8

x86 アセンブリを学んでおり、NASM でおもちゃのオペレーティング システムを作成しようとしていますが、いくつかのことがわかりません。

カーネルを正常に起動するブートローダーを作成しました。

  1. カーネル ファイルを含むディスケットから 14 セクタをロードします。
  2. というラベルの付いたこれらのセクターでファイルを検索しますkernel.feo
  3. そのファイルをオフセットのメモリにロードします0x2000
  4. far jump を使用してカーネルを実行しますjmp 0x2000:0x0000

したがって0x2000:0、メモリ内にカーネルコードがあります。CSファージャンプを使用しているため、適切に設定されている可能性があります。このカーネル コードでは、32 ビット プロテクト モードに入りたいのですが、GDT がどのように機能しているかわかりません。以下のコードを仮想マシン(QEMU)で実行すると、何も実行されません。

32 ビット プロテクト モードに入るのを手伝ってください!

とはいえ、次の問題があります。

  1. 0x7c00:0が原因でコードが にロードされていると想定していますがorg 0、そうではない可能性があります。保証されるのは物理アドレスだけです。CS適切に設定されるように、エントリ ポイントへのファー ジャンプを使用する必要があります。
  2. 何らかの理由で、コードがデータをまったく検出しないように設定DSしています。matchに0x2000設定するか、どこでもオーバーライドを使用する必要があります (推奨されません)。DSCSCS
  3. プロテクト モードのコードはゼロから始まるセグメントを前提とorg 0x7c00しています。org 0x7c00および セグメントに切り替える必要があり0ます。
  4. VGA テキスト モード セグメントは0xb8000not 0xb80000(ゼロを 1 つ引いた値) です。
  5. 0x55 0xaaブート セクタの最後にブート署名バイトがありません。

コードで次のことを修正しました。

  1. [org 0x0]は に修正され[org 0x2000]、セグメントは に設定され0ます。
  2. DS0の代わりに に修正されたので、 ;0x2000と一致するようになりました。CS
  3. VGA テキスト モード セグメントは に修正されました0xb8000

しかし、コードはこれらの修正では機能しません。2 つの文字列を出力するはずですが、何もしません!

このカーネル コードは0x55 0xAA、ブート セクターではないため、ブート署名で終わらないように注意してください。

修正されたカーネル コードは次のとおりです (動作していません)。

[bits 16]
[org 0x2000]

    jmp 0:kernel_start

gdt_start:

gdt_null:
    dd 0x0
    dd 0x0

gdt_code:
    dw 0xffff
    dw 0x0
    db 0x0
    db 10011010b
    db 11001111b
    db 0x0

gdt_data:
    dw 0xffff
    dw 0x0
    db 0x0
    db 10010010b
    db 11001111b
    db 0x0

gdt_end:

gdt_descriptor:
    dw gdt_end - gdt_start
    dd gdt_start

CODE_SEG equ gdt_code - gdt_start
DATA_SEG equ gdt_data - gdt_start

print:
    mov ah, 14
    mov bh, 0
    lodsb
    cmp al, 0
    je .done
    int 0x10
    jmp print
.done:
    ret

uzenet_real db 'uzenet16', 0
uzenet_prot db 'uzenet32', 0

kernel_start:
    mov ax, 0
    mov ss, ax
    mov sp, 0xFFFC

    mov ax, 0
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax

    mov si, uzenet_real
    call print

    cli
    lgdt[gdt_descriptor]
    mov eax, cr0
    or eax, 0x1
    mov cr0, eax
    jmp CODE_SEG:b32

[bits 32]

VIDEO_MEMORY equ 0xb8000
WHITE_ON_BLACK equ 0x0f

print32:
    pusha
    mov edx, VIDEO_MEMORY
.loop:
    mov al, [ebx]
    mov ah, WHITE_ON_BLACK
    cmp al, 0
    je .done
    mov [edx], ax
    add ebx, 1
    add edx, 2
    jmp .loop
.done:
    popa
    ret

b32:
    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

    mov ebx, uzenet_prot
    call print32

    jmp $
4

1 に答える 1

10

OS のプログラミングは高度な作業です。少なくとも、デバッガーを使用して自分の間違いを見つけ、基本的なことを理解できることが期待されます。この取り組みの前提条件をすべて満たしているかどうかを再検討することをお勧めします。

とはいえ、次の問題があります。

  1. 0x7c00:0が原因でコードが にロードされていると想定していますがorg 0、そうではない可能性があります。保証されるのは物理アドレスだけです。CS適切に設定されるように、エントリ ポイントへのファー ジャンプを使用する必要があります。
  2. 何らかの理由で、コードがデータをまったく検出しないように設定DSしています。matchに0x2000設定するか、どこでもオーバーライドを使用する必要があります (推奨されません)。DSCSCS
  3. プロテクト モードのコードはゼロから始まるセグメントを前提とorg 0x7c00しています。org 0x7c00および セグメントに切り替える必要があり0ます。
  4. VGA テキスト モード セグメントは0xb8000not 0xb80000(ゼロを 1 つ引いた値) です。
  5. 0x55 0xaaブート セクタの最後にブート署名バイトがありません。

固定コード:

[bits 16]
[org 0x7c00]

    jmp 0:kernel_start

gdt_start:

gdt_null:
    dd 0x0
    dd 0x0

gdt_code:
    dw 0xffff
    dw 0x0
    db 0x0
    db 10011010b
    db 11001111b
    db 0x0

gdt_data:
    dw 0xffff
    dw 0x0
    db 0x0
    db 10010010b
    db 11001111b
    db 0x0

gdt_end:

gdt_descriptor:
    dw gdt_end - gdt_start
    dd gdt_start

CODE_SEG equ gdt_code - gdt_start
DATA_SEG equ gdt_data - gdt_start

print:
    pusha
    mov ah, 14
    mov bh, 0
.loop:
    lodsb
    cmp al, 0
    je .done
    int 0x10
    jmp .loop
.done:
    popa
    ret

uzenet16 db 'uzenet16', 0
uzenet32 db 'uzenet32', 0

kernel_start:
    mov ax, 0
    mov ss, ax
    mov sp, 0xFFFC

    mov ax, 0
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax

    mov si, uzenet16
    call print

    cli
    lgdt[gdt_descriptor]
    mov eax, cr0
    or eax, 0x1
    mov cr0, eax
    jmp CODE_SEG:b32

[bits 32]

VIDEO_MEMORY equ 0xb8000
WHITE_ON_BLACK equ 0x0f

print32:
    pusha
    mov edx, VIDEO_MEMORY
.loop:
    mov al, [ebx]
    mov ah, WHITE_ON_BLACK
    cmp al, 0
    je .done
    mov [edx], ax
    add ebx, 1
    add edx, 2
    jmp .loop
.done:
    popa
    ret

b32:
    mov ax, DATA_SEG
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    mov ss, ax

    mov ebp, 0x2000
    mov esp, ebp

    mov ebx, uzenet32
    call print32

    jmp $

[SECTION signature start=0x7dfe]
dw 0AA55h

あなたの更新された質問は、コードがロードされている場所についてまだ混乱しているoffset 0x2000ようExecutes the kernel using a far jump jmp 0x2000:0x0000ですjmp 0:0x2000. それ以外に、コードが実際にメモリの正しい場所にロードされていることを確認してください。デバッガーの使い方を学びます。

これは、上記のコードを 2 番目のセクターから address にロードする小さなブート セクター0x2000です。問題なく動作します。問題は GDT のものではありません。特に、リアル モードのメッセージが出力されない場合はなおさらです (それについても明確ではありませんでした)。

[bits 16]
[org 0x7c00]
mov ax, 0201h
mov cx, 0002h
mov dh, 0
mov bx, 0
mov es, bx
mov bx, 2000h
int 13h
jmp 0:2000h

[SECTION signature start=0x7dfe]
dw 0AA55h
于 2015-02-21T12:44:46.457 に答える