From 55f410e2bbcd9b7affb772c22f73d3a73acd6383 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Neuh=C3=A4user?= Date: Wed, 4 Mar 2026 11:23:27 +0100 Subject: [PATCH] Refactor and reorganize project structure --- .gitignore | 1 + Cargo.lock | 7 + Cargo.toml | 10 +- src/aarch64/mmu.rs | 17 ++ src/aarch64/mod.rs | 2 + src/aarch64/registers.rs | 57 +++++ src/framebuffer.rs | 2 +- src/interrupt_handlers.rs | 87 ++----- src/irq_interrupt.rs | 227 ------------------ src/lib.rs | 5 +- src/main.rs | 8 +- src/peripherals/uart.rs | 2 +- src/{ => pi3}/mailbox.rs | 0 src/pi3/mod.rs | 2 + src/{ => pi3}/power_management.rs | 0 {heap => workspace/heap}/.cargo/config.toml | 0 {heap => workspace/heap}/Cargo.toml | 0 {heap => workspace/heap}/src/lib.rs | 0 {heap => workspace/heap}/src/tests.rs | 0 .../nova_error}/Cargo.toml | 0 .../nova_error}/src/lib.rs | 0 21 files changed, 118 insertions(+), 309 deletions(-) create mode 100644 src/aarch64/mmu.rs create mode 100644 src/aarch64/mod.rs create mode 100644 src/aarch64/registers.rs delete mode 100644 src/irq_interrupt.rs rename src/{ => pi3}/mailbox.rs (100%) create mode 100644 src/pi3/mod.rs rename src/{ => pi3}/power_management.rs (100%) rename {heap => workspace/heap}/.cargo/config.toml (100%) rename {heap => workspace/heap}/Cargo.toml (100%) rename {heap => workspace/heap}/src/lib.rs (100%) rename {heap => workspace/heap}/src/tests.rs (100%) rename {nova_error => workspace/nova_error}/Cargo.toml (100%) rename {nova_error => workspace/nova_error}/src/lib.rs (100%) diff --git a/.gitignore b/.gitignore index 44f9ef3..1bc1b3f 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ kernel8.img sd.img settings.json .DS_Store +.venv diff --git a/Cargo.lock b/Cargo.lock index 3c3c3f3..23658e2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -47,12 +47,19 @@ dependencies = [ "heap", "libm", "nova_error", + "paste", ] [[package]] name = "nova_error" version = "0.1.0" +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + [[package]] name = "ppv-lite86" version = "0.2.21" diff --git a/Cargo.toml b/Cargo.toml index a657ddd..e5a1c75 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,11 +14,13 @@ panic = "abort" [dependencies] libm = "0.2.15" -heap = {path = "heap"} -nova_error = {path = "nova_error"} +heap = {path = "workspace/heap"} +nova_error = {path = "workspace/nova_error"} +paste = "1.0.15" [workspace] -members = [ "nova_error", - "heap" +members = [ + "workspace/nova_error", + "workspace/heap", ] diff --git a/src/aarch64/mmu.rs b/src/aarch64/mmu.rs new file mode 100644 index 0000000..428c1b6 --- /dev/null +++ b/src/aarch64/mmu.rs @@ -0,0 +1,17 @@ +use core::arch::asm; + +pub fn init_mmu() { + let ips = 0b000 << 32; + + // 4KB granularity + let tg0 = 0b00 << 14; + let tg1 = 0b00 << 30; + + //64-25 = 29 bits of VA + // FFFF_FF80_0000_0000 start address + let t0sz = 25; + + let tcr_el1: u64 = ips | tg0 | tg1 | t0sz; + + unsafe { asm!("msr TCR_EL1, {0:x}", in(reg) tcr_el1) }; +} diff --git a/src/aarch64/mod.rs b/src/aarch64/mod.rs new file mode 100644 index 0000000..4c89405 --- /dev/null +++ b/src/aarch64/mod.rs @@ -0,0 +1,2 @@ +pub mod mmu; +pub mod registers; diff --git a/src/aarch64/registers.rs b/src/aarch64/registers.rs new file mode 100644 index 0000000..c39ed66 --- /dev/null +++ b/src/aarch64/registers.rs @@ -0,0 +1,57 @@ +use core::arch::asm; + +pub mod daif { + use core::arch::asm; + + #[inline(always)] + pub fn mask_all() { + unsafe { asm!("msr DAIFSet, #0xf", options(nomem, nostack)) } + } + + #[inline(always)] + pub fn unmask_all() { + unsafe { asm!("msr DAIFClr, #0xf", options(nomem, nostack)) } + } + + #[inline(always)] + pub fn mask_irq() { + unsafe { asm!("msr DAIFSet, #0x2", options(nomem, nostack)) } + } + + #[inline(always)] + pub fn unmask_irq() { + unsafe { asm!("msr DAIFClr, #0x2", options(nomem, nostack)) } + } +} + +#[macro_export] +macro_rules! psr { + ($name:ident, $t:tt) => { + paste::item! { + pub fn []() -> $t { + let buf: $t; + unsafe { + asm!( + concat!("mrs {0:x}, ", stringify!($name)), + out(reg) buf + ); + } + buf + } + } + }; +} + +psr!(TCR_EL1, u64); + +psr!(ID_AA64MMFR0_EL1, u64); + +psr!(ESR_EL1, u32); + +psr!(SPSR_EL1, u32); + +psr!(ELR_EL1, u32); + +pub fn read_exception_source_el() -> u32 { + read_spsr_el1() & 0b1111 +} diff --git a/src/framebuffer.rs b/src/framebuffer.rs index b906047..8c14e34 100644 --- a/src/framebuffer.rs +++ b/src/framebuffer.rs @@ -5,7 +5,7 @@ mod bitmaps; use bitmaps::BASIC_LEGACY; use crate::{ - mailbox::{read_mailbox, write_mailbox}, + pi3::mailbox::{read_mailbox, write_mailbox}, println, }; #[repr(align(16))] diff --git a/src/interrupt_handlers.rs b/src/interrupt_handlers.rs index bc051fb..9423eea 100644 --- a/src/interrupt_handlers.rs +++ b/src/interrupt_handlers.rs @@ -3,8 +3,11 @@ use core::arch::asm; use alloc::vec::Vec; use crate::{ + aarch64::registers::{ + daif::{mask_all, unmask_irq}, + read_esr_el1, read_exception_source_el, + }, get_current_el, - interrupt_handlers::daif::unmask_irq, peripherals::{ gpio::{read_gpio_event_detect_status, reset_gpio_event_detect_status}, uart::clear_uart_interrupt_state, @@ -68,15 +71,15 @@ impl From for EsrElX { #[no_mangle] unsafe extern "C" fn rust_irq_handler() { - daif::mask_all(); + mask_all(); let pending_irqs = get_irq_pending_sources(); if pending_irqs & GPIO_PENDING_BIT_OFFSET != 0 { handle_gpio_interrupt(); - let source_el = get_exception_return_exception_level() >> 2; + let source_el = read_exception_source_el() >> 2; println!("Source EL: {}", source_el); println!("Current EL: {}", get_current_el()); - println!("Return register address: {:#x}", get_elr_el1()); + println!("Return register address: {:#x}", read_esr_el1()); } if let Some(handler_vec) = unsafe { INTERRUPT_HANDLERS.as_ref() } { @@ -91,14 +94,14 @@ unsafe extern "C" fn rust_irq_handler() { #[no_mangle] unsafe extern "C" fn rust_synchronous_interrupt_no_el_change() { - daif::mask_all(); + mask_all(); - let source_el = get_exception_return_exception_level() >> 2; + let source_el = read_exception_source_el() >> 2; println!("--------Sync Exception in EL{}--------", source_el); println!("No EL change"); println!("Current EL: {}", get_current_el()); - println!("{:?}", EsrElX::from(get_esr_el1())); - println!("Return register address: {:#x}", get_elr_el1()); + println!("{:?}", EsrElX::from(read_esr_el1())); + println!("Return register address: {:#x}", read_esr_el1()); println!("-------------------------------------"); } @@ -109,15 +112,15 @@ unsafe extern "C" fn rust_synchronous_interrupt_no_el_change() { /// AArch64. #[no_mangle] unsafe extern "C" fn rust_synchronous_interrupt_imm_lower_aarch64() { - daif::mask_all(); + mask_all(); - let source_el = get_exception_return_exception_level() >> 2; + let source_el = read_exception_source_el() >> 2; println!("--------Sync Exception in EL{}--------", source_el); println!("Exception escalated to EL {}", get_current_el()); println!("Current EL: {}", get_current_el()); - let esr = EsrElX::from(get_esr_el1()); + let esr = EsrElX::from(read_esr_el1()); println!("{:?}", EsrElX::from(esr)); - println!("Return register address: {:#x}", get_elr_el1()); + println!("Return register address: {:#x}", read_esr_el1()); match esr.ec { 0b100100 => { @@ -144,42 +147,6 @@ fn set_return_to_kernel_main() { } } -fn get_exception_return_exception_level() -> u32 { - let spsr: u32; - unsafe { - asm!("mrs {0:x}, SPSR_EL1", out(reg) spsr); - } - spsr & 0b1111 -} - -/// Read the syndrome information that caused an exception -/// -/// ESR = Exception Syndrome Register -fn get_esr_el1() -> u32 { - let esr: u32; - unsafe { - asm!( - "mrs {esr:x}, ESR_EL1", - esr = out(reg) esr - ); - } - esr -} - -/// Read the return address -/// -/// ELR = Exception Link Registers -fn get_elr_el1() -> u32 { - let elr: u32; - unsafe { - asm!( - "mrs {esr:x}, ELR_EL1", - esr = out(reg) elr - ); - } - elr -} - fn handle_gpio_interrupt() { println!("Interrupt"); for i in 0..=53u32 { @@ -245,30 +212,6 @@ pub fn get_irq_pending_sources() -> u64 { pending } -pub mod daif { - use core::arch::asm; - - #[inline(always)] - pub fn mask_all() { - unsafe { asm!("msr DAIFSet, #0xf", options(nomem, nostack)) } - } - - #[inline(always)] - pub fn unmask_all() { - unsafe { asm!("msr DAIFClr, #0xf", options(nomem, nostack)) } - } - - #[inline(always)] - pub fn mask_irq() { - unsafe { asm!("msr DAIFSet, #0x2", options(nomem, nostack)) } - } - - #[inline(always)] - pub fn unmask_irq() { - unsafe { asm!("msr DAIFClr, #0x2", options(nomem, nostack)) } - } -} - pub fn initialize_interrupt_handler() { unsafe { INTERRUPT_HANDLERS = Some(Vec::new()) }; } diff --git a/src/irq_interrupt.rs b/src/irq_interrupt.rs deleted file mode 100644 index 2a85486..0000000 --- a/src/irq_interrupt.rs +++ /dev/null @@ -1,227 +0,0 @@ -use core::arch::asm; - -use crate::{ - get_current_el, - irq_interrupt::daif::unmask_irq, - mmio_read, mmio_write, - peripherals::gpio::{read_gpio_event_detect_status, reset_gpio_event_detect_status}, -}; - -const INTERRUPT_BASE: u32 = 0x3F00_B000; -const IRQ_PENDING_BASE: u32 = INTERRUPT_BASE + 0x204; -const ENABLE_IRQ_BASE: u32 = INTERRUPT_BASE + 0x210; -const DISABLE_IRQ_BASE: u32 = INTERRUPT_BASE + 0x21C; - -#[repr(u32)] -pub enum IRQState { - AuxInt = 29, - I2cSpiSlvInt = 44, - Pwa0 = 45, - Pwa1 = 46, - Smi = 48, - GpioInt0 = 49, - GpioInt1 = 50, - GpioInt2 = 51, - GpioInt3 = 52, - I2cInt = 53, - SpiInt = 54, - PcmInt = 55, - UartInt = 57, -} - -/// Representation of the ESR_ELx registers -/// -/// Reference: D1.10.4 -#[derive(Debug, Clone, Copy)] -#[allow(dead_code)] -struct EsrElX { - ec: u32, - il: u32, - iss: u32, -} - -impl From for EsrElX { - fn from(value: u32) -> Self { - Self { - ec: value >> 26, - il: (value >> 25) & 0b1, - iss: value & 0x1FFFFFF, - } - } -} - -#[no_mangle] -unsafe extern "C" fn rust_irq_handler() { - daif::mask_all(); - handle_gpio_interrupt(); - let source_el = get_exception_return_exception_level() >> 2; - println!("Source EL: {}", source_el); - println!("Current EL: {}", get_current_el()); - println!("Return register address: {:#x}", get_elr_el1()); -} - -#[no_mangle] -unsafe extern "C" fn rust_synchronous_interrupt_no_el_change() { - daif::mask_all(); - - let source_el = get_exception_return_exception_level() >> 2; - println!("--------Sync Exception in EL{}--------", source_el); - println!("No EL change"); - println!("Current EL: {}", get_current_el()); - println!("{:?}", EsrElX::from(get_esr_el1())); - println!("Return register address: {:#x}", get_elr_el1()); - println!("-------------------------------------"); -} - -/// Synchronous Exception Handler -/// -/// Lower Exception level, where the implemented level -/// immediately lower than the target level is using -/// AArch64. -#[no_mangle] -unsafe extern "C" fn rust_synchronous_interrupt_imm_lower_aarch64() { - daif::mask_all(); - - let source_el = get_exception_return_exception_level() >> 2; - println!("--------Sync Exception in EL{}--------", source_el); - println!("Exception escalated to EL {}", get_current_el()); - println!("Current EL: {}", get_current_el()); - let esr = EsrElX::from(get_esr_el1()); - println!("{:?}", EsrElX::from(esr)); - println!("Return register address: {:#x}", get_elr_el1()); - - match esr.ec { - 0b100100 => { - println!("Cause: Data Abort from a lower Exception level"); - } - _ => {} - } - println!("-------------------------------------"); - - set_return_to_kernel_main(); -} - -fn set_return_to_kernel_main() { - unsafe { - asm!("ldr x0, =kernel_main", "msr ELR_EL1, x0"); - asm!("mov x0, #(0b0101)", "msr SPSR_EL1, x0"); - } -} - -fn get_exception_return_exception_level() -> u32 { - let spsr: u32; - unsafe { - asm!("mrs {0:x}, SPSR_EL1", out(reg) spsr); - } - spsr & 0b1111 -} - -/// Read the syndrome information that caused an exception -/// -/// ESR = Exception Syndrome Register -fn get_esr_el1() -> u32 { - let esr: u32; - unsafe { - asm!( - "mrs {esr:x}, ESR_EL1", - esr = out(reg) esr - ); - } - esr -} - -/// Read the return address -/// -/// ELR = Exception Link Registers -fn get_elr_el1() -> u32 { - let elr: u32; - unsafe { - asm!( - "mrs {esr:x}, ELR_EL1", - esr = out(reg) elr - ); - } - elr -} - -fn handle_gpio_interrupt() { - println!("Interrupt"); - for i in 0..=53u32 { - let val = read_gpio_event_detect_status(i); - - if val { - #[allow(clippy::single_match)] - match i { - 26 => { - println!("Button Pressed"); - } - _ => {} - } - // Reset GPIO Interrupt handler by writing a 1 - reset_gpio_event_detect_status(i); - } - } - unmask_irq(); -} - -/// Enables IRQ Source -pub fn enable_irq_source(state: IRQState) { - let nr = state as u32; - let register = ENABLE_IRQ_BASE + 4 * (nr / 32); - let register_offset = nr % 32; - let current = mmio_read(register); - let mask = 0b1 << register_offset; - let new_val = current | mask; - mmio_write(register, new_val); -} - -/// Disable IRQ Source -pub fn disable_irq_source(state: IRQState) { - let nr = state as u32; - let register = DISABLE_IRQ_BASE + 4 * (nr / 32); - let register_offset = nr % 32; - let current = mmio_read(register); - let mask = 0b1 << register_offset; - let new_val = current | mask; - mmio_write(register, new_val); -} - -/// Read current IRQ Source status -pub fn read_irq_source_status(state: IRQState) -> u32 { - let nr = state as u32; - let register = ENABLE_IRQ_BASE + 4 * (nr / 32); - let register_offset = nr % 32; - (mmio_read(register) >> register_offset) & 0b1 -} - -/// Status if a IRQ Source is enabled -pub fn read_irq_pending(state: IRQState) -> bool { - let nr = state as u32; - let register = IRQ_PENDING_BASE + 4 * (nr / 32); - let register_offset = nr % 32; - ((mmio_read(register) >> register_offset) & 0b1) != 0 -} - -pub mod daif { - use core::arch::asm; - - #[inline(always)] - pub fn mask_all() { - unsafe { asm!("msr DAIFSet, #0xf", options(nomem, nostack)) } - } - - #[inline(always)] - pub fn unmask_all() { - unsafe { asm!("msr DAIFClr, #0xf", options(nomem, nostack)) } - } - - #[inline(always)] - pub fn mask_irq() { - unsafe { asm!("msr DAIFSet, #0x2", options(nomem, nostack)) } - } - - #[inline(always)] - pub fn unmask_irq() { - unsafe { asm!("msr DAIFClr, #0x2", options(nomem, nostack)) } - } -} diff --git a/src/lib.rs b/src/lib.rs index f12cb31..b61f16d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -41,14 +41,15 @@ fn panic(_panic: &PanicInfo) -> ! { pub mod peripherals; +pub mod aarch64; pub mod configuration; pub mod framebuffer; pub mod interrupt_handlers; pub mod logger; -pub mod mailbox; -pub mod power_management; pub mod timer; +pub mod pi3; + #[inline(always)] pub unsafe fn read_address(address: u32) -> u32 { unsafe { read_volatile(address as *const u32) } diff --git a/src/main.rs b/src/main.rs index 80475c5..6a33913 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,10 +12,11 @@ extern crate alloc; use alloc::boxed::Box; use nova::{ + aarch64::registers::{daif, read_id_aa64mmfr0_el1, read_tcr_el1}, framebuffer::{FrameBuffer, BLUE, GREEN, RED}, get_current_el, init_heap, - interrupt_handlers::{daif, enable_irq_source, IRQSource}, - log, mailbox, + interrupt_handlers::{enable_irq_source, IRQSource}, + log, peripherals::{ gpio::{ blink_gpio, gpio_pull_up, set_falling_edge_detect, set_gpio_function, GPIOFunction, @@ -23,6 +24,7 @@ use nova::{ }, uart::uart_init, }, + pi3::mailbox, println, }; @@ -86,6 +88,8 @@ pub extern "C" fn kernel_main() -> ! { unsafe { init_heap(); + println!("{:b}", read_id_aa64mmfr0_el1()); + println!("{:b}", read_tcr_el1()); el1_to_el0(); }; diff --git a/src/peripherals/uart.rs b/src/peripherals/uart.rs index dfcd141..57e2843 100644 --- a/src/peripherals/uart.rs +++ b/src/peripherals/uart.rs @@ -3,7 +3,7 @@ use core::{ fmt::{self, Write}, }; -use crate::{println, read_address, write_address}; +use crate::{read_address, write_address}; const BAUD: u32 = 115200; const UART_CLK: u32 = 48_000_000; diff --git a/src/mailbox.rs b/src/pi3/mailbox.rs similarity index 100% rename from src/mailbox.rs rename to src/pi3/mailbox.rs diff --git a/src/pi3/mod.rs b/src/pi3/mod.rs new file mode 100644 index 0000000..e23f6e4 --- /dev/null +++ b/src/pi3/mod.rs @@ -0,0 +1,2 @@ +pub mod mailbox; +pub mod power_management; diff --git a/src/power_management.rs b/src/pi3/power_management.rs similarity index 100% rename from src/power_management.rs rename to src/pi3/power_management.rs diff --git a/heap/.cargo/config.toml b/workspace/heap/.cargo/config.toml similarity index 100% rename from heap/.cargo/config.toml rename to workspace/heap/.cargo/config.toml diff --git a/heap/Cargo.toml b/workspace/heap/Cargo.toml similarity index 100% rename from heap/Cargo.toml rename to workspace/heap/Cargo.toml diff --git a/heap/src/lib.rs b/workspace/heap/src/lib.rs similarity index 100% rename from heap/src/lib.rs rename to workspace/heap/src/lib.rs diff --git a/heap/src/tests.rs b/workspace/heap/src/tests.rs similarity index 100% rename from heap/src/tests.rs rename to workspace/heap/src/tests.rs diff --git a/nova_error/Cargo.toml b/workspace/nova_error/Cargo.toml similarity index 100% rename from nova_error/Cargo.toml rename to workspace/nova_error/Cargo.toml diff --git a/nova_error/src/lib.rs b/workspace/nova_error/src/lib.rs similarity index 100% rename from nova_error/src/lib.rs rename to workspace/nova_error/src/lib.rs