Vaddr to phaddr translation
All checks were successful
Continuous Integration / Check (push) Successful in 42s
Continuous Integration / Clippy (push) Successful in 41s

This commit is contained in:
August 2026-06-30 12:30:11 +00:00
parent c200938bec
commit be027961dc
Signed by: shibedrill
SSH Key Fingerprint: SHA256:M0m3JW1s38BgO2t0fG146Yxd9OJ2IOqkvCAsuRHQ6Pw
8 changed files with 121 additions and 88 deletions

26
Cargo.lock generated
View File

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

View File

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

View File

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

View File

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

View File

@ -70,6 +70,7 @@ impl Logger {
line: u32,
column: u32,
) {
if level <= self.level {
for dev in &self.devices {
let message = format!(
"{} {}:{},{}- {}",
@ -82,6 +83,7 @@ impl Logger {
dev(&message)
}
}
}
pub fn add_device(&mut self, device: Box<dyn Fn(&str) + Send + Sync>) {
self.devices.push(device);
}

View File

@ -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);
{
let root_ptable_info = unsafe { active_root_table() };
log_info!(
"Virtual address of current L4 table: 0x{:x}",
phys_to_virt(l4_start)
"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();

View File

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

View File

@ -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<PhysAddr> {
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!()
}
}
*/