Refactor and reorganize project structure

This commit is contained in:
2026-03-04 11:23:27 +01:00
parent 0f5f942d78
commit 55f410e2bb
21 changed files with 118 additions and 309 deletions

1
.gitignore vendored
View File

@@ -4,3 +4,4 @@ kernel8.img
sd.img sd.img
settings.json settings.json
.DS_Store .DS_Store
.venv

7
Cargo.lock generated
View File

@@ -47,12 +47,19 @@ dependencies = [
"heap", "heap",
"libm", "libm",
"nova_error", "nova_error",
"paste",
] ]
[[package]] [[package]]
name = "nova_error" name = "nova_error"
version = "0.1.0" version = "0.1.0"
[[package]]
name = "paste"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
[[package]] [[package]]
name = "ppv-lite86" name = "ppv-lite86"
version = "0.2.21" version = "0.2.21"

View File

@@ -14,11 +14,13 @@ panic = "abort"
[dependencies] [dependencies]
libm = "0.2.15" libm = "0.2.15"
heap = {path = "heap"} heap = {path = "workspace/heap"}
nova_error = {path = "nova_error"} nova_error = {path = "workspace/nova_error"}
paste = "1.0.15"
[workspace] [workspace]
members = [ "nova_error", members = [
"heap" "workspace/nova_error",
"workspace/heap",
] ]

17
src/aarch64/mmu.rs Normal file
View File

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

2
src/aarch64/mod.rs Normal file
View File

@@ -0,0 +1,2 @@
pub mod mmu;
pub mod registers;

57
src/aarch64/registers.rs Normal file
View File

@@ -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 [<read_ $name:lower>]() -> $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
}

View File

@@ -5,7 +5,7 @@ mod bitmaps;
use bitmaps::BASIC_LEGACY; use bitmaps::BASIC_LEGACY;
use crate::{ use crate::{
mailbox::{read_mailbox, write_mailbox}, pi3::mailbox::{read_mailbox, write_mailbox},
println, println,
}; };
#[repr(align(16))] #[repr(align(16))]

View File

@@ -3,8 +3,11 @@ use core::arch::asm;
use alloc::vec::Vec; use alloc::vec::Vec;
use crate::{ use crate::{
aarch64::registers::{
daif::{mask_all, unmask_irq},
read_esr_el1, read_exception_source_el,
},
get_current_el, get_current_el,
interrupt_handlers::daif::unmask_irq,
peripherals::{ peripherals::{
gpio::{read_gpio_event_detect_status, reset_gpio_event_detect_status}, gpio::{read_gpio_event_detect_status, reset_gpio_event_detect_status},
uart::clear_uart_interrupt_state, uart::clear_uart_interrupt_state,
@@ -68,15 +71,15 @@ impl From<u32> for EsrElX {
#[no_mangle] #[no_mangle]
unsafe extern "C" fn rust_irq_handler() { unsafe extern "C" fn rust_irq_handler() {
daif::mask_all(); mask_all();
let pending_irqs = get_irq_pending_sources(); let pending_irqs = get_irq_pending_sources();
if pending_irqs & GPIO_PENDING_BIT_OFFSET != 0 { if pending_irqs & GPIO_PENDING_BIT_OFFSET != 0 {
handle_gpio_interrupt(); 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!("Source EL: {}", source_el);
println!("Current EL: {}", get_current_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() } { if let Some(handler_vec) = unsafe { INTERRUPT_HANDLERS.as_ref() } {
@@ -91,14 +94,14 @@ unsafe extern "C" fn rust_irq_handler() {
#[no_mangle] #[no_mangle]
unsafe extern "C" fn rust_synchronous_interrupt_no_el_change() { 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!("--------Sync Exception in EL{}--------", source_el);
println!("No EL change"); println!("No EL change");
println!("Current EL: {}", get_current_el()); println!("Current EL: {}", get_current_el());
println!("{:?}", EsrElX::from(get_esr_el1())); println!("{:?}", EsrElX::from(read_esr_el1()));
println!("Return register address: {:#x}", get_elr_el1()); println!("Return register address: {:#x}", read_esr_el1());
println!("-------------------------------------"); println!("-------------------------------------");
} }
@@ -109,15 +112,15 @@ unsafe extern "C" fn rust_synchronous_interrupt_no_el_change() {
/// AArch64. /// AArch64.
#[no_mangle] #[no_mangle]
unsafe extern "C" fn rust_synchronous_interrupt_imm_lower_aarch64() { 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!("--------Sync Exception in EL{}--------", source_el);
println!("Exception escalated to EL {}", get_current_el()); println!("Exception escalated to EL {}", get_current_el());
println!("Current 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!("{:?}", EsrElX::from(esr));
println!("Return register address: {:#x}", get_elr_el1()); println!("Return register address: {:#x}", read_esr_el1());
match esr.ec { match esr.ec {
0b100100 => { 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() { fn handle_gpio_interrupt() {
println!("Interrupt"); println!("Interrupt");
for i in 0..=53u32 { for i in 0..=53u32 {
@@ -245,30 +212,6 @@ pub fn get_irq_pending_sources() -> u64 {
pending 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() { pub fn initialize_interrupt_handler() {
unsafe { INTERRUPT_HANDLERS = Some(Vec::new()) }; unsafe { INTERRUPT_HANDLERS = Some(Vec::new()) };
} }

View File

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

View File

@@ -41,14 +41,15 @@ fn panic(_panic: &PanicInfo) -> ! {
pub mod peripherals; pub mod peripherals;
pub mod aarch64;
pub mod configuration; pub mod configuration;
pub mod framebuffer; pub mod framebuffer;
pub mod interrupt_handlers; pub mod interrupt_handlers;
pub mod logger; pub mod logger;
pub mod mailbox;
pub mod power_management;
pub mod timer; pub mod timer;
pub mod pi3;
#[inline(always)] #[inline(always)]
pub unsafe fn read_address(address: u32) -> u32 { pub unsafe fn read_address(address: u32) -> u32 {
unsafe { read_volatile(address as *const u32) } unsafe { read_volatile(address as *const u32) }

View File

@@ -12,10 +12,11 @@ extern crate alloc;
use alloc::boxed::Box; use alloc::boxed::Box;
use nova::{ use nova::{
aarch64::registers::{daif, read_id_aa64mmfr0_el1, read_tcr_el1},
framebuffer::{FrameBuffer, BLUE, GREEN, RED}, framebuffer::{FrameBuffer, BLUE, GREEN, RED},
get_current_el, init_heap, get_current_el, init_heap,
interrupt_handlers::{daif, enable_irq_source, IRQSource}, interrupt_handlers::{enable_irq_source, IRQSource},
log, mailbox, log,
peripherals::{ peripherals::{
gpio::{ gpio::{
blink_gpio, gpio_pull_up, set_falling_edge_detect, set_gpio_function, GPIOFunction, blink_gpio, gpio_pull_up, set_falling_edge_detect, set_gpio_function, GPIOFunction,
@@ -23,6 +24,7 @@ use nova::{
}, },
uart::uart_init, uart::uart_init,
}, },
pi3::mailbox,
println, println,
}; };
@@ -86,6 +88,8 @@ pub extern "C" fn kernel_main() -> ! {
unsafe { unsafe {
init_heap(); init_heap();
println!("{:b}", read_id_aa64mmfr0_el1());
println!("{:b}", read_tcr_el1());
el1_to_el0(); el1_to_el0();
}; };

View File

@@ -3,7 +3,7 @@ use core::{
fmt::{self, Write}, fmt::{self, Write},
}; };
use crate::{println, read_address, write_address}; use crate::{read_address, write_address};
const BAUD: u32 = 115200; const BAUD: u32 = 115200;
const UART_CLK: u32 = 48_000_000; const UART_CLK: u32 = 48_000_000;

2
src/pi3/mod.rs Normal file
View File

@@ -0,0 +1,2 @@
pub mod mailbox;
pub mod power_management;