装配中的实验操作系统 - 无法在屏幕上显示字符(pmode)

ali*_*ali 2 memory video assembly operating-system bootloader

我希望这里有一些经验丰富的汇编/操作系统开发人员,即使我的问题不是很大.我正在尝试使用汇编并创建一个小型操作系统.事实上,我想要的是一个启动加载器和第二个启动加载器,它激活pmode并在屏幕上显示一个字符,使用视频内存(显然没有中断).我正在使用VirtualBox来模拟代码,我在VHD磁盘中手动粘贴(两个代码段)

首先,我的代码:

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
Run Code Online (Sandbox Code Playgroud)

boot2.asm
这是第二个引导加载器,粘贴在第二个扇区(接下来的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
Run Code Online (Sandbox Code Playgroud)

因此,我编译此代码并将二进制文件粘贴到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)
Run Code Online (Sandbox Code Playgroud)

因此,这是测试结束时处理器的状态.

问题是,我无法在屏幕上看到这个角色.这可能是一个与内存有关的问题(我必须承认我不太擅长内存寻址),比如段寄存器中的错误内容,或者它可能与我尝试按顺序使用视频内存的方式有关显示该角色,但它可能是其他东西.你觉得怎么了?非常感谢!

更新 问题与内存寻址有关.ShowChar指令未执行.我在日志文件中验证了它.我所知道的是,一切都在这一行上正确执行:

jmp 08h:ShowChar
Run Code Online (Sandbox Code Playgroud)

因此,这可能与错误的段寄存器,错误的GDTR或与存储器寻址有关的其他内容有关.

更新 我改变GDT,是一个线性地址而不是一个段:偏移一个,但仍然没有看到该字符.问题是我无法找出问题的根源,因为我无法验证GDT是否正确.我可以看到所有寄存器的内容,但我怎么知道GDTR(目前是哪个0000000000ff53f0:00e9)是正确的?我只是假设由于错误的GDT而没有执行ShowChar函数,而只是一个假设.

Ant*_*nko 5

问题是,尽管您在DX中使用角色和属性的所有工作:

mov bl, '.'
mov dl, bl          ; Get character
mov dh, CHAR_ATTRIB     ; the character attribute
Run Code Online (Sandbox Code Playgroud)

你最终将第63个字写入屏幕缓冲区:

mov word [edi], 63      ; write to video display
Run Code Online (Sandbox Code Playgroud)

这是与零个属性的问号,即上问号黑色背景.

  • 您可以在编写字符时(或之后或之前)插入"系统复位"序列(outb 0xfe到端口0x64):如果机器重新启动,您将知道已达到此代码,即至少您的CS是对. (2认同)