From 842a2b23fe36b4d4111d983d9687ed8a3b451c98 Mon Sep 17 00:00:00 2001 From: Arthur Beck Date: Sat, 5 Apr 2025 17:32:51 -0500 Subject: [PATCH 1/3] Removed proc macros(for now) as kernel items are pretty much useless, added untested interrupts stuff --- kernel/Cargo.toml | 1 - kernel/aphrodite_proc_macros/Cargo.toml | 14 -- kernel/check | 4 +- kernel/config.aphro.example | 1 + kernel/src/kernel/arch/example_impl/mod.rs | 6 - kernel/src/kernel/arch/x86/gdt.rs | 4 + kernel/src/kernel/arch/x86/interrupt_impls.rs | 36 ++++ kernel/src/kernel/arch/x86/interrupts.rs | 15 +- kernel/src/kernel/arch/x86/memory.rs | 180 ------------------ kernel/src/kernel/arch/x86/mod.rs | 74 +++++-- kernel/src/kernel/arch/x86/paging.rs | 4 - kernel/src/kernel/cfg.rs | 2 +- kernel/src/kernel/indep_boot_entry.rs | 7 +- kernel/src/kernel/mem.rs | 6 +- kernel/src/kernel/mod.rs | 1 + kernel/src/proc_macros/mod.rs | 62 ------ 16 files changed, 108 insertions(+), 309 deletions(-) delete mode 100644 kernel/aphrodite_proc_macros/Cargo.toml create mode 100644 kernel/src/kernel/arch/x86/interrupt_impls.rs delete mode 100644 kernel/src/kernel/arch/x86/memory.rs delete mode 100644 kernel/src/proc_macros/mod.rs diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index d8f16cc..e3b8bba 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -5,7 +5,6 @@ edition = "2024" [dependencies] paste = "1.0.15" -aphrodite_proc_macros = { path = "./aphrodite_proc_macros"} [profile.release] opt-level = "z" diff --git a/kernel/aphrodite_proc_macros/Cargo.toml b/kernel/aphrodite_proc_macros/Cargo.toml deleted file mode 100644 index 219725f..0000000 --- a/kernel/aphrodite_proc_macros/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[package] -name = "aphrodite_proc_macros" -version = "0.1.0" -edition = "2024" - -[lib] -proc-macro = true -path = "../src/proc_macros/mod.rs" - -[dependencies] -quote = "1.0.38" -syn = { version = "2.0.98", features = ["full"] } -aphrodite_common = { path = "../aphrodite_common" } -proc-macro2 = "1.0.93" diff --git a/kernel/check b/kernel/check index 9c4d6ae..19276e6 100755 --- a/kernel/check +++ b/kernel/check @@ -19,7 +19,7 @@ real_check=false if [[ "$HAVE_GETOPT" = "true" ]]; then - LONGOPTS=real_check + LONGOPTS=real_check,real-check OPTIONS=c PARSED=$(getopt --options=$OPTIONS --longoptions=$LONGOPTS --name "$0" -- "$@") || ( @@ -30,7 +30,7 @@ while true; do case "$1" in - -c|--real_check) + -c|--real_check|--real-check) real_check=true shift ;; diff --git a/kernel/config.aphro.example b/kernel/config.aphro.example index 04ae3db..35eb551 100644 --- a/kernel/config.aphro.example +++ b/kernel/config.aphro.example @@ -14,6 +14,7 @@ VERSION=generate CONFIG_DISABLE_MULTIBOOT2_SUPPORT=false # Panic behavior. When debugging, generally halt on panic is more useful. +# Halt on panic takes priority over spin on panic if both are enabled. CONFIG_HALT_ON_PANIC=true CONFIG_SPIN_ON_PANIC=false diff --git a/kernel/src/kernel/arch/example_impl/mod.rs b/kernel/src/kernel/arch/example_impl/mod.rs index d8a1649..f71f044 100644 --- a/kernel/src/kernel/arch/example_impl/mod.rs +++ b/kernel/src/kernel/arch/example_impl/mod.rs @@ -23,28 +23,22 @@ pub mod interrupts { pub const USER_SYSCALL_VECTOR: u16 = 0xA0; /// Returns whether interrupts are enabled or not. - #[aphrodite_proc_macros::kernel_item(InterruptsCheck)] fn interrupts_enabled() -> bool { false } /// Enables interrupts. - #[aphrodite_proc_macros::kernel_item(InterruptsEnable)] fn enable_interrupts() {} /// Disables interrupts. - #[aphrodite_proc_macros::kernel_item(InterruptsDisable)] fn disable_interrupts() {} /// Disables interrupts and a value that can be used to restore them /// with [restore_irq]. - #[aphrodite_proc_macros::kernel_item(InterruptsPop)] fn pop_irq() -> u64 { 0 } /// Restores interrupts after a [pop_irq] call. - #[aphrodite_proc_macros::kernel_item(InterruptsRestore)] fn restore_irq(_irq: u64) {} /// Activates an IDT. - #[aphrodite_proc_macros::kernel_item(ActivateIDT)] fn activate_idt(_idt: Idt) {} /// An IDT. diff --git a/kernel/src/kernel/arch/x86/gdt.rs b/kernel/src/kernel/arch/x86/gdt.rs index 0475ef8..6c74ae8 100644 --- a/kernel/src/kernel/arch/x86/gdt.rs +++ b/kernel/src/kernel/arch/x86/gdt.rs @@ -9,10 +9,14 @@ use alloc::vec::Vec; /// The GDTR. Used internally in [activate_gdt]. #[repr(C, packed)] struct Gdtr { + // raw pointer to the GDT base: *const u8, + // size of the GDT in bytes size: usize, } +/// Activates the GDT using `lgdt`. Does NOT, I repeat, does NOT change the +/// segment registers! pub unsafe fn activate_gdt(ptr: *const [u8]) { let gdtr = Gdtr { base: ptr as *const u8, diff --git a/kernel/src/kernel/arch/x86/interrupt_impls.rs b/kernel/src/kernel/arch/x86/interrupt_impls.rs new file mode 100644 index 0000000..1ea1df4 --- /dev/null +++ b/kernel/src/kernel/arch/x86/interrupt_impls.rs @@ -0,0 +1,36 @@ +//! Implementations of interrupts. +#![cfg(target_arch = "x86")] +#![allow(undefined_naked_function_abi)] // special calling convention anyway + +use core::arch::naked_asm; + +macro_rules! int_wrapper { + ($func:block, $num:expr) => { + paste::paste! { + /// autogenerated interrupt wrapper + #[naked] + pub unsafe fn [< int $num >]() { + unsafe { + naked_asm!( + "pushad", + "cld", + "call {}", + "popad", + "iret", + sym [< int $num _rust >] + ) + } + } + + /// autogenerated interrupt body + unsafe extern "C" fn [< int $num _rust >]() $func + } + }; +} + +int_wrapper!( + { + super::output::sdebugsln("Interrupt handler #0 ran"); + }, + 0 +); diff --git a/kernel/src/kernel/arch/x86/interrupts.rs b/kernel/src/kernel/arch/x86/interrupts.rs index ed08071..63d3642 100644 --- a/kernel/src/kernel/arch/x86/interrupts.rs +++ b/kernel/src/kernel/arch/x86/interrupts.rs @@ -9,7 +9,6 @@ use core::mem::MaybeUninit; pub const USER_SYSCALL_VECTOR: u16 = 0xA0; /// Returns whether interrupts are enabled or not. -#[aphrodite_proc_macros::kernel_item(InterruptsCheck)] pub fn interrupts_enabled() -> bool { let flags: u32; unsafe { @@ -22,7 +21,6 @@ pub fn interrupts_enabled() -> bool { } /// Disables interrupts. -#[aphrodite_proc_macros::kernel_item(InterruptsDisable)] pub fn disable_interrupts() { unsafe { asm!("cli") } } /// PoppedInterrupts implements drop and restores the interrupts upon being @@ -37,7 +35,6 @@ impl Drop for PoppedInterrupts { } /// Disables interrupts and returns the value of them. -#[aphrodite_proc_macros::kernel_item(InterruptsPop)] pub fn pop_irq() -> PoppedInterrupts { let flags: u32; unsafe { @@ -51,7 +48,6 @@ pub fn pop_irq() -> PoppedInterrupts { } /// Restores interrupts after a [pop_irq] call. -#[aphrodite_proc_macros::kernel_item(InterruptsRestore)] pub fn restore_irq(flags: PoppedInterrupts) { let flags = flags.0; unsafe { @@ -76,7 +72,7 @@ unsafe fn load_idt(base: *const u8, size: usize) { } #[derive(Clone, Copy)] -pub(super) struct IdtEntry { +pub struct IdtEntry { pub offset_high: u16, pub data: u16, pub segment: u16, @@ -108,8 +104,7 @@ impl From for RawIdtEntry { /// /// # Panics /// Panics if the global allocator has not been setup -#[aphrodite_proc_macros::kernel_item(ActivateIDT)] -fn activate_idt(idt: Idt) { +pub unsafe fn activate_idt(idt: Idt) { let mut entries = alloc::vec::Vec::new(); for i in 0..idt.len { if idt.using_raw[i] { @@ -195,7 +190,7 @@ fn activate_idt(idt: Idt) { #[derive(Clone, Copy)] pub struct Idt { vectors: [u16; 256], - funcs: [MaybeUninit; 256], + funcs: [MaybeUninit; 256], user_callable: [bool; 256], exception: [bool; 256], raw_entries: [IdtEntry; 256], @@ -207,7 +202,7 @@ pub struct Idt { #[derive(Clone, Copy)] pub struct IdtBuilder { vectors: [u16; 256], - funcs: [MaybeUninit; 256], + funcs: [MaybeUninit; 256], user_callable: [bool; 256], exception: [bool; 256], raw_entries: [IdtEntry; 256], @@ -238,7 +233,7 @@ impl IdtBuilder { pub fn add_fn( &mut self, vector: u16, - func: fn(), + func: unsafe fn(), user_callable: bool, exception: bool, ) -> &mut Self { diff --git a/kernel/src/kernel/arch/x86/memory.rs b/kernel/src/kernel/arch/x86/memory.rs deleted file mode 100644 index 99a946d..0000000 --- a/kernel/src/kernel/arch/x86/memory.rs +++ /dev/null @@ -1,180 +0,0 @@ -//! Hardware-level memory sections. Unimplemented for certain hardware, x86 -//! implements with GDT. -#![cfg(target_arch = "x86")] - -use core::arch::asm; - -use alloc::vec; -use alloc::vec::Vec; - -use crate::memsections::*; - -use super::gdt::{GDTEntry, write_gdt_entries}; - -/// A list of memory sections. Create one with [MemorySectionBuilder]. -pub struct MemorySections { - sections: Vec, -} - -#[repr(packed)] -struct GDTR { - address: u32, - size: u16, -} - -unsafe impl crate::memsections::MemorySections for MemorySections { - unsafe fn write(self) -> Result<(), crate::Error<'static>> { - let mut entries: Vec = vec![]; - - for section in self.sections { - let mut section: MemorySection = section; - // rust-analyzer doesn't want to cooperate and recognize that section is already - // MemorySection, so I'm telling it here. - fn make_entry(section: &mut MemorySection, entries: &mut Vec) { - if section.length == 0 { - return; - } - let mut len = section.length as u32; - while len > 0xFFFFF { - len -= 0xFFFFF; - } - let mut access = 0b10000001u8; - match section.owner { - Owner::Kernelspace => { - access |= 0b0000000; - }, - Owner::Modulespace => { - access |= 0b0100000; - }, - Owner::Userspace => { - access |= 0b1100000; - }, - } - if let SectionType::TaskSection { busy } = section.section_type { - access |= 0b00000; - if busy { - access |= 0x9; - } else { - access |= 0xB; - } - } else { - access |= 0b10000; - if let SectionType::CodeSection { - can_powerful_sections_jump, - } = section.section_type - { - access |= 0b1000; - if can_powerful_sections_jump { - access |= 0b100; - } - if section.readable { - access |= 0b10; - } - } else if section.section_type == SectionType::DataSection { - access |= 0b0000; - if section.writable { - access |= 0b10; - } - } - } - - let flags = 0b1100u8; - - let entry = GDTEntry { - limit: len, - base: section.address as u32, - access, - flags, - }; - if section.length > 0xFFFFF { - section.length -= 0xFFFFF; - } - entries.push(entry); - } - while section.length > 0xFFFFF { - make_entry(&mut section, &mut entries); - } - make_entry(&mut section, &mut entries); - } - unsafe { - let _ = super::interrupts::pop_irq(); - - let segment_entries: Vec = entries.clone(); - - let ptr = write_gdt_entries(entries)?; - - let gdtr = GDTR { - address: ptr as *const u8 as usize as u32, - size: (ptr.len() - 1) as u16, - }; - - let addr = &gdtr as *const GDTR as *const () as usize as u32; - - asm!( - "lgdt eax", - in("eax") addr - ); - - let mut code_segment = 0u16; - let mut code_set = false; - let mut data_segment = 0u16; - let mut data_set = false; - - let mut i = 0; - for entry in segment_entries { - let entry: GDTEntry = entry; - i += 1; - if code_set && data_set { - break; - } - - if entry.access & 0b11000 == 0b11000 && !code_set { - code_segment = i - 1; - code_set = true; - } else if entry.access & 0b10000 == 0b10000 && !data_set { - data_segment = i - 1; - data_set = true; - } - } - - asm!( - "jmp bx:2 ; `#[deny(named_asm_labels)]` on by default; see - 2: ; ax is already loaded with the correct value from rustland - mov ds, ax - mov es, ax - mov fs, ax - mov gs, ax - mov ss, ax", - in("bx") code_segment, - in("ax") data_segment, - options(preserves_flags, nomem, nostack) - ); - } - - Ok(()) - } -} - -/// A memory section builder. -pub struct MemorySectionBuilder { - sections: Vec, -} - -impl MemorySectionBuilder { - /// Create a new MemorySectionBuilder. - pub fn new() -> Self { MemorySectionBuilder { sections: vec![] } } - - /// Adds a section to this MemorySectionBuilder. - pub fn add_section(&mut self, section: MemorySection) -> &mut Self { - self.sections.push(section); - - self - } - - /// Finishes this MemorySectionBuilder and returns a MemorySections. - pub fn finish(self) -> MemorySections { - MemorySections { - sections: self.sections, - } - } -} diff --git a/kernel/src/kernel/arch/x86/mod.rs b/kernel/src/kernel/arch/x86/mod.rs index 8e22688..59f2bd6 100644 --- a/kernel/src/kernel/arch/x86/mod.rs +++ b/kernel/src/kernel/arch/x86/mod.rs @@ -5,8 +5,8 @@ use core::arch::asm; pub mod egatext; mod gdt; +mod interrupt_impls; pub mod interrupts; -pub mod memory; pub mod output; pub mod paging; pub mod ports; @@ -92,27 +92,63 @@ pub fn initalize_rtc() { unsafe { RTC_INITALIZED = true } } -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, - }); // + { + // GDT + let mut entries = vec![]; + entries.push(gdt::GDT_NULL_ENTRY); + entries.push(GDTEntry { + limit: 0, + base: 0, + access: 0b10011011, + flags: 0b1100, + }); // kernel code segment, segment 0x08 + entries.push(GDTEntry { + limit: 0, + base: 0, + access: 0b10010011, + flags: 0b1100, + }); // kernel data segment, segment 0x10 + entries.push(GDTEntry { + limit: 0, + base: 0, + access: 0b11111011, + flags: 0b1100, + }); // user code segment, segment 0x18 + entries.push(GDTEntry { + limit: 0, + base: 0, + access: 0b11110011, + flags: 0b1100, + }); // user data segment, segment 0x20 - unsafe { - gdt::activate_gdt(gdt::write_gdt_entries(entries).unwrap()); + unsafe { + gdt::activate_gdt(gdt::write_gdt_entries(entries).unwrap()); + } + + unsafe { + asm!( + "jmp 0x08:2", + "2:", + "mov ax, 0x10", + "mov ds, ax", + "mov es, ax", + "mov fs, ax", + "mov gs, ax", + "mov ss, ax", + out("ax") _ + ); + } + } + { + // IDT + let idt = self::interrupts::IdtBuilder::new() + .add_fn(0, interrupt_impls::int0, false, true) + .finish(); + unsafe { + interrupts::activate_idt(idt); + } } restore_irq(irq); } diff --git a/kernel/src/kernel/arch/x86/paging.rs b/kernel/src/kernel/arch/x86/paging.rs index a7cc795..c09f1f4 100644 --- a/kernel/src/kernel/arch/x86/paging.rs +++ b/kernel/src/kernel/arch/x86/paging.rs @@ -3,8 +3,6 @@ use core::arch::asm; -use aphrodite_proc_macros::kernel_item; - /// One page directory entry. Use [PageDirectoryEntry::create_fourmb] or /// [PageDirectoryEntry::create_other] to make these. pub enum PageDirectoryEntry { @@ -120,11 +118,9 @@ static mut PAGE_DIRECTORY: PageDirectoryEntry = PageDirectoryEntry::create_other(0, false, 0, false, false, false, false, false, false, false); /// Initalize paging. -#[kernel_item(PagingInit)] pub fn initalize_paging() {} /// Disables paging by clearing bit 31 in the cr0 register. -#[kernel_item(PagingDeinit)] pub fn disable_paging() { unsafe { asm!( diff --git a/kernel/src/kernel/cfg.rs b/kernel/src/kernel/cfg.rs index 38ce8eb..c00de8f 100644 --- a/kernel/src/kernel/cfg.rs +++ b/kernel/src/kernel/cfg.rs @@ -1,6 +1,6 @@ //! Config-related stuff. -/// C +/// Get configurations as a certain type #[macro_export] macro_rules! cfg_int { ($cfg:literal, $type:ident) => { diff --git a/kernel/src/kernel/indep_boot_entry.rs b/kernel/src/kernel/indep_boot_entry.rs index 4080ae5..2c441af 100644 --- a/kernel/src/kernel/indep_boot_entry.rs +++ b/kernel/src/kernel/indep_boot_entry.rs @@ -7,11 +7,8 @@ use crate::arch::output::*; use crate::display::{COLOR_DEFAULT, NoneTextDisplay}; use crate::output::*; -use aphrodite_proc_macros::*; - /// The real entrypoint to the kernel. `internel/arch/*/entry.rs` files /// eventually call this. -#[kernel_item(IndepBootEntry)] fn indep_boot_entry( display: Option<&dyn crate::display::TextDisplay>, #[allow(non_snake_case)] BI: &crate::boot::BootInfo, @@ -24,11 +21,11 @@ fn indep_boot_entry( let display = display.unwrap_or(&NoneTextDisplay {}); - display.clear_screen(COLOR_DEFAULT); + display.clear_screen(COLOR_DEFAULT).unwrap(); sreset(); let mem_map = BI.memory_map.unwrap(); - crate::mem::MemMapAllocInit(mem_map).unwrap(); + crate::mem::memory_map_alloc_init(mem_map).unwrap(); crate::arch::alloc_available_boot(); diff --git a/kernel/src/kernel/mem.rs b/kernel/src/kernel/mem.rs index f840b72..1221560 100644 --- a/kernel/src/kernel/mem.rs +++ b/kernel/src/kernel/mem.rs @@ -9,8 +9,6 @@ use core::ptr::{NonNull, null_mut}; use crate::boot::{MemoryMap, MemoryType}; -use aphrodite_proc_macros::*; - #[derive(Clone, Copy)] struct Allocation { /// Whether this allocation is used. This is used so that the @@ -65,7 +63,6 @@ static mut ALLOCATOR: MaybeMemoryMapAlloc<'static> = MaybeMemoryMapAlloc::new(No static mut ALLOCATOR_MEMMAP: MaybeUninit = MaybeUninit::uninit(); static mut ALLOCATOR_INITALIZED: bool = false; -#[kernel_item(MemMapAlloc)] pub fn get_allocator() -> Option<&'static MemoryMapAlloc<'static>> { if unsafe { ALLOCATOR_INITALIZED } { #[allow(static_mut_refs)] @@ -90,8 +87,7 @@ pub unsafe fn get_allocator_unchecked() -> &'static MemoryMapAlloc<'static> { } } -#[kernel_item(MemMapAllocInit)] -fn memory_map_alloc_init(memmap: crate::boot::MemoryMap) -> Result<(), crate::Error<'static>> { +pub fn memory_map_alloc_init(memmap: crate::boot::MemoryMap) -> Result<(), crate::Error<'static>> { #[allow(static_mut_refs)] unsafe { ALLOCATOR_MEMMAP.write(memmap); diff --git a/kernel/src/kernel/mod.rs b/kernel/src/kernel/mod.rs index 3c9c3e6..d4db6a9 100644 --- a/kernel/src/kernel/mod.rs +++ b/kernel/src/kernel/mod.rs @@ -20,6 +20,7 @@ #![allow(internal_features)] #![feature(core_intrinsics)] #![feature(vec_into_raw_parts)] +#![feature(naked_functions)] extern crate alloc; diff --git a/kernel/src/proc_macros/mod.rs b/kernel/src/proc_macros/mod.rs deleted file mode 100644 index f5b7df4..0000000 --- a/kernel/src/proc_macros/mod.rs +++ /dev/null @@ -1,62 +0,0 @@ -use proc_macro::TokenStream; -use quote::{ToTokens, quote}; -use syn::parse::{Parse, ParseStream}; -use syn::{ItemFn, Signature, Token}; - -struct KernelItemNameInput { - item: syn::Ident, -} - -impl Parse for KernelItemNameInput { - fn parse(input: ParseStream) -> syn::Result { - let item: syn::Ident = input.parse()?; - Ok(KernelItemNameInput { item }) - } -} - -fn to_tokens(signature: Signature, tokens: &mut proc_macro2::TokenStream) { - let ts = tokens; - signature.constness.to_tokens(ts); - signature.asyncness.to_tokens(ts); - signature.unsafety.to_tokens(ts); - signature.abi.to_tokens(ts); - signature.fn_token.to_tokens(ts); - signature.generics.to_tokens(ts); - signature.paren_token.surround(ts, |tokens| { - signature.inputs.to_tokens(tokens); - if let Some(variadic) = &signature.variadic { - if !signature.inputs.empty_or_trailing() { - ::default().to_tokens(tokens); - } - variadic.to_tokens(tokens); - } - }); - signature.output.to_tokens(ts); - signature.generics.where_clause.to_tokens(ts); -} - -fn to_token_stream(signature: Signature) -> proc_macro2::TokenStream { - let mut tokens = proc_macro2::TokenStream::new(); - to_tokens(signature, &mut tokens); - tokens -} - -/// Implement a kernel item. -#[proc_macro_attribute] -pub fn kernel_item(attr: TokenStream, item: TokenStream) -> TokenStream { - let name: KernelItemNameInput = syn::parse_macro_input!(attr); - let item_name = name.item; - - let input_fn = syn::parse_macro_input!(item as ItemFn); - let fn_name = input_fn.clone().sig.ident; - let fn_sig = to_token_stream(input_fn.clone().sig); - - quote! { - /// The #item_name kernel item. - #[allow(non_upper_case_globals)] - pub const #item_name: #fn_sig = #fn_name; - - #input_fn - } - .into() -} From 59c9daf02f9eb1d7a80299d6ed924ddaac1fec76 Mon Sep 17 00:00:00 2001 From: Arthur Beck Date: Sat, 19 Apr 2025 09:07:34 -0500 Subject: [PATCH 2/3] I've been doing a lot of work on this and GDT is almost but not quite working --- kernel/aphrodite_common/Cargo.toml | 12 -- kernel/build | 2 +- kernel/build.rs | 24 +++- kernel/config.aphro.example | 3 + kernel/emulate | 2 +- kernel/grub_template/boot/grub/grub.cfg | 11 +- kernel/src/arch_boot_entry/x86.rs | 17 +-- kernel/src/common/mod.rs | 1 - kernel/src/kernel/arch/x86/gdt.rs | 120 +++++++++++++----- kernel/src/kernel/arch/x86/interrupts.rs | 16 ++- kernel/src/kernel/arch/x86/mod.rs | 81 ++++++------ kernel/src/kernel/arch/x86/x86.s | 24 ++++ kernel/src/kernel/boot.rs | 2 +- kernel/src/kernel/indep_boot_entry.rs | 9 +- kernel/src/kernel/mem.rs | 4 +- kernel/src/kernel/mod.rs | 2 + kernel/src/kernel/multiboot2.rs | 10 +- kernel/src/kernel/power_on_tests/display.rs | 19 +++ .../src/kernel/power_on_tests/memmapalloc.rs | 3 +- kernel/src/kernel/power_on_tests/mod.rs | 4 + kernel/src/kernel/util.rs | 39 ++++-- 21 files changed, 276 insertions(+), 129 deletions(-) delete mode 100644 kernel/aphrodite_common/Cargo.toml delete mode 100644 kernel/src/common/mod.rs create mode 100644 kernel/src/kernel/arch/x86/x86.s create mode 100644 kernel/src/kernel/power_on_tests/display.rs diff --git a/kernel/aphrodite_common/Cargo.toml b/kernel/aphrodite_common/Cargo.toml deleted file mode 100644 index ef75eb6..0000000 --- a/kernel/aphrodite_common/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -name = "aphrodite_common" -version = "0.1.0" -edition = "2024" - -[lib] -path = "../src/common/mod.rs" - -[dependencies] -strum = "0.27.0" -strum_macros = "0.27.0" -syn = "2.0.98" diff --git a/kernel/build b/kernel/build index 1afd7b7..5256646 100755 --- a/kernel/build +++ b/kernel/build @@ -122,7 +122,7 @@ echo "[INFO] Checking target with clippy" cargo clippy --target "$real_target" --release -Zbuild-std=core,alloc --bin entrypoint_$target echo "[INFO] Building target" - cargo build --target "$real_target" --release -Zbuild-std=core,alloc --bin entrypoint_$target 2>/dev/null + cargo build --target "$real_target" --release -Zbuild-std=core,alloc --bin entrypoint_$target cp "target/$(echo $target_json | sed 's/\.json//')/release/entrypoint_$target" kernel-$target if [[ "$CONFIG_BUILD_GRUB" = "true" ]]; then diff --git a/kernel/build.rs b/kernel/build.rs index 89cbf86..11c64ed 100644 --- a/kernel/build.rs +++ b/kernel/build.rs @@ -1,4 +1,6 @@ -fn main() { +fn main() -> Result<(), std::io::Error> { + println!("cargo:rerun-if-changed=src/kernel/arch/x86/change_code_segment.s"); + let env = std::env::vars(); // Begin checks @@ -49,6 +51,10 @@ fn main() { println!( r#"cargo:rustc-check-cfg=cfg(CONFIG_POWERON_TEST_ALLOC, values("true", "false", none()))"# ); + + println!( + r#"cargo:rustc-check-cfg=cfg(CONFIG_POWERON_TEST_DISPLAY, values("true", "false", none()))"# + ); // End checks // Configuration name used when a config is required but should always evaluate @@ -62,4 +68,20 @@ fn main() { println!("cargo:rerun-if-env-changed={}", var); println!("cargo:rustc-cfg={}=\"{}\"", var, val); } + + if !std::process::Command::new("as") + .arg("src/kernel/arch/x86/x86.s") + .arg("-march=i686") + .arg("--32") + .arg("-o") + .arg(format!("{}/x86_asm.o", std::env::var("OUT_DIR").unwrap())) + .spawn()? + .wait()?.success() { + return Err(std::io::Error::new(std::io::ErrorKind::InvalidInput, "Assembler failed to run")); + } else { + println!("cargo::rustc-link-arg={}/x86_asm.o", std::env::var("OUT_DIR").unwrap()); + } + + Ok(()) + } diff --git a/kernel/config.aphro.example b/kernel/config.aphro.example index 35eb551..7034cbd 100644 --- a/kernel/config.aphro.example +++ b/kernel/config.aphro.example @@ -45,4 +45,7 @@ CONFIG_POWERON_TESTS=true # Whether to run the allocator power on test. CONFIG_POWERON_TEST_ALLOC=true + +# Whether to run the display power on test. +CONFIG_POWERON_TEST_DISPLAY=true # End configs \ No newline at end of file diff --git a/kernel/emulate b/kernel/emulate index 276c918..97fb943 100755 --- a/kernel/emulate +++ b/kernel/emulate @@ -27,7 +27,7 @@ if [[ "$1" = "x86" ]]; then sed -i "s@%{BUILT_FILE}@aphrodite-$1.iso@g" bochsrc - bochs -q + bochs -q -debugger else if [[ "$TARGETS" =~ "$1" ]]; then echo "[ERROR] Cannot emulate specified architecture \"$1\"." diff --git a/kernel/grub_template/boot/grub/grub.cfg b/kernel/grub_template/boot/grub/grub.cfg index 464e45f..1d00ace 100644 --- a/kernel/grub_template/boot/grub/grub.cfg +++ b/kernel/grub_template/boot/grub/grub.cfg @@ -6,8 +6,11 @@ insmod gfxterm insmod efi_uga insmod efi_gop -menuentry "Aphrodite" --class aphrodite --class kernel --class os $menuentry_id_option 'aphrodite-basic-%{VERSION}' { - echo 'Loading Aphrodite aphrodite-%{VERSION} ...' - multiboot2 /boot/aphrodite.kernel - boot +menuentry "Aphrodite (default)" --class aphrodite --class kernel --class os $menuentry_id_option 'aphrodite-basic-%{VERSION}' { + echo 'Loading Aphrodite aphrodite-%{VERSION}...' + if multiboot2 /boot/aphrodite.kernel; then + boot + else + echo 'Error loading kernel; not attempting to boot' + fi } \ No newline at end of file diff --git a/kernel/src/arch_boot_entry/x86.rs b/kernel/src/arch_boot_entry/x86.rs index bbb5b12..9670909 100644 --- a/kernel/src/arch_boot_entry/x86.rs +++ b/kernel/src/arch_boot_entry/x86.rs @@ -17,11 +17,9 @@ use core::panic::PanicInfo; use aphrodite::arch::egatext; use aphrodite::arch::output::*; use aphrodite::boot::{BootInfo, MemoryMapping}; -use aphrodite::display::COLOR_DEFAULT; use aphrodite::multiboot2::{ FramebufferInfo, MemoryMap, MemorySection, RawMemoryMap, RootTag, Tag, }; -use aphrodite::output::*; #[cfg(not(CONFIG_DISABLE_MULTIBOOT2_SUPPORT))] #[unsafe(link_section = ".bootheader")] @@ -34,7 +32,7 @@ static MULTIBOOT2_HEADER: [u8; 48] = [ 0x0A, 0x00, // Relocatable tag 0x00, 0x00, // Flags, 0x18, 0x00, 0x00, 0x00, // Size of tag - 0x00, 0x00, 0x00, 0xB0, // Starting minimum location + 0x00, 0x00, 0x00, 0x00, // 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 @@ -70,7 +68,6 @@ static mut MAGIC: u32 = 0xFFFFFFFF; #[unsafe(link_section = ".start")] #[unsafe(no_mangle)] -#[aphrodite_proc_macros::kernel_item(ArchBootEntry)] extern "C" fn _start() -> ! { unsafe { // Copy values provided by the bootloader out @@ -313,7 +310,7 @@ extern "C" fn _start() -> ! { sdebugsln("Bootloader information has been successfully loaded"); sdebugunp(b'\n'); - aphrodite::arch::initalize_rtc(); + //aphrodite::arch::initalize_rtc(); unsafe { if BI.output.clone().is_some() { @@ -332,20 +329,14 @@ extern "C" fn _start() -> ! { sdebugs("Framebuffer bpp: "); sdebugbnpln(&aphrodite::u8_as_u8_slice(framebuffer_info.bpp)); - sdebugsln("Beginning test output to screen..."); let ega: &dyn aphrodite::display::TextDisplay = &framebuffer_info; - framebuffer_info.disable_cursor(); - 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(); - aphrodite::indep_boot_entry::IndepBootEntry(Some(ega), &BI); + aphrodite::indep_boot_entry::indep_boot_entry(Some(ega), &BI); } } - aphrodite::indep_boot_entry::IndepBootEntry(None, &BI); + aphrodite::indep_boot_entry::indep_boot_entry(None, &BI); } #[unsafe(link_section = ".panic")] diff --git a/kernel/src/common/mod.rs b/kernel/src/common/mod.rs deleted file mode 100644 index 8b13789..0000000 --- a/kernel/src/common/mod.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/kernel/src/kernel/arch/x86/gdt.rs b/kernel/src/kernel/arch/x86/gdt.rs index 6c74ae8..9965271 100644 --- a/kernel/src/kernel/arch/x86/gdt.rs +++ b/kernel/src/kernel/arch/x86/gdt.rs @@ -4,43 +4,88 @@ use core::alloc::Layout; use core::arch::asm; -use alloc::vec::Vec; - /// The GDTR. Used internally in [activate_gdt]. #[repr(C, packed)] +#[derive(Clone, Copy)] struct Gdtr { // raw pointer to the GDT - base: *const u8, + base: u32, // size of the GDT in bytes - size: usize, + size: u16, } +unsafe impl Sync for Gdtr {} + /// Activates the GDT using `lgdt`. Does NOT, I repeat, does NOT change the /// segment registers! 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) } + unsafe { + asm!( + "mov [3f], ax", // load limit + "mov [3f+2], ebx", // load base + "xor ax, ax", // clear ax + "lldt ax", // deactivate LDT + "lgdt [3f]", // load GDT + "jmp 2f", // jump past the data + "3:", // GDT data + "nop; nop; nop; nop; nop; nop", + "2:", // end + in("ax") ptr.len() as u16, + in("ebx") ptr as *const u8 as usize as u32, + options(readonly) + ) + // super::output::sdebugs("base: "); + // super::output::sdebugbnp(&crate::u32_as_u8_slice(GDTR.base)); + // super::output::sdebugsnp(" size: "); + // super::output::sdebugbnpln(&crate::u16_as_u8_slice(GDTR.size)); + } } /// Writes a series of GDT entries to an allocated section of memory and returns /// a pointer. pub unsafe fn write_gdt_entries( - entries: Vec, + entries: &[GDTEntry], ) -> Result<*const [u8], crate::Error<'static>> { let mut mem = - unsafe { alloc::alloc::alloc(Layout::from_size_align(8 * entries.len(), 1).unwrap()) }; - for ele in &entries { - let ele: &GDTEntry = ele; - unsafe { ele.write_to_addr(mem as *mut ())? } + unsafe { alloc::alloc::alloc(Layout::from_size_align(8 * entries.len(), 8).unwrap()) }; + for ele in entries { + let serialized = ele.serialize()?; + unsafe { + core::ptr::write(mem as *mut [u8; 8], serialized); + } mem = (mem as usize + 8) as *mut u8; } Ok(core::ptr::from_raw_parts(mem, 8 * entries.len())) } +const fn concat_arrays(a: [T; M], b: [T; N]) -> [T; M + N] { + let mut result = core::mem::MaybeUninit::uninit(); + let dest = result.as_mut_ptr() as *mut T; + unsafe { + core::ptr::copy_nonoverlapping(a.as_ptr(), dest, M); + core::ptr::copy_nonoverlapping(b.as_ptr(), dest.add(M), N); + core::mem::forget(a); + core::mem::forget(b); + result.assume_init() + } +} + +pub const fn serialize_gdt_entries( + entries: [GDTEntry; 5], +) -> [u8; 5 * 8] { + concat_arrays( + concat_arrays( + concat_arrays( + concat_arrays(entries[0].serialize_panicing(), entries[1].serialize_panicing()), + entries[2].serialize_panicing(), + ), + entries[3].serialize_panicing(), + ), + entries[4].serialize_panicing(), + ) +} + /// A GDT entry. #[derive(Clone, Copy)] pub struct GDTEntry { @@ -63,35 +108,52 @@ pub const GDT_NULL_ENTRY: GDTEntry = GDTEntry { /// An error returned by [GDTEntry::write_to_addr] when the limit is greater /// than 0xFFFFF. -const GDT_WRITE_ADDR_INVALID_LIMIT: i16 = -1; +pub const GDT_WRITE_ADDR_INVALID_LIMIT: i16 = -1; impl GDTEntry { - const unsafe fn write_to_addr(self, ptr: *mut ()) -> Result<(), crate::Error<'static>> { + const fn serialize(self) -> Result<[u8; 8], crate::Error<'static>> { if self.limit > 0xFFFFF { return Err(crate::Error::new( "Invalid GDT entry limit(more than 0xFFFFF)", GDT_WRITE_ADDR_INVALID_LIMIT, )); } - let mut serialized = (0u64).to_ne_bytes(); + let mut out = [0u8; 8]; - serialized[0] = (self.limit & 0xFF) as u8; - serialized[1] = ((self.limit >> 8) & 0xFF) as u8; - serialized[6] = ((self.limit >> 16) & 0x0F) as u8; + out[0] = (self.limit & 0xFF) as u8; + out[1] = ((self.limit >> 8) & 0xFF) as u8; + out[6] = ((self.limit >> 16) & 0x0F) as u8; - serialized[2] = (self.base & 0xFF) as u8; - serialized[3] = ((self.base >> 8) & 0xFF) as u8; - serialized[4] = ((self.base >> 16) & 0xFF) as u8; - serialized[7] = ((self.base >> 24) & 0xFF) as u8; + out[2] = (self.base & 0xFF) as u8; + out[3] = ((self.base >> 8) & 0xFF) as u8; + out[4] = ((self.base >> 16) & 0xFF) as u8; + out[7] = ((self.base >> 24) & 0xFF) as u8; - serialized[5] = self.access; + out[5] = self.access; - serialized[6] |= self.flags << 4; + out[6] |= self.flags << 4; - unsafe { - core::ptr::write(ptr as *mut [u8; 8], serialized); + Ok(out) + } + const fn serialize_panicing(self) -> [u8; 8] { + if self.limit > 0xFFFFF { + panic!("Invalid GDT entry limit(more than 0xFFFFF)"); } + let mut out = [0u8; 8]; - Ok(()) + out[0] = (self.limit & 0xFF) as u8; + out[1] = ((self.limit >> 8) & 0xFF) as u8; + out[6] = ((self.limit >> 16) & 0x0F) as u8; + + out[2] = (self.base & 0xFF) as u8; + out[3] = ((self.base >> 8) & 0xFF) as u8; + out[4] = ((self.base >> 16) & 0xFF) as u8; + out[7] = ((self.base >> 24) & 0xFF) as u8; + + out[5] = self.access; + + out[6] |= self.flags << 4; + + out } } diff --git a/kernel/src/kernel/arch/x86/interrupts.rs b/kernel/src/kernel/arch/x86/interrupts.rs index 63d3642..27106c0 100644 --- a/kernel/src/kernel/arch/x86/interrupts.rs +++ b/kernel/src/kernel/arch/x86/interrupts.rs @@ -23,6 +23,9 @@ pub fn interrupts_enabled() -> bool { /// Disables interrupts. pub fn disable_interrupts() { unsafe { asm!("cli") } } +/// Enables interrupts. +pub fn enable_interrupts() { unsafe { asm!("sti") } } + /// PoppedInterrupts implements drop and restores the interrupts upon being /// dropped. This is useful in functions where you need interrupts disabled /// during it but also want to use functions like [Result::unwrap] or @@ -67,8 +70,17 @@ struct Idtr { /// Loads an interrupt descriptor table. 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) } + static mut IDTR: Idtr = Idtr { + base: 0 as *const u8, + size: 0, + }; + unsafe { + IDTR = Idtr { + base, + size, + }; + } + unsafe { asm!("lidt {}", sym IDTR) } } #[derive(Clone, Copy)] diff --git a/kernel/src/kernel/arch/x86/mod.rs b/kernel/src/kernel/arch/x86/mod.rs index 59f2bd6..5a3ee96 100644 --- a/kernel/src/kernel/arch/x86/mod.rs +++ b/kernel/src/kernel/arch/x86/mod.rs @@ -13,11 +13,11 @@ pub mod ports; mod constants; -use alloc::vec; use constants::*; use gdt::GDTEntry; -use interrupts::{pop_irq, restore_irq}; +use interrupts::{disable_interrupts, enable_interrupts, pop_irq, restore_irq}; use ports::{inb, outb}; +use output::*; /// Returns the most specific architecture available. pub const fn get_arch() -> super::Architecture { super::Architecture::X86 } @@ -93,62 +93,65 @@ pub fn initalize_rtc() { } pub fn alloc_available_boot() { - let irq = pop_irq(); + disable_interrupts(); { // GDT - let mut entries = vec![]; - entries.push(gdt::GDT_NULL_ENTRY); - entries.push(GDTEntry { - limit: 0, - base: 0, - access: 0b10011011, - flags: 0b1100, - }); // kernel code segment, segment 0x08 - entries.push(GDTEntry { - limit: 0, - base: 0, - access: 0b10010011, - flags: 0b1100, - }); // kernel data segment, segment 0x10 - entries.push(GDTEntry { - limit: 0, - base: 0, - access: 0b11111011, - flags: 0b1100, - }); // user code segment, segment 0x18 - entries.push(GDTEntry { - limit: 0, - base: 0, - access: 0b11110011, - flags: 0b1100, - }); // user data segment, segment 0x20 + sdebugsln("Setting up GDT"); + + let entries = gdt::serialize_gdt_entries([ + gdt::GDT_NULL_ENTRY, + GDTEntry { // kernel code segment, segment 0x08 + limit: 0xFFFFF, + base: 0, + access: 0x9A, + flags: 0xC, + }, + GDTEntry { // kernel data segment, segment 0x10 + limit: 0xFFFFF, + base: 0, + access: 0x92, + flags: 0xC, + }, + GDTEntry { // user code segment, segment 0x18 + limit: 0xFFFFF, + base: 0, + access: 0xFA, + flags: 0xC, + }, + GDTEntry { // user data segment, segment 0x20 + limit: 0xFFFFF, + base: 0, + access: 0xF2, + flags: 0xC, + } + ]); + + sdebugsln("GDT prepared"); unsafe { - gdt::activate_gdt(gdt::write_gdt_entries(entries).unwrap()); + gdt::activate_gdt(&entries); } + sdebugsln("GDT successfully activated; resetting segment registers"); + unsafe { asm!( - "jmp 0x08:2", - "2:", - "mov ax, 0x10", - "mov ds, ax", - "mov es, ax", - "mov fs, ax", - "mov gs, ax", - "mov ss, ax", + "call reloadSegments", // I hate rust's inline assembly out("ax") _ ); } + sdebugsln("Segment registers reset"); } { // IDT + sdebugsln("Setting up IDT"); let idt = self::interrupts::IdtBuilder::new() .add_fn(0, interrupt_impls::int0, false, true) .finish(); unsafe { interrupts::activate_idt(idt); } + enable_interrupts(); + sdebugsln("IDT successfully loaded"); } - restore_irq(irq); } diff --git a/kernel/src/kernel/arch/x86/x86.s b/kernel/src/kernel/arch/x86/x86.s new file mode 100644 index 0000000..e2ada5d --- /dev/null +++ b/kernel/src/kernel/arch/x86/x86.s @@ -0,0 +1,24 @@ +.intel_syntax noprefix + +.global reloadSegments + +reloadSegments: + mov ax, 0x10 + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + mov ss, ax + xchg bx, bx + call get_retaddr_ppro + add eax, 7 + pushd 0x8 + push eax + retf + +.reload_cs: + ret + +get_retaddr_ppro: + mov eax, [esp] + ret \ No newline at end of file diff --git a/kernel/src/kernel/boot.rs b/kernel/src/kernel/boot.rs index 1328dd0..d2f33cd 100644 --- a/kernel/src/kernel/boot.rs +++ b/kernel/src/kernel/boot.rs @@ -127,7 +127,7 @@ impl core::iter::Iterator for MemoryMap { self.reset_iter(); return None; } - Some(self.sections[self.idx - 1].into()) + Some(self.sections[self.idx - 1]) } } diff --git a/kernel/src/kernel/indep_boot_entry.rs b/kernel/src/kernel/indep_boot_entry.rs index 2c441af..f1ea444 100644 --- a/kernel/src/kernel/indep_boot_entry.rs +++ b/kernel/src/kernel/indep_boot_entry.rs @@ -4,12 +4,12 @@ #![allow(static_mut_refs)] use crate::arch::output::*; -use crate::display::{COLOR_DEFAULT, NoneTextDisplay}; +use crate::display::NoneTextDisplay; use crate::output::*; /// The real entrypoint to the kernel. `internel/arch/*/entry.rs` files /// eventually call this. -fn indep_boot_entry( +pub fn indep_boot_entry( display: Option<&dyn crate::display::TextDisplay>, #[allow(non_snake_case)] BI: &crate::boot::BootInfo, ) -> ! { @@ -19,10 +19,9 @@ fn indep_boot_entry( "Somehow the kernel successfully booted into IndepBootEntry with a dummy architecture" ); - let display = display.unwrap_or(&NoneTextDisplay {}); + sdebugsln("IndepBootEntry running"); - display.clear_screen(COLOR_DEFAULT).unwrap(); - sreset(); + let display = display.unwrap_or(&NoneTextDisplay {}); let mem_map = BI.memory_map.unwrap(); crate::mem::memory_map_alloc_init(mem_map).unwrap(); diff --git a/kernel/src/kernel/mem.rs b/kernel/src/kernel/mem.rs index 1221560..3fdcf8a 100644 --- a/kernel/src/kernel/mem.rs +++ b/kernel/src/kernel/mem.rs @@ -199,7 +199,7 @@ impl<'a> MemoryMapAlloc<'a> { } } } - if out.allocations == core::ptr::null_mut() { + if out.allocations.is_null() { return Err(crate::Error::new( "no free memory with space for 32 allocations", ALLOCATIONS_NOT_ENOUGH_SPACE, @@ -341,7 +341,7 @@ impl<'a> MemoryMapAlloc<'a> { /// Finds a free block of memory that can fit the requested size and /// alignment fn find_free_block(&self, size: u64, align: usize) -> Option { - for mapping in self.memory_map.clone() { + for mapping in *self.memory_map { if mapping.len < size { continue; } diff --git a/kernel/src/kernel/mod.rs b/kernel/src/kernel/mod.rs index d4db6a9..8645790 100644 --- a/kernel/src/kernel/mod.rs +++ b/kernel/src/kernel/mod.rs @@ -7,6 +7,7 @@ #![deny(rustdoc::invalid_html_tags)] #![deny(rustdoc::invalid_rust_codeblocks)] #![deny(unsafe_op_in_unsafe_fn)] +#![allow(incomplete_features)] #![feature(ptr_metadata)] #![feature(const_trait_impl)] #![feature(f128)] @@ -21,6 +22,7 @@ #![feature(core_intrinsics)] #![feature(vec_into_raw_parts)] #![feature(naked_functions)] +#![feature(generic_const_exprs)] extern crate alloc; diff --git a/kernel/src/kernel/multiboot2.rs b/kernel/src/kernel/multiboot2.rs index 53a6cfe..eeee735 100644 --- a/kernel/src/kernel/multiboot2.rs +++ b/kernel/src/kernel/multiboot2.rs @@ -54,18 +54,18 @@ pub struct MemorySection { reserved: u32, } -impl Into for MemorySection { - fn into(self) -> crate::boot::MemoryMapping { +impl From for crate::boot::MemoryMapping { + fn from(val: MemorySection) -> Self { MemoryMapping { - mem_type: match self.mem_type { + mem_type: match val.mem_type { 1 => crate::boot::MemoryType::Free, 2 => crate::boot::MemoryType::HardwareReserved, 3 => crate::boot::MemoryType::HardwareSpecific(3, false), 5 => crate::boot::MemoryType::Faulty, _ => crate::boot::MemoryType::Reserved, }, - start: self.base_addr, - len: self.length, + start: val.base_addr, + len: val.length, } } } diff --git a/kernel/src/kernel/power_on_tests/display.rs b/kernel/src/kernel/power_on_tests/display.rs new file mode 100644 index 0000000..b19efbe --- /dev/null +++ b/kernel/src/kernel/power_on_tests/display.rs @@ -0,0 +1,19 @@ +#![cfg(all( + not(CONFIG_POWERON_TESTS = "false"), + not(CONFIG_POWERON_TEST_DISPLAY = "false") +))] + +use crate::display::{TextDisplay, COLOR_BLACK, COLOR_DEFAULT}; +use crate::output::{toutputsln, sreset}; + +pub fn run(display: &dyn TextDisplay) { + display.clear_screen(COLOR_DEFAULT).unwrap(); + sreset(); + toutputsln("Testing display...", display).unwrap(); + toutputsln("Testing display...", display).unwrap(); + toutputsln("Testing display...", display).unwrap(); + display.clear_screen(COLOR_BLACK).unwrap(); + sreset(); + display.clear_screen(COLOR_DEFAULT).unwrap(); + sreset(); +} \ No newline at end of file diff --git a/kernel/src/kernel/power_on_tests/memmapalloc.rs b/kernel/src/kernel/power_on_tests/memmapalloc.rs index be615a7..6209d26 100644 --- a/kernel/src/kernel/power_on_tests/memmapalloc.rs +++ b/kernel/src/kernel/power_on_tests/memmapalloc.rs @@ -27,7 +27,7 @@ pub fn run(display: &dyn TextDisplay) { tdebugsnpln(" byte(s) of memory...", display).unwrap(); let allocation = allocator.allocate(Layout::from_size_align(size, 1).unwrap()); - if let Err(_) = allocation { + if allocation.is_err() { terrors("Failed to allocate: ", display).unwrap(); unsafe { crate::mem::LAST_MEMMAP_ERR.unwrap_err().display_np(display) } panic!("Allocator test failure"); @@ -51,6 +51,5 @@ pub fn run(display: &dyn TextDisplay) { tdebugsln("Successfully deallocated!", display).unwrap(); } } - tdebugsln("", display).unwrap(); } } diff --git a/kernel/src/kernel/power_on_tests/mod.rs b/kernel/src/kernel/power_on_tests/mod.rs index 6f52a96..9b3bdcc 100644 --- a/kernel/src/kernel/power_on_tests/mod.rs +++ b/kernel/src/kernel/power_on_tests/mod.rs @@ -3,8 +3,12 @@ use crate::display::TextDisplay; mod memmapalloc; +mod display; pub fn run(display: &dyn TextDisplay) { #[cfg(not(CONFIG_POWERON_TEST_ALLOC = "false"))] memmapalloc::run(display); + + #[cfg(not(CONFIG_POWERON_TEST_DISPLAY = "false"))] + display::run(display); } diff --git a/kernel/src/kernel/util.rs b/kernel/src/kernel/util.rs index caac0fc..22680d4 100644 --- a/kernel/src/kernel/util.rs +++ b/kernel/src/kernel/util.rs @@ -16,7 +16,7 @@ pub const fn i16_as_u8_slice(mut value: i16) -> [u8; 6] { let digit = value % 10; let char = b'0' + digit as u8; buf[i] = char; - value = value / 10; + value /= 10; i -= 1; } buf @@ -33,7 +33,24 @@ pub const fn u32_as_u8_slice(mut value: u32) -> [u8; 10] { let digit = value % 10; let char = b'0' + digit as u8; buf[i] = char; - value = value / 10; + value /= 10; + i -= 1; + } + buf +} + +/// Converts an u16 to an [u8; 5]. +pub const fn u16_as_u8_slice(mut value: u16) -> [u8; 5] { + let mut buf = [0u8; 5]; + let mut i = 4; + if value == 0 { + buf[0] = b'0'; + } + while value > 0 { + let digit = value % 10; + let char = b'0' + digit as u8; + buf[i] = char; + value /= 10; i -= 1; } buf @@ -48,15 +65,15 @@ pub const fn u8_as_u8_slice(mut value: u8) -> [u8; 3] { } while value > 0 { let digit = value % 10; - let char = b'0' + digit as u8; + let char = b'0' + digit; buf[i] = char; - value = value / 10; + value /= 10; i -= 1; } buf } -/// Converts an usize(32 or 64 bit) to an [u8; 10]. +/// Converts an usize(32 or 64 bit) to an [u8; 20]. pub const fn usize_as_u8_slice(mut value: usize) -> [u8; 20] { let mut buf = [0u8; 20]; let mut i = 19; @@ -67,7 +84,7 @@ pub const fn usize_as_u8_slice(mut value: usize) -> [u8; 20] { let digit = value % 10; let char = b'0' + digit as u8; buf[i] = char; - value = value / 10; + value /= 10; i -= 1; } buf @@ -84,7 +101,7 @@ pub const fn u64_as_u8_slice(mut value: u64) -> [u8; 20] { let digit = value % 10; let char = b'0' + digit as u8; buf[i] = char; - value = value / 10; + value /= 10; i -= 1; } buf @@ -99,7 +116,7 @@ pub fn str_as_i16(mut value: &[u8]) -> i16 { } for byte in value { let byte = *byte; - if byte < b'0' || byte > b'9' { + if !byte.is_ascii_digit() { continue; } out *= 10; @@ -121,7 +138,7 @@ pub fn str_as_u32(value: &[u8]) -> u32 { let mut out = 0u32; for byte in value { let byte = *byte; - if byte < b'0' || byte > b'9' { + if !byte.is_ascii_digit() { continue; } out *= 10; @@ -143,7 +160,7 @@ pub fn str_as_u128(value: &[u8]) -> u128 { let mut out = 0u128; for byte in value { let byte = *byte; - if byte < b'0' || byte > b'9' { + if !byte.is_ascii_digit() { continue; } out *= 10; @@ -165,7 +182,7 @@ pub fn str_as_u64(value: &[u8]) -> u64 { let mut out = 0u64; for byte in value { let byte = *byte; - if byte < b'0' || byte > b'9' { + if !byte.is_ascii_digit() { continue; } out *= 10; From 11f8ac03c643a026084c10f70f8d0a17d3249172 Mon Sep 17 00:00:00 2001 From: Arthur Beck Date: Sat, 19 Apr 2025 09:08:01 -0500 Subject: [PATCH 3/3] Modified bochsrc --- emulation/bochsrc | 1 + emulation/bochsrc.template | 1 + 2 files changed, 2 insertions(+) diff --git a/emulation/bochsrc b/emulation/bochsrc index 5ead1e9..3fbfc21 100644 --- a/emulation/bochsrc +++ b/emulation/bochsrc @@ -2,6 +2,7 @@ display_library: x, options="gui_debug" port_e9_hack: enabled=1 cpu: reset_on_triple_fault=0, model=corei7_icelake_u magic_break: enabled=1 +clock: sync=realtime, time0=local ata0-master: type=cdrom, path=../kernel/aphrodite-x86.iso, status=inserted boot: cdrom diff --git a/emulation/bochsrc.template b/emulation/bochsrc.template index 48506d3..4ce46c9 100644 --- a/emulation/bochsrc.template +++ b/emulation/bochsrc.template @@ -2,6 +2,7 @@ display_library: x, options="gui_debug" port_e9_hack: enabled=1 cpu: reset_on_triple_fault=0, model=corei7_icelake_u magic_break: enabled=1 +clock: sync=realtime, time0=local ata0-master: type=cdrom, path=../kernel/%{BUILT_FILE}, status=inserted boot: cdrom