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
.venv
.nvimlog
__pycache__
.pytest_cache

10
.vscode/launch.json vendored
View File

@@ -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"]
}
]
}

25
Cargo.lock generated
View File

@@ -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"

View File

@@ -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]

View File

@@ -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<VirtAddr, NovaError> {
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<VirtAddr, NovaEr
)?
};
if let Some(virt_addr) = table.next() {
return Ok(virt_addr);
if let Some(offset) = table.next() {
return Ok(start + (offset * GRANULARITY));
}
Err(NovaError::OutOfMeomory)
}

View File

@@ -1,24 +1,21 @@
use alloc::vec::Vec;
use crate::{
aarch64::mmu::{
find_free_kerne_page_in_block, map_page, physical_mapping::reserve_page, TableEntry,
NORMAL_MEM, TRANSLATIONTABLE_TTBR1, WRITABLE,
find_free_kerne_page_in_block, map_page, physical_mapping::reserve_page, PageTable,
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 table_ptr: *mut TableEntry,
}
impl Default for Application {
fn default() -> 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<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() {
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
.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 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;
extern "C" {

View File

@@ -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();
}

View File

@@ -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);

View File

@@ -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

View File

@@ -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());