Squashed some bugs; implemented first iteration of kernel items

This commit is contained in:
Arthur Beck 2025-02-11 21:30:43 +00:00
parent a2311366f2
commit 04ee0a1cb2
13 changed files with 245 additions and 111 deletions

View file

@ -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"
],
}

View file

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

View file

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

View file

@ -1,3 +1,3 @@
#!/bin/bash
RUSTFLAGS='-Clink-arg=--script=link.x' cargo expand --target i686-unknown-none.json --release -Zbuild-std --bin entrypoint
RUSTFLAGS='-Clink-arg=--script=link.x' cargo expand --target i686-unknown-none.json --release -Zbuild-std --bin entrypoint_x86

View file

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

View file

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

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

View file

@ -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::<Allocation>() * (self.idx as usize-1)))
*((self.ptr as usize + (size_of::<Allocation>() * (self.idx as usize - 1)))
as *const Allocation)
} as *const Allocation as *mut Allocation)
}
}
static mut ALLOCATOR: MaybeUninit<MemoryMapAlloc<'static>> = MaybeUninit::uninit();
static mut ALLOCATOR_MEMMAP: MaybeUninit<MemoryMap> = 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::<AllocationHeader>()),
core::ptr::without_provenance_mut::<()>(
mapping.start as usize + size_of::<AllocationHeader>(),
),
(),
);
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::<AllocationHeader>()),
core::ptr::without_provenance_mut::<()>(
mapping.start as usize + size_of::<AllocationHeader>(),
),
(),
);
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::<Allocation>() * 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::<Allocation>() as u64 * (num_allocations))
{
if unsafe { *self.allocationheader }.len + size_of::<Allocation>() as u64 >= self.max_allocations_size {
if unsafe { *self.allocations }.len < (size_of::<Allocation>() as u64 * (num_allocations)) {
if unsafe { *self.allocationheader }.len + size_of::<Allocation>() 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::<Allocation>() * (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;
}
}

View file

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

6
user/Cargo.toml Normal file
View file

@ -0,0 +1,6 @@
[package]
name = "user"
version = "0.1.0"
edition = "2024"
[dependencies]

6
user/src/arch/mod.rs Normal file
View file

@ -0,0 +1,6 @@
//! Architecture-specific stuff, mainly syscall methods.
#[macro_use]
mod x86;
pub use x86::*;

62
user/src/arch/x86/mod.rs Normal file
View file

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

5
user/src/lib.rs Normal file
View file

@ -0,0 +1,5 @@
#[warn(missing_docs)]
mod arch;
use arch::*;