kernel: attempt to correct stack overflow test

This commit is contained in:
janis 2026-08-03 20:46:04 +02:00
parent 8f441135e0
commit 87d7f5860d
Signed by: janis
SSH key fingerprint: SHA256:bB1qbbqmDXZNT0KKD5c2Dfjg53JGhj7B3CFcLIzSqq8
4 changed files with 57 additions and 12 deletions

View file

@ -10,4 +10,4 @@ target = "x86_64-unknown-kernel.json"
runner = "./run.sh"
rustflags = [
"-C", "force-frame-pointers=yes",
]
]

View file

@ -1,7 +1,7 @@
use core::{
arch::asm,
fmt::Debug,
mem::offset_of,
mem::{MaybeUninit, offset_of},
ops::{Deref, DerefMut},
};
@ -468,12 +468,16 @@ impl DerefMut for TssEntry {
}
}
const PRIVILEGE_STACK_TABLE_SIZE: usize = 3;
const INTERRUPT_STACK_TABLE_SIZE: usize = 7;
#[repr(C, packed(4))]
#[derive(Debug)]
pub struct TaskStateSegment {
_reserved1: [u8; 4],
pub privilege_stack_table: [u64; 3],
pub privilege_stack_table: [u64; PRIVILEGE_STACK_TABLE_SIZE],
_reserved2: [u8; 8],
pub interrupt_stack_table: [u64; 7],
pub interrupt_stack_table: [u64; INTERRUPT_STACK_TABLE_SIZE],
_reserved3: [u8; 10],
pub iomap_base: u16,
}
@ -489,6 +493,13 @@ impl TaskStateSegment {
_reserved3: [0; 10],
}
}
pub fn set_stack(&mut self, index: u8, stack: &'static Stack) {
assert!(
(index as usize) < INTERRUPT_STACK_TABLE_SIZE,
"Interrupt stack table index out of bounds"
);
self.interrupt_stack_table[index as usize] = stack.top().to_address();
}
}
const impl Default for TaskStateSegment {
@ -500,17 +511,35 @@ const impl Default for TaskStateSegment {
pub const DF_STACK: u8 = 0;
pub const NMI_STACK: u8 = 1;
pub const MC_STACK: u8 = 2;
pub const PF_STACK: u8 = 3;
const STACK_SIZE: usize = super::PAGE_SIZE * 5;
#[repr(align(16))]
pub struct Stack(MaybeUninit<[u8; STACK_SIZE]>);
impl Stack {
const fn new() -> Self {
Stack(MaybeUninit::uninit())
}
fn top(&self) -> *const u8 {
unsafe {
(&raw const *self)
.cast::<u8>()
.byte_add(super::PAGE_SIZE * 5)
}
}
}
pub static TSS: LazyLock<TaskStateSegment> = LazyLock::new(|| {
let mut tss = TaskStateSegment::new();
const STACK_SIZE: usize = super::PAGE_SIZE * 5;
static mut STACKS: [[u8; STACK_SIZE]; 3] = [[0; STACK_SIZE]; 3];
static mut STACKS: [Stack; 4] = [const { Stack::new() }; 4];
let stack_top = |n: usize| unsafe { STACKS[n].as_ptr().add(STACK_SIZE).to_address() };
tss.set_stack(DF_STACK, unsafe { &STACKS[DF_STACK as usize] });
tss.set_stack(NMI_STACK, unsafe { &STACKS[NMI_STACK as usize] });
tss.set_stack(MC_STACK, unsafe { &STACKS[MC_STACK as usize] });
tss.set_stack(PF_STACK, unsafe { &STACKS[PF_STACK as usize] });
tss.interrupt_stack_table[DF_STACK as usize] = stack_top(DF_STACK as usize);
tss.interrupt_stack_table[NMI_STACK as usize] = stack_top(NMI_STACK as usize);
tss.interrupt_stack_table[MC_STACK as usize] = stack_top(MC_STACK as usize);
serial_println!("Initialized TSS {:#?}", tss);
tss
});

View file

@ -89,6 +89,9 @@ impl Entry {
ExceptionVector::NON_MASKABLE_INTERRUPT => {
options.set_interrupt_stack_table_index(super::gdt::NMI_STACK);
}
ExceptionVector::PAGE_FAULT => {
options.set_interrupt_stack_table_index(super::gdt::PF_STACK);
}
ExceptionVector::MACHINE_CHECK => {
options.set_interrupt_stack_table_index(super::gdt::MC_STACK);
}

View file

@ -25,12 +25,13 @@ pub extern "C" fn main() -> ! {
_stack_frame: &mut idt::InterruptStackFrame,
_error_code: u64,
) -> ! {
kernel::serial_println!("[ok] Double fault handler called");
kernel::serial_println!("[ok] Fault handler called");
kernel::testing::exit_qemu(kernel::testing::QemuExitCode::Success)
}
static IDT: LazyLock<InterruptDescriptorTable> = LazyLock::new(|| {
let mut idt = InterruptDescriptorTable::new_default();
idt.double_fault = unsafe {
Entry::new(
double_fault_handler as *const (),
@ -38,7 +39,19 @@ pub extern "C" fn main() -> ! {
idt::EntryOptions::empty_interrupt_gate()
.with_present(true)
.with_privilege_level(RING0)
.with_interrupt_stack_table_index(DF_STACK),
.with_interrupt_stack_table_index(kernel::x86_64::gdt::DF_STACK),
)
};
// this should fire #PF since we have it installed anways in the default idt
idt.page_fault = unsafe {
Entry::new(
double_fault_handler as *const (),
offset_of!(GlobalDescriptorTable, kernel_code) as u16,
idt::EntryOptions::empty_interrupt_gate()
.with_present(true)
.with_privilege_level(RING0)
.with_interrupt_stack_table_index(kernel::x86_64::gdt::PF_STACK),
)
};