我正嘗試使用lret指令從ring0切換到ring3。因此,我爲ss,esp,cs,ip推送正確的值,並使用lret。在x86中從ring0切換到ring3時出錯
我用QEMU和gdb調試代碼,並發現一件奇怪的事情:
LRET instrunction後,處理器成功地切換到環3(我用「信息登記」的QEMU來檢查),值ss,cs,esp都是正確的,並且eip指向ring3代碼的第一條指令。
但是,不管是什麼環3代碼的第一個指令是(甚至NOP指令),QEMU將重新啓動(可能是一般保護性錯誤?)
下面是代碼,頭文件是從this repo。自舉程序將CPU切換到保護模式,並將內核加載到0x100000,內核的虛擬地址從0x80100000開始。
#include "memlayout.h"
#include "mmu.h"
#include "asm.h"
.text
.globl _start
_start = V2P_WO(entry)
.globl entry
entry:
mov %cr4, %eax
or $(CR4_PSE), %eax
mov %eax, %cr4
mov $(V2P_WO(pgdir)), %eax
mov %eax, %cr3
mov %cr0, %eax
or $(CR0_PG|CR0_WP), %eax
mov %eax, %cr0
lgdt gdtdesc
mov $0x28, %ax
ltr %ax
mov $kernel_stack, %esp
push $0x23
push $user_stack
push $0x1b
push $user_task
lret
user_task:
nop
die:
jmp die
.data
.align 4096
tss:
.long 0
.long kernel_stack
.word 0x10, 0
.long 0, 0, 0, 0
.long pgdir
.long 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
.long 0, 0, 0, 0, 0, 0, 0, 0
gdt:
SEG_NULLASM
SEG_ASM(STA_X|STA_R, 0x0, 0xffffffff) # code seg
SEG_ASM(STA_W, 0x0, 0xffffffff) # data seg
SEG_ASM_USER(STA_X|STA_R, 0x0, 0xffffffff)
SEG_ASM_USER(STA_W, 0x0, 0xffffffff)
.word 0, 0x1000
.byte 0x10, 0x89, 0x80, 0x80
gdtdesc:
.word (gdtdesc - gdt - 1)
.long gdt
.align 4096
pgdir: .long PTE_P|PTE_W|PTE_PS
.fill 511, 4
.long PTE_P|PTE_W|PTE_PS
.fill 511, 4
.fill 4096
kernel_stack:
.fill 4096
user_stack:
向我們展示您的代碼和全局描述符錶轉儲。我不知道如何使用/打開Qemu中的功能,但在[Bochs emulator](http://bochs.sourceforge.net/)中,調試界面有**指令跟蹤**(http:///bochs.sourceforge.net/doc/docbook/user/internal-debugger.html).. – xmojmr 2014-11-01 08:34:04