高中的时候,有次我看到《30 天自制操作系统》这本书,是个日本老哥写的,岛国人们的科技树和西方的科技树点的总不太一样,这本书点亮后的第一件事就是画鼠标、画桌面、画窗口,这其实都还好,最邪恶的是这本书用的工具链全是作者魔改的,但是提供了 windows 版本(这一点值得好评)。当时就跟了他学了一点输出字符就没有继续下去了(这古书写的还是为软盘启动设计的)。虽然但是,开发操作系统之路就从此开始了。
来自旧世代的记录
这里本来是记的一些古早时期开发操作系统(其实主要就是写汇编和 bootloader)时的零碎问题,单留着看着感觉东一点西一点的,就和新的文章并在一起了。
MBR 程序在 bochs 可以正常运行但是在 VMware 中表现异常
经尝试后大致推测原因为没有设定 SS
和 SP
的值,导致 ret
时 IP
寄存器被被赋予了未定义的值。但是此问题在 bochs 中并没有表现出来。
ret 返回到了一个错误的地址
当时程序表现为引导程序持续重启,后调试发现某次 ret
后跳转至了内存 0x81e9
处,而此地址不在引导程序的范围内。检查堆栈发现此程序使用 0x7c00
作为栈底,0x81e9
恰好于程序头两个字节一致。最后检查代码发现实为原本应该用 call
的地方误用了 jmp
,导致 ret
时发生错误。
《30天自制操作系统》中为何引导程序要跳转至 0xc200 处
起初简单认为是某个约定的值,但在自己实践时始终无法成功跳出 MBR 进入后续部分。后来我认为是书中所使用的镜像制作工具有特殊操作导致的,但经实验被证否,使用 WinImage 和书中的程序是可以正常运行的。了解 FAT12 文件系统的结构后发现其数据区从偏移 0x4200
处开始,而且数据被从头开始加载至 0x8000
处,两者叠加就有了 0xc200
。若直接将软盘 0x4200
偏移处的数据加载至 0x8000
处,则直接 jmp 0x8000
就可以了。
使用 BIOS 的 int 0x15 0xe820 获取内存结构失败
这里的失败不是中断按照约定返回了一个错误码,而是导致程序不正常运行或给出了不正常的数据。经过多次试验,现发现当 ES:DI
指向的缓冲区在当前程序数据内,且偏移小于 0xff
时(即使通过变换段寄存器的值使 DI
的值大于等于 0xff
也会失败),就会根据 DI
的具体数值触发诸如宕机,在 BIOS 代码内死循环,底端内存被全部覆写为 0x8a
,返回数据为乱码等问题。导致此情况的原因未知。最后采用将数据段置于代码段之后(拉高偏移值)的方法。