heap/linker/main: set up a heap allocator
authorKit Rhett Aultman <kit@kitaultman.com>
Sun, 30 Jun 2024 16:38:01 +0000 (12:38 -0400)
committerKit Rhett Aultman <kit@kitaultman.com>
Sun, 30 Jun 2024 16:38:01 +0000 (12:38 -0400)
This commit sets up a heap allocator.  Again, I cannot sufficiently
stress the usefulness of Meyer Zinn for getting things this far, and
much of what I needed to know about getting linker symbols propagated
into Rust code comes from:
https://meyerzinn.tech/posts/2023/03/08/p1-printing-and-allocating/

Meyer steps through the process of setting up the linked list allocator.
However, there's a buddy list allocator that can be used as a drop-in
replacement, and since this is a more common allocator scheme, and since
doing my own thing means writing my own code and getting more familiar
with Rust, it seemed a divergence worth taking.

Cargo.lock
Cargo.toml
src/heap.rs [new file with mode: 0644]
src/linker.ld
src/main.rs

index 75e1067292c5566d3e670f5c1ed693f9577bd5d9..d7e35c554e59025ec9e253cbd99f4c042924959e 100644 (file)
@@ -20,6 +20,15 @@ version = "1.3.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
 
+[[package]]
+name = "buddy_system_allocator"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d44d578cadd17312c75e7d0ef489361f160ace58f7139aa32001fee1a51b89b5"
+dependencies = [
+ "spin",
+]
+
 [[package]]
 name = "lock_api"
 version = "0.4.12"
@@ -43,6 +52,7 @@ dependencies = [
 name = "riscv"
 version = "0.1.0"
 dependencies = [
+ "buddy_system_allocator",
  "spinning_top",
  "uart_16550",
 ]
@@ -59,6 +69,15 @@ version = "1.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
 
+[[package]]
+name = "spin"
+version = "0.9.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
+dependencies = [
+ "lock_api",
+]
+
 [[package]]
 name = "spinning_top"
 version = "0.3.0"
index f88d624c0e1fc69d1e0174bbc6f517217167ac8d..ab3c17d3f9a9d2932c0fd345558afaf984d5468b 100644 (file)
@@ -7,6 +7,7 @@ edition = "2021"
 target = "riscv64gc-unknown-none-elf"
 
 [dependencies]
+buddy_system_allocator = "0.9.1"
 spinning_top = "0.3.0"
 uart_16550 = "0.3.0"
 
diff --git a/src/heap.rs b/src/heap.rs
new file mode 100644 (file)
index 0000000..6eca8bb
--- /dev/null
@@ -0,0 +1,31 @@
+
+
+use buddy_system_allocator::LockedHeap;
+
+// The recommended order for the heap is 32, which to me says the largest
+// block size would be 2^32, or 4GiB.  We don't actually have that available
+// but at the same time, when I tried to reduce the order down to 16 the init
+// simply stalled out.  So...32 is is. ((shrug))
+
+#[global_allocator]
+static HEAP_ALLOCATOR: LockedHeap<32> = LockedHeap::<32>::empty();
+
+pub unsafe fn init() {
+    let heap_start: usize;
+    let heap_size: usize;
+    // UNSAFE: This is fine, just loading some constants.
+    unsafe {
+        // using inline assembly is easier to access linker constants
+        use core::arch::asm;
+        asm!(
+          "la {heap_start}, _heap_start",
+          "la {heap_size}, _heap_size",
+          heap_start = out(reg) heap_start,
+          heap_size = out(reg) heap_size,
+          options(nomem)
+        )
+    };
+    println!("Kernel heap symbols: start: {:#x}, size: {}", heap_start, heap_size);
+
+    unsafe { HEAP_ALLOCATOR.lock().init(heap_start, heap_size); }
+}
index 21ec60bb0b9ad1824c6c5fd6db92f8c2e70a5386..364615a7c7d64c3c143cf59864ef47bf2f3555a1 100644 (file)
@@ -37,8 +37,17 @@ SECTIONS {
     *(.sbss .sbss.*) *(.bss .bss.*)
     PROVIDE(_bss_end = .); # ... and one at the end
   } >RAM AT>RAM :bss # and this goes into the bss segment
-
+  PROVIDE(_kernel_end = .);
+
+  # heap reserved space starts where the kernel ends and
+  # continues until it reaches the stack.  Because the stack
+  # is a fixed size, as the kernel grows, the heap will shrink
+  PROVIDE(_heap_start = .);
+  PROVIDE(_heap_size = _stack_bottom - _heap_start);
+  
   # start the stack at the end of memory and let it grow downward
+  # capped at 1M
+  PROVIDE(_stack_bottom = ORIGIN(RAM) + LENGTH(RAM) - 1M);
   PROVIDE(_stack_top = ORIGIN(RAM) + LENGTH(RAM));
 }
 
index 3e9bc536d03e987c918a7f683d21c53c0c3b2bba..99941dadb378ac01af9b79c18837f938da322b78 100644 (file)
@@ -2,7 +2,9 @@
 #![no_main]
 #![feature(naked_functions)] // enable functions that are pure inline assembly
 
+#[macro_use]
 mod console;
+mod heap;
 
 use core::panic::PanicInfo;
 
@@ -60,8 +62,16 @@ unsafe extern "C" fn _start() -> ! {
 
 #[no_mangle] // Again, being mindful of the C calling convention
 extern "C" fn entry() -> ! {
+    // Init serial console
     use crate::console;
     console::init_console();
     println!("KIT-- hello works from println!");
+
+    // Init heap
+    use crate::heap;
+    // Safety: initialize once (and that's done now)
+    unsafe { heap::init() };
+
+    println!("Kernel init complete");
     loop {}
 }