Impelement a basic logger, WIP

This commit is contained in:
2026-01-10 19:49:05 +01:00
parent 48fbc2e5fa
commit 0f5f942d78
8 changed files with 171 additions and 66 deletions

View File

@@ -1,9 +1,14 @@
use core::arch::asm; use core::arch::asm;
use alloc::vec::Vec;
use crate::{ use crate::{
get_current_el, get_current_el,
interrupt_handlers::daif::unmask_irq, interrupt_handlers::daif::unmask_irq,
peripherals::gpio::{read_gpio_event_detect_status, reset_gpio_event_detect_status}, peripherals::{
gpio::{read_gpio_event_detect_status, reset_gpio_event_detect_status},
uart::clear_uart_interrupt_state,
},
println, read_address, write_address, println, read_address, write_address,
}; };
@@ -14,6 +19,15 @@ const DISABLE_IRQ_BASE: u32 = INTERRUPT_BASE + 0x21C;
const GPIO_PENDING_BIT_OFFSET: u64 = 0b1111 << 49; const GPIO_PENDING_BIT_OFFSET: u64 = 0b1111 << 49;
struct InterruptHandlers {
source: IRQSource,
function: fn(),
}
// TODO: replace with hashmap and check for better alternatives for option
static mut INTERRUPT_HANDLERS: Option<Vec<InterruptHandlers>> = None;
#[derive(Clone)]
#[repr(u32)] #[repr(u32)]
pub enum IRQSource { pub enum IRQSource {
AuxInt = 29, AuxInt = 29,
@@ -59,11 +73,20 @@ unsafe extern "C" fn rust_irq_handler() {
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;
println!("Source EL: {}", source_el);
println!("Current EL: {}", get_current_el());
println!("Return register address: {:#x}", get_elr_el1());
}
if let Some(handler_vec) = unsafe { INTERRUPT_HANDLERS.as_ref() } {
for handler in handler_vec {
if (pending_irqs & (1 << (handler.source.clone() as u32))) != 0 {
(handler.function)();
clear_interrupt_for_source(handler.source.clone());
}
}
} }
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] #[no_mangle]
@@ -107,6 +130,13 @@ unsafe extern "C" fn rust_synchronous_interrupt_imm_lower_aarch64() {
set_return_to_kernel_main(); set_return_to_kernel_main();
} }
fn clear_interrupt_for_source(source: IRQSource) {
match source {
IRQSource::UartInt => clear_uart_interrupt_state(),
_ => {}
}
}
fn set_return_to_kernel_main() { fn set_return_to_kernel_main() {
unsafe { unsafe {
asm!("ldr x0, =kernel_main", "msr ELR_EL1, x0"); asm!("ldr x0, =kernel_main", "msr ELR_EL1, x0");
@@ -238,3 +268,13 @@ pub mod daif {
unsafe { asm!("msr DAIFClr, #0x2", options(nomem, nostack)) } unsafe { asm!("msr DAIFClr, #0x2", options(nomem, nostack)) }
} }
} }
pub fn initialize_interrupt_handler() {
unsafe { INTERRUPT_HANDLERS = Some(Vec::new()) };
}
pub fn register_interrupt_handler(source: IRQSource, function: fn()) {
if let Some(handler_vec) = unsafe { INTERRUPT_HANDLERS.as_mut() } {
handler_vec.push(InterruptHandlers { source, function });
}
}

View File

@@ -6,14 +6,13 @@ extern crate alloc;
use alloc::boxed::Box; use alloc::boxed::Box;
use core::{ use core::{
arch::asm, arch::asm,
fmt,
panic::PanicInfo, panic::PanicInfo,
ptr::{read_volatile, write_volatile}, ptr::{read_volatile, write_volatile},
}; };
use heap::Heap; use heap::Heap;
use crate::logger::{DefaultLogger, Logger}; use crate::{interrupt_handlers::initialize_interrupt_handler, logger::DefaultLogger};
static PERIPHERAL_BASE: u32 = 0x3F00_0000; static PERIPHERAL_BASE: u32 = 0x3F00_0000;
@@ -74,4 +73,5 @@ pub fn get_current_el() -> u64 {
pub fn initialize_kernel() { pub fn initialize_kernel() {
logger::set_logger(Box::new(DefaultLogger)); logger::set_logger(Box::new(DefaultLogger));
initialize_interrupt_handler();
} }

View File

@@ -6,43 +6,40 @@ use crate::peripherals::uart;
static mut LOGGER: Option<Box<dyn Logger>> = None; static mut LOGGER: Option<Box<dyn Logger>> = None;
pub trait Logger: Write + Sync {} pub trait Logger: Write + Sync {
fn flush(&mut self);
}
pub struct DefaultLogger; pub struct DefaultLogger;
impl Logger for DefaultLogger {} impl Logger for DefaultLogger {
fn flush(&mut self) {}
}
impl Write for DefaultLogger { impl Write for DefaultLogger {
fn write_str(&mut self, s: &str) -> core::fmt::Result { fn write_str(&mut self, s: &str) -> core::fmt::Result {
uart::write_str(s) uart::Uart.write_str(s)
} }
} }
#[macro_export] #[macro_export]
macro_rules! print { macro_rules! log {
() => {}; () => {};
($($arg:tt)*) => { ($($arg:tt)*) => {
$crate::logger::_print(format_args!($($arg)*)) $crate::logger::log(format_args!($($arg)*))
}; };
} }
pub fn _print(args: fmt::Arguments) { pub fn log(args: fmt::Arguments) {
unsafe { unsafe {
if let Some(logger) = LOGGER.as_mut() { if let Some(logger) = LOGGER.as_mut() {
logger.write_fmt(args); logger.write_str("\n").unwrap();
logger.write_fmt(args).unwrap();
logger.flush();
} }
} }
} }
#[macro_export]
macro_rules! println {
() => {};
($($arg:tt)*) => {
$crate::print!($($arg)*);
$crate::print!("\r\n");
};
}
pub fn set_logger(logger: Box<dyn Logger>) { pub fn set_logger(logger: Box<dyn Logger>) {
unsafe { unsafe {
LOGGER = Some(logger); LOGGER = Some(logger);

View File

@@ -15,21 +15,17 @@ use nova::{
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::{daif, enable_irq_source, IRQSource},
mailbox, log, mailbox,
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,
SpecificGpio, SpecificGpio,
}, },
uart::{read_uart_data, uart_init}, uart::uart_init,
}, },
print, println, println,
}; };
use crate::uart_term::Terminal;
mod uart_term;
global_asm!(include_str!("vector.S")); global_asm!(include_str!("vector.S"));
extern "C" { extern "C" {
@@ -120,14 +116,13 @@ pub extern "C" fn el0() -> ! {
fb.draw_function(cos, 100, 101, RED); fb.draw_function(cos, 100, 101, RED);
loop { loop {
read_uart_data();
let temp = mailbox::read_soc_temp([0]).unwrap(); let temp = mailbox::read_soc_temp([0]).unwrap();
println!("{} °C", temp[1] / 1000); log!("{} °C", temp[1] / 1000);
blink_gpio(SpecificGpio::OnboardLed as u8, 500); blink_gpio(SpecificGpio::OnboardLed as u8, 500);
let b = Box::new([1, 2, 3, 4]); let b = Box::new([1, 2, 3, 4]);
println!("{:?}", b); log!("{:?}", b);
} }
} }

View File

@@ -19,13 +19,54 @@ const UART0_FBRD: u32 = 0x3F20_1028;
const UART0_CR: u32 = 0x3F20_1030; const UART0_CR: u32 = 0x3F20_1030;
const UART0_CR_UARTEN: u32 = 1 << 0; const UART0_CR_UARTEN: u32 = 1 << 0;
const UART0_CR_LBE: u32 = 1 << 7;
const UART0_CR_TXE: u32 = 1 << 8; const UART0_CR_TXE: u32 = 1 << 8;
const UART0_CR_RXE: u32 = 1 << 9; const UART0_CR_RXE: u32 = 1 << 9;
const UART0_LCRH: u32 = 0x3F20_102C; const UART0_LCRH: u32 = 0x3F20_102C;
const UART0_LCRH_FEN: u32 = 1 << 4; const UART0_LCRH_FEN: u32 = 1 << 4;
const UART0_IMSC: u32 = 0x3F20_1038;
const UART0_IMSC_RXIM: u32 = 1 << 4;
const UART0_ICR: u32 = 0x3F20_1044;
pub struct Uart;
impl Write for Uart {
fn write_str(&mut self, s: &str) -> core::fmt::Result {
for byte in s.bytes() {
while (unsafe { read_address(UART0_FR) } & UART0_FR_TXFF) != 0 {
unsafe { asm!("nop") }
}
unsafe { write_address(UART0_DR, byte as u32) };
}
// wait till uart is not busy anymore
while ((unsafe { read_address(UART0_FR) } >> 3) & 0b1) != 0 {}
Ok(())
}
}
#[macro_export]
macro_rules! print {
() => {};
($($arg:tt)*) => {
$crate::peripherals::uart::_print(format_args!($($arg)*))
};
}
#[macro_export]
macro_rules! println {
() => {};
($($arg:tt)*) => {
$crate::print!($($arg)*);
$crate::print!("\r\n");
};
}
pub fn _print(args: fmt::Arguments) {
let _ = Uart.write_fmt(args);
}
/// Initialize UART peripheral /// Initialize UART peripheral
pub fn uart_init() { pub fn uart_init() {
let baud_div_times_64 = (UART_CLK * 4) / BAUD; let baud_div_times_64 = (UART_CLK * 4) / BAUD;
@@ -41,6 +82,7 @@ pub fn uart_init() {
write_address(UART0_FBRD, fbrd); write_address(UART0_FBRD, fbrd);
} }
uart_enable_rx_interrupt();
uart_set_lcrh(0b11, true); uart_set_lcrh(0b11, true);
// Enable transmit, receive and uart // Enable transmit, receive and uart
@@ -76,6 +118,10 @@ fn uart_fifo_enable(enable: bool) {
unsafe { write_address(UART0_LCRH, lcrh) }; unsafe { write_address(UART0_LCRH, lcrh) };
} }
fn uart_enable_rx_interrupt() {
unsafe { write_address(UART0_IMSC, UART0_IMSC_RXIM) };
}
/// Set UART word length and set FIFO status /// Set UART word length and set FIFO status
fn uart_set_lcrh(wlen: u32, enable_fifo: bool) { fn uart_set_lcrh(wlen: u32, enable_fifo: bool) {
let mut value = (wlen & 0b11) << 5; let mut value = (wlen & 0b11) << 5;
@@ -85,21 +131,12 @@ fn uart_set_lcrh(wlen: u32, enable_fifo: bool) {
unsafe { write_address(UART0_LCRH, value) }; unsafe { write_address(UART0_LCRH, value) };
} }
pub fn read_uart_data() { pub fn read_uart_data() -> char {
println!( (unsafe { read_address(UART0_DR) } & 0xFF) as u8 as char
"{:?}",
(unsafe { read_address(UART0_DR) } & 0xFF) as u8 as char
);
} }
pub fn write_str(s: &str) -> core::fmt::Result { pub fn clear_uart_interrupt_state() {
for byte in s.bytes() { unsafe {
while (unsafe { read_address(UART0_FR) } & UART0_FR_TXFF) != 0 { write_address(UART0_ICR, 1 << 4);
unsafe { asm!("nop") }
}
unsafe { write_address(UART0_DR, byte as u32) };
} }
// wait till uart is not busy anymore
while ((unsafe { read_address(UART0_FR) } >> 3) & 0b1) != 0 {}
Ok(())
} }

53
src/terminal.rs Normal file
View File

@@ -0,0 +1,53 @@
use core::fmt::Write;
use alloc::string::String;
use nova::{
interrupt_handlers::register_interrupt_handler, logger::Logger,
peripherals::uart::read_uart_data, print, println,
};
pub struct Terminal {
buffer: String,
input: String,
}
impl Terminal {
pub fn new() -> Self {
Self {
buffer: String::new(),
input: String::new(),
}
}
fn flush(&mut self) {
println!("{}", self.buffer);
print!("> {}", self.input);
self.buffer.clear();
}
}
impl Write for Terminal {
fn write_str(&mut self, s: &str) -> core::fmt::Result {
self.buffer.push_str(s);
Ok(())
}
}
impl Logger for Terminal {
fn flush(&mut self) {
println!("{}", self.buffer);
print!("> {}", self.input);
self.buffer.clear();
}
}
fn terminal_uart_rx_interrupt_handler() {
print!("{}", read_uart_data());
}
pub fn register_terminal_interrupt_handler() {
register_interrupt_handler(
nova::interrupt_handlers::IRQSource::UartInt,
terminal_uart_rx_interrupt_handler,
);
}

View File

@@ -1,17 +0,0 @@
use core::fmt::Write;
use nova::logger::Logger;
/// Goals:
/// - I want to have a functional terminal over uart
/// - It shall continue to log
pub struct Terminal {}
impl Write for Terminal {
fn write_str(&mut self, s: &str) -> core::fmt::Result {
Ok(())
}
}
impl Logger for Terminal {}

View File

@@ -6,6 +6,6 @@ llvm-objcopy -O binary ../target/aarch64-unknown-none/release/nova ../target/aar
qemu-system-aarch64 \ qemu-system-aarch64 \
-M raspi3b \ -M raspi3b \
-cpu cortex-a53 \ -cpu cortex-a53 \
-serial pty \ -serial stdio \
-sd ../sd.img \ -sd ../sd.img \
-kernel ../target/aarch64-unknown-none/release/kernel8.img -kernel ../target/aarch64-unknown-none/release/kernel8.img