mirror of
https://github.com/iceHtwoO/novaOS.git
synced 2026-04-17 04:32:27 +00:00
Impelement a basic logger, WIP
This commit is contained in:
@@ -1,9 +1,14 @@
|
||||
use core::arch::asm;
|
||||
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use crate::{
|
||||
get_current_el,
|
||||
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,
|
||||
};
|
||||
|
||||
@@ -14,6 +19,15 @@ const DISABLE_IRQ_BASE: u32 = INTERRUPT_BASE + 0x21C;
|
||||
|
||||
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)]
|
||||
pub enum IRQSource {
|
||||
AuxInt = 29,
|
||||
@@ -59,11 +73,20 @@ unsafe extern "C" fn rust_irq_handler() {
|
||||
|
||||
if pending_irqs & GPIO_PENDING_BIT_OFFSET != 0 {
|
||||
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]
|
||||
@@ -107,6 +130,13 @@ unsafe extern "C" fn rust_synchronous_interrupt_imm_lower_aarch64() {
|
||||
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() {
|
||||
unsafe {
|
||||
asm!("ldr x0, =kernel_main", "msr ELR_EL1, x0");
|
||||
@@ -238,3 +268,13 @@ pub mod daif {
|
||||
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 });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,14 +6,13 @@ extern crate alloc;
|
||||
use alloc::boxed::Box;
|
||||
use core::{
|
||||
arch::asm,
|
||||
fmt,
|
||||
panic::PanicInfo,
|
||||
ptr::{read_volatile, write_volatile},
|
||||
};
|
||||
|
||||
use heap::Heap;
|
||||
|
||||
use crate::logger::{DefaultLogger, Logger};
|
||||
use crate::{interrupt_handlers::initialize_interrupt_handler, logger::DefaultLogger};
|
||||
|
||||
static PERIPHERAL_BASE: u32 = 0x3F00_0000;
|
||||
|
||||
@@ -74,4 +73,5 @@ pub fn get_current_el() -> u64 {
|
||||
|
||||
pub fn initialize_kernel() {
|
||||
logger::set_logger(Box::new(DefaultLogger));
|
||||
initialize_interrupt_handler();
|
||||
}
|
||||
|
||||
@@ -6,43 +6,40 @@ use crate::peripherals::uart;
|
||||
|
||||
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;
|
||||
|
||||
impl Logger for DefaultLogger {}
|
||||
impl Logger for DefaultLogger {
|
||||
fn flush(&mut self) {}
|
||||
}
|
||||
|
||||
impl Write for DefaultLogger {
|
||||
fn write_str(&mut self, s: &str) -> core::fmt::Result {
|
||||
uart::write_str(s)
|
||||
uart::Uart.write_str(s)
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! print {
|
||||
macro_rules! log {
|
||||
() => {};
|
||||
($($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 {
|
||||
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>) {
|
||||
unsafe {
|
||||
LOGGER = Some(logger);
|
||||
|
||||
15
src/main.rs
15
src/main.rs
@@ -15,21 +15,17 @@ use nova::{
|
||||
framebuffer::{FrameBuffer, BLUE, GREEN, RED},
|
||||
get_current_el, init_heap,
|
||||
interrupt_handlers::{daif, enable_irq_source, IRQSource},
|
||||
mailbox,
|
||||
log, mailbox,
|
||||
peripherals::{
|
||||
gpio::{
|
||||
blink_gpio, gpio_pull_up, set_falling_edge_detect, set_gpio_function, GPIOFunction,
|
||||
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"));
|
||||
|
||||
extern "C" {
|
||||
@@ -120,14 +116,13 @@ pub extern "C" fn el0() -> ! {
|
||||
fb.draw_function(cos, 100, 101, RED);
|
||||
|
||||
loop {
|
||||
read_uart_data();
|
||||
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);
|
||||
|
||||
let b = Box::new([1, 2, 3, 4]);
|
||||
println!("{:?}", b);
|
||||
log!("{:?}", b);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,13 +19,54 @@ const UART0_FBRD: u32 = 0x3F20_1028;
|
||||
const UART0_CR: u32 = 0x3F20_1030;
|
||||
const UART0_CR_UARTEN: u32 = 1 << 0;
|
||||
|
||||
const UART0_CR_LBE: u32 = 1 << 7;
|
||||
const UART0_CR_TXE: u32 = 1 << 8;
|
||||
const UART0_CR_RXE: u32 = 1 << 9;
|
||||
|
||||
const UART0_LCRH: u32 = 0x3F20_102C;
|
||||
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
|
||||
pub fn uart_init() {
|
||||
let baud_div_times_64 = (UART_CLK * 4) / BAUD;
|
||||
@@ -41,6 +82,7 @@ pub fn uart_init() {
|
||||
write_address(UART0_FBRD, fbrd);
|
||||
}
|
||||
|
||||
uart_enable_rx_interrupt();
|
||||
uart_set_lcrh(0b11, true);
|
||||
|
||||
// Enable transmit, receive and uart
|
||||
@@ -76,6 +118,10 @@ fn uart_fifo_enable(enable: bool) {
|
||||
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
|
||||
fn uart_set_lcrh(wlen: u32, enable_fifo: bool) {
|
||||
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) };
|
||||
}
|
||||
|
||||
pub fn read_uart_data() {
|
||||
println!(
|
||||
"{:?}",
|
||||
(unsafe { read_address(UART0_DR) } & 0xFF) as u8 as char
|
||||
);
|
||||
pub fn read_uart_data() -> char {
|
||||
(unsafe { read_address(UART0_DR) } & 0xFF) as u8 as char
|
||||
}
|
||||
|
||||
pub fn write_str(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) };
|
||||
pub fn clear_uart_interrupt_state() {
|
||||
unsafe {
|
||||
write_address(UART0_ICR, 1 << 4);
|
||||
}
|
||||
// wait till uart is not busy anymore
|
||||
while ((unsafe { read_address(UART0_FR) } >> 3) & 0b1) != 0 {}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
53
src/terminal.rs
Normal file
53
src/terminal.rs
Normal 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,
|
||||
);
|
||||
}
|
||||
@@ -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 {}
|
||||
Reference in New Issue
Block a user