diff --git a/.cargo/config.toml b/.cargo/config.toml deleted file mode 100644 index b814980..0000000 --- a/.cargo/config.toml +++ /dev/null @@ -1,7 +0,0 @@ -[target.'cfg(target_os = "none")'] -runner = "cargo run --package simple_boot --" - -[alias] -kbuild = "build --target x86_64-custom.json -Zbuild-std=core -Zbuild-std-features=compiler-builtins-mem" -kimage = "run --target x86_64-custom.json -Zbuild-std=core -Zbuild-std-features=compiler-builtins-mem -- --no-run" -krun = "run --target x86_64-custom.json -Zbuild-std=core -Zbuild-std-features=compiler-builtins-mem" \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index dd2f3c0..1561936 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,10 +11,12 @@ spin = "0.9.1" x86_64 = "0.14.10" rlibc = "1.0" multiboot2 = { version = "0.14.0", optional = true } +linked_list_allocator = { version = "0.9.0", optional = true } [dependencies.lazy_static] version = "1.4.0" features = ["spin_no_std"] [features] -default = ["f_multiboot2"] -f_multiboot2 = ["dep:multiboot2"] \ No newline at end of file +default = ["f_multiboot2", "f_ll_alloc"] +f_multiboot2 = ["dep:multiboot2"] +f_ll_alloc = ["dep:linked_list_allocator"] \ No newline at end of file diff --git a/Makefile b/Makefile index 138188e..bd74e82 100644 --- a/Makefile +++ b/Makefile @@ -44,7 +44,7 @@ $(final): $(kernel) $(linker_script) $(assembly_object_files) --gc-sections $(kernel): - @RUST_TARGET_PATH=$(shell pwd) xargo build --target $(target) -Zbuild-std=core --features "f_multiboot2" + @RUST_TARGET_PATH=$(shell pwd) xargo build --target $(target) -Zbuild-std=core,alloc --features "f_multiboot2" build/arch/$(arch)/%.o: arch/$(arch)/%.asm @mkdir -p $(shell dirname $@) diff --git a/serial.log b/serial.log index ab8ca9b..ef292d9 100644 --- a/serial.log +++ b/serial.log @@ -12,5 +12,7 @@ BdsDxe: starting Boot0001 "UEFI QEMU DVD-ROM QM00003 " from PciRoot(0x0)/Pci(0x1 welcome to wukkOS! (c) 2022 Real Microsoft, LLC -initialising memory maps...[OK] -L4 entry 0: PageTableEntry { addr: PhysAddr(0x128000), flags: PRESENT | WRITABLE | ACCESSED } +initialising mapper...[OK] +initialising frame allocator...[OK] +initialising heap...[OK] +testing heap...[OK] diff --git a/src/boot/mod.rs b/src/boot/mod.rs index d85fcc1..3491cce 100644 --- a/src/boot/mod.rs +++ b/src/boot/mod.rs @@ -32,6 +32,12 @@ impl KernelInfo { } } + #[cfg(feature = "f_multiboot2")] + pub fn get_memory_tag(&self) -> &MemoryMapTag { + let mm_tag = self.boot_info.memory_map_tag().expect("no memory map tag").clone(); + mm_tag + } + #[cfg(feature = "f_multiboot2")] pub fn memory_areas(&self) -> impl Iterator { let mm_tag = self.boot_info.memory_map_tag().expect("ERR NO MEM MAP TAG!"); @@ -41,4 +47,8 @@ impl KernelInfo { pub fn is_safe_memory(&self, addr: u64) -> bool { addr >= self.safe_mem_start && addr >= self.kernel_end } + + pub fn safe_memory_start(&self) -> u64 { + self.safe_mem_start + } } \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 328dda9..bbea6ce 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,19 +2,24 @@ #![feature(default_alloc_error_handler)] #![feature(panic_info_message)] #![feature(asm_const)] +#![feature(alloc_error_handler)] #![no_std] #![no_main] extern crate rlibc; +extern crate alloc; +use alloc::rc::Rc; +use alloc::vec; use lazy_static::lazy_static; use core::panic::PanicInfo; use multiboot2::MemoryAreaType; +use spin::Mutex; use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame}; -use x86_64::VirtAddr; +use x86_64::{PhysAddr, VirtAddr}; +use x86_64::structures::paging::Translate; use crate::boot::KernelInfo; use crate::internals::WhyDoTheyCallItOvenWhenYouOfInTheColdFoodOfOutHotEatTheFood::*; -use crate::memory::active_level_4_table; use crate::serial::terminal::ST; mod font; @@ -38,6 +43,10 @@ lazy_static! { const RAINBOW : [Colour; 6] = [Colour{r:255,g:0,b:0}, Colour{r:255,g:127,b:0}, Colour{r:255,g:255,b:0}, Colour{r:0,g:255,b:0}, Colour{r:0,g:255,b:255}, Colour{r:0,g:0,b:255}]; +#[alloc_error_handler] +fn alloc_error_handler(layout: alloc::alloc::Layout) -> ! { + panic!("allocation error: {:?}", layout) +} #[panic_handler] fn panic(info: &PanicInfo) -> ! { @@ -89,17 +98,29 @@ pub extern fn kernel_main(args: KernelArgs) -> ! { println!(); println!("welcome to wukkOS!"); println!("(c) 2022 Real Microsoft, LLC"); - print!("initialising memory maps..."); - let kern_info = KernelInfo::init_from_kernel_args(args); - let mut mem_areas = kern_info.memory_areas(); + let kern_info = Mutex::new(KernelInfo::init_from_kernel_args(args)); + print!("initialising mapper..."); + let mut mapper = unsafe { memory::init(VirtAddr::new(0)) }; + println!("[OK]"); + print!("initialising frame allocator..."); + let mut frame_allocator = unsafe { memory::BootInfoFrameAllocator::init(kern_info) }; + println!("[OK]"); + print!("initialising heap..."); + memory::allocator::init_heap(&mut mapper, &mut frame_allocator).expect("heap init failed"); println!("[OK]"); - let l4_table = active_level_4_table(VirtAddr::new(0)); - for (i, entry) in l4_table.iter().enumerate() { - if !entry.is_unused() { - println!("L4 entry {}: {:?}", i, entry); - } + print!("testing heap..."); + let reference_counted = Rc::new(vec![1, 2, 3]); + let cloned = reference_counted.clone(); + let test_1 = Rc::strong_count(&reference_counted) == 2; + drop(cloned); + let test_2 = Rc::strong_count(&reference_counted) == 1; + if test_1 && test_2 { + println!("[OK]"); + } else { + println!("[FAIL]"); } + drop(reference_counted); loop {} } \ No newline at end of file diff --git a/src/memory/allocator.rs b/src/memory/allocator.rs new file mode 100644 index 0000000..c8f3624 --- /dev/null +++ b/src/memory/allocator.rs @@ -0,0 +1,41 @@ +use x86_64::structures::paging::{FrameAllocator, Mapper, Page, PageTableFlags, Size4KiB}; +use x86_64::structures::paging::mapper::MapToError; +use x86_64::VirtAddr; + +pub const HEAP_START: u64 = 0x_4444_4444_0000; +pub const HEAP_SIZE: u64 = 100 * 1024; // 100 KiB + +#[cfg(feature = "f_ll_alloc")] +use linked_list_allocator::LockedHeap; + +#[global_allocator] +static ALLOCATOR: LockedHeap = LockedHeap::empty(); + +pub fn init_heap( + mapper: &mut impl Mapper, + frame_allocator: &mut impl FrameAllocator, +) -> Result<(), MapToError> { + let page_range = { + let heap_start = VirtAddr::new(HEAP_START as u64); + let heap_end = heap_start + HEAP_SIZE - 1u64; + let heap_start_page = Page::containing_address(heap_start); + let heap_end_page = Page::containing_address(heap_end); + Page::range_inclusive(heap_start_page, heap_end_page) + }; + + for page in page_range { + let frame = frame_allocator + .allocate_frame() + .ok_or(MapToError::FrameAllocationFailed)?; + let flags = PageTableFlags::PRESENT | PageTableFlags::WRITABLE; + unsafe { + mapper.map_to(page, frame, flags, frame_allocator)?.flush() + }; + } + + unsafe { + ALLOCATOR.lock().init(HEAP_START as usize, HEAP_SIZE as usize); + } + + Ok(()) +} \ No newline at end of file diff --git a/src/memory/mod.rs b/src/memory/mod.rs index c6ed4e9..125c885 100644 --- a/src/memory/mod.rs +++ b/src/memory/mod.rs @@ -1,15 +1,68 @@ -use x86_64::registers::control::Cr3; -use x86_64::structures::paging::PageTable; -use x86_64::VirtAddr; +pub mod allocator; -pub fn active_level_4_table(physical_memory_offset: VirtAddr) -> &'static mut PageTable { +use x86_64::structures::paging::{FrameAllocator, OffsetPageTable, PageTable, PhysFrame, Size4KiB}; +use x86_64::{PhysAddr, VirtAddr}; + +pub unsafe fn init(phys_mem_offset: VirtAddr) -> OffsetPageTable<'static> { + let level_4_table = active_level_4_table(phys_mem_offset); + OffsetPageTable::new(level_4_table, phys_mem_offset) +} + +unsafe fn active_level_4_table(phys_mem_offset: VirtAddr) -> &'static mut PageTable { use x86_64::registers::control::Cr3; let (level_4_table_frame, _) = Cr3::read(); let phys = level_4_table_frame.start_address(); - let virt = physical_memory_offset + phys.as_u64(); + let virt = phys_mem_offset + phys.as_u64(); let page_table_ptr: *mut PageTable = virt.as_mut_ptr(); unsafe { &mut *page_table_ptr } // unsafe +} + +#[cfg(feature = "f_multiboot2")] +use multiboot2::{MemoryMapTag, BootInformation}; +use spin::Mutex; +use crate::boot::KernelInfo; + +pub struct BootInfoFrameAllocator { + kern_info: Mutex, + next: usize, +} + +impl BootInfoFrameAllocator { + #[cfg(feature = "f_multiboot2")] + pub unsafe fn init(kern_info: Mutex) -> Self { + Self { + kern_info, + next: 0, + } + } +} + +unsafe impl FrameAllocator for BootInfoFrameAllocator { + fn allocate_frame(&mut self) -> Option { + #[cfg(feature = "f_multiboot2")] { + let mut kern_lock = self.kern_info.lock(); + let mut usable_frames = kern_lock + .memory_areas(); + let mut usable_frames = usable_frames + .map(|area| { + let frame_addr = area.start_address(); + let frame_end = area.end_address(); + let frame_size = frame_end - frame_addr; + let num_frames = frame_size / 4096; + let start_frame = PhysFrame::containing_address(PhysAddr::new(frame_addr)); + (0..num_frames).map(move |i| start_frame + i) + }) + .flatten(); + let frame = usable_frames.nth(self.next).clone(); + self.next += 1; + + // ensure unlock + unsafe { self.kern_info.force_unlock() }; + + frame + } + } } \ No newline at end of file