Look for local APIC, try to map it
All checks were successful
Continuous Integration / Check (push) Successful in 41s
Continuous Integration / Clippy (push) Successful in 42s

This commit is contained in:
August 2026-06-30 20:33:36 +00:00
parent eeac6fea0d
commit 9777e9d3ea
Signed by: shibedrill
SSH Key Fingerprint: SHA256:M0m3JW1s38BgO2t0fG146Yxd9OJ2IOqkvCAsuRHQ6Pw
7 changed files with 129 additions and 24 deletions

View File

@ -9,8 +9,8 @@ use x86_64::structures::gdt;
use x86_64::structures::gdt::*;
use crate::log::*;
use crate::{log_info, log_trace};
use crate::memory::alloc::format;
use crate::{log_info, log_trace};
#[allow(dead_code)]
pub trait GdtEntryRead {

View File

@ -1,11 +1,19 @@
// Copyright (c) 2025 shibedrill
// SPDX-License-Identifier: MIT
use crate::LogLevel;
use crate::{LOGGER, format, log_trace};
use crate::{LOGGER, format, log_info, log_trace};
use crate::{LogLevel, log_error};
use lazy_static::lazy_static;
use x86_64::PhysAddr;
use x86_64::structures::idt::*;
pub fn get_lapic_addr() -> PhysAddr {
let apic_base = x86_64::registers::model_specific::ApicBase::read();
let addr: PhysAddr = apic_base.0.start_address();
log_info!("Found LAPIC at 0x{:x}, flags {:?}", addr, apic_base.1);
addr
}
lazy_static! {
pub static ref IDT: InterruptDescriptorTable = {
let mut idt = InterruptDescriptorTable::new();
@ -14,6 +22,7 @@ lazy_static! {
// approach will fall apart once multiarch support is re-added.
idt.double_fault.set_handler_fn(double_fault);
idt.page_fault.set_handler_fn(page_fault);
idt.general_protection_fault.set_handler_fn(gen_prot_fault);
idt
};
}
@ -37,7 +46,7 @@ extern "x86-interrupt" fn page_fault(info: InterruptStackFrame, errcode: PageFau
);
if errcode.contains(PageFaultErrorCode::USER_MODE) {
// Fault occurred in usermode. Non fatal.
todo!()
todo!("Page fault handler (usermode)")
} else {
// Fault occurred in kernel mode. This is possibly fatal.
// This is recoverable if we simply hit an unavailable page,
@ -46,9 +55,20 @@ extern "x86-interrupt" fn page_fault(info: InterruptStackFrame, errcode: PageFau
| errcode.contains(PageFaultErrorCode::MALFORMED_TABLE)
{
let info_formatted = format!("{info:#?}");
crate::interrupt::page_fault(addr.unwrap().as_u64() as usize, info_formatted)
crate::interrupt::page_fault_fatal(addr.unwrap().as_u64() as usize, info_formatted)
} else {
todo!()
log_error!("Page Fault, trying to recover...");
todo!("Page fault handler (kernel mode)")
}
}
}
#[allow(dead_code)]
extern "x86-interrupt" fn gen_prot_fault(info: InterruptStackFrame, _: u64) {
crate::interrupt::gen_prot_fault(format!(
"RIP 0x{:x}, CS {} ({:?})",
info.instruction_pointer,
info.code_segment.index(),
info.code_segment.rpl()
));
}

View File

@ -1,12 +1,17 @@
// Copyright (c) 2025 shibedrill
// SPDX-License-Identifier: MIT
use crate::memory::alloc::string::String;
use crate::log::*;
use crate::{format, log_error, memory::alloc::string::String};
pub fn double_fault(info: String) -> ! {
panic!("Double fault: {}", info);
}
pub fn page_fault(addr: usize, info: String) -> ! {
panic!("Page fault at 0x{:x}: {}", addr, info);
pub fn page_fault_fatal(addr: usize, info: String) -> ! {
panic!("Fatal page fault at 0x{:x}: {}", addr, info);
}
pub fn gen_prot_fault(info: String) {
log_error!("General protection fault: {}", info);
}

View File

@ -31,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::structures::paging::{PageTableFlags, page_table::PageTableEntry};
use crate::{
arch::{
@ -38,9 +39,10 @@ use crate::{
x86_64::{
cpuid::{CPUID, virt_supported},
gdt::dump_gdt,
interrupts::get_lapic_addr,
},
},
memory::paging::{self, active_root_table},
memory::paging::{self, active_root_table, map_page, phys_to_virt},
};
lazy_static! {
@ -147,7 +149,7 @@ unsafe extern "C" fn main() -> ! {
None => log_info!("Multiprocessing response not received"),
Some(resp) => {
log_info!("Multiprocessing response received");
log_trace!("{} CPUs found", resp.cpus().len());
log_info!("{} CPUs found", resp.cpus().len());
}
}
@ -183,11 +185,24 @@ unsafe extern "C" fn main() -> ! {
root_ptable_info.1,
addr_of!(*root_ptable_info.0) as usize
);
// This is an expensive function. Only run it if we're actually logging the results.
let loglevel = LOGGER.lock().level;
if loglevel > LogLevel::Trace {
paging::walk_tables();
}
}
log_info!("Long mode: {}", asm::long_mode());
dump_gdt();
let lapic = get_lapic_addr();
let mapping = {
let mut m = PageTableEntry::new();
m.set_addr(lapic, PageTableFlags::PRESENT);
m
};
let res = map_page(phys_to_virt(lapic), mapping);
log_info!("Map status: {:?}", res);
panic!("Finished boot, but cannot start init because processes not implemented!");
}

View File

@ -90,16 +90,10 @@ pub fn log_address() {
if let Some(resp) = ADDRESS_REQUEST.response() {
log_info!("Kernel physical start address: 0x{:x}", resp.physical_base);
log_info!("Kernel virtual start address: 0x{:x}", resp.virtual_base);
log_info!(
"Testing virt_to_phys(): 0x{:x}",
resp.virtual_base
);
log_info!("Testing virt_to_phys(): 0x{:x}", resp.virtual_base);
let hhdm_vaddr = VirtAddr::new(resp.virtual_base);
let hhdm_paddr = virt_to_phys(hhdm_vaddr);
log_info!(
"Result: 0x{:x}",
hhdm_paddr.unwrap()
);
log_info!("Result: 0x{:x}", hhdm_paddr.unwrap());
} else {
log_warning!("No kernel address response provided.");
}

View File

@ -1,3 +1,4 @@
use core::ops::DerefMut;
use core::ops::Index;
use core::ptr::addr_of;
@ -8,17 +9,83 @@ use x86_64::registers::control;
use x86_64::registers::control::Cr4Flags;
use x86_64::structures::paging::PageTable;
use x86_64::structures::paging::PageTableFlags;
use x86_64::structures::paging::page_table::PageTableEntry;
use crate::log::*;
use crate::memory::HHDM_RESPONSE;
use crate::memory::format;
#[allow(dead_code)]
pub fn map_page(_virt: VirtAddr, _phys: PhysAddr) {
pub fn map_page(virt: VirtAddr, mapping: PageTableEntry) -> Option<VirtAddr> {
// TODO:
// This function should create necessary page tables until the
// supplied virtual address maps to the supplied physical address.
todo!()
// Currently, it *will* give up if there are any missing tables on the path.
// It needs to be altered to support creating new intermediary tables.
// This will likely not be a necessary function in the future if VMM is left to processes.
log_info!(
"Mapping 0x{:x} to 0x{:x} with flags {:?}",
virt,
mapping.addr(),
mapping.flags()
);
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 > 0 {
log_trace!(
"Searching through a level {} table at 0x{:x}",
current_table.1,
addr_of!(*current_table.0) as usize
);
log_trace!("Index: {}", table_indices[current_table.1]);
let current_table_entry: &mut PageTableEntry =
&mut current_table.0.deref_mut()[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
log_error!("Could not map: Entry on path is Huge Page!");
return None;
} else if current_table.1 == 2 {
// Large page (2MiB), last 21 bits preserved
log_error!("Could not map: Entry on path is Large Page!");
return None;
}
} 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 {
current_table_entry.set_addr(mapping.addr(), mapping.flags());
return Some(virt);
}
} else {
log_error!(
"Could not map: Level {} entry on path is not present!",
current_table.1
);
return None;
}
}
// Current table is level 1
unreachable!()
}
#[allow(dead_code)]
@ -89,7 +156,11 @@ pub fn virt_to_phys(virt: VirtAddr) -> Option<PhysAddr> {
virt.as_u64().bits(48..=56) as usize, // Page Map Level 5 index
];
while current_table.1 > 0 {
log_trace!("Searching through a level {} table at 0x{:x}", current_table.1, addr_of!(*current_table.0) as usize);
log_trace!(
"Searching through a level {} table at 0x{:x}",
current_table.1,
addr_of!(*current_table.0) as usize
);
log_trace!("Index: {}", table_indices[current_table.1]);
let current_table_entry = current_table.0.index(table_indices[current_table.1]);
if current_table_entry

View File

@ -33,7 +33,7 @@ pub struct Process {
#[allow(dead_code)]
pub fn context_switch() -> ! {
todo!()
todo!("Context switch")
}
#[allow(dead_code)]