2

私の問題が大きなものでなくても、経験豊富なアセンブリ/OS 開発者がここにいることを願っています。アセンブリで遊んで、小さなオペレーティング システムを作成しようとしています。実際、私が必要としているのは、ビデオ メモリを使用して (明らかに割り込みではなく)、pmode をアクティブにして画面に単一の文字を表示するブート ローダーと 2 つ目のブート ローダーです。VirtualBox を使用してコードをエミュレートし、VHD ディスク (2 セクターのコード) 内に手動で貼り付けます。

まず、私のコード:

boot.asm
これは最初のブートローダーです

bits    16
org     0
mov     al, dl

jmp     07c0h:Start

Start:
    cli
    push    ax
    mov     ax, cs
    mov     ds, ax
    mov     es, ax
    pop     ax
    sti
    jmp     ReadDisk

ReadDisk:
    call    ResetDisk
    mov     bx, 0x1000
    mov     es, bx
    mov     bx, 0x0000
    mov     dl, al
    mov     ah, 0x02
    mov     al, 0x01
    mov     ch, 0x00
    mov     cl, 0x02
    mov     dh, 0x00
    int     0x13
    jc      ReadDisk
    jmp     0x1000:0x0000

ResetDisk:
    mov     ah, 0x00
    mov     dl, al
    int     0x13
    jc      ResetDisk
    ret

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

boot2.asm
これは 2 番目のブートローダーで、2 番目のセクター (次の 512 バイト) に貼り付けられます

bits    16
org     0

jmp     0x1000:Start

InstallGDT:
    cli
    pusha
    lgdt    [GDT]
    sti
    popa
    ret

StartGDT: 
    dd      0
    dd      0 

    dw      0ffffh 
    dw      0
    db      0
    db      10011010b
    db      11001111b
    db      0

    dw      0ffffh
    dw      0
    db      0
    db      10010010b
    db      11001111b
    db      0

StopGDT:

GDT:
    dw StopGDT - StartGDT - 1
    dd StartGDT + 10000h

OpenA20:
    cli
    pusha
    call    WaitInput
    mov     al, 0xad
    out     0x64, al
    call    WaitInput
    mov     al, 0xd0
    out     0x64, al
    call    WaitInput
    in      al, 0x60
    push    eax
    call    WaitInput
    mov     al, 0xd1
    out     0x64, al
    call    WaitInput
    pop     eax
    or      al, 2
    out     0x60, al
    call    WaitInput
    mov     al, 0xae
    out     0x64, al
    call    WaitInput
    popa
    sti
    ret

WaitInput:
    in      al, 0x64
    test    al, 2
    jnz     WaitInput
    ret

WaitOutput:
    in      al, 0x64
    test    al, 1
    jz      WaitOutput
    ret

Start:
    cli
    xor ax,     ax
    mov ds,     ax
    mov     es,     ax
    mov ax,     0x9000
    mov ss,     ax
    mov sp,     0xffff
    sti

    call    InstallGDT
    call    OpenA20

ProtectedMode:
    cli
    mov     eax,    cr0
    or      eax,    1
    mov     cr0,    eax
    jmp 08h:ShowChar

bits    32

ShowChar:
    mov ax, 0x10
    mov ds, ax
    mov ss, ax
    mov es, ax
    mov esp, 90000h

    pusha               ; save registers
    mov edi, 0xB8000
    mov bl, '.'
    mov dl, bl          ; Get character
    mov dh, 63      ; the character attribute
    mov word [edi], dx      ; write to video display
    popa
cli
hlt

そこで、このコードをコンパイルしてバイナリを VHD に貼り付け、Virtual Box でシステムを実行します。正しく pmode になり、A20 ゲートが有効になり、LGTR にメモリ アドレスが含まれていることがわかります (これが正しいかどうかはわかりません)。これは、ログ ファイルの一部であり、興味深い可能性があります。

00:00:07.852082 ****************** Guest state at power off ******************
00:00:07.852088 Guest CPUM (VCPU 0) state: 
00:00:07.852096 eax=00000011 ebx=00000000 ecx=00010002 edx=00000080 esi=0000f4a0     edi=0000fff0
00:00:07.852102 eip=0000016d esp=0000ffff ebp=00000000 iopl=0         nv up di pl zr na po nc
00:00:07.852108 cs={1000 base=0000000000010000 limit=0000ffff flags=0000009b} dr0=00000000 dr1=00000000
00:00:07.852118 ds={0000 base=0000000000000000 limit=0000ffff flags=00000093} dr2=00000000 dr3=00000000
00:00:07.852124 es={0000 base=0000000000000000 limit=0000ffff flags=00000093} dr4=00000000 dr5=00000000
00:00:07.852129 fs={0000 base=0000000000000000 limit=0000ffff flags=00000093} dr6=ffff0ff0 dr7=00000400
00:00:07.852136 gs={0000 base=0000000000000000 limit=0000ffff flags=00000093} cr0=00000011 cr2=00000000
00:00:07.852141 ss={9000 base=0000000000090000 limit=0000ffff flags=00000093} cr3=00000000 cr4=00000000
00:00:07.852148 gdtr=0000000000539fc0:003d  idtr=0000000000000000:ffff  eflags=00000006
00:00:07.852155 ldtr={0000 base=00000000 limit=0000ffff flags=00000082}
00:00:07.852158 tr  ={0000 base=00000000 limit=0000ffff flags=0000008b}
00:00:07.852162 SysEnter={cs=0000 eip=00000000 esp=00000000}
00:00:07.852166 FCW=037f FSW=0000 FTW=0000 FOP=0000 MXCSR=00001f80 MXCSR_MASK=0000ffff
00:00:07.852172 FPUIP=00000000 CS=0000 Rsrvd1=0000  FPUDP=00000000 DS=0000 Rsvrd2=0000
00:00:07.852177 ST(0)=FPR0={0000'00000000'00000000} t0 +0.0000000000000000000000 ^ 0
00:00:07.852185 ST(1)=FPR1={0000'00000000'00000000} t0 +0.0000000000000000000000 ^ 0
00:00:07.852193 ST(2)=FPR2={0000'00000000'00000000} t0 +0.0000000000000000000000 ^ 0
00:00:07.852201 ST(3)=FPR3={0000'00000000'00000000} t0 +0.0000000000000000000000 ^ 0
00:00:07.852209 ST(4)=FPR4={0000'00000000'00000000} t0 +0.0000000000000000000000 ^ 0
00:00:07.852222 ST(5)=FPR5={0000'00000000'00000000} t0 +0.0000000000000000000000 ^ 0
00:00:07.852229 ST(6)=FPR6={0000'00000000'00000000} t0 +0.0000000000000000000000 ^ 0
00:00:07.852236 ST(7)=FPR7={0000'00000000'00000000} t0 +0.0000000000000000000000 ^ 0
00:00:07.852244 XMM0 =00000000'00000000'00000000'00000000  XMM1 =00000000'00000000'00000000'00000000
00:00:07.852253 XMM2 =00000000'00000000'00000000'00000000  XMM3 =00000000'00000000'00000000'00000000
00:00:07.852262 XMM4 =00000000'00000000'00000000'00000000  XMM5 =00000000'00000000'00000000'00000000
00:00:07.852270 XMM6 =00000000'00000000'00000000'00000000  XMM7 =00000000'00000000'00000000'00000000
00:00:07.852280 XMM8 =00000000'00000000'00000000'00000000  XMM9 =00000000'00000000'00000000'00000000
00:00:07.852287 XMM10=00000000'00000000'00000000'00000000  XMM11=00000000'00000000'00000000'00000000
00:00:07.852295 XMM12=00000000'00000000'00000000'00000000  XMM13=00000000'00000000'00000000'00000000
00:00:07.852302 XMM14=00000000'00000000'00000000'00000000  XMM15=00000000'00000000'00000000'00000000
00:00:07.852310 EFER         =0000000000000000
00:00:07.852312 PAT          =0007040600070406
00:00:07.852316 STAR         =0000000000000000
00:00:07.852318 CSTAR        =0000000000000000
00:00:07.852320 LSTAR        =0000000000000000
00:00:07.852322 SFMASK       =0000000000000000
00:00:07.852324 KERNELGSBASE =0000000000000000
00:00:07.852327 ***
00:00:07.852334 Guest paging mode:  Protected (changed 5 times), A20 enabled (changed 2 times)

これがテスト終了時のプロセッサのステータスです。

問題は、画面に文字が表示されないことです。これは、メモリに関連する問題である可能性があります (私はメモリ アドレッシングがあまり得意ではないことを認めなければなりません)、セグメント レジスタの内容が間違っているか、ビデオ メモリを順番に使用しようとしている方法に関連している可能性があります。その性格を示すために、しかしそれは何か他のものかもしれません。何が間違っていると思いますか?本当にありがとう!

更新 この問題は、メモリのアドレス指定に関連しています。ShowChar 命令は実行されません。ログファイルで確認しました。私が知っているのは、次の行まですべてが正しく実行されていることです。

jmp 08h:ShowChar

したがって、これは間違ったセグメント レジスタ、間違った GDTR、またはメモリ アドレッシングに関連する何かに関連している可能性があります。

更新 GDT をセグメントの代わりに線形アドレスに変更しました: オフセット 1 ですが、まだ文字が表示されません。問題は、GDT が正しいかどうかを確認できないため、問題の原因を特定できないことです。すべてのレジスターの内容を見ることができますが、GDTR (現時点では0000000000ff53f0:00e9) が正しいことをどのように知ることができますか? GDTが間違っているためにShowChar関数が実行されていないと仮定していますが、単なる仮定です。

4

5 に答える 5

5

問題は、キャラクターと属性を DX で使用できるようにするためのすべての作業にもかかわらず、次のことです。

mov bl, '.'
mov dl, bl          ; Get character
mov dh, CHAR_ATTRIB     ; the character attribute

ワード 63 をスクリーン バッファに書き込むことになります。

mov word [edi], 63      ; write to video display

これは、属性がゼロのクエスチョン マークです。つまり、黒の背景に黒のクエスチョン マークが表示されます。

于 2013-01-17T20:42:32.577 に答える
2

私はこれについてあまり経験がありませんが、...

GDT:
    dw StopGDT - StartGDT - 1
    dd StartGDT

これは「絶対」(seg:offs ではない) アドレスである必要はありませんか? セグメント 1000h でロードしたので、dd StartGDT + 10000hここにいるはずです。いいえ?

于 2013-01-17T22:32:08.977 に答える
1

これは、Qemu を使用して、保護された状態に切り替えて「X」を VGA に出力する実行可能な最小限のブートローダーです (ディスクを読み取る必要はありません)。

[org 0x7C00]

cli
lgdt [gdt_descriptor] 

; Enter PM
mov eax, cr0
or  eax, 0x1
mov cr0, eax

; 1 GDT entry is 8B, code segment is 2nd entry (after null entry), so
; jump to code segment at 0x08 and load init_pm from there
jmp 0x8:init_pm   


[bits 32]
init_pm :
    ; Data segment is 3rd entry in GDT, so pass to ds the value 3*8B = 0x10
    mov ax, 0x10
    mov ds, ax
    mov ss, ax
    mov es, ax
    mov fs, ax
    mov gs, ax

    ;Print a X of cyan color
    ;Note that this is printed over the previously printed Qemu screen
    mov al, 'L'
    mov ah, 3 ; cyan
    mov edx, 0xb8004
    mov [edx], ax      

    jmp $


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
[bits 16]

GDT:
;null : 
    dd 0x0 
    dd 0x0

;code : 
    dw 0xffff       ;Limit
    dw 0x0          ;Base
    db 0x0          ;Base
    db 0b10011010   ;1st flag, Type flag
    db 0b11001111   ;2nd flag, Limit
    db 0x0          ;Base

;data : 
    dw 0xffff       
    dw 0x0          
    db 0x0
    db 0b10010010 
    db 0b11001111 
    db 0x0

gdt_descriptor :
    dw $ - GDT - 1      ;16-bit size
    dd GDT              ;32-bit start address


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Bootsector padding
times 510-($-$$) db 0
dw 0xaa55

次に、次のようにします。

nasm boot.asm
qemu boot
于 2014-11-21T00:09:39.560 に答える
0

標準 VGA でビデオ メモリに書き込むには、データをメモリ アドレス0xb8000またはメモリ内のバイト 8000 に書き込みます。単純な白黒文字を実行するには、文字値と値を単純に OR して15 << 8、16 ビットの unsigned short を取得します。次に、これらの 16 ビットをそのメモリ位置に書き込み、文字を描画します。

于 2013-01-17T20:40:20.457 に答える
0

問題は、ORG ディレクティブの使用と、リアル モードとプロテクト モードのアドレッシング スキームを混同していることです。32ビットコードが実行されていないことについては正しいです。CPU がこのコードを実行すると、次のようになります。

jmp 08h:ShowChar

32ビットコードではなく、メモリの先頭にある、現在ロードされている割り込みベクトルテーブルのどこかにジャンプします。なんで?定義したコード セグメントのベースは 0 であり、アセンブラに 0 からの相対アドレスを解決するように指示したためです。

Org 0

したがって、CPU は、数値的に (0 + ShowChar コードの最初の命令のオフセット) (つまり、コード セグメント ベース + オフセット) に等しいアドレスに実際にジャンプしています。

この問題を修正するには、次を変更します。

Org 0

の中へ

Org 0x10000

次に、一致するようにセグメントレジスタを変更する必要がありますが、この場合、最初に設定したセグメントレジスタは、最初に指定したoriginディレクティブに対して正しくありませんでしたが、originディレクティブが上記のように変更されたときに有効であるため、それ以上の変更は必要ありません作られる。補足として、origin ディレクティブが正しくないという事実は、GDT アドレスがガベージのように見える理由を説明できます。実際には、lgdt 命令によってロードされた割り込みベクトル テーブルの一部であるためです。GDT パラメーター (「GTD」ラベル) へのポインターは、実際には割り込みベクター テーブルの先頭のどこかを指しています。

とにかく、上記のように origin ディレクティブを変更するだけで問題が解決するはずです。

ところで、あなたのコードはhttp://www.brokenthorn.com/Resources/OSDev8.htmlのコードと酷似しています。

特にhttp://www.brokenthorn.com/Resources/OSDev10.htmlのページの下部にあるデモ コード

面白い..

于 2015-01-03T12:01:04.840 に答える