Don't depend on the stack setup by the bootloader

This way we can choose our own size for the stack and don't have to
identity map it manually. Also this way the bootloader doesn't have to
change the stack pointer right before calling into the kernel (which it
currently does in an unsound way)
This commit is contained in:
bjorn3
2025-09-13 18:32:15 +02:00
committed by Jeremy Soller
parent b7a69a26ba
commit ff65afd003
5 changed files with 54 additions and 19 deletions
+15 -1
View File
@@ -1,9 +1,10 @@
//! This function is where the kernel sets up IRQ handlers
//! It is increcibly unsafe, and should be minimal in nature
//! It is incredibly unsafe, and should be minimal in nature
//! It must create the IDT with the correct entries, those entries are
//! defined in other files inside of the `arch` module
use core::{
arch::global_asm,
cell::SyncUnsafeCell,
slice,
sync::atomic::{AtomicBool, Ordering},
};
@@ -22,6 +23,12 @@ static mut DATA_TEST_NONZERO: usize = 0xFFFF_FFFF_FFFF_FFFF;
pub static AP_READY: AtomicBool = AtomicBool::new(false);
static BSP_READY: AtomicBool = AtomicBool::new(false);
#[repr(C, align(16))]
struct StackAlign<T>(T);
static STACK: SyncUnsafeCell<StackAlign<[u8; 128 * 1024]>> =
SyncUnsafeCell::new(StackAlign([0; 128 * 1024]));
global_asm!("
.globl kstart
kstart:
@@ -33,6 +40,11 @@ global_asm!("
ldr x9, [x9, :lo12:{data_test_nonzero}]
cbz x9, .Lkstart_crash
adrp x1, {stack}
add x1, x1, :lo12:{stack}
mov x2, {stack_size}-16
add sp, x1, x2
mov lr, 0
b {start}
@@ -42,6 +54,8 @@ global_asm!("
",
bss_test_zero = sym BSS_TEST_ZERO,
data_test_nonzero = sym DATA_TEST_NONZERO,
stack = sym STACK,
stack_size = const size_of_val(&STACK),
start = sym start,
);
+13 -5
View File
@@ -1,5 +1,6 @@
use core::{
arch::{asm, global_asm},
cell::SyncUnsafeCell,
sync::atomic::{AtomicUsize, Ordering},
};
@@ -36,6 +37,12 @@ fn get_boot_hart_id(env: &[u8]) -> Option<usize> {
None
}
#[repr(C, align(16))]
struct StackAlign<T>(T);
static STACK: SyncUnsafeCell<StackAlign<[u8; 128 * 1024]>> =
SyncUnsafeCell::new(StackAlign([0; 128 * 1024]));
global_asm!("
.globl kstart
kstart:
@@ -49,6 +56,10 @@ global_asm!("
ld t0, {data_test_nonzero}
beqz t0, .Lkstart_crash
.Lpcrel_hi0:
auipc sp, %pcrel_hi({stack}+{stack_size}-16)
addi sp, sp, %pcrel_lo(.Lpcrel_hi0)
li ra, 0
j {start}
@@ -57,17 +68,14 @@ global_asm!("
",
bss_test_zero = sym BSS_TEST_ZERO,
data_test_nonzero = sym DATA_TEST_NONZERO,
stack = sym STACK,
stack_size = const size_of_val(&STACK),
start = sym start,
);
/// The entry to Rust, all things must be initialized
unsafe extern "C" fn start(args_ptr: *const KernelArgs) -> ! {
unsafe {
asm!(
"sd x0, -16(fp)", // and stop frame walker here
"sd x0, -8(fp)",
);
let bootstrap = {
let args = args_ptr.read();
+26 -3
View File
@@ -1,5 +1,5 @@
//! This function is where the kernel sets up IRQ handlers
//! It is increcibly unsafe, and should be minimal in nature
//! It is incredibly unsafe, and should be minimal in nature
//! It must create the IDT with the correct entries, those entries are
//! defined in other files inside of the `arch` module
use core::{
@@ -30,6 +30,12 @@ static DATA_TEST_NONZERO: SyncUnsafeCell<usize> = SyncUnsafeCell::new(usize::MAX
pub static AP_READY: AtomicBool = AtomicBool::new(false);
static BSP_READY: AtomicBool = AtomicBool::new(false);
#[repr(C, align(16))]
struct StackAlign<T>(T);
static STACK: SyncUnsafeCell<StackAlign<[u8; 128 * 1024]>> =
SyncUnsafeCell::new(StackAlign([0; 128 * 1024]));
#[cfg(target_arch = "x86")]
global_asm!("
.globl kstart
@@ -40,6 +46,11 @@ global_asm!("
cmp dword ptr [{data_test_nonzero}], 0
je .Lkstart_crash
mov eax, [esp + 4]
lea esp, [{stack}+{stack_size}-16]
mov [esp + 4], eax
mov [esp + 8], esp
jmp {start}
.Lkstart_crash:
@@ -48,6 +59,8 @@ global_asm!("
",
bss_test_zero = sym BSS_TEST_ZERO,
data_test_nonzero = sym DATA_TEST_NONZERO,
stack = sym STACK,
stack_size = const size_of_val(&STACK),
start = sym start,
);
@@ -61,6 +74,14 @@ global_asm!("
cmp qword ptr [rip + {data_test_nonzero}], 0
je .Lkstart_crash
// Note: The System V ABI requires the stack to be aligned to 16 bytes
// before the call instruction. As we jump rather than call it has to
// be offset by 8 bytes. Additionally reserve a bit more space at the
// end of the stack to ensure that the start function returns to
// address 0.
lea rsp, [rip + {stack}+{stack_size}-24]
mov rsi, rsp
jmp {start}
.Lkstart_crash:
@@ -69,11 +90,13 @@ global_asm!("
",
bss_test_zero = sym BSS_TEST_ZERO,
data_test_nonzero = sym DATA_TEST_NONZERO,
stack = sym STACK,
stack_size = const size_of_val(&STACK),
start = sym start,
);
/// The entry to Rust, all things must be initialized
unsafe extern "C" fn start(args_ptr: *const KernelArgs) -> ! {
unsafe extern "C" fn start(args_ptr: *const KernelArgs, stack_end: usize) -> ! {
unsafe {
let bootstrap = {
let args = args_ptr.read();
@@ -88,7 +111,7 @@ unsafe extern "C" fn start(args_ptr: *const KernelArgs) -> ! {
args.print();
// Set up GDT
gdt::init_bsp(args.stack_base as usize + args.stack_size as usize);
gdt::init_bsp(stack_end);
// Set up IDT
idt::init_bsp();
-5
View File
@@ -155,11 +155,6 @@ fn register_memory_from_kernel_args(args: &KernelArgs) {
args.kernel_size as usize,
BootloaderMemoryKind::Kernel,
);
register_memory_region(
args.stack_base as usize,
args.stack_size as usize,
BootloaderMemoryKind::IdentityMap,
);
register_memory_region(
args.env_base as usize,
args.env_size as usize,
-5
View File
@@ -40,11 +40,6 @@ impl KernelArgs {
{ self.kernel_base },
self.kernel_base + self.kernel_size
);
info!(
"Stack: {:X}:{:X}",
{ self.stack_base },
self.stack_base + self.stack_size
);
info!(
"Env: {:X}:{:X}",
{ self.env_base },