From d5f31ecce72567e5467e4dea80483aeeaaecc5a5 Mon Sep 17 00:00:00 2001 From: Arthur Beck Date: Sat, 5 Apr 2025 16:35:35 -0500 Subject: [PATCH] worked on stuff --- kernel/src/arch_boot_entry/x86.rs | 38 +++- kernel/src/kernel/arch/x86/gdt.rs | 23 +++ kernel/src/kernel/arch/x86/interrupts.rs | 177 +++++++++++++++--- kernel/src/kernel/arch/x86/mod.rs | 104 +++------- kernel/src/kernel/boot.rs | 4 +- kernel/src/kernel/indep_boot_entry.rs | 10 + kernel/src/kernel/mem.rs | 4 +- kernel/src/kernel/mod.rs | 1 + kernel/src/kernel/multiboot2.rs | 11 +- .../src/kernel/power_on_tests/memmapalloc.rs | 5 +- 10 files changed, 250 insertions(+), 127 deletions(-) diff --git a/kernel/src/arch_boot_entry/x86.rs b/kernel/src/arch_boot_entry/x86.rs index b68a5de..76c047b 100644 --- a/kernel/src/arch_boot_entry/x86.rs +++ b/kernel/src/arch_boot_entry/x86.rs @@ -15,7 +15,6 @@ use core::fmt::Debug; use core::panic::PanicInfo; use aphrodite::arch::egatext; -use aphrodite::arch::enable_a20; use aphrodite::arch::output::*; use aphrodite::boot::{BootInfo, MemoryMapping}; use aphrodite::display::COLOR_DEFAULT; @@ -27,11 +26,20 @@ use aphrodite::output::*; #[cfg(not(CONFIG_DISABLE_MULTIBOOT2_SUPPORT))] #[unsafe(link_section = ".bootheader")] #[unsafe(no_mangle)] -static MULTIBOOT2_HEADER: [u8; 24] = [ +static MULTIBOOT2_HEADER: [u8; 48] = [ 0xd6, 0x50, 0x52, 0xe8, // Magic number 0x00, 0x00, 0x00, 0x00, // Architecture 0x18, 0x00, 0x00, 0x00, // Size 0x12, 0xaf, 0xad, 0x17, // Checksum + + 0x0A, 0x00, // Relocatable tag + 0x00, 0x00, // Flags, + 0x18, 0x00, 0x00, 0x00, // Size of tag + 0x00, 0x00, 0x00, 0xB0, // Starting minimum location + 0xFF, 0xFF, 0xFF, 0xFF, // Ending maximum location: End of 32-bit address space + 0x00, 0x00, 0x00, 0x00, // Image alignment + 0x01, 0x00, 0x00, 0x00, // Loading preference: lowest possible + 0x00, 0x00, // End tag 0x00, 0x00, // Flags 0x08, 0x00, 0x00, 0x00, // Size @@ -85,6 +93,7 @@ extern "C" fn _start() -> ! { memory_map: None, bootloader_name: None, output: None, + load_base: None, }; unsafe { match MAGIC { @@ -135,7 +144,7 @@ extern "C" fn _start() -> ! { break; }, 4 => { - // Basic memory information + // Basic memory information, ignore if current_tag.tag_len != 16 { // Unexpected size, something is probably up panic!("size of basic memory information tag != 16"); @@ -177,7 +186,7 @@ extern "C" fn _start() -> ! { let memorysections: &'static mut [aphrodite::multiboot2::MemorySection] = &mut *core::ptr::from_raw_parts_mut((&mut (*rawmemorymap).sections[0]) as &mut MemorySection, (*rawmemorymap).sections.len()); // Above is a bit hard to understand, but what it does is transmute - // rawmemorymap's sections into a pointer to those sections. + // rawmemorymap's sections into a pointer to those sections for ele in &mut *memorysections { (*ele) = core::mem::transmute::< @@ -252,6 +261,20 @@ extern "C" fn _start() -> ! { }; BI.output = Some(&FBI) }, + 21 => { + // Image load base physical address + if current_tag.tag_len != 12 { + panic!("size of image load base physical address tag != 12"); + } + let ptr = (ptr + size_of::()) as *const u32; + + sdebugs("ptr: "); + sdebugbnp(&aphrodite::usize_as_u8_slice(ptr as usize)); + sdebugsnp(" value: "); + sdebugbnpln(&aphrodite::u32_as_u8_slice(*ptr)); + + BI.load_base = Some(*ptr); + }, _ => { // Unknown/unimplemented tag type, ignore swarnings("Unknown tag type "); @@ -292,10 +315,7 @@ extern "C" fn _start() -> ! { sdebugsln("Bootloader information has been successfully loaded"); sdebugunp(b'\n'); - if !enable_a20() { - panic!("failed to enable a20 gate"); - } - initalize_rtc(); + aphrodite::arch::initalize_rtc(); unsafe { if BI.output.clone().is_some() { @@ -318,7 +338,7 @@ extern "C" fn _start() -> ! { let ega: &dyn aphrodite::display::TextDisplay = &framebuffer_info; framebuffer_info.disable_cursor(); - ega.clear_screen(COLOR_DEFAULT); + ega.clear_screen(COLOR_DEFAULT).unwrap(); toutputsln("Testing EGA Text framebuffer...", ega).unwrap(); toutputsln("Testing EGA Text framebuffer...", ega).unwrap(); toutputsln("Testing EGA Text framebuffer...", ega).unwrap(); diff --git a/kernel/src/kernel/arch/x86/gdt.rs b/kernel/src/kernel/arch/x86/gdt.rs index e6f0df2..0475ef8 100644 --- a/kernel/src/kernel/arch/x86/gdt.rs +++ b/kernel/src/kernel/arch/x86/gdt.rs @@ -2,9 +2,25 @@ #![cfg(target_arch = "x86")] use core::alloc::Layout; +use core::arch::asm; use alloc::vec::Vec; +/// The GDTR. Used internally in [activate_gdt]. +#[repr(C, packed)] +struct Gdtr { + base: *const u8, + size: usize, +} + +pub unsafe fn activate_gdt(ptr: *const [u8]) { + let gdtr = Gdtr { + base: ptr as *const u8, + size: ptr.len(), + }; + unsafe { asm!("lgdt {}", in(reg) (&gdtr) as *const Gdtr as usize) } +} + /// Writes a series of GDT entries to an allocated section of memory and returns /// a pointer. pub unsafe fn write_gdt_entries( @@ -34,6 +50,13 @@ pub struct GDTEntry { pub flags: u8, } +pub const GDT_NULL_ENTRY: GDTEntry = GDTEntry { + limit: 0, + base: 0, + access: 0, + flags: 0, +}; + /// An error returned by [GDTEntry::write_to_addr] when the limit is greater /// than 0xFFFFF. const GDT_WRITE_ADDR_INVALID_LIMIT: i16 = -1; diff --git a/kernel/src/kernel/arch/x86/interrupts.rs b/kernel/src/kernel/arch/x86/interrupts.rs index 4bb962f..ed08071 100644 --- a/kernel/src/kernel/arch/x86/interrupts.rs +++ b/kernel/src/kernel/arch/x86/interrupts.rs @@ -2,7 +2,6 @@ #![cfg(target_arch = "x86")] #![allow(static_mut_refs)] -use core::alloc::{Allocator, Layout}; use core::arch::asm; use core::mem::MaybeUninit; @@ -70,29 +69,125 @@ struct Idtr { size: usize, } -unsafe impl Send for Idtr {} -unsafe impl Sync for Idtr {} - /// Loads an interrupt descriptor table. -fn load_idt(base: *const u8, size: usize) { - static mut IDTR: MaybeUninit = MaybeUninit::uninit(); - unsafe { - IDTR.write(Idtr { base, size }); - } - unsafe { asm!("lidt {}", in(reg) IDTR.as_ptr() as usize) } +unsafe fn load_idt(base: *const u8, size: usize) { + let idtr = Idtr { base, size }; + unsafe { asm!("lidt {}", in(reg) (&idtr) as *const Idtr as usize) } } -/// Activate an IDT. +#[derive(Clone, Copy)] +pub(super) struct IdtEntry { + pub offset_high: u16, + pub data: u16, + pub segment: u16, + pub offset_low: u16, + pub vector: u16, +} + +#[repr(C, packed)] +struct RawIdtEntry { + pub offset_high: u16, + pub data: u16, + pub segment: u16, + pub offset_low: u16, +} + +impl From for RawIdtEntry { + fn from(value: IdtEntry) -> Self { + RawIdtEntry { + offset_high: value.offset_high, + data: value.data, + segment: value.segment, + offset_low: value.offset_low, + } + } +} + +/// Activate an IDT. Requires that all handlers can properly handle the calling +/// convention and are in GDT segment 1. +/// +/// # Panics +/// Panics if the global allocator has not been setup #[aphrodite_proc_macros::kernel_item(ActivateIDT)] -fn activate_idt(idt: Idt, alloc: crate::mem::MemoryMapAlloc) { - let mem = alloc - .allocate(unsafe { Layout::from_size_align_unchecked(8 * idt.len, 1) }) - .unwrap() - .as_mut_ptr(); +fn activate_idt(idt: Idt) { + let mut entries = alloc::vec::Vec::new(); for i in 0..idt.len { - let _vector = idt.vectors[i]; - let _func = unsafe { idt.funcs[i].assume_init() } as usize as u64; - let _user_callable = idt.user_callable[i]; + if idt.using_raw[i] { + entries.push(idt.raw_entries[i]); + continue; + } + let vector = idt.vectors[i]; + let func = unsafe { idt.funcs[i].assume_init() } as usize as u32; + let user_callable = idt.user_callable[i]; + let exception = idt.exception[i]; + + let mut entry = IdtEntry { + offset_high: (func & 0xFFFF0000) as u16, + data: 0b1000000000000000, + segment: 1, + offset_low: (func & 0xFFFF) as u16, + vector, + }; + if user_callable { + entry.data |= 0b110000000000000; + } + if exception { + entry.data |= 0b111100000000; + } else { + entry.data |= 0b111000000000; + } + entries.push(entry); + } + entries.sort_by(|ele1: &IdtEntry, ele2: &IdtEntry| ele1.vector.cmp(&ele2.vector)); + let mut last_vector = 0u16; + let mut start = true; + + let mut entries2 = alloc::vec::Vec::new(); + + for entry in &entries { + if start { + let mut vector = entry.vector; + while vector > 0 { + entries2.push(IdtEntry { + offset_high: 0, + data: 0, + segment: 0, + offset_low: 0, + vector: 0, + }); + vector -= 1; + } + last_vector = entry.vector; + entries2.push(*entry); + start = false; + continue; + } + if entry.vector - last_vector > 0 { + let mut vector = entry.vector - last_vector; + while vector > 0 { + entries2.push(IdtEntry { + offset_high: 0, + data: 0, + segment: 0, + offset_low: 0, + vector: 0, + }); + vector -= 1; + } + } + last_vector = entry.vector; + entries2.push(*entry); + } + + let mut raw_entries: alloc::vec::Vec = alloc::vec::Vec::new(); + for entry in &entries2 { + raw_entries.push(RawIdtEntry::from(*entry)); + } + + let raw_entries = raw_entries.into_raw_parts(); + + unsafe { + load_idt(raw_entries.0 as *const u8, (idt.len * 8) - 1); } } @@ -102,6 +197,9 @@ pub struct Idt { vectors: [u16; 256], funcs: [MaybeUninit; 256], user_callable: [bool; 256], + exception: [bool; 256], + raw_entries: [IdtEntry; 256], + using_raw: [bool; 256], len: usize, } @@ -111,6 +209,9 @@ pub struct IdtBuilder { vectors: [u16; 256], funcs: [MaybeUninit; 256], user_callable: [bool; 256], + exception: [bool; 256], + raw_entries: [IdtEntry; 256], + using_raw: [bool; 256], idx: usize, } @@ -121,14 +222,38 @@ impl IdtBuilder { vectors: [0; 256], funcs: [MaybeUninit::uninit(); 256], user_callable: [false; 256], + exception: [false; 256], + raw_entries: [IdtEntry { + offset_high: 0, + data: 0, + segment: 0, + offset_low: 0, + vector: 0, + }; 256], + using_raw: [false; 256], idx: 0, } } /// Add a function to this IdtBuilder. - pub fn add_fn(&mut self, vector: u16, func: fn(), user_callable: bool) -> &mut Self { + pub fn add_fn( + &mut self, + vector: u16, + func: fn(), + user_callable: bool, + exception: bool, + ) -> &mut Self { self.vectors[self.idx] = vector; self.funcs[self.idx].write(func); self.user_callable[self.idx] = user_callable; + self.exception[self.idx] = exception; + self.using_raw[self.idx] = false; + self.idx += 1; + self + } + pub fn add_raw(&mut self, vector: u16, raw_entry: IdtEntry) -> &mut Self { + self.vectors[self.idx] = vector; + self.raw_entries[self.idx] = raw_entry; + self.using_raw[self.idx] = true; self.idx += 1; self } @@ -138,18 +263,14 @@ impl IdtBuilder { vectors: self.vectors, funcs: self.funcs, user_callable: self.user_callable, + raw_entries: self.raw_entries, + using_raw: self.using_raw, + exception: self.exception, len: self.idx, } } } impl Default for IdtBuilder { - fn default() -> Self { - IdtBuilder { - vectors: [0; 256], - funcs: [MaybeUninit::uninit(); 256], - user_callable: [false; 256], - idx: 0, - } - } + fn default() -> Self { Self::new() } } diff --git a/kernel/src/kernel/arch/x86/mod.rs b/kernel/src/kernel/arch/x86/mod.rs index 6426198..8e22688 100644 --- a/kernel/src/kernel/arch/x86/mod.rs +++ b/kernel/src/kernel/arch/x86/mod.rs @@ -13,7 +13,9 @@ pub mod ports; mod constants; +use alloc::vec; use constants::*; +use gdt::GDTEntry; use interrupts::{pop_irq, restore_irq}; use ports::{inb, outb}; @@ -77,83 +79,6 @@ pub fn get_keyboard_data() -> u8 { inb(0x60) } /// Sends data to the keyboard. pub fn send_keyboard_data(data: u8) { outb(0x60, data); } -/// Tries to enable the a20 gate via the keyboard controller method. -pub fn enable_a20_keyboard() { - let irq = pop_irq(); - - wait_for_keyboard_cmd(); - send_keyboard_cmd(0xAD); // disable keyboard - - wait_for_keyboard_cmd(); - send_keyboard_cmd(0xD0); // read from input - - wait_for_keyboard_cmd(); - wait_for_keyboard_data(); - let a = get_keyboard_data(); - - wait_for_keyboard_cmd(); - send_keyboard_cmd(0xD1); // write to output - - wait_for_keyboard_cmd(); - send_keyboard_data(a | 2); - - wait_for_keyboard_cmd(); - send_keyboard_cmd(0xAE); // enable keyboard - - restore_irq(irq); -} - -/// Tries to enable the a20 gate via fast a20. -/// Note that this may not work or do something unexpected. -pub fn enable_a20_fasta20() { - let mut a = inb(0x92); - if a & 0b10 > 0 { - return; - } - a |= 0b10; - a &= 0xFE; - outb(0x92, a); -} - -/// Tries to enable the a20 gate by reading from port 0xee. -pub fn enable_a20_ee_port() { inb(0xee); } - -/// Tries to enable the a20 gate by trying many different methods -/// and seeing what sticks. -pub fn enable_a20() -> bool { - if test_a20() { - return true; - } - - enable_a20_keyboard(); - let mut i = 0u32; - while (!test_a20()) && i < 10000 { - i += 1; - } - - if test_a20() { - return true; - } - - enable_a20_ee_port(); - let mut i = 0u32; - while (!test_a20()) && i < 10000 { - i += 1; - } - - if test_a20() { - return true; - } - - enable_a20_fasta20(); - let mut i = 0u32; - while (!test_a20()) && i < 10000 { - i += 1; - } - - return test_a20(); -} - static mut RTC_INITALIZED: bool = false; pub fn initalize_rtc() { @@ -167,10 +92,27 @@ pub fn initalize_rtc() { unsafe { RTC_INITALIZED = true } } -pub fn sleep(seconds: u32) { - initalize_rtc(); -} +pub fn sleep(seconds: u32) { initalize_rtc(); } pub fn alloc_available_boot() { - + let irq = pop_irq(); + let mut entries = vec![]; + entries.push(gdt::GDT_NULL_ENTRY); + entries.push(GDTEntry { + limit: 0, + base: 0, + access: 0b10011011, + flags: 0b1100, + }); // kernel code segment + entries.push(GDTEntry { + limit: 0, + base: 0, + access: 0b10010011, + flags: 0b1100, + }); // + + unsafe { + gdt::activate_gdt(gdt::write_gdt_entries(entries).unwrap()); + } + restore_irq(irq); } diff --git a/kernel/src/kernel/boot.rs b/kernel/src/kernel/boot.rs index 9140754..1328dd0 100644 --- a/kernel/src/kernel/boot.rs +++ b/kernel/src/kernel/boot.rs @@ -135,7 +135,6 @@ impl core::iter::Iterator for MemoryMap { #[derive(Clone)] pub struct BootInfo<'a> { /// The commandline of the kernel. - /// See for the format. pub cmdline: Option<&'static str>, /// The memory map provided by the bootloader. If None, the kernel will @@ -147,4 +146,7 @@ pub struct BootInfo<'a> { /// Provides a way to display text. pub output: Option<&'a dyn crate::display::TextDisplay>, + + /// The base address of the kernel + pub load_base: Option, } diff --git a/kernel/src/kernel/indep_boot_entry.rs b/kernel/src/kernel/indep_boot_entry.rs index bd826a8..4080ae5 100644 --- a/kernel/src/kernel/indep_boot_entry.rs +++ b/kernel/src/kernel/indep_boot_entry.rs @@ -3,6 +3,7 @@ #![allow(unexpected_cfgs)] #![allow(static_mut_refs)] +use crate::arch::output::*; use crate::display::{COLOR_DEFAULT, NoneTextDisplay}; use crate::output::*; @@ -37,5 +38,14 @@ fn indep_boot_entry( tinfosln("Successfully ran all configured power on tests", display).unwrap(); } + if cfg!(CONFIG_PREUSER_OUTPUT_DEBUG = "true") { + if let Some(load_base) = BI.load_base { + sdebugs("Image load base address is "); + sdebugbnpln(&crate::u32_as_u8_slice(load_base)); + } else { + sdebugsln("Image load base address was not provided"); + } + } + loop {} } diff --git a/kernel/src/kernel/mem.rs b/kernel/src/kernel/mem.rs index f849814..f840b72 100644 --- a/kernel/src/kernel/mem.rs +++ b/kernel/src/kernel/mem.rs @@ -69,9 +69,9 @@ static mut ALLOCATOR_INITALIZED: bool = false; pub fn get_allocator() -> Option<&'static MemoryMapAlloc<'static>> { if unsafe { ALLOCATOR_INITALIZED } { #[allow(static_mut_refs)] - return Some(unsafe { ALLOCATOR.assume_init_ref() }); + Some(unsafe { ALLOCATOR.assume_init_ref() }) } else { - return None; + None } } diff --git a/kernel/src/kernel/mod.rs b/kernel/src/kernel/mod.rs index 60d5c53..3c9c3e6 100644 --- a/kernel/src/kernel/mod.rs +++ b/kernel/src/kernel/mod.rs @@ -19,6 +19,7 @@ #![feature(ptr_as_uninit)] #![allow(internal_features)] #![feature(core_intrinsics)] +#![feature(vec_into_raw_parts)] extern crate alloc; diff --git a/kernel/src/kernel/multiboot2.rs b/kernel/src/kernel/multiboot2.rs index 2ebf32b..53a6cfe 100644 --- a/kernel/src/kernel/multiboot2.rs +++ b/kernel/src/kernel/multiboot2.rs @@ -197,7 +197,6 @@ pub struct Multiboot2BootInfo { // If you need it, good luck. /// We're provided with a C-style UTF-8(null-terminated UTF-8) string. This /// should contain the original pointer provided by the bootloader. - /// See for the format. pub cmdline: Option<&'static core::ffi::CStr>, // Due to the way modules work, it's not easily possible to make a struct that contains all the @@ -220,14 +219,16 @@ pub struct Multiboot2BootInfo { // it. /// Provides information on the framebuffer. pub framebuffer_info: Option, + /// Color info, stored separately from [FramebufferInfo] because rust pub color_info: Option, + // Even though SMBIOS is documented for Multiboot2, we're not using it and will instead search // for it ourselves. This is because right now I cannot figure out what format it provides // the SMBIOS table in. - // EFI memory map and image handle pointers are not included for portability. - - // "Image load base physical address" is not included as at the moment the kernel is not - // relocatable. + // EFI memory map and image handle pointers are not included for portability. Yeah, that's what + // I'm calling it. + /// Base address of the kernel + pub load_base: Option, } diff --git a/kernel/src/kernel/power_on_tests/memmapalloc.rs b/kernel/src/kernel/power_on_tests/memmapalloc.rs index 44e9dc4..be615a7 100644 --- a/kernel/src/kernel/power_on_tests/memmapalloc.rs +++ b/kernel/src/kernel/power_on_tests/memmapalloc.rs @@ -1,4 +1,7 @@ -#![cfg(all(not(CONFIG_POWERON_TESTS = "false"), not(CONFIG_POWERON_TEST_ALLOC = "false")))] +#![cfg(all( + not(CONFIG_POWERON_TESTS = "false"), + not(CONFIG_POWERON_TEST_ALLOC = "false") +))] use crate::display::TextDisplay; use crate::output::*;