diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000..b814980 --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,7 @@ +[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 1561936..dd2f3c0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,12 +11,10 @@ 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_ll_alloc"] -f_multiboot2 = ["dep:multiboot2"] -f_ll_alloc = ["dep:linked_list_allocator"] \ No newline at end of file +default = ["f_multiboot2"] +f_multiboot2 = ["dep:multiboot2"] \ No newline at end of file diff --git a/Makefile b/Makefile index bd74e82..2de5bc9 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 -m 512M + -serial chardev:char0 -mon chardev=char0 quick_invalidate: @echo "quick invalidation" @@ -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 --features "f_multiboot2" + @RUST_TARGET_PATH=$(shell pwd) xargo build --target $(target) -Zbuild-std=core,alloc build/arch/$(arch)/%.o: arch/$(arch)/%.asm @mkdir -p $(shell dirname $@) diff --git a/arch/x86_64/linker.ld b/arch/x86_64/linker.ld index 72e7d29..0bf33f6 100644 --- a/arch/x86_64/linker.ld +++ b/arch/x86_64/linker.ld @@ -11,16 +11,6 @@ SECTIONS { .text : { - *(.text .text.*) - } - - .rodata : - { - *(.rodata .rodata.*) - } - - .data.rel.ro : - { - *(.data.rel.ro.local*) *(.data.rel.ro .data.rel.ro.*) + *(.text) } } \ No newline at end of file diff --git a/serial.log b/serial.log index ef292d9..107d5ab 100644 --- a/serial.log +++ b/serial.log @@ -6,13 +6,16 @@ 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. - using serial port 0 as console - - - -welcome to wukkOS! -(c) 2022 Real Microsoft, LLC -initialising mapper...[OK] -initialising frame allocator...[OK] -initialising heap...[OK] -testing heap...[OK] + + + +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 diff --git a/src/allocator/mod.rs b/src/allocator/mod.rs new file mode 100644 index 0000000..1083d78 --- /dev/null +++ b/src/allocator/mod.rs @@ -0,0 +1,55 @@ +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 3491cce..bb6f30e 100644 --- a/src/boot/mod.rs +++ b/src/boot/mod.rs @@ -1,54 +1,27 @@ -use core::marker::PhantomData; +use alloc::vec::Vec; use crate::KernelArgs; #[cfg(feature = "f_multiboot2")] -use multiboot2::{load, MemoryMapTag, BootInformation}; +pub mod multiboot2; -pub struct KernelInfo { - kernel_start: u64, - kernel_end: u64, - safe_mem_start: u64, - #[cfg(feature = "f_multiboot2")] - boot_info: BootInformation, +pub enum MemoryType { + Available, + Reserved, + AcpiReclaimable, + Nvs, + BadMemory, + Kernel, + Bootloader, + Unknown(u32) } -impl KernelInfo { - pub fn init_from_kernel_args(args: KernelArgs) -> Self { - #[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 - } - } +pub struct MemoryArea { + pub start: usize, + pub end: usize, + pub area_type: MemoryType, +} - #[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!"); - mm_tag.all_memory_areas() - } - - 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 - } +pub trait KernelInfo { + fn init_from_kernel_args(&mut self, args: KernelArgs); + fn get_memory_areas(&self) -> Vec; } \ No newline at end of file diff --git a/src/boot/multiboot2/mod.rs b/src/boot/multiboot2/mod.rs new file mode 100644 index 0000000..9dab24d --- /dev/null +++ b/src/boot/multiboot2/mod.rs @@ -0,0 +1,41 @@ +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 e42b78f..fc84314 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 bbea6ce..9b5c351 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,30 +1,33 @@ #![feature(abi_x86_interrupt)] #![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::boxed::Box; +use alloc::format; +use alloc::string::ToString; +use alloc::sync::Arc; +use allocator::*; -use alloc::rc::Rc; -use alloc::vec; +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 spin::Mutex; use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame}; -use x86_64::{PhysAddr, VirtAddr}; -use x86_64::structures::paging::Translate; use crate::boot::KernelInfo; use crate::internals::WhyDoTheyCallItOvenWhenYouOfInTheColdFoodOfOutHotEatTheFood::*; -use crate::serial::terminal::ST; +use crate::serial::{Port, potential_serial_ports, terminal_helpers, terminal::ST}; mod font; mod serial; mod internals; +mod allocator; mod security; mod boot; mod memory; @@ -43,33 +46,28 @@ 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) -> ! { - println!("---KERNEL FUCKY WUKKY UWU (panic)---"); - if let Some(s) = info.payload().downcast_ref::<&str>() { - println!("panic payload: {s:?}") + ST.logln("---KERNEL FUCKY WUKKY UWU (panic)---"); + ST.logln(if let Some(s) = info.payload().downcast_ref::<&str>() { + format!("panic payload: {s:?}") } else { - println!("no panic payload") - }; - if let Some(msg) = info.message() { - println!("panic msg: {}", msg.as_str().unwrap_or("no message")) + format!("no panic payload") + }.as_str()); + ST.logln(if let Some(msg) = info.message() { + format!("panic msg: {}", msg.as_str().unwrap_or("no message")) } else { - println!("no message"); - } - if let Some(location) = info.location() { - println!("location: file {} line {}", location.file(), location.line()); + "no message".to_string() + }.as_str()); + ST.logln(if let Some(location) = info.location() { + format!("location: file {} line {}", location.file(), location.line()) } else { - println!("no location"); - }; + "no location".to_string() + }.as_str()); loop {} } -#[repr(C)] pub struct KernelArgs { #[cfg(feature = "f_multiboot2")] multiboot_information_address: usize @@ -89,38 +87,38 @@ 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); } + 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!(); println!(); println!("welcome to wukkOS!"); println!("(c) 2022 Real Microsoft, LLC"); - let kern_info = Mutex::new(KernelInfo::init_from_kernel_args(args)); - print!("initialising mapper..."); - let mut mapper = unsafe { memory::init(VirtAddr::new(0)) }; + print!("initialising memory maps..."); + let mem_areas = kern_info.get_memory_areas(); 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]"); - - 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]"); + 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" + }); } - drop(reference_counted); loop {} } \ No newline at end of file diff --git a/src/macros/mod.rs b/src/macros/mod.rs index 390ce73..3867f91 100644 --- a/src/macros/mod.rs +++ b/src/macros/mod.rs @@ -1,4 +1,6 @@ +use alloc::fmt::format; use core::fmt; +use std::fmt::format; use crate::serial::terminal::ST; #[macro_export] @@ -15,5 +17,6 @@ macro_rules! println { #[doc(hidden)] pub fn _print(args: fmt::Arguments) { use core::fmt::Write; - ST.writer.lock().write_fmt(args).unwrap(); + let string = format(args); + ST.log(string.as_str()); } \ No newline at end of file diff --git a/src/memory/allocator.rs b/src/memory/allocator.rs deleted file mode 100644 index c8f3624..0000000 --- a/src/memory/allocator.rs +++ /dev/null @@ -1,41 +0,0 @@ -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 125c885..3d184ed 100644 --- a/src/memory/mod.rs +++ b/src/memory/mod.rs @@ -1,68 +1,4 @@ -pub mod allocator; - -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 = 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 - } - } +#[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 bb07bdc..2151240 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 0246bc2..005b985 100644 --- a/src/serial/terminal.rs +++ b/src/serial/terminal.rs @@ -1,25 +1,17 @@ -use core::fmt; +use alloc::sync::Arc; use core::ops::Deref; use lazy_static::lazy_static; use spin::Mutex; use crate::serial::Port; pub struct SerialTerminal { - pub port: Mutex>, - pub writer: Mutex, -} - -pub struct SerialTerminalWriter { - pub port: Mutex>, + pub port: Arc>>, } lazy_static! { pub static ref ST: SerialTerminal = { - let serial_terminal: SerialTerminal = SerialTerminal { - port: Mutex::new(None), - writer: Mutex::new(SerialTerminalWriter { - port: Mutex::new(None), - }), + let mut serial_terminal = SerialTerminal { + port: Arc::new(Mutex::new(None)), }; serial_terminal }; @@ -28,7 +20,6 @@ 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) { @@ -43,13 +34,4 @@ 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