2016-04-01 18 views
0

Ich fing an, ein kleines Spielzeug-Betriebssystem in (NASM) Assembly zu entwickeln, nur zu meiner Unterhaltung. Ich habe einen Bootloader geschrieben, der die erste (und einzige) Datei aus einem FAT12-Dateisystem namens "kernel.sys" in den Speicher mit dem Offset 0x7E00 lädt. Im Real-Modus stellt der Kernel nur den geeigneten Videomodus über das BIOS ein und der 32-Bit-Modus (Geschützt) wird aktiviert. Und das ist der Punkt, wo mein Problem gefunden werden kann.Bochs: Assembly far Jump ging verloren im falschen Speicherbereich (ungültiger Opcode-Fehler)

Zunächst habe ich eine GDT mit 3 Deskriptoren (Null, Ring 0 Code, Ring 0 Daten) eingerichtet, und ich lade es direkt in den Speicherbereich 0x0500. Dann benutze ich LGDT Anweisung, um es an den Prozessor zu sagen, dann setze ich das PE Bit in CR0 Register, und ich möchte geschützten Modus mit einem Weitsprung, um das entsprechende Segment (0x08 - Code-Segment in GDT) und den Befehlszeiger .

Die erste Version davon wurde in QEMU gearbeitet, aber nicht in Bochs. Bochs musste die Segmente vor dem Weitsprung setzen, also änderte ich dies in meinem Code: Direkt vor dem Weitsprung lade ich Selektoren mit dem Datensegment aus meiner GDT. Aber Bochs kann wegen eines "Opcode ungültig" -Fehlers immer noch nicht in den geschützten Modus wechseln.

Bitte helfen Sie mir, diesen Fehler zu lösen!

Hier ist meine Kernel-Code: (! Beachten Sie, dass Etikett b32 nie erreicht)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 
;;                 ;; 
;;       16-BIT ENTRY       ;; 
;;                 ;; 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 

use16 
org 0x7e00 
jmp start 

sys_gdt  equ 0x00000500 
sys_gdt_ring0c equ 0x00000508 
sys_gdt_ring0d equ 0x00000510 
sys_gdtr  equ 0x00000518 

start: 
    cli 

    mov ax, 0 
    mov ds, ax 
    mov es, ax 
    mov fs, ax 
    mov gs, ax 
    mov ss, ax 
    mov sp, 0x1000 
    sti 

    mov ax, 3 
    int 0x10 

set_a20: 
    in al, 0x64 
    test al, 2 
    jnz set_a20 

    mov al, 0xd1 
    out 0x64, al 

test_a20: 
    in al, 0x64 
    test al, 2 
    jnz test_a20 

    mov al, 0xdf 
    out 0x60, al 

    mov dword [sys_gdt+0], 0 
    mov dword [sys_gdt+4], 0 

    mov word [sys_gdt_ring0c+0], 0xffff 
    mov word [sys_gdt_ring0c+2], 0 
    mov byte [sys_gdt_ring0c+4], 0 
    mov byte [sys_gdt_ring0c+5], 10011010b 
    mov byte [sys_gdt_ring0c+6], 01001111b 
    mov byte [sys_gdt_ring0c+7], 0 

    mov word [sys_gdt_ring0d+0], 0xffff 
    mov word [sys_gdt_ring0d+2], 0 
    mov byte [sys_gdt_ring0d+4], 0 
    mov byte [sys_gdt_ring0d+5], 10010010b 
    mov byte [sys_gdt_ring0d+6], 01001111b 
    mov byte [sys_gdt_ring0d+7], 0 

    mov word [sys_gdtr+0], sys_gdtr-sys_gdt-1 
    mov dword [sys_gdtr+2], sys_gdt 

    cli 
    lgdt [sys_gdtr] ;; :96 

    mov eax, cr0 
    or eax, 0x1 
    mov cr0, eax 

    mov ax, 0x10 
    mov ds, ax 
    mov es, ax 
    mov fs, ax 
    mov gs, ax 
    mov ss, ax 
    mov esp, 0x90000 

    jmp 0x08:b32 

use32 

b32: 
    mov cx, 5 
    jmp $ 

Hier ist log die Bochs:

00014041550i[BIOS ] Booting from 0000:7c00 
00015625085e[CPU0 ] write_virtual_checks(): write beyond limit, r/w 
00015625085i[CPU0 ] CPU is in protected mode (active) 
00015625085i[CPU0 ] CS.d_b = 32 bit 
00015625085i[CPU0 ] SS.d_b = 32 bit 
00015625085i[CPU0 ] EFER = 0x00000000 
00015625085i[CPU0 ] | RAX=0000000060000010 RBX=0000000000000204 
00015625085i[CPU0 ] | RCX=0000000000090000 RDX=0000000000000fff 
00015625085i[CPU0 ] | RSP=0000000000090000 RBP=0000000000000000 
00015625085i[CPU0 ] | RSI=00000000000e018e RDI=0000000000008000 
00015625085i[CPU0 ] | R8=0000000000000000 R9=0000000000000000 
00015625085i[CPU0 ] | R10=0000000000000000 R11=0000000000000000 
00015625085i[CPU0 ] | R12=0000000000000000 R13=0000000000000000 
00015625085i[CPU0 ] | R14=0000000000000000 R15=0000000000000000 
00015625085i[CPU0 ] | IOPL=0 id vip vif ac vm rf nt of df if tf sf zf af PF cf 
00015625085i[CPU0 ] | SEG selector  base limit G D 
00015625085i[CPU0 ] | SEG sltr(index|ti|rpl)  base limit G D 
00015625085i[CPU0 ] | CS:0008(0001| 0| 0) 00000000 000fffff 0 1 
00015625085i[CPU0 ] | DS:0010(0002| 0| 0) 00000000 000fffff 0 1 
00015625085i[CPU0 ] | SS:0010(0002| 0| 0) 00000000 000fffff 0 1 
00015625085i[CPU0 ] | ES:0010(0002| 0| 0) 00000000 000fffff 0 1 
00015625085i[CPU0 ] | FS:0010(0002| 0| 0) 00000000 000fffff 0 1 
00015625085i[CPU0 ] | GS:0010(0002| 0| 0) 00000000 000fffff 0 1 
00015625085i[CPU0 ] | MSR_FS_BASE:0000000000000000 
00015625085i[CPU0 ] | MSR_GS_BASE:0000000000000000 
00015625085i[CPU0 ] | RIP=0000000000007ebb (0000000000007eb9) 
00015625085i[CPU0 ] | CR0=0x60000011 CR2=0x0000000000000000 
00015625085i[CPU0 ] | CR3=0x00000000 CR4=0x00000000 
00015625085i[CPU0 ] 0x0000000000007eb9>> add byte ptr ds:[eax], al : 0000 
00015625085i[CMOS ] Last time is 1459506108 (Fri Apr 1 12:21:48 2016) 
00015625085i[  ] restoring default signal behavior 
00015625085i[CTRL ] quit_sim called with exit code 1 

Hier ist mein Bootloader:

use16 
jmp start 

    OEMLabel   db 'SYRACUSE' 
    BytesPerSector dw 512 
    SectorsPerCluster db 1 
    ReservedForBoot dw 1 
    NumberOfFats  db 2 
    RootDirEntries dw 224 
    LogicalSectors dw 2880 
    MediumByte  db 0xf0 
    SectorsPerFat  dw 9 
    SectorsPerTrack dw 18 
    Heads    dw 2 
    HiddenSectors  dd 0 
    LargeSectors  dd 0 
    DriveNo   dw 0 
    Signature   db 41 
    VolumeID   dd 0 
    VolumeLabel  db 'Syracuse1.0' 
    FileSystem  db 'FAT12 ' 

chs_lba: 
    sub ax, 2 
    xor cx, cx 
    mov cl, byte [SectorsPerCluster] 
    mul cx 
    add ax, word [datasector] 
    ret 

lba_chs: 
    xor dx, dx 
    div word [SectorsPerTrack] 
    inc dl 
    mov byte [absoluteSector], dl 
    xor dx, dx 
    div word [Heads] 
    mov byte [absoluteHead], dl 
    mov byte [absoluteTrack], al 
    ret 

print: 
    pusha 
    mov ah, 0xe 
.repeat: 
    lodsb 
    cmp al, 0 
    je .done 
    int 0x10 
    jmp short .repeat 
.done: 
    popa 
    ret 

read_sectors: 
    mov di, 5 
.loop: 
    pusha 

    call lba_chs 
    mov ah, 2 
    mov al, 1 
    mov ch, byte [absoluteTrack] 
    mov cl, byte [absoluteSector] 
    mov dh, byte [absoluteHead] 
    mov dl, byte [DriveNo] 
    int 0x13 
    jnc .done 

    xor ax, ax 
    int 0x13 

    dec di 
    popa 
    jnz .loop 
    int 0x18 
.done: 
    popa 

    inc ax 
    add bx, word [BytesPerSector] 
    loop read_sectors 
    ret 

start: 
    cli 
    mov ax, 0x07c0 
    mov ds, ax 
    mov es, ax 
    mov fs, ax 
    mov gs, ax 

    mov ax, 0 
    mov ss, ax 
    mov sp, 0xffff 
    sti 

load_root: 
    xor cx, cx 
    xor dx, dx 
    mov ax, 32 
    mul word [RootDirEntries] 
    div word [BytesPerSector] 
    xchg ax, cx 

    mov al, byte [NumberOfFats] 
    mul word [SectorsPerFat] 
    add ax, word [ReservedForBoot] 
    mov word [datasector], ax 
    add word [datasector], cx 

    mov bx, 0x0200 
    call read_sectors 

    mov cx, word [RootDirEntries] 
    mov di, 0x0200 

.loop: 
    push cx 

    mov cx, 11 
    mov si, kernel 

    push di 
    rep cmpsb 
    pop di 
    je load_fat 

    pop cx 
    add di, 32 
    loop .loop 

    jmp failure 

load_fat: 
    mov dx, word [di+0x001a] 
    mov word [cluster], dx 

    xor ax, ax 
    mov al, byte [NumberOfFats] 
    mul word [SectorsPerFat] 
    mov cx, ax 

    mov ax, word [ReservedForBoot] 

    mov bx, 0x0200 
    call read_sectors 

    mov ax, 0x7e00 
    mov es, ax 
    mov bx, 0x0000 

load_kernel: 
    mov ax, word [cluster] 
    call chs_lba 
    xor cx, cx 
    mov cl, byte [SectorsPerCluster] 
    call read_sectors 

    mov ax, word [cluster] 
    mov cx, ax 
    mov dx, ax 
    shr dx, 1 
    add cx, dx 
    mov bx, 0x0200 
    add bx, cx 
    mov dx, word [bx] 
    test ax, 1 
    jnz .odd 

.even: 
    and dx, 0000111111111111b 
    jmp .done 

.odd: 
    shr dx, 4 

.done: 
    mov word [cluster], dx 
    cmp dx, 0x0ff0 
    jb load_kernel 

    pusha 
    mov di, 0x7e00 
    xor ax, ax 
    mov cx, 512 
    rep stosb 


execute_kernel: 
    ;push word 0x7e00 
    ;push word 0x0000 
    ;retf 

    jmp 0x7e00:0x0000 

failure: 
    mov si, msg 
    call print 

    mov ah, 0 
    int 0x16 
    int 0x19 

absoluteSector db 0 
absoluteHead db 0 
absoluteTrack db 0 

datasector dw 0 
cluster dw 0 

kernel db 'KERNEL SYS' 
msg db 'MISSING KERNEL. Press any key to reboot...', 0xA, 0xD, 0 

times 510-($-$$) db 0 
dw 0xAA55 
+0

Funktioniert hier in Bochs 2.6.8. Ich hoffe, als du gesagt hast, dass du geladen hast, um '0x7E00: 0x0000' zu adressieren, war das nur ein Tippfehler. – Jester

+0

Oh. Ich habe es geladen, um '0x7E00' zu versetzen. Arbeitest du immer noch bei dir? – kerberos

+0

Nun, ich habe Ihren Loader nicht, also habe ich ihn bei '0x7C00' als Boot-Sektor geladen, aber das funktioniert und ich sehe nicht, warum es nirgendwo anders funktionieren würde. Überprüfen Sie auch Ihren Eintrag/Disassembly, um zu sehen, was bei '7eb9' ist, weil bochs zu denken scheint, dass Sie' 00 00' dort haben (das ist der Ort des Fehlers). Ganz zu schweigen von den eingebauten Debugger und Einzelschritt. – Jester

Antwort

2

Sie wissen, dass Real-Modus-Adressierung 16*segment+offset als ph verwendet Persönliche Adresse, oder? Sie laden den Code unter 0x7E00:0000, der somit die physikalische Adresse 0x7E000 ist (Hinweis 3 Nullen). Aber Ihr Kernel erwartet die Adresse 0x7E00 (beachten Sie 2 Nullen).

Ihr Code ist doppelt falsch. Zuerst springen Sie tatsächlich zum Offset 0, also sollten Sie org 0 verwenden (was der Standardwert ist). Zweitens muss die physikalische Adresse für das Real-Modus-Segment angepasst werden, das heißt jmp dword 0x8:b32+0x7e000. Das wird den aktuellen Code beheben, aber der 32-Bit-Teil wird wieder falsch org verwenden.

Sie machen Ihr eigenes Leben unnötig kompliziert. Die übliche bewährte Methode besteht darin, den Code in eine Adresse innerhalb der ersten 64 KB zu laden, wo Sie Offsets mit 0 und 16 Bit verwenden können, die sowohl im realen als auch im geschützten Modus direkt auf den physischen Speicher abgebildet werden. Als solche empfehle ich, laden, sagen wir 0:0x8000.

+0

Oh, wirklich. Wie du schon sagtest, funktioniert '0: 0x8000' immer noch, aber bis jetzt habe ich eine Frage. Wir wissen, dass der Bootloader den Kernel in eine Adresse lädt, auf die mit 'ES: BX' gezeigt wird, also wenn 'ES = 0' und' BX = 0x8000' und der Kernel 'ORG 0x8000' enthält, funktioniert der Code völlig. Aber wenn ich 'ES: BX = 0: 0x7e00' und' ORG 0x7e00' setze, dann funktioniert mein Kernel einfach nicht, aber warum? – kerberos

+0

Nicht sicher, wie Ihr Code jetzt aussieht, aber das Original hat einen Block bei '0x7e00' auf Null gesetzt, damit Ihr geladener Kernel gelöscht wird;) Keine Ahnung, warum Sie das getan haben. – Jester

+0

Ich meinte, es wurde bereits entfernt, in meinem aktuellen Loader-Code, dieser 'rep stosb' Befehl ist bereits weg. Aber wenn ich den Kernel auf '0: 0x7e00' lade, funktioniert das weder jetzt noch. Ich habe auch 'ORG' im Kernel korrigiert. – kerberos