changed page allocation to happen on page fault for performance reasons

This commit is contained in:
2025-02-27 23:57:23 +00:00
parent 2915d0c879
commit 192100be7a
9 changed files with 144 additions and 61 deletions
+2 -4
View File
@@ -1,5 +1,6 @@
use core::arch::x86_64::__cpuid; use core::arch::x86_64::__cpuid;
use libk::drivers::memory::FoundryOSFrameAllocator;
use spin::Lazy; use spin::Lazy;
use x86_64::{ use x86_64::{
PhysAddr, VirtAddr, PhysAddr, VirtAddr,
@@ -12,10 +13,7 @@ use x86_64::{
use crate::serial_print; use crate::serial_print;
use super::{ use super::{cpu::model_specific_registers::*, memmap::PHYSICAL_MEMORY_OFFSET};
cpu::model_specific_registers::*, memmap::PHYSICAL_MEMORY_OFFSET,
memory::FoundryOSFrameAllocator,
};
const IA32_APIC_BASE_MSR: u32 = 0x1b; const IA32_APIC_BASE_MSR: u32 = 0x1b;
const IA32_APIC_BASE_MSR_BSP: u64 = 0x100; const IA32_APIC_BASE_MSR_BSP: u64 = 0x100;
+39 -11
View File
@@ -1,7 +1,10 @@
use libk::drivers::memory::{FRAME_ALLOCATOR, OFFSET_PAGE_TABLE};
use libk::prelude::*; use libk::prelude::*;
use pic8259::ChainedPics; use pic8259::ChainedPics;
use x86_64::registers::control::Cr2; use x86_64::registers::control::Cr2;
use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame, PageFaultErrorCode}; use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame, PageFaultErrorCode};
use x86_64::structures::paging::mapper::MapperFlushAll;
use x86_64::structures::paging::{FrameAllocator, Mapper, Page, PageTableFlags, Size4KiB};
use spin::{Lazy, Mutex}; use spin::{Lazy, Mutex};
@@ -52,12 +55,19 @@ impl InterruptIndex {
pub fn init_idt() { pub fn init_idt() {
IDT.load(); IDT.load();
// enable_apic(); }
// TODO: fix apic
// unsafe { pub fn enable_pic() {
// PICS.lock().initialize(); unsafe {
// PICS.lock().write_masks(0xfc, 0xff); PICS.lock().initialize();
// } PICS.lock().write_masks(0xfc, 0xff);
}
}
pub fn disable_pic() {
unsafe {
PICS.lock().disable();
}
} }
extern "x86-interrupt" fn breakpoint_handler(stack_frame: InterruptStackFrame) { extern "x86-interrupt" fn breakpoint_handler(stack_frame: InterruptStackFrame) {
@@ -118,10 +128,28 @@ extern "x86-interrupt" fn page_fault_handler(
stack_frame: InterruptStackFrame, stack_frame: InterruptStackFrame,
error_code: PageFaultErrorCode, error_code: PageFaultErrorCode,
) { ) {
serial_println!("Exception: Page Fault"); // serial_println!("Exception: Page Fault");
serial_println!("Accessed Address: {:?}", Cr2::read()); // serial_println!("Accessed Address: {:?}", Cr2::read());
serial_println!("Error Code: {:?}", error_code); // serial_println!("Error Code: {:?}", error_code);
serial_println!("{:#?}", stack_frame); // serial_println!("{:#?}", stack_frame);
panic!("page fault"); if let Some(frame_allocator) = FRAME_ALLOCATOR.get() {
let mut f = frame_allocator.lock();
let frame = f.allocate_frame().unwrap();
let flags = PageTableFlags::PRESENT | PageTableFlags::WRITABLE;
let page: Page<Size4KiB> = Page::containing_address(Cr2::read().unwrap());
unsafe {
let mut mapper = OFFSET_PAGE_TABLE.get().unwrap().lock();
match mapper.map_to(page, frame, flags, &mut *f) {
Ok(_) => {}
Err(why) => panic!("failed to map page: {:?}", why),
}
}
MapperFlushAll::new().flush_all();
} else {
panic!("failed to get frame allocator");
}
} }
+4 -4
View File
@@ -14,6 +14,10 @@ static MEMORY_MAP_REQUEST: MemoryMapRequest = MemoryMapRequest::new();
#[unsafe(link_section = ".requests")] #[unsafe(link_section = ".requests")]
static HIGHER_HALF_DIRECT_MAP_REQUEST: HhdmRequest = HhdmRequest::new(); static HIGHER_HALF_DIRECT_MAP_REQUEST: HhdmRequest = HhdmRequest::new();
#[used]
#[unsafe(link_section = ".requests")]
static KERNEL_ADDRESS_REQUEST: KernelAddressRequest = KernelAddressRequest::new();
/// ```rs /// ```rs
/// let virt_addr = phys_addr + offset; /// let virt_addr = phys_addr + offset;
/// let phys_addr = virt_addr - offset; // (given VA is in the HHDM). Do not use for executable code. /// let phys_addr = virt_addr - offset; // (given VA is in the HHDM). Do not use for executable code.
@@ -25,10 +29,6 @@ pub static PHYSICAL_MEMORY_OFFSET: Lazy<u64> = Lazy::new(|| {
.offset() .offset()
}); });
#[used]
#[unsafe(link_section = ".requests")]
static KERNEL_ADDRESS_REQUEST: KernelAddressRequest = KernelAddressRequest::new();
/// Converts virtual addresses in the kernel to a physical address like this: /// Converts virtual addresses in the kernel to a physical address like this:
/// ```rs /// ```rs
/// let phys_addr = virt_addr - virtual_base + physical_base; /// let phys_addr = virt_addr - virtual_base + physical_base;
-2
View File
@@ -2,8 +2,6 @@ pub mod gdt;
pub mod interrupts; pub mod interrupts;
pub mod memory;
pub mod memmap; pub mod memmap;
pub mod apic; pub mod apic;
+27 -18
View File
@@ -15,6 +15,7 @@ extern crate alloc;
use arch::x86_64::apic::enable_apic; use arch::x86_64::apic::enable_apic;
use core::arch::asm; use core::arch::asm;
use libk::drivers::memory;
use limine::BaseRevision; use limine::BaseRevision;
use libk::drivers::kalloc::allocator::init_heap; use libk::drivers::kalloc::allocator::init_heap;
@@ -57,7 +58,7 @@ pub fn boot() -> Result<(), &'static str> {
return Err("base revision not supported"); return Err("base revision not supported");
} }
use arch::x86_64::{gdt, interrupts, memmap, memory}; use arch::x86_64::{gdt, interrupts, memmap};
let memory_map = memmap::get_memory_map(); let memory_map = memmap::get_memory_map();
@@ -72,29 +73,37 @@ pub fn boot() -> Result<(), &'static str> {
gdt::init(); gdt::init();
println_log!("[Success]"); println_log!("[Success]");
print_log!(" Initialising Memory Subsystem... ");
let physical_memory_offset = VirtAddr::new(*memmap::PHYSICAL_MEMORY_OFFSET);
let mut l4_table = unsafe { memory::init(physical_memory_offset) };
println_log!("[Success]");
print_log!(" Setting Up Page Table... ");
let mut frame_allocator = unsafe { memory::FoundryOSFrameAllocator::init(memory_map) };
println_log!("[Success]");
print_log!(" Initialising Heap... ");
if init_heap(&mut l4_table, &mut frame_allocator).is_err() {
return Err("Failed to initialise heap: error");
}
println_log!("[Success]");
print_log!(" Setting Up Interrupt Descriptor Table... "); print_log!(" Setting Up Interrupt Descriptor Table... ");
interrupts::init_idt(); interrupts::init_idt();
println_log!("[Success]"); println_log!("[Success]");
print_log!(" Initialising APIC"); print_log!(" Initialising Memory Subsystem... ");
enable_apic(&mut l4_table, &mut frame_allocator); let physical_memory_offset = VirtAddr::new(*memmap::PHYSICAL_MEMORY_OFFSET);
let mut l4_table = memory::init_page_table(physical_memory_offset);
println_log!("[Success]"); println_log!("[Success]");
print_log!(" Setting Up Page Table... ");
memory::init_frame_allocator(memory_map);
println_log!("[Success]");
print_log!(" Initialising Heap... ");
if init_heap().is_err() {
return Err("Failed to initialise heap: error");
}
println_log!("[Success]");
print_log!(" Enabling PICs... ");
interrupts::enable_pic();
println_log!("[Success]");
// print_log!(" Disabling PICs... ");
// interrupts::disable_pic();
// println_log!("[Success]");
//
// print_log!(" Initialising APIC");
// enable_apic(&mut l4_table, &mut frame_allocator);
// println_log!("[Success]");
print_log!(" Enabling Interrupts... "); print_log!(" Enabling Interrupts... ");
x86_64::instructions::interrupts::enable(); x86_64::instructions::interrupts::enable();
println_log!("[Success]"); println_log!("[Success]");
+7
View File
@@ -28,6 +28,13 @@ extern "C" fn kmain() -> ! {
println!("Dimensions: {}x{} (chars)", dimensions.0, dimensions.1); println!("Dimensions: {}x{} (chars)", dimensions.0, dimensions.1);
let mut executor = Executor::new(); let mut executor = Executor::new();
let mut v = Vec::with_capacity(1000 * 1000);
for i in 0..1000 * 1000 {
v.push(i);
}
println!("v.len(): {}", v.len());
executor.spawn(Task::new(shell())); executor.spawn(Task::new(shell()));
executor.run(); executor.run();
} }
+48 -20
View File
@@ -2,10 +2,16 @@ use linked_list_allocator::LockedHeap;
use x86_64::{ use x86_64::{
VirtAddr, VirtAddr,
structures::paging::{ structures::paging::{
FrameAllocator, Mapper, Page, PageTableFlags, Size4KiB, mapper::MapToError, FrameAllocator, Mapper, Page, PageTableFlags, Size4KiB,
mapper::{MapToError, MapperFlushAll},
}, },
}; };
use crate::{
drivers::memory::{FRAME_ALLOCATOR, OFFSET_PAGE_TABLE},
serial_print, serial_println,
};
/// We are currently using a linked list heap allocator which uses our underlying page allocator. /// We are currently using a linked list heap allocator which uses our underlying page allocator.
pub type FoundryAllocator = LockedHeap; pub type FoundryAllocator = LockedHeap;
@@ -14,28 +20,50 @@ pub type FoundryAllocator = LockedHeap;
static ALLOCATOR: FoundryAllocator = FoundryAllocator::empty(); static ALLOCATOR: FoundryAllocator = FoundryAllocator::empty();
pub const HEAP_START: usize = 0x4444_4444_0000; pub const HEAP_START: usize = 0x4444_4444_0000;
pub const HEAP_SIZE: usize = 1000 * 1024; pub const HEAP_SIZE: usize = 1024 * 1024 * 1024;
/// Sets up the heap using the backing page frame allocator. /// Sets up the heap using the backing page frame allocator.
pub fn init_heap( pub fn init_heap() -> Result<(), MapToError<Size4KiB>> {
mapper: &mut impl Mapper<Size4KiB>, // let mut frame_allocator = if let Some(f) = FRAME_ALLOCATOR.get() {
frame_allocator: &mut impl FrameAllocator<Size4KiB>, // f.lock()
) -> Result<(), MapToError<Size4KiB>> { // } else {
let range = { // return Err(MapToError::FrameAllocationFailed);
let heap_start = VirtAddr::new(HEAP_START as u64); // };
let heap_end = heap_start + HEAP_SIZE as u64 - 1u64;
let heap_start_page = Page::<Size4KiB>::containing_address(heap_start);
let heap_end_page = Page::<Size4KiB>::containing_address(heap_end);
Page::range_inclusive(heap_start_page, heap_end_page)
};
for page in range { // let mut mapper = if let Some(m) = OFFSET_PAGE_TABLE.get() {
let frame = frame_allocator // m.lock()
.allocate_frame() // } else {
.ok_or(MapToError::FrameAllocationFailed)?; // return Err(MapToError::FrameAllocationFailed);
let flags = PageTableFlags::PRESENT | PageTableFlags::WRITABLE; // };
unsafe { mapper.map_to(page, frame, flags, frame_allocator)?.flush() };
} // let 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::<Size4KiB>::containing_address(heap_start);
// let heap_end_page = Page::<Size4KiB>::containing_address(heap_end);
// Page::range_inclusive(heap_start_page, heap_end_page)
// };
// let usable_frames = frame_allocator.count_usable_frames();
// serial_println!("usable frames: {}", usable_frames);
// let mut i = 0;
// for page in range {
// i += 1;
// if i % 128 == 0 {
// serial_println!("allocated {} pages", i);
// }
// let frame = frame_allocator
// .allocate_frame()
// .ok_or(MapToError::FrameAllocationFailed)?;
// let flags = PageTableFlags::PRESENT | PageTableFlags::WRITABLE;
// unsafe {
// // IMPORTANT: make sure to flush the mapper!!!!
// let _ = mapper.map_to(page, frame, flags, &mut *frame_allocator)?;
// }
// }
// MapperFlushAll::new().flush_all();
unsafe { unsafe {
ALLOCATOR.lock().init(HEAP_START as *mut u8, HEAP_SIZE); ALLOCATOR.lock().init(HEAP_START as *mut u8, HEAP_SIZE);
@@ -1,5 +1,6 @@
// use lib_alloc::allocator::FoundryAllocator; // use lib_alloc::allocator::FoundryAllocator;
use limine::{memory_map::EntryType, response::MemoryMapResponse}; use limine::{memory_map::EntryType, response::MemoryMapResponse};
use spin::{Mutex, Once};
use x86_64::{ use x86_64::{
PhysAddr, VirtAddr, PhysAddr, VirtAddr,
registers::control::Cr3, registers::control::Cr3,
@@ -9,6 +10,8 @@ use x86_64::{
}, },
}; };
pub static FRAME_ALLOCATOR: Once<Mutex<FoundryOSFrameAllocator>> = Once::new();
pub static OFFSET_PAGE_TABLE: Once<Mutex<OffsetPageTable>> = Once::new();
/// Returns a mutable reference to the current level 4 page table. /// Returns a mutable reference to the current level 4 page table.
/// ///
/// # Safety /// # Safety
@@ -42,10 +45,11 @@ unsafe fn active_l4_table(physical_memory_offset: VirtAddr) -> &'static mut Page
/// ///
/// Returns an `OffsetPageTable` that allows for manipulation of the page /// Returns an `OffsetPageTable` that allows for manipulation of the page
/// tables for the current CPU architecture. /// tables for the current CPU architecture.
pub unsafe fn init(physical_memory_offset: VirtAddr) -> OffsetPageTable<'static> { pub fn init_page_table(physical_memory_offset: VirtAddr) {
unsafe { unsafe {
let l4_table = active_l4_table(physical_memory_offset); let l4_table = active_l4_table(physical_memory_offset);
OffsetPageTable::new(l4_table, physical_memory_offset) let offset_table = OffsetPageTable::new(l4_table, physical_memory_offset);
OFFSET_PAGE_TABLE.call_once(|| Mutex::new(offset_table));
} }
} }
@@ -54,6 +58,12 @@ pub struct FoundryOSFrameAllocator {
next: usize, next: usize,
} }
pub fn init_frame_allocator(memory_map: &'static MemoryMapResponse) {
unsafe {
FRAME_ALLOCATOR.call_once(|| Mutex::new(FoundryOSFrameAllocator::init(memory_map)));
}
}
impl FoundryOSFrameAllocator { impl FoundryOSFrameAllocator {
/// Creates a new `FoundryOSFrameAllocator` from a memory map. /// Creates a new `FoundryOSFrameAllocator` from a memory map.
/// ///
@@ -67,6 +77,10 @@ impl FoundryOSFrameAllocator {
} }
} }
pub fn count_usable_frames(&self) -> u32 {
self.usable_frames().count() as u32
}
/// An iterator over all usable frames in the memory map. /// An iterator over all usable frames in the memory map.
/// ///
/// Yields one `PhysFrame` for each available 4KiB frame in the memory map. /// Yields one `PhysFrame` for each available 4KiB frame in the memory map.
+1
View File
@@ -2,4 +2,5 @@ pub mod io;
pub mod kalloc; pub mod kalloc;
pub mod async_io; pub mod async_io;
pub mod memory;
pub mod pic; pub mod pic;