【问题标题】:Error when switching from ring0 to ring3 in x86在 x86 中从 ring0 切换到 ring3 时出错
【发布时间】: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:

【问题讨论】:

标签: assembly operating-system x86 kernel bootloader


【解决方案1】:

哦,我找到了问题所在。访问冲突发生在分页时。

【讨论】:

  • 你能否补充一些细节,你是如何发现这个错误的,有什么可能对未来的读者有用的吗?
  • 我重新组织了我的代码并把它放在这里。放代码后突然发现我开启了分页,没有考虑分页的权限问题。
猜你喜欢
  • 2017-04-25
  • 1970-01-01
  • 2016-09-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-06
  • 2011-01-18
相关资源
最近更新 更多