在x86中从ring0切换到ring3时出错

时间:2014-11-01 07:42:22

标签: assembly operating-system x86 kernel bootloader

我正在尝试使用lret指令从ring0切换到ring3。因此,我推送ss,esp,cs,ip的正确值,并使用lret。

我使用qemu和gdb来调试这段代码,并发现一件奇怪的事情:

在lret instrunction之后,处理器成功切换到ring3(我在qemu中使用“info registers”来检查),ss,cs,esp的值都是正确的,并且eip指向ring3代码的第一条指令。

但是,无论ring3代码的第一条指令是什么(甚至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:

1 个答案:

答案 0 :(得分:0)

哦,我发现了问题所在。访问冲突发生在分页上。