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

9
想象一台32位x86计算机,内存不到3GB,CPU设置为禁用分页和平面段描述符(基地址为0x0,数据和代码的有效限制均为0xffffffff)。
当ring0中的指令尝试使用mov指令引用未被任何内存地址支持的物理地址时会发生什么?
QEMU仿真会出现错误,如“fatal: Trying to execute code outside RAM or ROM”。
这些异常与内存问题有关:
1.它不应该是“Segment Not Present (#NP)”,因为只有在加载段寄存器时才会发生,但我实际上可以加载平面段而没有问题。
2.“Stack Fault (#SS)”不应该生成,因为代码不引用堆栈。
3.由于代码正在ring-0中运行,并且段被设置为允许访问每个物理地址,因此不应该发生“General Protection (#GP)”。
4.分页已禁用,因此也不是“Page Fault (#PF)”。
5.它不是对齐问题,因此不应触发“Alignment Check (#AC)”。
我已经没有其他选择了,我不知道应该发生什么。

你的编程问题是什么?从编程角度来看,正确的答案是“不要那样做”。 - Raymond Chen
请注意,物理地址空间包括设备具有其MMIO寄存器的MMIO区域。例如,在PC上通常在768MiB和1GiB之间,如果我没记错的话。以及ROM。因此,“不存在的物理地址”表示不是RAM、ROM或MMIO。 - Peter Cordes
2个回答

6
如果禁用分页并且当前段的限制为4GiB(在32位模式下),则不存在“不存在”的地址:
在这种情况下,所有2 ^ 32个可能的地址都存在,并且可以读取和写入。
如果在没有RAM,ROM等位置的地址进行读取或写入操作,则取决于CPU外部的硬件而不是CPU本身。
向此类地址的写操作通常会被忽略,读操作通常会导致一个无意义的值(在大多数PC上是“全部为1”的值,如0xFF,0xFFFF,0xFFFFFFFF)。
从理论上讲,这样的地址访问可能会导致中断甚至崩溃计算机,具体取决于地址。但是,这并不是由CPU本身完成的,而是由其他硬件组件完成的。
在该地址上执行代码基本上仅相当于从该地址读取访问。

读取“无意义的值”是计算机在启动时如何确定安装了多少内存的方式... - Kerrek SB
1
@KerrekSB:要检查给定地址是否为RAM,您需要向RAM写入一个值并读回该值。为了确保,您还应该使用不同的值进行此操作。但是,无法确定某个地址是否包含ROM(包含值为0xFF的字节)或仅为空! - Martin Rosenau
@MartinRosenau:这是我使用_int 15h/AX=E820h_(如果需要,可以回退到AX=E802h/8800h)来映射内存并在进入保护模式之前找到可用的RAM的原因之一。另外,ROM中的BIOS扩展(1mb以下和A000:0000以上)可以通过扫描2kb块的内存查找前两个字节中的0x55、0xAA来发现。如果找到,则第三个字节将包含BIOS扩展消耗的512字节块数。 - Michael Petch
我认为这取决于CPU的实现方式。根据8086数据手册,有一个READY信号,它是从被寻址的内存或I/O设备发出的确认信号,表明它将完成数据传输。 - youfu

5

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

注意:尝试读写不存在的内存时,您永远不会收到错误提示--这一点很重要:您将不会获得有效结果,但也不会收到错误提示。


根据硬件设计,这可能是真实的也可能不是。一些处理器可能没有在传入数据总线上的同步器,并且可能依赖于外部硬件来确保总线状态在被采样时不会改变。如果总线处于浮动状态,并且恰好在错误的时间发生了变化,可能会导致相当“有趣”的后果,其中最少惊人的可能是在基于读取值设置或清除标志的架构上,标志可能与报告的值不一致。 - supercat

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接