在开发一个小型内核时,我在使用APIC引导应用程序处理器时遇到了一个奇怪的问题。
正如在OSDev和英特尔手册上所说的,处理器首先进入了实模式,我的目标是让它在保护模式下运行。在设置了一个小堆栈并启用了"A20"-Line并跳转到我的32位代码之后,我试图清除使用xor eax, eax的eax,以达到正确的目的。
令我惊讶的是,只有eax的较低的单词被清除,但是高的单词保持不变。

有趣的是,如果我只做一个xor ax, ax,而不是xor eax, eax,寄存器就会被完全清除。
下面是我使用APIC引导应用程序处理器的代码:
; 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部分保留下来。
有人知道为什么这不管用吗?
发布于 2021-08-09 01:11:44
正如@ it 95126所暗示的那样,我似乎装错了GDT。在使用32位段描述符创建并加载GDT之后,问题得到了解决.
如果有人感兴趣,下面是我的新GDT代码,用于从实模式切换到保护模式:
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
}
};发布于 2021-08-09 01:09:55
; 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节,“模式切换”)。如果你还没有看过这本手册,那么现在就是最好的时机了。)
https://stackoverflow.com/questions/68705584
复制相似问题