【问题标题】:Protected mode, setting segment registers保护模式,设置段寄存器
【发布时间】:2015-05-15 22:56:11
【问题描述】:

我最近在简单的操作系统开发中使用 gnu-assembler。我正在使用下面的代码将 CPU 切换到保护模式。为了做到这一点,我如下设置 GDT 并执行远跳转到给定标签 wit 0x08 作为 GDT 偏移量(设置 CS)。在jmp 之后CPU 没有自行复位,但是在跳转到leaveToKernel 之后没有一条mov 指令被正确执行。我说mov设置DS和SS失败的原因是这个qemu打印(info registers):

EAX=00000000 EBX=00105fd8 ECX=000003eb EDX=000b8000
ESI=00010000 EDI=00000000 EBP=00105fc0 ESP=00105fc0
EIP=0083ec44 EFL=00200002 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0018 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
CS =0008 00100000 02710fff 00c09a00 DPL=0 CS32 [-R-]
SS =0018 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
DS =0018 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
FS =0018 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
GS =0018 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]

有人可以帮助我理解和解释这种行为吗?提前致谢

CPU切换到p模式的代码(GAS语法):

.equ NULL_DESCRIPTOR,  0x0000000000000000

.equ CODE0,          0x00C09A1000002710
.equ DATA0,          0x00C09210010007D0
.equ PLACE_HLD1,     0x0000000000000000
.equ PLACE_HLD2,     0x0000000000000000
.section .data
     GDT:
        .quad NULL_DESCRIPTOR
        .quad CODE_P0
        .quad DATA_P0
        .quad PLACE_HLD1
        .quad PLACE_HLD2
    _GDT:
        .word 24
        .long GDT
.section .text
.global setProtectedMode
.type setProtectedMode, @function
setProtectedMode:
    push %ebp
    mov %esp,%ebp

    cli
    lgdt _GDT
    mov %cr0, %eax
    or $1, %eax
    mov %eax, %cr0
    jmp $0x08 ,$leaveToKernel
    leaveToKernel:
    xor %eax, %eax
    mov $0x10, %ax
    mov %ax, %ss
    mov %ax, %ds
    hlt
leave    
ret

【问题讨论】:

    标签: assembly x86 gnu-assembler memory-segmentation protected-mode


    【解决方案1】:

    显然你的 CS 基础不是零,所以我说你没有跳到正确的地方。非零 CS 基数并不常见,我假设您确实想要 0,但 GDT 条目设置错误。修复它:)

    【讨论】:

    • 我会试试的,但是应该不会错CS导致三重故障和cpu重置?
    • 它本身并没有错,它只是没有指向您的代码。谁知道它走到哪里都能找到什么代码。如果你很幸运,那不会有错。
    • 但是我觉得奇怪的是您的 DS=ES=FS=GS=SS=0x18 ... 这非常可疑并且表明一些有效的代码可以设置它。但是,您的片段将 0x10 用于 DS 和 SS。
    • 好的,我已经更改了 0x08 描述符 (CS) 的基数,现在值已正确设置(或者至少按照我的意愿设置)。但是我不明白为什么CS必须从0开始,你能解释一下吗?
    • 不必如此,但如果不是,那么您必须格外小心地使用适当的偏移量。例如,汇编器不会自动知道您更改了段基数,因此它会为您的leaveToKernel 生成错误的地址。
    猜你喜欢
    • 2016-11-05
    • 2013-11-22
    • 2015-09-25
    • 1970-01-01
    • 2018-08-30
    • 2019-05-31
    • 2018-02-09
    • 1970-01-01
    相关资源
    最近更新 更多