简体   繁体   English

切换到保护模式后的“通话”

[英]“call” after switching to Protected Mode

I'm trying to switch to the protected mode in intel x86. 我正在尝试在Intel x86中切换到保护模式。

I've loaded my gdt with lgdt, set the P flag of cr0 to 1 and all the segments selectors but when I return from the function call, I can't call any other function or I get this error 我已经用lgdt加载了gdt,将cr0的P标志设置为1以及所有的段选择器,但是当我从函数调用中返回时,我无法调用任何其他函数,否则会出现此错误

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

Here is my switch_to_pmode function: 这是我的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

And my calls 还有我的电话

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

Thank you 谢谢

You need to make sure the assembler translates the code following the protected mode switch as 32 bit code, with a .code32 (or use32 in nasm) directive. 您需要确保汇编程序使用.code32 (或nasm中的use32 )指令将保护模式切换后的代码转换为32位代码。

Additionally your return address after your protected mode routine is no longer valid. 此外,保护模式例程之后的寄信人地址不再有效。 You cant really return to anything after that. 在那之后,您真的无法返回任何内容。 Instead set esp to something useful and go on. 而是将esp设置为有用的东西,然后继续。

A move to CR0 that sets or clears PE must be immediately followed by a far jump to reload the PC, and then you must reload %esp as well as all the segment registers. 移至设置或清除PE的CR0之前,必须立即跳远以重新加载PC,然后必须重新加载%esp以及所有段寄存器。 You need to do all of this before you touch the stack or enable interrupts. 您需要先完成所有这些操作, 然后再触摸堆栈或启用中断。 And (as drhirsch says) it's impossible to return from this operation, even if you pop the return address off before you invalidate the real-mode stack, because the return address is a real-mode address. (正如drhirsch说)这是不可能从这一操作中返回 ,即使你去歇你无效实模式栈之前的返回地址,因为返回地址是实模式地址。

You appear to be trying to use lret to reload the PC and simultaneously re-enable interrupts, but that won't work, because the stack pointer is invalid. 您似乎正在尝试使用lret重新加载PC并同时重新启用中断,但这将不起作用,因为堆栈指针无效。 Correct code would look something like this: 正确的代码如下所示:

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

You should read Intel's system programming guide , particularly chapter 9 (machine initialization), especially section 9.9, which describes in detail how to do a protected mode switch. 您应该阅读英特尔的系统编程指南 ,特别是第9章(机器初始化), 尤其是 9.9节,其中详细介绍了如何进行保护模式切换。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM