diff --git a/kernel/Cargo.lock b/kernel/Cargo.lock index 795704c..ad9ae74 100644 --- a/kernel/Cargo.lock +++ b/kernel/Cargo.lock @@ -2,12 +2,6 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "alloc-traits" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b2d54853319fd101b8dd81de382bcbf3e03410a64d8928bbee85a3e7dcde483" - [[package]] name = "autocfg" version = "1.3.0" @@ -44,9 +38,9 @@ version = "0.0.1" dependencies = [ "bitvec", "kernel-common", + "linked_list_allocator", "log", "spin", - "static-alloc", ] [[package]] @@ -57,6 +51,15 @@ dependencies = [ "log", ] +[[package]] +name = "linked_list_allocator" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afa463f5405ee81cdb9cc2baf37e08ec7e4c8209442b5d72c04cfb2cd6e6286" +dependencies = [ + "spinning_top", +] + [[package]] name = "lock_api" version = "0.4.12" @@ -95,12 +98,12 @@ dependencies = [ ] [[package]] -name = "static-alloc" +name = "spinning_top" version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b2975e035ce16539eecee08d7c6e5626ca26f299c6e90af343b302c6dd2e61e" +checksum = "5b9eb1a2f4c41445a3a0ff9abc5221c5fcd28e1f13cd7c0397706f9ac938ddb0" dependencies = [ - "alloc-traits", + "lock_api", ] [[package]] diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index d27eb19..4e6be24 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -6,6 +6,6 @@ edition = "2021" [dependencies] bitvec = {version = "1.0.1", default-features = false, features = ["alloc", "atomic"]} kernel-common = {path = "../lib/kernel-common"} +linked_list_allocator = "0.10.5" log = "0.4.22" spin = "0.9.8" -static-alloc = "0.2.5" diff --git a/kernel/src/cpu/paging.rs b/kernel/src/cpu/paging.rs index 276740f..800de94 100644 --- a/kernel/src/cpu/paging.rs +++ b/kernel/src/cpu/paging.rs @@ -1,8 +1,10 @@ +use core::panic; + use alloc::boxed::Box; -use bitvec::{bitvec, order::Lsb0}; +use bitvec::{bitvec, order::Lsb0, vec::BitVec}; use kernel_common::{ loader_struct::LoaderStruct, - paging::{load_cr3, PageEntry, PageTable, KERNEL_VIRT_START}, + paging::{load_cr3, PageEntry, PageTable, KERNEL_HEAP_INITIAL_SIZE, KERNEL_HEAP_START, KERNEL_VIRT_START}, }; use log::info; use spin::{Mutex, Once}; @@ -18,9 +20,19 @@ extern "C" { static _bss_end: u8; } -static KERNEL_PHYS_START: Once = Once::new(); +static HEAP_PHYS_START: Once = Once::new(); static CURRENT_PML4: Mutex> = Mutex::new(None); +static PHYSICAL_FRAMES: Mutex>> = Mutex::new(None); +fn _get_free_frame() -> u64 { + let frames_vec = PHYSICAL_FRAMES.lock(); + for i in 0..frames_vec.as_ref().unwrap().len() { + if !frames_vec.as_ref().unwrap()[i] { + return i as u64; + } + } + panic!("No free memory left"); +} fn get_table_entry(table: &mut PageTable, i: usize) -> &mut PageTable { if table.entries_virt[i].is_none() { const NONE: Option> = None; @@ -60,7 +72,7 @@ fn get_page(pml4: &mut PageTable, virt: u64) -> Option<&mut PageEntry> { fn virt_to_phys(virt: u64) -> u64 { let mut current_pml4 = CURRENT_PML4.lock(); match current_pml4.as_mut() { - None => virt - KERNEL_VIRT_START + KERNEL_PHYS_START.get().unwrap(), + None => virt - KERNEL_HEAP_START + HEAP_PHYS_START.get().unwrap(), Some(pml4) => { let page = get_page(pml4, virt); match page { @@ -74,6 +86,10 @@ fn map(pml4: &mut PageTable, virt: u64, phys: u64, user: bool, write: bool, exec if virt < 0x1000 { panic!("First page shouldn't be mapped"); } + { + let mut frames_vec = PHYSICAL_FRAMES.lock(); + frames_vec.as_mut().unwrap().set(phys as usize / 0x1000, true); + } let virt_page = virt as usize / 0x1000; let table_i = virt_page % 512; let directory_i = virt_page / 512 % 512; @@ -88,8 +104,8 @@ fn map(pml4: &mut PageTable, virt: u64, phys: u64, user: bool, write: bool, exec table.entries_phys[table_i].set_execute_disable(!exec as u64); table.entries_phys[table_i].set_present(1); } -pub fn setup_paging(loader_struct: &LoaderStruct, phys_start: u64) { - KERNEL_PHYS_START.call_once(|| phys_start); +pub fn setup_paging(loader_struct: &LoaderStruct, phys_start: u64, heap_start: u64) { + HEAP_PHYS_START.call_once(|| heap_start); let mut memory_size = 0; for i in loader_struct.available_memory { if i.initial_page + i.page_count > memory_size { @@ -97,11 +113,14 @@ pub fn setup_paging(loader_struct: &LoaderStruct, phys_start: u64) { } } info!("Memory size: {} MB", memory_size * 0x1000 / 1024 / 1024); - let mut frames_vec = bitvec![u64, Lsb0; 1; memory_size as usize]; - for i in loader_struct.available_memory { - for j in 0..i.page_count { - let page = i.initial_page + j; - frames_vec.set(page as usize, false); + { + let mut frames_vec = PHYSICAL_FRAMES.lock(); + *frames_vec = Some(bitvec![u64, Lsb0; 1; memory_size as usize]); + for i in loader_struct.available_memory { + for j in 0..i.page_count { + let page = i.initial_page + j; + frames_vec.as_mut().unwrap().set(page as usize, false); + } } } let text_start; @@ -135,24 +154,19 @@ pub fn setup_paging(loader_struct: &LoaderStruct, phys_start: u64) { } } for i in text_start..text_end { - let phys = i * 0x1000 - KERNEL_VIRT_START + phys_start; - frames_vec.set(phys as usize / 0x1000, true); - map(pml4, i * 0x1000, phys, false, false, true); + map(pml4, i * 0x1000, i * 0x1000 - KERNEL_VIRT_START + phys_start, false, false, true); } for i in rodata_start..rodata_end { - let phys = i * 0x1000 - KERNEL_VIRT_START + phys_start; - frames_vec.set(phys as usize / 0x1000, true); - map(pml4, i * 0x1000, phys, false, false, false); + map(pml4, i * 0x1000, i * 0x1000 - KERNEL_VIRT_START + phys_start, false, false, false); } for i in data_start..data_end { - let phys = i * 0x1000 - KERNEL_VIRT_START + phys_start; - frames_vec.set(phys as usize / 0x1000, true); - map(pml4, i * 0x1000, phys, false, true, false); + map(pml4, i * 0x1000, i * 0x1000 - KERNEL_VIRT_START + phys_start, false, true, false); } for i in bss_start..bss_end { - let phys = i * 0x1000 - KERNEL_VIRT_START + phys_start; - frames_vec.set(phys as usize / 0x1000, true); - map(pml4, i * 0x1000, phys, false, true, false); + map(pml4, i * 0x1000, i * 0x1000 - KERNEL_VIRT_START + phys_start, false, true, false); + } + for i in 0..KERNEL_HEAP_INITIAL_SIZE / 0x1000 { + map(pml4, KERNEL_HEAP_START + i as u64 * 0x1000, heap_start + i as u64 * 0x1000, false, true, false); } unsafe { load_cr3(virt_to_phys(pml4 as *const PageTable as u64)); diff --git a/kernel/src/main.rs b/kernel/src/main.rs index 610cb9f..e70992b 100644 --- a/kernel/src/main.rs +++ b/kernel/src/main.rs @@ -3,21 +3,22 @@ extern crate alloc; -use core::{arch::global_asm, panic::PanicInfo}; +use core::{arch::global_asm, mem::MaybeUninit, panic::PanicInfo}; use cpu::{gdt::setup_gdt, idt::setup_idt, paging::setup_paging}; use kernel_common::{ instructions::{cli, hlt}, loader_struct::{LoaderStruct, LOADER_STRUCT_MAGIC}, log::init_logger, + paging::{KERNEL_HEAP_INITIAL_SIZE, KERNEL_HEAP_START}, }; +use linked_list_allocator::LockedHeap; use log::{error, info}; -use static_alloc::Bump; mod cpu; #[global_allocator] -static ALLOC: Bump<[u8; 8 * 1024 * 1024]> = Bump::uninit(); +static ALLOC: LockedHeap = LockedHeap::empty(); global_asm!( " @@ -35,16 +36,23 @@ global_asm!( ); #[no_mangle] -extern "C" fn main(temp_loader_struct: &LoaderStruct) -> ! { +extern "C" fn main(temp_loader_struct: *const LoaderStruct) -> ! { + unsafe { + ALLOC.lock().init(KERNEL_HEAP_START as *mut u8, KERNEL_HEAP_INITIAL_SIZE); + } init_logger(); info!("Starting kernel..."); - let loader_struct = temp_loader_struct.clone(); + let mut loader_struct: LoaderStruct; + unsafe { + loader_struct = MaybeUninit::zeroed().assume_init(); + temp_loader_struct.copy_to(&mut loader_struct, 1); + } if loader_struct.magic != LOADER_STRUCT_MAGIC { panic!("Invalid bootloader struct"); } setup_gdt(); setup_idt(); - setup_paging(&loader_struct, loader_struct.phys_kernel_start); + setup_paging(&loader_struct, loader_struct.phys_kernel_start, loader_struct.phys_heap_start); loop { hlt(); } diff --git a/lib/kernel-common/src/loader_struct.rs b/lib/kernel-common/src/loader_struct.rs index 5a4114d..3a79398 100644 --- a/lib/kernel-common/src/loader_struct.rs +++ b/lib/kernel-common/src/loader_struct.rs @@ -9,6 +9,7 @@ pub struct LoaderStructMemoryRegion { pub struct LoaderStruct { pub magic: u64, pub phys_kernel_start: u64, + pub phys_heap_start: u64, pub available_memory: [LoaderStructMemoryRegion; 1024], } diff --git a/lib/kernel-common/src/paging.rs b/lib/kernel-common/src/paging.rs index 7cf4ca3..290cfae 100644 --- a/lib/kernel-common/src/paging.rs +++ b/lib/kernel-common/src/paging.rs @@ -26,6 +26,8 @@ pub struct PageTable { } pub const KERNEL_VIRT_START: u64 = 0xffffffff80000000; +pub const KERNEL_HEAP_START: u64 = 0xfffffffe00000000; +pub const KERNEL_HEAP_INITIAL_SIZE: usize = 16 * 1024 * 1024; pub unsafe fn load_cr3(cr3: u64) { asm!("mov cr3, {}", in(reg) cr3); diff --git a/loader/Cargo.lock b/loader/Cargo.lock index 09475da..1a0bd91 100644 --- a/loader/Cargo.lock +++ b/loader/Cargo.lock @@ -123,9 +123,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.68" +version = "2.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "901fa70d88b9d6c98022e23b4136f9f3e54e4662c3bc1bd1d84a42a9a0f0c1e9" +checksum = "201fcda3845c23e8212cd466bfebf0bd20694490fc0356ae8e428e0824a915a6" dependencies = [ "proc-macro2", "quote", @@ -165,7 +165,7 @@ checksum = "4f345e42323c05e41e29e409505f5f8e0df7b5743340215d60344dbd79b729f4" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.69", ] [[package]] diff --git a/loader/src/loader_struct.rs b/loader/src/loader_struct.rs index 6826fb5..1e76dcd 100644 --- a/loader/src/loader_struct.rs +++ b/loader/src/loader_struct.rs @@ -1,10 +1,11 @@ use kernel_common::loader_struct::{LoaderStruct, LoaderStructMemoryRegion, LOADER_STRUCT_MAGIC}; use uefi::table::boot::{MemoryMap, MemoryType}; -pub fn generate_loader_struct(memory_map: &MemoryMap, phys_start: u64) -> LoaderStruct { +pub fn generate_loader_struct(memory_map: &MemoryMap, phys_start: u64, heap_start: u64) -> LoaderStruct { let mut loader_struct = LoaderStruct { magic: LOADER_STRUCT_MAGIC, phys_kernel_start: phys_start, + phys_heap_start: heap_start, available_memory: [LoaderStructMemoryRegion { initial_page: 0, page_count: 0 }; 1024], }; let mut next_entry = 0; diff --git a/loader/src/main.rs b/loader/src/main.rs index 67bcbd7..139c341 100644 --- a/loader/src/main.rs +++ b/loader/src/main.rs @@ -10,6 +10,7 @@ use kernel_common::{ instructions::{cli, hlt}, loader_struct::LoaderStruct, log::init_logger, + paging::KERNEL_HEAP_INITIAL_SIZE, }; use loader_struct::generate_loader_struct; use log::{error, info}; @@ -17,7 +18,10 @@ use paging::setup_paging; use static_alloc::Bump; use uefi::{ entry, - table::{boot::MemoryType, Boot, SystemTable}, + table::{ + boot::{AllocateType, MemoryType}, + Boot, SystemTable, + }, Handle, Status, }; @@ -36,13 +40,17 @@ fn main(image_handle: Handle, mut system_table: SystemTable) -> Status { info!("Starting bootloader..."); uefi::helpers::init(&mut system_table).unwrap(); let (kernel_start, kernel_entry) = load_kernel(KERNEL, &system_table); + let heap_start = system_table + .boot_services() + .allocate_pages(AllocateType::AnyPages, MemoryType::LOADER_DATA, KERNEL_HEAP_INITIAL_SIZE / 0x1000) + .unwrap(); let memory_map; unsafe { memory_map = system_table.exit_boot_services(MemoryType::LOADER_DATA).1; } - let pml4 = setup_paging(&memory_map); + let pml4 = setup_paging(&memory_map, heap_start); map_kernel(KERNEL, pml4, kernel_start); - let loader_struct = generate_loader_struct(&memory_map, kernel_start); + let loader_struct = generate_loader_struct(&memory_map, kernel_start, heap_start); info!("Jumping to kernel..."); unsafe { (mem::transmute::<_, extern "C" fn(&LoaderStruct) -> !>(kernel_entry))(&loader_struct); diff --git a/loader/src/paging.rs b/loader/src/paging.rs index bd9accc..75e4b37 100644 --- a/loader/src/paging.rs +++ b/loader/src/paging.rs @@ -1,7 +1,7 @@ use core::arch::asm; use alloc::boxed::Box; -use kernel_common::paging::{load_cr3, PageEntry, PageTable}; +use kernel_common::paging::{load_cr3, PageEntry, PageTable, KERNEL_HEAP_INITIAL_SIZE, KERNEL_HEAP_START}; use uefi::table::boot::{MemoryMap, MemoryType}; fn get_table_entry(table: &mut PageTable, i: usize) -> &mut PageTable { @@ -32,7 +32,7 @@ pub fn map(pml4: &mut PageTable, virt: u64, phys: u64, write: bool, exec: bool) table.entries_phys[table_i].set_execute_disable(!exec as u64); table.entries_phys[table_i].set_present(1); } -pub fn setup_paging(memory_map: &MemoryMap) -> &mut PageTable { +pub fn setup_paging(memory_map: &MemoryMap, heap_start: u64) -> &mut PageTable { const NONE: Option> = None; let pml4 = Box::leak(Box::new(PageTable { entries_phys: [PageEntry(0); 512], @@ -59,6 +59,9 @@ pub fn setup_paging(memory_map: &MemoryMap) -> &mut PageTable { } } } + for i in 0..KERNEL_HEAP_INITIAL_SIZE / 0x1000 { + map(pml4, KERNEL_HEAP_START + i as u64 * 0x1000, heap_start + i as u64 * 0x1000, true, false); + } unsafe { load_cr3(pml4 as *const PageTable as u64); // Write Protect