我正在尝试在 rust 和 global asm 中设置 GDT,但是当我尝试加载 GDT 时,它似乎出现了三重故障。
# init_gdt.asm.
.intel_syntax noprefix
# **Notes**: 0x00: The Kernel Null Segment.
# 0x10: The Kernel Data Segment.
# 0x08: The Kernel Code Segment.
# Load the GDT and set all of the segments.
LoadGDT:
# Use the `lgdt` Load GDT instruction to set the new GDT.
# The rdi register contains the first argument of the function.
lgdt [rdi]
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
pop rdi
mov rax, 0x08
push rax
push rdi
retfq
.global LoadGDT
global_asm!(include_str!("load_gdt.asm"));
#[repr(C, packed)]
struct GDTDescriptor {
size: u16,
offset: u64,
}
impl GDTDescriptor {
#[inline]
pub fn new(size: u16, offset: u64) -> Self {
Self { size, offset }
}
}
#[repr(C)]
struct GDTEntry {
limit_low: u16,
base_low: u16,
base_middle: u8,
access_byte: u8,
limit_hi_flags: u8,
base_hi: u8,
}
impl GDTEntry {
#[inline]
fn new(
limit_low: u16,
base_low: u16,
base_middle: u8,
access_byte: u8,
limit_hi_flags: u8,
base_hi: u8,
) -> Self {
Self {
limit_low,
base_low,
base_middle,
access_byte,
limit_hi_flags,
base_hi,
}
}
}
/// The GDT.
#[repr(C, align(0x1000))]
struct GDT {
kernel_null: GDTEntry,
kernel_code: GDTEntry,
kernel_data: GDTEntry,
user_null: GDTEntry,
user_code: GDTEntry,
user_data: GDTEntry,
}
/// Initialize the GDT.
pub fn init() {
unsafe {
let gdt_descriptor = GDTDescriptor::new(
(size_of::<GDT>() - 1) as u16,
(&GLOBAL_DESCRIPTOR_TABLE as *const _) as u64,
);
LoadGDT(&gdt_descriptor as *const _)
}
}
lazy_static! {
/// The GDT (Global Descriptor Table).
static ref GLOBAL_DESCRIPTOR_TABLE: GDT = GDT {
kernel_null: GDTEntry::new(0, 0, 0, 0x00, 0x00, 0),
kernel_code: GDTEntry::new(0, 0, 0, 0x9a, 0xa0, 0),
kernel_data: GDTEntry::new(0, 0, 0, 0x92, 0xa0, 0),
user_null: GDTEntry::new(0, 0, 0, 0x00, 0x00, 0),
user_code: GDTEntry::new(0, 0, 0, 0x9a, 0xa0, 0),
user_data: GDTEntry::new(0, 0, 0, 0x92, 0xa0, 0)
};
}
根据 qemu 日志,它发生在mov ds, ax
指令中。我遵循了 osdev.org 的指令,我很确定我的程序集是完全有效的。
我也一直在尝试更改并尝试一些随机的 GDTEntries 以查看它们是否有效,但这里没有运气。