【发布时间】:2014-12-28 12:17:57
【问题描述】:
我正在尝试使用 lret 指令从 ring0 切换到 ring3。因此,我为 ss、esp、cs、ip 推送正确的值,并使用 lret。
我用qemu和gdb调试这段代码,发现一个奇怪的东西:
lret指令后,处理器成功切换到ring3(我使用qemu中的“info registers”检查),ss,cs,esp的值都正确,eip指向ring3代码的第一条指令。
但是,不管 ring3 代码的第一条指令是什么(甚至是 nop 指令),qemu 都会重启(可能是一般的保护错误?)
这里是代码,头文件来自this repo。 bootloader将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 中,调试界面有一个指令跟踪 (bochs.sourceforge.net/doc/docbook/user/internal-debugger.html)..
标签: assembly operating-system x86 kernel bootloader