diff --git a/src/allocator.rs b/src/allocator.rs index 44e73bb..e6fb132 100644 --- a/src/allocator.rs +++ b/src/allocator.rs @@ -1,7 +1,6 @@ -use crate::println; use alloc::alloc::{GlobalAlloc, Layout}; -use bootloader::BootInfo; use core::ptr::null_mut; +use fixed_size_block::FixedSizeBlockAllocator; use x86_64::{ structures::paging::{ mapper::MapToError, FrameAllocator, Mapper, Page, PageTableFlags, Size4KiB, @@ -13,26 +12,12 @@ pub mod bump; pub mod fixed_size_block; pub mod linked_list; -use fixed_size_block::FixedSizeBlockAllocator; +pub const HEAP_START: usize = 0x_4444_4444_0000; +pub const HEAP_SIZE: usize = 4 * 1024 * 1024; // 4 MiB #[global_allocator] static ALLOCATOR: Locked = Locked::new(FixedSizeBlockAllocator::new()); -pub struct Dummy; - -unsafe impl GlobalAlloc for Dummy { - unsafe fn alloc(&self, _layout: Layout) -> *mut u8 { - null_mut() - } - - unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) { - panic!("dealloc should be never called") - } -} - -pub const HEAP_START: usize = 0x_4444_4444_0000; -pub const HEAP_SIZE: usize = 4 * 1024 * 1024; // 4 MiB - pub fn init_heap( mapper: &mut impl Mapper, frame_allocator: &mut impl FrameAllocator, @@ -53,17 +38,23 @@ pub fn init_heap( mapper.map_to(page, frame, flags, frame_allocator)?.flush(); } + unsafe { + ALLOCATOR.lock().init(HEAP_START, HEAP_SIZE); + } + Ok(()) } -pub fn init(boot_info: &'static BootInfo) { - use crate::memory::{self, BootInfoFrameAllocator}; +pub struct Dummy; - let phys_mem_offset = VirtAddr::new(boot_info.physical_memory_offset); - let mut mapper = unsafe { memory::init(phys_mem_offset) }; - let mut frame_allocator = unsafe { BootInfoFrameAllocator::init(&boot_info.memory_map) }; +unsafe impl GlobalAlloc for Dummy { + unsafe fn alloc(&self, _layout: Layout) -> *mut u8 { + null_mut() + } - init_heap(&mut mapper, &mut frame_allocator).expect("heap initialization failed"); + unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) { + panic!("dealloc should be never called") + } } /// A wrapper around spin::Mutex to permit trait implementations. diff --git a/src/allocator/bump.rs b/src/allocator/bump.rs index 0d00858..3703125 100644 --- a/src/allocator/bump.rs +++ b/src/allocator/bump.rs @@ -26,7 +26,7 @@ impl BumpAllocator { /// memory range is unused. Also, this method must be called only once. pub unsafe fn init(&mut self, heap_start: usize, heap_size: usize) { self.heap_start = heap_start; - self.heap_end = heap_start + heap_size; + self.heap_end = heap_start.saturating_add(heap_size); self.next = heap_start; } } diff --git a/src/allocator/fixed_size_block.rs b/src/allocator/fixed_size_block.rs index 9291b3a..559199c 100644 --- a/src/allocator/fixed_size_block.rs +++ b/src/allocator/fixed_size_block.rs @@ -5,16 +5,24 @@ use core::{ ptr::{self, NonNull}, }; -struct ListNode { - next: Option<&'static mut ListNode>, -} - /// The block sizes to use. /// /// The sizes must each be power of 2 because they are also used as /// the block alignment (alignments must be always powers of 2). const BLOCK_SIZES: &[usize] = &[8, 16, 32, 64, 128, 256, 512, 1024, 2048]; +/// Choose an appropriate block size for the given layout. +/// +/// Returns an index into the `BLOCK_SIZES` array. +fn list_index(layout: &Layout) -> Option { + let required_block_size = layout.size().max(layout.align()); + BLOCK_SIZES.iter().position(|&s| s >= required_block_size) +} + +struct ListNode { + next: Option<&'static mut ListNode>, +} + pub struct FixedSizeBlockAllocator { list_heads: [Option<&'static mut ListNode>; BLOCK_SIZES.len()], fallback_allocator: linked_list_allocator::Heap, @@ -47,14 +55,6 @@ impl FixedSizeBlockAllocator { } } -/// Choose an appropriate block size for the given layout. -/// -/// Returns an index into the `BLOCK_SIZES` array. -fn list_index(layout: &Layout) -> Option { - let required_block_size = layout.size().max(layout.align()); - BLOCK_SIZES.iter().position(|&s| s >= required_block_size) -} - unsafe impl GlobalAlloc for Locked { unsafe fn alloc(&self, layout: Layout) -> *mut u8 { let mut allocator = self.lock(); diff --git a/src/allocator/linked_list.rs b/src/allocator/linked_list.rs index 118a30b..c2d1958 100644 --- a/src/allocator/linked_list.rs +++ b/src/allocator/linked_list.rs @@ -81,8 +81,7 @@ impl LinkedListAllocator { None } - /// Try to use the given region for an allocation with given size and - /// alignment. + /// Try to use the given region for an allocation with given size and alignment. /// /// Returns the allocation start address on success. fn alloc_from_region(region: &ListNode, size: usize, align: usize) -> Result { diff --git a/src/lib.rs b/src/lib.rs index 25b32cb..32fe0cc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -31,12 +31,20 @@ use bootloader::BootInfo; use core::panic::PanicInfo; pub fn init(boot_info: &'static BootInfo) { + use x86_64::VirtAddr; + use self::memory::{self, BootInfoFrameAllocator}; + println!("XeOS booting:"); gdt::init(); interrupts::init_idt(); unsafe { interrupts::PICS.lock().initialize() }; x86_64::instructions::interrupts::enable(); - allocator::init(&boot_info); + + let phys_mem_offset = VirtAddr::new(boot_info.physical_memory_offset); + let mut mapper = unsafe { memory::init(phys_mem_offset) }; + let mut frame_allocator = unsafe { BootInfoFrameAllocator::init(&boot_info.memory_map) }; + + allocator::init_heap(&mut mapper, &mut frame_allocator).expect("heap initialization failed"); } pub fn hlt_loop() -> ! { diff --git a/src/memory.rs b/src/memory.rs index ddf668d..e938020 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -1,7 +1,8 @@ use bootloader::bootinfo::{MemoryMap, MemoryRegionType}; use x86_64::{ structures::paging::{ - FrameAllocator, Mapper, OffsetPageTable, Page, PageTable, PhysFrame, Size4KiB, UnusedPhysFrame, + FrameAllocator, Mapper, OffsetPageTable, Page, PageTable, PhysFrame, Size4KiB, + UnusedPhysFrame, }, PhysAddr, VirtAddr, }; @@ -35,6 +36,32 @@ unsafe fn active_level_4_table(physical_memory_offset: VirtAddr) -> &'static mut &mut *page_table_ptr // unsafe } +/// Creates an example mapping for the given page to frame `0xb8000`. +pub fn create_example_mapping( + page: Page, + mapper: &mut OffsetPageTable, + frame_allocator: &mut impl FrameAllocator, +) { + use x86_64::structures::paging::PageTableFlags as Flags; + + let frame = PhysFrame::containing_address(PhysAddr::new(0xb8000)); + // FIXME: ONLY FOR TEMPORARY TESTING + let unused_frame = unsafe { UnusedPhysFrame::new(frame) }; + let flags = Flags::PRESENT | Flags::WRITABLE; + + let map_to_result = mapper.map_to(page, unused_frame, flags, frame_allocator); + map_to_result.expect("map_to failed").flush(); +} + +/// A FrameAllocator that always returns `None`. +pub struct EmptyFrameAllocator; + +unsafe impl FrameAllocator for EmptyFrameAllocator { + fn allocate_frame(&mut self) -> Option { + None + } +} + /// A FrameAllocator that returns usable frames from the bootloader's memory map. pub struct BootInfoFrameAllocator { memory_map: &'static MemoryMap, @@ -53,18 +80,14 @@ impl BootInfoFrameAllocator { next: 0, } } -} -impl BootInfoFrameAllocator { /// Returns an iterator over the usable frames specified in the memory map. fn usable_frames(&self) -> impl Iterator { // get usable regions from memory map let regions = self.memory_map.iter(); - let usable_regions = regions - .filter(|r| r.region_type == MemoryRegionType::Usable); + let usable_regions = regions.filter(|r| r.region_type == MemoryRegionType::Usable); // map each region to its address range - let addr_ranges = usable_regions - .map(|r| r.range.start_addr()..r.range.end_addr()); + let addr_ranges = usable_regions.map(|r| r.range.start_addr()..r.range.end_addr()); // transform to an iterator of frame start addresses let frame_addresses = addr_ranges.flat_map(|r| r.step_by(4096)); // create `PhysFrame` types from the start addresses @@ -81,4 +104,3 @@ unsafe impl FrameAllocator for BootInfoFrameAllocator { frame } } -