feat: UART terminal (#7)

* feat: basic terminal

* feat: execute application via terminal
This commit is contained in:
Alexander Neuhäuser
2026-03-24 17:50:28 +01:00
committed by GitHub
parent 34a66ff87a
commit f33100d36b
16 changed files with 232 additions and 150 deletions

1
.gitignore vendored
View File

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

9
.vscode/launch.json vendored
View File

@@ -58,15 +58,12 @@
], ],
"preLaunchTask": "Run QEMU wo window" "preLaunchTask": "Run QEMU wo window"
}, },
{ {
"name": "Attach LLDB", "name": "LLDB",
"type": "lldb", "type": "lldb",
"request": "attach", "request": "launch",
"debugServer": 1234,
"program": "${workspaceFolder}/target/aarch64-unknown-none/debug/nova", "program": "${workspaceFolder}/target/aarch64-unknown-none/debug/nova",
"stopOnEntry": true, "preLaunchTask": "Run QEMU wo window"
"processCreateCommands": ["gdb-remote localhost:1234"]
} }
] ]
} }

7
Cargo.lock generated
View File

@@ -40,12 +40,19 @@ version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de"
[[package]]
name = "log"
version = "0.4.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
[[package]] [[package]]
name = "nova" name = "nova"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"heap", "heap",
"libm", "libm",
"log",
"nova_error", "nova_error",
"paste", "paste",
] ]

View File

@@ -17,6 +17,7 @@ libm = "0.2.15"
heap = {path = "workspace/heap"} heap = {path = "workspace/heap"}
nova_error = {path = "workspace/nova_error"} nova_error = {path = "workspace/nova_error"}
paste = "1.0.15" paste = "1.0.15"
log = "0.4.29"
[workspace] [workspace]

View File

@@ -106,6 +106,18 @@ pub enum PhysSource {
#[repr(align(4096))] #[repr(align(4096))]
pub struct PageTable([TableEntry; TABLE_ENTRY_COUNT]); pub struct PageTable([TableEntry; TABLE_ENTRY_COUNT]);
impl Iterator for PageTable {
type Item = VirtAddr;
fn next(&mut self) -> Option<Self::Item> {
for (offset, entity) in self.0.iter().enumerate() {
if entity.is_invalid() {
return Some(offset);
}
}
None
}
}
#[no_mangle] #[no_mangle]
pub static mut TRANSLATIONTABLE_TTBR0: PageTable = PageTable([TableEntry { value: 0 }; 512]); pub static mut TRANSLATIONTABLE_TTBR0: PageTable = PageTable([TableEntry { value: 0 }; 512]);
#[no_mangle] #[no_mangle]
@@ -197,7 +209,7 @@ fn map_range_dynamic(
/// Allocate a singe page. /// Allocate a singe page.
pub fn alloc_page( pub fn alloc_page(
virtual_address: usize, virtual_address: VirtAddr,
base_table: *mut PageTable, base_table: *mut PageTable,
additional_flags: u64, additional_flags: u64,
) -> Result<(), NovaError> { ) -> 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<VirtAddr, NovaError> {
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`. /// Allocate a single page at an explicit `physical_address`.
pub fn alloc_page_explicit( pub fn alloc_page_explicit(
virtual_address: usize, virtual_address: usize,

View File

@@ -77,7 +77,7 @@ configure_mmu_el1:
.align 4 .align 4
.global el1_to_el0 .global el1_to_el0
el1_to_el0: el1_to_el0:
mov x8, x0
// Set SPSR_EL1: return to EL0t // Set SPSR_EL1: return to EL0t
mov x0, #(0b0000) mov x0, #(0b0000)
msr SPSR_EL1, x0 msr SPSR_EL1, x0
@@ -93,5 +93,6 @@ el1_to_el0:
isb isb
mov x0, x8
// Return to EL0 // Return to EL0
eret eret

View File

@@ -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 const MAILBOX_VIRTUAL_ADDRESS: VirtAddr = 0xFFFF_FF81_FFFF_E000;
pub static mut MAILBOX_PHYSICAL_ADDRESS: Option<PhysAddr> = None; pub static mut MAILBOX_PHYSICAL_ADDRESS: Option<PhysAddr> = None;
pub const APPLICATION_TRANSLATION_TABLE_VA: VirtAddr = 0xFFFF_FF81_FE00_0000;
extern "C" { extern "C" {
static __text_end: u64; static __text_end: u64;
static __share_end: u64; static __share_end: u64;
@@ -99,6 +101,7 @@ pub fn initialize_mmu_translation_tables() {
) )
.unwrap(); .unwrap();
// Allocate Mailbox buffer
{ {
let addr = reserve_page(); let addr = reserve_page();
unsafe { MAILBOX_PHYSICAL_ADDRESS = Some(addr) }; unsafe { MAILBOX_PHYSICAL_ADDRESS = Some(addr) };

View File

@@ -4,10 +4,8 @@ mod bitmaps;
use bitmaps::BASIC_LEGACY; use bitmaps::BASIC_LEGACY;
use crate::{ use crate::pi3::mailbox::{read_mailbox, write_mailbox};
pi3::mailbox::{read_mailbox, write_mailbox}, use log::error;
println,
};
#[repr(align(16))] #[repr(align(16))]
struct Mailbox([u32; 36]); struct Mailbox([u32; 36]);
@@ -237,7 +235,7 @@ impl Default for FrameBuffer {
let _ = read_mailbox(8); let _ = read_mailbox(8);
if mailbox.0[1] == 0 { if mailbox.0[1] == 0 {
println!("Failed"); error!("Mailbox request was not processed!");
} }
mailbox.0[28] &= 0x3FFFFFFF; mailbox.0[28] &= 0x3FFFFFFF;

View File

@@ -2,8 +2,9 @@ use core::arch::asm;
use crate::{ use crate::{
aarch64::registers::{daif::mask_all, read_esr_el1, read_exception_source_el}, 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 INTERRUPT_BASE: u32 = 0x3F00_B000;
const IRQ_PENDING_BASE: u32 = INTERRUPT_BASE + 0x204; const IRQ_PENDING_BASE: u32 = INTERRUPT_BASE + 0x204;
@@ -66,17 +67,17 @@ unsafe extern "C" fn rust_synchronous_interrupt_no_el_change() {
mask_all(); mask_all();
let source_el = read_exception_source_el() >> 2; let source_el = read_exception_source_el() >> 2;
println!("--------Sync Exception in EL{}--------", source_el); debug!("--------Sync Exception in EL{}--------", source_el);
println!("No EL change"); debug!("No EL change");
println!("Current EL: {}", get_current_el()); debug!("Current EL: {}", get_current_el());
println!("{:?}", EsrElX::from(read_esr_el1())); debug!("{:?}", EsrElX::from(read_esr_el1()));
println!("Return register address: {:#x}", read_esr_el1()); debug!("Return register address: {:#x}", read_esr_el1());
println!("-------------------------------------"); debug!("-------------------------------------");
} }
fn set_return_to_kernel_main() { fn set_return_to_kernel_loop() {
unsafe { 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"); asm!("mov x0, #(0b0101)", "msr SPSR_EL1, x0");
} }
} }

View File

@@ -12,9 +12,11 @@ use crate::{
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,
}, },
println, read_address, write_address, read_address, write_address,
}; };
use alloc::vec::Vec; use alloc::vec::Vec;
use log::{debug, info};
struct InterruptHandlers { struct InterruptHandlers {
source: IRQSource, source: IRQSource,
function: fn(), function: fn(),
@@ -60,9 +62,9 @@ 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 = read_exception_source_el() >> 2; let source_el = read_exception_source_el() >> 2;
println!("Source EL: {}", source_el); debug!("Source EL: {}", source_el);
println!("Current EL: {}", get_current_el()); debug!("Current EL: {}", get_current_el());
println!("Return register address: {:#x}", read_esr_el1()); debug!("Return register address: {:#x}", read_esr_el1());
} }
if let Some(handler_vec) = unsafe { &*core::ptr::addr_of_mut!(INTERRUPT_HANDLERS) } { 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() { fn handle_gpio_interrupt() {
println!("Interrupt"); debug!("GPIO interrupt triggered");
for i in 0..=53u32 { for i in 0..=53u32 {
let val = read_gpio_event_detect_status(i); let val = read_gpio_event_detect_status(i);
@@ -84,7 +86,7 @@ fn handle_gpio_interrupt() {
#[allow(clippy::single_match)] #[allow(clippy::single_match)]
match i { match i {
26 => { 26 => {
println!("Button Pressed"); info!("Button Pressed");
} }
_ => {} _ => {}
} }

View File

@@ -1,11 +1,12 @@
use crate::{ use crate::{
aarch64::registers::{daif::mask_all, read_elr_el1, read_esr_el1, read_exception_source_el}, aarch64::registers::{daif::mask_all, read_elr_el1, read_esr_el1, read_exception_source_el},
get_current_el, get_current_el,
interrupt_handlers::{set_return_to_kernel_main, EsrElX, TrapFrame}, interrupt_handlers::{set_return_to_kernel_loop, EsrElX, TrapFrame},
pi3::mailbox, pi3::mailbox,
println,
}; };
use log::{debug, error, warn};
/// Synchronous Exception Handler /// Synchronous Exception Handler
/// ///
/// Source is a lower Exception level, where the implemented level /// 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 { unsafe extern "C" fn rust_synchronous_interrupt_imm_lower_aarch64(frame: &mut TrapFrame) -> usize {
mask_all(); mask_all();
let esr: EsrElX = EsrElX::from(read_esr_el1()); let esr: EsrElX = EsrElX::from(read_esr_el1());
debug!("Synchronous interrupt from lower EL triggered");
log_sync_exception();
match esr.ec { match esr.ec {
0b100100 => { 0b100100 => {
log_sync_exception(); warn!("Cause: Data Abort from a lower Exception level");
println!("Cause: Data Abort from a lower Exception level");
} }
0b010101 => { 0b010101 => {
println!("Cause: SVC instruction execution in AArch64"); debug!("Cause: SVC instruction execution in AArch64");
return handle_svc(frame); 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 0
} }
@@ -46,11 +48,11 @@ fn handle_svc(frame: &mut TrapFrame) -> usize {
fn log_sync_exception() { fn log_sync_exception() {
let source_el = read_exception_source_el() >> 2; let source_el = read_exception_source_el() >> 2;
println!("--------Sync Exception in EL{}--------", source_el); debug!("--------Sync Exception in EL{}--------", source_el);
println!("Exception escalated to EL {}", get_current_el()); debug!("Exception escalated to EL {}", get_current_el());
println!("Current EL: {}", get_current_el()); debug!("Current EL: {}", get_current_el());
let esr: EsrElX = EsrElX::from(read_esr_el1()); let esr: EsrElX = EsrElX::from(read_esr_el1());
println!("{:?}", esr); debug!("{:?}", esr);
println!("Return address: {:#x}", read_elr_el1()); debug!("Return address: {:#x}", read_elr_el1());
println!("-------------------------------------"); debug!("-------------------------------------");
} }

View File

@@ -3,12 +3,13 @@
extern crate alloc; extern crate alloc;
use alloc::boxed::Box;
use core::{ use core::{
arch::asm, arch::asm,
panic::PanicInfo, panic::PanicInfo,
ptr::{read_volatile, write_volatile}, ptr::{read_volatile, write_volatile},
}; };
use log::LevelFilter;
use log::{Level, Metadata, Record};
use heap::Heap; use heap::Heap;
@@ -18,10 +19,11 @@ use crate::{
WRITABLE, WRITABLE,
}, },
interrupt_handlers::irq::initialize_interrupt_handler, interrupt_handlers::irq::initialize_interrupt_handler,
logger::DefaultLogger,
pi3::timer::sleep_s, pi3::timer::sleep_s,
terminal::{flush_terminal, init_terminal},
}; };
static LOGGER: UartLogger = UartLogger;
static PERIPHERAL_BASE: usize = 0x3F00_0000; static PERIPHERAL_BASE: usize = 0x3F00_0000;
unsafe extern "C" { unsafe extern "C" {
@@ -31,7 +33,7 @@ unsafe extern "C" {
#[global_allocator] #[global_allocator]
pub static mut GLOBAL_ALLOCATOR: Heap = Heap::empty(); 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 start = core::ptr::addr_of_mut!(__kernel_end) as usize | KERNEL_VIRTUAL_MEM_SPACE;
let size = LEVEL2_BLOCK_SIZE * 2; let size = LEVEL2_BLOCK_SIZE * 2;
@@ -54,9 +56,9 @@ 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 pi3; pub mod pi3;
pub mod terminal;
#[inline(always)] #[inline(always)]
pub unsafe fn read_address(address: u32) -> u32 { pub unsafe fn read_address(address: u32) -> u32 {
@@ -80,14 +82,33 @@ pub fn get_current_el() -> u64 {
el >> 2 el >> 2
} }
static mut KERNEL_INITIALIZED: bool = false;
pub fn initialize_kernel() { pub fn initialize_kernel() {
if unsafe { KERNEL_INITIALIZED } { unsafe { initialize_kernel_heap() };
return;
}
unsafe { init_kernel_heap() };
logger::set_logger(Box::new(DefaultLogger));
initialize_interrupt_handler(); 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();
} }

View File

@@ -1,45 +0,0 @@
use core::fmt::Write;
use alloc::{boxed::Box, fmt};
use crate::peripherals::uart;
static mut LOGGER: Option<Box<dyn Logger>> = 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<dyn Logger>) {
unsafe {
LOGGER = Some(logger);
}
}

View File

@@ -6,6 +6,7 @@ use core::{
arch::{asm, global_asm}, arch::{asm, global_asm},
ptr::write_volatile, ptr::write_volatile,
}; };
use log::{debug, info};
extern crate alloc; extern crate alloc;
@@ -14,7 +15,7 @@ use nova::{
aarch64::registers::{daif, read_id_aa64mmfr0_el1}, aarch64::registers::{daif, read_id_aa64mmfr0_el1},
configuration::memory_mapping::initialize_mmu_translation_tables, configuration::memory_mapping::initialize_mmu_translation_tables,
framebuffer::{FrameBuffer, BLUE, GREEN, RED}, framebuffer::{FrameBuffer, BLUE, GREEN, RED},
get_current_el, get_current_el, init_logger,
interrupt_handlers::irq::{enable_irq_source, IRQSource}, interrupt_handlers::irq::{enable_irq_source, IRQSource},
peripherals::{ peripherals::{
gpio::{ gpio::{
@@ -23,7 +24,7 @@ use nova::{
}, },
uart::uart_init, uart::uart_init,
}, },
println, print, println,
}; };
global_asm!(include_str!("vector.S")); global_asm!(include_str!("vector.S"));
@@ -33,7 +34,6 @@ static mut FRAMEBUFFER: Option<FrameBuffer> = None;
extern "C" { extern "C" {
fn el2_to_el1(); fn el2_to_el1();
fn el1_to_el0();
fn configure_mmu_el1(); fn configure_mmu_el1();
static mut __bss_start: u32; static mut __bss_start: u32;
static mut __bss_end: u32; static mut __bss_end: u32;
@@ -60,16 +60,18 @@ pub extern "C" fn main() -> ! {
// Set ACT Led to Outout // Set ACT Led to Outout
let _ = set_gpio_function(21, GPIOFunction::Output); let _ = set_gpio_function(21, GPIOFunction::Output);
init_logger();
println!("Hello World!"); info!("Hello World!");
println!("Exception level: {}", get_current_el()); info!("Current exception level: {}", get_current_el());
info!("initializing MMU...");
initialize_mmu_translation_tables(); initialize_mmu_translation_tables();
unsafe { configure_mmu_el1() }; unsafe { configure_mmu_el1() };
println!("MMU initialized..."); info!("MMU configured!");
println!("Register: AA64MMFR0_EL1: {:064b}", read_id_aa64mmfr0_el1()); debug!("Register: AA64MMFR0_EL1: {:064b}", read_id_aa64mmfr0_el1());
println!("Moving El2->EL1"); info!("Moving El2->EL1");
unsafe { FRAMEBUFFER = Some(FrameBuffer::default()) }; unsafe { FRAMEBUFFER = Some(FrameBuffer::default()) };
unsafe { unsafe {
@@ -89,28 +91,32 @@ unsafe fn zero_bss() {
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn kernel_main() -> ! { pub extern "C" fn kernel_main() {
println!("Kernel Start...");
nova::initialize_kernel(); nova::initialize_kernel();
info!("Kernel Initialized...");
info!("Current exception Level: {}", get_current_el());
let mut test_vector = Vec::new(); let mut test_vector = Vec::new();
for i in 0..20 { for i in 0..20 {
test_vector.push(i); 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(); daif::unmask_all();
unsafe {
el1_to_el0();
};
#[allow(clippy::empty_loop)] #[allow(clippy::empty_loop)]
loop {} loop {}
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn el0() -> ! { pub extern "C" fn el0(input: usize) {
println!("Jumped into EL0"); println!("Jumped into EL0");
// Set GPIO 26 to Input // Set GPIO 26 to Input
@@ -119,8 +125,6 @@ pub extern "C" fn el0() -> ! {
gpio_pull_up(26); gpio_pull_up(26);
set_falling_edge_detect(26, true); set_falling_edge_detect(26, true);
enable_irq_source(IRQSource::UartInt);
if let Some(fb) = unsafe { FRAMEBUFFER.as_mut() } { if let Some(fb) = unsafe { FRAMEBUFFER.as_mut() } {
for i in 0..1080 { for i in 0..1080 {
fb.draw_pixel(50, i, BLUE); fb.draw_pixel(50, i, BLUE);
@@ -134,12 +138,27 @@ pub extern "C" fn el0() -> ! {
fb.draw_function(cos, 0, 101, RED); fb.draw_function(cos, 0, 101, RED);
} }
loop { let _temp = syscall(67);
let temp = syscall(67);
println!("{} °C", temp / 1000);
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 { fn cos(x: u32) -> f64 {

View File

@@ -1,53 +1,92 @@
use core::fmt::Write; use core::arch::asm;
use alloc::string::String; use alloc::string::String;
use nova::{
interrupt_handlers::register_interrupt_handler, logger::Logger, use crate::{
peripherals::uart::read_uart_data, print, println, interrupt_handlers::irq::{register_interrupt_handler, IRQSource},
peripherals::uart::read_uart_data,
pi3::mailbox::read_soc_temp,
print, println,
}; };
pub static mut TERMINAL: Option<Terminal> = None;
pub struct Terminal { pub struct Terminal {
buffer: String,
input: String, input: String,
} }
extern "C" {
fn el1_to_el0();
}
impl Default for Terminal {
fn default() -> Self {
Self::new()
}
}
impl Terminal { impl Terminal {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
buffer: String::new(),
input: String::new(), input: String::new(),
} }
} }
fn flush(&mut self) { fn flush(&mut self) {
println!("{}", self.buffer); print!("\n> {}", self.input);
print!("> {}", self.input); }
self.buffer.clear();
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 { pub fn init_terminal() {
fn write_str(&mut self, s: &str) -> core::fmt::Result { unsafe { TERMINAL = Some(Terminal::new()) };
self.buffer.push_str(s); register_terminal_interrupt_handler();
Ok(())
}
}
impl Logger for Terminal {
fn flush(&mut self) {
println!("{}", self.buffer);
print!("> {}", self.input);
self.buffer.clear();
}
} }
fn terminal_uart_rx_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() { pub fn flush_terminal() {
register_interrupt_handler( #[allow(static_mut_refs)]
nova::interrupt_handlers::IRQSource::UartInt, if let Some(term) = unsafe { TERMINAL.as_mut() } {
terminal_uart_rx_interrupt_handler, term.flush();
); }
}
fn register_terminal_interrupt_handler() {
register_interrupt_handler(IRQSource::UartInt, terminal_uart_rx_interrupt_handler);
} }

View File

@@ -11,4 +11,5 @@ pub enum NovaError {
Misalignment, Misalignment,
InvalidGranularity, InvalidGranularity,
Paging, Paging,
OutOfMeomory,
} }