Megacommit to move some memory code into kernel crate

This commit is contained in:
2025-02-28 02:13:50 +00:00
parent 192100be7a
commit 92fe618a99
16 changed files with 106 additions and 323 deletions
+1 -1
View File
@@ -72,7 +72,7 @@ impl Writer {
}
// Get the character data from the font array. -- each byte is a row of pixels
let data: &[u8] = &self.font.0[c as usize];
let data: &[u8] = &self.font.glyphs[c as usize];
if let Some(writer) = FRAMEBUFFER_WRITER.lock().as_mut() {
for (row, line) in data.iter().enumerate().take(16) {
-73
View File
@@ -1,73 +0,0 @@
use linked_list_allocator::LockedHeap;
use x86_64::{
VirtAddr,
structures::paging::{
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.
pub type FoundryAllocator = LockedHeap;
#[global_allocator]
/// This is now Rust's global allocator, so we can use stuff requiring heap allocations.
static ALLOCATOR: FoundryAllocator = FoundryAllocator::empty();
pub const HEAP_START: usize = 0x4444_4444_0000;
pub const HEAP_SIZE: usize = 1024 * 1024 * 1024;
/// Sets up the heap using the backing page frame allocator.
pub fn init_heap() -> Result<(), MapToError<Size4KiB>> {
// let mut frame_allocator = if let Some(f) = FRAME_ALLOCATOR.get() {
// f.lock()
// } else {
// return Err(MapToError::FrameAllocationFailed);
// };
// let mut mapper = if let Some(m) = OFFSET_PAGE_TABLE.get() {
// m.lock()
// } else {
// return Err(MapToError::FrameAllocationFailed);
// };
// 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 {
ALLOCATOR.lock().init(HEAP_START as *mut u8, HEAP_SIZE);
}
Ok(())
}
-1
View File
@@ -1 +0,0 @@
pub mod allocator;
-149
View File
@@ -1,149 +0,0 @@
// use lib_alloc::allocator::FoundryAllocator;
use limine::{memory_map::EntryType, response::MemoryMapResponse};
use spin::{Mutex, Once};
use x86_64::{
PhysAddr, VirtAddr,
registers::control::Cr3,
structures::paging::{
FrameAllocator, Mapper, OffsetPageTable, Page, PageTable, PhysFrame, Size4KiB,
page_table::FrameError,
},
};
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.
///
/// # Safety
///
/// The caller must ensure that the level 4 page table is not modified
/// simultaneously. The caller must also ensure that the physical memory offset
/// is correct, to ensure that the correct virtual address is constructed.
unsafe fn active_l4_table(physical_memory_offset: VirtAddr) -> &'static mut PageTable {
let (level_4_frame, _) = Cr3::read();
let phys_addr = level_4_frame.start_address();
let virt = phys_addr.as_u64() + physical_memory_offset.as_u64();
unsafe { &mut *(virt as *mut PageTable) }
}
/// Initializes the `OffsetPageTable` for the current CPU architecture.
///
/// # Safety
///
/// This function must be called only once and should be called before any
/// memory operations are performed that rely on virtual memory management.
/// The provided `physical_memory_offset` must be accurate to ensure correct
/// translation of physical addresses.
///
/// # Parameters
///
/// - `physical_memory_offset`: The offset to convert physical addresses to
/// virtual addresses in the higher-half direct map.
///
/// # Returns
///
/// Returns an `OffsetPageTable` that allows for manipulation of the page
/// tables for the current CPU architecture.
pub fn init_page_table(physical_memory_offset: VirtAddr) {
unsafe {
let l4_table = active_l4_table(physical_memory_offset);
let offset_table = OffsetPageTable::new(l4_table, physical_memory_offset);
OFFSET_PAGE_TABLE.call_once(|| Mutex::new(offset_table));
}
}
pub struct FoundryOSFrameAllocator {
memory_map: &'static MemoryMapResponse,
next: usize,
}
pub fn init_frame_allocator(memory_map: &'static MemoryMapResponse) {
unsafe {
FRAME_ALLOCATOR.call_once(|| Mutex::new(FoundryOSFrameAllocator::init(memory_map)));
}
}
impl FoundryOSFrameAllocator {
/// Creates a new `FoundryOSFrameAllocator` from a memory map.
///
/// This function takes a reference to a `MemoryMapResponse` and initializes a
/// `FoundryOSFrameAllocator` with it. The `next` field is set to 0, indicating that
/// the first frame to be allocated is the first frame in the memory map.
pub const unsafe fn init(memory_map: &'static MemoryMapResponse) -> Self {
Self {
memory_map,
next: 0,
}
}
pub fn count_usable_frames(&self) -> u32 {
self.usable_frames().count() as u32
}
/// An iterator over all usable frames in the memory map.
///
/// Yields one `PhysFrame` for each available 4KiB frame in the memory map.
///
/// This function is used to allocate frames for the pagemap.
fn usable_frames(&self) -> impl Iterator<Item = PhysFrame> + use<> {
let regions = self.memory_map.entries().iter();
let usable_regions = regions.filter(|region| region.entry_type == EntryType::USABLE);
let addr_ranges = usable_regions.map(|region| region.base..region.base + region.length);
let frame_addresses = addr_ranges.flat_map(|r| r.step_by(4096));
frame_addresses.map(|addr| PhysFrame::from_start_address(PhysAddr::new(addr)).unwrap())
}
}
unsafe impl FrameAllocator<Size4KiB> for FoundryOSFrameAllocator {
/// Allocates a frame from the list of usable frames.
///
/// This function returns the next available `PhysFrame` from the memory map,
/// if one exists. Once a frame is allocated, the internal counter is incremented
/// to point to the next frame for future allocations.
///
/// # Returns
///
/// - `Some(PhysFrame)`: If a usable frame is available.
/// - `None`: If there are no more usable frames to allocate.
fn allocate_frame(&mut self) -> Option<PhysFrame> {
let frame = self.usable_frames().nth(self.next);
self.next += 1;
frame
}
}
// pub unsafe fn translate_addr(addr: VirtAddr, physical_memory_offset: VirtAddr) -> Option<PhysAddr> {
// translate_addr_inner(addr, physical_memory_offset)
// }
// fn translate_addr_inner(addr: VirtAddr, physical_memory_offset: VirtAddr) -> Option<PhysAddr> {
// let (l4_table_frame, _) = Cr3::read();
// let table_indexes = [
// addr.p4_index(),
// addr.p3_index(),
// addr.p2_index(),
// addr.p1_index(),
// ];
// let mut frame = l4_table_frame;
// for &i in &table_indexes {
// let virt = physical_memory_offset + frame.start_address().as_u64();
// let table_ptr: *const PageTable = virt.as_ptr();
// let table = unsafe { &*table_ptr };
// let entry = &table[i];
// frame = match entry.frame() {
// Ok(frame) => frame,
// Err(FrameError::FrameNotPresent) => return None,
// Err(FrameError::HugeFrame) => panic!("huge frames are not supported!"),
// };
// }
// Some(frame.start_address() + u64::from(addr.page_offset()))
// }
+1 -4
View File
@@ -1,6 +1,3 @@
pub mod io;
pub mod kalloc;
pub mod async_io;
pub mod memory;
pub mod io;
pub mod pic;
+11 -17
View File
@@ -40,8 +40,8 @@ pub struct ChainedPics {
}
impl ChainedPics {
pub const unsafe fn new(offset1: u8, offset2: u8) -> Self {
ChainedPics {
pub const fn new(offset1: u8, offset2: u8) -> Self {
Self {
pics: [
Pic {
offset: offset1,
@@ -57,20 +57,14 @@ impl ChainedPics {
}
}
/// .
///
/// # Safety
///
/// .
pub const unsafe fn new_contiguous(primary_offset: u8) -> Self {
unsafe { Self::new(primary_offset, primary_offset + 8) }
pub const fn new_contiguous(primary_offset: u8) -> Self {
Self::new(primary_offset, primary_offset + 8)
}
/// Returns the initialize of this [`ChainedPics`].
///
/// # Safety
///
/// .
/// This should be safe if called just once on initialisation, however
/// sending data to IO ports tends to have side-effects.
pub unsafe fn initialize(&mut self) {
unsafe {
let mut wait_port: Port<u8> = Port::new(0x80);
@@ -112,12 +106,12 @@ impl ChainedPics {
}
/// Reads the interrupt masks of both PICs.
pub unsafe fn read_masks(&mut self) -> [u8; 2] {
pub fn read_masks(&mut self) -> [u8; 2] {
unsafe { [self.pics[0].read_mask(), self.pics[1].read_mask()] }
}
/// Writes the interrupt masks of both PICs.
pub unsafe fn write_masks(&mut self, mask1: u8, mask2: u8) {
pub fn write_masks(&mut self, mask1: u8, mask2: u8) {
unsafe {
self.pics[0].write_mask(mask1);
self.pics[1].write_mask(mask2);
@@ -125,8 +119,8 @@ impl ChainedPics {
}
/// Disables both PICs by masking all interrupts.
pub unsafe fn disable(&mut self) {
unsafe { self.write_masks(u8::MAX, u8::MAX) }
pub fn disable(&mut self) {
self.write_masks(u8::MAX, u8::MAX)
}
/// Do we handle this interrupt?
@@ -137,7 +131,7 @@ impl ChainedPics {
/// Figure out which (if any) PICs in our chain need to know about this
/// interrupt. This is tricky, because all interrupts from `pics[1]`
/// get chained through `pics[0]`.
pub unsafe fn notify_end_of_interrupt(&mut self, interrupt_id: u8) {
pub fn notify_end_of_interrupt(&mut self, interrupt_id: u8) {
if self.handles_interrupt(interrupt_id) {
if self.pics[1].handles_interrupt(interrupt_id) {
unsafe {
+9
View File
@@ -36,3 +36,12 @@ pub use crate::drivers::io::{
ascii::{_print, _print_log},
serial::_serial_write,
};
pub type FoundryAllocator = linked_list_allocator::LockedHeap;
#[global_allocator]
/// This is now Rust's global allocator, so we can use stuff requiring heap allocations.
static ALLOCATOR: FoundryAllocator = FoundryAllocator::empty();
pub const HEAP_START: usize = 0x4444_4444_0000;
pub const HEAP_SIZE: usize = 1024 * 1024 * 1024;
+20 -7
View File
@@ -1,13 +1,26 @@
// use libm::include_font;
use libm::include_font;
pub mod ibm_vga_8x16;
pub static FONT_SPLEEN_8X16: Font = Font(include_font!(
"./libk/resources/font/spleen-8x16.psf"
));
pub static FONT_SPLEEN_8X16: Font =
Font::new(include_font!("./libk/resources/font/spleen-8x16.psf"));
pub static FONT_CP850_8X16: Font = Font(include_font!(
"./libk/resources/font/cp850-8x16.psf"
));
pub static FONT_CP850_8X16: Font = Font::new(include_font!("./libk/resources/font/cp850-8x16.psf"));
pub struct Font(pub [[u8; 16]; 512]);
pub struct Font {
pub glyphs: [[u8; 16]; 512],
}
impl Default for Font {
fn default() -> Self {
Self::new([[0; 16]; 512])
}
}
impl Font {
pub const fn new(glyphs: [[u8; 16]; 512]) -> Self {
Self { glyphs }
}
}