diff --git a/.vscode/settings.json b/.vscode/settings.json index 08771cf..1a8d43e 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -2,6 +2,8 @@ "rust-analyzer.cargo.allTargets": false, "rust-analyzer.check.allTargets": false, "rust-analyzer.linkedProjects": [ - "kernel/Cargo.toml" - ] + "kernel/Cargo.toml", + "kernel/aphrodite_proc_macros/Cargo.toml", + "kernel/aphrodite_common/Cargo.toml" + ], } \ No newline at end of file diff --git a/emulation/bochsrc b/emulation/bochsrc index 150fedb..f73553f 100644 --- a/emulation/bochsrc +++ b/emulation/bochsrc @@ -4,4 +4,5 @@ cpu: reset_on_triple_fault=0, model=tigerlake magic_break: enabled=1 ata0-master: type=cdrom, path=../kernel/aphrodite.iso, status=inserted -boot: cdrom \ No newline at end of file +boot: cdrom +memory: guest=512, host=512 \ No newline at end of file diff --git a/emulation/bx_enh_dbg.ini b/emulation/bx_enh_dbg.ini new file mode 100644 index 0000000..e6a026a --- /dev/null +++ b/emulation/bx_enh_dbg.ini @@ -0,0 +1,26 @@ +# bx_enh_dbg_ini +SeeReg[0] = TRUE +SeeReg[1] = TRUE +SeeReg[2] = TRUE +SeeReg[3] = TRUE +SeeReg[4] = FALSE +SeeReg[5] = FALSE +SeeReg[6] = FALSE +SeeReg[7] = FALSE +SingleCPU = FALSE +ShowIOWindows = TRUE +ShowButtons = TRUE +SeeRegColors = TRUE +ignoreNxtT = TRUE +ignSSDisasm = TRUE +UprCase = 0 +DumpInAsciiMode = 3 +isLittleEndian = TRUE +DefaultAsmLines = 512 +DumpWSIndex = 0 +DockOrder = 0x123 +ListWidthPix[0] = 179 +ListWidthPix[1] = 245 +ListWidthPix[2] = 281 +MainWindow = 0, 0, 709, 500 +FontName = Normal diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 2671c1e..d114495 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -5,6 +5,7 @@ edition = "2024" [dependencies] paste = "1.0.15" +aphrodite_proc_macros = { path = "./aphrodite_proc_macros"} [profile.release] opt-level = "z" @@ -15,15 +16,11 @@ panic = "abort" [[bin]] name = "entrypoint_x86" -path = "src/internal/arch/x86_asmp/entry.rs" - -[[bin]] -name = "main" -path = "src/internal/main.rs" +path = "src/arch_boot_entry/x86.rs" [lib] name = "aphrodite" -path = "src/include/mod.rs" +path = "src/kernel/mod.rs" [[test]] name = "test_aphrodite" diff --git a/kernel/aphrodite_common/Cargo.toml b/kernel/aphrodite_common/Cargo.toml new file mode 100644 index 0000000..ef75eb6 --- /dev/null +++ b/kernel/aphrodite_common/Cargo.toml @@ -0,0 +1,12 @@ +[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/aphrodite_proc_macros/Cargo.toml b/kernel/aphrodite_proc_macros/Cargo.toml new file mode 100644 index 0000000..219725f --- /dev/null +++ b/kernel/aphrodite_proc_macros/Cargo.toml @@ -0,0 +1,14 @@ +[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/build b/kernel/build index 2e3b033..3f0df50 100755 --- a/kernel/build +++ b/kernel/build @@ -3,9 +3,8 @@ ( set -e - if [[ -n "$KERNEL_DIR" ]]; then - export KERNEL_DIR=$(readlink -e .) - fi + + export KERNEL_DIR=$(readlink -e .) DIR="${BASH_SOURCE%/*}" if [[ ! -d "$DIR" ]]; then DIR="$PWD"; fi @@ -40,24 +39,22 @@ for target in $TARGETS; do real_target=${!target} cargo build --target "$real_target" --release -Zbuild-std --bin entrypoint_$target + cp target/i686-unknown-none/release/entrypoint_$target kernel.flat + + if [[ "$CONFIG_BUILD_GRUB" = "true" ]]; then + rm -rf grub aphrodite-grub.iso + if [[ "$target" = "x86" ]]; then + cp -r ./grub_template ./grub + + cp kernel.flat ./grub/boot/aphrodite.kernel + + sed -i "s@%{VERSION}@$VERSION@g" ./grub/boot/grub/grub.cfg + + grub-mkrescue -o aphrodite-grub.iso grub + cp aphrodite-grub.iso aphrodite.iso + fi + fi done - # build the kernel's entrypoint - - cp target/i686-unknown-none/release/entrypoint kernel.flat - # copy it out - - rm -rf grub aphrodite.iso aphrodite-grub.iso - - if [[ $CONFIG_BUILD_GRUB = "true" ]]; then - cp -r ./grub_template ./grub - - cp kernel.flat ./grub/boot/aphrodite.kernel - - sed -i "s@%{VERSION}@$VERSION@g" ./grub/boot/grub/grub.cfg - - grub-mkrescue -o aphrodite-grub.iso grub - cp aphrodite-grub.iso aphrodite.iso - fi reset_version_vars ) \ No newline at end of file diff --git a/kernel/src/internal/arch/x86_asmp/entry.rs b/kernel/src/arch_boot_entry/x86.rs similarity index 91% rename from kernel/src/internal/arch/x86_asmp/entry.rs rename to kernel/src/arch_boot_entry/x86.rs index 72ce2da..c69004a 100644 --- a/kernel/src/internal/arch/x86_asmp/entry.rs +++ b/kernel/src/arch_boot_entry/x86.rs @@ -7,9 +7,12 @@ #![allow(static_mut_refs)] #![feature(ptr_metadata)] #![feature(cfg_match)] +#![feature(formatting_options)] use core::{arch::asm, ffi::CStr, panic::PanicInfo}; -use aphrodite::boot::BootInfo; +use core::fmt::Debug; + +use aphrodite::boot::{BootInfo, MemoryMapping}; use aphrodite::multiboot2::{FramebufferInfo, MemoryMap, MemorySection, RawMemoryMap, RootTag, Tag}; use aphrodite::arch::output::*; use aphrodite::arch::egatext as egatext; @@ -40,7 +43,6 @@ static mut MM: MemoryMap = MemoryMap { entry_size: 0, version: 0, sections: &[], - idx: 0, }; static mut FBI: aphrodite::arch::egatext::FramebufferInfo = aphrodite::arch::egatext::FramebufferInfo { @@ -142,17 +144,23 @@ extern "C" fn _start() -> ! { if current_tag.tag_len < 16 { // Unexpected size, something is probably up panic!("size of memory map tag < 16"); } - let rawmemorymap: *const RawMemoryMap = core::ptr::from_raw_parts( - ptr as *const u8, (current_tag.tag_len / *((ptr + 8usize) as *const u32)) as usize + let rawmemorymap: *mut RawMemoryMap = core::ptr::from_raw_parts_mut( + ptr as *mut u8, (current_tag.tag_len / *((ptr + 8usize) as *const u32)) as usize ); // The end result of the above is creating a *const RawMemoryMap that has the same address as current_tag // and has all of the [aphrodite::multiboot2::MemorySection]s for the memory map + 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. + + for ele in &mut *memorysections { + (*ele) = core::mem::transmute(Into::::into(*ele)) + } + MM = MemoryMap { version: (*rawmemorymap).entry_version, entry_size: (*rawmemorymap).entry_size, - sections: &*core::ptr::from_raw_parts((&(*rawmemorymap).sections[0]) as &MemorySection, (*rawmemorymap).sections.len()), - idx: 0 + sections: core::mem::transmute(memorysections), }; let mm2 = aphrodite::boot::MemoryMap { len: MM.sections.len() as u64, @@ -264,17 +272,19 @@ extern "C" fn _start() -> ! { toutputsln("Testing EGA Text framebuffer...", ega).unwrap(); toutputsln("Testing EGA Text framebuffer...", ega).unwrap(); - aphrodite::_entry::_entry(Some(ega), &BI); + aphrodite::indep_boot_entry::indep_boot_entry(Some(ega), &BI); } } - aphrodite::_entry::_entry(None, &BI); + aphrodite::indep_boot_entry::indep_boot_entry(None, &BI); } #[unsafe(link_section = ".panic")] #[panic_handler] #[cfg(not(CONFIG_HALT_ON_PANIC = "false"))] fn halt_on_panic(info: &PanicInfo) -> ! { + use core::fmt::FormattingOptions; + if info.location().is_some() { sfatals("Panic at "); sfatalsnp(info.location().unwrap().file()); @@ -286,10 +296,8 @@ fn halt_on_panic(info: &PanicInfo) -> ! { } else { sfatals("Panic: "); } - let message = info.message().as_str().unwrap_or(""); - if message != "" { - sfatalsnpln(message); - } + let mut formatter = FormattingOptions::new().create_formatter(unsafe { &mut FBI }); + let _ = info.message().fmt(&mut formatter); aphrodite::arch::interrupts::disable_interrupts(); unsafe { asm!("hlt", options(noreturn)); @@ -314,6 +322,8 @@ fn spin_on_panic(info: &PanicInfo) -> ! { let message = info.message().as_str().unwrap_or(""); if message != "" { sfatalsnpln(message); + } else { + sfatalsnp("\n"); } aphrodite::arch::interrupts::disable_interrupts(); loop {} diff --git a/kernel/src/common/mod.rs b/kernel/src/common/mod.rs new file mode 100644 index 0000000..49471ca --- /dev/null +++ b/kernel/src/common/mod.rs @@ -0,0 +1,37 @@ +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/include/_entry.rs b/kernel/src/include/_entry.rs deleted file mode 100644 index 6395466..0000000 --- a/kernel/src/include/_entry.rs +++ /dev/null @@ -1,29 +0,0 @@ -//! The main code for the kernel. -#![warn(missing_docs)] -#![allow(unexpected_cfgs)] -#![allow(static_mut_refs)] - -use core::alloc::{Allocator, Layout}; - -use crate::output::*; - -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. -#[allow(non_snake_case)] -pub fn _entry(display: Option<&dyn crate::display::TextDisplay>, BI: &crate::boot::BootInfo) -> ! { - let mut mem_map = BI.memory_map.unwrap(); - let allocator = crate::mem::MemoryMapAlloc::new(&mut mem_map).unwrap(); - tdebugsln("Testing allocator...", display.unwrap()); - - for size in MEM_TEST_SIZES { - tdebugs("Allocating ", display.unwrap()); - tdebugbnp(&crate::usize_as_u8_slice(size), display.unwrap()); - tdebugsnpln(" bytes of memory...", display.unwrap()); - if let Err(_) = allocator.allocate(Layout::from_size_align(size, 1).unwrap()) { - terrors("Failed to allocate: ",display.unwrap()); - unsafe { crate::mem::LAST_MEMMAP_ERR.unwrap_err().display_np(display.unwrap()) } - } - } - loop {} -} \ No newline at end of file diff --git a/kernel/src/include/arch/mod.rs b/kernel/src/kernel/arch/mod.rs similarity index 73% rename from kernel/src/include/arch/mod.rs rename to kernel/src/kernel/arch/mod.rs index c0ca90d..8801ebf 100644 --- a/kernel/src/include/arch/mod.rs +++ b/kernel/src/kernel/arch/mod.rs @@ -1,5 +1,5 @@ //! Arch-specific code. This module re-exports all code from the architecture being used. -mod x86_asmp; +mod x86; -pub use x86_asmp::*; \ No newline at end of file +pub use x86::*; \ No newline at end of file diff --git a/kernel/src/include/arch/x86_asmp/constants.rs b/kernel/src/kernel/arch/x86/constants.rs similarity index 100% rename from kernel/src/include/arch/x86_asmp/constants.rs rename to kernel/src/kernel/arch/x86/constants.rs diff --git a/kernel/src/include/arch/x86_asmp/egatext.rs b/kernel/src/kernel/arch/x86/egatext.rs similarity index 94% rename from kernel/src/include/arch/x86_asmp/egatext.rs rename to kernel/src/kernel/arch/x86/egatext.rs index 95128ab..89e383f 100644 --- a/kernel/src/include/arch/x86_asmp/egatext.rs +++ b/kernel/src/kernel/arch/x86/egatext.rs @@ -25,6 +25,13 @@ pub const ERR_INVALID_X: i16 = -1; /// Returned when the provided position is invalid in the Y direction. pub const ERR_INVALID_Y: i16 = -2; +impl core::fmt::Write for FramebufferInfo { + fn write_str(&mut self, s: &str) -> core::fmt::Result { + crate::output::toutputsnp(s, self).unwrap(); + Ok(()) + } +} + impl crate::display::TextDisplay for FramebufferInfo { /// Writes a character to the screen. fn write_char(&self, mut pos: (u32, u32), char: u8, color: Color) -> Result<(), crate::Error<'static>> { diff --git a/kernel/src/include/arch/x86_asmp/interrupts.rs b/kernel/src/kernel/arch/x86/interrupts.rs similarity index 100% rename from kernel/src/include/arch/x86_asmp/interrupts.rs rename to kernel/src/kernel/arch/x86/interrupts.rs diff --git a/kernel/src/include/arch/x86_asmp/mod.rs b/kernel/src/kernel/arch/x86/mod.rs similarity index 100% rename from kernel/src/include/arch/x86_asmp/mod.rs rename to kernel/src/kernel/arch/x86/mod.rs diff --git a/kernel/src/include/arch/x86_asmp/output.rs b/kernel/src/kernel/arch/x86/output.rs similarity index 100% rename from kernel/src/include/arch/x86_asmp/output.rs rename to kernel/src/kernel/arch/x86/output.rs diff --git a/kernel/src/include/arch/x86_asmp/paging.rs b/kernel/src/kernel/arch/x86/paging.rs similarity index 100% rename from kernel/src/include/arch/x86_asmp/paging.rs rename to kernel/src/kernel/arch/x86/paging.rs diff --git a/kernel/src/include/arch/x86_asmp/ports.rs b/kernel/src/kernel/arch/x86/ports.rs similarity index 100% rename from kernel/src/include/arch/x86_asmp/ports.rs rename to kernel/src/kernel/arch/x86/ports.rs diff --git a/kernel/src/include/boot.rs b/kernel/src/kernel/boot.rs similarity index 57% rename from kernel/src/include/boot.rs rename to kernel/src/kernel/boot.rs index 523e03f..4d30288 100644 --- a/kernel/src/include/boot.rs +++ b/kernel/src/kernel/boot.rs @@ -9,7 +9,7 @@ pub enum MemoryType { /// Free RAM with no use. Free, - /// RAM used by the kernel + /// RAM where the kernel is loaded. Kernel, /// Reserved by something. Reserved, @@ -26,6 +26,31 @@ pub enum MemoryType { Permanent, } +impl MemoryType { + /// Outputs the contents of this to the debug port with [crate::arch::output::sdebugsnp]. + pub fn output(&self) { + match self { + MemoryType::Free => crate::arch::output::sdebugsnp("Free"), + MemoryType::Faulty => crate::arch::output::sdebugsnp("Faulty RAM"), + MemoryType::HardwareReserved => crate::arch::output::sdebugsnp("Hardware Reserved"), + MemoryType::HardwareSpecific(val, allocatable) => { + crate::arch::output::sdebugsnp("Hardware specific "); + crate::arch::output::sdebugbnp(&crate::u32_as_u8_slice(*val)); + if *allocatable { + crate::arch::output::sdebugsnp(" allocatable"); + } else { + crate::arch::output::sdebugsnp(" unallocatable"); + } + + }, + MemoryType::Kernel => crate::arch::output::sdebugsnp("Kernel loaded"), + MemoryType::Permanent => crate::arch::output::sdebugsnp("Flash"), + MemoryType::Reserved => crate::arch::output::sdebugsnp("Reserved"), + MemoryType::Unknown => crate::arch::output::sdebugsnp("Unknown"), + } + } +} + /// A single memory mapping for [MemoryMap]. #[derive(Clone, Copy)] pub struct MemoryMapping { @@ -37,10 +62,26 @@ pub struct MemoryMapping { pub len: u64, } +impl MemoryMapping { + /// Converts this MemoryMapping to [core::fmt::Arguments]. + pub fn output(&self) { + crate::arch::output::sdebugs("Memory type: "); + self.mem_type.output(); + crate::arch::output::sdebugsnp("; Start: "); + crate::arch::output::sdebugbnp(&crate::u64_as_u8_slice(self.start)); + crate::arch::output::sdebugsnp("; Length: "); + crate::arch::output::sdebugbnp(&crate::u64_as_u8_slice(self.len)); + } +} + +/// A memory map outputted by the bootloader or by the kernel. #[derive(Clone, Copy)] pub struct MemoryMap { + /// The number of [MemoryMapping]s in this MemoryMap. pub len: u64, + /// The size of memory in pages. pub size_pages: u64, + /// The size of one page. pub page_size: u64, /// All sections. @@ -51,12 +92,11 @@ pub struct MemoryMap { } impl MemoryMap { - pub fn len(&self) -> u64 { - self.sections.len() as u64 - } + /// Resets the index of the iterator (sets self.idx to 0). pub fn reset_iter(&mut self) { self.idx = 0; } + /// The size of allocatable memory in bytes. pub fn mem_size(&mut self) -> u64 { let curr_idx = self.idx; self.reset_iter(); @@ -87,10 +127,11 @@ impl core::iter::Iterator for MemoryMap { type Item = MemoryMapping; fn next(&mut self) -> Option { self.idx += 1; - if self.sections.len()<=self.idx-1 { + if self.sections.len() <= self.idx - 1 { + self.reset_iter(); return None; } - Some(self.sections[self.idx-1].into()) + Some(self.sections[self.idx - 1].into()) } } diff --git a/kernel/src/include/cfg.rs b/kernel/src/kernel/cfg.rs similarity index 97% rename from kernel/src/include/cfg.rs rename to kernel/src/kernel/cfg.rs index 33f0fd0..00a455c 100644 --- a/kernel/src/include/cfg.rs +++ b/kernel/src/kernel/cfg.rs @@ -1,5 +1,6 @@ //! Config-related stuff. -//! + +/// C #[macro_export] macro_rules! cfg_int { ($cfg:literal, $type:ident) => { diff --git a/kernel/src/include/cmdline.rs b/kernel/src/kernel/cmdline.rs similarity index 100% rename from kernel/src/include/cmdline.rs rename to kernel/src/kernel/cmdline.rs diff --git a/kernel/src/include/constants.rs b/kernel/src/kernel/constants.rs similarity index 100% rename from kernel/src/include/constants.rs rename to kernel/src/kernel/constants.rs diff --git a/kernel/src/include/display.rs b/kernel/src/kernel/display.rs similarity index 98% rename from kernel/src/include/display.rs rename to kernel/src/kernel/display.rs index e6ba028..edc1d41 100644 --- a/kernel/src/include/display.rs +++ b/kernel/src/kernel/display.rs @@ -14,7 +14,7 @@ pub const COLOR_BLACK: Color = (0, true); pub const COLOR_DEFAULT: Color = (1, true); /// Some form of display that can be written to with text. -pub trait TextDisplay { +pub trait TextDisplay: core::fmt::Write { /// Writes a single character to the specified position. fn write_char(&self, pos: (u32, u32), char: u8, color: Color) -> Result<(), crate::Error<'static>>; /// Gets the size of the screen. diff --git a/kernel/src/include/errors.rs b/kernel/src/kernel/errors.rs similarity index 83% rename from kernel/src/include/errors.rs rename to kernel/src/kernel/errors.rs index e2771f1..ee788dc 100644 --- a/kernel/src/include/errors.rs +++ b/kernel/src/kernel/errors.rs @@ -17,10 +17,11 @@ impl<'a> Error<'a> { } impl Error<'_> { + /// Display the contents of the error on a [TextDisplay]. pub fn display_np(&self, display: &dyn TextDisplay) { - crate::output::terrorbnp(&crate::i16_as_u8_slice(self.code), display); - crate::output::terrorsnp(": ", display); - crate::output::terrorsnpln(self.message, display); + crate::output::terrorbnp(&crate::i16_as_u8_slice(self.code), display).unwrap(); + crate::output::terrorsnp(": ", display).unwrap(); + crate::output::terrorsnpln(self.message, display).unwrap(); } } diff --git a/kernel/src/kernel/indep_boot_entry.rs b/kernel/src/kernel/indep_boot_entry.rs new file mode 100644 index 0000000..036ed5e --- /dev/null +++ b/kernel/src/kernel/indep_boot_entry.rs @@ -0,0 +1,62 @@ +//! The main code for the kernel. +#![warn(missing_docs)] +#![allow(unexpected_cfgs)] +#![allow(static_mut_refs)] + +use core::alloc::{Allocator, Layout}; + +use crate::{display::COLOR_DEFAULT, output::*}; + +use aphrodite_proc_macros::*; + +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) -> ! { + crate::arch::output::sdebugsln("Entrypoint called"); + + let display = display.unwrap(); + + 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(); + + 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(); + + tdebugs("Allocating ", display).unwrap(); + tdebugbnp(&crate::usize_as_u8_slice(size), display).unwrap(); + tdebugsnpln(" byte(s) of memory...", display).unwrap(); + + let allocation = allocator.allocate(Layout::from_size_align(size, 1).unwrap()); + if let Err(_) = allocation { + 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 { + tdebugs("Successfully allocated! Address is ", display).unwrap(); + tdebugbnp(&crate::usize_as_u8_slice(ptr.addr().get()), display).unwrap(); + 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()) } + if let Err(err) = unsafe { crate::mem::LAST_MEMMAP_ERR } { + terrors("Failed to deallocate: ", display).unwrap(); + err.display_np(display); + panic!("Deallocation failure"); + } + } + tdebugsln("", display).unwrap(); + } + loop {} +} \ No newline at end of file diff --git a/kernel/src/include/iso01-12x22.psfu b/kernel/src/kernel/iso01-12x22.psfu similarity index 100% rename from kernel/src/include/iso01-12x22.psfu rename to kernel/src/kernel/iso01-12x22.psfu diff --git a/kernel/src/include/mem.rs b/kernel/src/kernel/mem.rs similarity index 73% rename from kernel/src/include/mem.rs rename to kernel/src/kernel/mem.rs index cde1bb1..0343202 100644 --- a/kernel/src/include/mem.rs +++ b/kernel/src/kernel/mem.rs @@ -1,26 +1,34 @@ //! Memory allocation. use core::{ - alloc::{Allocator, GlobalAlloc}, - num::NonZero, - ops::Range, - ptr::{NonNull, null_mut}, + alloc::{Allocator, GlobalAlloc}, fmt::Debug, num::NonZero, ops::Range, ptr::{null_mut, NonNull} }; use crate::boot::MemoryType; #[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 + /// on every allocation. pub used: bool, + /// The starting address of the allocation. pub addr: u64, + /// The length of the allocation. pub len: u64, } #[derive(Clone, Copy)] struct AllocationHeader { + /// Whether this allocation table is used. Kept for parity with [Allocation]s. + #[allow(dead_code)] pub used: bool, + /// The starting address of the allocation table. + #[allow(dead_code)] pub addr: u64, + /// The length in bytes of the allocation table. pub len: u64, + /// The number of allocations in the allocation table. pub num_allocations: u64, } @@ -33,11 +41,16 @@ struct AllocationIter { impl Iterator for AllocationIter { type Item = *mut Allocation; fn next(&mut self) -> Option<::Item> { - if self.idx >= self.num_allocations { + crate::arch::output::sdebugbln(&crate::u64_as_u8_slice(self.num_allocations)); + crate::arch::output::sdebugbln(&crate::u64_as_u8_slice(self.idx)); + self.idx += 1; + if self.idx > self.num_allocations { return None; } + crate::arch::output::sdebugsln("Providing allocation from iterator"); + Some(&unsafe { - *((self.ptr as usize + (size_of::() * self.idx as usize)) + *((self.ptr as usize + (size_of::() * (self.idx as usize-1))) as *const Allocation) } as *const Allocation as *mut Allocation) } @@ -68,6 +81,15 @@ const EXTEND_ALLOCATION_ALLOCATION_UNUSED: i16 = -5; /// The allocation provided to [MemoryMapAlloc::extend_allocation], if extended, would extend into another allocation. 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(" allocations")?; + Ok(()) + } +} + impl<'a> MemoryMapAlloc<'a> { /// Creates a new [MemoryMapAlloc]. Please call this method instead of creating it manually! /// This method uses the memory mapping to @@ -82,6 +104,8 @@ impl<'a> MemoryMapAlloc<'a> { }; out.memory_map.reset_iter(); for mapping in &mut *out.memory_map { + mapping.output(); + crate::arch::output::sdebugsnpln(""); if mapping.len < (size_of::() * 32) as u64 { continue; } @@ -125,12 +149,17 @@ impl<'a> MemoryMapAlloc<'a> { used: true, addr: out.allocations as usize as u64, len: (size_of::() * 32) as u64, - num_allocations: 0 + num_allocations: 1 } } Ok(out) } + /// Returns the number of allocations. + pub fn number_of_allocations(&self) -> u64 { + unsafe { *self.allocationheader }.num_allocations + } + /// Creates a [AllocationIter] to iterate over the current allocations. fn allocations_iter(&self) -> AllocationIter { AllocationIter { @@ -142,17 +171,12 @@ impl<'a> MemoryMapAlloc<'a> { /// Add an allocation to [MemoryMapAlloc::allocations]. It will overwrite allocations with `used` set to false. fn add_allocation(&self, allocation: Allocation) -> Result<(), crate::Error<'static>> { - let mut created_allocation = false; for alloc in self.allocations_iter() { if !unsafe { *alloc }.used { unsafe { (*alloc) = allocation } - created_allocation = true; - break; + return Ok(()); } } - if created_allocation { - return Ok(()); - } unsafe { *self.allocationheader }.num_allocations += 1; @@ -168,7 +192,7 @@ impl<'a> MemoryMapAlloc<'a> { )); } - let res = self.extend_allocation(0, size_of::() as u64); + let res = self.extend_allocation_header(size_of::() as u64); if let Err(err) = res { unsafe { *self.allocationheader }.num_allocations -= 1; return Err(err); @@ -186,7 +210,6 @@ impl<'a> MemoryMapAlloc<'a> { /// Extend an allocation. This has numerous checks, so please use this /// instead of manually changing [Allocation::len]! - #[inline(always)] fn extend_allocation(&self, idx: u64, by: u64) -> Result<(), crate::Error<'static>> { if idx > unsafe { *self.allocationheader }.num_allocations { return Err(crate::Error::new( @@ -220,11 +243,35 @@ impl<'a> MemoryMapAlloc<'a> { Ok(()) } + /// Extend the allocation header. This has numerous checks, so please use this + /// instead of manually changing [AllocationHeader::len]! + fn extend_allocation_header(&self, by: u64) -> Result<(), crate::Error<'static>> { + let alloc = self.allocationheader; + + if self.check_range( + (unsafe { *alloc }.addr + unsafe { *alloc }.len) + ..(unsafe { *alloc }.addr + unsafe { *alloc }.len + by), + ) { + return Err(crate::Error::new( + "the allocation header, if extended, would extend into another allocation", + EXTEND_ALLOCATION_OTHER_ALLOCATION, + )); + } + + unsafe { + (*alloc).len += by; + } + Ok(()) + } + /// 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) { + return true; + } for ele in self.allocations_iter() { let alloc = unsafe { *ele }; - if addr > alloc.addr && addr < alloc.addr + alloc.len { + if addr >= alloc.addr && addr < alloc.addr + alloc.len { return true; } } @@ -255,7 +302,7 @@ unsafe impl<'a> GlobalAlloc for MemoryMapAlloc<'a> { if result.is_err() { return null_mut(); } - result.unwrap().as_mut_ptr() as *mut u8 + result.unwrap().as_mut_ptr() } unsafe fn dealloc(&self, ptr: *mut u8, layout: core::alloc::Layout) { unsafe { @@ -299,11 +346,24 @@ unsafe impl<'a> Allocator for MemoryMapAlloc<'a> { } 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) { + 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 { + break; + } + continue; } } + if addr == 0 { + unsafe { + LAST_MEMMAP_ERR = Err(crate::Error::new( + "Free memory of the correct size and alignment couldn't be found", + FREE_MEMORY_UNAVAILABLE, + )) + } + return Err(core::alloc::AllocError {}); + } 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 {}); @@ -314,13 +374,10 @@ unsafe impl<'a> Allocator for MemoryMapAlloc<'a> { layout.size(), )) } + unsafe fn deallocate(&self, ptr: core::ptr::NonNull, _layout: core::alloc::Layout) { unsafe { LAST_MEMMAP_ERR = Ok(()) } let addr = ptr.addr().get() as u64; - if !self.check_addr(addr) { // Memory not allocated, something is up - unsafe { LAST_MEMMAP_ERR = Err(crate::Error::new("memory not allocated", MEMORY_NOT_ALLOCATED)) } - return; - } if self.allocations == core::ptr::null_mut() { unsafe { LAST_MEMMAP_ERR = Err(crate::Error::new( @@ -330,14 +387,21 @@ unsafe impl<'a> Allocator for MemoryMapAlloc<'a> { } return; } + crate::arch::output::sdebugbln(&crate::u64_as_u8_slice(unsafe { *self.allocationheader }.num_allocations)); for allocation in self.allocations_iter() { - if !unsafe { *allocation }.used { + crate::arch::output::sdebugsln("Allocation"); + let alloc = unsafe { *allocation }.clone(); + if !alloc.used { continue; } - if unsafe { *allocation }.addr == addr { + crate::arch::output::sdebugsln("Used"); + if alloc.addr == addr { unsafe { *allocation }.used = false; - break; + return; } } + // 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)) } + return; } } diff --git a/kernel/src/include/mod.rs b/kernel/src/kernel/mod.rs similarity index 80% rename from kernel/src/include/mod.rs rename to kernel/src/kernel/mod.rs index 50ecfd6..fc9ca62 100644 --- a/kernel/src/include/mod.rs +++ b/kernel/src/kernel/mod.rs @@ -1,6 +1,7 @@ //! This provides raw methods for internal kernel usage for the Aphrodite kernel. See aphrodite_user for userspace. #![no_std] #![warn(missing_docs)] +// tidy-alphabetical-start #![feature(ptr_metadata)] #![feature(const_trait_impl)] #![feature(f128)] @@ -8,26 +9,28 @@ #![feature(allocator_api)] #![feature(slice_ptr_get)] #![feature(nonnull_provenance)] +#![feature(min_specialization)] +#![allow(internal_features)] +#![feature(core_intrinsics)] +// tidy-alphabetical-end -mod constants; -mod util; -pub mod multiboot2; +pub mod indep_boot_entry; pub mod arch; -mod errors; -pub mod _entry; -mod traits; -pub mod output; pub mod boot; -pub mod psfont; -pub mod display; pub mod cmdline; +mod constants; +pub mod display; +mod errors; pub mod mem; +pub mod multiboot2; +pub mod output; +pub mod psfont; +mod traits; +mod util; #[macro_use] mod cfg; -pub use cfg::*; - #[allow(unused_imports)] // if there are no constants, then it gives a warning pub use constants::*; @@ -35,4 +38,4 @@ pub use errors::*; pub use util::*; #[allow(unused_imports)] // if there are no traits, then it gives a warning -pub use traits::*; \ No newline at end of file +pub use traits::*; diff --git a/kernel/src/include/multiboot2.rs b/kernel/src/kernel/multiboot2.rs similarity index 97% rename from kernel/src/include/multiboot2.rs rename to kernel/src/kernel/multiboot2.rs index ec603ab..e048353 100644 --- a/kernel/src/include/multiboot2.rs +++ b/kernel/src/kernel/multiboot2.rs @@ -91,17 +91,11 @@ pub struct MemoryMap { pub entry_size: u32, /// All sections. pub sections: &'static [crate::boot::MemoryMapping], - /// Iterator's index. - pub idx: usize, } impl MemoryMap { - pub fn reset_iter(&mut self) { - self.idx = 0; - } + /// The size of allocatable memory in bytes. pub fn mem_size(&mut self) -> u64 { - let curr_idx = self.idx; - self.reset_iter(); let mut out = 0u64; for ele in self.sections { if ele.mem_type == crate::boot::MemoryType::Free { @@ -112,7 +106,6 @@ impl MemoryMap { } } } - self.idx = curr_idx; out } } diff --git a/kernel/src/include/output.rs b/kernel/src/kernel/output.rs similarity index 99% rename from kernel/src/include/output.rs rename to kernel/src/kernel/output.rs index 5283a15..77771e4 100644 --- a/kernel/src/include/output.rs +++ b/kernel/src/kernel/output.rs @@ -3,6 +3,7 @@ use paste::paste; use crate::display::COLOR_DEFAULT; +/// The position to output stuff to. static mut OUTPUT_TERM_POSITION: (u32, u32) = (0, 0); macro_rules! message_funcs { diff --git a/kernel/src/include/psfont.rs b/kernel/src/kernel/psfont.rs similarity index 100% rename from kernel/src/include/psfont.rs rename to kernel/src/kernel/psfont.rs diff --git a/kernel/src/include/test.rs b/kernel/src/kernel/test.rs similarity index 100% rename from kernel/src/include/test.rs rename to kernel/src/kernel/test.rs diff --git a/kernel/src/include/traits.rs b/kernel/src/kernel/traits.rs similarity index 100% rename from kernel/src/include/traits.rs rename to kernel/src/kernel/traits.rs diff --git a/kernel/src/include/util.rs b/kernel/src/kernel/util.rs similarity index 79% rename from kernel/src/include/util.rs rename to kernel/src/kernel/util.rs index c90a7cf..c54b448 100644 --- a/kernel/src/include/util.rs +++ b/kernel/src/kernel/util.rs @@ -90,56 +90,74 @@ pub const fn u64_as_u8_slice(mut value: u64) -> [u8; 20] { buf } -/// Converts an &mut \[u8] to a i16. `value` is clobbered. -pub fn str_as_i16(mut value: &mut [u8]) -> i16 { +/// Converts an &mut \[u8] to a i16. +pub fn str_as_i16(mut value: &[u8]) -> i16 { let mut out = 0i16; let negative = core::str::from_utf8(value).unwrap().starts_with("-"); if negative { - value = &mut value[1..]; + value = &value[1..]; } - value.reverse(); for byte in value { let byte = *byte; - if byte == b'_' { + if byte < b'0' || byte > b'9' { continue; } out *= 10; out += (byte-b'0') as i16; } - if negative { - out = -out; + + let mut reversed = 0; + + while out != 0 { + reversed = reversed * 10 + out % 10; + out /= 10; } - out + + reversed } -/// Converts an &mut \[u8] to a u32. `value` is clobbered. -pub fn str_as_u32(value: &mut [u8]) -> u32 { +/// Converts an &mut \[u8] to a u32. +pub fn str_as_u32(value: &[u8]) -> u32 { let mut out = 0u32; - value.reverse(); for byte in value { let byte = *byte; - if byte == b'_' { + if byte < b'0' || byte > b'9' { continue; } out *= 10; out += (byte-b'0') as u32; } - out + + let mut reversed = 0; + + while out != 0 { + reversed = reversed * 10 + out % 10; + out /= 10; + } + + reversed } -/// Converts an &mut \[u8] to a u128. `value` is clobbered. -pub fn str_as_u128(value: &mut [u8]) -> u128 { +/// Converts an &mut \[u8] to a u128. +pub fn str_as_u128(value: &[u8]) -> u128 { let mut out = 0u128; - value.reverse(); for byte in value { let byte = *byte; - if byte == b'_' { + if byte < b'0' || byte > b'9' { continue; } out *= 10; out += (byte-b'0') as u128; } - out + + let mut reversed = 0; + + while out != 0 { + reversed = reversed * 10 + out % 10; + out /= 10; + } + + reversed } /// Converts an &mut \[u8] to a u64. diff --git a/kernel/src/proc_macros/mod.rs b/kernel/src/proc_macros/mod.rs new file mode 100644 index 0000000..8b73d29 --- /dev/null +++ b/kernel/src/proc_macros/mod.rs @@ -0,0 +1,59 @@ +use proc_macro::TokenStream; +use quote::{quote_spanned, ToTokens}; +use syn::{parse::{Parse, ParseStream}, spanned::Spanned, ItemFn, Signature, Token}; + +struct KernelItemNameInput { + item: aphrodite_common::KernelItem +} + +impl Parse for KernelItemNameInput { + fn parse(input: ParseStream) -> syn::Result { + let item: aphrodite_common::KernelItem = 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); + } + variadic.to_tokens(tokens); + } + }); + signature.output.to_tokens(&mut (*tokens).clone().into()); + signature.generics.where_clause.to_tokens(&mut (*tokens).clone().into()); +} + +fn to_token_stream(signature: Signature) -> TokenStream { + let mut tokens = proc_macro::TokenStream::new(); + to_tokens(signature, &mut tokens); + tokens.into() +} + +/// 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 input_fn: ItemFn = 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. + #[allow(non_upper_case_globals)] + pub const #item_name: #fn_sig = #fn_name; + + #input_fn + }).into() +} \ No newline at end of file