clean up and use own heap

This commit is contained in:
Bryan McShea
2024-02-16 02:26:23 -05:00
parent 167b095bd1
commit 05e9433ceb
13 changed files with 148 additions and 112 deletions

35
kernel/Cargo.lock generated
View File

@@ -83,7 +83,6 @@ dependencies = [
"bootloader_api", "bootloader_api",
"embedded-graphics", "embedded-graphics",
"lazy_static", "lazy_static",
"linked_list_allocator",
"pc-keyboard", "pc-keyboard",
"pic8259", "pic8259",
"uart_16550", "uart_16550",
@@ -99,25 +98,6 @@ dependencies = [
"spin", "spin",
] ]
[[package]]
name = "linked_list_allocator"
version = "0.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9afa463f5405ee81cdb9cc2baf37e08ec7e4c8209442b5d72c04cfb2cd6e6286"
dependencies = [
"spinning_top",
]
[[package]]
name = "lock_api"
version = "0.4.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45"
dependencies = [
"autocfg",
"scopeguard",
]
[[package]] [[package]]
name = "micromath" name = "micromath"
version = "2.1.0" version = "2.1.0"
@@ -163,27 +143,12 @@ version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4"
[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]] [[package]]
name = "spin" name = "spin"
version = "0.5.2" version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
[[package]]
name = "spinning_top"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b9eb1a2f4c41445a3a0ff9abc5221c5fcd28e1f13cd7c0397706f9ac938ddb0"
dependencies = [
"lock_api",
]
[[package]] [[package]]
name = "uart_16550" name = "uart_16550"
version = "0.3.0" version = "0.3.0"

View File

@@ -11,7 +11,6 @@ bench = false
[dependencies] [dependencies]
embedded-graphics = "0.8.1" embedded-graphics = "0.8.1"
pc-keyboard = "0.5.0" pc-keyboard = "0.5.0"
linked_list_allocator = "0.10.5"
[target.'cfg(target_arch = "x86_64")'.dependencies] [target.'cfg(target_arch = "x86_64")'.dependencies]
pic8259 = "0.10.1" pic8259 = "0.10.1"

View File

@@ -1,30 +1,60 @@
use core::alloc::Allocator; use core::{alloc::GlobalAlloc, ops::Range, ptr::null_mut};
use crate::util::mutex::Mutex;
#[global_allocator] #[global_allocator]
static ALLOCATOR: Alloc = Alloc::empty(); static ALLOCATOR: LockedHeap = LockedHeap::empty();
struct Alloc { struct Heap {
base: *mut u8,
cur: *mut u8, cur: *mut u8,
end: *mut u8,
} }
unsafe impl Allocator for Alloc { impl Heap {
fn allocate(&self, layout: core::alloc::Layout) -> Result<core::ptr::NonNull<[u8]>, core::alloc::AllocError> { pub const fn empty() -> Self {
Self {
cur: null_mut(),
end: null_mut(),
}
}
pub fn init(&mut self, start: *mut u8, end: *mut u8) {
self.cur = start;
self.end = end;
} }
} }
impl Alloc { pub fn init_heap(range: Range<*mut u8>) {
pub fn empty() -> Self { ALLOCATOR.init(range.start, range.end);
}
struct LockedHeap(Mutex<Heap>);
// should look into why I need this, didn't see it in linked list alloc crate
unsafe impl Sync for LockedHeap {}
impl LockedHeap {
pub const fn empty() -> Self {
Self(Mutex::new(Heap::empty()))
} }
pub fn init(&self, start: *mut u8, end: *mut u8) {
pub fn init(&mut self, start: *mut u8, len: usize) { self.0.lock().init(start, end);
} }
} }
pub fn init_heap() { unsafe impl GlobalAlloc for LockedHeap {
unsafe { unsafe fn alloc(&self, layout: core::alloc::Layout) -> *mut u8 {
ALLOCATOR.init(crate::arch::paging::first_free(), crate::arch::paging::free_len()); // blazing fast implementation :sunglasses:
// (gonna switch to my own linked list later)
let mut heap = self.0.lock();
let pointer = heap.cur;
heap.cur = heap.cur.add(layout.size());
if heap.cur >= heap.end {
return null_mut();
}
return pointer;
}
unsafe fn dealloc(&self, ptr: *mut u8, layout: core::alloc::Layout) {
// bet ur impl is slower
} }
} }

View File

@@ -1,4 +1,4 @@
use core::ptr::null_mut; use core::{arch::asm, ops::Range};
use crate::{ use crate::{
arch::{asm, csr, interrupts, paging, wait}, arch::{asm, csr, interrupts, paging, wait},
@@ -6,13 +6,11 @@ use crate::{
main, main,
}; };
static mut DT_ADDR: *mut FDT = null_mut();
#[no_mangle] #[no_mangle]
#[link_section = ".text.init"] #[link_section = ".text.init"]
#[naked] #[naked]
unsafe extern "C" fn _start() -> ! { unsafe extern "C" fn _start() -> ! {
core::arch::asm!( asm!(
// disable interrupts // disable interrupts
"csrw mie, zero", "csrw mie, zero",
// set up gp & sp // set up gp & sp
@@ -32,10 +30,15 @@ unsafe extern "C" fn _start() -> ! {
"csrw mstatus, t0", "csrw mstatus, t0",
"la t0, {init}", "la t0, {init}",
"csrw mepc, t0", "csrw mepc, t0",
"la ra, 2f",
"mret", "mret",
"2:", init = sym init,
options(noreturn)
);
}
pub unsafe fn to_supervisor() {
asm!(
"li t0, (1 << 8) | (1 << 5)", "li t0, (1 << 8) | (1 << 5)",
"csrw sstatus, t0", "csrw sstatus, t0",
"li t0, (7 << 0) | (1 << 3)", "li t0, (7 << 0) | (1 << 3)",
@@ -45,18 +48,14 @@ unsafe extern "C" fn _start() -> ! {
"li t2, (1 << 1) | (1 << 5) | (1 << 9)", "li t2, (1 << 1) | (1 << 5) | (1 << 9)",
"csrw mideleg, t2", "csrw mideleg, t2",
"csrw sie, t2", "csrw sie, t2",
"la t0, {start}", "mv t0, ra",
"csrw sepc, t0", "csrw sepc, t0",
"sfence.vma", "sfence.vma",
"sret", "sret",
start = sym start,
init = sym init,
options(noreturn)
); );
} }
pub fn init() { pub unsafe fn init() -> ! {
let dt_addr = asm::reg!("a1") as *mut u8; let dt_addr = asm::reg!("a1") as *mut u8;
let hart = csr::hartid::read(); let hart = csr::hartid::read();
if hart != 0 { if hart != 0 {
@@ -64,9 +63,12 @@ pub fn init() {
} }
interrupts::init(); interrupts::init();
let fdt = FDT::from_addr(dt_addr); let fdt = FDT::from_addr(dt_addr);
paging::init(fdt); let raw_mem_range = fdt.mem_range();
} let heap_start = paging::init(raw_mem_range.end());
let heap_mem = Range {
pub fn start() { start: heap_start,
main(unsafe { DT_ADDR }); end: raw_mem_range.end(),
};
to_supervisor();
main(heap_mem, fdt);
} }

View File

@@ -0,0 +1,3 @@
use super::asm::linker_static;
linker_static!(PROGRAM_END: usize, ".dword _end");

View File

@@ -4,6 +4,7 @@ pub mod asm;
pub mod interrupts; pub mod interrupts;
pub mod paging; pub mod paging;
pub mod qemu; pub mod qemu;
pub mod mem;
pub fn wait() -> ! { pub fn wait() -> ! {
loop { loop {

View File

@@ -1,20 +1,15 @@
use super::asm::linker_static;
use crate::{ use crate::{
arch::csr::{self, satp}, arch::csr::{self, satp},
fdt::FDT,
println,
util::bits::get_bits, util::bits::get_bits,
}; };
use core::{ptr::null_mut, slice}; use core::slice;
use super::mem::PROGRAM_END;
linker_static!(END: usize, ".dword _end");
const PAGE_SIZE: usize = 4096; const PAGE_SIZE: usize = 4096;
const TABLE_LEN: usize = 2usize.pow(9); const TABLE_LEN: usize = 2usize.pow(9);
const TABLE_SIZE: usize = core::mem::size_of::<Table>(); const TABLE_SIZE: usize = core::mem::size_of::<Table>();
static mut FIRST_FREE: *mut u8 = null_mut();
static mut MEM_END: *mut u8 = null_mut();
#[repr(C)] #[repr(C)]
pub struct Entry(usize); pub struct Entry(usize);
@@ -53,19 +48,12 @@ pub struct Table {
pub entries: [Entry; TABLE_LEN], pub entries: [Entry; TABLE_LEN],
} }
pub fn init(fdt: FDT) { pub fn init(mem_end: *mut u8) -> *mut u8 {
unsafe { unsafe {
println!("program end: 0x{:x}", END); let total_pages = mem_end as usize / 4096;
let range = fdt.mem_range();
let start = range.start.get();
let len = range.len.get();
let end = start + len;
MEM_END = end as *mut u8;
println!("memory range: 0x{:x} -> 0x{:x}", start, end);
let total_pages = end / 4096;
let lvl1_count = (total_pages.saturating_sub(1)) / TABLE_LEN + 1; let lvl1_count = (total_pages.saturating_sub(1)) / TABLE_LEN + 1;
let lvl2_count = (lvl1_count.saturating_sub(1)) / TABLE_LEN + 1; let lvl2_count = (lvl1_count.saturating_sub(1)) / TABLE_LEN + 1;
let lvl2 = &mut *(END as *mut Table); let lvl2 = &mut *(PROGRAM_END as *mut Table);
let lvl1_arr = slice::from_raw_parts_mut((lvl2 as *mut Table).add(TABLE_SIZE), lvl2_count); let lvl1_arr = slice::from_raw_parts_mut((lvl2 as *mut Table).add(TABLE_SIZE), lvl2_count);
let lvl0_arr = slice::from_raw_parts_mut( let lvl0_arr = slice::from_raw_parts_mut(
lvl1_arr.as_ptr().add(lvl1_arr.len()) as *mut Table, lvl1_arr.as_ptr().add(lvl1_arr.len()) as *mut Table,
@@ -106,10 +94,8 @@ pub fn init(fdt: FDT) {
asid: 0, asid: 0,
ppn: lvl2, ppn: lvl2,
}); });
let satp = csr::satp::read(); let table_end = lvl0_arr.as_ptr().add(lvl0_arr.len()) as *mut u8;
println!("satp: {satp:?}"); table_end
let end = lvl0_arr.as_ptr().add(lvl0_arr.len()) as *mut u8;
FIRST_FREE = end;
} }
} }
@@ -128,11 +114,3 @@ pub fn virt_to_physical(table: &Table, addr: usize) -> usize {
addr addr
} }
} }
pub fn first_free() -> *mut u8 {
unsafe { FIRST_FREE }
}
pub fn free_len() -> usize {
unsafe { MEM_END.offset_from(FIRST_FREE) as usize }
}

1
kernel/src/dev/mod.rs Normal file
View File

@@ -0,0 +1 @@
pub mod uart;

0
kernel/src/dev/uart.rs Normal file
View File

View File

@@ -1,14 +1,11 @@
// NOTE: basically none of this is safe rn, ideally it's eventually made safe / able to recover // garbage .1% finished FDT implementation
// also, I do a ton of slice.try_into and then transmuting which I'm pretty sure is bad and
// I really should be transmuting into references but I cannot be bothered rn
use crate::{ use crate::{
println, println,
util::bits::{u32_from_bytes, Be}, util::bits::{u32_from_bytes, Be},
}; };
use core::{ use core::{
mem::{size_of, transmute}, fmt::Debug, mem::{size_of, transmute}, ops::Range, slice
slice,
}; };
const MAGIC: u32 = 0xd00dfeed; const MAGIC: u32 = 0xd00dfeed;
@@ -161,12 +158,12 @@ impl FDT {
} }
} }
} }
pub fn mem_range(&self) -> MemRange { pub fn mem_range(&self) -> FDTMemRange {
if let Some(node) = self.into_iter().find(|n| n.name.starts_with("memory@")) { if let Some(node) = self.into_iter().find(|n| n.name.starts_with("memory@")) {
let prop = node.find_prop("reg"); let prop = node.find_prop("reg");
if let Some(prop) = prop { if let Some(prop) = prop {
for d in prop.data.chunks(size_of::<MemRange>()) { for d in prop.data.chunks(size_of::<FDTMemRange>()) {
let d: [u8; size_of::<MemRange>()] = d.try_into().unwrap(); let d: [u8; size_of::<FDTMemRange>()] = d.try_into().unwrap();
// just return first one for now // just return first one for now
return unsafe { transmute(d) }; return unsafe { transmute(d) };
} }
@@ -177,11 +174,38 @@ impl FDT {
} }
#[repr(C)] #[repr(C)]
pub struct MemRange { pub struct FDTMemRange {
pub start: Be<usize>, pub start: Be<*mut u8>,
pub len: Be<usize>, pub len: Be<usize>,
} }
impl FDTMemRange {
pub fn start(&self) -> *mut u8 {
self.start.get()
}
pub fn len(&self) -> usize {
self.len.get()
}
pub fn end(&self) -> *mut u8 {
unsafe { self.start().add(self.len.get()) }
}
}
impl Debug for FDTMemRange {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{:?}..{:?}", self.start(), self.end())
}
}
impl Into<Range<*mut u8>> for FDTMemRange {
fn into(self) -> Range<*mut u8> {
Range {
start: self.start(),
end: self.end(),
}
}
}
pub struct Node { pub struct Node {
pub name: &'static str, pub name: &'static str,
pub strings: &'static [u8], pub strings: &'static [u8],

View File

@@ -4,6 +4,8 @@
#![feature(naked_functions)] #![feature(naked_functions)]
#![feature(fn_align)] #![feature(fn_align)]
use core::ops::Range;
use fdt::FDT; use fdt::FDT;
extern crate alloc; extern crate alloc;
@@ -14,10 +16,16 @@ pub mod fdt;
pub mod log; pub mod log;
pub mod qemu; pub mod qemu;
pub mod util; pub mod util;
pub mod dev;
pub fn main(dt_addr: *mut FDT) -> ! { pub fn main(heap_mem: Range<*mut u8>, fdt: FDT) -> ! {
println!("we out here vibin"); println!("we out here vibin");
allocator::init_heap(); println!("memory range: {:?}", fdt.mem_range());
println!("heap range: {:?}", heap_mem);
for node in &fdt {
}
allocator::init_heap(heap_mem);
let mut test = alloc::vec![1, 2, 3]; let mut test = alloc::vec![1, 2, 3];
test.push(3); test.push(3);
println!("{:?}", test); println!("{:?}", test);
@@ -25,6 +33,10 @@ pub fn main(dt_addr: *mut FDT) -> ! {
let x = *(0x3000 as *const u8); let x = *(0x3000 as *const u8);
println!("{}", x); println!("{}", x);
} }
for i in 0..10000 {
let test2: alloc::vec::Vec<i32> = alloc::vec::Vec::with_capacity(10_000_000);
println!("{}", i);
}
// for _ in 0..40000000 {} // for _ in 0..40000000 {}
// let x = unsafe { *(0x10000000000 as *mut u8) }; // let x = unsafe { *(0x10000000000 as *mut u8) };
// println!("we got {x}"); // println!("we got {x}");

View File

@@ -1,4 +1,7 @@
use core::mem::transmute; use core::{
fmt::{Debug, Display},
mem::transmute,
};
macro_rules! get_bits { macro_rules! get_bits {
($name:ident[$high:expr,$low:expr]) => {{ ($name:ident[$high:expr,$low:expr]) => {{
@@ -38,6 +41,24 @@ impl BeRep for usize {
} }
} }
impl BeRep for *mut u8 {
fn _from_be(&self) -> Self {
(*self as usize).to_be() as *mut u8
}
}
impl<T: Debug + BeRep> Debug for Be<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{:?}", self.get())
}
}
impl<T: Display + BeRep> Display for Be<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{}", self.get())
}
}
pub fn u32_from_bytes(bytes: &[u8]) -> Option<u32> { pub fn u32_from_bytes(bytes: &[u8]) -> Option<u32> {
if bytes.len() < 4 { if bytes.len() < 4 {
return None; return None;

View File

@@ -27,7 +27,7 @@ fn main() {
fn run_qemu(target: &Target, gdb: Option<Option<u16>>) { fn run_qemu(target: &Target, gdb: Option<Option<u16>>) {
let mut qemu = target.qemu(); let mut qemu = target.qemu();
qemu.args(["-d", "guest_errors"]); qemu.args(["-d", "guest_errors"]);
qemu.args(["-m", "4G"]); qemu.args(["-m", "1G"]);
qemu.args(["-monitor", "telnet:127.0.0.1:1235,server,nowait"]); qemu.args(["-monitor", "telnet:127.0.0.1:1235,server,nowait"]);
if let Some(port) = gdb { if let Some(port) = gdb {
let port = port.unwrap_or(1234); let port = port.unwrap_or(1234);