diff --git a/.gitignore b/.gitignore index 1bc1b3f..3e3ad8f 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ sd.img settings.json .DS_Store .venv +.nvimlog diff --git a/.vscode/launch.json b/.vscode/launch.json index 77dba6e..00f9603 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -58,15 +58,12 @@ ], "preLaunchTask": "Run QEMU wo window" }, - { - "name": "Attach LLDB", + "name": "LLDB", "type": "lldb", - "request": "attach", - "debugServer": 1234, + "request": "launch", "program": "${workspaceFolder}/target/aarch64-unknown-none/debug/nova", - "stopOnEntry": true, - "processCreateCommands": ["gdb-remote localhost:1234"] + "preLaunchTask": "Run QEMU wo window" } ] } diff --git a/Cargo.lock b/Cargo.lock index 23658e2..c50c509 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -40,12 +40,19 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + [[package]] name = "nova" version = "0.1.0" dependencies = [ "heap", "libm", + "log", "nova_error", "paste", ] diff --git a/Cargo.toml b/Cargo.toml index e5a1c75..81e363e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,7 @@ libm = "0.2.15" heap = {path = "workspace/heap"} nova_error = {path = "workspace/nova_error"} paste = "1.0.15" +log = "0.4.29" [workspace] diff --git a/src/aarch64/mmu.rs b/src/aarch64/mmu.rs index 50aac0c..0762a95 100644 --- a/src/aarch64/mmu.rs +++ b/src/aarch64/mmu.rs @@ -106,6 +106,18 @@ pub enum PhysSource { #[repr(align(4096))] pub struct PageTable([TableEntry; TABLE_ENTRY_COUNT]); +impl Iterator for PageTable { + type Item = VirtAddr; + + fn next(&mut self) -> Option { + for (offset, entity) in self.0.iter().enumerate() { + if entity.is_invalid() { + return Some(offset); + } + } + None + } +} #[no_mangle] pub static mut TRANSLATIONTABLE_TTBR0: PageTable = PageTable([TableEntry { value: 0 }; 512]); #[no_mangle] @@ -197,7 +209,7 @@ fn map_range_dynamic( /// Allocate a singe page. pub fn alloc_page( - virtual_address: usize, + virtual_address: VirtAddr, base_table: *mut PageTable, additional_flags: u64, ) -> Result<(), NovaError> { @@ -209,6 +221,28 @@ pub fn alloc_page( ) } +/// Allocate a singe page in one block. +pub fn find_free_kerne_page_in_block(start: VirtAddr) -> Result { + if !start.is_multiple_of(GRANULARITY) { + return Err(NovaError::Misalignment); + } + + let (off1, off2, _) = virtual_address_to_table_offset(start); + let offsets = [off1, off2]; + let table = unsafe { + &mut *navigate_table( + core::ptr::addr_of_mut!(TRANSLATIONTABLE_TTBR1), + &offsets, + true, + )? + }; + + if let Some(virt_addr) = table.next() { + return Ok(virt_addr); + } + Err(NovaError::OutOfMeomory) +} + /// Allocate a single page at an explicit `physical_address`. pub fn alloc_page_explicit( virtual_address: usize, diff --git a/src/config.S b/src/config.S index 619f33c..5e13a6d 100644 --- a/src/config.S +++ b/src/config.S @@ -77,7 +77,7 @@ configure_mmu_el1: .align 4 .global el1_to_el0 el1_to_el0: - + mov x8, x0 // Set SPSR_EL1: return to EL0t mov x0, #(0b0000) msr SPSR_EL1, x0 @@ -93,5 +93,6 @@ el1_to_el0: isb + mov x0, x8 // Return to EL0 eret diff --git a/src/configuration/memory_mapping.rs b/src/configuration/memory_mapping.rs index 2d0c21c..2adbcee 100644 --- a/src/configuration/memory_mapping.rs +++ b/src/configuration/memory_mapping.rs @@ -19,6 +19,8 @@ pub const EL0_STACK_SIZE: usize = LEVEL2_BLOCK_SIZE * 2; pub const MAILBOX_VIRTUAL_ADDRESS: VirtAddr = 0xFFFF_FF81_FFFF_E000; pub static mut MAILBOX_PHYSICAL_ADDRESS: Option = None; +pub const APPLICATION_TRANSLATION_TABLE_VA: VirtAddr = 0xFFFF_FF81_FE00_0000; + extern "C" { static __text_end: u64; static __share_end: u64; @@ -99,6 +101,7 @@ pub fn initialize_mmu_translation_tables() { ) .unwrap(); + // Allocate Mailbox buffer { let addr = reserve_page(); unsafe { MAILBOX_PHYSICAL_ADDRESS = Some(addr) }; diff --git a/src/framebuffer.rs b/src/framebuffer.rs index 0102927..7cd247a 100644 --- a/src/framebuffer.rs +++ b/src/framebuffer.rs @@ -4,10 +4,8 @@ mod bitmaps; use bitmaps::BASIC_LEGACY; -use crate::{ - pi3::mailbox::{read_mailbox, write_mailbox}, - println, -}; +use crate::pi3::mailbox::{read_mailbox, write_mailbox}; +use log::error; #[repr(align(16))] struct Mailbox([u32; 36]); @@ -237,7 +235,7 @@ impl Default for FrameBuffer { let _ = read_mailbox(8); if mailbox.0[1] == 0 { - println!("Failed"); + error!("Mailbox request was not processed!"); } mailbox.0[28] &= 0x3FFFFFFF; diff --git a/src/interrupt_handlers.rs b/src/interrupt_handlers.rs index ab0a41b..d2df3c8 100644 --- a/src/interrupt_handlers.rs +++ b/src/interrupt_handlers.rs @@ -2,8 +2,9 @@ use core::arch::asm; use crate::{ aarch64::registers::{daif::mask_all, read_esr_el1, read_exception_source_el}, - get_current_el, println, + get_current_el, }; +use log::debug; const INTERRUPT_BASE: u32 = 0x3F00_B000; const IRQ_PENDING_BASE: u32 = INTERRUPT_BASE + 0x204; @@ -66,17 +67,17 @@ unsafe extern "C" fn rust_synchronous_interrupt_no_el_change() { mask_all(); 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(read_esr_el1())); - println!("Return register address: {:#x}", read_esr_el1()); - println!("-------------------------------------"); + debug!("--------Sync Exception in EL{}--------", source_el); + debug!("No EL change"); + debug!("Current EL: {}", get_current_el()); + debug!("{:?}", EsrElX::from(read_esr_el1())); + debug!("Return register address: {:#x}", read_esr_el1()); + debug!("-------------------------------------"); } -fn set_return_to_kernel_main() { +fn set_return_to_kernel_loop() { unsafe { - asm!("ldr x0, =kernel_main", "msr ELR_EL1, x0"); + asm!("ldr x0, =kernel_loop", "msr ELR_EL1, x0"); asm!("mov x0, #(0b0101)", "msr SPSR_EL1, x0"); } } diff --git a/src/interrupt_handlers/irq.rs b/src/interrupt_handlers/irq.rs index 29d3388..f7cc3ad 100644 --- a/src/interrupt_handlers/irq.rs +++ b/src/interrupt_handlers/irq.rs @@ -12,9 +12,11 @@ use crate::{ gpio::{read_gpio_event_detect_status, reset_gpio_event_detect_status}, uart::clear_uart_interrupt_state, }, - println, read_address, write_address, + read_address, write_address, }; use alloc::vec::Vec; +use log::{debug, info}; + struct InterruptHandlers { source: IRQSource, function: fn(), @@ -60,9 +62,9 @@ unsafe extern "C" fn rust_irq_handler() { if pending_irqs & GPIO_PENDING_BIT_OFFSET != 0 { handle_gpio_interrupt(); let source_el = read_exception_source_el() >> 2; - println!("Source EL: {}", source_el); - println!("Current EL: {}", get_current_el()); - println!("Return register address: {:#x}", read_esr_el1()); + debug!("Source EL: {}", source_el); + debug!("Current EL: {}", get_current_el()); + debug!("Return register address: {:#x}", read_esr_el1()); } if let Some(handler_vec) = unsafe { &*core::ptr::addr_of_mut!(INTERRUPT_HANDLERS) } { @@ -76,7 +78,7 @@ unsafe extern "C" fn rust_irq_handler() { } fn handle_gpio_interrupt() { - println!("Interrupt"); + debug!("GPIO interrupt triggered"); for i in 0..=53u32 { let val = read_gpio_event_detect_status(i); @@ -84,7 +86,7 @@ fn handle_gpio_interrupt() { #[allow(clippy::single_match)] match i { 26 => { - println!("Button Pressed"); + info!("Button Pressed"); } _ => {} } diff --git a/src/interrupt_handlers/synchronous.rs b/src/interrupt_handlers/synchronous.rs index 2b20364..8f06c70 100644 --- a/src/interrupt_handlers/synchronous.rs +++ b/src/interrupt_handlers/synchronous.rs @@ -1,11 +1,12 @@ use crate::{ aarch64::registers::{daif::mask_all, read_elr_el1, read_esr_el1, read_exception_source_el}, get_current_el, - interrupt_handlers::{set_return_to_kernel_main, EsrElX, TrapFrame}, + interrupt_handlers::{set_return_to_kernel_loop, EsrElX, TrapFrame}, pi3::mailbox, - println, }; +use log::{debug, error, warn}; + /// Synchronous Exception Handler /// /// Source is a lower Exception level, where the implemented level @@ -15,22 +16,23 @@ use crate::{ unsafe extern "C" fn rust_synchronous_interrupt_imm_lower_aarch64(frame: &mut TrapFrame) -> usize { mask_all(); let esr: EsrElX = EsrElX::from(read_esr_el1()); + debug!("Synchronous interrupt from lower EL triggered"); + log_sync_exception(); match esr.ec { 0b100100 => { - log_sync_exception(); - println!("Cause: Data Abort from a lower Exception level"); + warn!("Cause: Data Abort from a lower Exception level"); } 0b010101 => { - println!("Cause: SVC instruction execution in AArch64"); + debug!("Cause: SVC instruction execution in AArch64"); return handle_svc(frame); } _ => { - println!("Unknown Error Code: {:b}", esr.ec); + error!("Synchronous interrupt: Unknown Error Code: {:b}", esr.ec); } } - println!("Returning to kernel main..."); - set_return_to_kernel_main(); + warn!("UnhandledException -> Returning to kernel..."); + set_return_to_kernel_loop(); 0 } @@ -46,11 +48,11 @@ fn handle_svc(frame: &mut TrapFrame) -> usize { fn log_sync_exception() { 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()); + debug!("--------Sync Exception in EL{}--------", source_el); + debug!("Exception escalated to EL {}", get_current_el()); + debug!("Current EL: {}", get_current_el()); let esr: EsrElX = EsrElX::from(read_esr_el1()); - println!("{:?}", esr); - println!("Return address: {:#x}", read_elr_el1()); - println!("-------------------------------------"); + debug!("{:?}", esr); + debug!("Return address: {:#x}", read_elr_el1()); + debug!("-------------------------------------"); } diff --git a/src/lib.rs b/src/lib.rs index 19f5b29..25b0865 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,12 +3,13 @@ extern crate alloc; -use alloc::boxed::Box; use core::{ arch::asm, panic::PanicInfo, ptr::{read_volatile, write_volatile}, }; +use log::LevelFilter; +use log::{Level, Metadata, Record}; use heap::Heap; @@ -18,10 +19,11 @@ use crate::{ WRITABLE, }, interrupt_handlers::irq::initialize_interrupt_handler, - logger::DefaultLogger, pi3::timer::sleep_s, + terminal::{flush_terminal, init_terminal}, }; +static LOGGER: UartLogger = UartLogger; static PERIPHERAL_BASE: usize = 0x3F00_0000; unsafe extern "C" { @@ -31,7 +33,7 @@ unsafe extern "C" { #[global_allocator] pub static mut GLOBAL_ALLOCATOR: Heap = Heap::empty(); -pub unsafe fn init_kernel_heap() { +pub unsafe fn initialize_kernel_heap() { let start = core::ptr::addr_of_mut!(__kernel_end) as usize | KERNEL_VIRTUAL_MEM_SPACE; let size = LEVEL2_BLOCK_SIZE * 2; @@ -54,9 +56,9 @@ pub mod aarch64; pub mod configuration; pub mod framebuffer; pub mod interrupt_handlers; -pub mod logger; pub mod pi3; +pub mod terminal; #[inline(always)] pub unsafe fn read_address(address: u32) -> u32 { @@ -80,14 +82,33 @@ pub fn get_current_el() -> u64 { el >> 2 } -static mut KERNEL_INITIALIZED: bool = false; - pub fn initialize_kernel() { - if unsafe { KERNEL_INITIALIZED } { - return; - } - unsafe { init_kernel_heap() }; - logger::set_logger(Box::new(DefaultLogger)); + unsafe { initialize_kernel_heap() }; initialize_interrupt_handler(); - unsafe { KERNEL_INITIALIZED = true }; + init_terminal(); +} + +struct UartLogger; + +impl log::Log for UartLogger { + fn enabled(&self, metadata: &Metadata) -> bool { + metadata.level() <= Level::Debug + } + + fn log(&self, record: &Record) { + if self.enabled(record.metadata()) { + println!("{} - {}", record.level(), record.args()); + if record.level() <= Level::Info { + flush_terminal(); + } + } + } + + fn flush(&self) {} +} + +pub fn init_logger() { + log::set_logger(&LOGGER) + .map(|()| log::set_max_level(LevelFilter::Debug)) + .unwrap(); } diff --git a/src/logger.rs b/src/logger.rs deleted file mode 100644 index c769551..0000000 --- a/src/logger.rs +++ /dev/null @@ -1,45 +0,0 @@ -use core::fmt::Write; - -use alloc::{boxed::Box, fmt}; - -use crate::peripherals::uart; - -static mut LOGGER: Option> = None; - -pub trait Logger: Write + Sync { - fn flush(&mut self); -} - -pub struct DefaultLogger; - -impl Logger for DefaultLogger { - fn flush(&mut self) {} -} - -impl Write for DefaultLogger { - fn write_str(&mut self, s: &str) -> core::fmt::Result { - uart::Uart.write_str(s) - } -} - -#[macro_export] -macro_rules! log { - () => {}; - ($($arg:tt)*) => { - $crate::logger::log(format_args!($($arg)*)) - }; -} - -pub fn log(args: fmt::Arguments) { - if let Some(logger) = unsafe { &mut *core::ptr::addr_of_mut!(LOGGER) } { - logger.write_str("\n").unwrap(); - logger.write_fmt(args).unwrap(); - logger.flush(); - } -} - -pub fn set_logger(logger: Box) { - unsafe { - LOGGER = Some(logger); - } -} diff --git a/src/main.rs b/src/main.rs index 8bb9675..0b1d814 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,6 +6,7 @@ use core::{ arch::{asm, global_asm}, ptr::write_volatile, }; +use log::{debug, info}; extern crate alloc; @@ -14,7 +15,7 @@ use nova::{ aarch64::registers::{daif, read_id_aa64mmfr0_el1}, configuration::memory_mapping::initialize_mmu_translation_tables, framebuffer::{FrameBuffer, BLUE, GREEN, RED}, - get_current_el, + get_current_el, init_logger, interrupt_handlers::irq::{enable_irq_source, IRQSource}, peripherals::{ gpio::{ @@ -23,7 +24,7 @@ use nova::{ }, uart::uart_init, }, - println, + print, println, }; global_asm!(include_str!("vector.S")); @@ -33,7 +34,6 @@ static mut FRAMEBUFFER: Option = None; extern "C" { fn el2_to_el1(); - fn el1_to_el0(); fn configure_mmu_el1(); static mut __bss_start: u32; static mut __bss_end: u32; @@ -60,16 +60,18 @@ pub extern "C" fn main() -> ! { // Set ACT Led to Outout let _ = set_gpio_function(21, GPIOFunction::Output); + init_logger(); - println!("Hello World!"); - println!("Exception level: {}", get_current_el()); + info!("Hello World!"); + info!("Current exception level: {}", get_current_el()); + info!("initializing MMU..."); initialize_mmu_translation_tables(); unsafe { configure_mmu_el1() }; - println!("MMU initialized..."); + info!("MMU configured!"); - println!("Register: AA64MMFR0_EL1: {:064b}", read_id_aa64mmfr0_el1()); - println!("Moving El2->EL1"); + debug!("Register: AA64MMFR0_EL1: {:064b}", read_id_aa64mmfr0_el1()); + info!("Moving El2->EL1"); unsafe { FRAMEBUFFER = Some(FrameBuffer::default()) }; unsafe { @@ -89,28 +91,32 @@ unsafe fn zero_bss() { } #[no_mangle] -pub extern "C" fn kernel_main() -> ! { - println!("Kernel Start..."); +pub extern "C" fn kernel_main() { nova::initialize_kernel(); + info!("Kernel Initialized..."); + info!("Current exception Level: {}", get_current_el()); + let mut test_vector = Vec::new(); for i in 0..20 { test_vector.push(i); } - println!("heap allocation test: {:?}", test_vector); + debug!("heap allocation test: {:?}", test_vector); - println!("Exception Level: {}", get_current_el()); + enable_irq_source(IRQSource::UartInt); + + kernel_loop(); +} + +#[no_mangle] +pub extern "C" fn kernel_loop() { daif::unmask_all(); - unsafe { - el1_to_el0(); - }; - #[allow(clippy::empty_loop)] loop {} } #[no_mangle] -pub extern "C" fn el0() -> ! { +pub extern "C" fn el0(input: usize) { println!("Jumped into EL0"); // Set GPIO 26 to Input @@ -119,8 +125,6 @@ pub extern "C" fn el0() -> ! { gpio_pull_up(26); set_falling_edge_detect(26, true); - enable_irq_source(IRQSource::UartInt); - if let Some(fb) = unsafe { FRAMEBUFFER.as_mut() } { for i in 0..1080 { fb.draw_pixel(50, i, BLUE); @@ -134,12 +138,27 @@ pub extern "C" fn el0() -> ! { fb.draw_function(cos, 0, 101, RED); } - loop { - let temp = syscall(67); - println!("{} °C", temp / 1000); + let _temp = syscall(67); - blink_gpio(SpecificGpio::OnboardLed as u8, 500); + println!("Calculting prime to: {}", input); + + for i in 3..input { + let mut is_prime = true; + for j in 3..i { + if i == j { + continue; + } + if i % j == 0 { + is_prime = false; + } + } + if is_prime { + print!("{} ", i); + } } + println!(""); + + blink_gpio(SpecificGpio::OnboardLed as u8, 500); } fn cos(x: u32) -> f64 { diff --git a/src/terminal.rs b/src/terminal.rs index 83b22a7..f64dd33 100644 --- a/src/terminal.rs +++ b/src/terminal.rs @@ -1,53 +1,92 @@ -use core::fmt::Write; +use core::arch::asm; use alloc::string::String; -use nova::{ - interrupt_handlers::register_interrupt_handler, logger::Logger, - peripherals::uart::read_uart_data, print, println, + +use crate::{ + interrupt_handlers::irq::{register_interrupt_handler, IRQSource}, + peripherals::uart::read_uart_data, + pi3::mailbox::read_soc_temp, + print, println, }; +pub static mut TERMINAL: Option = None; + pub struct Terminal { - buffer: String, input: String, } +extern "C" { + fn el1_to_el0(); +} + +impl Default for Terminal { + fn default() -> Self { + Self::new() + } +} + 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(); + print!("\n> {}", self.input); + } + + fn exec(&mut self) { + print!("\n"); + let val = self.input.clone(); + self.input.clear(); + + match val.as_str() { + "temp" => { + println!("{}", read_soc_temp([0]).unwrap()[1]); + } + "el0" => unsafe { + let i = 69; + asm!("", in("x0") i); + el1_to_el0(); + }, + _ => { + println!("Unknown command: \"{}\"", self.input); + } + } + self.input.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(); - } +pub fn init_terminal() { + unsafe { TERMINAL = Some(Terminal::new()) }; + register_terminal_interrupt_handler(); } fn terminal_uart_rx_interrupt_handler() { - print!("{}", read_uart_data()); + let input = read_uart_data(); + #[allow(static_mut_refs)] + if let Some(term) = unsafe { TERMINAL.as_mut() } { + match input { + '\r' => { + term.exec(); + term.flush(); + } + _ => { + term.input.push(input); + print!("{}", input); + } + } + } } -pub fn register_terminal_interrupt_handler() { - register_interrupt_handler( - nova::interrupt_handlers::IRQSource::UartInt, - terminal_uart_rx_interrupt_handler, - ); +pub fn flush_terminal() { + #[allow(static_mut_refs)] + if let Some(term) = unsafe { TERMINAL.as_mut() } { + term.flush(); + } +} + +fn register_terminal_interrupt_handler() { + register_interrupt_handler(IRQSource::UartInt, terminal_uart_rx_interrupt_handler); } diff --git a/workspace/nova_error/src/lib.rs b/workspace/nova_error/src/lib.rs index bc32817..266905c 100644 --- a/workspace/nova_error/src/lib.rs +++ b/workspace/nova_error/src/lib.rs @@ -11,4 +11,5 @@ pub enum NovaError { Misalignment, InvalidGranularity, Paging, + OutOfMeomory, }