mirror of
https://github.com/iceHtwoO/novaOS.git
synced 2026-04-16 20:22:26 +00:00
feat: support CLI args, by applying System V ABI concepts
This commit is contained in:
@@ -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.");
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
36
src/main.rs
36
src/main.rs
@@ -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 {
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user