切换到用户 space

Switch to user space

这是演示os内核基本功能的部分代码。 刷新 GTD 并设置 IDT 后,我想切换到环 3 运行 一些 int 和上下文切换。 但是我不能跳转到用户模式。我想在 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 [=11=]x10, %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 [=11=]x10
        pushl %eax

        pushf
        #enable ints after switch to ring 3
        pop %eax
        or [=11=]x200, %eax
        push %eax

        #CS selector
        pushl [=11=]x08
        pushl [=11=]x60 #Address of .leave (I have written proper ld script and checked with objdump)
        iret

    .section .upper_code, "ax", @progbits
    .leave:
        hlt
        call upperKernelCode

问题出在 iret 开始执行此指令后,检查选择器的特权级别并且执行代码,因此导致 CPU 故障并重置。 这是 BOCHS 的日志形式:check_cs(0x0008): non-conforming code seg descriptor dpl != cpl, dpl=3, cpl=0。我将非常感谢对此问题的任何帮助

正如 bochs 告诉您的那样,您的选择器 0x08 具有 CPL=0,但描述符条目具有 DPL=3。请记住,选择器的两个最低有效位是 CPL。因此,要切换到 ring3,您应该使用 0x0b.