[英]“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.