diff --git a/.gitignore b/.gitignore index 3e3ad8f..380eff1 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,6 @@ settings.json .DS_Store .venv .nvimlog +__pycache__ +.pytest_cache + diff --git a/.vscode/launch.json b/.vscode/launch.json index 5512088..7257aa3 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -66,6 +66,16 @@ "preLaunchTask": "Run QEMU", "stopOnEntry": true, "processCreateCommands": ["gdb-remote localhost:1234"] + }, + + { + "name": "NVIM LLDB", + "type": "codelldb", + "request": "attach", + "program": "${workspaceFolder}/target/aarch64-unknown-none/debug/nova", + "preLaunchTask": "Run QEMU", + "stopOnEntry": true, + "processCreateCommands": ["gdb-remote localhost:1234"] } ] } diff --git a/Cargo.lock b/Cargo.lock index c50c509..84935db 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -40,6 +40,15 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + [[package]] name = "log" version = "0.4.29" @@ -55,6 +64,7 @@ dependencies = [ "log", "nova_error", "paste", + "spin", ] [[package]] @@ -129,6 +139,21 @@ dependencies = [ "getrandom", ] +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "spin" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5fe4ccb98d9c292d56fec89a5e07da7fc4cf0dc11e156b41793132775d3e591" +dependencies = [ + "lock_api", +] + [[package]] name = "syn" version = "2.0.111" diff --git a/Cargo.toml b/Cargo.toml index 81e363e..489b8b1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,6 +18,7 @@ heap = {path = "workspace/heap"} nova_error = {path = "workspace/nova_error"} paste = "1.0.15" log = "0.4.29" +spin = "0.10.0" [workspace] diff --git a/src/aarch64/mmu.rs b/src/aarch64/mmu.rs index b54e1c7..b090742 100644 --- a/src/aarch64/mmu.rs +++ b/src/aarch64/mmu.rs @@ -105,7 +105,7 @@ pub enum PhysSource { } #[repr(align(4096))] -pub struct PageTable([TableEntry; TABLE_ENTRY_COUNT]); +pub struct PageTable(pub [TableEntry; TABLE_ENTRY_COUNT]); impl Iterator for PageTable { type Item = VirtAddr; @@ -204,7 +204,6 @@ fn map_range_dynamic( (virt, _) = virt.overflowing_add(GRANULARITY); remaining -= GRANULARITY; } - Ok(()) } @@ -224,7 +223,7 @@ pub fn alloc_page( /// Allocate a singe page in one block. pub fn find_free_kerne_page_in_block(start: VirtAddr) -> Result { - if !start.is_multiple_of(GRANULARITY) { + if !start.is_multiple_of(LEVEL2_BLOCK_SIZE) { return Err(NovaError::Misalignment); } @@ -238,8 +237,8 @@ pub fn find_free_kerne_page_in_block(start: VirtAddr) -> Result Self { - Self::new() - } + pub start_addr: usize, } impl Application { - pub fn new() -> Self { + pub fn new(start_addr: VirtAddr) -> Self { let physical_addr = reserve_page(); let virtual_address = find_free_kerne_page_in_block(APPLICATION_TRANSLATION_TABLE_VA).unwrap(); @@ -31,14 +28,55 @@ impl Application { ) .unwrap(); + // TODO: Temporary fix, while kernel and app share some memory regions + #[allow(static_mut_refs)] + unsafe { + let table = &mut *(virtual_address as *mut PageTable); + table.0 = TRANSLATIONTABLE_TTBR0.0; + } + Self { table_ptr: physical_addr as *mut TableEntry, + start_addr, + } + } + pub fn start(&self) { + 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 TTBR0_EL1, {}", in(reg) self.table_ptr as usize); + asm!("eret"); } } } -pub static mut APPLICATION_LIST: Option> = None; +struct AppManager { + apps: Option>, +} + +impl AppManager { + const fn new() -> Self { + Self { apps: None } + } +} + +unsafe impl Send for AppManager {} + +static APP_MANAGER: Mutex = Mutex::new(AppManager::new()); pub fn initialize_app_manager() { - unsafe { APPLICATION_LIST = Some(Vec::new()) } + let mut guard = APP_MANAGER.lock(); + guard.apps = Some(Vec::new()); +} +pub fn add_app(app: Application) { + if let Some(app_list) = APP_MANAGER.lock().apps.as_mut() { + app_list.push(app); + } +} + +pub fn start_app(index: usize) { + if let Some(app_list) = APP_MANAGER.lock().apps.as_mut() { + app_list[index].start(); + } } diff --git a/src/config.S b/src/config.S index cebe9d4..ca89164 100644 --- a/src/config.S +++ b/src/config.S @@ -78,25 +78,3 @@ configure_mmu_el1: ret -.align 4 -.global el1_to_el0 -el1_to_el0: - mov x8, x0 - // Set SPSR_EL1: return to EL0t - mov x0, #(0b0000) - msr SPSR_EL1, x0 - - // Set return address to el0 - ldr x0, =el0 - msr ELR_EL1, x0 - - // Set SP_EL1 to stack base - adrp x0, EL0_STACK_TOP - ldr x1, [x0, :lo12:EL0_STACK_TOP] - msr SP_EL0, x1 - - isb - - mov x0, x8 - // Return to EL0 - eret diff --git a/src/configuration/memory_mapping.rs b/src/configuration/memory_mapping.rs index c5758af..c6718c9 100644 --- a/src/configuration/memory_mapping.rs +++ b/src/configuration/memory_mapping.rs @@ -18,6 +18,8 @@ pub const EL0_STACK_SIZE: usize = LEVEL2_BLOCK_SIZE * 2; pub const MAILBOX_VIRTUAL_ADDRESS: VirtAddr = 0xFFFF_FF81_FFFF_E000; pub static mut MAILBOX_PHYSICAL_ADDRESS: Option = None; +// TODO: Currently limited to 512 applications, more than enough, but has to be kept +// in mind pub const APPLICATION_TRANSLATION_TABLE_VA: VirtAddr = 0xFFFF_FF81_FE00_0000; extern "C" { diff --git a/src/main.rs b/src/main.rs index 0b1d814..0de0492 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,6 +13,7 @@ extern crate alloc; use alloc::vec::Vec; use nova::{ aarch64::registers::{daif, read_id_aa64mmfr0_el1}, + application_manager::{add_app, Application}, configuration::memory_mapping::initialize_mmu_translation_tables, framebuffer::{FrameBuffer, BLUE, GREEN, RED}, get_current_el, init_logger, @@ -77,7 +78,6 @@ pub extern "C" fn main() -> ! { unsafe { el2_to_el1(); } - #[allow(clippy::empty_loop)] loop {} } @@ -104,6 +104,9 @@ pub extern "C" fn kernel_main() { enable_irq_source(IRQSource::UartInt); + let app = Application::new(el0 as *const () as usize); + add_app(app); + kernel_loop(); } diff --git a/src/terminal.rs b/src/terminal.rs index f64dd33..db299a2 100644 --- a/src/terminal.rs +++ b/src/terminal.rs @@ -3,6 +3,7 @@ use core::arch::asm; use alloc::string::String; use crate::{ + application_manager::start_app, interrupt_handlers::irq::{register_interrupt_handler, IRQSource}, peripherals::uart::read_uart_data, pi3::mailbox::read_soc_temp, @@ -15,10 +16,6 @@ pub struct Terminal { input: String, } -extern "C" { - fn el1_to_el0(); -} - impl Default for Terminal { fn default() -> Self { Self::new() @@ -48,7 +45,7 @@ impl Terminal { "el0" => unsafe { let i = 69; asm!("", in("x0") i); - el1_to_el0(); + start_app(0); }, _ => { println!("Unknown command: \"{}\"", self.input); diff --git a/tools/start_simulator_debug.sh b/tools/start_simulator_debug.sh index 9f52332..b9a70df 100755 --- a/tools/start_simulator_debug.sh +++ b/tools/start_simulator_debug.sh @@ -11,4 +11,4 @@ qemu-system-aarch64 \ -cpu cortex-a53 \ -serial stdio \ -sd ../sd.img \ - -kernel ../target/aarch64-unknown-none/debug/kernel8.img \ + -kernel ../target/aarch64-unknown-none/debug/kernel8.img -S -s diff --git a/workspace/heap/src/tests.rs b/workspace/heap/src/tests.rs index cad2fd2..c5cb0af 100644 --- a/workspace/heap/src/tests.rs +++ b/workspace/heap/src/tests.rs @@ -29,7 +29,7 @@ fn test_heap_allocation() { assert_eq!(actual_alloc_size % MIN_BLOCK_SIZE, 0); // Verify section is occupied - assert!((*malloc_header).free == false); + assert!(!(*malloc_header).free); // Verify next header has been created let next = (*malloc_header).next.unwrap(); @@ -55,7 +55,7 @@ fn test_full_heap() { let malloc = heap.malloc(malloc_size).unwrap(); let malloc_header = Heap::get_header_ref_from_data_pointer(malloc); unsafe { - assert_eq!((*malloc_header).free, false); + assert!(!(*malloc_header).free); assert!((*malloc_header).next.is_none()); } @@ -79,7 +79,7 @@ fn test_freeing_root() { let malloc = heap.malloc(malloc_size).unwrap(); let malloc_header = Heap::get_header_ref_from_data_pointer(malloc); unsafe { - assert_eq!((*malloc_header).free, false); + assert!(!(*malloc_header).free); assert!((*malloc_header).size >= malloc_size); assert!((*root_header).next.is_some());