Bladeren bron

hal: add a function to setup kernel call frames

Setting up call frames manually is highly architecture dependent, such
as stack alignment at function entry and argument passing rules. Leave
this work to the HAL crate to relief the end users from complexity.

Signed-off-by: greatbridf <greatbridf@icloud.com>
greatbridf 1 week geleden
bovenliggende
commit
425291d85a

+ 9 - 0
crates/eonix_hal/eonix_hal_traits/src/trap.rs

@@ -4,6 +4,10 @@ use eonix_mm::address::VAddr;
 
 use crate::fault::Fault;
 
+pub trait Stack {
+    fn get_bottom(&self) -> *mut usize;
+}
+
 /// A raw trap context.
 ///
 /// This should be implemented by the architecture-specific trap context
@@ -35,6 +39,11 @@ pub trait RawTrapContext: Copy {
         &mut self, pc: usize, sp: Option<usize>, ra: Option<usize>,
         args: &[usize], write_memory: impl Fn(VAddr, &[u8]) -> Result<(), E>,
     ) -> Result<(), E>;
+
+    fn set_kernel_call_frame(
+        &mut self, pc: usize, stack: &impl Stack, ra: Option<usize>,
+        args: &[usize],
+    );
 }
 
 #[doc(notable_trait)]

+ 26 - 1
crates/eonix_hal/src/arch/riscv64/trap/trap_context.rs

@@ -2,7 +2,7 @@ use core::arch::asm;
 use core::mem::offset_of;
 
 use eonix_hal_traits::fault::{Fault, PageFaultErrorCode};
-use eonix_hal_traits::trap::{RawTrapContext, TrapType};
+use eonix_hal_traits::trap::{RawTrapContext, Stack, TrapType};
 use eonix_mm::address::VAddr;
 use riscv::interrupt::{Exception, Interrupt, Trap};
 use riscv::register::scause::{self, Scause};
@@ -276,6 +276,31 @@ impl RawTrapContext for TrapContext {
 
         Ok(())
     }
+
+    fn set_kernel_call_frame(
+        &mut self, pc: usize, sp: &impl Stack, ra: Option<usize>,
+        args: &[usize],
+    ) {
+        self.set_program_counter(pc);
+        self.set_stack_pointer(sp.get_bottom().addr());
+
+        if let Some(ra) = ra {
+            self.regs.ra = ra as u64;
+        }
+
+        let arg_regs = [
+            &mut self.regs.a0,
+            &mut self.regs.a1,
+            &mut self.regs.a2,
+            &mut self.regs.a3,
+            &mut self.regs.a4,
+            &mut self.regs.a5,
+        ];
+
+        for (&arg, reg) in args.iter().zip(arg_regs.into_iter()) {
+            *reg = arg as u64;
+        }
+    }
 }
 
 impl TrapContext {

+ 27 - 1
crates/eonix_hal/src/arch/x86_64/trap/trap_context.rs

@@ -2,7 +2,7 @@ use core::arch::asm;
 use core::mem::offset_of;
 
 use eonix_hal_traits::fault::{Fault, PageFaultErrorCode};
-use eonix_hal_traits::trap::{RawTrapContext, TrapType};
+use eonix_hal_traits::trap::{RawTrapContext, Stack, TrapType};
 use eonix_mm::address::VAddr;
 
 use crate::processor::CPU;
@@ -221,4 +221,30 @@ impl RawTrapContext for TrapContext {
         self.set_stack_pointer(sp);
         Ok(())
     }
+
+    fn set_kernel_call_frame(
+        &mut self, pc: usize, stack: &impl Stack, ra: Option<usize>,
+        args: &[usize],
+    ) {
+        let sp = stack.get_bottom().wrapping_sub(1);
+
+        self.set_program_counter(pc);
+        self.set_stack_pointer(sp.addr());
+
+        unsafe {
+            sp.write(ra.map(|f| f as usize).unwrap_or(0));
+        }
+
+        if let Some(&arg) = args.get(0) {
+            self.rdi = arg as _;
+        }
+
+        if let Some(&arg) = args.get(1) {
+            self.rsi = arg as _;
+        }
+
+        if args.len() > 2 {
+            unimplemented!("More than 2 arguments are not supported for now");
+        }
+    }
 }

+ 3 - 5
src/kernel/task.rs

@@ -109,7 +109,7 @@ where
 
     let stack = KernelStack::new();
 
-    fn execute<F>(
+    unsafe extern "C" fn execute<F>(
         mut future: Pin<&mut F>, output_ptr: NonNull<Option<F::Output>>,
     ) -> !
     where
@@ -194,19 +194,17 @@ where
         unreachable!()
     }
 
-    let sp = stack.get_bottom();
     let mut output = UnsafeCell::new(None);
 
     let mut trap_ctx = TrapContext::new();
 
     trap_ctx.set_user_mode(false);
     trap_ctx.set_interrupt_enabled(true);
-    let _ = trap_ctx.set_user_call_frame(
+    trap_ctx.set_kernel_call_frame(
         symbol_addr!(execute::<F>),
-        Some(sp.addr().get()),
+        &stack,
         None,
         &[(&raw mut future) as usize, output.get() as usize],
-        |_, _| Ok::<(), u32>(()),
     );
 
     loop {

+ 8 - 0
src/kernel/task/kernel_stack.rs

@@ -1,5 +1,7 @@
 use core::ptr::NonNull;
 
+use eonix_hal::traits::trap::Stack;
+
 use crate::kernel::mem::FolioOwned;
 
 #[derive(Debug)]
@@ -26,3 +28,9 @@ impl KernelStack {
         unsafe { ptr.cast().byte_add(len) }
     }
 }
+
+impl Stack for KernelStack {
+    fn get_bottom(&self) -> *mut usize {
+        self.get_bottom().cast().as_ptr()
+    }
+}

+ 8 - 16
src/lib.rs

@@ -67,17 +67,13 @@ fn kernel_init(mut data: eonix_hal::bootstrap::BootStrapData) -> ! {
     drop(data);
 
     let mut ctx = TrapContext::new();
-    let stack_bottom = {
-        let stack = KernelStack::new();
-        let bottom = stack.get_bottom().addr().get();
-        core::mem::forget(stack);
+    let stack = KernelStack::new();
 
-        bottom
-    };
     ctx.set_interrupt_enabled(true);
     ctx.set_user_mode(false);
-    ctx.set_program_counter(symbol_addr!(standard_main));
-    ctx.set_stack_pointer(stack_bottom);
+    ctx.set_kernel_call_frame(symbol_addr!(standard_main), &stack, None, &[]);
+
+    core::mem::forget(stack);
 
     unsafe {
         ctx.trap_return_noreturn();
@@ -94,17 +90,13 @@ fn kernel_ap_main(_stack_range: PRange) -> ! {
     println_debug!("AP{} started", CPU::local().cpuid());
 
     let mut ctx = TrapContext::new();
-    let stack_bottom = {
-        let stack = KernelStack::new();
-        let bottom = stack.get_bottom().addr().get();
-        core::mem::forget(stack);
+    let stack = KernelStack::new();
 
-        bottom
-    };
     ctx.set_interrupt_enabled(true);
     ctx.set_user_mode(false);
-    ctx.set_program_counter(symbol_addr!(standard_main));
-    ctx.set_stack_pointer(stack_bottom);
+    ctx.set_kernel_call_frame(symbol_addr!(standard_main), &stack, None, &[]);
+
+    core::mem::forget(stack);
 
     unsafe {
         ctx.trap_return_noreturn();