diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 18998f4..280c5a5 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -14,7 +14,7 @@ { "label": "Run QEMU", "type": "shell", - "command": "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 -display none -kernel ${workspaceFolder}/target/aarch64-unknown-none/debug/kernel8.img -S -s -m 1024", "isBackground": true, "dependsOn": ["Build"] } diff --git a/README.md b/README.md index 325091c..e7ad108 100644 --- a/README.md +++ b/README.md @@ -12,5 +12,8 @@ NovaOS is a expository project where I build a kernel from scratch for a Raspber - GPIO Interrupts ✓ - Communicate with peripherals via mailboxes ✓ - Frame Buffer ✓ +- Heap Memory allocation +- Dynamic clock speed - MMU +- Multiprocessing - Basic Terminal over UART diff --git a/link.ld b/link.ld index f4ef72e..7ead11e 100644 --- a/link.ld +++ b/link.ld @@ -27,9 +27,17 @@ SECTIONS { KEEP(*(.vector_table)) } - .stack 0x8018000 : ALIGN(16) + .heap 0x8000000 : ALIGN(16) + { + __heap_start = .; + . += 0x10000; #10kB + __heap_end = .; + } + + .stack : ALIGN(16) { __stack_start = .; + . += 0x10000; #10kB stack __stack_end = .; } diff --git a/src/framebuffer.rs b/src/framebuffer.rs index cbafe26..0eeafb2 100644 --- a/src/framebuffer.rs +++ b/src/framebuffer.rs @@ -9,7 +9,6 @@ use crate::mailbox::{read_mailbox, write_mailbox}; struct Mailbox([u32; 36]); const ALLOCATE_BUFFER: u32 = 0x0004_0001; -const GET_PHYSICAL_DISPLAY_WH: u32 = 0x0004_0003; const SET_PHYSICAL_DISPLAY_WH: u32 = 0x0004_8003; const SET_VIRTUAL_DISPLAY_WH: u32 = 0x0004_8004; const SET_PIXEL_DEPTH: u32 = 0x0004_8005; @@ -242,26 +241,3 @@ impl FrameBuffer { } } } - -pub fn print_display_resolution() { - let mut mailbox: [u32; 8] = [0; 8]; - mailbox[0] = 8 * 4; - mailbox[1] = 0; - mailbox[2] = GET_PHYSICAL_DISPLAY_WH; - mailbox[3] = 8; - mailbox[4] = 0; - mailbox[5] = 0; - mailbox[6] = 0; - mailbox[7] = 0; - - let addr = core::ptr::addr_of!(mailbox[0]) as u32; - - write_mailbox(8, addr); - - let _ = read_mailbox(8); - if mailbox[1] == 0 { - println!("Failed"); - } - - println!("Width x Height: {}x{}", mailbox[5], mailbox[6]); -} diff --git a/src/heap.rs b/src/heap.rs new file mode 100644 index 0000000..d10e13b --- /dev/null +++ b/src/heap.rs @@ -0,0 +1,114 @@ +use core::{ + alloc::GlobalAlloc, + ptr::{self, null, null_mut, read_volatile, write_volatile}, +}; + +use crate::NovaError; +extern crate alloc; + +extern "C" { + static mut __heap_start: u8; + static mut __heap_end: u8; +} + +#[repr(C)] +struct Header { + next: *mut Header, + before: *mut Header, + size: usize, + free: bool, +} + +#[derive(Default)] +pub struct Novalloc; + +unsafe impl GlobalAlloc for Novalloc { + unsafe fn alloc(&self, layout: core::alloc::Layout) -> *mut u8 { + malloc(layout.size()).unwrap() + } + + unsafe fn dealloc(&self, ptr: *mut u8, layout: core::alloc::Layout) { + todo!() + } +} + +#[global_allocator] +static GLOBAL_ALLOCATOR: Novalloc = Novalloc; + +pub fn init_malloc() { + 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 { + next: null_mut(), + before: null_mut(), + size: heap_end - heap_start - size_of::
(), + free: true, + }, + ); + } +} + +pub fn malloc(mut size: usize) -> Result<*mut u8, NovaError> { + let mut head = &raw const __heap_start as *mut Header; + + // Align size to the next 16 bytes + size += (16 - (size % 16)) % 16; + + unsafe { + // Find First-Fit memory segment + while !(*head).free || size > (*head).size { + if (*head).next.is_null() { + return Err(NovaError::HeapFull); + } + head = (*head).next; + } + + let byte_offset = size_of::
() + size; + let new_address = head.byte_add(byte_offset); + + // Handle case where free data block is in the center + let mut next = null_mut(); + if !(*head).next.is_null() { + next = (*head).next; + (*next).before = new_address; + } + + ptr::write( + new_address as *mut Header, + Header { + next, + before: head, + size: (*head).size - size - size_of::
(), + free: true, + }, + ); + (*head).next = new_address; + (*head).free = false; + (*head).size = size; + + let data_start_address = new_address.byte_add(size_of::
()); + + Ok(data_start_address as *mut u8) + } +} + +pub fn traverse_heap_tree() { + let mut pointer_address = &raw const __heap_start as *const Header; + loop { + let head = unsafe { read_volatile(pointer_address) }; + println!("Header {}", pointer_address as u32); + println!("free: {}", head.free); + println!("size: {}", head.size); + println!("hasNext: {}", !head.next.is_null()); + if !head.next.is_null() { + pointer_address = head.next; + } else { + println!("---------------"); + return; + } + } +} diff --git a/src/lib.rs b/src/lib.rs index ef07ac5..b874e02 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -23,9 +23,9 @@ pub mod peripherals; pub mod configuration; pub mod framebuffer; +pub mod heap; pub mod irq_interrupt; pub mod mailbox; -pub mod math; pub mod timer; pub fn mmio_read(address: u32) -> u32 { @@ -39,4 +39,5 @@ pub fn mmio_write(address: u32, data: u32) { #[derive(Debug)] pub enum NovaError { Mailbox, + HeapFull, } diff --git a/src/mailbox.rs b/src/mailbox.rs index 8f2dc46..5cfe8ad 100644 --- a/src/mailbox.rs +++ b/src/mailbox.rs @@ -58,7 +58,10 @@ macro_rules! mailbox_command { }; } -mailbox_command!(mb_read_soc_temp, 0x00030006, 4, 8); +mailbox_command!(mb_read_soc_temp, 0x0003_0006, 4, 8); + +// Framebuffer +mailbox_command!(mb_get_display_resolution, 0x0004_0003, 0, 8); pub fn read_mailbox(channel: u32) -> u32 { // Wait until mailbox is not empty diff --git a/src/main.rs b/src/main.rs index 0af0cb3..cca3033 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,11 +8,14 @@ use core::{ ptr::write_volatile, }; +extern crate alloc; +use alloc::vec::Vec; + use nova::{ - framebuffer::{print_display_resolution, FrameBuffer, BLUE, GREEN, ORANGE, RED, YELLOW}, + framebuffer::{FrameBuffer, BLUE, GREEN, RED}, + heap::{init_malloc, malloc, traverse_heap_tree}, irq_interrupt::enable_irq_source, mailbox::mb_read_soc_temp, - math::polar_to_cartesian, peripherals::{ gpio::{ blink_gpio, gpio_pull_up, set_falling_edge_detect, set_gpio_function, GPIOFunction, @@ -44,7 +47,7 @@ fn panic(_panic: &PanicInfo) -> ! { pub unsafe extern "C" fn _start() { // Set the stack pointer asm!( - "ldr x0, =0x8008000", + "ldr x0, =__stack_end", "mov sp, x0", "b main", options(noreturn) @@ -61,8 +64,6 @@ pub extern "C" fn main() -> ! { // Set ACT Led to Outout let _ = set_gpio_function(21, GPIOFunction::Output); - print_current_el_str(); - // Delay so clock speed can stabilize delay_nops(50000); println!("Hello World!"); @@ -86,7 +87,20 @@ unsafe fn zero_bss() { #[no_mangle] pub extern "C" fn kernel_main() -> ! { - print_current_el_str(); + 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); sleep_us(500_000); @@ -96,20 +110,7 @@ pub extern "C" fn kernel_main() -> ! { gpio_pull_up(26); set_falling_edge_detect(26, true); - print_display_resolution(); let fb = FrameBuffer::new(); - print_display_resolution(); - - for a in 0..360 { - let (x, y) = polar_to_cartesian(100.0, a as f32); - fb.draw_line( - 150, - 150, - (150.0 + x) as u32, - (150.0 + y) as u32, - a * (0x00FFFFFF / 360), - ); - } fb.draw_square(500, 500, 600, 700, RED); fb.draw_square_fill(800, 800, 900, 900, GREEN); @@ -118,10 +119,6 @@ pub extern "C" fn kernel_main() -> ! { fb.draw_string("Hello World! :D\nTest next Line", 500, 5, 3, BLUE); fb.draw_function(cos, 100, 101, RED); - fb.draw_function(cos, 100, 102, ORANGE); - fb.draw_function(cos, 100, 103, YELLOW); - fb.draw_function(cos, 100, 104, GREEN); - fb.draw_function(cos, 100, 105, BLUE); loop { let temp = mb_read_soc_temp([0]).unwrap(); @@ -153,16 +150,3 @@ fn enable_uart() { let _ = set_gpio_function(14, GPIOFunction::Alternative0); let _ = set_gpio_function(15, GPIOFunction::Alternative0); } - -fn print_current_el_str() { - let el = get_current_el(); - let el_str = match el { - 0b11 => "Level 3", - 0b10 => "Level 2", - 0b01 => "Level 1", - 0b00 => "Level 0", - _ => "Unknown EL", - }; - - println!("{}", el_str); -} diff --git a/src/math.rs b/src/math.rs deleted file mode 100644 index 4597857..0000000 --- a/src/math.rs +++ /dev/null @@ -1,5 +0,0 @@ -pub fn polar_to_cartesian(r: f32, theta_rad: f32) -> (f32, f32) { - let x = r * libm::cosf(theta_rad); - let y = r * libm::sinf(theta_rad); - (x, y) -}