假设我的API是从一个系统调用的,该系统可能只在实模式或大实模式下工作 . 我的API应该显示当前的系统模式 . 然后怎么知道当前模式是实模式还是大实模式?
注意:
在大实模式下, CR0 中的保护模式使能位被禁用,因此检查它没有任何区别 .
CR0
即使启用了A20地址线,也不意味着它处于大实模式 .
如果你执行这个:
mov ebx, 0x10000 mov al, [ebx]
并获得 #GP ,然后 DS 的段描述符的原始限制为0xFFFF,这是正常实地址模式和虚拟8086模式的情况 .
#GP
DS
如果没有从 mov al, [ebx] 获得 #GP ,则原始限制已扩展到0xFFFF以上(通常为0xFFFFFFFF,但不一定如此) .
mov al, [ebx]
顺便说一句,检查v86模式可以并且可能应该在尝试上述之前完成(如果主机操作系统没有正确反映处理程序的异常) . 执行 smsw 以获取 cr0.pe . 它将在v86模式下设置为1,在实际地址模式下设置为0 . 直接用 mov 读取 cr0 将在v86模式下生成 #GP ,这就是 smsw 是首选方法的原因 .
smsw
cr0.pe
mov
cr0
在大实模式下,实模式地址别名将失败 . 让我们假设你处于大实模式,你的DS值为0x6000 . 由于已重新加载DS的描述符缓存(大实模式的定义),因此DS:0的物理地址不是0x60000 . 如果使用另一个段寄存器命中0x60000,则该内存位置不同 .
所以这是一个食谱 . 在数据段中创建临时变量 . 注意它相对于DS的 offset . 使用DS-1的值加载ES,更改变量的值,并查看是否在ES处获得相同的值:( offset 0x10) . 为了防止误报,请做两次 .
offset
这不会检测虚拟86模式 . 此外,如果ES通过缓存的描述符指向高内存,那么当您重新加载ES时,这将丢失 . 确保调用者代码不依赖于ES保持不变 .
大的实模式本身并不是CPU模式 - 没有寄存器位表示“我们现在处于大的实际状态” . 它只是一种使用香草实模式的i386特定逻辑访问高内存的方法 . 上述程序仅检查DS是否已按此方式处理;根据实现,DOS扩展器可能已经通过ES描述符重新加载实现了大的真实,同时保留了DS vanilla . 维基百科说,有时甚至CS也会以这种方式出现混淆,尽管由于中断,这是一个棘手的提议 .
在90年代早期,我们使用一种未记录的方法让我们在REAL模式下访问4Gig(现在可称为BIG REAL MODE) . 方法是进入保护模式,将粒度位更改为1(表示4K粒度而不是1字节粒度)然后返回实模式并将所有段寄存器设置为0.然后可以使用ebx等访问4Gig的内存 .
因此,如果您正在讨论这个问题,请尝试进入保护模式并检查粒度位的设置 . 对不起,我所有的旧手册都在阁楼里 . 如果您需要这些信息,我可以将它们挖出来 .
3 回答
如果你执行这个:
并获得
#GP
,然后DS
的段描述符的原始限制为0xFFFF,这是正常实地址模式和虚拟8086模式的情况 .如果没有从
mov al, [ebx]
获得#GP
,则原始限制已扩展到0xFFFF以上(通常为0xFFFFFFFF,但不一定如此) .顺便说一句,检查v86模式可以并且可能应该在尝试上述之前完成(如果主机操作系统没有正确反映处理程序的异常) . 执行
smsw
以获取cr0.pe
. 它将在v86模式下设置为1,在实际地址模式下设置为0 . 直接用mov
读取cr0
将在v86模式下生成#GP
,这就是smsw
是首选方法的原因 .在大实模式下,实模式地址别名将失败 . 让我们假设你处于大实模式,你的DS值为0x6000 . 由于已重新加载DS的描述符缓存(大实模式的定义),因此DS:0的物理地址不是0x60000 . 如果使用另一个段寄存器命中0x60000,则该内存位置不同 .
所以这是一个食谱 . 在数据段中创建临时变量 . 注意它相对于DS的
offset
. 使用DS-1的值加载ES,更改变量的值,并查看是否在ES处获得相同的值:(offset
0x10) . 为了防止误报,请做两次 .这不会检测虚拟86模式 . 此外,如果ES通过缓存的描述符指向高内存,那么当您重新加载ES时,这将丢失 . 确保调用者代码不依赖于ES保持不变 .
大的实模式本身并不是CPU模式 - 没有寄存器位表示“我们现在处于大的实际状态” . 它只是一种使用香草实模式的i386特定逻辑访问高内存的方法 . 上述程序仅检查DS是否已按此方式处理;根据实现,DOS扩展器可能已经通过ES描述符重新加载实现了大的真实,同时保留了DS vanilla . 维基百科说,有时甚至CS也会以这种方式出现混淆,尽管由于中断,这是一个棘手的提议 .
在90年代早期,我们使用一种未记录的方法让我们在REAL模式下访问4Gig(现在可称为BIG REAL MODE) . 方法是进入保护模式,将粒度位更改为1(表示4K粒度而不是1字节粒度)然后返回实模式并将所有段寄存器设置为0.然后可以使用ebx等访问4Gig的内存 .
因此,如果您正在讨论这个问题,请尝试进入保护模式并检查粒度位的设置 . 对不起,我所有的旧手册都在阁楼里 . 如果您需要这些信息,我可以将它们挖出来 .