Add kernel heap

This commit is contained in:
Mathieu Strypsteen 2024-07-08 11:47:29 +02:00
parent 646a4ea2b7
commit 98aaab64d7
10 changed files with 89 additions and 49 deletions

23
kernel/Cargo.lock generated
View file

@ -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]]

View file

@ -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"

View file

@ -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<u64> = Once::new();
static HEAP_PHYS_START: Once<u64> = Once::new();
static CURRENT_PML4: Mutex<Option<&mut PageTable>> = Mutex::new(None);
static PHYSICAL_FRAMES: Mutex<Option<BitVec<u64>>> = 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<Box<PageTable>> = 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];
{
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.set(page as usize, false);
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));

View file

@ -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();
}

View file

@ -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],
}

View file

@ -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);

6
loader/Cargo.lock generated
View file

@ -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]]

View file

@ -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;

View file

@ -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<Boot>) -> 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);

View file

@ -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<Box<PageTable>> = 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