diff --git a/.vscode/settings.json b/.vscode/settings.json index 1a8d43e..c842fc6 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -4,6 +4,7 @@ "rust-analyzer.linkedProjects": [ "kernel/Cargo.toml", "kernel/aphrodite_proc_macros/Cargo.toml", - "kernel/aphrodite_common/Cargo.toml" + "kernel/aphrodite_common/Cargo.toml", + "user/Cargo.toml" ], } \ No newline at end of file diff --git a/emulation/bochsrc b/emulation/bochsrc index f73553f..fce2d2a 100644 --- a/emulation/bochsrc +++ b/emulation/bochsrc @@ -1,6 +1,6 @@ display_library: x, options="gui_debug" port_e9_hack: enabled=1 -cpu: reset_on_triple_fault=0, model=tigerlake +cpu: reset_on_triple_fault=0, model=corei7_icelake_u magic_break: enabled=1 ata0-master: type=cdrom, path=../kernel/aphrodite.iso, status=inserted diff --git a/kernel/config.aphro.example b/kernel/config.aphro.example index 0970aa8..402a350 100644 --- a/kernel/config.aphro.example +++ b/kernel/config.aphro.example @@ -1,6 +1,6 @@ # config.aphro for aphrodite devel-6a2a677-out-of-tree CFG_VERSION=devel-6a2a677-out-of-tree -CONT_WITH_DIFFERENT_VERSION=false +CONT_WITH_DIFFERENT_VERSION=true # Begin metadata diff --git a/kernel/expand b/kernel/expand index 706c6dc..c198d22 100755 --- a/kernel/expand +++ b/kernel/expand @@ -1,3 +1,3 @@ #!/bin/bash -RUSTFLAGS='-Clink-arg=--script=link.x' cargo expand --target i686-unknown-none.json --release -Zbuild-std --bin entrypoint \ No newline at end of file +RUSTFLAGS='-Clink-arg=--script=link.x' cargo expand --target i686-unknown-none.json --release -Zbuild-std --bin entrypoint_x86 \ 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 c69004a..d69bbb7 100644 --- a/kernel/src/arch_boot_entry/x86.rs +++ b/kernel/src/arch_boot_entry/x86.rs @@ -220,18 +220,18 @@ extern "C" fn _start() -> ! { ptr = (ptr + current_tag.tag_len as usize + 7) & !7; if ptr>end_addr { cfg_match! { - cfg(all(CONFIG_PREUSER_ERROR_ON_INVALID_LENGTH = "true", CONFIG_PREUSER_PANIC_ON_INVALID_LENGTH = "false")) => { + all(CONFIG_PREUSER_ERROR_ON_INVALID_LENGTH = "true", CONFIG_PREUSER_PANIC_ON_INVALID_LENGTH = "false") => { serrorsln("Current tag length would put pointer out-of-bounds; CONFIG_PREUSER_ERROR_ON_INVALID_LENGTH is set, continuing"); } - cfg(all(CONFIG_PREUSER_WARN_ON_INVALID_LENGTH = "true", CONFIG_PREUSER_PANIC_ON_INVALID_LENGTH = "false")) => { + all(CONFIG_PREUSER_WARN_ON_INVALID_LENGTH = "true", CONFIG_PREUSER_PANIC_ON_INVALID_LENGTH = "false") => { swarningsln("Current tag length would put pointer out-of-bounds; CONFIG_PREUSER_WARN_ON_INVALID_LENGTH is set, continuing"); } } cfg_match! { - cfg(not(CONFIG_PREUSER_PANIC_ON_INVALID_LENGTH = "false")) => { + not(CONFIG_PREUSER_PANIC_ON_INVALID_LENGTH = "false") => { panic!("current tag length would put pointer out-of-bounds") } - cfg(CONFIG_PREUSER_EXIT_LOOP_ON_INVALID_LENGTH = "true") => { + CONFIG_PREUSER_EXIT_LOOP_ON_INVALID_LENGTH = "true" => { sinfos("Exiting loop as current tag length would put pointer out-of-bounds "); sinfosnpln("and CONFIG_PREUSER_EXIT_LOOP_ON_INVALID_LENGTH is set"); break; @@ -263,7 +263,7 @@ extern "C" fn _start() -> ! { sdebugs("Framebuffer bpp: "); sdebugbnpln(&aphrodite::u8_as_u8_slice(framebuffer_info.bpp)); - sdebugsln("Beginning output to screen..."); + sdebugsln("Beginning test output to screen..."); let ega: &dyn aphrodite::display::TextDisplay = &framebuffer_info; framebuffer_info.disable_cursor(); @@ -272,11 +272,11 @@ extern "C" fn _start() -> ! { toutputsln("Testing EGA Text framebuffer...", ega).unwrap(); toutputsln("Testing EGA Text framebuffer...", ega).unwrap(); - aphrodite::indep_boot_entry::indep_boot_entry(Some(ega), &BI); + aphrodite::indep_boot_entry::IndepBootEntry(Some(ega), &BI); } } - aphrodite::indep_boot_entry::indep_boot_entry(None, &BI); + aphrodite::indep_boot_entry::IndepBootEntry(None, &BI); } #[unsafe(link_section = ".panic")] diff --git a/kernel/src/common/mod.rs b/kernel/src/common/mod.rs index 49471ca..e69de29 100644 --- a/kernel/src/common/mod.rs +++ b/kernel/src/common/mod.rs @@ -1,37 +0,0 @@ -use syn::{parse::Parse, Ident}; -use strum::IntoEnumIterator; -use strum_macros::EnumIter; - -#[derive(Debug, Clone, Copy, EnumIter)] -pub enum KernelItem { - IndepBootEntry, - ArchBootEntry, - SyscallSetup, - MemMapGen, - MemMapAlloc, - PreuserModLoad, - InitEnv, - KernelFSMount, - StorageFSMount, - PreuserMod, - RamLoader, - UserInit, - UserModLoad, - ProcessFSMount -} - -impl Parse for KernelItem { - fn parse(input: syn::parse::ParseStream) -> syn::Result { - let ident: Ident = input.parse()?; - - for variant in Self::iter() { - let name = format!("{:?}", variant); - - if ident.to_string().as_str() == name { - return Ok(variant); - } - } - - Err(syn::Error::new(ident.span(), "Expected one of aphrodite_common::KernelItem's variants")) - } -} \ No newline at end of file diff --git a/kernel/src/kernel/indep_boot_entry.rs b/kernel/src/kernel/indep_boot_entry.rs index 036ed5e..54a3c6a 100644 --- a/kernel/src/kernel/indep_boot_entry.rs +++ b/kernel/src/kernel/indep_boot_entry.rs @@ -13,7 +13,11 @@ const MEM_TEST_SIZES: [usize; 8] = [1, 2, 4, 8, 16, 32, 64, 128]; /// The real entrypoint to the kernel. `internel/arch/*/entry.rs` files eventually call this. #[kernel_item(IndepBootEntry)] -pub fn indep_boot_entry(display: Option<&dyn crate::display::TextDisplay>, BI: &crate::boot::BootInfo) -> ! { +fn indep_boot_entry( + display: Option<&dyn crate::display::TextDisplay>, + #[allow(non_snake_case)] + BI: &crate::boot::BootInfo, +) -> ! { crate::arch::output::sdebugsln("Entrypoint called"); let display = display.unwrap(); @@ -21,18 +25,19 @@ pub fn indep_boot_entry(display: Option<&dyn crate::display::TextDisplay>, BI: & display.clear_screen(COLOR_DEFAULT); sreset(); - let mut mem_map = BI.memory_map.unwrap(); - let allocator_res = crate::mem::MemoryMapAlloc::new(&mut mem_map); - if allocator_res.is_err() { - panic!("{}", allocator_res.unwrap_err()); - } - let allocator = allocator_res.unwrap(); + let mem_map = BI.memory_map.unwrap(); + crate::mem::MemMapAllocInit(mem_map).unwrap(); + let allocator = crate::mem::MemMapAlloc().unwrap(); tdebugsln("Testing allocator...", display).unwrap(); for size in MEM_TEST_SIZES { tdebugs("Number of allocations: ", display).unwrap(); - tdebugbnpln(&crate::u64_as_u8_slice(allocator.number_of_allocations()), display).unwrap(); + tdebugbnpln( + &crate::u64_as_u8_slice(allocator.number_of_allocations()), + display, + ) + .unwrap(); tdebugs("Allocating ", display).unwrap(); tdebugbnp(&crate::usize_as_u8_slice(size), display).unwrap(); @@ -40,7 +45,7 @@ pub fn indep_boot_entry(display: Option<&dyn crate::display::TextDisplay>, BI: & let allocation = allocator.allocate(Layout::from_size_align(size, 1).unwrap()); if let Err(_) = allocation { - terrors("Failed to allocate: ",display).unwrap(); + terrors("Failed to allocate: ", display).unwrap(); unsafe { crate::mem::LAST_MEMMAP_ERR.unwrap_err().display_np(display) } panic!("Allocation failure"); } else if let Ok(ptr) = allocation { @@ -49,7 +54,12 @@ pub fn indep_boot_entry(display: Option<&dyn crate::display::TextDisplay>, BI: & tdebugsnpln(".", display).unwrap(); tdebugsln("", display).unwrap(); tdebugsln("Deallocating memory...", display).unwrap(); - unsafe { allocator.deallocate(ptr.as_non_null_ptr(), Layout::from_size_align(size, 1).unwrap()) } + unsafe { + allocator.deallocate( + ptr.as_non_null_ptr(), + Layout::from_size_align(size, 1).unwrap(), + ) + } if let Err(err) = unsafe { crate::mem::LAST_MEMMAP_ERR } { terrors("Failed to deallocate: ", display).unwrap(); err.display_np(display); @@ -59,4 +69,4 @@ pub fn indep_boot_entry(display: Option<&dyn crate::display::TextDisplay>, BI: & tdebugsln("", display).unwrap(); } loop {} -} \ No newline at end of file +} diff --git a/kernel/src/kernel/mem.rs b/kernel/src/kernel/mem.rs index 0343202..aaf7488 100644 --- a/kernel/src/kernel/mem.rs +++ b/kernel/src/kernel/mem.rs @@ -1,15 +1,22 @@ //! Memory allocation. use core::{ - alloc::{Allocator, GlobalAlloc}, fmt::Debug, num::NonZero, ops::Range, ptr::{null_mut, NonNull} + alloc::{Allocator, GlobalAlloc}, + fmt::Debug, + mem::MaybeUninit, + num::NonZero, + ops::Range, + ptr::{NonNull, null_mut}, }; -use crate::boot::MemoryType; +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 - /// entire allocation table doesn't need to be shifted back + /// entire allocation table doesn't need to be shifted back /// on every allocation. pub used: bool, /// The starting address of the allocation. @@ -50,12 +57,48 @@ impl Iterator for AllocationIter { crate::arch::output::sdebugsln("Providing allocation from iterator"); Some(&unsafe { - *((self.ptr as usize + (size_of::() * (self.idx as usize-1))) + *((self.ptr as usize + (size_of::() * (self.idx as usize - 1))) as *const Allocation) } as *const Allocation as *mut Allocation) } } +static mut ALLOCATOR: MaybeUninit> = MaybeUninit::uninit(); +static mut ALLOCATOR_MEMMAP: MaybeUninit = MaybeUninit::uninit(); +static mut ALLOCATOR_INITALIZED: bool = false; + +#[kernel_item(MemMapAlloc)] +fn get_allocator() -> Option<&'static MemoryMapAlloc<'static>> { + if unsafe { ALLOCATOR_INITALIZED } { + #[allow(static_mut_refs)] + return Some(unsafe { ALLOCATOR.assume_init_ref() }); + } else { + return None; + } +} + +#[kernel_item(MemMapAllocInit)] +fn memory_map_alloc_init( + memmap: crate::boot::MemoryMap, +) -> Result<(), crate::Error<'static>> { + #[allow(static_mut_refs)] + unsafe { + ALLOCATOR_MEMMAP.write(memmap); + } + #[allow(static_mut_refs)] + let alloc = MemoryMapAlloc::new(unsafe { ALLOCATOR_MEMMAP.assume_init_mut() })?; + + #[allow(static_mut_refs)] + unsafe { + ALLOCATOR.write(alloc); + } + unsafe { + ALLOCATOR_INITALIZED = true; + } + + Ok(()) +} + /// A implementation of a physical memory allocator that uses a [crate::boot::MemoryMap]. pub struct MemoryMapAlloc<'a> { /// The memory map to use to allocate memory. @@ -84,7 +127,12 @@ const EXTEND_ALLOCATION_OTHER_ALLOCATION: i16 = -6; impl<'a> Debug for MemoryMapAlloc<'a> { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.write_str("MemoryMapAlloc with ")?; - f.write_str(core::str::from_utf8(&crate::u64_as_u8_slice(unsafe { *self.allocationheader }.num_allocations)).unwrap())?; + f.write_str( + core::str::from_utf8(&crate::u64_as_u8_slice( + unsafe { *self.allocationheader }.num_allocations, + )) + .unwrap(), + )?; f.write_str(" allocations")?; Ok(()) } @@ -115,7 +163,9 @@ impl<'a> MemoryMapAlloc<'a> { (), ); out.allocations = core::ptr::from_raw_parts_mut( - core::ptr::without_provenance_mut::<()>(mapping.start as usize+size_of::()), + core::ptr::without_provenance_mut::<()>( + mapping.start as usize + size_of::(), + ), (), ); out.max_allocations_size = mapping.len; @@ -126,7 +176,9 @@ impl<'a> MemoryMapAlloc<'a> { (), ); out.allocations = core::ptr::from_raw_parts_mut( - core::ptr::without_provenance_mut::<()>(mapping.start as usize+size_of::()), + core::ptr::without_provenance_mut::<()>( + mapping.start as usize + size_of::(), + ), (), ); out.max_allocations_size = mapping.len; @@ -149,7 +201,7 @@ impl<'a> MemoryMapAlloc<'a> { used: true, addr: out.allocations as usize as u64, len: (size_of::() * 32) as u64, - num_allocations: 1 + num_allocations: 1, } } Ok(out) @@ -182,10 +234,10 @@ impl<'a> MemoryMapAlloc<'a> { let num_allocations = unsafe { *self.allocationheader }.num_allocations; - if unsafe { *self.allocations }.len - < (size_of::() as u64 * (num_allocations)) - { - if unsafe { *self.allocationheader }.len + size_of::() as u64 >= self.max_allocations_size { + if unsafe { *self.allocations }.len < (size_of::() as u64 * (num_allocations)) { + if unsafe { *self.allocationheader }.len + size_of::() as u64 + >= self.max_allocations_size + { return Err(crate::Error::new( "not enough space for another allocation", TOO_MANY_ALLOCATIONS, @@ -202,7 +254,7 @@ impl<'a> MemoryMapAlloc<'a> { let new_alloc = (self.allocations as usize + (size_of::() * (num_allocations) as usize)) as *const Allocation as *mut Allocation; - + unsafe { (*new_alloc) = allocation } Ok(()) @@ -266,7 +318,9 @@ impl<'a> MemoryMapAlloc<'a> { /// Check to see if any allocations contain the given address. Returns true if so. fn check_addr(&self, addr: u64) -> bool { - if addr >= (self.allocationheader as u64) && addr < (self.allocationheader as u64+unsafe { *self.allocationheader }.len) { + if addr >= (self.allocationheader as u64) + && addr < (self.allocationheader as u64 + unsafe { *self.allocationheader }.len) + { return true; } for ele in self.allocations_iter() { @@ -345,11 +399,17 @@ unsafe impl<'a> Allocator for MemoryMapAlloc<'a> { allocatable = alloc; } if allocatable { - addr = mapping.start+mapping.len-layout.size() as u64; - while self.check_range(addr..addr+layout.size() as u64) && (addr as usize % layout.align() != 0) && addr >= mapping.start { - addr -= layout.size() as u64/crate::cfg_int!("CONFIG_ALLOC_PRECISION", u64); + addr = mapping.start + mapping.len - layout.size() as u64; + while self.check_range(addr..addr + layout.size() as u64) + && (addr as usize % layout.align() != 0) + && addr >= mapping.start + { + addr -= layout.size() as u64 / crate::cfg_int!("CONFIG_ALLOC_PRECISION", u64); } - if (!self.check_range(addr..addr+layout.size() as u64)) && (addr as usize % layout.align() == 0) && addr >= mapping.start { + if (!self.check_range(addr..addr + layout.size() as u64)) + && (addr as usize % layout.align() == 0) + && addr >= mapping.start + { break; } continue; @@ -364,7 +424,11 @@ unsafe impl<'a> Allocator for MemoryMapAlloc<'a> { } return Err(core::alloc::AllocError {}); } - if let Err(err) = self.add_allocation(Allocation { used: true, addr, len: layout.size() as u64 }) { + if let Err(err) = self.add_allocation(Allocation { + used: true, + addr, + len: layout.size() as u64, + }) { unsafe { LAST_MEMMAP_ERR = Err(err) } return Err(core::alloc::AllocError {}); } @@ -387,7 +451,9 @@ unsafe impl<'a> Allocator for MemoryMapAlloc<'a> { } return; } - crate::arch::output::sdebugbln(&crate::u64_as_u8_slice(unsafe { *self.allocationheader }.num_allocations)); + crate::arch::output::sdebugbln(&crate::u64_as_u8_slice( + unsafe { *self.allocationheader }.num_allocations, + )); for allocation in self.allocations_iter() { crate::arch::output::sdebugsln("Allocation"); let alloc = unsafe { *allocation }.clone(); @@ -401,7 +467,12 @@ unsafe impl<'a> Allocator for MemoryMapAlloc<'a> { } } // Memory not allocated, something is up, this is put after the loop to prevent a costly call to check_addr - unsafe { LAST_MEMMAP_ERR = Err(crate::Error::new("memory not allocated", MEMORY_NOT_ALLOCATED)) } + unsafe { + LAST_MEMMAP_ERR = Err(crate::Error::new( + "memory not allocated", + MEMORY_NOT_ALLOCATED, + )) + } return; } } diff --git a/kernel/src/proc_macros/mod.rs b/kernel/src/proc_macros/mod.rs index 8b73d29..b8fdbc0 100644 --- a/kernel/src/proc_macros/mod.rs +++ b/kernel/src/proc_macros/mod.rs @@ -1,59 +1,69 @@ use proc_macro::TokenStream; -use quote::{quote_spanned, ToTokens}; -use syn::{parse::{Parse, ParseStream}, spanned::Spanned, ItemFn, Signature, Token}; +use quote::{ToTokens, quote}; +use syn::{ + ItemFn, Signature, Token, + parse::{Parse, ParseStream} +}; struct KernelItemNameInput { - item: aphrodite_common::KernelItem + item: syn::Ident, } impl Parse for KernelItemNameInput { fn parse(input: ParseStream) -> syn::Result { - let item: aphrodite_common::KernelItem = input.parse()?; + let item: syn::Ident = input.parse()?; Ok(KernelItemNameInput { item }) } } -fn to_tokens(signature: Signature, tokens: &mut TokenStream) { - signature.constness.to_tokens(&mut (*tokens).clone().into()); - signature.asyncness.to_tokens(&mut (*tokens).clone().into()); - signature.unsafety.to_tokens(&mut (*tokens).clone().into()); - signature.abi.to_tokens(&mut (*tokens).clone().into()); - signature.fn_token.to_tokens(&mut (*tokens).clone().into()); - signature.generics.to_tokens(&mut (*tokens).clone().into()); - signature.paren_token.surround(&mut (*tokens).clone().into(), |tokens| { - signature.inputs.to_tokens(tokens); - if let Some(variadic) = &signature.variadic { - if !signature.inputs.empty_or_trailing() { - ::default().to_tokens(tokens); +fn to_tokens(signature: Signature, tokens: &mut proc_macro2::TokenStream) { + let ts = tokens; + signature.constness.to_tokens(ts.into()); + signature.asyncness.to_tokens(ts.into()); + signature.unsafety.to_tokens(ts.into()); + signature.abi.to_tokens(ts.into()); + signature.fn_token.to_tokens(ts.into()); + signature.generics.to_tokens(ts.into()); + signature + .paren_token + .surround(ts.into(), |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); } - variadic.to_tokens(tokens); - } - }); - signature.output.to_tokens(&mut (*tokens).clone().into()); - signature.generics.where_clause.to_tokens(&mut (*tokens).clone().into()); + }); + signature.output.to_tokens(ts.into()); + signature + .generics + .where_clause + .to_tokens(ts.into()); } -fn to_token_stream(signature: Signature) -> TokenStream { - let mut tokens = proc_macro::TokenStream::new(); +fn to_token_stream(signature: Signature) -> proc_macro2::TokenStream { + let mut tokens = proc_macro2::TokenStream::new(); to_tokens(signature, &mut tokens); tokens.into() } -/// Implement a kernel item. +/// Implement a kernel item. #[proc_macro_attribute] pub fn kernel_item(attr: TokenStream, item: TokenStream) -> TokenStream { - let item_name_input: KernelItemNameInput = syn::parse_macro_input!(attr); - let item_name = format!("{:?}", item_name_input.item); + let name: KernelItemNameInput = syn::parse_macro_input!(attr); + let item_name = name.item; - let input_fn: ItemFn = syn::parse_macro_input!(item as ItemFn); + 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_spanned!(input_fn.span()=>{ - // The #item_name kernel item. + quote!{ + /// The #item_name kernel item. #[allow(non_upper_case_globals)] pub const #item_name: #fn_sig = #fn_name; #input_fn - }).into() -} \ No newline at end of file + } + .into() +} diff --git a/user/Cargo.toml b/user/Cargo.toml new file mode 100644 index 0000000..68f345f --- /dev/null +++ b/user/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "user" +version = "0.1.0" +edition = "2024" + +[dependencies] diff --git a/user/src/arch/mod.rs b/user/src/arch/mod.rs new file mode 100644 index 0000000..6b2aae6 --- /dev/null +++ b/user/src/arch/mod.rs @@ -0,0 +1,6 @@ +//! Architecture-specific stuff, mainly syscall methods. + +#[macro_use] +mod x86; + +pub use x86::*; \ No newline at end of file diff --git a/user/src/arch/x86/mod.rs b/user/src/arch/x86/mod.rs new file mode 100644 index 0000000..5d0b383 --- /dev/null +++ b/user/src/arch/x86/mod.rs @@ -0,0 +1,62 @@ +//! x86 syscall method. + +/// Syscall method. +#[macro_export] +macro_rules! syscall { + ($id: expr) => { + unsafe { + let out = 0u32; + asm!( + "int 0xA0", + id = in("eax") const $id, + out("eax") out + ) + out + } + }; + ($id: expr, $d0: expr) => { + unsafe { + let out = 0u32; + let d0 = $d0; + asm!( + "int 0xA0", + id = in("eax") const $id, + d0 = in("ebx") $d0, + out("eax") out + ) + out + } + }; + ($id: expr, $d0: expr, $d1: expr) => { + unsafe { + let out = 0u32; + let d0 = $d0; + let d1 = $d1; + asm!( + "int 0xA0", + id = in("eax") const $id, + d0 = in("ebx") $d0, + d1 = in("ecx") $d1, + out("eax") out + ) + out + } + }; + ($id: expr, $d0: expr, $d1: expr, $d2: expr) => { + unsafe { + let out = 0u32; + let d0 = $d0; + let d1 = $d1; + let d2 = $d2; + asm!( + "int 0xA0", + id = in("eax") const $id, + d0 = in("ebx") $d0, + d1 = in("ecx") $d1, + d2 = in("edx") $d2, + out("eax") out + ) + out + } + } +} \ No newline at end of file diff --git a/user/src/lib.rs b/user/src/lib.rs new file mode 100644 index 0000000..84d3811 --- /dev/null +++ b/user/src/lib.rs @@ -0,0 +1,5 @@ +#[warn(missing_docs)] + +mod arch; + +use arch::*; \ No newline at end of file