切换到保护模式后“呼叫”

Posted

技术标签:

【中文标题】切换到保护模式后“呼叫”【英文标题】:"call" after switching to Protected Mode 【发布时间】:2012-02-06 17:08:45 【问题描述】:

我正在尝试在 intel x86 中切换到保护模式。

我已经用 lgdt 加载了我的 gdt,将 cr0 的 P 标志设置为 1 和所有的段选择器,但是当我从函数调用返回时,我不能调用任何其他函数或者我得到这个错误

qemu: fatal: Trying to execute code outside RAM or ROM at 0xfeeb7c5b

这是我的 switch_to_pmode 函数:

gdtr:
.short      23  // limit
gdtr_base:
.long       0   // base

switch_to_pmode:
    movl $null_segment, %eax        // Address of the first byte of the GDT
    movl %eax, gdtr_base

    cli             // disable interrupts

    lgdt (gdtr)

    movl %cr0, %eax
    or $0x1, %eax
    movl %eax, %cr0         // Set the PE flag

    push $0x8
    push $reload_segments
    lret

reload_segments:
    movl $0x10, %eax
    movl %eax, %ds
    movl %eax, %ss
    movl %eax, %es
    movl %eax, %fs
    movl %eax, %gs

    ret

foo:
    ret

还有我的电话

_start:
    call switch_to_pmode
    call foo // <----- Ouch!

谢谢

【问题讨论】:

【参考方案1】:

您需要确保汇编器使用.code32(或nasm 中的use32)指令将受保护模式开关后的代码转换为32 位代码。

此外,您在受保护模式例程之后的返回地址不再有效。在那之后你不能真正回到任何东西。而是将 esp 设置为有用的东西并继续。

【讨论】:

【参考方案2】:

必须立即移动到设置或清除 PE 的 CR0,然后进行远跳转以重新加载 PC,然后您必须重新加载 %esp 以及所有段寄存器。您需要在触摸堆栈或启用中断之前完成所有这些操作。。并且(正如 drhirsch 所说)不可能从该操作中返回,即使您在使实模式堆栈无效之前弹出返回地址,因为返回地址是实模式地址。

您似乎正在尝试使用lret 重新加载 PC 并同时重新启用中断,但这不起作用,因为堆栈指针无效。正确的代码如下所示:

switch_to_pmode:
    # ... what you have ...

    movl %eax, %cr0
.code32
    ljmpl reload_segments

reload_segments:
    # ... what you have ...
    movl $pm_stack, %esp
    sti # perhaps

    # and then just go on with your startup code here
    call foo

您应该阅读 Intel 的 system programming guide,尤其是第 9 章(机器初始化),尤其是第 9.9 节,其中详细描述了如何进行保护模式切换。

【讨论】:

AFAIK 只要不执行远跳转,CPU 仍然在实模式下工作。我读了push $8; push reload_segments; retl 作为执行远跳的创造性方式。但是您描述的方式是规范的方式,并且以这种方式工作可靠。 很有创意,但不保证能正常工作——架构手册上说的很清楚:“紧跟MOV CR0指令,执行far JMP或far CALL指令……可能会出现随机故障如果在 [这些指令] 之间存在其他指令。” (强调我的)(Intel® 64 and IA-32 Architectures Software Developer’s Manual Volume 3: System Programming Guide,第 9.9 节)

以上是关于切换到保护模式后“呼叫”的主要内容,如果未能解决你的问题,请参考以下文章

GRUB 是不是切换到保护模式?

什么是linux 保护模式

Linux 0.11-进入保护模式-07

引导加载程序 - 将处理器切换到保护模式

《80X86汇编语言程序设计教程》十 实模式与保护模式的切换实例

在loader程序中涉及到的CPU模式切换