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 x86_64::structures::gdt::*;
use crate::log::*; use crate::log::*;
use crate::{log_info, log_trace};
use crate::memory::alloc::format; use crate::memory::alloc::format;
use crate::{log_info, log_trace};
#[allow(dead_code)] #[allow(dead_code)]
pub trait GdtEntryRead { pub trait GdtEntryRead {

View File

@ -1,11 +1,19 @@
// Copyright (c) 2025 shibedrill // Copyright (c) 2025 shibedrill
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
use crate::LogLevel; use crate::{LOGGER, format, log_info, log_trace};
use crate::{LOGGER, format, log_trace}; use crate::{LogLevel, log_error};
use lazy_static::lazy_static; use lazy_static::lazy_static;
use x86_64::PhysAddr;
use x86_64::structures::idt::*; 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! { lazy_static! {
pub static ref IDT: InterruptDescriptorTable = { pub static ref IDT: InterruptDescriptorTable = {
let mut idt = InterruptDescriptorTable::new(); let mut idt = InterruptDescriptorTable::new();
@ -14,6 +22,7 @@ lazy_static! {
// approach will fall apart once multiarch support is re-added. // approach will fall apart once multiarch support is re-added.
idt.double_fault.set_handler_fn(double_fault); idt.double_fault.set_handler_fn(double_fault);
idt.page_fault.set_handler_fn(page_fault); idt.page_fault.set_handler_fn(page_fault);
idt.general_protection_fault.set_handler_fn(gen_prot_fault);
idt idt
}; };
} }
@ -37,7 +46,7 @@ extern "x86-interrupt" fn page_fault(info: InterruptStackFrame, errcode: PageFau
); );
if errcode.contains(PageFaultErrorCode::USER_MODE) { if errcode.contains(PageFaultErrorCode::USER_MODE) {
// Fault occurred in usermode. Non fatal. // Fault occurred in usermode. Non fatal.
todo!() todo!("Page fault handler (usermode)")
} else { } else {
// Fault occurred in kernel mode. This is possibly fatal. // Fault occurred in kernel mode. This is possibly fatal.
// This is recoverable if we simply hit an unavailable page, // 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) | errcode.contains(PageFaultErrorCode::MALFORMED_TABLE)
{ {
let info_formatted = format!("{info:#?}"); 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 { } 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 // Copyright (c) 2025 shibedrill
// SPDX-License-Identifier: MIT // 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) -> ! { pub fn double_fault(info: String) -> ! {
panic!("Double fault: {}", info); panic!("Double fault: {}", info);
} }
pub fn page_fault(addr: usize, info: String) -> ! { pub fn page_fault_fatal(addr: usize, info: String) -> ! {
panic!("Page fault at 0x{:x}: {}", addr, info); 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, FIRMWARE_TYPE_EFI32, FIRMWARE_TYPE_EFI64, FIRMWARE_TYPE_SBI, FIRMWARE_TYPE_X86BIOS,
}; };
use spin::mutex::Mutex; use spin::mutex::Mutex;
use x86_64::structures::paging::{PageTableFlags, page_table::PageTableEntry};
use crate::{ use crate::{
arch::{ arch::{
@ -38,9 +39,10 @@ use crate::{
x86_64::{ x86_64::{
cpuid::{CPUID, virt_supported}, cpuid::{CPUID, virt_supported},
gdt::dump_gdt, 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! { lazy_static! {
@ -147,7 +149,7 @@ unsafe extern "C" fn main() -> ! {
None => log_info!("Multiprocessing response not received"), None => log_info!("Multiprocessing response not received"),
Some(resp) => { Some(resp) => {
log_info!("Multiprocessing response received"); 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, root_ptable_info.1,
addr_of!(*root_ptable_info.0) as usize 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(); paging::walk_tables();
} }
}
log_info!("Long mode: {}", asm::long_mode()); log_info!("Long mode: {}", asm::long_mode());
dump_gdt(); 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!"); 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() { if let Some(resp) = ADDRESS_REQUEST.response() {
log_info!("Kernel physical start address: 0x{:x}", resp.physical_base); log_info!("Kernel physical start address: 0x{:x}", resp.physical_base);
log_info!("Kernel virtual start address: 0x{:x}", resp.virtual_base); log_info!("Kernel virtual start address: 0x{:x}", resp.virtual_base);
log_info!( log_info!("Testing virt_to_phys(): 0x{:x}", resp.virtual_base);
"Testing virt_to_phys(): 0x{:x}",
resp.virtual_base
);
let hhdm_vaddr = VirtAddr::new(resp.virtual_base); let hhdm_vaddr = VirtAddr::new(resp.virtual_base);
let hhdm_paddr = virt_to_phys(hhdm_vaddr); let hhdm_paddr = virt_to_phys(hhdm_vaddr);
log_info!( log_info!("Result: 0x{:x}", hhdm_paddr.unwrap());
"Result: 0x{:x}",
hhdm_paddr.unwrap()
);
} else { } else {
log_warning!("No kernel address response provided."); log_warning!("No kernel address response provided.");
} }

View File

@ -1,3 +1,4 @@
use core::ops::DerefMut;
use core::ops::Index; use core::ops::Index;
use core::ptr::addr_of; use core::ptr::addr_of;
@ -8,17 +9,83 @@ use x86_64::registers::control;
use x86_64::registers::control::Cr4Flags; use x86_64::registers::control::Cr4Flags;
use x86_64::structures::paging::PageTable; use x86_64::structures::paging::PageTable;
use x86_64::structures::paging::PageTableFlags; use x86_64::structures::paging::PageTableFlags;
use x86_64::structures::paging::page_table::PageTableEntry;
use crate::log::*; use crate::log::*;
use crate::memory::HHDM_RESPONSE; use crate::memory::HHDM_RESPONSE;
use crate::memory::format; use crate::memory::format;
#[allow(dead_code)] #[allow(dead_code)]
pub fn map_page(_virt: VirtAddr, _phys: PhysAddr) { pub fn map_page(virt: VirtAddr, mapping: PageTableEntry) -> Option<VirtAddr> {
// TODO: // TODO:
// This function should create necessary page tables until the // This function should create necessary page tables until the
// supplied virtual address maps to the supplied physical address. // 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)] #[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 virt.as_u64().bits(48..=56) as usize, // Page Map Level 5 index
]; ];
while current_table.1 > 0 { 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]); log_trace!("Index: {}", table_indices[current_table.1]);
let current_table_entry = current_table.0.index(table_indices[current_table.1]); let current_table_entry = current_table.0.index(table_indices[current_table.1]);
if current_table_entry if current_table_entry

View File

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