这是演示os内核基本功能的代码的一部分。
在刷新GTD并设置IDT后,我想切换到ring 3运行一些int和context switch。
但是我无法跳转到用户模式。我想用iret
指令来使用技巧。据我所知,iret
将弹出
从堆栈跟随值:SS ESP EFLAGS CS EIP
所以想法是将适当的值推送到堆栈(使用新的段选择器),
并让iret
在寄存器中设置值。这是我正在使用的代码:
.equ NULL_DESCRIPTOR, 0x0000000000000000
.equ CODE_P3, 0x40C3FA000000D090
.equ DATA_P3, 0x40C3F2000000D090
.equ CODE_KERNEL, 0x00CF9A000000FFFF
.equ DATA_KERNEL, 0x00CF92000000FFFF
GDT:
.quad NULL_DESCRIPTOR
.quad CODE_P3 #0x08
.quad DATA_P3 #0x10
.quad CODE_KERNEL #0x18
.quad DATA_KERNEL #0x20
_GDT:
.word 39
.long GDT
.global flushGDT
.type flushGDT, @function
flushGDT:
cli
lgdt _GDT
xor %eax, %eax
#Data segment setup
mov $0x10, %ax
mov %ax, %ds
mov %ax, %gs
mov %ax, %fs
mov %ax, %es
#Stack save
mov %esp, %eax
#stack setup for iret and user space return
pushl $0x10
pushl %eax
pushf
#enable ints after switch to ring 3
pop %eax
or $0x200, %eax
push %eax
#CS selector
pushl $0x08
pushl $0x60 #Address of .leave (I have written proper ld script and checked with objdump)
iret
.section .upper_code, "ax", @progbits
.leave:
hlt
call upperKernelCode
问题在于iret
开始执行此指令后检查选择器的权限级别并且代码是perforem,因此结果CPU故障和重置。
这是日志形式BOCHS:check_cs(0x0008): non-conforming code seg descriptor dpl != cpl, dpl=3, cpl=0
。我将非常感谢您对此问题的任何帮助
答案 0 :(得分:2)
正如bochs告诉你的那样,你的选择器0x08
有CPL=0
但描述符条目有DPL=3
。请记住,选择器的两个最低有效位是CPL
。因此,要切换到ring3,您应该使用0x0b
。