加载 GDT 时的三重故障
Triple fault when loading the GDT
我正在尝试在 rust 和全局 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 以查看它们是否有效,但在这里运气不好。
我不知道这是一个简单的答案!我只需要 dref(*) GDT 因为它是惰性静态的并且解决了所有问题 :D
我正在尝试在 rust 和全局 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 以查看它们是否有效,但在这里运气不好。
我不知道这是一个简单的答案!我只需要 dref(*) GDT 因为它是惰性静态的并且解决了所有问题 :D