diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 280c5a5..1cff419 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -14,7 +14,7 @@ { "label": "Run QEMU", "type": "shell", - "command": "llvm-objcopy -O binary target/aarch64-unknown-none/debug/nova target/aarch64-unknown-none/debug/kernel8.img && qemu-system-aarch64 -M raspi3b -cpu cortex-a53 -serial stdio -sd sd.img -display none -kernel ${workspaceFolder}/target/aarch64-unknown-none/debug/kernel8.img -S -s -m 1024", + "command": "llvm-objcopy -O binary target/aarch64-unknown-none/debug/nova target/aarch64-unknown-none/debug/kernel8.img && qemu-system-aarch64 -M raspi3b -cpu cortex-a53 -serial stdio -sd sd.img -kernel ${workspaceFolder}/target/aarch64-unknown-none/debug/kernel8.img -S -s -m 1024", "isBackground": true, "dependsOn": ["Build"] } diff --git a/src/heap.rs b/src/heap.rs index d10e13b..3263161 100644 --- a/src/heap.rs +++ b/src/heap.rs @@ -12,13 +12,16 @@ extern "C" { } #[repr(C)] -struct Header { - next: *mut Header, - before: *mut Header, - size: usize, +pub struct HeapHeader { + pub next: *mut HeapHeader, + before: *mut HeapHeader, + pub size: usize, free: bool, } +const HEAP_HEADER_SIZE: usize = size_of::(); +const MIN_BLOCK_SIZE: usize = 16; + #[derive(Default)] pub struct Novalloc; @@ -28,24 +31,24 @@ unsafe impl GlobalAlloc for Novalloc { } unsafe fn dealloc(&self, ptr: *mut u8, layout: core::alloc::Layout) { - todo!() + free(ptr).unwrap(); } } #[global_allocator] static GLOBAL_ALLOCATOR: Novalloc = Novalloc; -pub fn init_malloc() { +pub fn init_heap() { unsafe { let heap_end = &raw const __heap_end as usize; let heap_start = &raw const __heap_start as usize; - let s = size_of::
(); + ptr::write( - &raw const __heap_start as *mut Header, - Header { + &raw const __heap_start as *mut HeapHeader, + HeapHeader { next: null_mut(), before: null_mut(), - size: heap_end - heap_start - size_of::
(), + size: heap_end - heap_start - HEAP_HEADER_SIZE, free: true, }, ); @@ -53,7 +56,15 @@ pub fn init_malloc() { } pub fn malloc(mut size: usize) -> Result<*mut u8, NovaError> { - let mut head = &raw const __heap_start as *mut Header; + let mut head = &raw const __heap_start as *mut HeapHeader; + + if size == 0 { + return Err(NovaError::EmptyHeapNotAllowed); + } + + if size < MIN_BLOCK_SIZE { + size = MIN_BLOCK_SIZE; + } // Align size to the next 16 bytes size += (16 - (size % 16)) % 16; @@ -67,22 +78,28 @@ pub fn malloc(mut size: usize) -> Result<*mut u8, NovaError> { head = (*head).next; } - let byte_offset = size_of::
() + size; + // Return entire block WITHOUT generating a new header + // if the current block doesn't have enough space to hold: requested size + HEAP_HEADER_SIZE + MIN_BLOCK_SIZE + if (*head).size < size + HEAP_HEADER_SIZE + MIN_BLOCK_SIZE { + (*head).free = false; + return Ok(head.byte_add(HEAP_HEADER_SIZE) as *mut u8); + } + + let byte_offset = HEAP_HEADER_SIZE + size; let new_address = head.byte_add(byte_offset); - // Handle case where free data block is in the center - let mut next = null_mut(); + // Handle case where fragmenting center free space + let next = (*head).next; if !(*head).next.is_null() { - next = (*head).next; (*next).before = new_address; } ptr::write( - new_address as *mut Header, - Header { + new_address as *mut HeapHeader, + HeapHeader { next, before: head, - size: (*head).size - size - size_of::
(), + size: (*head).size - size - HEAP_HEADER_SIZE, free: true, }, ); @@ -90,20 +107,60 @@ pub fn malloc(mut size: usize) -> Result<*mut u8, NovaError> { (*head).free = false; (*head).size = size; - let data_start_address = new_address.byte_add(size_of::
()); + let data_start_address = head.byte_add(HEAP_HEADER_SIZE); Ok(data_start_address as *mut u8) } } +pub fn free(pointer: *mut u8) -> Result<(), NovaError> { + let mut head = unsafe { pointer.sub(HEAP_HEADER_SIZE) as *mut HeapHeader }; + unsafe { + // IF prev is free: + // Delete header, add size to previous and fix pointers. + // Move Head left + if !(*head).before.is_null() && (*(*head).before).free { + let before_head = (*head).before; + (*before_head).size += (*head).size + HEAP_HEADER_SIZE; + delete_header(head); + head = before_head; + } + // IF next is free: + // Delete next header and merge size, fix pointers + if !(*head).next.is_null() && (*(*head).next).free { + let next_head = (*head).next; + (*head).size += (*next_head).size + HEAP_HEADER_SIZE; + delete_header(next_head); + } + // Neither: Set free + (*head).free = true; + } + + Ok(()) +} + +unsafe fn delete_header(header: *mut HeapHeader) { + let before = (*header).before; + let next = (*header).next; + + if !before.is_null() { + (*before).next = next; + } + + if !next.is_null() { + (*next).before = before; + } +} + pub fn traverse_heap_tree() { - let mut pointer_address = &raw const __heap_start as *const Header; + let mut pointer_address = &raw const __heap_start as *const HeapHeader; loop { let head = unsafe { read_volatile(pointer_address) }; - println!("Header {}", pointer_address as u32); + 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 { diff --git a/src/lib.rs b/src/lib.rs index b874e02..f9fdc23 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -40,4 +40,5 @@ pub fn mmio_write(address: u32, data: u32) { pub enum NovaError { Mailbox, HeapFull, + EmptyHeapNotAllowed, } diff --git a/src/main.rs b/src/main.rs index cca3033..f2c21d9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,11 +9,10 @@ use core::{ }; extern crate alloc; -use alloc::vec::Vec; use nova::{ framebuffer::{FrameBuffer, BLUE, GREEN, RED}, - heap::{init_malloc, malloc, traverse_heap_tree}, + heap::init_heap, irq_interrupt::enable_irq_source, mailbox::mb_read_soc_temp, peripherals::{ @@ -89,18 +88,8 @@ unsafe fn zero_bss() { pub extern "C" fn kernel_main() -> ! { println!("EL: {}", get_current_el()); - // Heap stuff - init_malloc(); - malloc(32).unwrap(); - malloc(32).unwrap(); - - let mut vector = Vec::::new(); - - vector.push(5); - malloc(32).unwrap(); - vector.push(8); - vector.push(8); - vector.push(8); + // Initialize the first heap header + init_heap(); sleep_us(500_000);