Look for local APIC, try to map it
This commit is contained in:
parent
eeac6fea0d
commit
9777e9d3ea
@ -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 {
|
||||
|
||||
@ -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()
|
||||
));
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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
|
||||
);
|
||||
paging::walk_tables();
|
||||
// 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!");
|
||||
}
|
||||
|
||||
@ -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.");
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -33,7 +33,7 @@ pub struct Process {
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn context_switch() -> ! {
|
||||
todo!()
|
||||
todo!("Context switch")
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
|
||||
Loading…
Reference in New Issue
Block a user