mirror of
https://github.com/iceHtwoO/novaOS.git
synced 2026-04-16 20:22:26 +00:00
Impelement a basic logger, WIP
This commit is contained in:
@@ -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 });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
15
src/main.rs
15
src/main.rs
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
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 {}
|
|
||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user