2016-12-11 2 views
2

J'essaye d'écrire un chargeur de démarrage en utilisant NASM et par conséquent, j'ai trouvé OSDEV extrêmement utile. Toutefois, quelque part dans le processus de configuration de la pagination, du chargement de mon GDT ou de la transition (im venant directement du mode réel), une erreur entraîne le redémarrage de l'ordinateur. J'ai basé mon code sur le Long mode OSDEV article. Voilà ce que j'ai ce qui est important à la question:Configuration de la pagination pour le mode réel sur le commutateur de mode 64 bits

TDG

gdt_start: 

.gdt_null: equ $-gdt_start  ; mandatory null descriptor 
    dw 0 
    dw 0 
    db 0       ; define double word 
    db 0 
    db 0 
    db 0 

.gdt_code: equ $-gdt_start  ; code segment 
           ; base = 0x0, limif = 0xffff 
           ; 1st flags: (present)1 (privilege)00 (descriptor type)1 -> 1001 
           ; type flags: (code)1 (conforming)0 (readable)1 (accessed)0 -> 1010 
           ; 2nd flags: (granularity)1 (32 bit default)1 (64 bit seg)0 (AVL)0 -> 1100 
    dw 0       ; limit (0-15) 
    dw 0       ; base (0-15) 
    db 0       ; base (16-23) 
    db 10011010b     ; 1st/type flags 
    db 00100000b     ; 2nd flags, limit (16-19) 
    db 0       ; base (bits 24-31) 

.gdt_data: equ $-gdt_start  ; data segment descriptor 
       ; type flags (code)0 (expand down)0 (writable)1 (accessed)0 -> 0010 
    dw 0       ; limit 
    dw 0       ; base 
    db 0       ; base 
    db 10010010b     ; 1st/type flags 
    db 00000000b     ; 2nd flags, limit 
    db 0       ; base 

gdt_end: 

gdt_descriptor: 
    dw gdt_end - gdt_start - 1 ; size of GDT 

    dq gdt_start 

CODE_SEG equ gdt_start.gdt_code 
DATA_SEG equ gdt_start.gdt_data 

Paging et interrupteur:

%include "gdt.ns" 

;test/enable A20 line 
call test_a20 
fin: 

cmp ax, 1 
je enabled 

call enable_A20 

enabled: 

;switch 
call switch_to_lm 
jmp $ 

switch_to_lm: 
; 
; SET UP PAGING!!!!! 
; 

;no previous paging defined so the below code is unnecessary 
;mov eax, cr0 
;and eax, 01111111111111111111111111111111b 
;mov cr0, eax 

;clear tables 
mov edi, 0x1000 
mov cr3, edi 
xor eax, eax 
mov ecx, 4096 
rep stosd 
mov edi, cr3 

;set up new tables 
mov DWORD [edi], 0x2003 
add edi, 0x1000 
mov DWORD [edi], 0x3003 
add edi, 0x1000 
mov DWORD [edi], 0x4003 
add edi, 0x1000 

mov ebx, 0x00000003 
mov ecx, 512 

.setEntry: 
    mov DWORD [edi], ebx 
    add ebx, 0x1000 
    add edi, 8 
    loop .setEntry 

;enable PAE bit in CR4 
mov eax, cr4 
or eax, 1<<5 
mov cr4, eax 

;switch from REAL MODE 
;set long mode bit 
mov ecx, 0xc0000080 
rdmsr 
or eax, 1<<8 
wrmsr 

;enable paging 
mov eax, cr0 
or eax, 1<<31 
mov cr0, eax 

lgdt [gdt_descriptor] 
jmp CODE_SEG:init_lm 

[bits 64] 

init_lm: 

    cli 
    mov ax, DATA_SEG 
    mov ds, ax 
    mov es, ax 
    mov fs, ax 
    mov gs, ax 
    mov ss, ax 

    mov ebp, 0x90000 
    mov esp, ebp 

    call BEGIN_LM 

Mon code pour tester A20:

test_a20: 
    pushf 
    push ds 
    push es 
    push di 
    push si 

    cli 

    xor ax, ax 
    mov es, ax 

    not ax 
    mov ds, ax 

    mov di, 0x0500 
    mov si, 0x0510 

    mov al, byte [es:di] 
    push ax 

    mov byte [es:di], 0x00 
    mov byte [ds:si], 0xff 

    cmp byte [es:di], 0xff 

    pop ax 
    mov byte [ds:si], al 

    pop ax 
    mov byte [es:di], al 

    mov ax, 0 
    je test_exit 

    mov ax, 1 

test_exit: 
    pop si 
    pop di 
    pop es 
    pop ds 
    popf 

    jmp fin 
+0

Veuillez montrer un exemple minimal complet vérifiable. –

+1

@MichaelPetch La seule autre chose que je fais est de vérifier cpuid/longmode comme mentionné par l'article OSDEV et j'active la ligne A20 si elle n'est pas déjà activée. Le problème se produit lorsque j'appelle l'étiquette 'switch_to_lm'. Quelle "réponse varifiable complète minimale" voulez-vous? – Mike

+0

La quantité minimale et complète de code qui permet à quiconque de reproduire le problème, y compris les commandes utilisent pour lier/compiler/assembler etc Regardant ça je ne vois pas le problème, et je suis très actif dans les questions OSDEV sur SO. Les fois où je ne demande pas un exemple complet minimal, je passe des heures inutiles et des dizaines de commentaires pour découvrir que des choses sans rapport avec le code présenté étaient un problème. Si vous deviez placer votre code sur Github ou m'envoyer une archive de vos fichiers par email, je pourrais probablement tester votre problème plus rapidement. Mon adresse e-mail est [email protected] –

Répondre

1

Dans votre code, il y a un problème avec votre fonction test_a20. En particulier, vous avez ce code:

mov al, byte [es:di] 
push ax 

mov byte [es:di], 0x00 
mov byte [ds:si], 0xff 

cmp byte [es:di], 0xff 

pop ax 
mov byte [ds:si], al 

pop ax 
mov byte [es:di], al 

Vous semblez pousser une valeur de AX sur la pile, sauter 2 au bout. Cela va gâcher la pile, les registres seront restaurés correctement, y compris DS et les drapeaux. Il semble que vous ayez essayé de contourner ce bug en n'utilisant pas ret pour revenir. Au lieu de cela, vous avez utilisé jmp fin pour passer à un point après l'instruction . Il semble que vous essayiez d'utiliser A20 test code from OSDEV Wiki. Vous remarquerez que vous manquez ces lignes:

mov al, byte [ds:si] 
push ax 

Si vous modifiez votre fonction test_a20 ajouter la ligne manquante et utiliser ret il devrait ressembler à:

test_a20: 
    pushf 
    push ds 
    push es 
    push di 
    push si 

    cli 

    xor ax, ax 
    mov es, ax 

    not ax 
    mov ds, ax 

    mov di, 0x0500 
    mov si, 0x0510 

    mov al, byte [es:di] 
    push ax 

    mov al, byte [ds:si] 
    push ax 

    mov byte [es:di], 0x00 
    mov byte [ds:si], 0xff 

    cmp byte [es:di], 0xff 

    pop ax 
    mov byte [ds:si], al 

    pop ax 
    mov byte [es:di], al 

    mov ax, 0 
    je test_exit 

    mov ax, 1 

test_exit: 
    pop si 
    pop di 
    pop es 
    pop ds 
    popf 
    ret 

Ce changement devrait corriger les problèmes avec le registre DS est détruit et l'accès mémoire subséquent dans le code d'écriture de page ne fonctionne pas correctement. Vous devez également modifier votre code d'activation de page pour activer également le mode protégé. Ce code:

;enable paging 
mov eax, cr0 
or eax, 1<<31 
mov cr0, eax 

devrait être:

;enable paging 
mov eax, cr0 
or eax, (1<<31) | (1<<0) 
mov cr0, eax 

Avec ces changements, vous devriez être en mesure d'entrer en mode à long 64 bits.