首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >无法在保护模式下访问32位

无法在保护模式下访问32位
EN

Stack Overflow用户
提问于 2021-08-09 00:01:19
回答 2查看 206关注 0票数 0

在开发一个小型内核时,我在使用APIC引导应用程序处理器时遇到了一个奇怪的问题。

正如在OSDev和英特尔手册上所说的,处理器首先进入了实模式,我的目标是让它在保护模式下运行。在设置了一个小堆栈并启用了"A20"-Line并跳转到我的32位代码之后,我试图清除使用xor eax, eaxeax,以达到正确的目的。

令我惊讶的是,只有eax的较低的单词被清除,但是高的单词保持不变。

有趣的是,如果我只做一个xor ax, ax,而不是xor eax, eax,寄存器就会被完全清除。

下面是我使用APIC引导应用程序处理器的代码:

代码语言:javascript
复制
; Extern reference to the GDTR
section .data
extern g_gdtr

; Serves as a temporary stack used for flushing the cpu-pipeline
SMP_BOOT_STACK_SIZE equ 64
smp_boot_stack:
    dq 0
    dq 0
    dq 0
    dq 0

section .text
global __smp_ap_rm_entry
align 0x1000
[bits 16]
; Real-Mode Entry point for other processor cores (AP's)
; after a INIT-SIPI-SIPI was issued
__smp_ap_rm_entry:
    cli
    xor ax, ax
    mov ds, ax
    mov ss, ax
    lea bp, [ds:smp_boot_stack + SMP_BOOT_STACK_SIZE - 1]
    mov sp, bp
    
    ; Enable A20 line
    sti
    in al, 0x92
    or al, 2
    out 0x92, al
    cli

    lgdt [ds:g_gdtr]

    ; Enable Protected Mode
    mov eax, cr0
    or eax, 0x1
    mov cr0, eax

    ; Far jump
    push 0x8
    push __smp_ap_pm_entry
    retf

align 4
[bits 32]
__smp_ap_pm_entry:
    mov ax, word 0x10
    ; Doing this two times is somehow necessary (wtf?)
    mov es, ax
    mov es, ax 

    mov ss, ax
    mov fs, ax
    mov gs, ax
    mov ds, ax

    xor eax, eax
    int 3 ; To check for changed values in qemu

    jmp $

此外,我还尝试将32位值赋值到寄存器中,例如mov eax, 0xDEADBEEF,但只有BEEF部分保留下来。

有人知道为什么这不管用吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2021-08-09 01:11:44

正如@ it 95126所暗示的那样,我似乎装错了GDT。在使用32位段描述符创建并加载GDT之后,问题得到了解决.

如果有人感兴趣,下面是我的新GDT代码,用于从实模式切换到保护模式:

代码语言:javascript
复制
struct SegmentDescriptor32_s
{
    u16 SegmentLimitLow;
    u16 BaseAddressLow;
    union
    {
        struct
        {
            u32 BaseAddressMiddle : 8;
            u32 Type : 4;
            u32 DescriptorType : 1;
            u32 DescriptorPrivilegeLevel : 2;
            u32 Present : 1;
            u32 SegmentLimitHigh : 4;
            u32 System : 1;
            u32 LongMode : 1;
            u32 DefaultBig : 1;
            u32 Granularity : 1;
            u32 BaseAddressHigh : 8;
        };
        u32 Flags;
    };
} __attribute__((packed));

__attribute__((aligned(0x1000)))
static struct SegmentDescriptor32_s smp_ap_gdt[] =
{
    { /* Null-Selector */
        .SegmentLimitLow = 0x0,
        .BaseAddressLow = 0x0,
        .Flags = 0x0
    },
    { /* Flat Code */
        .SegmentLimitLow = 0xFFFF,
        .BaseAddressLow = 0x0000,
        .Flags = 0x00CF9A00
    },
    { /* Flat Data */
        .SegmentLimitLow = 0xFFFF,
        .BaseAddressLow = 0x0000,
        .Flags = 0x008F9200,
    },
    { /* TSS */
        .SegmentLimitLow = 0x68,
        .BaseAddressLow = 0x0000,
        .Flags = 0x00CF8900
    }
};
票数 2
EN

Stack Overflow用户

发布于 2021-08-09 01:09:55

代码语言:javascript
复制
; Enable Protected Mode
mov eax, cr0
or eax, 0x1
mov cr0, eax

; Far jump
push 0x8
push __smp_ap_pm_entry
retf

当体系结构手册要求修改PE位的MOV CR0必须立即跟随一个FAR JMP时,它们是指特定的指令FAR JMP (操作码EA或FF,取决于您如何表示操作数),它们意味着它必须是下一个指令。如果你不这样做,效果是不可预测的。我怀疑您的仿真器在执行FAR JMP之前实际上不会翻转开关,所以您仍然处于16位的真实模式,机器指令31 c0仍然意味着xor ax,ax而不是xor eax, eax

FAR JMP接受一个显式的绝对段:偏移表达式;您不能只编写jmp far __smp_ap_pm_entry。我不知道你到底需要写什么。

(见Intel 64和IA-32架构软件开发人员手册合并了第3A、3B、3C和3D卷:系统编程指南第9.9节,“模式切换”)。如果你还没有看过这本手册,那么现在就是最好的时机了。)

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/68705584

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档