From ea7ebb942412c5452dbad060112b144aaf873062 Mon Sep 17 00:00:00 2001 From: Jonathan Klimt Date: Mon, 25 Nov 2024 22:19:33 +0100 Subject: [PATCH] Added uhyve buffered serial output for aarch64 --- src/arch/aarch64/kernel/mod.rs | 19 ++----- src/arch/aarch64/kernel/serial.rs | 94 +++++++++++++++++++++++-------- 2 files changed, 77 insertions(+), 36 deletions(-) diff --git a/src/arch/aarch64/kernel/mod.rs b/src/arch/aarch64/kernel/mod.rs index 723490ddb9..ae9313d675 100644 --- a/src/arch/aarch64/kernel/mod.rs +++ b/src/arch/aarch64/kernel/mod.rs @@ -25,7 +25,7 @@ use crate::env; const SERIAL_PORT_BAUDRATE: u32 = 115200; -static COM1: SpinMutex = SpinMutex::new(SerialPort::new(0x800)); +static COM1: SpinMutex> = SpinMutex::new(None); /// `CPU_ONLINE` is the count of CPUs that finished initialization. /// @@ -81,9 +81,7 @@ pub fn args() -> Option<&'static str> { pub fn message_output_init() { CoreLocal::install(); - let mut com1 = COM1.lock(); - - com1.port_address = env::boot_info() + let com_port_address = env::boot_info() .hardware_info .serial_port_base .map(|uartport| uartport.get()) @@ -93,18 +91,13 @@ pub fn message_output_init() { // We can only initialize the serial port here, because VGA requires processor // configuration first. - com1.init(SERIAL_PORT_BAUDRATE); -} - -pub fn output_message_byte(byte: u8) { - // Output messages to the serial port. - COM1.lock().write_byte(byte); + let com = SerialPort::new(com_port_address); + com.init(SERIAL_PORT_BAUDRATE); + *COM1.lock() = Some(com); } pub fn output_message_buf(buf: &[u8]) { - for byte in buf { - output_message_byte(*byte); - } + COM1.lock().as_mut().unwrap().write_buf(buf); } /// Real Boot Processor initialization as soon as we have put the first Welcome message on the screen. diff --git a/src/arch/aarch64/kernel/serial.rs b/src/arch/aarch64/kernel/serial.rs index b061573564..8b29d637f7 100644 --- a/src/arch/aarch64/kernel/serial.rs +++ b/src/arch/aarch64/kernel/serial.rs @@ -1,36 +1,84 @@ use core::arch::asm; +use heapless::Vec; + +use crate::syscalls::interfaces::serial_buf_hypercall; + +const SERIAL_BUFFER_SIZE: usize = 256; + +#[allow(clippy::large_enum_variant)] +enum SerialInner { + Uart(u32), + Uhyve(Vec), // heapless vec to have print before allocators are initialized +} + pub struct SerialPort { - pub port_address: u32, + inner: SerialInner, } impl SerialPort { - pub const fn new(port_address: u32) -> Self { - Self { port_address } + pub fn new(port_address: u32) -> Self { + if crate::env::is_uhyve() { + Self { + inner: SerialInner::Uhyve(Vec::new()), + } + } else { + Self { + inner: SerialInner::Uart(port_address), + } + } } - pub fn write_byte(&self, byte: u8) { - let port = core::ptr::with_exposed_provenance_mut::(self.port_address as usize); - - // LF newline characters need to be extended to CRLF over a real serial port. - if byte == b'\n' { - unsafe { - asm!( - "strb w8, [{port}]", - port = in(reg) port, - in("x8") b'\r', - options(nostack), - ); + pub fn write_buf(&mut self, buf: &[u8]) { + match &mut self.inner { + SerialInner::Uhyve(output_buf) => { + if SERIAL_BUFFER_SIZE - output_buf.len() >= buf.len() { + // unwrap: we checked that buf fits in output_buf + output_buf.extend_from_slice(buf).unwrap(); + if buf.contains(&b'\n') { + serial_buf_hypercall(output_buf); + output_buf.clear(); + } + } else { + serial_buf_hypercall(output_buf); + output_buf.clear(); + if buf.len() >= SERIAL_BUFFER_SIZE { + serial_buf_hypercall(buf); + } else { + // unwrap: we checked that buf fits in output_buf + output_buf.extend_from_slice(buf).unwrap(); + if buf.contains(&b'\n') { + serial_buf_hypercall(output_buf); + output_buf.clear(); + } + } + } } - } + SerialInner::Uart(port_address) => { + let port = core::ptr::with_exposed_provenance_mut::(*port_address as usize); + for &byte in buf { + // LF newline characters need to be extended to CRLF over a real serial port. + if byte == b'\n' { + unsafe { + asm!( + "strb w8, [{port}]", + port = in(reg) port, + in("x8") b'\r', + options(nostack), + ); + } + } - unsafe { - asm!( - "strb w8, [{port}]", - port = in(reg) port, - in("x8") byte, - options(nostack), - ); + unsafe { + asm!( + "strb w8, [{port}]", + port = in(reg) port, + in("x8") byte, + options(nostack), + ); + } + } + } } }