From 37432ef90274857d4fb088bda4b65cc967f8309d Mon Sep 17 00:00:00 2001 From: Julien CLEMENT Date: Wed, 8 Dec 2021 22:47:46 +0100 Subject: [PATCH] feat(heap): refacto memory init and add heap simple allocation Signed-off-by: Julien CLEMENT --- .cargo/config.toml | 2 +- Cargo.lock | 34 +++++++++++++++ Cargo.toml | 1 + src/lib.rs | 65 +++++++-------------------- src/linker.ld | 7 +++ src/memory/heap_alloc/mod.rs | 8 ++++ src/memory/mod.rs | 85 ++++++++++++++++++++++++++++++++++++ src/memory/paging/mod.rs | 11 ++--- 8 files changed, 157 insertions(+), 56 deletions(-) create mode 100644 src/memory/heap_alloc/mod.rs diff --git a/.cargo/config.toml b/.cargo/config.toml index 7137ff2..b5465ee 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -3,4 +3,4 @@ target = "x86_64-julios.json" [unstable] build-std-features = ["compiler-builtins-mem"] -build-std = ["core", "compiler_builtins"] +build-std = ["core", "compiler_builtins", "alloc"] diff --git a/Cargo.lock b/Cargo.lock index da8af61..50c0a7a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -25,6 +25,7 @@ name = "julios" version = "0.1.0" dependencies = [ "lazy_static", + "linked_list_allocator", "multiboot2", "pc-keyboard", "pic8259", @@ -42,6 +43,24 @@ dependencies = [ "spin", ] +[[package]] +name = "linked_list_allocator" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "549ce1740e46b291953c4340adcd74c59bcf4308f4cac050fd33ba91b7168f4a" +dependencies = [ + "spinning_top", +] + +[[package]] +name = "lock_api" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109" +dependencies = [ + "scopeguard", +] + [[package]] name = "multiboot2" version = "0.1.0" @@ -66,12 +85,27 @@ dependencies = [ "x86_64", ] +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + [[package]] name = "spin" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" +[[package]] +name = "spinning_top" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75adad84ee84b521fb2cca2d4fd0f1dab1d8d026bda3c5bea4ca63b5f9f9293c" +dependencies = [ + "lock_api", +] + [[package]] name = "volatile" version = "0.2.7" diff --git a/Cargo.toml b/Cargo.toml index 3335063..710aebc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,7 @@ x86_64 = "0.14.2" pic8259 = "0.10.1" pc-keyboard = "0.5.0" multiboot2 = "0.1.0" +linked_list_allocator = "0.9.0" [dependencies.lazy_static] version = "1.0" diff --git a/src/lib.rs b/src/lib.rs index ddc6f8d..797f70d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,7 @@ #![no_std] #![no_main] #![feature(abi_x86_interrupt)] +#![feature(alloc_error_handler)] mod gdt; mod interrupts; @@ -8,13 +9,19 @@ mod memory; mod serial; mod vga; +//#[macro_use] +extern crate alloc; extern crate multiboot2; use core::panic::PanicInfo; -use memory::paging::{FrameAllocator, Size4KiB}; use multiboot2::BootInformation; use vga::{Color, ColorCode}; +#[alloc_error_handler] +fn alloc_error_handler(layout: alloc::alloc::Layout) -> ! { + panic!("Allocation error: {:?}", layout) +} + #[panic_handler] fn panic_handler(info: &PanicInfo) -> ! { vga::change_color(ColorCode::new(Color::LightRed, Color::Black)); @@ -28,68 +35,26 @@ pub fn hlt_loop() -> ! { } } -pub fn init(frame_allocator: &mut A, boot_info: &BootInformation) -where - A: FrameAllocator, +pub fn init(boot_info: &BootInformation) { vga::change_color(ColorCode::new(Color::LightCyan, Color::Black)); println!("Starting init"); - enable_nxe_bit(); - enable_write_protect_bit(); - memory::kernel_remap(frame_allocator, boot_info); + memory::init(boot_info); gdt::init_gdt(); interrupts::init_idt(); vga::change_color(ColorCode::new(Color::LightGreen, Color::Black)); } -fn enable_nxe_bit() { - println!("Enabling nxe bit"); - use x86_64::registers::control::{Efer, EferFlags}; - unsafe { Efer::update(|efer| *efer |= EferFlags::NO_EXECUTE_ENABLE) } -} - -fn enable_write_protect_bit() { - println!("Enabling write protection bit"); - use x86_64::registers::control::{Cr0, Cr0Flags}; - - unsafe { Cr0::write(Cr0::read() | Cr0Flags::WRITE_PROTECT) }; -} - -fn get_frame_allocator(multiboot_info_addr: usize) -> memory::AreaFrameAllocator { - let boot_info = unsafe { multiboot2::load(multiboot_info_addr) }; - let memory_map_tag = boot_info.memory_map_tag().expect("Memory map tag required"); - - let elf_sections_tag = boot_info - .elf_sections_tag() - .expect("Elf-sections tag required"); - - let kernel_start: u64 = elf_sections_tag.sections().map(|s| s.addr).min().unwrap(); - let kernel_end: u64 = elf_sections_tag - .sections() - .map(|s| s.addr + s.size) - .max() - .unwrap(); - - let multiboot_start: u64 = multiboot_info_addr as u64; - let multiboot_end: u64 = multiboot_start + (boot_info.total_size as u64); - - memory::AreaFrameAllocator::new( - kernel_start, - kernel_end, - multiboot_start, - multiboot_end, - memory_map_tag.memory_areas(), - ) -} - #[no_mangle] pub extern "C" fn julios_main(multiboot_info_addr: usize) -> ! { let boot_info = unsafe { multiboot2::load(multiboot_info_addr) }; - let mut frame_allocator = get_frame_allocator(multiboot_info_addr); - - init(&mut frame_allocator, &boot_info); + init(&boot_info); println!("***JuliOS V0.1.0***"); serial_println!("Hello serial"); + + use alloc::boxed::Box; + let x = Box::new(41); + panic!("Kernel end of flow"); } diff --git a/src/linker.ld b/src/linker.ld index 8df41e8..4ab13e4 100644 --- a/src/linker.ld +++ b/src/linker.ld @@ -2,6 +2,7 @@ ENTRY(_start) SECTIONS { . = 1M; + . = ALIGN(4K); .rodata : { /* ensure that the multiboot header is at the beginning */ @@ -10,6 +11,12 @@ SECTIONS { . = ALIGN(4K); } + . = ALIGN(4K); + .eh_frame : + { + *(.eh_frame .eh_frame.*) + . = ALIGN(4K); + } . = ALIGN(4K); .text : { diff --git a/src/memory/heap_alloc/mod.rs b/src/memory/heap_alloc/mod.rs new file mode 100644 index 0000000..bf8e61a --- /dev/null +++ b/src/memory/heap_alloc/mod.rs @@ -0,0 +1,8 @@ +use super::PAGE_SIZE; +use linked_list_allocator::LockedHeap; + +pub const HEAP_START: u64 = 0x4444_4444_0000; +pub const HEAP_SIZE: u64 = PAGE_SIZE as u64 * 25; + +#[global_allocator] +pub static ALLOCATOR: LockedHeap = LockedHeap::empty(); diff --git a/src/memory/mod.rs b/src/memory/mod.rs index a261cd0..7254ac2 100644 --- a/src/memory/mod.rs +++ b/src/memory/mod.rs @@ -1,7 +1,92 @@ pub use self::frame_allocator::AreaFrameAllocator; pub use paging::kernel_remap; +use crate::println; +use multiboot2::BootInformation; +use paging::{Size4KiB, RecursivePageTable, FrameAllocator, Page, Flags, Mapper}; +use heap_alloc::{HEAP_START, HEAP_SIZE, ALLOCATOR}; +use x86_64::VirtAddr; +use x86_64::structures::paging::{mapper::MapToError, page::PageRangeInclusive}; pub mod frame_allocator; pub mod paging; +pub mod heap_alloc; pub const PAGE_SIZE: usize = 4096; + +pub fn init(boot_info: &BootInformation) { + enable_nxe_bit(); + enable_write_protect_bit(); + let mut frame_allocator = get_frame_allocator(boot_info.start_address()); + let mut active_table = kernel_remap(&mut frame_allocator, boot_info); + init_heap(&mut active_table, &mut frame_allocator) + .expect("Heap initialization failed"); +} + +fn init_heap(active_table: &mut RecursivePageTable, frame_allocator: &mut A) + -> Result<(), MapToError> + where A: FrameAllocator +{ + let page_range: PageRangeInclusive = { + let heap_start = VirtAddr::new(HEAP_START); + 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 = Flags::PRESENT | Flags::WRITABLE; + unsafe { + active_table.map_to(page, frame, flags, frame_allocator)?.flush(); + } + } + + unsafe { + ALLOCATOR.lock().init(HEAP_START as usize, HEAP_SIZE as usize); + } + + Ok(()) +} + +fn get_frame_allocator(multiboot_info_addr: usize) -> AreaFrameAllocator { + let boot_info = unsafe { multiboot2::load(multiboot_info_addr) }; + let memory_map_tag = boot_info.memory_map_tag().expect("Memory map tag required"); + + let elf_sections_tag = boot_info + .elf_sections_tag() + .expect("Elf-sections tag required"); + + let kernel_start: u64 = elf_sections_tag.sections().map(|s| s.addr).min().unwrap(); + let kernel_end: u64 = elf_sections_tag + .sections() + .map(|s| s.addr + s.size) + .max() + .unwrap(); + + let multiboot_start: u64 = multiboot_info_addr as u64; + let multiboot_end: u64 = multiboot_start + (boot_info.total_size as u64); + + AreaFrameAllocator::new( + kernel_start, + kernel_end, + multiboot_start, + multiboot_end, + memory_map_tag.memory_areas(), + ) +} + +fn enable_nxe_bit() { + println!("Enabling nxe bit"); + use x86_64::registers::control::{Efer, EferFlags}; + unsafe { Efer::update(|efer| *efer |= EferFlags::NO_EXECUTE_ENABLE) } +} + +fn enable_write_protect_bit() { + println!("Enabling write protection bit"); + use x86_64::registers::control::{Cr0, Cr0Flags}; + + unsafe { Cr0::write(Cr0::read() | Cr0Flags::WRITE_PROTECT) }; +} diff --git a/src/memory/paging/mod.rs b/src/memory/paging/mod.rs index eca8974..8b86e7d 100644 --- a/src/memory/paging/mod.rs +++ b/src/memory/paging/mod.rs @@ -13,6 +13,7 @@ mod temporary_page; pub const P4: *mut PageTable = 0o177777_777_777_777_777_0000 as *mut _; + fn get_flags_from_elf_section(section: &ElfSection) -> Flags { use multiboot2::{ELF_SECTION_ALLOCATED, ELF_SECTION_EXECUTABLE, ELF_SECTION_WRITABLE}; @@ -31,17 +32,16 @@ fn get_flags_from_elf_section(section: &ElfSection) -> Flags { flags } -pub fn kernel_remap(allocator: &mut A, boot_info: &BootInformation) -where - A: FrameAllocator, +pub fn kernel_remap<'a, A>(allocator: &mut A, boot_info: & BootInformation) -> RecursivePageTable<'a> + where A: FrameAllocator, { println!("Remapping kernel"); let mut temporary_page = TemporaryPage::new( Page::containing_address(VirtAddr::new(0xcafebabe)), allocator, ); - let mut active_table = get_active_page_table(); - let mut new_table = { + let mut active_table: RecursivePageTable = get_active_page_table(); + let mut new_table: InactivePageTable = { let frame = allocator.allocate_frame().expect("No more frames"); InactivePageTable::new(frame, &mut active_table, &mut temporary_page) }; @@ -109,6 +109,7 @@ where )); active_table.unmap(old_p4_page).expect("Failed to unmap old P4").1.flush(); println!("Stack guard page at {:#x}", old_p4_page.start_address()); + active_table } struct InactivePageTable {