Compare commits
3 Commits
6882af0390
...
f9fd19b6d0
| Author | SHA1 | Date | |
|---|---|---|---|
| f9fd19b6d0 | |||
| 108ddb7cf9 | |||
| c9f1f6466d |
@ -15,6 +15,7 @@ compile_error!(
|
||||
pub mod x86_64;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub use x86_64::asm;
|
||||
pub use x86_64::startup;
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
pub mod aarch64;
|
||||
|
||||
@ -54,7 +54,6 @@ pub struct Selectors {
|
||||
pub sel_kernel_stack: SegmentSelector,
|
||||
pub sel_user_code: SegmentSelector,
|
||||
pub sel_user_stack: SegmentSelector,
|
||||
#[allow(unused)]
|
||||
pub sel_tss: SegmentSelector,
|
||||
pub gdt: GlobalDescriptorTable<48>,
|
||||
}
|
||||
@ -79,7 +78,7 @@ lazy_static! {
|
||||
// DO NOT REORDER
|
||||
let sel_tss = gdt.append(
|
||||
Descriptor::tss_segment(&TSS).set_flags(DescriptorFlags::from_bits_retain(0b1010))
|
||||
//.set_access(0b10001011), // This would set the TSS to Busy, but it causes a GPF.
|
||||
.set_access(0b10001011), // This would set the TSS to Busy, but it causes a GPF.
|
||||
);
|
||||
Selectors {
|
||||
sel_kernel_code: sel_k_cs,
|
||||
|
||||
@ -23,9 +23,9 @@ lazy_static! {
|
||||
// code. The x86_interrupt ABI is always breaking, and this
|
||||
// approach will fall apart once multiarch support is re-added.
|
||||
unsafe {
|
||||
idt.double_fault.set_handler_fn(double_fault).set_code_selector(SELECTORS.sel_kernel_code).set_privilege_level(x86_64::PrivilegeLevel::Ring0);
|
||||
idt.page_fault.set_handler_fn(page_fault).set_code_selector(SELECTORS.sel_kernel_code).set_privilege_level(x86_64::PrivilegeLevel::Ring0);
|
||||
idt.general_protection_fault.set_handler_fn(gen_prot_fault).set_code_selector(SELECTORS.sel_kernel_code).set_privilege_level(x86_64::PrivilegeLevel::Ring0);
|
||||
idt.double_fault.set_handler_fn(double_fault).set_code_selector(SELECTORS.sel_kernel_code);
|
||||
idt.page_fault.set_handler_fn(page_fault).set_code_selector(SELECTORS.sel_kernel_code);
|
||||
idt.general_protection_fault.set_handler_fn(gen_prot_fault).set_code_selector(SELECTORS.sel_kernel_code);
|
||||
}
|
||||
idt
|
||||
};
|
||||
@ -35,6 +35,7 @@ lazy_static! {
|
||||
#[allow(dead_code)]
|
||||
extern "x86-interrupt" fn double_fault(info: InterruptStackFrame, _: u64) -> ! {
|
||||
crate::interrupt::double_fault(format!("{info:#?}"));
|
||||
unsafe { info.iretq() }
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
@ -68,11 +69,13 @@ extern "x86-interrupt" fn page_fault(info: InterruptStackFrame, errcode: PageFau
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
extern "x86-interrupt" fn gen_prot_fault(info: InterruptStackFrame, _: u64) {
|
||||
extern "x86-interrupt" fn gen_prot_fault(info: InterruptStackFrame, error: u64) {
|
||||
crate::interrupt::gen_prot_fault(format!(
|
||||
"RIP 0x{:x}, CS {} ({:?})",
|
||||
"RIP 0x{:x}, CS {} ({:?}), error: 0x{:x}",
|
||||
info.instruction_pointer,
|
||||
info.code_segment.index(),
|
||||
info.code_segment.rpl()
|
||||
info.code_segment.rpl(),
|
||||
error
|
||||
));
|
||||
unsafe { info.iretq() }
|
||||
}
|
||||
|
||||
@ -8,3 +8,4 @@ pub mod gdt;
|
||||
pub mod intel_virt;
|
||||
pub mod interrupts;
|
||||
pub mod serial;
|
||||
pub mod startup;
|
||||
|
||||
46
src/kernel/arch/x86_64/startup.rs
Normal file
46
src/kernel/arch/x86_64/startup.rs
Normal file
@ -0,0 +1,46 @@
|
||||
use x86_64::{VirtAddr, registers::rflags::RFlags, structures::idt::InterruptStackFrameValue};
|
||||
|
||||
use crate::{
|
||||
arch::{
|
||||
asm::ltr,
|
||||
x86_64::{
|
||||
gdt::{SELECTORS, dump_gdt},
|
||||
interrupts::IDT,
|
||||
},
|
||||
},
|
||||
log::{LOGGER, LogLevel},
|
||||
log_info,
|
||||
memory::alloc::format,
|
||||
};
|
||||
|
||||
pub fn init() -> Result<(), ()> {
|
||||
// Ensure GDT exists
|
||||
SELECTORS.gdt.load();
|
||||
log_info!("GDT loaded!");
|
||||
// Load IDT
|
||||
IDT.load();
|
||||
log_info!("IDT loaded!");
|
||||
x86_64::registers::model_specific::Star::write(
|
||||
SELECTORS.sel_user_code,
|
||||
SELECTORS.sel_user_stack,
|
||||
SELECTORS.sel_kernel_code,
|
||||
SELECTORS.sel_kernel_stack,
|
||||
)
|
||||
.expect("Segment order in GDT is bad");
|
||||
dump_gdt();
|
||||
ltr(SELECTORS.sel_tss.index());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn jump_to_usermode(sp: VirtAddr, ip: VirtAddr) -> ! {
|
||||
unsafe {
|
||||
InterruptStackFrameValue::new(
|
||||
ip,
|
||||
SELECTORS.sel_user_code,
|
||||
RFlags::INTERRUPT_FLAG,
|
||||
sp,
|
||||
SELECTORS.sel_user_stack,
|
||||
)
|
||||
.iretq();
|
||||
}
|
||||
}
|
||||
@ -4,8 +4,8 @@
|
||||
use crate::log::*;
|
||||
use crate::{format, log_error, memory::alloc::string::String};
|
||||
|
||||
pub fn double_fault(info: String) -> ! {
|
||||
panic!("Double fault: {}", info);
|
||||
pub fn double_fault(info: String) {
|
||||
log_error!("Double fault: {}", info);
|
||||
}
|
||||
|
||||
pub fn page_fault_fatal(addr: usize, info: String) -> ! {
|
||||
|
||||
@ -18,7 +18,6 @@ mod util;
|
||||
|
||||
use core::ptr::addr_of;
|
||||
|
||||
use arch::x86_64::interrupts::IDT;
|
||||
use arch::x86_64::serial::SerialPort;
|
||||
use boot::{BASE_REVISION, params, *};
|
||||
use constants::*;
|
||||
@ -31,16 +30,10 @@ use limine::firmware::{
|
||||
FIRMWARE_TYPE_EFI32, FIRMWARE_TYPE_EFI64, FIRMWARE_TYPE_SBI, FIRMWARE_TYPE_X86BIOS,
|
||||
};
|
||||
use spin::mutex::Mutex;
|
||||
use x86_64::{VirtAddr, registers::rflags::RFlags, structures::idt::InterruptStackFrameValue};
|
||||
use x86_64::VirtAddr;
|
||||
|
||||
use crate::{
|
||||
arch::{
|
||||
asm::ltr,
|
||||
x86_64::{
|
||||
cpuid::{CPUID, virt_supported},
|
||||
gdt::SELECTORS,
|
||||
},
|
||||
},
|
||||
arch::x86_64::cpuid::{CPUID, virt_supported},
|
||||
boot::modules::MODULE_RESPONSE,
|
||||
memory::paging::active_root_table,
|
||||
};
|
||||
@ -79,31 +72,22 @@ unsafe extern "C" fn main() -> ! {
|
||||
LOGGER.lock().add_device(Box::new(serial_logger));
|
||||
}
|
||||
log_trace!("Configured kernel logging devices");
|
||||
let log_level = LOGGER.lock().level;
|
||||
log_info!("Log level: {:?}", log_level);
|
||||
}
|
||||
|
||||
// END OF CRITICAL AREA
|
||||
// Fallible code can be placed below this comment
|
||||
|
||||
let _ = arch::startup::init();
|
||||
// Initialize all statics so the bootloader memory can be reclaimed
|
||||
memory::init_statics();
|
||||
|
||||
// Ensure IDT exists
|
||||
SELECTORS.gdt.load();
|
||||
log_info!("GDT loaded!");
|
||||
IDT.load();
|
||||
log_info!("IDT loaded!");
|
||||
|
||||
log_info!(
|
||||
"Kernel cmdline: {}",
|
||||
"Boot cmdline: {} {}",
|
||||
EXECUTABLE_FILE_RESPONSE.executable_file().path(),
|
||||
EXECUTABLE_FILE_RESPONSE.executable_file().cmdline()
|
||||
);
|
||||
log_info!(
|
||||
"Kernel file path: {}",
|
||||
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 {
|
||||
@ -181,60 +165,23 @@ unsafe extern "C" fn main() -> ! {
|
||||
}
|
||||
log_info!("Virtualization provider: {:?}", virt_supported());
|
||||
|
||||
{
|
||||
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
|
||||
);
|
||||
// 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();
|
||||
//}
|
||||
}
|
||||
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
|
||||
);
|
||||
|
||||
if let Some(modules_list) = *MODULE_RESPONSE
|
||||
&& modules_list.modules()[0].path().ends_with("/userboot.bin")
|
||||
{
|
||||
let ub = modules_list.modules()[0];
|
||||
log_info!("Found userboot: {} {}", ub.path(), ub.cmdline());
|
||||
// TODO: remap userboot as user pages
|
||||
|
||||
//let start_addr = VirtAddr::from_ptr(ub.data() as *const [u8]);
|
||||
let start_addr = VirtAddr::from_ptr(usermode_fn as *const fn());
|
||||
log_info!("Start address: 0x{:x}", start_addr);
|
||||
|
||||
x86_64::registers::model_specific::Star::write(
|
||||
SELECTORS.sel_user_code,
|
||||
SELECTORS.sel_user_stack,
|
||||
SELECTORS.sel_kernel_code,
|
||||
SELECTORS.sel_kernel_stack,
|
||||
)
|
||||
.expect("fuck");
|
||||
ltr(SELECTORS.sel_tss.index());
|
||||
unsafe {
|
||||
InterruptStackFrameValue::new(
|
||||
VirtAddr::from_ptr(usermode_fn as *const fn()),
|
||||
SELECTORS.sel_user_code,
|
||||
RFlags::INTERRUPT_FLAG,
|
||||
VirtAddr::new(0xffffffff80000000),
|
||||
SELECTORS.sel_user_stack,
|
||||
)
|
||||
.iretq();
|
||||
}
|
||||
}
|
||||
|
||||
// TODO:
|
||||
// - Map APIC
|
||||
// - Create an interrupt stack frame, push it to stack, and iret to userboot
|
||||
|
||||
panic!("Finished boot, but cannot start init because processes not implemented!");
|
||||
}
|
||||
|
||||
fn usermode_fn() -> ! {
|
||||
log_info!("In usermode!");
|
||||
loop {
|
||||
arch::asm::nop();
|
||||
let start_addr = VirtAddr::from_ptr(ub.data() as *const [u8]);
|
||||
arch::startup::jump_to_usermode(VirtAddr::new(0xfffffff800000000), start_addr)
|
||||
} else {
|
||||
panic!("Userboot not found, cannot boot!");
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user