2016-04-01 2 views
0

J'ai commencé à développer un petit système d'exploitation de jouet dans l'assemblage (NASM), juste pour mon divertissement. J'ai écrit un chargeur de démarrage qui charge le premier (et le seul) fichier d'un système de fichiers FAT12 appelé "kernel.sys" dans la mémoire au décalage 0x7E00. En mode réel, le noyau définit uniquement le mode vidéo approprié via le BIOS et passe en mode 32 bits (protégé). Et c'est le point où mon problème peut être trouvé. Tout d'abord, j'ai mis en place un GDT avec 3 descripteurs (null, ring 0, 0) et je le charge directement dans la zone mémoire 0x0500. Puis j'utilise l'instruction LGDT pour le dire au processeur, puis je règle le bit PE dans le registre CR0, et je veux entrer en mode protégé avec un saut lointain pour régler le segment approprié (0x08 - segment de code dans GDT) et le pointeur d'instruction .Bochs: le saut lointain d'assemblage s'est perdu dans la zone de mémoire bidon (erreur de code d'erreur invalide)

La première version a été travaillée dans QEMU, mais pas dans Bochs. Bochs avait besoin de définir les segments avant le saut lointain, donc j'ai modifié cela dans mon code: juste avant le saut lointain, je charge les sélecteurs avec le segment de données de mon GDT. Mais, Bochs ne peut toujours pas entrer en mode protégé, en raison d'une erreur "opcode invalide".

S'il vous plaît aidez-moi à résoudre cette erreur!

Voici mon code du noyau: (! Notez que l'étiquette b32 n'a jamais atteint)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 
;;                 ;; 
;;       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 $ 

Voici le Bochs journal:

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 

Voici mon 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

Fonctionne bien ici dans les bochs 2.6.8. J'espère quand vous avez dit que vous avez chargé pour adresser '0x7E00: 0x0000' qui était juste une faute de frappe. – Jester

+0

Oh. Je l'ai chargé pour décaler '0x7E00'. Vous travaillez encore chez vous? – kerberos

+0

Eh bien, je n'ai pas votre chargeur, donc je l'ai chargé à 0x7C00 comme un secteur de démarrage, mais cela fonctionne et je ne vois pas pourquoi cela ne fonctionnerait pas ailleurs. En outre, vérifiez votre liste/démontage pour voir ce qui est à '7eb9' parce que bochs semble penser que vous avez' 00 00' là (c'est l'endroit de la faute). Pour ne pas mentionner simplement utiliser le débogueur intégré et une seule étape. – Jester

Répondre

2

Vous savez que l'adressage en mode réel utilise 16*segment+offset comme ph adresse physique, non? Vous chargez le code au 0x7E00:0000 qui est donc l'adresse physique 0x7E000 (remarquez 3 zéros). Mais votre noyau attend l'adresse 0x7E00 (remarquez 2 zéros).

Votre code est doublement erroné. Tout d'abord, vous sautez pour compenser 0 donc vous devriez utiliser org 0 (qui est la valeur par défaut). Deuxièmement, l'adresse physique doit être ajustée pour le segment en mode réel, c'est-à-dire jmp dword 0x8:b32+0x7e000. Cela va corriger le code actuel, mais la partie 32 bits utilisera de nouveau org.

Vous rendez votre propre vie inutilement compliquée. La meilleure pratique habituelle consiste à charger le code dans une adresse dans le premier 64k où vous pouvez utiliser des décalages de segment 0 et 16 bits qui mappent directement à la mémoire physique en mode réel et en mode plat. En tant que tel, je suggère de charger, par exemple, 0:0x8000.

+0

Oh, vraiment. Comme vous l'avez dit, '0: 0x8000' fonctionne encore, mais jusqu'à présent, j'ai une question. Nous savons que bootloader charge le noyau à une adresse pointée par 'ES: BX', donc si' ES = 0' et 'BX = 0x8000', et que le noyau contient' ORG 0x8000', le code fonctionne totalement. Mais si je mets 'ES: BX = 0: 0x7e00' et' ORG 0x7e00', alors mon noyau ne fonctionne pas, mais pourquoi? – kerberos

+0

Vous ne savez pas exactement à quoi ressemble votre code maintenant, mais l'original a mis à zéro un bloc à '0x7e00' afin de vider votre noyau chargé;) Je ne sais pas pourquoi vous l'avez fait. – Jester

+0

Je voulais dire qu'il a déjà été supprimé, dans mon code loader actuel, que l'instruction 'rep stosb' a déjà disparu. Mais si je charge le noyau à '0: 0x7e00', cela ne fonctionne pas, ni maintenant. J'ai également corrigé 'ORG' dans le noyau. – kerberos