feat: start application via application_manager

This commit is contained in:
2026-03-25 21:40:33 +01:00
parent 6798f6b56d
commit 804941d933
12 changed files with 107 additions and 51 deletions

3
.gitignore vendored
View File

@@ -6,3 +6,6 @@ settings.json
.DS_Store .DS_Store
.venv .venv
.nvimlog .nvimlog
__pycache__
.pytest_cache

10
.vscode/launch.json vendored
View File

@@ -66,6 +66,16 @@
"preLaunchTask": "Run QEMU", "preLaunchTask": "Run QEMU",
"stopOnEntry": true, "stopOnEntry": true,
"processCreateCommands": ["gdb-remote localhost:1234"] "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"]
} }
] ]
} }

25
Cargo.lock generated
View File

@@ -40,6 +40,15 @@ version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" 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]] [[package]]
name = "log" name = "log"
version = "0.4.29" version = "0.4.29"
@@ -55,6 +64,7 @@ dependencies = [
"log", "log",
"nova_error", "nova_error",
"paste", "paste",
"spin",
] ]
[[package]] [[package]]
@@ -129,6 +139,21 @@ dependencies = [
"getrandom", "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]] [[package]]
name = "syn" name = "syn"
version = "2.0.111" version = "2.0.111"

View File

@@ -18,6 +18,7 @@ heap = {path = "workspace/heap"}
nova_error = {path = "workspace/nova_error"} nova_error = {path = "workspace/nova_error"}
paste = "1.0.15" paste = "1.0.15"
log = "0.4.29" log = "0.4.29"
spin = "0.10.0"
[workspace] [workspace]

View File

@@ -105,7 +105,7 @@ pub enum PhysSource {
} }
#[repr(align(4096))] #[repr(align(4096))]
pub struct PageTable([TableEntry; TABLE_ENTRY_COUNT]); pub struct PageTable(pub [TableEntry; TABLE_ENTRY_COUNT]);
impl Iterator for PageTable { impl Iterator for PageTable {
type Item = VirtAddr; type Item = VirtAddr;
@@ -204,7 +204,6 @@ fn map_range_dynamic(
(virt, _) = virt.overflowing_add(GRANULARITY); (virt, _) = virt.overflowing_add(GRANULARITY);
remaining -= GRANULARITY; remaining -= GRANULARITY;
} }
Ok(()) Ok(())
} }
@@ -224,7 +223,7 @@ pub fn alloc_page(
/// Allocate a singe page in one block. /// Allocate a singe page in one block.
pub fn find_free_kerne_page_in_block(start: VirtAddr) -> Result<VirtAddr, NovaError> { pub fn find_free_kerne_page_in_block(start: VirtAddr) -> Result<VirtAddr, NovaError> {
if !start.is_multiple_of(GRANULARITY) { if !start.is_multiple_of(LEVEL2_BLOCK_SIZE) {
return Err(NovaError::Misalignment); return Err(NovaError::Misalignment);
} }
@@ -238,8 +237,8 @@ pub fn find_free_kerne_page_in_block(start: VirtAddr) -> Result<VirtAddr, NovaEr
)? )?
}; };
if let Some(virt_addr) = table.next() { if let Some(offset) = table.next() {
return Ok(virt_addr); return Ok(start + (offset * GRANULARITY));
} }
Err(NovaError::OutOfMeomory) Err(NovaError::OutOfMeomory)
} }

View File

@@ -1,24 +1,21 @@
use alloc::vec::Vec;
use crate::{ use crate::{
aarch64::mmu::{ aarch64::mmu::{
find_free_kerne_page_in_block, map_page, physical_mapping::reserve_page, TableEntry, find_free_kerne_page_in_block, map_page, physical_mapping::reserve_page, PageTable,
NORMAL_MEM, TRANSLATIONTABLE_TTBR1, WRITABLE, TableEntry, VirtAddr, NORMAL_MEM, TRANSLATIONTABLE_TTBR0, TRANSLATIONTABLE_TTBR1, WRITABLE,
}, },
configuration::memory_mapping::APPLICATION_TRANSLATION_TABLE_VA, configuration::memory_mapping::{APPLICATION_TRANSLATION_TABLE_VA, EL0_STACK_TOP},
}; };
use alloc::vec::Vec;
use core::arch::asm;
use spin::Mutex;
pub struct Application { pub struct Application {
pub table_ptr: *mut TableEntry, pub table_ptr: *mut TableEntry,
} pub start_addr: usize,
impl Default for Application {
fn default() -> Self {
Self::new()
}
} }
impl Application { impl Application {
pub fn new() -> Self { pub fn new(start_addr: VirtAddr) -> Self {
let physical_addr = reserve_page(); let physical_addr = reserve_page();
let virtual_address = let virtual_address =
find_free_kerne_page_in_block(APPLICATION_TRANSLATION_TABLE_VA).unwrap(); find_free_kerne_page_in_block(APPLICATION_TRANSLATION_TABLE_VA).unwrap();
@@ -31,14 +28,55 @@ impl Application {
) )
.unwrap(); .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 { Self {
table_ptr: physical_addr as *mut TableEntry, 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<Vec<Application>> = None; struct AppManager {
apps: Option<Vec<Application>>,
}
impl AppManager {
const fn new() -> Self {
Self { apps: None }
}
}
unsafe impl Send for AppManager {}
static APP_MANAGER: Mutex<AppManager> = Mutex::new(AppManager::new());
pub fn initialize_app_manager() { 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();
}
} }

View File

@@ -78,25 +78,3 @@ configure_mmu_el1:
ret 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

View File

@@ -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 const MAILBOX_VIRTUAL_ADDRESS: VirtAddr = 0xFFFF_FF81_FFFF_E000;
pub static mut MAILBOX_PHYSICAL_ADDRESS: Option<PhysAddr> = None; pub static mut MAILBOX_PHYSICAL_ADDRESS: Option<PhysAddr> = 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; pub const APPLICATION_TRANSLATION_TABLE_VA: VirtAddr = 0xFFFF_FF81_FE00_0000;
extern "C" { extern "C" {

View File

@@ -13,6 +13,7 @@ extern crate alloc;
use alloc::vec::Vec; use alloc::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},
configuration::memory_mapping::initialize_mmu_translation_tables, configuration::memory_mapping::initialize_mmu_translation_tables,
framebuffer::{FrameBuffer, BLUE, GREEN, RED}, framebuffer::{FrameBuffer, BLUE, GREEN, RED},
get_current_el, init_logger, get_current_el, init_logger,
@@ -77,7 +78,6 @@ pub extern "C" fn main() -> ! {
unsafe { unsafe {
el2_to_el1(); el2_to_el1();
} }
#[allow(clippy::empty_loop)] #[allow(clippy::empty_loop)]
loop {} loop {}
} }
@@ -104,6 +104,9 @@ pub extern "C" fn kernel_main() {
enable_irq_source(IRQSource::UartInt); enable_irq_source(IRQSource::UartInt);
let app = Application::new(el0 as *const () as usize);
add_app(app);
kernel_loop(); kernel_loop();
} }

View File

@@ -3,6 +3,7 @@ use core::arch::asm;
use alloc::string::String; use alloc::string::String;
use crate::{ use crate::{
application_manager::start_app,
interrupt_handlers::irq::{register_interrupt_handler, IRQSource}, interrupt_handlers::irq::{register_interrupt_handler, IRQSource},
peripherals::uart::read_uart_data, peripherals::uart::read_uart_data,
pi3::mailbox::read_soc_temp, pi3::mailbox::read_soc_temp,
@@ -15,10 +16,6 @@ pub struct Terminal {
input: String, input: String,
} }
extern "C" {
fn el1_to_el0();
}
impl Default for Terminal { impl Default for Terminal {
fn default() -> Self { fn default() -> Self {
Self::new() Self::new()
@@ -48,7 +45,7 @@ impl Terminal {
"el0" => unsafe { "el0" => unsafe {
let i = 69; let i = 69;
asm!("", in("x0") i); asm!("", in("x0") i);
el1_to_el0(); start_app(0);
}, },
_ => { _ => {
println!("Unknown command: \"{}\"", self.input); println!("Unknown command: \"{}\"", self.input);

View File

@@ -11,4 +11,4 @@ qemu-system-aarch64 \
-cpu cortex-a53 \ -cpu cortex-a53 \
-serial stdio \ -serial stdio \
-sd ../sd.img \ -sd ../sd.img \
-kernel ../target/aarch64-unknown-none/debug/kernel8.img \ -kernel ../target/aarch64-unknown-none/debug/kernel8.img -S -s

View File

@@ -29,7 +29,7 @@ fn test_heap_allocation() {
assert_eq!(actual_alloc_size % MIN_BLOCK_SIZE, 0); assert_eq!(actual_alloc_size % MIN_BLOCK_SIZE, 0);
// Verify section is occupied // Verify section is occupied
assert!((*malloc_header).free == false); assert!(!(*malloc_header).free);
// Verify next header has been created // Verify next header has been created
let next = (*malloc_header).next.unwrap(); let next = (*malloc_header).next.unwrap();
@@ -55,7 +55,7 @@ fn test_full_heap() {
let malloc = heap.malloc(malloc_size).unwrap(); let malloc = heap.malloc(malloc_size).unwrap();
let malloc_header = Heap::get_header_ref_from_data_pointer(malloc); let malloc_header = Heap::get_header_ref_from_data_pointer(malloc);
unsafe { unsafe {
assert_eq!((*malloc_header).free, false); assert!(!(*malloc_header).free);
assert!((*malloc_header).next.is_none()); assert!((*malloc_header).next.is_none());
} }
@@ -79,7 +79,7 @@ fn test_freeing_root() {
let malloc = heap.malloc(malloc_size).unwrap(); let malloc = heap.malloc(malloc_size).unwrap();
let malloc_header = Heap::get_header_ref_from_data_pointer(malloc); let malloc_header = Heap::get_header_ref_from_data_pointer(malloc);
unsafe { unsafe {
assert_eq!((*malloc_header).free, false); assert!(!(*malloc_header).free);
assert!((*malloc_header).size >= malloc_size); assert!((*malloc_header).size >= malloc_size);
assert!((*root_header).next.is_some()); assert!((*root_header).next.is_some());