当处理器尝试访问不存在的物理地址时会发生什么?

时间:2014-02-17 04:33:29

标签: assembly x86

想象一下32位x86计算机,内存少于3千兆字节,CPU设置为禁用分页和平面段描述符(0x0为基础,0xffffffff作为数据和码)。

当ring0中的指令尝试使用mov指令引用未被任何内存地址支持的物理地址时会发生什么?

QEMU模拟只是停顿了一个错误,比如“致命:试图在RAM或ROM外部执行代码”。

这些例外与内存问题有关:

  1. 它不应该是“段不存在(#NP)”:它只在加载段寄存器时发生,但我实际上可以毫无问题地加载扁平段。
  2. 不应生成“堆栈错误(#SS)”,因为代码不引用堆栈。
  3. “一般保护(#GP)”不应该发生,因为代码在ring-0中运行,并且段设置为允许访问每个物理地址。
  4. 分页已被禁用,因此它也不是“页面错误(#PF)”。
  5. 并且它不是对齐问题,因此不应触发“对齐检查(#AC)”。
  6. 我的选项用完了,我不知道会发生什么。

3 个答案:

答案 0 :(得分:3)

我的理解是非分页内存访问直接进入总线,导致未定义的行为(取决于芯片组,总线类型等) - 参见Manual Probing

  

注意:尝试读取/写入不存在的内存时永远不会出现错误 - 这一点很重要:您不会获得有效的结果,但也不会出现错误。

答案 1 :(得分:2)

如果禁用分页且当前分段的限制为4GiB(在32位模式下),则没有“不存在”的地址:

在这种情况下,所有2 ^ 32个可能的地址都可以读取和写入。

如果对没有RAM,ROM等的地址进行读写操作,会发生什么情况取决于CPU外部的硬件而不是CPU本身。

通常会忽略对此类地址的写操作,读取操作通常会产生非感测值(在大多数PC上,“全1”值如0xFF,0xFFFF,0xFFFFFFFF)。

理论上,这样的地址访问可能会导致中断甚至导致计算机崩溃,具体取决于地址。但是,这不是由CPU本身完成的,而是由其他硬件组件完成的。

在这样的地址上执行代码基本上只是来自该地址的读访问。

答案 2 :(得分:0)

据我记得,这可能是Page Fault中断(向量位置14)。

"寻呼"这是一个广义的术语,任何内存访问仍然会产生该错误。但是,虚拟主机可能不知道如何正确处理它。

至少我假设你实现了所有的异常向量,所以如果发生任何一个异常,你会得到一条消息,日志,它出错了吗?这就是我要做的。直接在输出缓冲区(D800:0000?)中写一条消息将是最有帮助的。只需在那里复制一个字符串,模拟器应该最终在控制台中显示它。

例外情况在我手册中的6.4.1中,它在"中断或异常处理程序的调用和返回操作"下。这应该是客人应该做的最有帮助的(但在实践中......)

考虑到这一点,并不是不可能这样的"坏"将错误报告给运行guest虚拟机的主机而不是guest虚拟机本身。如果你无法确定,有一种可能性就是让你直接使用该代码启动你的计算机并查看CPU在这种情况下的作用......(假设你有所有例外的处理程序,你应该得到那么一个明确的答案。)

实际上,我发现了一篇你可能感兴趣的文件:

http://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-vol-3b-part-2-manual.pdf

请看第20.3章。这些都是关于x86仿真情况下的中断。答案是:处理器将异常发送到virtual-8086监视器,然后IT必须将其转发给您。如果他们不这样做,那么......你无能为力。也许您的模拟器可以选择帮助您吗?

  

因为它被设计为在8086处理器上运行,所以在虚拟8086模式任务中运行的8086程序包含一个8086样式的中断向量表,该表从线性地址0开始。如果virtual-8086监视器正确指示中断或异常向量回到它来自的虚拟8086模式任务,8086程序中的处理程序可以处理中断或异常。 virtual-8086监视器必须执行以下步骤才能将中断或异常发送回8086程序:

     
      
  1. 使用8086中断向量在8086程序中断表中找到适当的处理程序。

  2.   
  3. 在特权级别3堆栈上存储8086程序的EFLAGS(仅16位低位),CS和EIP值。这是virtual-8086模式任务正在使用的堆栈。 (8086处理程序可以使用或修改此信息。)

  4.   
  5. 更改权限级别0堆栈上的返回链接以指向权限级别3处理程序。

  6.   
  7. 执行IRET指令将控制权传递给8086程序处理程序。

  8.   
  9. 当来自特权级别3处理程序的IRET指令触发一般保护异常(#GP)并因此有效地再次调用virtual-8086监视器时,将特权级别0堆栈上的返回链接恢复为指向原始的,中断的,特权级别3的程序。

  10.   
  11. 将EFLAGS映像的低16位从特权级别3堆栈复制到特权级别0堆栈(因为某些8086处理程序会修改这些标志以将信息返回到导致中断的代码)。

  12.   
  13. 执行IRET指令将控制权传递回中断的8086程序。   请注意,如果操作系统打算支持所有基于8086 MS-DOS的程序,则必须使用程序随附的实际8086中断和异常处理程序。这样做的原因是某些程序修改自己的中断向量表以替换(或挂钩)它们自己的专用中断和异常   处理程序。

  14.   

P.S。这是x86特有的。请注意,当我使用6502访问不存在的内存时,我只会得到垃圾。没有更多......