diff --git a/Makefile.toml b/Makefile.toml index d3d4024..af724fc 100644 --- a/Makefile.toml +++ b/Makefile.toml @@ -126,7 +126,7 @@ script = ''' cp -f ${LIMINEDIR}/${LIMINEBIN} build/iso/EFI/BOOT cp -f ${ARTIFACTDIR}/kernel build/iso/boot/${ARCH}/kernel - cp -f ${ARTIFACTDIR}/userboot build/iso/boot/${ARCH}/userboot + cargo objcopy --release --bin userboot -- -O binary build/iso/boot/${ARCH}/userboot.bin xorriso -as mkisofs \ -b boot/limine/limine-bios-cd.bin \ @@ -147,6 +147,11 @@ dependencies = ["iso"] command = "${QEMUCOMMAND}" args = ["-drive", "file=build/gila.iso,format=raw,index=0,media=disk"] +[tasks.monitor_run] +dependencies = ["iso"] +command = "${QEMUCOMMAND}" +args = ["-display", "none", "-drive", "file=build/gila.iso,format=raw,index=0,media=disk", "-monitor", "stdio"] + [tasks.run] dependencies = ["iso"] command = "${QEMUCOMMAND}" diff --git a/configs/limine.conf b/configs/limine.conf index 9195447..dc7d9df 100644 --- a/configs/limine.conf +++ b/configs/limine.conf @@ -1,11 +1,32 @@ -timeout: 1 +timeout: 2 wallpaper: boot():/wallpaper.png wallpaper_style: centered +default_entry: Gila/Trace +serial: yes -/Gila +/+Gila +comment: The Gila microkernel. + + //Trace protocol: limine kernel_path: boot():/boot/${ARCH}/kernel cmdline: -loglevel=Trace -logdev=display,serial - module_path: boot():/boot/${ARCH}/userboot + module_path: boot():/boot/${ARCH}/userboot.bin kaslr: yes randomize_hhdm_base: yes + + //Info + protocol: limine + kernel_path: boot():/boot/${ARCH}/kernel + cmdline: -loglevel=Info -logdev=display,serial + module_path: boot():/boot/${ARCH}/userboot.bin + kaslr: yes + randomize_hhdm_base: yes + + //Warn + protocol: limine + kernel_path: boot():/boot/${ARCH}/kernel + cmdline: -loglevel=Warning -logdev=display,serial + module_path: boot():/boot/${ARCH}/userboot.bin + kaslr: yes + randomize_hhdm_base: yes \ No newline at end of file diff --git a/shell.nix b/shell.nix index 21fa481..cd2616e 100644 --- a/shell.nix +++ b/shell.nix @@ -12,6 +12,7 @@ pkgs.mkShell { rustup qemu cargo-make + cargo-binutils ]; buildInputs = with pkgs; [ diff --git a/src/kernel/arch/x86_64/gdt.rs b/src/kernel/arch/x86_64/gdt.rs index 413b509..e35d86d 100644 --- a/src/kernel/arch/x86_64/gdt.rs +++ b/src/kernel/arch/x86_64/gdt.rs @@ -5,6 +5,8 @@ use core::arch::asm; use core::ptr::addr_of_mut; use intbits::Bits; +use lazy_static::lazy_static; +use x86_64::PrivilegeLevel::{Ring0, Ring3}; use x86_64::structures::gdt; use x86_64::structures::gdt::*; @@ -12,6 +14,51 @@ use crate::log::*; use crate::memory::alloc::format; use crate::{log_info, log_trace}; +trait ModifyFlags { + fn set_flags(self, flags: DescriptorFlags) -> Self; +} + +// All this is necessary because there's no fucking method to change the +// flags in a segment descriptor. WHY?????? +impl ModifyFlags for Descriptor { + fn set_flags(self, flags: DescriptorFlags) -> Descriptor { + match self { + Descriptor::UserSegment(a) => { + Descriptor::UserSegment(a.with_bits(52..=55, flags.bits().bits(0..=3))) + } + Descriptor::SystemSegment(a, b) => { + log_trace!("0b{:b}", flags.bits().bits(0..=3)); + Descriptor::SystemSegment(a.with_bits(52..=55, flags.bits().bits(0..=3)), b) + } + } + } +} + +lazy_static! { + pub static ref TSS: x86_64::structures::tss::TaskStateSegment = + x86_64::structures::tss::TaskStateSegment::new(); + pub static ref GDT: x86_64::structures::gdt::GlobalDescriptorTable<64> = { + let mut g = GlobalDescriptorTable::empty(); + g.append(Descriptor::kernel_code_segment()); + g.append( + Descriptor::kernel_data_segment().set_flags(DescriptorFlags::from_bits_retain(0b1010)), + ); + g.append(Descriptor::user_code_segment()); + g.append( + Descriptor::user_data_segment().set_flags(DescriptorFlags::from_bits_retain(0b1010)), + ); + g.append( + Descriptor::tss_segment(&TSS).set_flags(DescriptorFlags::from_bits_retain(0b1010)), + ); + g + }; +} +pub const GDT_SELECTOR_KERNEL_CODE: SegmentSelector = SegmentSelector::new(1, Ring0); +pub const GDT_SELECTOR_KERNEL_DATA: SegmentSelector = SegmentSelector::new(2, Ring0); +pub const GDT_SELECTOR_USER_CODE: SegmentSelector = SegmentSelector::new(3, Ring3); +pub const GDT_SELECTOR_USER_DATA: SegmentSelector = SegmentSelector::new(4, Ring3); +pub const GDT_SELECTOR_TSS: SegmentSelector = SegmentSelector::new(5, Ring0); + #[allow(dead_code)] pub trait GdtEntryRead { fn base(&self) -> usize; diff --git a/src/kernel/interrupt/mod.rs b/src/kernel/interrupt/mod.rs index 7581a18..77ae801 100644 --- a/src/kernel/interrupt/mod.rs +++ b/src/kernel/interrupt/mod.rs @@ -1,7 +1,7 @@ // Copyright (c) 2025 shibedrill // SPDX-License-Identifier: MIT -use crate::log::*; +use crate::{SERIAL_3F8, log::*}; use crate::{format, log_error, memory::alloc::string::String}; pub fn double_fault(info: String) -> ! { @@ -13,5 +13,6 @@ pub fn page_fault_fatal(addr: usize, info: String) -> ! { } pub fn gen_prot_fault(info: String) { + SERIAL_3F8.lock().log_writeln("Ohhhhh shit double fault"); log_error!("General protection fault: {}", info); } diff --git a/src/kernel/main.rs b/src/kernel/main.rs index 4eca7b4..ae2f5d7 100644 --- a/src/kernel/main.rs +++ b/src/kernel/main.rs @@ -31,19 +31,22 @@ 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 x86_64::{ + PhysAddr, VirtAddr, + registers::rflags::RFlags, + structures::{ + gdt::SegmentSelector, + idt::InterruptStackFrameValue, + paging::{PageTableFlags, page_table::PageTableEntry}, + }, +}; use crate::{ arch::{ - asm, - x86_64::{ - cpuid::{CPUID, virt_supported}, - gdt::dump_gdt, - interrupts::get_lapic_addr, + asm, x86_64::{ + cpuid::{CPUID, virt_supported}, gdt::{GDT, GDT_SELECTOR_USER_CODE, GDT_SELECTOR_USER_DATA, dump_gdt}, interrupts::get_lapic_addr, }, - }, - boot::modules::MODULE_RESPONSE, - memory::paging::{self, active_root_table, map_page, phys_to_virt}, + }, boot::modules::MODULE_RESPONSE, memory::paging::{self, active_root_table, map_page, phys_to_virt}, }; lazy_static! { @@ -88,8 +91,19 @@ unsafe extern "C" fn main() -> ! { // Initialize all statics so the bootloader memory can be reclaimed memory::init_statics(); + log_info!( + "Long mode: {}", + if asm::long_mode() { + "enabled" + } else { + "disabled" + } + ); // Ensure IDT exists IDT.load(); + log_info!("IDT loaded!"); + GDT.load(); + log_info!("GDT loaded!"); log_info!( "Kernel cmdline: {}", @@ -188,12 +202,11 @@ unsafe extern "C" fn main() -> ! { ); // This is an expensive function. Only run it if we're actually logging the results. let loglevel = LOGGER.lock().level; - if loglevel > LogLevel::Trace { + if loglevel <= LogLevel::Trace { paging::walk_tables(); } } - log_info!("Long mode: {}", asm::long_mode()); dump_gdt(); let lapic = get_lapic_addr(); @@ -206,18 +219,29 @@ unsafe extern "C" fn main() -> ! { log_info!("Map status: {:?}", res); if let Some(modules_list) = *MODULE_RESPONSE - && modules_list.modules()[0].path().ends_with("/userboot") + && modules_list.modules()[0].path().ends_with("/userboot.bin") { - log_info!( - "Found userboot: {} {}", - modules_list.modules()[0].path(), - modules_list.modules()[0].cmdline() - ); - log_info!( - "Start address: 0x{:x}", - modules_list.modules()[0].data().as_ptr() as usize - ); + 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]); + log_info!("Start address: 0x{:x}", start_addr); + + // This does not work :/ + unsafe { + InterruptStackFrameValue::new( + start_addr, + GDT_SELECTOR_USER_CODE, + RFlags::empty(), + phys_to_virt(PhysAddr::new(0x1000)), + GDT_SELECTOR_USER_DATA, + ) + .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!"); } diff --git a/src/kernel/memory/mod.rs b/src/kernel/memory/mod.rs index d87c32a..1923f3b 100644 --- a/src/kernel/memory/mod.rs +++ b/src/kernel/memory/mod.rs @@ -5,7 +5,6 @@ const PAGE_SIZE: usize = 4096; use crate::boot::modules::MODULE_RESPONSE; use crate::boot::params::EXECUTABLE_FILE_RESPONSE; -use crate::memory::paging::virt_to_phys; use crate::{LOGGER, LogLevel, format}; use alloc::string::String; @@ -13,7 +12,6 @@ use lazy_static::lazy_static; use limine::request::{ExecutableAddressRequest, HhdmRepsonse, HhdmRequest}; use limine::request::{MemmapRequest, MemmapResponse}; use talc::*; -use x86_64::VirtAddr; pub extern crate alloc; @@ -90,10 +88,6 @@ 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); - let hhdm_vaddr = VirtAddr::new(resp.virtual_base); - let hhdm_paddr = virt_to_phys(hhdm_vaddr); - log_info!("Result: 0x{:x}", hhdm_paddr.unwrap()); } else { log_warning!("No kernel address response provided."); } diff --git a/src/kernel/memory/paging.rs b/src/kernel/memory/paging.rs index 0e723e2..bd017d2 100644 --- a/src/kernel/memory/paging.rs +++ b/src/kernel/memory/paging.rs @@ -144,6 +144,7 @@ pub fn phys_to_virt(phys: PhysAddr) -> VirtAddr { VirtAddr::new(phys.as_u64() + HHDM_RESPONSE.offset) } +#[allow(dead_code)] pub fn virt_to_phys(virt: VirtAddr) -> Option { let root_table = unsafe { active_root_table() }; let mut current_table = root_table; diff --git a/src/userboot/main.rs b/src/userboot/main.rs index b756363..13a66a9 100644 --- a/src/userboot/main.rs +++ b/src/userboot/main.rs @@ -5,6 +5,7 @@ use core::panic::PanicInfo; #[unsafe(no_mangle)] unsafe extern "C" fn main() -> ! { + unsafe { x86_64::instructions::port::Port::new(0x3f8).write(9u8) }; panic!() }