diff --git a/Cargo.lock b/Cargo.lock index e63cd4b..32d9f8a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11,12 +11,6 @@ dependencies = [ "sptr", ] -[[package]] -name = "align-address" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cee078b3ed87e2621e0389729e2f032cc0408a4548768ced01678c9451c62237" - [[package]] name = "autocfg" version = "1.5.1" @@ -73,17 +67,6 @@ version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7ac824320a75a52197e8f2d787f6a38b6718bb6897a35142d749af3c0e8f4fe" -[[package]] -name = "free-list" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "358d33fcfc734d809ab9d4c45de31f1e73e3b973656deaff0db3cd5951782134" -dependencies = [ - "align-address", - "smallvec", - "x86_64", -] - [[package]] name = "intbits" version = "0.2.0" @@ -92,12 +75,11 @@ checksum = "5170c2c8ecda29c1bccb9d95ccbe107bc75fa084dc0c9c6087e719f9d46330e5" [[package]] name = "kernel" -version = "0.3.1" +version = "0.3.2" dependencies = [ "acid_alloc", "enumflags2", "flagset", - "free-list", "intbits", "lazy_static", "libgila", @@ -218,12 +200,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" -[[package]] -name = "smallvec" -version = "1.15.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90" - [[package]] name = "spin" version = "0.9.8" diff --git a/configs/limine.conf b/configs/limine.conf index e65a39a..2a5d8ca 100644 --- a/configs/limine.conf +++ b/configs/limine.conf @@ -1,10 +1,10 @@ -timeout: 2 +timeout: 1 wallpaper: boot():/bg.png wallpaper_style: centered /Gila protocol: limine kernel_path: boot():/boot/${ARCH}/gila - cmdline: -loglevel=Trace -logdev=display,serial -initramfs=/boot/${ARCH}/initramfs.tar.lzma + cmdline: -loglevel=Info -logdev=display,serial -initramfs=/boot/${ARCH}/initramfs.tar.lzma kaslr: yes randomize_hhdm_base: yes diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 90481f6..f77b0d8 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "kernel" -version = "0.3.1" +version = "0.3.2" edition = "2024" license = "MIT" @@ -8,7 +8,6 @@ license = "MIT" acid_alloc = { version = "0.1.0", features = ["alloc"] } enumflags2 = "0.7.12" flagset = "0.4.7" -free-list = { version = "0.3.1", features = ["x86_64"] } intbits = "0.2.0" lazy_static = { version = "1.5.0", default-features = false, features = ["spin_no_std"] } limine = "0.6.5" diff --git a/kernel/src/arch/x86_64/amd_virt.rs b/kernel/src/arch/x86_64/amd_virt.rs index 5c35e34..bf78639 100644 --- a/kernel/src/arch/x86_64/amd_virt.rs +++ b/kernel/src/arch/x86_64/amd_virt.rs @@ -26,6 +26,8 @@ pub fn amd_v_supported() -> bool { pub fn enable_svm() { let mut efer = x86_64::registers::model_specific::Efer::read().bits(); efer.set_bit(12, true); + // I'm not sure why this is here. But clearly there was a reason for it. + // So now I'm scared to touch it... assert!(efer.bit(12)); unsafe { x86_64::registers::model_specific::Efer::write(EferFlags::from_bits_retain(efer)) }; } diff --git a/kernel/src/log.rs b/kernel/src/log.rs index f7a8e6b..a7dcd28 100644 --- a/kernel/src/log.rs +++ b/kernel/src/log.rs @@ -70,16 +70,18 @@ impl Logger { line: u32, column: u32, ) { - for dev in &self.devices { - let message = format!( - "{} {}:{},{}- {}", - level.normalized_string(), - file, - line, - column, - message - ); - dev(&message) + if level <= self.level { + for dev in &self.devices { + let message = format!( + "{} {}:{},{}- {}", + level.normalized_string(), + file, + line, + column, + message + ); + dev(&message) + } } } pub fn add_device(&mut self, device: Box) { diff --git a/kernel/src/main.rs b/kernel/src/main.rs index be51253..5bc0b98 100644 --- a/kernel/src/main.rs +++ b/kernel/src/main.rs @@ -16,6 +16,8 @@ mod panic; mod process; mod util; +use core::ptr::addr_of; + use arch::x86_64::interrupts::IDT; use arch::x86_64::serial::SerialPort; use boot::{BASE_REVISION, params, *}; @@ -29,6 +31,7 @@ use limine::firmware::{ FIRMWARE_TYPE_EFI32, FIRMWARE_TYPE_EFI64, FIRMWARE_TYPE_SBI, FIRMWARE_TYPE_X86BIOS, }; use spin::mutex::Mutex; +use x86_64::VirtAddr; use crate::{ arch::{ @@ -38,7 +41,7 @@ use crate::{ gdt::dump_gdt, }, }, - memory::{paging, phys_to_virt}, + memory::paging::{self, active_root_table, virt_to_phys}, }; lazy_static! { @@ -95,6 +98,9 @@ unsafe extern "C" fn main() -> ! { EXECUTABLE_FILE_RESPONSE.executable_file().path() ); + let log_level = log::LOGGER.lock().level; + log_info!("Log level: {:?}", log_level); + // Branding for line in ASCII_LOGO { let mut locked = SERIAL_3F8.lock(); @@ -171,13 +177,24 @@ unsafe extern "C" fn main() -> ! { } log_info!("Virtualization provider: {:?}", virt_supported()); - let l4_start = x86_64::registers::control::Cr3::read().0.start_address(); - log_info!("Physical address of current L4 table: 0x{:x}", l4_start); - log_info!( - "Virtual address of current L4 table: 0x{:x}", - phys_to_virt(l4_start) - ); - paging::walk_tables(); + { + let root_ptable_info = unsafe { active_root_table() }; + log_info!( + "Root page table is Level {} at 0x{:x}", + root_ptable_info.1, + addr_of!(*root_ptable_info.0) as usize + ); + paging::walk_tables(); + log_info!( + "Testing virt_to_phys: 0x{:x}", + addr_of!(*root_ptable_info.0) as usize + ); + log_info!( + "Result: 0x{:x}", + virt_to_phys(VirtAddr::new(addr_of!(*root_ptable_info.0) as u64)).unwrap() + ); + } + log_info!("Long mode: {}", asm::long_mode()); dump_gdt(); diff --git a/kernel/src/memory/mod.rs b/kernel/src/memory/mod.rs index dbdaf30..1923f3b 100644 --- a/kernel/src/memory/mod.rs +++ b/kernel/src/memory/mod.rs @@ -12,16 +12,11 @@ use lazy_static::lazy_static; use limine::request::{ExecutableAddressRequest, HhdmRepsonse, HhdmRequest}; use limine::request::{MemmapRequest, MemmapResponse}; use talc::*; -use x86_64::{PhysAddr, VirtAddr}; pub extern crate alloc; pub mod paging; -pub fn phys_to_virt(phys: PhysAddr) -> VirtAddr { - VirtAddr::new(phys.as_u64() + HHDM_RESPONSE.offset) -} - lazy_static! { pub static ref MEMMAP_RESPONSE: &'static MemmapResponse = MEMMAP_REQUEST .response() diff --git a/kernel/src/memory/paging.rs b/kernel/src/memory/paging.rs index 96cf926..50d2de7 100644 --- a/kernel/src/memory/paging.rs +++ b/kernel/src/memory/paging.rs @@ -1,6 +1,10 @@ -use lazy_static::lazy_static; +use core::ops::Index; + +use intbits::Bits; use x86_64::PhysAddr; use x86_64::VirtAddr; +use x86_64::registers::control; +use x86_64::registers::control::Cr4Flags; use x86_64::structures::paging::PageTable; use x86_64::structures::paging::PageTableFlags; @@ -25,62 +29,100 @@ pub fn unmap_page(_virt: VirtAddr) -> Result<(), ()> { } #[allow(dead_code)] -pub unsafe fn active_level_4_table() -> &'static mut PageTable { +/// Safety: CR3 must never be modified while a PageTable returned from +/// this function is in scope. Otherwise, it could point to stale or even +/// invalid tables. +pub unsafe fn active_root_table() -> (&'static mut PageTable, usize) { use x86_64::registers::control::Cr3; - - let (level_4_table_frame, _) = Cr3::read(); - - let phys = level_4_table_frame.start_address(); - let virt: VirtAddr = VirtAddr::new(HHDM_RESPONSE.offset + phys.as_u64()); + let root_table_frame = Cr3::read().0; + let virt = phys_to_virt(root_table_frame.start_address()); let page_table_ptr: *mut PageTable = virt.as_mut_ptr(); - unsafe { &mut *page_table_ptr } -} - -lazy_static! { - pub static ref PML4: &'static mut PageTable = unsafe { active_level_4_table() }; + ( + unsafe { &mut *page_table_ptr }, + match control::Cr4::read().contains(Cr4Flags::L5_PAGING) { + true => 5, + false => 4, + }, + ) } pub fn walk_tables() { - iter_table(4, &PML4); + iter_table( + match control::Cr4::read().contains(Cr4Flags::L5_PAGING) { + true => 5, + false => 4, + }, + unsafe { active_root_table().0 }, + ); } -// Not used right now, helpful for debugging #[allow(dead_code)] pub fn iter_table(level: usize, table: &PageTable) { for (i, entry) in table.iter().enumerate() { if !entry.is_unused() & entry.flags().contains(PageTableFlags::PRESENT) { - log_info!("L{} Entry {}: {:?}", level, i, entry); + log_trace!("L{} Entry {}: {:?}", level, i, entry); if (level > 1) & !entry.flags().contains(PageTableFlags::HUGE_PAGE) { - let phys = entry.frame().unwrap().start_address(); - let virt = phys.as_u64() + HHDM_RESPONSE.offset; - let ptr = VirtAddr::new(virt).as_mut_ptr(); - let new_table: &PageTable = unsafe { &*ptr }; + let phys = entry.addr(); + let virt = phys_to_virt(phys).as_mut_ptr(); + let new_table: &PageTable = unsafe { &*virt }; iter_table(level - 1, new_table); } } } } -/* - let l4_table = unsafe { active_level_4_table() }; +pub fn phys_to_virt(phys: PhysAddr) -> VirtAddr { + VirtAddr::new(phys.as_u64() + HHDM_RESPONSE.offset) +} - for (i, entry) in l4_table.iter().enumerate() { - if !entry.is_unused() { - log_info!("L4 Entry {}: {:?}", i, entry); - - // get the physical address from the entry and convert it - let phys = entry.frame().unwrap().start_address(); - let virt = phys.as_u64() + HHDM_RESPONSE.offset(); - let ptr = VirtAddr::new(virt).as_mut_ptr(); - let l3_table: &PageTable = unsafe { &*ptr }; - - // print non-empty entries of the level 3 table - for (i, entry) in l3_table.iter().enumerate() { - if !entry.is_unused() { - log_info!(" L3 Entry {}: {:?}", i, entry); +pub fn virt_to_phys(virt: VirtAddr) -> Option { + let root_table = unsafe { active_root_table() }; + let mut current_table = root_table; + let table_indices = [ + virt.as_u64().bits(0..=11) as usize, // Page offset + virt.as_u64().bits(12..=20) as usize, // Page Table index + virt.as_u64().bits(21..=29) as usize, // Page Directory index + virt.as_u64().bits(30..=38) as usize, // Page Directory Pointer Table index + virt.as_u64().bits(39..=47) as usize, // Page Map Level 4 index + virt.as_u64().bits(48..=56) as usize, // Page Map Level 5 index + ]; + while current_table.1 > 1 { + let current_table_entry = current_table.0.index(table_indices[current_table.1]); + if current_table_entry + .flags() + .contains(PageTableFlags::PRESENT) + && !current_table_entry.is_unused() + { + if current_table_entry + .flags() + .contains(PageTableFlags::HUGE_PAGE) + { + if current_table.1 == 3 { + // Huge page (1GiB), last 30 bits preserved + return Some(PhysAddr::new( + current_table_entry.addr().as_u64() | virt.as_u64().bits(0..=29), + )); + } else if current_table.1 == 2 { + // Large page (2MiB), last 21 bits preserved + return Some(PhysAddr::new( + current_table_entry.addr().as_u64() | virt.as_u64().bits(0..=20), + )); } + } else if current_table.1 > 1 { + current_table = ( + unsafe { &mut *phys_to_virt(current_table_entry.addr()).as_mut_ptr() } + as &mut PageTable, + current_table.1 - 1, + ); + } else { + return Some(PhysAddr::new( + current_table_entry.addr().as_u64() | virt.as_u64().bits(0..=11), + )); } + } else { + return None; } } -*/ + unreachable!() +}