Removed proc macros(for now) as kernel items are pretty much useless, added untested interrupts stuff

This commit is contained in:
Arthur Beck 2025-04-05 17:32:51 -05:00
parent 9e6897d8ba
commit 842a2b23fe
Signed by: ArthurB
GPG key ID: CA200B389F0F6BC9
16 changed files with 108 additions and 309 deletions

View file

@ -5,7 +5,6 @@ edition = "2024"
[dependencies]
paste = "1.0.15"
aphrodite_proc_macros = { path = "./aphrodite_proc_macros"}
[profile.release]
opt-level = "z"

View file

@ -1,14 +0,0 @@
[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

@ -19,7 +19,7 @@
real_check=false
if [[ "$HAVE_GETOPT" = "true" ]]; then
LONGOPTS=real_check
LONGOPTS=real_check,real-check
OPTIONS=c
PARSED=$(getopt --options=$OPTIONS --longoptions=$LONGOPTS --name "$0" -- "$@") || (
@ -30,7 +30,7 @@
while true; do
case "$1" in
-c|--real_check)
-c|--real_check|--real-check)
real_check=true
shift
;;

View file

@ -14,6 +14,7 @@ VERSION=generate
CONFIG_DISABLE_MULTIBOOT2_SUPPORT=false
# Panic behavior. When debugging, generally halt on panic is more useful.
# Halt on panic takes priority over spin on panic if both are enabled.
CONFIG_HALT_ON_PANIC=true
CONFIG_SPIN_ON_PANIC=false

View file

@ -23,28 +23,22 @@ pub mod interrupts {
pub const USER_SYSCALL_VECTOR: u16 = 0xA0;
/// Returns whether interrupts are enabled or not.
#[aphrodite_proc_macros::kernel_item(InterruptsCheck)]
fn interrupts_enabled() -> bool { false }
/// Enables interrupts.
#[aphrodite_proc_macros::kernel_item(InterruptsEnable)]
fn enable_interrupts() {}
/// Disables interrupts.
#[aphrodite_proc_macros::kernel_item(InterruptsDisable)]
fn disable_interrupts() {}
/// Disables interrupts and a value that can be used to restore them
/// with [restore_irq].
#[aphrodite_proc_macros::kernel_item(InterruptsPop)]
fn pop_irq() -> u64 { 0 }
/// Restores interrupts after a [pop_irq] call.
#[aphrodite_proc_macros::kernel_item(InterruptsRestore)]
fn restore_irq(_irq: u64) {}
/// Activates an IDT.
#[aphrodite_proc_macros::kernel_item(ActivateIDT)]
fn activate_idt(_idt: Idt) {}
/// An IDT.

View file

@ -9,10 +9,14 @@ use alloc::vec::Vec;
/// The GDTR. Used internally in [activate_gdt].
#[repr(C, packed)]
struct Gdtr {
// raw pointer to the GDT
base: *const u8,
// size of the GDT in bytes
size: usize,
}
/// Activates the GDT using `lgdt`. Does NOT, I repeat, does NOT change the
/// segment registers!
pub unsafe fn activate_gdt(ptr: *const [u8]) {
let gdtr = Gdtr {
base: ptr as *const u8,

View file

@ -0,0 +1,36 @@
//! Implementations of interrupts.
#![cfg(target_arch = "x86")]
#![allow(undefined_naked_function_abi)] // special calling convention anyway
use core::arch::naked_asm;
macro_rules! int_wrapper {
($func:block, $num:expr) => {
paste::paste! {
/// autogenerated interrupt wrapper
#[naked]
pub unsafe fn [< int $num >]() {
unsafe {
naked_asm!(
"pushad",
"cld",
"call {}",
"popad",
"iret",
sym [< int $num _rust >]
)
}
}
/// autogenerated interrupt body
unsafe extern "C" fn [< int $num _rust >]() $func
}
};
}
int_wrapper!(
{
super::output::sdebugsln("Interrupt handler #0 ran");
},
0
);

View file

@ -9,7 +9,6 @@ use core::mem::MaybeUninit;
pub const USER_SYSCALL_VECTOR: u16 = 0xA0;
/// Returns whether interrupts are enabled or not.
#[aphrodite_proc_macros::kernel_item(InterruptsCheck)]
pub fn interrupts_enabled() -> bool {
let flags: u32;
unsafe {
@ -22,7 +21,6 @@ pub fn interrupts_enabled() -> bool {
}
/// Disables interrupts.
#[aphrodite_proc_macros::kernel_item(InterruptsDisable)]
pub fn disable_interrupts() { unsafe { asm!("cli") } }
/// PoppedInterrupts implements drop and restores the interrupts upon being
@ -37,7 +35,6 @@ impl Drop for PoppedInterrupts {
}
/// Disables interrupts and returns the value of them.
#[aphrodite_proc_macros::kernel_item(InterruptsPop)]
pub fn pop_irq() -> PoppedInterrupts {
let flags: u32;
unsafe {
@ -51,7 +48,6 @@ pub fn pop_irq() -> PoppedInterrupts {
}
/// Restores interrupts after a [pop_irq] call.
#[aphrodite_proc_macros::kernel_item(InterruptsRestore)]
pub fn restore_irq(flags: PoppedInterrupts) {
let flags = flags.0;
unsafe {
@ -76,7 +72,7 @@ unsafe fn load_idt(base: *const u8, size: usize) {
}
#[derive(Clone, Copy)]
pub(super) struct IdtEntry {
pub struct IdtEntry {
pub offset_high: u16,
pub data: u16,
pub segment: u16,
@ -108,8 +104,7 @@ impl From<IdtEntry> for RawIdtEntry {
///
/// # Panics
/// Panics if the global allocator has not been setup
#[aphrodite_proc_macros::kernel_item(ActivateIDT)]
fn activate_idt(idt: Idt) {
pub unsafe fn activate_idt(idt: Idt) {
let mut entries = alloc::vec::Vec::new();
for i in 0..idt.len {
if idt.using_raw[i] {
@ -195,7 +190,7 @@ fn activate_idt(idt: Idt) {
#[derive(Clone, Copy)]
pub struct Idt {
vectors: [u16; 256],
funcs: [MaybeUninit<fn()>; 256],
funcs: [MaybeUninit<unsafe fn()>; 256],
user_callable: [bool; 256],
exception: [bool; 256],
raw_entries: [IdtEntry; 256],
@ -207,7 +202,7 @@ pub struct Idt {
#[derive(Clone, Copy)]
pub struct IdtBuilder {
vectors: [u16; 256],
funcs: [MaybeUninit<fn()>; 256],
funcs: [MaybeUninit<unsafe fn()>; 256],
user_callable: [bool; 256],
exception: [bool; 256],
raw_entries: [IdtEntry; 256],
@ -238,7 +233,7 @@ impl IdtBuilder {
pub fn add_fn(
&mut self,
vector: u16,
func: fn(),
func: unsafe fn(),
user_callable: bool,
exception: bool,
) -> &mut Self {

View file

@ -1,180 +0,0 @@
//! Hardware-level memory sections. Unimplemented for certain hardware, x86
//! implements with GDT.
#![cfg(target_arch = "x86")]
use core::arch::asm;
use alloc::vec;
use alloc::vec::Vec;
use crate::memsections::*;
use super::gdt::{GDTEntry, write_gdt_entries};
/// A list of memory sections. Create one with [MemorySectionBuilder].
pub struct MemorySections {
sections: Vec<MemorySection>,
}
#[repr(packed)]
struct GDTR {
address: u32,
size: u16,
}
unsafe impl crate::memsections::MemorySections for MemorySections {
unsafe fn write(self) -> Result<(), crate::Error<'static>> {
let mut entries: Vec<GDTEntry> = vec![];
for section in self.sections {
let mut section: MemorySection = section;
// rust-analyzer doesn't want to cooperate and recognize that section is already
// MemorySection, so I'm telling it here.
fn make_entry(section: &mut MemorySection, entries: &mut Vec<GDTEntry>) {
if section.length == 0 {
return;
}
let mut len = section.length as u32;
while len > 0xFFFFF {
len -= 0xFFFFF;
}
let mut access = 0b10000001u8;
match section.owner {
Owner::Kernelspace => {
access |= 0b0000000;
},
Owner::Modulespace => {
access |= 0b0100000;
},
Owner::Userspace => {
access |= 0b1100000;
},
}
if let SectionType::TaskSection { busy } = section.section_type {
access |= 0b00000;
if busy {
access |= 0x9;
} else {
access |= 0xB;
}
} else {
access |= 0b10000;
if let SectionType::CodeSection {
can_powerful_sections_jump,
} = section.section_type
{
access |= 0b1000;
if can_powerful_sections_jump {
access |= 0b100;
}
if section.readable {
access |= 0b10;
}
} else if section.section_type == SectionType::DataSection {
access |= 0b0000;
if section.writable {
access |= 0b10;
}
}
}
let flags = 0b1100u8;
let entry = GDTEntry {
limit: len,
base: section.address as u32,
access,
flags,
};
if section.length > 0xFFFFF {
section.length -= 0xFFFFF;
}
entries.push(entry);
}
while section.length > 0xFFFFF {
make_entry(&mut section, &mut entries);
}
make_entry(&mut section, &mut entries);
}
unsafe {
let _ = super::interrupts::pop_irq();
let segment_entries: Vec<GDTEntry> = entries.clone();
let ptr = write_gdt_entries(entries)?;
let gdtr = GDTR {
address: ptr as *const u8 as usize as u32,
size: (ptr.len() - 1) as u16,
};
let addr = &gdtr as *const GDTR as *const () as usize as u32;
asm!(
"lgdt eax",
in("eax") addr
);
let mut code_segment = 0u16;
let mut code_set = false;
let mut data_segment = 0u16;
let mut data_set = false;
let mut i = 0;
for entry in segment_entries {
let entry: GDTEntry = entry;
i += 1;
if code_set && data_set {
break;
}
if entry.access & 0b11000 == 0b11000 && !code_set {
code_segment = i - 1;
code_set = true;
} else if entry.access & 0b10000 == 0b10000 && !data_set {
data_segment = i - 1;
data_set = true;
}
}
asm!(
"jmp bx:2 ; `#[deny(named_asm_labels)]` on by default; see <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels>
2: ; ax is already loaded with the correct value from rustland
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax",
in("bx") code_segment,
in("ax") data_segment,
options(preserves_flags, nomem, nostack)
);
}
Ok(())
}
}
/// A memory section builder.
pub struct MemorySectionBuilder {
sections: Vec<MemorySection>,
}
impl MemorySectionBuilder {
/// Create a new MemorySectionBuilder.
pub fn new() -> Self { MemorySectionBuilder { sections: vec![] } }
/// Adds a section to this MemorySectionBuilder.
pub fn add_section(&mut self, section: MemorySection) -> &mut Self {
self.sections.push(section);
self
}
/// Finishes this MemorySectionBuilder and returns a MemorySections.
pub fn finish(self) -> MemorySections {
MemorySections {
sections: self.sections,
}
}
}

View file

@ -5,8 +5,8 @@ use core::arch::asm;
pub mod egatext;
mod gdt;
mod interrupt_impls;
pub mod interrupts;
pub mod memory;
pub mod output;
pub mod paging;
pub mod ports;
@ -92,27 +92,63 @@ pub fn initalize_rtc() {
unsafe { RTC_INITALIZED = true }
}
pub fn sleep(seconds: u32) { initalize_rtc(); }
pub fn alloc_available_boot() {
let irq = pop_irq();
let mut entries = vec![];
entries.push(gdt::GDT_NULL_ENTRY);
entries.push(GDTEntry {
limit: 0,
base: 0,
access: 0b10011011,
flags: 0b1100,
}); // kernel code segment
entries.push(GDTEntry {
limit: 0,
base: 0,
access: 0b10010011,
flags: 0b1100,
}); //
{
// GDT
let mut entries = vec![];
entries.push(gdt::GDT_NULL_ENTRY);
entries.push(GDTEntry {
limit: 0,
base: 0,
access: 0b10011011,
flags: 0b1100,
}); // kernel code segment, segment 0x08
entries.push(GDTEntry {
limit: 0,
base: 0,
access: 0b10010011,
flags: 0b1100,
}); // kernel data segment, segment 0x10
entries.push(GDTEntry {
limit: 0,
base: 0,
access: 0b11111011,
flags: 0b1100,
}); // user code segment, segment 0x18
entries.push(GDTEntry {
limit: 0,
base: 0,
access: 0b11110011,
flags: 0b1100,
}); // user data segment, segment 0x20
unsafe {
gdt::activate_gdt(gdt::write_gdt_entries(entries).unwrap());
unsafe {
gdt::activate_gdt(gdt::write_gdt_entries(entries).unwrap());
}
unsafe {
asm!(
"jmp 0x08:2",
"2:",
"mov ax, 0x10",
"mov ds, ax",
"mov es, ax",
"mov fs, ax",
"mov gs, ax",
"mov ss, ax",
out("ax") _
);
}
}
{
// IDT
let idt = self::interrupts::IdtBuilder::new()
.add_fn(0, interrupt_impls::int0, false, true)
.finish();
unsafe {
interrupts::activate_idt(idt);
}
}
restore_irq(irq);
}

View file

@ -3,8 +3,6 @@
use core::arch::asm;
use aphrodite_proc_macros::kernel_item;
/// One page directory entry. Use [PageDirectoryEntry::create_fourmb] or
/// [PageDirectoryEntry::create_other] to make these.
pub enum PageDirectoryEntry {
@ -120,11 +118,9 @@ static mut PAGE_DIRECTORY: PageDirectoryEntry =
PageDirectoryEntry::create_other(0, false, 0, false, false, false, false, false, false, false);
/// Initalize paging.
#[kernel_item(PagingInit)]
pub fn initalize_paging() {}
/// Disables paging by clearing bit 31 in the cr0 register.
#[kernel_item(PagingDeinit)]
pub fn disable_paging() {
unsafe {
asm!(

View file

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

View file

@ -7,11 +7,8 @@ use crate::arch::output::*;
use crate::display::{COLOR_DEFAULT, NoneTextDisplay};
use crate::output::*;
use aphrodite_proc_macros::*;
/// The real entrypoint to the kernel. `internel/arch/*/entry.rs` files
/// eventually call this.
#[kernel_item(IndepBootEntry)]
fn indep_boot_entry(
display: Option<&dyn crate::display::TextDisplay>,
#[allow(non_snake_case)] BI: &crate::boot::BootInfo,
@ -24,11 +21,11 @@ fn indep_boot_entry(
let display = display.unwrap_or(&NoneTextDisplay {});
display.clear_screen(COLOR_DEFAULT);
display.clear_screen(COLOR_DEFAULT).unwrap();
sreset();
let mem_map = BI.memory_map.unwrap();
crate::mem::MemMapAllocInit(mem_map).unwrap();
crate::mem::memory_map_alloc_init(mem_map).unwrap();
crate::arch::alloc_available_boot();

View file

@ -9,8 +9,6 @@ use core::ptr::{NonNull, null_mut};
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
@ -65,7 +63,6 @@ static mut ALLOCATOR: MaybeMemoryMapAlloc<'static> = MaybeMemoryMapAlloc::new(No
static mut ALLOCATOR_MEMMAP: MaybeUninit<MemoryMap> = MaybeUninit::uninit();
static mut ALLOCATOR_INITALIZED: bool = false;
#[kernel_item(MemMapAlloc)]
pub fn get_allocator() -> Option<&'static MemoryMapAlloc<'static>> {
if unsafe { ALLOCATOR_INITALIZED } {
#[allow(static_mut_refs)]
@ -90,8 +87,7 @@ pub unsafe fn get_allocator_unchecked() -> &'static MemoryMapAlloc<'static> {
}
}
#[kernel_item(MemMapAllocInit)]
fn memory_map_alloc_init(memmap: crate::boot::MemoryMap) -> Result<(), crate::Error<'static>> {
pub fn memory_map_alloc_init(memmap: crate::boot::MemoryMap) -> Result<(), crate::Error<'static>> {
#[allow(static_mut_refs)]
unsafe {
ALLOCATOR_MEMMAP.write(memmap);

View file

@ -20,6 +20,7 @@
#![allow(internal_features)]
#![feature(core_intrinsics)]
#![feature(vec_into_raw_parts)]
#![feature(naked_functions)]
extern crate alloc;

View file

@ -1,62 +0,0 @@
use proc_macro::TokenStream;
use quote::{ToTokens, quote};
use syn::parse::{Parse, ParseStream};
use syn::{ItemFn, Signature, Token};
struct KernelItemNameInput {
item: syn::Ident,
}
impl Parse for KernelItemNameInput {
fn parse(input: ParseStream) -> syn::Result<Self> {
let item: syn::Ident = input.parse()?;
Ok(KernelItemNameInput { item })
}
}
fn to_tokens(signature: Signature, tokens: &mut proc_macro2::TokenStream) {
let ts = tokens;
signature.constness.to_tokens(ts);
signature.asyncness.to_tokens(ts);
signature.unsafety.to_tokens(ts);
signature.abi.to_tokens(ts);
signature.fn_token.to_tokens(ts);
signature.generics.to_tokens(ts);
signature.paren_token.surround(ts, |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(ts);
signature.generics.where_clause.to_tokens(ts);
}
fn to_token_stream(signature: Signature) -> proc_macro2::TokenStream {
let mut tokens = proc_macro2::TokenStream::new();
to_tokens(signature, &mut tokens);
tokens
}
/// Implement a kernel item.
#[proc_macro_attribute]
pub fn kernel_item(attr: TokenStream, item: TokenStream) -> TokenStream {
let name: KernelItemNameInput = syn::parse_macro_input!(attr);
let item_name = name.item;
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! {
/// The #item_name kernel item.
#[allow(non_upper_case_globals)]
pub const #item_name: #fn_sig = #fn_name;
#input_fn
}
.into()
}