记一次操作系统还原实操问题
在跟随《操作系统真象还原》进行实际操作时,遭遇了一个非常奇怪的问题。
问题现象是以下两段代码会导致不一样的结果
第一段代码,在后面实现了用户进程地址空间后,程序会跑飞
相关代码如下:
|
|
以及
|
|
这两端代码都是为了加载中断描述符表,但是只有第二种写法能正常运行,第一种不行。
两段代码实际运行时得到的idt_operand
值是相同的。直观上从代码上已经看不出端倪了。
如图所示,第一个代码中计算得到的idt_operand值为0x8320017f
,高4字节是0,按照IDTR寄存器指令的要求: lidt 48位内存地址
, 低16位是IDT界限(此处为0x017f=0x30*8-1),高32位为IDT的线性地址(此处为0x00008320),可以看见这个线性地址是在1MB空间内的,在内核执行过程中没有任何问题(内核寻址3GB以上1MB空间与1MB线性空间映射到相同的低1MB物理地址空间)。可是当加载用户空间代码时,会进行切页操作,切换页表后,新的线性地址空间的低1MB空间不在映射到3GB空间以上了,因此在执行用户空间代码时,一旦有中断发生,CPU会发现原先的LIDT加载的地址不再可用了,因此服务异常。
这里再说一下为什么第二种代码可以,第二种代码里面idt_operand的值实际为0xc0008320017f
,可以看见其值在3GB空间以上,这里也可以在gdb中打印看出。
这里的疏忽在于我当前实现的简易操作系统,其支持打印函数是32位,因此不容易发现这个问题