在x86上,启用分页是否会导致“无条件跳转”(因为EIP现在是虚拟地址)?

时间:2015-06-22 05:37:11

标签: x86 cpu paging

通过将CR0中的分页位设置为1来启用分页时,所有指针(包括EIP)现在都被解释为虚拟地址而不是物理地址。除非CPU当前正在执行的内存区域是“身份映射”(虚拟地址映射到相同的物理地址),否则这似乎会导致CPU执行相当于“无条件跳转”的操作 - 它应该从不同的(物理)地址开始执行代码。

这实际发生了吗?看起来让操作系统启动代码可靠地运行这种行为是非常棘手的。或者所有保护模式操作系统身份映射他们自己的内核代码?

3 个答案:

答案 0 :(得分:3)

这不需要完整的身份地图;例如,Linux一旦完成运行就会完全丢弃启动代码。相关代码位于pmjump.S,其中使用平面模式(32位身份映射),并在启用保护模式后立即执行跳转。值得注意的是,由于切换到32位模式,跳转以机器代码形式写入。从那里,它通过startup_32继续设置页面表。我不确定是否完全需要状态更改后的无条件跳转(例如,32-bit real mode是一种无计划的副作用,即不按预期执行此类操作)。

答案 1 :(得分:3)

是和否

,在非正式意义上,因为现在MMU执行从虚拟地址到线性地址的转换,并且因为CPU获取虚拟地址。如果我们在地址4000h执行指令时打开分页,假设下一条指令位于4003h,则4003h可能会转换为8003h,因此实际上会进行跳转4000h8003h。因此,我们必须映射我们当前正在执行的页面,或者我们不知道CPU将从何处执行代码。

,从技术意义上说这不是跳转,因为CPU没有看到任何带有所有副作用的跳转指令(比如丢弃OoO指令),而且CPU只能在访问内存之后错过整个缓存层次结构意味着即使页面映射到不同的地址,您仍然可以执行4003h的指令。

那么,我们需要或不需要身份图吗?

是的,我们需要它。不是完整的身份地图,我通常只会(身份)映射第7页和第8页(对应于线性范围7000h-8fffh)。

比较启用分页和启用保护模式,您可以看到它们有多么不同。分页立即生效,因此您需要创建所有页面表 之前激活它,并且您需要至少一个身份页来处理当前运行的代码而不依赖于缓存。
相反,启用保护模式更容易"您甚至可以在输入保护模式后创建 GDT条目,您可以通过更改细分来控制何时首次使用它注册(通常CS跳转)。

实际上,如果您知道自己在做什么(例如通过复制代码或使用某些硬件内存别名),那么您并不需要严格需要身份页面,但这在一般情况下是非常特定于上下文的无用的复杂。

答案 2 :(得分:0)

经验答案:在此最小分页示例上注释掉分页标识映射设置:https://github.com/cirosantilli/x86-bare-metal-examples/blob/24988411adf10cf9f6afd1566e35472eb8ae771a/paging.S#L79并观察操作系统中断。所以,是的,#跳跃"。