From bfcf7fc17d2dfc5cdccdd9b0a9f49eb52967d30e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Neuh=C3=A4user?= Date: Fri, 27 Mar 2026 11:40:36 +0100 Subject: [PATCH] feat: support CLI args, by applying System V ABI concepts --- src/application_manager.rs | 37 +++++++++++++--- src/interrupt_handlers/synchronous.rs | 61 +++++++++++++++++++++++++-- src/main.rs | 56 ++++++++++++++++-------- src/terminal.rs | 11 ++--- 4 files changed, 130 insertions(+), 35 deletions(-) diff --git a/src/application_manager.rs b/src/application_manager.rs index f3e3c67..66268b3 100644 --- a/src/application_manager.rs +++ b/src/application_manager.rs @@ -6,7 +6,7 @@ use crate::{ configuration::memory_mapping::{APPLICATION_TRANSLATION_TABLE_VA, EL0_STACK_TOP}, }; use alloc::vec::Vec; -use core::arch::asm; +use core::{arch::asm, mem, ptr::write_volatile}; use log::error; use nova_error::NovaError; use spin::Mutex; @@ -49,17 +49,42 @@ impl Application { /// `SPSR_EL1` -> Saved Program State Register (settings for `eret` behaviour) /// `SP_EL0` -> Stack Pointer Register (virtual_address of stack Pointer) /// `TTBR0_EL1` -> Translation Table base Register Register - pub fn start(&self) { + pub fn start(&self, args: Vec<&str>) { + let size = args.len(); + + let mut sp = EL0_STACK_TOP; + let mut arg_addresses = Vec::with_capacity(size); + for value in args { + sp -= value.len() * mem::size_of::(); + let pointer = sp as *mut u8; + unsafe { core::ptr::copy(value.as_ptr(), pointer, value.len()) }; + arg_addresses.push(pointer); + } + sp = align_down(sp, 16); + + let argv = sp; + + for addr in arg_addresses { + unsafe { write_volatile(sp as *mut *const u8, addr) }; + sp -= mem::size_of::<*const u8>(); + } + unsafe { asm!("msr ELR_EL1, {}", in(reg) self.start_addr); asm!("msr SPSR_EL1, {0:x}", in(reg) 0); - asm!("msr SP_EL0, {0:x}", in(reg) EL0_STACK_TOP); + asm!("msr SP_EL0, {0:x}", in(reg) sp); asm!("msr TTBR0_EL1, {}", in(reg) self.table_ptr as usize); + asm!("", in("x0") size); + asm!("", in("x1") argv); asm!("eret"); } } } +fn align_down(sp: usize, align: usize) -> usize { + sp & !(align - 1) +} + struct AppManager { apps: Option>, } @@ -87,15 +112,13 @@ pub fn add_app(app: Application) -> Result<(), NovaError> { Err(NovaError::General("AppManager not initalized.")) } } - -pub fn start_app(index: usize) -> Result<(), NovaError> { - if let Some(app) = APP_MANAGER +pub fn start_app(index: usize, args: Vec<&str>) -> Result<(), NovaError> { if let Some(app) = APP_MANAGER .lock() .apps .as_mut() .and_then(|am| am.get(index)) { - app.start(); + app.start(args); unreachable!() } else { error!("Unable to start app due to invalid App ID."); diff --git a/src/interrupt_handlers/synchronous.rs b/src/interrupt_handlers/synchronous.rs index b7f757c..bf3ea55 100644 --- a/src/interrupt_handlers/synchronous.rs +++ b/src/interrupt_handlers/synchronous.rs @@ -20,14 +20,15 @@ unsafe extern "C" fn rust_synchronous_interrupt_imm_lower_aarch64(frame: &mut Tr log_sync_exception(); match esr.ec { 0b100100 => { - error!("Cause: Data Abort from a lower Exception level"); + error!("Data Abort from a lower Exception level"); + error!("Cause: {}", decode_data_abort(esr.iss as usize)); } 0b010101 => { - debug!("Cause: SVC instruction execution in AArch64"); + debug!("SVC instruction execution in AArch64"); return handle_svc(frame); } 0b100010 => { - error!("Cause: PC alignment fault."); + error!("PC alignment fault."); } _ => { error!("Synchronous interrupt: Unknown Error Code: {:b}", esr.ec); @@ -39,8 +40,62 @@ unsafe extern "C" fn rust_synchronous_interrupt_imm_lower_aarch64(frame: &mut Tr 0 } +fn decode_data_abort(iss: usize) -> &'static str { + match iss & 0b111111 { + 0b000000 => "Address size fault, level 0", + 0b000001 => "Address size fault, level 1", + 0b000010 => "Address size fault, level 2", + 0b000011 => "Address size fault, level 3", + + 0b000100 => "Translation fault, level 0", + 0b000101 => "Translation fault, level 1", + 0b000110 => "Translation fault, level 2", + 0b000111 => "Translation fault, level 3", + + 0b001001 => "Access flag fault, level 1", + 0b001010 => "Access flag fault, level 2", + 0b001011 => "Access flag fault, level 3", + + 0b001101 => "Permission fault, level 1", + 0b001110 => "Permission fault, level 2", + 0b001111 => "Permission fault, level 3", + + 0b010000 => "Synchronous External abort, not on translation table walk", + 0b011000 => { + "Synchronous parity or ECC error on memory access, not on translation table walk" + } + + 0b010100 => "Synchronous External abort, on translation table walk, level 0", + 0b010101 => "Synchronous External abort, on translation table walk, level 1", + 0b010110 => "Synchronous External abort, on translation table walk, level 2", + 0b010111 => "Synchronous External abort, on translation table walk, level 3", + + 0b011100 => "Synchronous parity or ECC error on translation table walk, level 0", + 0b011101 => "Synchronous parity or ECC error on translation table walk, level 1", + 0b011110 => "Synchronous parity or ECC error on translation table walk, level 2", + 0b011111 => "Synchronous parity or ECC error on translation table walk, level 3", + + 0b100001 => "Alignment fault", + 0b110000 => "TLB conflict abort", + 0b110001 => "Unsupported atomic hardware update fault", + + 0b110100 => "IMPLEMENTATION DEFINED fault (Lockdown)", + 0b110101 => "IMPLEMENTATION DEFINED fault (Unsupported Exclusive or Atomic access)", + + 0b111101 => "Section Domain Fault", + 0b111110 => "Page Domain Fault", + + _ => "Reserved / Unknown", + } +} + fn handle_svc(frame: &mut TrapFrame) -> usize { match frame.x8 { + 0 => { + debug!("Program exited!"); + set_return_to_kernel_loop(); + 0 + } 67 => { let response = mailbox::read_soc_temp([0]).unwrap(); response[1] as usize diff --git a/src/main.rs b/src/main.rs index 6d5971e..5702781 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,7 +10,7 @@ use log::{debug, info}; extern crate alloc; -use alloc::vec::Vec; +use alloc::{slice, vec::Vec}; use nova::{ aarch64::registers::{daif, read_id_aa64mmfr0_el1}, application_manager::{add_app, Application}, @@ -25,6 +25,7 @@ use nova::{ }, uart::uart_init, }, + pi3::timer::sleep_s, print, println, }; @@ -101,7 +102,6 @@ pub extern "C" fn kernel_main() { test_vector.push(i); } debug!("heap allocation test: {:?}", test_vector); - enable_irq_source(IRQSource::UartInt); let app = Application::new(el0 as *const () as usize); @@ -109,18 +109,33 @@ pub extern "C" fn kernel_main() { kernel_loop(); } - #[no_mangle] pub extern "C" fn kernel_loop() { daif::unmask_all(); - #[allow(clippy::empty_loop)] loop {} } - #[no_mangle] -pub extern "C" fn el0(input: usize) { +pub unsafe extern "C" fn el0(argc: usize, argv: *const *const u8) { println!("Jumped into EL0"); + println!("num: {}", argc); + println!("argv: {:?}", argv); + + let raw_args = unsafe { slice::from_raw_parts(argv, argc) }; + let first_arg = raw_args + .iter() + .map(|&arg_ptr| { + if arg_ptr.is_null() { + return ""; + } + + let c_str = unsafe { core::ffi::CStr::from_ptr(arg_ptr) }; + let str_slice = c_str.to_str().unwrap(); + str_slice + }) + .next(); + + sleep_s(1); // Set GPIO 26 to Input enable_irq_source(IRQSource::GpioInt0); //26 is on the first GPIO bank @@ -143,25 +158,30 @@ pub extern "C" fn el0(input: usize) { let _temp = syscall(67); - println!("Calculting prime to: {}", input); + if let Some(num) = first_arg.and_then(|val| val.parse::().ok()) { + println!("Calculting prime to: {}", num); - for i in 3..input { - let mut is_prime = true; - for j in 3..i { - if i == j { - continue; + for i in 3..num { + let mut is_prime = true; + for j in 3..i { + if i == j { + continue; + } + if i % j == 0 { + is_prime = false; + } } - if i % j == 0 { - is_prime = false; + if is_prime { + print!("{} ", i); } } - if is_prime { - print!("{} ", i); - } + println!(""); + } else { + println!("Input NaN"); } - println!(""); blink_gpio(SpecificGpio::OnboardLed as u8, 500); + syscall(0); } fn cos(x: u32) -> f64 { diff --git a/src/terminal.rs b/src/terminal.rs index 62feeb4..836dec0 100644 --- a/src/terminal.rs +++ b/src/terminal.rs @@ -1,5 +1,3 @@ -use core::arch::asm; - use alloc::string::String; use crate::{ @@ -44,15 +42,14 @@ impl Terminal { "temp" => { println!("{}", read_soc_temp([0]).unwrap()[1]); } - "app" => unsafe { + "app" => { if let Some(app_id) = parts.next().and_then(|a| a.parse::().ok()) { - let i = 69; - asm!("", in("x0") i); - let _ = start_app(app_id); + let args = parts.collect(); + let _ = start_app(app_id, args); } else { println!("App ID not set."); } - }, + } _ => { println!("Unknown command: \"{}\"", self.input); }