Memory 组装中的实验操作系统-can';t在屏幕上显示字符(pmode)

Memory 组装中的实验操作系统-can';t在屏幕上显示字符(pmode),memory,video,assembly,operating-system,bootloader,Memory,Video,Assembly,Operating System,Bootloader,我希望这里有一些经验丰富的汇编/os开发人员,即使我的问题不是很大。 我正在尝试使用汇编并创建一个小型操作系统。事实上,我想要的是一个引导加载程序和第二个引导加载程序,它激活pmode并在屏幕上显示一个字符,使用视频内存(显然不是中断)。 我正在使用VirtualBox模拟代码,我将其手动粘贴到VHD磁盘中(两段代码) 首先,我的代码: boot.asm 这是第一个引导加载程序 boot2.asm 这是第二个引导加载程序,粘贴在第二个扇区上(下一个512字节) 因此,我编译这段代码并将二进制文件

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

首先,我的代码:

boot.asm
这是第一个引导加载程序

boot2.asm
这是第二个引导加载程序,粘贴在第二个扇区上(下一个512字节)

因此,我编译这段代码并将二进制文件粘贴到VHD中,然后在虚拟机上运行系统。我可以看到它正确地进入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(目前是
0000000000 FF53F0:00e9
)是正确的?我只是假设ShowChar函数不是因为错误的GDT而执行的,而是一个假设。

要在标准VGA中写入视频内存,需要将数据写入内存地址
0xb8000
或内存中的字节8000。要简单地执行简单的黑白字符或使用值
15的字符值,问题是,尽管您在DX中进行了所有使字符和属性可用的工作:

mov bl, '.'
mov dl, bl          ; Get character
mov dh, CHAR_ATTRIB     ; the character attribute
最后将word 63写入屏幕缓冲区:

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

这是一个具有零属性的问号,即黑色背景上的黑色问号。

我对此不是很有经验,但是。。。


这不需要是一个“绝对”(而不是seg:offs)地址吗?既然您在段1000h处加载了它,我希望
dd StartGDT+10000h
就在这里。否?

这是一个可行的最低限度引导加载程序,它可以切换到受保护状态,并使用Qemu将“X”打印到VGA(因此无需读取磁盘)

然后,做:

nasm boot.asm
qemu boot

问题在于您使用ORG指令,并且混淆了实模式和保护模式寻址方案。您的32位代码没有被执行是正确的。当CPU执行此代码时:

jmp 08h:ShowChar
它跳转到当前加载的中断向量表中的某个位置,在内存的开头,而不是32位代码。为什么?因为您定义的代码段的基是0,并且您告诉汇编器解析相对于0的地址:

Org 0
因此,CPU实际上跳转到一个地址,该地址的数值等于(0+ShowChar代码的第一条指令的偏移量)(即代码段基+偏移量)

要纠正此问题,请更改:

Org 0
进入

然后您需要更改段寄存器以匹配,但在这种情况下,您最初设置的段寄存器对于您最初指定的origin指令不正确,但在origin指令如上所述更改时有效,因此无需进行进一步更改。作为旁注,origin指令不正确的事实可以解释为什么GDT地址看起来是垃圾——因为它实际上是由lgdt指令加载的中断向量表的某个部分。指向GDT参数(“GTD”标签)的指针实际上指向中断向量表开头的某个地方

无论如何,只需如上图所示更改origin指令就可以解决问题

顺便说一句,您的代码看起来与上面的代码非常相似

特别是在第页底部提供的演示代码


有趣..

好的。CHAR_ATTRIB为63(浅蓝色背景上的白色文本),但结果相同。首先,我不知道如何测试ShowChar是否被访问和执行。在实模式下,用int 10h测试它很容易,但在保护模式下就不那么容易了。现在你甚至不用
CHAR\u ATTRIB
(也就是说,你把它放在
dh
,但不使用
dx
)。您是否尝试使用
MOV-WORD[EDI],DX
而不是
MOV-WORD[EDI],63
?那么请编辑这个问题。真傻!当然,1字节代表字符,1字节代表颜色。现在,我还是看不到这个角色。正如我所说,我想验证并确保ShowChar指令被执行。我觉得这可能与不正确的寻址有关,或者我需要一些
out
指令来显示字符。我可以通过填充一些寄存器来测试它,并在日志文件中查看它。问题是我没有正确调用ShowChar函数。您可以插入“系统重置”序列(outb 0xfe到端口0x64),而不是(或在写入字符之后或之前):如果机器重新启动,您将知道此代码
nasm boot.asm
qemu boot
jmp 08h:ShowChar
Org 0
Org 0
Org 0x10000