From bfeafc989248fad9fd53fb5d6fd8ca12311cfa12 Mon Sep 17 00:00:00 2001 From: guillaume didier Date: Thu, 14 Nov 2019 14:26:37 +0100 Subject: [PATCH] Implement memory allocation --- Cargo.lock | 10 +++++++++ Cargo.toml | 1 + src/allocator.rs | 58 ++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 37 ++++++++++++++++++------------ src/main.rs | 32 ++++++++++++-------------- 5 files changed, 106 insertions(+), 32 deletions(-) create mode 100644 src/allocator.rs diff --git a/Cargo.lock b/Cargo.lock index abf8f5b..acfab46 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -42,6 +42,7 @@ version = "0.1.0" dependencies = [ "bootloader 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "linked_list_allocator 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", "polling_serial 0.1.0", "vga_buffer 0.1.0", "volatile 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -56,6 +57,14 @@ dependencies = [ "spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "linked_list_allocator" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "nodrop" version = "0.1.13" @@ -114,6 +123,7 @@ dependencies = [ "checksum bootloader 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abfbe6cdea6367860818facc8e4a184f003cb83d7d004acaaf57baebf1949da0" "checksum cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "926013f2860c46252efceabb19f4a6b308197505082c609025aa6706c011d427" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +"checksum linked_list_allocator 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "47314ec1d29aa869ee7cb5a5be57be9b1055c56567d59c3fb6689926743e0bea" "checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" "checksum spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" "checksum ux 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "88dfeb711b61ce620c0cb6fd9f8e3e678622f0c971da2a63c4b3e25e88ed012f" diff --git a/Cargo.toml b/Cargo.toml index 603d3c6..ce634d7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,6 +27,7 @@ x86_64 = "0.7.5" vga_buffer = { path = "vga_buffer" } polling_serial = { path = "polling_serial" } volatile = "0.2.6" +linked_list_allocator = "0.6.4" [dependencies.lazy_static] version = "1.0" diff --git a/src/allocator.rs b/src/allocator.rs new file mode 100644 index 0000000..57bd05a --- /dev/null +++ b/src/allocator.rs @@ -0,0 +1,58 @@ +use alloc::alloc::{GlobalAlloc, Layout}; +use core::ptr::null_mut; +use polling_serial::serial_println; +use x86_64::instructions::bochs_breakpoint; +use x86_64::structures::paging::mapper::MapToError::PageAlreadyMapped; +use x86_64::{ + structures::paging::{ + mapper::MapToError, FrameAllocator, Mapper, Page, PageTableFlags, Size4KiB, + }, + VirtAddr, +}; + +pub const HEAP_START: usize = 0x4444_4444_0000; +pub const HEAP_SIZE: usize = 0x1 << 20; // 1MB Heap + +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 never be called"); + } +} + +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 as u64 - 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) + }; + + let mut i = 0; + 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() }; + if i == 0 { + serial_println!("Mapped {:?} at {:?}", page, frame); + } + i = i + 1; + } + + unsafe { + super::ALLOCATOR.lock().init(HEAP_START, HEAP_SIZE); + } + + Ok(()) +} diff --git a/src/lib.rs b/src/lib.rs index 8f0409b..13d2ce0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,24 +5,20 @@ #![reexport_test_harness_main = "test_main"] #![feature(abi_x86_interrupt)] #![feature(asm)] +#![feature(alloc_error_handler)] +extern crate alloc; -use core::panic::PanicInfo; - -#[cfg(test)] -use vga_buffer::print; - -#[cfg(test)] -use polling_serial::serial_print; - -use polling_serial::serial_println; - -use vga_buffer::println; -use x86_64::instructions::bochs_breakpoint; - +pub mod allocator; pub mod gdt; pub mod interrupts; pub mod memory; +use core::panic::PanicInfo; +use linked_list_allocator::LockedHeap; +use polling_serial::serial_println; +use vga_buffer::println; +use x86_64::instructions::bochs_breakpoint; + #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[repr(u32)] pub enum QemuExitCode { @@ -30,8 +26,15 @@ pub enum QemuExitCode { Failed = 0x11, } -// Custom panic handler, required for freestanding program +#[global_allocator] +static ALLOCATOR: LockedHeap = LockedHeap::empty(); +#[alloc_error_handler] +fn alloc_error_handler(layout: alloc::alloc::Layout) -> ! { + panic!("allocation error: {:?}", layout) +} + +// Custom panic handler, required for freestanding program pub fn test_panic_handler(info: &PanicInfo) -> ! { serial_println!("[failed]\n"); serial_println!("Error: {}\n", info); @@ -73,6 +76,12 @@ pub fn hlt_loop() -> ! { } } +#[cfg(test)] +use vga_buffer::print; + +#[cfg(test)] +use polling_serial::serial_print; + #[cfg(test)] use bootloader::{entry_point, BootInfo}; diff --git a/src/main.rs b/src/main.rs index e0b246c..fe3281e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,24 +6,24 @@ #![feature(custom_test_frameworks)] #![test_runner(dendrobates_tinctoreus_azureus::test_runner)] #![reexport_test_harness_main = "test_main"] - -use polling_serial::serial_println; +extern crate alloc; #[cfg(test)] use polling_serial::serial_print; -use vga_buffer::println; - -use core::panic::PanicInfo; -use vga_buffer; // required for custom panic handler - -use x86_64; - +use alloc::boxed::Box; use bootloader::{entry_point, BootInfo}; +use core::panic::PanicInfo; +use dendrobates_tinctoreus_azureus::allocator; +use polling_serial::serial_println; +use vga_buffer; // required for custom panic handler +use vga_buffer::println; +use x86_64; #[cfg(not(test))] use dendrobates_tinctoreus_azureus::hlt_loop; +use dendrobates_tinctoreus_azureus::memory::create_example_mapping; #[cfg(not(test))] use vga_buffer::{set_colors, Color, ForegroundColor}; @@ -59,6 +59,9 @@ fn kernel_main(boot_info: &'static BootInfo) -> ! { let phys_mem_offset = VirtAddr::new(boot_info.physical_memory_offset); // new: initialize a mapper + let mut frame_allocator = + unsafe { memory::BootInfoFrameAllocator::init(&boot_info.memory_map) }; + let mut mapper = unsafe { memory::init(phys_mem_offset) }; let addresses = [ @@ -79,16 +82,9 @@ fn kernel_main(boot_info: &'static BootInfo) -> ! { serial_println!("{:?} -> {:?}", virt, phys); } - let mut frame_allocator = - unsafe { memory::BootInfoFrameAllocator::init(&boot_info.memory_map) }; + allocator::init_heap(&mut mapper, &mut frame_allocator).expect("heap initialization failed"); - // map an unused page - let page = Page::containing_address(VirtAddr::new(0)); - memory::create_example_mapping(page, &mut mapper, &mut frame_allocator); - - // write the string `New!` to the screen through the new mapping - let page_ptr: *mut u64 = page.start_address().as_mut_ptr(); - unsafe { page_ptr.offset(400).write_volatile(0x_f021_f077_f065_f04e) }; + let x = Box::new(41); serial_println!("Preparing nasty fault..."); unsafe {