This commit is contained in:
Cadey Ratio 2020-03-27 18:45:12 -04:00
parent 7ba36c7041
commit a5250bda6d
6 changed files with 68 additions and 48 deletions

View File

@ -1,7 +1,6 @@
use crate::println;
use alloc::alloc::{GlobalAlloc, Layout}; use alloc::alloc::{GlobalAlloc, Layout};
use bootloader::BootInfo;
use core::ptr::null_mut; use core::ptr::null_mut;
use fixed_size_block::FixedSizeBlockAllocator;
use x86_64::{ use x86_64::{
structures::paging::{ structures::paging::{
mapper::MapToError, FrameAllocator, Mapper, Page, PageTableFlags, Size4KiB, mapper::MapToError, FrameAllocator, Mapper, Page, PageTableFlags, Size4KiB,
@ -13,26 +12,12 @@ pub mod bump;
pub mod fixed_size_block; pub mod fixed_size_block;
pub mod linked_list; 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] #[global_allocator]
static ALLOCATOR: Locked<FixedSizeBlockAllocator> = Locked::new(FixedSizeBlockAllocator::new()); static ALLOCATOR: Locked<FixedSizeBlockAllocator> = 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( pub fn init_heap(
mapper: &mut impl Mapper<Size4KiB>, mapper: &mut impl Mapper<Size4KiB>,
frame_allocator: &mut impl FrameAllocator<Size4KiB>, frame_allocator: &mut impl FrameAllocator<Size4KiB>,
@ -53,17 +38,23 @@ pub fn init_heap(
mapper.map_to(page, frame, flags, frame_allocator)?.flush(); mapper.map_to(page, frame, flags, frame_allocator)?.flush();
} }
unsafe {
ALLOCATOR.lock().init(HEAP_START, HEAP_SIZE);
}
Ok(()) Ok(())
} }
pub fn init(boot_info: &'static BootInfo) { pub struct Dummy;
use crate::memory::{self, BootInfoFrameAllocator};
let phys_mem_offset = VirtAddr::new(boot_info.physical_memory_offset); unsafe impl GlobalAlloc for Dummy {
let mut mapper = unsafe { memory::init(phys_mem_offset) }; unsafe fn alloc(&self, _layout: Layout) -> *mut u8 {
let mut frame_allocator = unsafe { BootInfoFrameAllocator::init(&boot_info.memory_map) }; 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. /// A wrapper around spin::Mutex to permit trait implementations.

View File

@ -26,7 +26,7 @@ impl BumpAllocator {
/// memory range is unused. Also, this method must be called only once. /// memory range is unused. Also, this method must be called only once.
pub unsafe fn init(&mut self, heap_start: usize, heap_size: usize) { pub unsafe fn init(&mut self, heap_start: usize, heap_size: usize) {
self.heap_start = heap_start; 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; self.next = heap_start;
} }
} }

View File

@ -5,16 +5,24 @@ use core::{
ptr::{self, NonNull}, ptr::{self, NonNull},
}; };
struct ListNode {
next: Option<&'static mut ListNode>,
}
/// The block sizes to use. /// The block sizes to use.
/// ///
/// The sizes must each be power of 2 because they are also used as /// The sizes must each be power of 2 because they are also used as
/// the block alignment (alignments must be always powers of 2). /// the block alignment (alignments must be always powers of 2).
const BLOCK_SIZES: &[usize] = &[8, 16, 32, 64, 128, 256, 512, 1024, 2048]; 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<usize> {
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 { pub struct FixedSizeBlockAllocator {
list_heads: [Option<&'static mut ListNode>; BLOCK_SIZES.len()], list_heads: [Option<&'static mut ListNode>; BLOCK_SIZES.len()],
fallback_allocator: linked_list_allocator::Heap, 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<usize> {
let required_block_size = layout.size().max(layout.align());
BLOCK_SIZES.iter().position(|&s| s >= required_block_size)
}
unsafe impl GlobalAlloc for Locked<FixedSizeBlockAllocator> { unsafe impl GlobalAlloc for Locked<FixedSizeBlockAllocator> {
unsafe fn alloc(&self, layout: Layout) -> *mut u8 { unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
let mut allocator = self.lock(); let mut allocator = self.lock();

View File

@ -81,8 +81,7 @@ impl LinkedListAllocator {
None None
} }
/// Try to use the given region for an allocation with given size and /// Try to use the given region for an allocation with given size and alignment.
/// alignment.
/// ///
/// Returns the allocation start address on success. /// Returns the allocation start address on success.
fn alloc_from_region(region: &ListNode, size: usize, align: usize) -> Result<usize, ()> { fn alloc_from_region(region: &ListNode, size: usize, align: usize) -> Result<usize, ()> {

View File

@ -31,12 +31,20 @@ use bootloader::BootInfo;
use core::panic::PanicInfo; use core::panic::PanicInfo;
pub fn init(boot_info: &'static BootInfo) { pub fn init(boot_info: &'static BootInfo) {
use x86_64::VirtAddr;
use self::memory::{self, BootInfoFrameAllocator};
println!("XeOS booting:"); println!("XeOS booting:");
gdt::init(); gdt::init();
interrupts::init_idt(); interrupts::init_idt();
unsafe { interrupts::PICS.lock().initialize() }; unsafe { interrupts::PICS.lock().initialize() };
x86_64::instructions::interrupts::enable(); 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() -> ! { pub fn hlt_loop() -> ! {

View File

@ -1,7 +1,8 @@
use bootloader::bootinfo::{MemoryMap, MemoryRegionType}; use bootloader::bootinfo::{MemoryMap, MemoryRegionType};
use x86_64::{ use x86_64::{
structures::paging::{ structures::paging::{
FrameAllocator, Mapper, OffsetPageTable, Page, PageTable, PhysFrame, Size4KiB, UnusedPhysFrame, FrameAllocator, Mapper, OffsetPageTable, Page, PageTable, PhysFrame, Size4KiB,
UnusedPhysFrame,
}, },
PhysAddr, VirtAddr, PhysAddr, VirtAddr,
}; };
@ -35,6 +36,32 @@ unsafe fn active_level_4_table(physical_memory_offset: VirtAddr) -> &'static mut
&mut *page_table_ptr // unsafe &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<Size4KiB>,
) {
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<Size4KiB> for EmptyFrameAllocator {
fn allocate_frame(&mut self) -> Option<UnusedPhysFrame> {
None
}
}
/// A FrameAllocator that returns usable frames from the bootloader's memory map. /// A FrameAllocator that returns usable frames from the bootloader's memory map.
pub struct BootInfoFrameAllocator { pub struct BootInfoFrameAllocator {
memory_map: &'static MemoryMap, memory_map: &'static MemoryMap,
@ -53,18 +80,14 @@ impl BootInfoFrameAllocator {
next: 0, next: 0,
} }
} }
}
impl BootInfoFrameAllocator {
/// Returns an iterator over the usable frames specified in the memory map. /// Returns an iterator over the usable frames specified in the memory map.
fn usable_frames(&self) -> impl Iterator<Item = UnusedPhysFrame> { fn usable_frames(&self) -> impl Iterator<Item = UnusedPhysFrame> {
// get usable regions from memory map // get usable regions from memory map
let regions = self.memory_map.iter(); let regions = self.memory_map.iter();
let usable_regions = regions let usable_regions = regions.filter(|r| r.region_type == MemoryRegionType::Usable);
.filter(|r| r.region_type == MemoryRegionType::Usable);
// map each region to its address range // map each region to its address range
let addr_ranges = usable_regions let addr_ranges = usable_regions.map(|r| r.range.start_addr()..r.range.end_addr());
.map(|r| r.range.start_addr()..r.range.end_addr());
// transform to an iterator of frame start addresses // transform to an iterator of frame start addresses
let frame_addresses = addr_ranges.flat_map(|r| r.step_by(4096)); let frame_addresses = addr_ranges.flat_map(|r| r.step_by(4096));
// create `PhysFrame` types from the start addresses // create `PhysFrame` types from the start addresses
@ -81,4 +104,3 @@ unsafe impl FrameAllocator<Size4KiB> for BootInfoFrameAllocator {
frame frame
} }
} }