diff --git a/Cargo.lock b/Cargo.lock index 701845c..a79a386 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12,7 +12,17 @@ checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" name = "kernel" version = "0.1.0" dependencies = [ - "spinning_top", + "linked_list_allocator", + "spinning_top 0.3.0", +] + +[[package]] +name = "linked_list_allocator" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afa463f5405ee81cdb9cc2baf37e08ec7e4c8209442b5d72c04cfb2cd6e6286" +dependencies = [ + "spinning_top 0.2.5", ] [[package]] @@ -31,6 +41,15 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "spinning_top" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b9eb1a2f4c41445a3a0ff9abc5221c5fcd28e1f13cd7c0397706f9ac938ddb0" +dependencies = [ + "lock_api", +] + [[package]] name = "spinning_top" version = "0.3.0" diff --git a/Cargo.toml b/Cargo.toml index 3d34e78..e8d3973 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,4 +4,5 @@ version = "0.1.0" edition = "2021" [dependencies] +linked_list_allocator = "0.10.5" spinning_top = "0.3.0" diff --git a/src/heap.rs b/src/heap.rs new file mode 100644 index 0000000..910a0a5 --- /dev/null +++ b/src/heap.rs @@ -0,0 +1,36 @@ +// src/heap.rs +//! Provides the kernel heap. + +use core::arch::asm; + +use linked_list_allocator::LockedHeap; + +use crate::println; + +#[global_allocator] +static ALLOCATOR: LockedHeap = LockedHeap::empty(); + +/// Initialise the kernel heap. +/// # Safety +/// Must be called at most once. +pub unsafe fn init() { + let heap_bottom; + let heap_size; + // UNSAFE: This is fine, just loading some constants. + unsafe { + // using inline assembly is easier to access linker constants + asm!( + "la {heap_bottom}, _kernel_heap_bottom", + "la {heap_size}, _kernel_heap_size", + heap_bottom = out(reg) heap_bottom, + heap_size = out(reg) heap_size, + options(nomem) + ) + }; + println!( + "Initialising kernel heap (bottom: {:#x}, size: {:#x})", + heap_bottom as usize, heap_size + ); + // UNSAFE: Fine to call at most once. + unsafe { ALLOCATOR.lock().init(heap_bottom, heap_size) }; +} diff --git a/src/main.rs b/src/main.rs index 24f9197..46646d2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,9 +1,11 @@ +// src/main.rs #![no_std] #![no_main] #![feature(naked_functions)] use core::panic::PanicInfo; +mod heap; mod uart; #[naked] @@ -43,6 +45,17 @@ unsafe extern "C" fn _start() -> ! { } extern "C" fn entry() -> ! { + // UNSAFE: Called exactly once, right here. + unsafe { heap::init() }; + + // Now we're free to use dynamic allocation! + { + extern crate alloc; + use alloc::boxed::Box; + let _my_heap_pointer = Box::new(10); + // _my_heap_pointer lives on the heap! + } + println!("This should not print because the console is not initialised."); unsafe { uart::init_console(0x1000_0000) }; println!("Hello, world!"); @@ -59,3 +72,5 @@ extern "C" fn entry() -> ! { fn on_panic(_info: &PanicInfo) -> ! { loop {} } + +// TODO unit testing \ No newline at end of file diff --git a/src/script.ld b/src/script.ld index c4444a1..3aad866 100644 --- a/src/script.ld +++ b/src/script.ld @@ -39,4 +39,8 @@ SECTIONS { . = ALIGN(16); # our stack needs to be 16-byte aligned, per the C calling convention PROVIDE(_init_stack_top = . + 0x1000); # reserve 0x1000 bytes for the initialisation stack + + PROVIDE(_kernel_heap_bottom = _init_stack_top); # allocate heap to remaining physical memory + PROVIDE(_kernel_heap_top = ORIGIN(ram) + LENGTH(ram)); # top of heap is end of ram + PROVIDE(_kernel_heap_size = _kernel_heap_top - _kernel_heap_bottom); # capture size of heap } \ No newline at end of file diff --git a/src/uart.rs b/src/uart.rs index f54e272..4a1e766 100644 --- a/src/uart.rs +++ b/src/uart.rs @@ -1,3 +1,4 @@ +// src/uart.rs //! This module provides access to the UART console. use spinning_top::Spinlock;