From 04ee0a1cb2817c233d9d3176344eda778d291604 Mon Sep 17 00:00:00 2001
From: Arthur Beck <averse.abfun@gmail.com>
Date: Tue, 11 Feb 2025 21:30:43 +0000
Subject: [PATCH] Squashed some bugs; implemented first iteration of kernel
 items

---
 .vscode/settings.json                 |   3 +-
 emulation/bochsrc                     |   2 +-
 kernel/config.aphro.example           |   2 +-
 kernel/expand                         |   2 +-
 kernel/src/arch_boot_entry/x86.rs     |  14 ++--
 kernel/src/common/mod.rs              |  37 ---------
 kernel/src/kernel/indep_boot_entry.rs |  32 +++++---
 kernel/src/kernel/mem.rs              | 113 +++++++++++++++++++++-----
 kernel/src/proc_macros/mod.rs         |  72 +++++++++-------
 user/Cargo.toml                       |   6 ++
 user/src/arch/mod.rs                  |   6 ++
 user/src/arch/x86/mod.rs              |  62 ++++++++++++++
 user/src/lib.rs                       |   5 ++
 13 files changed, 245 insertions(+), 111 deletions(-)
 create mode 100644 user/Cargo.toml
 create mode 100644 user/src/arch/mod.rs
 create mode 100644 user/src/arch/x86/mod.rs
 create mode 100644 user/src/lib.rs

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<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"))
-    }
-}
\ 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::<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;
     }
 }
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<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()
-}
\ 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