2016-12-11 10 views
2

NASMを使用してブートローダを作成しようとしています。その結果、OSDEVが非常に役立つことがわかりました。しかし、ページングを設定したり、GDTをロードしたり、実際のモードから直接移行したりする途中で、マシンを再起動させるエラーが発生します。コードはLong mode OSDEV articleに基づいています。リアルモードから64ビットロングモードスイッチへのページングを設定する

GDTページングとスイッチ

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 

%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 

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

最小限の完全な検証可能な例を示してください。 –

+1

@MichaelPetch私が行う唯一の他のものは、OSDEVの記事で述べたようにcpuid/longmodeをチェックすることです。まだ起動していない場合は、A20行を有効にします。この問題は、 'switch_to_lm'ラベルを呼び出すと発生します。どのような「最小限の完全なバリファイア可能な回答」が欲しいですか? – Mike

+0

誰もが問題を再現できるコードの最小限で完全な量は、コマンドを使用してリンク/コンパイル/アセンブルなどに使用します。それを私は問題が見当たらないので、OSDEVのSOの質問には非常に積極的です。私が最小限の完全な例を求めていない時は、不必要な時間と数十のコメントを費やして、提示されたコードに無関係なものが問題であることを知りました。コードをGithubに置くか、私がテストできる何かのファイルのアーカイブを私に電子メールで送るのであれば、おそらくあなたの問題をもっと早く発見することができます。私のメールアドレスは[email protected]です。 –

答えて

1

でごコードでは、test_a20機能に問題があります。

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 

あなたは後にオフに2をポップ、スタック上AXの一つの値をプッシュすることが表示されます。特に、あなたはこのコードを持っています。これは、スタックを混乱させるでしょう、レジスタは、のDSとフラグを含む間違って復元されます。このバグを回避するために、retを使用しないと表示されているようです。代わりにjmp finを使用してcall test_a20命令の後のポイントにジャンプしました。

A20 test code from OSDEV Wikiを使用しているようです。あなたが不足している行を追加し、retを使用するようにtest_a20機能を変更した場合、それはのようになります

mov al, byte [ds:si] 
push ax 

を::この変更は、との問題を修正する必要があり

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 

あなたはこれらの行に表示されません注意しましょうDSレジスタが破壊され、誤って動作するページ書き込みコードでメモリアクセスが一時的に中断されます。また、保護モードを有効にするコードを有効にするページを修正する必要があります。このコード:

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

する必要があります:あなたは64ビットロングモードに入ることができる必要があり、これらの変更により

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

関連する問題