Large backlog of changes; been working on this commit for a few weeks

This commit is contained in:
Arthur Beck 2025-02-11 07:00:31 -06:00
parent da73321233
commit a2311366f2
35 changed files with 463 additions and 146 deletions

View file

@ -2,6 +2,8 @@
"rust-analyzer.cargo.allTargets": false, "rust-analyzer.cargo.allTargets": false,
"rust-analyzer.check.allTargets": false, "rust-analyzer.check.allTargets": false,
"rust-analyzer.linkedProjects": [ "rust-analyzer.linkedProjects": [
"kernel/Cargo.toml" "kernel/Cargo.toml",
] "kernel/aphrodite_proc_macros/Cargo.toml",
"kernel/aphrodite_common/Cargo.toml"
],
} }

View file

@ -5,3 +5,4 @@ magic_break: enabled=1
ata0-master: type=cdrom, path=../kernel/aphrodite.iso, status=inserted ata0-master: type=cdrom, path=../kernel/aphrodite.iso, status=inserted
boot: cdrom boot: cdrom
memory: guest=512, host=512

26
emulation/bx_enh_dbg.ini Normal file
View file

@ -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

View file

@ -5,6 +5,7 @@ edition = "2024"
[dependencies] [dependencies]
paste = "1.0.15" paste = "1.0.15"
aphrodite_proc_macros = { path = "./aphrodite_proc_macros"}
[profile.release] [profile.release]
opt-level = "z" opt-level = "z"
@ -15,15 +16,11 @@ panic = "abort"
[[bin]] [[bin]]
name = "entrypoint_x86" name = "entrypoint_x86"
path = "src/internal/arch/x86_asmp/entry.rs" path = "src/arch_boot_entry/x86.rs"
[[bin]]
name = "main"
path = "src/internal/main.rs"
[lib] [lib]
name = "aphrodite" name = "aphrodite"
path = "src/include/mod.rs" path = "src/kernel/mod.rs"
[[test]] [[test]]
name = "test_aphrodite" name = "test_aphrodite"

View file

@ -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"

View file

@ -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"

View file

@ -3,9 +3,8 @@
( (
set -e set -e
if [[ -n "$KERNEL_DIR" ]]; then
export KERNEL_DIR=$(readlink -e .) export KERNEL_DIR=$(readlink -e .)
fi
DIR="${BASH_SOURCE%/*}" DIR="${BASH_SOURCE%/*}"
if [[ ! -d "$DIR" ]]; then DIR="$PWD"; fi if [[ ! -d "$DIR" ]]; then DIR="$PWD"; fi
@ -40,15 +39,11 @@
for target in $TARGETS; do for target in $TARGETS; do
real_target=${!target} real_target=${!target}
cargo build --target "$real_target" --release -Zbuild-std --bin entrypoint_$target cargo build --target "$real_target" --release -Zbuild-std --bin entrypoint_$target
done cp target/i686-unknown-none/release/entrypoint_$target kernel.flat
# build the kernel's entrypoint
cp target/i686-unknown-none/release/entrypoint kernel.flat if [[ "$CONFIG_BUILD_GRUB" = "true" ]]; then
# copy it out rm -rf grub aphrodite-grub.iso
if [[ "$target" = "x86" ]]; then
rm -rf grub aphrodite.iso aphrodite-grub.iso
if [[ $CONFIG_BUILD_GRUB = "true" ]]; then
cp -r ./grub_template ./grub cp -r ./grub_template ./grub
cp kernel.flat ./grub/boot/aphrodite.kernel cp kernel.flat ./grub/boot/aphrodite.kernel
@ -58,6 +53,8 @@
grub-mkrescue -o aphrodite-grub.iso grub grub-mkrescue -o aphrodite-grub.iso grub
cp aphrodite-grub.iso aphrodite.iso cp aphrodite-grub.iso aphrodite.iso
fi fi
fi
done
reset_version_vars reset_version_vars
) )

View file

@ -7,9 +7,12 @@
#![allow(static_mut_refs)] #![allow(static_mut_refs)]
#![feature(ptr_metadata)] #![feature(ptr_metadata)]
#![feature(cfg_match)] #![feature(cfg_match)]
#![feature(formatting_options)]
use core::{arch::asm, ffi::CStr, panic::PanicInfo}; 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::multiboot2::{FramebufferInfo, MemoryMap, MemorySection, RawMemoryMap, RootTag, Tag};
use aphrodite::arch::output::*; use aphrodite::arch::output::*;
use aphrodite::arch::egatext as egatext; use aphrodite::arch::egatext as egatext;
@ -40,7 +43,6 @@ static mut MM: MemoryMap = MemoryMap {
entry_size: 0, entry_size: 0,
version: 0, version: 0,
sections: &[], sections: &[],
idx: 0,
}; };
static mut FBI: aphrodite::arch::egatext::FramebufferInfo = aphrodite::arch::egatext::FramebufferInfo { 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 if current_tag.tag_len < 16 { // Unexpected size, something is probably up
panic!("size of memory map tag < 16"); panic!("size of memory map tag < 16");
} }
let rawmemorymap: *const RawMemoryMap = core::ptr::from_raw_parts( let rawmemorymap: *mut RawMemoryMap = core::ptr::from_raw_parts_mut(
ptr as *const u8, (current_tag.tag_len / *((ptr + 8usize) as *const u32)) as usize 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 // 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 // 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::<MemoryMapping>::into(*ele))
}
MM = MemoryMap { MM = MemoryMap {
version: (*rawmemorymap).entry_version, version: (*rawmemorymap).entry_version,
entry_size: (*rawmemorymap).entry_size, entry_size: (*rawmemorymap).entry_size,
sections: &*core::ptr::from_raw_parts((&(*rawmemorymap).sections[0]) as &MemorySection, (*rawmemorymap).sections.len()), sections: core::mem::transmute(memorysections),
idx: 0
}; };
let mm2 = aphrodite::boot::MemoryMap { let mm2 = aphrodite::boot::MemoryMap {
len: MM.sections.len() as u64, 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();
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")] #[unsafe(link_section = ".panic")]
#[panic_handler] #[panic_handler]
#[cfg(not(CONFIG_HALT_ON_PANIC = "false"))] #[cfg(not(CONFIG_HALT_ON_PANIC = "false"))]
fn halt_on_panic(info: &PanicInfo) -> ! { fn halt_on_panic(info: &PanicInfo) -> ! {
use core::fmt::FormattingOptions;
if info.location().is_some() { if info.location().is_some() {
sfatals("Panic at "); sfatals("Panic at ");
sfatalsnp(info.location().unwrap().file()); sfatalsnp(info.location().unwrap().file());
@ -286,10 +296,8 @@ fn halt_on_panic(info: &PanicInfo) -> ! {
} else { } else {
sfatals("Panic: "); sfatals("Panic: ");
} }
let message = info.message().as_str().unwrap_or(""); let mut formatter = FormattingOptions::new().create_formatter(unsafe { &mut FBI });
if message != "" { let _ = info.message().fmt(&mut formatter);
sfatalsnpln(message);
}
aphrodite::arch::interrupts::disable_interrupts(); aphrodite::arch::interrupts::disable_interrupts();
unsafe { unsafe {
asm!("hlt", options(noreturn)); asm!("hlt", options(noreturn));
@ -314,6 +322,8 @@ fn spin_on_panic(info: &PanicInfo) -> ! {
let message = info.message().as_str().unwrap_or(""); let message = info.message().as_str().unwrap_or("");
if message != "" { if message != "" {
sfatalsnpln(message); sfatalsnpln(message);
} else {
sfatalsnp("\n");
} }
aphrodite::arch::interrupts::disable_interrupts(); aphrodite::arch::interrupts::disable_interrupts();
loop {} loop {}

37
kernel/src/common/mod.rs Normal file
View file

@ -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<Self> {
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"))
}
}

View file

@ -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 {}
}

View file

@ -1,5 +1,5 @@
//! Arch-specific code. This module re-exports all code from the architecture being used. //! Arch-specific code. This module re-exports all code from the architecture being used.
mod x86_asmp; mod x86;
pub use x86_asmp::*; pub use x86::*;

View file

@ -25,6 +25,13 @@ pub const ERR_INVALID_X: i16 = -1;
/// Returned when the provided position is invalid in the Y direction. /// Returned when the provided position is invalid in the Y direction.
pub const ERR_INVALID_Y: i16 = -2; 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 { impl crate::display::TextDisplay for FramebufferInfo {
/// Writes a character to the screen. /// Writes a character to the screen.
fn write_char(&self, mut pos: (u32, u32), char: u8, color: Color) -> Result<(), crate::Error<'static>> { fn write_char(&self, mut pos: (u32, u32), char: u8, color: Color) -> Result<(), crate::Error<'static>> {

View file

@ -9,7 +9,7 @@
pub enum MemoryType { pub enum MemoryType {
/// Free RAM with no use. /// Free RAM with no use.
Free, Free,
/// RAM used by the kernel /// RAM where the kernel is loaded.
Kernel, Kernel,
/// Reserved by something. /// Reserved by something.
Reserved, Reserved,
@ -26,6 +26,31 @@ pub enum MemoryType {
Permanent, 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]. /// A single memory mapping for [MemoryMap].
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub struct MemoryMapping { pub struct MemoryMapping {
@ -37,10 +62,26 @@ pub struct MemoryMapping {
pub len: u64, 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)] #[derive(Clone, Copy)]
pub struct MemoryMap { pub struct MemoryMap {
/// The number of [MemoryMapping]s in this MemoryMap.
pub len: u64, pub len: u64,
/// The size of memory in pages.
pub size_pages: u64, pub size_pages: u64,
/// The size of one page.
pub page_size: u64, pub page_size: u64,
/// All sections. /// All sections.
@ -51,12 +92,11 @@ pub struct MemoryMap {
} }
impl MemoryMap { impl MemoryMap {
pub fn len(&self) -> u64 { /// Resets the index of the iterator (sets self.idx to 0).
self.sections.len() as u64
}
pub fn reset_iter(&mut self) { pub fn reset_iter(&mut self) {
self.idx = 0; self.idx = 0;
} }
/// The size of allocatable memory in bytes.
pub fn mem_size(&mut self) -> u64 { pub fn mem_size(&mut self) -> u64 {
let curr_idx = self.idx; let curr_idx = self.idx;
self.reset_iter(); self.reset_iter();
@ -87,10 +127,11 @@ impl core::iter::Iterator for MemoryMap {
type Item = MemoryMapping; type Item = MemoryMapping;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
self.idx += 1; self.idx += 1;
if self.sections.len()<=self.idx-1 { if self.sections.len() <= self.idx - 1 {
self.reset_iter();
return None; return None;
} }
Some(self.sections[self.idx-1].into()) Some(self.sections[self.idx - 1].into())
} }
} }

View file

@ -1,5 +1,6 @@
//! Config-related stuff. //! Config-related stuff.
//!
/// C
#[macro_export] #[macro_export]
macro_rules! cfg_int { macro_rules! cfg_int {
($cfg:literal, $type:ident) => { ($cfg:literal, $type:ident) => {

View file

@ -14,7 +14,7 @@ pub const COLOR_BLACK: Color = (0, true);
pub const COLOR_DEFAULT: Color = (1, true); pub const COLOR_DEFAULT: Color = (1, true);
/// Some form of display that can be written to with text. /// 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. /// Writes a single character to the specified position.
fn write_char(&self, pos: (u32, u32), char: u8, color: Color) -> Result<(), crate::Error<'static>>; fn write_char(&self, pos: (u32, u32), char: u8, color: Color) -> Result<(), crate::Error<'static>>;
/// Gets the size of the screen. /// Gets the size of the screen.

View file

@ -17,10 +17,11 @@ impl<'a> Error<'a> {
} }
impl Error<'_> { impl Error<'_> {
/// Display the contents of the error on a [TextDisplay].
pub fn display_np(&self, display: &dyn TextDisplay) { pub fn display_np(&self, display: &dyn TextDisplay) {
crate::output::terrorbnp(&crate::i16_as_u8_slice(self.code), display); crate::output::terrorbnp(&crate::i16_as_u8_slice(self.code), display).unwrap();
crate::output::terrorsnp(": ", display); crate::output::terrorsnp(": ", display).unwrap();
crate::output::terrorsnpln(self.message, display); crate::output::terrorsnpln(self.message, display).unwrap();
} }
} }

View file

@ -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 {}
}

View file

@ -1,26 +1,34 @@
//! Memory allocation. //! Memory allocation.
use core::{ use core::{
alloc::{Allocator, GlobalAlloc}, alloc::{Allocator, GlobalAlloc}, fmt::Debug, num::NonZero, ops::Range, ptr::{null_mut, NonNull}
num::NonZero,
ops::Range,
ptr::{NonNull, null_mut},
}; };
use crate::boot::MemoryType; use crate::boot::MemoryType;
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
struct Allocation { 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, pub used: bool,
/// The starting address of the allocation.
pub addr: u64, pub addr: u64,
/// The length of the allocation.
pub len: u64, pub len: u64,
} }
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
struct AllocationHeader { struct AllocationHeader {
/// Whether this allocation table is used. Kept for parity with [Allocation]s.
#[allow(dead_code)]
pub used: bool, pub used: bool,
/// The starting address of the allocation table.
#[allow(dead_code)]
pub addr: u64, pub addr: u64,
/// The length in bytes of the allocation table.
pub len: u64, pub len: u64,
/// The number of allocations in the allocation table.
pub num_allocations: u64, pub num_allocations: u64,
} }
@ -33,11 +41,16 @@ struct AllocationIter {
impl Iterator for AllocationIter { impl Iterator for AllocationIter {
type Item = *mut Allocation; type Item = *mut Allocation;
fn next(&mut self) -> Option<<Self as Iterator>::Item> { fn next(&mut self) -> Option<<Self as Iterator>::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; return None;
} }
crate::arch::output::sdebugsln("Providing allocation from iterator");
Some(&unsafe { Some(&unsafe {
*((self.ptr as usize + (size_of::<Allocation>() * self.idx as usize)) *((self.ptr as usize + (size_of::<Allocation>() * (self.idx as usize-1)))
as *const Allocation) as *const Allocation)
} as *const Allocation as *mut 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. /// The allocation provided to [MemoryMapAlloc::extend_allocation], if extended, would extend into another allocation.
const EXTEND_ALLOCATION_OTHER_ALLOCATION: i16 = -6; 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> { impl<'a> MemoryMapAlloc<'a> {
/// Creates a new [MemoryMapAlloc]. Please call this method instead of creating it manually! /// Creates a new [MemoryMapAlloc]. Please call this method instead of creating it manually!
/// This method uses the memory mapping to /// This method uses the memory mapping to
@ -82,6 +104,8 @@ impl<'a> MemoryMapAlloc<'a> {
}; };
out.memory_map.reset_iter(); out.memory_map.reset_iter();
for mapping in &mut *out.memory_map { for mapping in &mut *out.memory_map {
mapping.output();
crate::arch::output::sdebugsnpln("");
if mapping.len < (size_of::<Allocation>() * 32) as u64 { if mapping.len < (size_of::<Allocation>() * 32) as u64 {
continue; continue;
} }
@ -125,12 +149,17 @@ impl<'a> MemoryMapAlloc<'a> {
used: true, used: true,
addr: out.allocations as usize as u64, addr: out.allocations as usize as u64,
len: (size_of::<Allocation>() * 32) as u64, len: (size_of::<Allocation>() * 32) as u64,
num_allocations: 0 num_allocations: 1
} }
} }
Ok(out) 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. /// Creates a [AllocationIter] to iterate over the current allocations.
fn allocations_iter(&self) -> AllocationIter { fn allocations_iter(&self) -> AllocationIter {
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. /// 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>> { fn add_allocation(&self, allocation: Allocation) -> Result<(), crate::Error<'static>> {
let mut created_allocation = false;
for alloc in self.allocations_iter() { for alloc in self.allocations_iter() {
if !unsafe { *alloc }.used { if !unsafe { *alloc }.used {
unsafe { (*alloc) = allocation } unsafe { (*alloc) = allocation }
created_allocation = true;
break;
}
}
if created_allocation {
return Ok(()); return Ok(());
} }
}
unsafe { *self.allocationheader }.num_allocations += 1; unsafe { *self.allocationheader }.num_allocations += 1;
@ -168,7 +192,7 @@ impl<'a> MemoryMapAlloc<'a> {
)); ));
} }
let res = self.extend_allocation(0, size_of::<Allocation>() as u64); let res = self.extend_allocation_header(size_of::<Allocation>() as u64);
if let Err(err) = res { if let Err(err) = res {
unsafe { *self.allocationheader }.num_allocations -= 1; unsafe { *self.allocationheader }.num_allocations -= 1;
return Err(err); return Err(err);
@ -186,7 +210,6 @@ impl<'a> MemoryMapAlloc<'a> {
/// Extend an allocation. This has numerous checks, so please use this /// Extend an allocation. This has numerous checks, so please use this
/// instead of manually changing [Allocation::len]! /// instead of manually changing [Allocation::len]!
#[inline(always)]
fn extend_allocation(&self, idx: u64, by: u64) -> Result<(), crate::Error<'static>> { fn extend_allocation(&self, idx: u64, by: u64) -> Result<(), crate::Error<'static>> {
if idx > unsafe { *self.allocationheader }.num_allocations { if idx > unsafe { *self.allocationheader }.num_allocations {
return Err(crate::Error::new( return Err(crate::Error::new(
@ -220,11 +243,35 @@ impl<'a> MemoryMapAlloc<'a> {
Ok(()) 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. /// Check to see if any allocations contain the given address. Returns true if so.
fn check_addr(&self, addr: u64) -> bool { 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() { for ele in self.allocations_iter() {
let alloc = unsafe { *ele }; let alloc = unsafe { *ele };
if addr > alloc.addr && addr < alloc.addr + alloc.len { if addr >= alloc.addr && addr < alloc.addr + alloc.len {
return true; return true;
} }
} }
@ -255,7 +302,7 @@ unsafe impl<'a> GlobalAlloc for MemoryMapAlloc<'a> {
if result.is_err() { if result.is_err() {
return null_mut(); 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 fn dealloc(&self, ptr: *mut u8, layout: core::alloc::Layout) {
unsafe { unsafe {
@ -299,10 +346,23 @@ unsafe impl<'a> Allocator for MemoryMapAlloc<'a> {
} }
if allocatable { if allocatable {
addr = mapping.start+mapping.len-layout.size() as 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) { 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 -= 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 }) { if let Err(err) = self.add_allocation(Allocation { used: true, addr, len: layout.size() as u64 }) {
unsafe { LAST_MEMMAP_ERR = Err(err) } unsafe { LAST_MEMMAP_ERR = Err(err) }
@ -314,13 +374,10 @@ unsafe impl<'a> Allocator for MemoryMapAlloc<'a> {
layout.size(), layout.size(),
)) ))
} }
unsafe fn deallocate(&self, ptr: core::ptr::NonNull<u8>, _layout: core::alloc::Layout) { unsafe fn deallocate(&self, ptr: core::ptr::NonNull<u8>, _layout: core::alloc::Layout) {
unsafe { LAST_MEMMAP_ERR = Ok(()) } unsafe { LAST_MEMMAP_ERR = Ok(()) }
let addr = ptr.addr().get() as u64; 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() { if self.allocations == core::ptr::null_mut() {
unsafe { unsafe {
LAST_MEMMAP_ERR = Err(crate::Error::new( LAST_MEMMAP_ERR = Err(crate::Error::new(
@ -330,14 +387,21 @@ unsafe impl<'a> Allocator for MemoryMapAlloc<'a> {
} }
return; return;
} }
crate::arch::output::sdebugbln(&crate::u64_as_u8_slice(unsafe { *self.allocationheader }.num_allocations));
for allocation in self.allocations_iter() { for allocation in self.allocations_iter() {
if !unsafe { *allocation }.used { crate::arch::output::sdebugsln("Allocation");
let alloc = unsafe { *allocation }.clone();
if !alloc.used {
continue; continue;
} }
if unsafe { *allocation }.addr == addr { crate::arch::output::sdebugsln("Used");
if alloc.addr == addr {
unsafe { *allocation }.used = false; 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;
} }
} }

View file

@ -1,6 +1,7 @@
//! This provides raw methods for internal kernel usage for the Aphrodite kernel. See aphrodite_user for userspace. //! This provides raw methods for internal kernel usage for the Aphrodite kernel. See aphrodite_user for userspace.
#![no_std] #![no_std]
#![warn(missing_docs)] #![warn(missing_docs)]
// tidy-alphabetical-start
#![feature(ptr_metadata)] #![feature(ptr_metadata)]
#![feature(const_trait_impl)] #![feature(const_trait_impl)]
#![feature(f128)] #![feature(f128)]
@ -8,26 +9,28 @@
#![feature(allocator_api)] #![feature(allocator_api)]
#![feature(slice_ptr_get)] #![feature(slice_ptr_get)]
#![feature(nonnull_provenance)] #![feature(nonnull_provenance)]
#![feature(min_specialization)]
#![allow(internal_features)]
#![feature(core_intrinsics)]
// tidy-alphabetical-end
mod constants; pub mod indep_boot_entry;
mod util;
pub mod multiboot2;
pub mod arch; pub mod arch;
mod errors;
pub mod _entry;
mod traits;
pub mod output;
pub mod boot; pub mod boot;
pub mod psfont;
pub mod display;
pub mod cmdline; pub mod cmdline;
mod constants;
pub mod display;
mod errors;
pub mod mem; pub mod mem;
pub mod multiboot2;
pub mod output;
pub mod psfont;
mod traits;
mod util;
#[macro_use] #[macro_use]
mod cfg; mod cfg;
pub use cfg::*;
#[allow(unused_imports)] // if there are no constants, then it gives a warning #[allow(unused_imports)] // if there are no constants, then it gives a warning
pub use constants::*; pub use constants::*;

View file

@ -91,17 +91,11 @@ pub struct MemoryMap {
pub entry_size: u32, pub entry_size: u32,
/// All sections. /// All sections.
pub sections: &'static [crate::boot::MemoryMapping], pub sections: &'static [crate::boot::MemoryMapping],
/// Iterator's index.
pub idx: usize,
} }
impl MemoryMap { impl MemoryMap {
pub fn reset_iter(&mut self) { /// The size of allocatable memory in bytes.
self.idx = 0;
}
pub fn mem_size(&mut self) -> u64 { pub fn mem_size(&mut self) -> u64 {
let curr_idx = self.idx;
self.reset_iter();
let mut out = 0u64; let mut out = 0u64;
for ele in self.sections { for ele in self.sections {
if ele.mem_type == crate::boot::MemoryType::Free { if ele.mem_type == crate::boot::MemoryType::Free {
@ -112,7 +106,6 @@ impl MemoryMap {
} }
} }
} }
self.idx = curr_idx;
out out
} }
} }

View file

@ -3,6 +3,7 @@
use paste::paste; use paste::paste;
use crate::display::COLOR_DEFAULT; use crate::display::COLOR_DEFAULT;
/// The position to output stuff to.
static mut OUTPUT_TERM_POSITION: (u32, u32) = (0, 0); static mut OUTPUT_TERM_POSITION: (u32, u32) = (0, 0);
macro_rules! message_funcs { macro_rules! message_funcs {

View file

@ -90,56 +90,74 @@ pub const fn u64_as_u8_slice(mut value: u64) -> [u8; 20] {
buf buf
} }
/// Converts an &mut \[u8] to a i16. `value` is clobbered. /// Converts an &mut \[u8] to a i16.
pub fn str_as_i16(mut value: &mut [u8]) -> i16 { pub fn str_as_i16(mut value: &[u8]) -> i16 {
let mut out = 0i16; let mut out = 0i16;
let negative = core::str::from_utf8(value).unwrap().starts_with("-"); let negative = core::str::from_utf8(value).unwrap().starts_with("-");
if negative { if negative {
value = &mut value[1..]; value = &value[1..];
} }
value.reverse();
for byte in value { for byte in value {
let byte = *byte; let byte = *byte;
if byte == b'_' { if byte < b'0' || byte > b'9' {
continue; continue;
} }
out *= 10; out *= 10;
out += (byte-b'0') as i16; 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. /// Converts an &mut \[u8] to a u32.
pub fn str_as_u32(value: &mut [u8]) -> u32 { pub fn str_as_u32(value: &[u8]) -> u32 {
let mut out = 0u32; let mut out = 0u32;
value.reverse();
for byte in value { for byte in value {
let byte = *byte; let byte = *byte;
if byte == b'_' { if byte < b'0' || byte > b'9' {
continue; continue;
} }
out *= 10; out *= 10;
out += (byte-b'0') as u32; 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. /// Converts an &mut \[u8] to a u128.
pub fn str_as_u128(value: &mut [u8]) -> u128 { pub fn str_as_u128(value: &[u8]) -> u128 {
let mut out = 0u128; let mut out = 0u128;
value.reverse();
for byte in value { for byte in value {
let byte = *byte; let byte = *byte;
if byte == b'_' { if byte < b'0' || byte > b'9' {
continue; continue;
} }
out *= 10; out *= 10;
out += (byte-b'0') as u128; 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. /// Converts an &mut \[u8] to a u64.

View file

@ -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<Self> {
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() {
<Token![,]>::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()
}