From 3bb18ee8f7e878f80d41ded10400da934eb34e08 Mon Sep 17 00:00:00 2001 From: fekhesk Date: Wed, 26 Oct 2022 15:50:22 -0700 Subject: [PATCH 1/3] don't rely on allocator for basic stuff --- Makefile | 2 +- serial.log | 29 +++++++++------- src/allocator/mod.rs | 55 ----------------------------- src/boot/mod.rs | 37 ++++++++++---------- src/boot/multiboot2/mod.rs | 41 ---------------------- src/internals/errors.rs | 2 +- src/lib.rs | 71 ++++++++++++++------------------------ src/macros/mod.rs | 5 +-- src/memory/mod.rs | 4 --- src/serial/mod.rs | 2 +- src/serial/terminal.rs | 26 +++++++++++--- 11 files changed, 86 insertions(+), 188 deletions(-) delete mode 100644 src/allocator/mod.rs delete mode 100644 src/boot/multiboot2/mod.rs diff --git a/Makefile b/Makefile index 2de5bc9..38db85e 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,alloc + @RUST_TARGET_PATH=$(shell pwd) xargo build --target $(target) -Zbuild-std=core --features "f_multiboot2" build/arch/$(arch)/%.o: arch/$(arch)/%.asm @mkdir -p $(shell dirname $@) diff --git a/serial.log b/serial.log index 107d5ab..d5198e0 100644 --- a/serial.log +++ b/serial.log @@ -6,16 +6,19 @@ BdsDxe: starting Boot0001 "UEFI QEMU DVD-ROM QM00003 " from PciRoot(0x0)/Pci(0x1 WARNING: no console will be available to OS error: no suitable video mode found. - - - -welcome to wukkOS! -(c) 2022 Real Microsoft, LLC -initialising memory maps...[OK] -memory map: -0 - a0000 : Available -100000 - 800000 : Available -808000 - 80b000 : Available -80c000 - 810000 : Available -900000 - 78ef000 : Available -7bff000 - 7f58000 : Available + hello from wukkOS! + + +welcome to wukkOS! +(c) 2022 Real Microsoft, LLC +initialising memory maps...[OK] +memory map: +0 - a0000 : available +100000 - 800000 : available +800000 - 808000 : reserved for hibernation +808000 - 80b000 : available +80b000 - 80c000 : reserved for hibernation +80c000 - 810000 : available +810000 - 900000 : reserved for hibernation +900000 - 78ef000 : available +78ef000 - 79ef000 : reserved diff --git a/src/allocator/mod.rs b/src/allocator/mod.rs deleted file mode 100644 index 1083d78..0000000 --- a/src/allocator/mod.rs +++ /dev/null @@ -1,55 +0,0 @@ -use core::alloc::{GlobalAlloc, Layout}; -use core::cell::UnsafeCell; -use core::ptr::null_mut; -use core::sync::atomic::AtomicUsize; -use core::sync::atomic::Ordering::SeqCst; - -const ARENA_SIZE: usize = 128 * 1024; -const MAX_SUPPORTED_ALIGN: usize = 4096; -#[repr(C, align(4096))] // 4096 == MAX_SUPPORTED_ALIGN -struct SimpleAllocator { - arena: UnsafeCell<[u8; ARENA_SIZE]>, - remaining: AtomicUsize, // we allocate from the top, counting down -} - -#[global_allocator] -static ALLOCATOR: SimpleAllocator = SimpleAllocator { - arena: UnsafeCell::new([0x55; ARENA_SIZE]), - remaining: AtomicUsize::new(ARENA_SIZE), -}; - -unsafe impl Sync for SimpleAllocator {} - -unsafe impl GlobalAlloc for SimpleAllocator { - unsafe fn alloc(&self, layout: Layout) -> *mut u8 { - let size = layout.size(); - let align = layout.align(); - - // `Layout` contract forbids making a `Layout` with align=0, or align not power of 2. - // So we can safely use a mask to ensure alignment without worrying about UB. - let align_mask_to_round_down = !(align - 1); - - if align > MAX_SUPPORTED_ALIGN { - return null_mut(); - } - - let mut allocated = 0; - if self - .remaining - .fetch_update(SeqCst, SeqCst, |mut remaining| { - if size > remaining { - return None; - } - remaining -= size; - remaining &= align_mask_to_round_down; - allocated = remaining; - Some(remaining) - }) - .is_err() - { - return null_mut(); - }; - (self.arena.get() as *mut u8).add(allocated) - } - unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {} -} \ No newline at end of file diff --git a/src/boot/mod.rs b/src/boot/mod.rs index bb6f30e..4ede4d0 100644 --- a/src/boot/mod.rs +++ b/src/boot/mod.rs @@ -1,27 +1,26 @@ -use alloc::vec::Vec; +use core::marker::PhantomData; use crate::KernelArgs; #[cfg(feature = "f_multiboot2")] -pub mod multiboot2; +use multiboot2::{load, MemoryMapTag, BootInformation}; -pub enum MemoryType { - Available, - Reserved, - AcpiReclaimable, - Nvs, - BadMemory, - Kernel, - Bootloader, - Unknown(u32) +pub struct KernelInfo { + #[cfg(feature = "f_multiboot2")] + boot_info: BootInformation, } -pub struct MemoryArea { - pub start: usize, - pub end: usize, - pub area_type: MemoryType, -} +impl KernelInfo { + pub fn init_from_kernel_args(args: KernelArgs) -> Self { + let mut kernel_info = KernelInfo { + #[cfg(feature = "f_multiboot2")] + boot_info: unsafe { load(args.multiboot_information_address).expect("ERR ARGS BAD!") }, + }; + kernel_info + } -pub trait KernelInfo { - fn init_from_kernel_args(&mut self, args: KernelArgs); - fn get_memory_areas(&self) -> Vec; + #[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!"); + mm_tag.all_memory_areas() + } } \ No newline at end of file diff --git a/src/boot/multiboot2/mod.rs b/src/boot/multiboot2/mod.rs deleted file mode 100644 index 9dab24d..0000000 --- a/src/boot/multiboot2/mod.rs +++ /dev/null @@ -1,41 +0,0 @@ -extern crate multiboot2; - -use alloc::vec; -use alloc::vec::Vec; -use multiboot2::{BootInformation, load, MemoryAreaType}; -use crate::boot::{KernelInfo, MemoryArea, MemoryType}; -use crate::KernelArgs; - -#[derive(Default)] -pub struct Multiboot2Bootloader { - pub boot_info: Option, -} - -impl KernelInfo for Multiboot2Bootloader { - fn init_from_kernel_args(&mut self, args: KernelArgs) { - let boot_info = unsafe { - load(args.multiboot_information_address) - }.expect("invalid kernel args!"); - self.boot_info = Some(boot_info); - } - - fn get_memory_areas(&self) -> Vec { - let mut memory_areas = vec![]; - let boot_info = self.boot_info.as_ref().unwrap(); - let memory_map_tag = boot_info.memory_map_tag().expect("memory map tag required but not found!"); - for area in memory_map_tag.memory_areas() { - memory_areas.push(MemoryArea { - start: area.start_address() as usize, - end: area.end_address() as usize, - area_type: match area.typ() { - MemoryAreaType::Available => MemoryType::Available, - MemoryAreaType::Reserved => MemoryType::Reserved, - MemoryAreaType::AcpiAvailable => MemoryType::AcpiReclaimable, - MemoryAreaType::ReservedHibernate => MemoryType::Reserved, - MemoryAreaType::Defective => MemoryType::BadMemory, - } - }) - } - memory_areas - } -} \ No newline at end of file diff --git a/src/internals/errors.rs b/src/internals/errors.rs index fc84314..e42b78f 100644 --- a/src/internals/errors.rs +++ b/src/internals/errors.rs @@ -21,7 +21,7 @@ pub extern "x86-interrupt" fn double_fault(stack_frame: InterruptStackFrame, _er loop {} } -pub extern "x86-interrupt" fn page_fault(stack_frame: InterruptStackFrame, error_code: PageFaultErrorCode) -> ! { +pub extern "x86-interrupt" fn page_fault(stack_frame: InterruptStackFrame, error_code: PageFaultErrorCode) { println!("---KERNEL FUCKY WUKKY UWU---"); println!("page fault!"); println!("accessed address: {:?}", Cr2::read()); diff --git a/src/lib.rs b/src/lib.rs index 9b5c351..6993908 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,33 +1,23 @@ #![feature(abi_x86_interrupt)] #![feature(default_alloc_error_handler)] #![feature(panic_info_message)] +#![feature(asm_const)] #![no_std] #![no_main] -use alloc::boxed::Box; -use alloc::format; -use alloc::string::ToString; -use alloc::sync::Arc; -use allocator::*; - -extern crate alloc; extern crate rlibc; -use alloc::vec::Vec; -use spin::Mutex; -use core::arch::asm; -use core::ops::Deref; use lazy_static::lazy_static; use core::panic::PanicInfo; +use multiboot2::MemoryAreaType; use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame}; use crate::boot::KernelInfo; use crate::internals::WhyDoTheyCallItOvenWhenYouOfInTheColdFoodOfOutHotEatTheFood::*; -use crate::serial::{Port, potential_serial_ports, terminal_helpers, terminal::ST}; +use crate::serial::terminal::ST; mod font; mod serial; mod internals; -mod allocator; mod security; mod boot; mod memory; @@ -49,25 +39,26 @@ const RAINBOW : [Colour; 6] = [Colour{r:255,g:0,b:0}, Colour{r:255,g:127,b:0}, C #[panic_handler] fn panic(info: &PanicInfo) -> ! { - ST.logln("---KERNEL FUCKY WUKKY UWU (panic)---"); - ST.logln(if let Some(s) = info.payload().downcast_ref::<&str>() { - format!("panic payload: {s:?}") + println!("---KERNEL FUCKY WUKKY UWU (panic)---"); + if let Some(s) = info.payload().downcast_ref::<&str>() { + println!("panic payload: {s:?}") } else { - format!("no panic payload") - }.as_str()); - ST.logln(if let Some(msg) = info.message() { - format!("panic msg: {}", msg.as_str().unwrap_or("no message")) + println!("no panic payload") + }; + if let Some(msg) = info.message() { + println!("panic msg: {}", msg.as_str().unwrap_or("no message")) } else { - "no message".to_string() - }.as_str()); - ST.logln(if let Some(location) = info.location() { - format!("location: file {} line {}", location.file(), location.line()) + println!("no message"); + } + if let Some(location) = info.location() { + println!("location: file {} line {}", location.file(), location.line()); } else { - "no location".to_string() - }.as_str()); + println!("no location"); + }; loop {} } +#[repr(C)] pub struct KernelArgs { #[cfg(feature = "f_multiboot2")] multiboot_information_address: usize @@ -89,14 +80,6 @@ pub extern fn kernel_main(args: KernelArgs) -> ! { ST.init_from_port(*port); } - let kern_info: Box = { - #[cfg(feature = "f_multiboot2")] - { - let mut kern_info = boot::multiboot2::Multiboot2Bootloader::default(); - kern_info.init_from_kernel_args(args); - Box::new(kern_info) - } - }; println!(); println!(); @@ -104,19 +87,17 @@ pub extern fn kernel_main(args: KernelArgs) -> ! { println!("welcome to wukkOS!"); println!("(c) 2022 Real Microsoft, LLC"); print!("initialising memory maps..."); - let mem_areas = kern_info.get_memory_areas(); + let kern_info = KernelInfo::init_from_kernel_args(args); + let mut mem_areas = kern_info.memory_areas(); println!("[OK]"); println!("memory map:"); - for area in mem_areas { - println!("{:x} - {:x} : {}", area.start, area.end, match area.area_type { - boot::MemoryType::Available => "Available", - boot::MemoryType::Reserved => "Reserved", - boot::MemoryType::AcpiReclaimable => "ACPI Reclaimable", - boot::MemoryType::Nvs => "NVS", - boot::MemoryType::BadMemory => "Bad Memory", - boot::MemoryType::Kernel => "Kernel", - boot::MemoryType::Bootloader => "Bootloader", - boot::MemoryType::Unknown(_) => "Unknown" + while let Some(area) = mem_areas.next() { + println!("{:x} - {:x} : {}", area.start_address(), area.end_address(), match area.typ() { + MemoryAreaType::Available => "available", + MemoryAreaType::Reserved => "reserved", + MemoryAreaType::AcpiAvailable => "ACPI available", + MemoryAreaType::ReservedHibernate => "reserved for hibernation", + MemoryAreaType::Defective => "defective", }); } diff --git a/src/macros/mod.rs b/src/macros/mod.rs index 3867f91..390ce73 100644 --- a/src/macros/mod.rs +++ b/src/macros/mod.rs @@ -1,6 +1,4 @@ -use alloc::fmt::format; use core::fmt; -use std::fmt::format; use crate::serial::terminal::ST; #[macro_export] @@ -17,6 +15,5 @@ macro_rules! println { #[doc(hidden)] pub fn _print(args: fmt::Arguments) { use core::fmt::Write; - let string = format(args); - ST.log(string.as_str()); + ST.writer.lock().write_fmt(args).unwrap(); } \ No newline at end of file diff --git a/src/memory/mod.rs b/src/memory/mod.rs index 3d184ed..e69de29 100644 --- a/src/memory/mod.rs +++ b/src/memory/mod.rs @@ -1,4 +0,0 @@ -#[repr(align(4096))] -pub struct PageTable { - entries: [PageTableEntry; 512], -} \ No newline at end of file diff --git a/src/serial/mod.rs b/src/serial/mod.rs index 2151240..bb07bdc 100644 --- a/src/serial/mod.rs +++ b/src/serial/mod.rs @@ -1,4 +1,4 @@ -#![feature(asm_const)] + use core::arch::asm; use core::borrow::{Borrow, BorrowMut}; diff --git a/src/serial/terminal.rs b/src/serial/terminal.rs index 005b985..0246bc2 100644 --- a/src/serial/terminal.rs +++ b/src/serial/terminal.rs @@ -1,17 +1,25 @@ -use alloc::sync::Arc; +use core::fmt; use core::ops::Deref; use lazy_static::lazy_static; use spin::Mutex; use crate::serial::Port; pub struct SerialTerminal { - pub port: Arc>>, + pub port: Mutex>, + pub writer: Mutex, +} + +pub struct SerialTerminalWriter { + pub port: Mutex>, } lazy_static! { pub static ref ST: SerialTerminal = { - let mut serial_terminal = SerialTerminal { - port: Arc::new(Mutex::new(None)), + let serial_terminal: SerialTerminal = SerialTerminal { + port: Mutex::new(None), + writer: Mutex::new(SerialTerminalWriter { + port: Mutex::new(None), + }), }; serial_terminal }; @@ -20,6 +28,7 @@ lazy_static! { impl SerialTerminal { pub fn init_from_port(&self, port: Port) { self.port.lock().replace(port); + self.writer.lock().port.lock().replace(port); } pub fn log(&self, message: &str) { @@ -34,4 +43,13 @@ impl SerialTerminal { port.transmit_string("\r\n"); } } +} + +impl fmt::Write for SerialTerminalWriter { + fn write_str(&mut self, s: &str) -> fmt::Result { + if let Some(port) = self.port.lock().deref() { + port.transmit_string(s); + } + Ok(()) + } } \ No newline at end of file From 1d810657ffe3f217bb309514102b5fe79483810d Mon Sep 17 00:00:00 2001 From: fekhesk Date: Wed, 26 Oct 2022 16:31:33 -0700 Subject: [PATCH 2/3] page table something idk i'm tired --- Makefile | 2 +- arch/x86_64/linker.ld | 12 +++++++++++- serial.log | 14 +++----------- src/boot/mod.rs | 28 +++++++++++++++++++++++----- src/lib.rs | 18 +++++++++--------- src/memory/mod.rs | 15 +++++++++++++++ 6 files changed, 62 insertions(+), 27 deletions(-) diff --git a/Makefile b/Makefile index 38db85e..138188e 100644 --- a/Makefile +++ b/Makefile @@ -22,7 +22,7 @@ clean: run: $(final) $(iso) @qemu-system-$(arch) -bios $(efi_bios) -cdrom $(iso) \ -chardev stdio,id=char0,mux=on,logfile=serial.log,signal=off \ - -serial chardev:char0 -mon chardev=char0 + -serial chardev:char0 -mon chardev=char0 -m 512M quick_invalidate: @echo "quick invalidation" diff --git a/arch/x86_64/linker.ld b/arch/x86_64/linker.ld index 0bf33f6..72e7d29 100644 --- a/arch/x86_64/linker.ld +++ b/arch/x86_64/linker.ld @@ -11,6 +11,16 @@ SECTIONS { .text : { - *(.text) + *(.text .text.*) + } + + .rodata : + { + *(.rodata .rodata.*) + } + + .data.rel.ro : + { + *(.data.rel.ro.local*) *(.data.rel.ro .data.rel.ro.*) } } \ No newline at end of file diff --git a/serial.log b/serial.log index d5198e0..ab8ca9b 100644 --- a/serial.log +++ b/serial.log @@ -6,19 +6,11 @@ BdsDxe: starting Boot0001 "UEFI QEMU DVD-ROM QM00003 " from PciRoot(0x0)/Pci(0x1 WARNING: no console will be available to OS error: no suitable video mode found. - hello from wukkOS! + using serial port 0 as console + welcome to wukkOS! (c) 2022 Real Microsoft, LLC initialising memory maps...[OK] -memory map: -0 - a0000 : available -100000 - 800000 : available -800000 - 808000 : reserved for hibernation -808000 - 80b000 : available -80b000 - 80c000 : reserved for hibernation -80c000 - 810000 : available -810000 - 900000 : reserved for hibernation -900000 - 78ef000 : available -78ef000 - 79ef000 : reserved +L4 entry 0: PageTableEntry { addr: PhysAddr(0x128000), flags: PRESENT | WRITABLE | ACCESSED } diff --git a/src/boot/mod.rs b/src/boot/mod.rs index 4ede4d0..d85fcc1 100644 --- a/src/boot/mod.rs +++ b/src/boot/mod.rs @@ -5,17 +5,31 @@ use crate::KernelArgs; use multiboot2::{load, MemoryMapTag, BootInformation}; pub struct KernelInfo { + kernel_start: u64, + kernel_end: u64, + safe_mem_start: u64, #[cfg(feature = "f_multiboot2")] boot_info: BootInformation, } impl KernelInfo { pub fn init_from_kernel_args(args: KernelArgs) -> Self { - let mut kernel_info = KernelInfo { - #[cfg(feature = "f_multiboot2")] - boot_info: unsafe { load(args.multiboot_information_address).expect("ERR ARGS BAD!") }, - }; - kernel_info + #[cfg(feature = "f_multiboot2")] + { + let boot_info = unsafe { load(args.multiboot_information_address) }.expect("failed to load multiboot2 information"); + let elf_sections = boot_info.elf_sections_tag().expect("no elf sections tag"); + let kernel_start = elf_sections.sections().map(|s| s.start_address()).min().unwrap(); + let kernel_end = elf_sections.sections().map(|s| s.end_address()).max().unwrap(); + // get end of multiboot for safe memory + let safe_mem_start = boot_info.start_address() + boot_info.total_size(); + let kernel_info = KernelInfo { + kernel_start, + kernel_end, + safe_mem_start: safe_mem_start as u64, + boot_info, + }; + kernel_info + } } #[cfg(feature = "f_multiboot2")] @@ -23,4 +37,8 @@ impl KernelInfo { let mm_tag = self.boot_info.memory_map_tag().expect("ERR NO MEM MAP TAG!"); mm_tag.all_memory_areas() } + + pub fn is_safe_memory(&self, addr: u64) -> bool { + addr >= self.safe_mem_start && addr >= self.kernel_end + } } \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 6993908..328dda9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,8 +11,10 @@ use lazy_static::lazy_static; use core::panic::PanicInfo; use multiboot2::MemoryAreaType; use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame}; +use x86_64::VirtAddr; use crate::boot::KernelInfo; use crate::internals::WhyDoTheyCallItOvenWhenYouOfInTheColdFoodOfOutHotEatTheFood::*; +use crate::memory::active_level_4_table; use crate::serial::terminal::ST; mod font; @@ -78,6 +80,7 @@ pub extern fn kernel_main(args: KernelArgs) -> ! { if let Some(i) = console_port { let port = &serial_ports.ports[i]; ST.init_from_port(*port); + println!("using serial port {} as console", i); } @@ -90,15 +93,12 @@ pub extern fn kernel_main(args: KernelArgs) -> ! { let kern_info = KernelInfo::init_from_kernel_args(args); let mut mem_areas = kern_info.memory_areas(); println!("[OK]"); - println!("memory map:"); - while let Some(area) = mem_areas.next() { - println!("{:x} - {:x} : {}", area.start_address(), area.end_address(), match area.typ() { - MemoryAreaType::Available => "available", - MemoryAreaType::Reserved => "reserved", - MemoryAreaType::AcpiAvailable => "ACPI available", - MemoryAreaType::ReservedHibernate => "reserved for hibernation", - MemoryAreaType::Defective => "defective", - }); + 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); + } } loop {} diff --git a/src/memory/mod.rs b/src/memory/mod.rs index e69de29..c6ed4e9 100644 --- a/src/memory/mod.rs +++ b/src/memory/mod.rs @@ -0,0 +1,15 @@ +use x86_64::registers::control::Cr3; +use x86_64::structures::paging::PageTable; +use x86_64::VirtAddr; + +pub fn active_level_4_table(physical_memory_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 page_table_ptr: *mut PageTable = virt.as_mut_ptr(); + + unsafe { &mut *page_table_ptr } // unsafe +} \ No newline at end of file From 10df1c6cfaecdb31ef13d503f24c61c635650b7e Mon Sep 17 00:00:00 2001 From: fekhesk Date: Wed, 26 Oct 2022 17:21:58 -0700 Subject: [PATCH 3/3] heap --- .cargo/config.toml | 7 ----- Cargo.toml | 6 ++-- Makefile | 2 +- serial.log | 6 ++-- src/boot/mod.rs | 10 +++++++ src/lib.rs | 41 ++++++++++++++++++++------- src/memory/allocator.rs | 41 +++++++++++++++++++++++++++ src/memory/mod.rs | 63 +++++++++++++++++++++++++++++++++++++---- 8 files changed, 149 insertions(+), 27 deletions(-) delete mode 100644 .cargo/config.toml create mode 100644 src/memory/allocator.rs 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