diff --git a/src/kernel/arch/mod.rs b/src/kernel/arch/mod.rs index edd1e6f..291a1e1 100644 --- a/src/kernel/arch/mod.rs +++ b/src/kernel/arch/mod.rs @@ -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; diff --git a/src/kernel/arch/x86_64/mod.rs b/src/kernel/arch/x86_64/mod.rs index 540893e..a20cc17 100644 --- a/src/kernel/arch/x86_64/mod.rs +++ b/src/kernel/arch/x86_64/mod.rs @@ -8,3 +8,4 @@ pub mod gdt; pub mod intel_virt; pub mod interrupts; pub mod serial; +pub mod startup; diff --git a/src/kernel/arch/x86_64/startup.rs b/src/kernel/arch/x86_64/startup.rs new file mode 100644 index 0000000..c5ee808 --- /dev/null +++ b/src/kernel/arch/x86_64/startup.rs @@ -0,0 +1,42 @@ +use x86_64::{VirtAddr, registers::rflags::RFlags, structures::idt::InterruptStackFrameValue}; + +use crate::{ + arch::{ + asm::ltr, + x86_64::{gdt::SELECTORS, 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"); + 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(); + } +} diff --git a/src/kernel/main.rs b/src/kernel/main.rs index 59b2c53..cca2b6e 100644 --- a/src/kernel/main.rs +++ b/src/kernel/main.rs @@ -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,19 +165,12 @@ 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") @@ -201,40 +178,9 @@ unsafe extern "C" fn main() -> ! { let ub = modules_list.modules()[0]; log_info!("Found userboot: {} {}", ub.path(), ub.cmdline()); - //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!"); } }