From abdef70198fe261f623a82e53e5953f712d0d55b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Neuh=C3=A4user?= Date: Fri, 19 Dec 2025 15:32:54 +0100 Subject: [PATCH] use virtual workspaces for heap --- .cargo/config.toml | 3 - Cargo.lock | 13 ++++ Cargo.toml | 8 +++ NovaError/Cargo.toml | 4 ++ NovaError/src/lib.rs | 11 +++ heap/Cargo.toml | 7 ++ src/heap.rs => heap/src/lib.rs | 120 ++++++++++++++------------------- src/lib.rs | 37 +++++++--- src/mailbox.rs | 6 +- src/main.rs | 41 +++++------ 10 files changed, 138 insertions(+), 112 deletions(-) create mode 100644 NovaError/Cargo.toml create mode 100644 NovaError/src/lib.rs create mode 100644 heap/Cargo.toml rename src/heap.rs => heap/src/lib.rs (68%) diff --git a/.cargo/config.toml b/.cargo/config.toml index 1c1fd15..b0f88f2 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,5 +1,2 @@ -[build] -target = "aarch64-unknown-none" - [target.aarch64-unknown-none] rustflags = ["-C", "link-arg=-Tlink.ld"] diff --git a/Cargo.lock b/Cargo.lock index e68673b..be73e2b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,17 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "NovaError" +version = "0.1.0" + +[[package]] +name = "heap" +version = "0.1.0" +dependencies = [ + "NovaError", +] + [[package]] name = "libm" version = "0.2.15" @@ -12,5 +23,7 @@ checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" name = "nova" version = "0.1.0" dependencies = [ + "NovaError", + "heap", "libm", ] diff --git a/Cargo.toml b/Cargo.toml index 8de0a0e..dd540d0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,3 +14,11 @@ panic = "abort" [dependencies] libm = "0.2.15" +heap = {path = "heap"} +NovaError = {path = "NovaError"} + +[workspace] + +members = [ "NovaError", + "heap" +] diff --git a/NovaError/Cargo.toml b/NovaError/Cargo.toml new file mode 100644 index 0000000..55e27e1 --- /dev/null +++ b/NovaError/Cargo.toml @@ -0,0 +1,4 @@ +[package] +name = "NovaError" +version = "0.1.0" +edition = "2024" diff --git a/NovaError/src/lib.rs b/NovaError/src/lib.rs new file mode 100644 index 0000000..931c10a --- /dev/null +++ b/NovaError/src/lib.rs @@ -0,0 +1,11 @@ +#![no_std] + +use core::fmt::Debug; +use core::prelude::rust_2024::derive; + +#[derive(Debug)] +pub enum NovaError { + Mailbox, + HeapFull, + EmptyHeapSegmentNotAllowed, +} diff --git a/heap/Cargo.toml b/heap/Cargo.toml new file mode 100644 index 0000000..5665fac --- /dev/null +++ b/heap/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "heap" +version = "0.1.0" +edition = "2024" + +[dependencies] +NovaError = {path = "../NovaError"} diff --git a/src/heap.rs b/heap/src/lib.rs similarity index 68% rename from src/heap.rs rename to heap/src/lib.rs index 65d7351..99e193a 100644 --- a/src/heap.rs +++ b/heap/src/lib.rs @@ -1,17 +1,21 @@ #![allow(static_mut_refs)] +#![cfg_attr(not(test), no_std)] use core::{ alloc::GlobalAlloc, + default::Default, + mem::size_of, + prelude::v1::*, ptr::{self, null_mut, read_volatile}, + result::Result, }; -use crate::NovaError; -extern crate alloc; +use NovaError::NovaError; -extern "C" { - static mut __heap_start: u8; - static mut __heap_end: u8; -} +#[cfg(not(target_os = "none"))] +extern crate std; + +extern crate alloc; #[repr(C, align(16))] pub struct HeapHeader { @@ -27,51 +31,26 @@ const MIN_BLOCK_SIZE: usize = 16; // TODO: This implementation has to be reevaluated when implementing multiprocessing // Spinlock could be a solution but has its issues: // https://matklad.github.io/2020/01/02/spinlocks-considered-harmful.html -pub static mut HEAP: Heap = Heap { - start_address: &raw mut __heap_start as *mut HeapHeader, - end_address: &raw mut __heap_end as *mut HeapHeader, - raw_size: 0, -}; - -// TODO: investigate if there is a better alternative to this -pub unsafe fn init_global_heap() { - HEAP.init(); -} - -#[derive(Default)] -pub struct Novalloc; - -unsafe impl GlobalAlloc for Novalloc { - unsafe fn alloc(&self, layout: core::alloc::Layout) -> *mut u8 { - HEAP.malloc(layout.size()).unwrap() - } - - unsafe fn dealloc(&self, ptr: *mut u8, _: core::alloc::Layout) { - HEAP.free(ptr).unwrap(); - } -} - -#[global_allocator] -static GLOBAL_ALLOCATOR: Novalloc = Novalloc; pub struct Heap { - start_address: *mut HeapHeader, - end_address: *mut HeapHeader, - raw_size: usize, + pub start_address: *mut HeapHeader, + pub end_address: *mut HeapHeader, + pub raw_size: usize, } impl Heap { - pub fn new(heap_start: usize, heap_end: usize) -> Self { - let mut instance = Self { - start_address: &raw const heap_start as *mut HeapHeader, - end_address: &raw const heap_end as *mut HeapHeader, - raw_size: heap_end - heap_start, - }; - instance.init(); - instance + pub const fn empty() -> Self { + Self { + start_address: null_mut() as *mut HeapHeader, + end_address: null_mut() as *mut HeapHeader, + raw_size: 0, + } } - fn init(&mut self) { - self.raw_size = self.end_address as usize - self.start_address as usize; + pub fn init(&mut self, heap_start: usize, heap_end: usize) { + self.start_address = heap_start as *mut HeapHeader; + self.end_address = heap_end as *mut HeapHeader; + + self.raw_size = heap_end - heap_start; unsafe { ptr::write( @@ -130,7 +109,7 @@ impl Heap { unsafe fn fragment_segment(current: *mut HeapHeader, size: usize) { let byte_offset = HEAP_HEADER_SIZE + size; - let new_address = current.byte_add(byte_offset); + let new_address = unsafe { current.byte_add(byte_offset) }; // Handle case where fragmenting center free space let next = (*current).next; @@ -138,15 +117,17 @@ impl Heap { (*next).before = new_address; } - ptr::write( - new_address as *mut HeapHeader, - HeapHeader { - next, - before: current, - size: (*current).size - size - HEAP_HEADER_SIZE, - free: true, - }, - ); + unsafe { + ptr::write( + new_address as *mut HeapHeader, + HeapHeader { + next, + before: current, + size: (*current).size - size - HEAP_HEADER_SIZE, + free: true, + }, + ) + }; (*current).next = new_address; (*current).free = false; (*current).size = size; @@ -178,26 +159,20 @@ impl Heap { Ok(()) } +} - pub fn traverse_heap(&self) { - let mut pointer_address = self.start_address; - loop { - let head = unsafe { read_volatile(pointer_address) }; - println!("Header {:#x}", pointer_address as u32); - println!("free: {}", head.free); - println!("size: {}", head.size); - println!("hasNext: {}", !head.next.is_null()); - println!(""); - if !head.next.is_null() { - pointer_address = head.next; - } else { - println!("---------------"); - return; - } - } +unsafe impl GlobalAlloc for Heap { + unsafe fn alloc(&self, layout: core::alloc::Layout) -> *mut u8 { + self.malloc(layout.size()).unwrap() + } + + unsafe fn dealloc(&self, ptr: *mut u8, _: core::alloc::Layout) { + self.free(ptr).unwrap(); } } +unsafe impl Sync for Heap {} + unsafe fn fits(size: usize, header: *mut HeapHeader) -> bool { (*header).free && size <= (*header).size } @@ -214,3 +189,6 @@ unsafe fn delete_header(header: *mut HeapHeader) { (*next).before = before; } } + +#[cfg(test)] +mod tests {} diff --git a/src/lib.rs b/src/lib.rs index e5beec1..fc87771 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,33 @@ #![no_std] -use core::ptr::{read_volatile, write_volatile}; +use core::{ + panic::PanicInfo, + ptr::{read_volatile, write_volatile}, +}; + +use heap::Heap; + +unsafe extern "C" { + unsafe static mut __heap_start: u8; + unsafe static mut __heap_end: u8; +} + +#[global_allocator] +pub static mut GLOBAL_ALLOCATOR: Heap = Heap::empty(); + +pub unsafe fn init_heap() { + let start = core::ptr::addr_of_mut!(__heap_start) as usize; + let end = core::ptr::addr_of_mut!(__heap_end) as usize; + + GLOBAL_ALLOCATOR.init(start, end); +} + +#[panic_handler] +fn panic(_panic: &PanicInfo) -> ! { + loop { + println!("Panic"); + } +} #[macro_export] macro_rules! print { @@ -23,7 +50,6 @@ pub mod peripherals; pub mod configuration; pub mod framebuffer; -pub mod heap; pub mod irq_interrupt; pub mod mailbox; pub mod timer; @@ -35,10 +61,3 @@ pub fn mmio_read(address: u32) -> u32 { pub fn mmio_write(address: u32, data: u32) { unsafe { write_volatile(address as *mut u32, data) } } - -#[derive(Debug)] -pub enum NovaError { - Mailbox, - HeapFull, - EmptyHeapSegmentNotAllowed, -} diff --git a/src/mailbox.rs b/src/mailbox.rs index 35cce2f..cc9cb84 100644 --- a/src/mailbox.rs +++ b/src/mailbox.rs @@ -1,4 +1,4 @@ -use crate::{mmio_read, mmio_write, NovaError}; +use crate::{mmio_read, mmio_write}; const MBOX_BASE: u32 = 0x3F00_0000 + 0xB880; @@ -29,7 +29,7 @@ macro_rules! mailbox_command { /// More information at: https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface pub fn $name( request_data: [u32; $request_len / 4], - ) -> Result<[u32; $response_len / 4], NovaError> { + ) -> Result<[u32; $response_len / 4], NovaError::NovaError> { let mut mailbox = [0u32; (HEADER_LENGTH + max!($request_len, $response_len) + FOOTER_LENGTH) / 4]; mailbox[0] = (HEADER_LENGTH + max!($request_len, $response_len) + FOOTER_LENGTH) as u32; // Total length in Bytes @@ -48,7 +48,7 @@ macro_rules! mailbox_command { let _ = read_mailbox(8); if mailbox[1] == 0 { - return Err(NovaError::Mailbox); + return Err(NovaError::NovaError::Mailbox); } let mut out = [0u32; $response_len / 4]; diff --git a/src/main.rs b/src/main.rs index 5f778ea..082715a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,7 +4,6 @@ #![allow(static_mut_refs)] use core::{ arch::{asm, global_asm}, - panic::PanicInfo, ptr::write_volatile, }; @@ -12,7 +11,7 @@ extern crate alloc; use nova::{ framebuffer::{FrameBuffer, BLUE, GREEN, RED}, - heap::{init_global_heap, HEAP}, + init_heap, irq_interrupt::enable_irq_source, mailbox::mb_read_soc_temp, peripherals::{ @@ -24,6 +23,7 @@ use nova::{ }, print, println, timer::{delay_nops, sleep_us}, + GLOBAL_ALLOCATOR, }; global_asm!(include_str!("vector.S")); @@ -34,15 +34,8 @@ extern "C" { static mut __bss_end: u32; } -#[panic_handler] -fn panic(_panic: &PanicInfo) -> ! { - loop { - println!("Panic"); - } -} - #[no_mangle] -#[link_section = ".text._start"] +#[cfg_attr(not(test), link_section = ".text._start")] pub unsafe extern "C" fn _start() { // Set the stack pointer asm!( @@ -88,7 +81,10 @@ unsafe fn zero_bss() { pub extern "C" fn kernel_main() -> ! { println!("EL: {}", get_current_el()); - heap_test(); + unsafe { + init_heap(); + heap_test(); + }; sleep_us(500_000); @@ -116,21 +112,14 @@ pub extern "C" fn kernel_main() -> ! { } } -fn heap_test() { - unsafe { - init_global_heap(); - let a = HEAP.malloc(32).unwrap(); - let b = HEAP.malloc(64).unwrap(); - let c = HEAP.malloc(128).unwrap(); - let _ = HEAP.malloc(256).unwrap(); - HEAP.traverse_heap(); - HEAP.free(b).unwrap(); - HEAP.traverse_heap(); - HEAP.free(a).unwrap(); - HEAP.traverse_heap(); - HEAP.free(c).unwrap(); - HEAP.traverse_heap(); - } +unsafe fn heap_test() { + let a = GLOBAL_ALLOCATOR.malloc(32).unwrap(); + let b = GLOBAL_ALLOCATOR.malloc(64).unwrap(); + let c = GLOBAL_ALLOCATOR.malloc(128).unwrap(); + let _ = GLOBAL_ALLOCATOR.malloc(256).unwrap(); + GLOBAL_ALLOCATOR.free(b).unwrap(); + GLOBAL_ALLOCATOR.free(a).unwrap(); + GLOBAL_ALLOCATOR.free(c).unwrap(); } fn cos(x: u32) -> f64 {