【问题标题】:Switch to user space切换到用户空间
【发布时间】:2015-08-13 09:38:28
【问题描述】:

这是演示操作系统内核基本功能的代码的一部分。 刷新 GTD 并设置 IDT 后,我想切换到 ring 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 $0x10, %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 $0x10
        pushl %eax

        pushf
        #enable ints after switch to ring 3
        pop %eax
        or $0x200, %eax
        push %eax

        #CS selector
        pushl $0x08
        pushl $0x60 #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。我将非常感谢有关此问题的任何帮助

【问题讨论】:

    标签: assembly x86 operating-system kernel


    【解决方案1】:

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

    【讨论】:

    • 我必须承认我不明白。执行iret 时,CPU 不检查 GDT 中的整个条目?另外,如果我对 '%ss' 使用相同的规则,我已将 pushl $0x08 更改为 pushl $0x0b,现在我得到了 iret: SS.rpl != CS.rpl
    • 是的,同样的逻辑。你知道CPL是选择器的低2位吗?
    • 是的,我知道 CPL 被编码在给定选择器的两个低位中,但老实说,在你回答之后,我不知道这种机制是如何工作的。我认为 CPL(当前特权级别)与 DPL(描述符特权级别)相同。老实说,现在我对保护级别在 CPU 中的工作方式感到困惑。因此,如果我想编写适当的权限级别更改,我应该将 $0x13 用于数据和堆栈?
    • 是的,使用 0x13。 CPL/RPL/DPL 的混乱是为了让您可以为不同的权限级别重用描述符,但无论如何没有人这样做。所以只要确保所有这些都匹配。
    • 谢谢!为了清楚获得选择器的正确值,我可以使用这个公式:GDT_offset + privlige_level 吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-29
    • 1970-01-01
    • 2019-12-25
    • 1970-01-01
    • 2015-04-29
    相关资源
    最近更新 更多