feat: support CLI args, by applying System V ABI concepts

This commit is contained in:
2026-03-27 11:40:36 +01:00
parent 02f16715bc
commit bfcf7fc17d
4 changed files with 130 additions and 35 deletions

View File

@@ -6,7 +6,7 @@ use crate::{
configuration::memory_mapping::{APPLICATION_TRANSLATION_TABLE_VA, EL0_STACK_TOP}, configuration::memory_mapping::{APPLICATION_TRANSLATION_TABLE_VA, EL0_STACK_TOP},
}; };
use alloc::vec::Vec; use alloc::vec::Vec;
use core::arch::asm; use core::{arch::asm, mem, ptr::write_volatile};
use log::error; use log::error;
use nova_error::NovaError; use nova_error::NovaError;
use spin::Mutex; use spin::Mutex;
@@ -49,17 +49,42 @@ impl Application {
/// `SPSR_EL1` -> Saved Program State Register (settings for `eret` behaviour) /// `SPSR_EL1` -> Saved Program State Register (settings for `eret` behaviour)
/// `SP_EL0` -> Stack Pointer Register (virtual_address of stack Pointer) /// `SP_EL0` -> Stack Pointer Register (virtual_address of stack Pointer)
/// `TTBR0_EL1` -> Translation Table base Register Register /// `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::<u8>();
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 { unsafe {
asm!("msr ELR_EL1, {}", in(reg) self.start_addr); asm!("msr ELR_EL1, {}", in(reg) self.start_addr);
asm!("msr SPSR_EL1, {0:x}", in(reg) 0); 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!("msr TTBR0_EL1, {}", in(reg) self.table_ptr as usize);
asm!("", in("x0") size);
asm!("", in("x1") argv);
asm!("eret"); asm!("eret");
} }
} }
} }
fn align_down(sp: usize, align: usize) -> usize {
sp & !(align - 1)
}
struct AppManager { struct AppManager {
apps: Option<Vec<Application>>, apps: Option<Vec<Application>>,
} }
@@ -87,15 +112,13 @@ pub fn add_app(app: Application) -> Result<(), NovaError> {
Err(NovaError::General("AppManager not initalized.")) Err(NovaError::General("AppManager not initalized."))
} }
} }
pub fn start_app(index: usize, args: Vec<&str>) -> Result<(), NovaError> { if let Some(app) = APP_MANAGER
pub fn start_app(index: usize) -> Result<(), NovaError> {
if let Some(app) = APP_MANAGER
.lock() .lock()
.apps .apps
.as_mut() .as_mut()
.and_then(|am| am.get(index)) .and_then(|am| am.get(index))
{ {
app.start(); app.start(args);
unreachable!() unreachable!()
} else { } else {
error!("Unable to start app due to invalid App ID."); error!("Unable to start app due to invalid App ID.");

View File

@@ -20,14 +20,15 @@ unsafe extern "C" fn rust_synchronous_interrupt_imm_lower_aarch64(frame: &mut Tr
log_sync_exception(); log_sync_exception();
match esr.ec { match esr.ec {
0b100100 => { 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 => { 0b010101 => {
debug!("Cause: SVC instruction execution in AArch64"); debug!("SVC instruction execution in AArch64");
return handle_svc(frame); return handle_svc(frame);
} }
0b100010 => { 0b100010 => {
error!("Cause: PC alignment fault."); error!("PC alignment fault.");
} }
_ => { _ => {
error!("Synchronous interrupt: Unknown Error Code: {:b}", esr.ec); 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 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 { fn handle_svc(frame: &mut TrapFrame) -> usize {
match frame.x8 { match frame.x8 {
0 => {
debug!("Program exited!");
set_return_to_kernel_loop();
0
}
67 => { 67 => {
let response = mailbox::read_soc_temp([0]).unwrap(); let response = mailbox::read_soc_temp([0]).unwrap();
response[1] as usize response[1] as usize

View File

@@ -10,7 +10,7 @@ use log::{debug, info};
extern crate alloc; extern crate alloc;
use alloc::vec::Vec; use alloc::{slice, vec::Vec};
use nova::{ use nova::{
aarch64::registers::{daif, read_id_aa64mmfr0_el1}, aarch64::registers::{daif, read_id_aa64mmfr0_el1},
application_manager::{add_app, Application}, application_manager::{add_app, Application},
@@ -25,6 +25,7 @@ use nova::{
}, },
uart::uart_init, uart::uart_init,
}, },
pi3::timer::sleep_s,
print, println, print, println,
}; };
@@ -101,7 +102,6 @@ pub extern "C" fn kernel_main() {
test_vector.push(i); test_vector.push(i);
} }
debug!("heap allocation test: {:?}", test_vector); debug!("heap allocation test: {:?}", test_vector);
enable_irq_source(IRQSource::UartInt); enable_irq_source(IRQSource::UartInt);
let app = Application::new(el0 as *const () as usize); let app = Application::new(el0 as *const () as usize);
@@ -109,18 +109,33 @@ pub extern "C" fn kernel_main() {
kernel_loop(); kernel_loop();
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn kernel_loop() { pub extern "C" fn kernel_loop() {
daif::unmask_all(); daif::unmask_all();
#[allow(clippy::empty_loop)] #[allow(clippy::empty_loop)]
loop {} loop {}
} }
#[no_mangle] #[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!("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 // Set GPIO 26 to Input
enable_irq_source(IRQSource::GpioInt0); //26 is on the first GPIO bank enable_irq_source(IRQSource::GpioInt0); //26 is on the first GPIO bank
@@ -143,9 +158,10 @@ pub extern "C" fn el0(input: usize) {
let _temp = syscall(67); let _temp = syscall(67);
println!("Calculting prime to: {}", input); if let Some(num) = first_arg.and_then(|val| val.parse::<usize>().ok()) {
println!("Calculting prime to: {}", num);
for i in 3..input { for i in 3..num {
let mut is_prime = true; let mut is_prime = true;
for j in 3..i { for j in 3..i {
if i == j { if i == j {
@@ -160,8 +176,12 @@ pub extern "C" fn el0(input: usize) {
} }
} }
println!(""); println!("");
} else {
println!("Input NaN");
}
blink_gpio(SpecificGpio::OnboardLed as u8, 500); blink_gpio(SpecificGpio::OnboardLed as u8, 500);
syscall(0);
} }
fn cos(x: u32) -> f64 { fn cos(x: u32) -> f64 {

View File

@@ -1,5 +1,3 @@
use core::arch::asm;
use alloc::string::String; use alloc::string::String;
use crate::{ use crate::{
@@ -44,15 +42,14 @@ impl Terminal {
"temp" => { "temp" => {
println!("{}", read_soc_temp([0]).unwrap()[1]); println!("{}", read_soc_temp([0]).unwrap()[1]);
} }
"app" => unsafe { "app" => {
if let Some(app_id) = parts.next().and_then(|a| a.parse::<usize>().ok()) { if let Some(app_id) = parts.next().and_then(|a| a.parse::<usize>().ok()) {
let i = 69; let args = parts.collect();
asm!("", in("x0") i); let _ = start_app(app_id, args);
let _ = start_app(app_id);
} else { } else {
println!("App ID not set."); println!("App ID not set.");
} }
}, }
_ => { _ => {
println!("Unknown command: \"{}\"", self.input); println!("Unknown command: \"{}\"", self.input);
} }