diff --git a/api/arceos_api/src/imp/mod.rs b/api/arceos_api/src/imp/mod.rs index 84ec8840d1..21a2b520f3 100644 --- a/api/arceos_api/src/imp/mod.rs +++ b/api/arceos_api/src/imp/mod.rs @@ -19,8 +19,14 @@ cfg_display! { mod stdio { use core::fmt; - pub fn ax_console_read_byte() -> Option { - axhal::console::getchar().map(|c| if c == b'\r' { b'\n' } else { c }) + pub fn ax_console_read_bytes(buf: &mut [u8]) -> crate::AxResult { + let len = axhal::console::read_bytes(buf); + for c in &mut buf[..len] { + if *c == b'\r' { + *c = b'\n'; + } + } + Ok(len) } pub fn ax_console_write_bytes(buf: &[u8]) -> crate::AxResult { diff --git a/api/arceos_api/src/lib.rs b/api/arceos_api/src/lib.rs index bf770028da..8bba9224de 100644 --- a/api/arceos_api/src/lib.rs +++ b/api/arceos_api/src/lib.rs @@ -106,8 +106,8 @@ pub mod mem { pub mod stdio { use core::fmt; define_api! { - /// Reads a byte from the console, or returns [`None`] if no input is available. - pub fn ax_console_read_byte() -> Option; + /// Reads a slice of bytes from the console, returns the number of bytes written. + pub fn ax_console_read_bytes(buf: &mut [u8]) -> crate::AxResult; /// Writes a slice of bytes to the console, returns the number of bytes written. pub fn ax_console_write_bytes(buf: &[u8]) -> crate::AxResult; /// Writes a formatted string to the console. diff --git a/api/arceos_posix_api/src/imp/stdio.rs b/api/arceos_posix_api/src/imp/stdio.rs index ded9c3333a..82a6f5eca7 100644 --- a/api/arceos_posix_api/src/imp/stdio.rs +++ b/api/arceos_posix_api/src/imp/stdio.rs @@ -5,8 +5,14 @@ use axsync::Mutex; #[cfg(feature = "fd")] use {alloc::sync::Arc, axerrno::LinuxError, axerrno::LinuxResult, axio::PollState}; -fn console_read_bytes() -> Option { - axhal::console::getchar().map(|c| if c == b'\r' { b'\n' } else { c }) +fn console_read_bytes(buf: &mut [u8]) -> AxResult { + let len = axhal::console::read_bytes(buf); + for c in &mut buf[..len] { + if *c == b'\r' { + *c = b'\n'; + } + } + Ok(len) } fn console_write_bytes(buf: &[u8]) -> AxResult { @@ -22,12 +28,11 @@ impl Read for StdinRaw { fn read(&mut self, buf: &mut [u8]) -> AxResult { let mut read_len = 0; while read_len < buf.len() { - if let Some(c) = console_read_bytes() { - buf[read_len] = c; - read_len += 1; - } else { + let len = console_read_bytes(buf[read_len..].as_mut())?; + if len == 0 { break; } + read_len += len; } Ok(read_len) } diff --git a/modules/axhal/src/lib.rs b/modules/axhal/src/lib.rs index 0601b93b3d..7e2116e640 100644 --- a/modules/axhal/src/lib.rs +++ b/modules/axhal/src/lib.rs @@ -60,13 +60,6 @@ pub mod paging; /// Console input and output. pub mod console { pub use super::platform::console::*; - - /// Write a slice of bytes to the console. - pub fn write_bytes(bytes: &[u8]) { - for c in bytes { - putchar(*c); - } - } } /// Miscellaneous operation, e.g. terminate the system. diff --git a/modules/axhal/src/platform/aarch64_bsta1000b/dw_apb_uart.rs b/modules/axhal/src/platform/aarch64_bsta1000b/dw_apb_uart.rs index ef6b3276e9..c6edb10f68 100644 --- a/modules/axhal/src/platform/aarch64_bsta1000b/dw_apb_uart.rs +++ b/modules/axhal/src/platform/aarch64_bsta1000b/dw_apb_uart.rs @@ -22,10 +22,32 @@ pub fn putchar(c: u8) { } /// Reads a byte from the console, or returns [`None`] if no input is available. -pub fn getchar() -> Option { +fn getchar() -> Option { UART.lock().getchar() } +/// Write a slice of bytes to the console. +pub fn write_bytes(bytes: &[u8]) { + for c in bytes { + putchar(*c); + } +} + +/// Reads bytes from the console into the given mutable slice. +/// Returns the number of bytes read. +pub fn read_bytes(bytes: &mut [u8]) -> usize { + let mut read_len = 0; + while read_len < bytes.len() { + if let Some(c) = getchar() { + bytes[read_len] = c; + } else { + break; + } + read_len += 1; + } + read_len +} + /// UART simply initialize pub fn init_early() { UART.lock().init(); diff --git a/modules/axhal/src/platform/aarch64_common/pl011.rs b/modules/axhal/src/platform/aarch64_common/pl011.rs index c0afd5bbfe..8b4325c04e 100644 --- a/modules/axhal/src/platform/aarch64_common/pl011.rs +++ b/modules/axhal/src/platform/aarch64_common/pl011.rs @@ -24,10 +24,32 @@ pub fn putchar(c: u8) { } /// Reads a byte from the console, or returns [`None`] if no input is available. -pub fn getchar() -> Option { +fn getchar() -> Option { UART.lock().getchar() } +/// Write a slice of bytes to the console. +pub fn write_bytes(bytes: &[u8]) { + for c in bytes { + putchar(*c); + } +} + +/// Reads bytes from the console into the given mutable slice. +/// Returns the number of bytes read. +pub fn read_bytes(bytes: &mut [u8]) -> usize { + let mut read_len = 0; + while read_len < bytes.len() { + if let Some(c) = getchar() { + bytes[read_len] = c; + } else { + break; + } + read_len += 1; + } + read_len +} + /// Initialize the UART pub fn init_early() { UART.lock().init(); diff --git a/modules/axhal/src/platform/dummy/mod.rs b/modules/axhal/src/platform/dummy/mod.rs index 389f14c778..e0d229ff3a 100644 --- a/modules/axhal/src/platform/dummy/mod.rs +++ b/modules/axhal/src/platform/dummy/mod.rs @@ -2,13 +2,14 @@ #![allow(dead_code)] pub mod console { - /// Writes a byte to the console. - pub fn putchar(c: u8) { + /// Writes bytes to the console from input u8 slice. + pub fn write_bytes(_bytes: &[u8]) { unimplemented!() } - /// Reads a byte from the console, or returns [`None`] if no input is available. - pub fn getchar() -> Option { + /// Reads bytes from the console into the given mutable slice. + /// Returns the number of bytes read. + pub fn read_bytes(_bytes: &mut [u8]) -> usize { unimplemented!() } } diff --git a/modules/axhal/src/platform/riscv64_qemu_virt/console.rs b/modules/axhal/src/platform/riscv64_qemu_virt/console.rs index a7ec3e6465..e89c15442c 100644 --- a/modules/axhal/src/platform/riscv64_qemu_virt/console.rs +++ b/modules/axhal/src/platform/riscv64_qemu_virt/console.rs @@ -1,14 +1,47 @@ +use memory_addr::VirtAddr; + +use crate::mem::virt_to_phys; + +/// The maximum number of bytes that can be read at once. +const MAX_RW_SIZE: usize = 256; + /// Writes a byte to the console. pub fn putchar(c: u8) { - #[allow(deprecated)] - sbi_rt::legacy::console_putchar(c as usize); + sbi_rt::console_write_byte(c); } -/// Reads a byte from the console, or returns [`None`] if no input is available. -pub fn getchar() -> Option { - #[allow(deprecated)] - match sbi_rt::legacy::console_getchar() as isize { - -1 => None, - c => Some(c as u8), +/// Tries to write bytes to the console from input u8 slice. +/// Returns the number of bytes written. +fn try_write_bytes(bytes: &[u8]) -> usize { + sbi_rt::console_write(sbi_rt::Physical::new( + // A maximum of 256 bytes can be written at a time + // to prevent SBI from disabling IRQs for too long. + bytes.len().min(MAX_RW_SIZE), + virt_to_phys(VirtAddr::from_ptr_of(bytes.as_ptr())).as_usize(), + 0, + )) + .value +} + +/// Writes bytes to the console from input u8 slice. +pub fn write_bytes(bytes: &[u8]) { + let mut write_len = 0; + while write_len < bytes.len() { + let len = try_write_bytes(&bytes[write_len..]); + if len == 0 { + break; + } + write_len += len; } } + +/// Reads bytes from the console into the given mutable slice. +/// Returns the number of bytes read. +pub fn read_bytes(bytes: &mut [u8]) -> usize { + sbi_rt::console_read(sbi_rt::Physical::new( + bytes.len().min(MAX_RW_SIZE), + virt_to_phys(VirtAddr::from_mut_ptr_of(bytes.as_mut_ptr())).as_usize(), + 0, + )) + .value +} diff --git a/modules/axhal/src/platform/x86_pc/uart16550.rs b/modules/axhal/src/platform/x86_pc/uart16550.rs index 3c773d3074..66ee56f01c 100644 --- a/modules/axhal/src/platform/x86_pc/uart16550.rs +++ b/modules/axhal/src/platform/x86_pc/uart16550.rs @@ -84,7 +84,7 @@ impl Uart16550 { } /// Writes a byte to the console. -pub fn putchar(c: u8) { +fn putchar(c: u8) { let mut uart = COM1.lock(); match c { b'\n' => { @@ -96,10 +96,32 @@ pub fn putchar(c: u8) { } /// Reads a byte from the console, or returns [`None`] if no input is available. -pub fn getchar() -> Option { +fn getchar() -> Option { COM1.lock().getchar() } +/// Write a slice of bytes to the console. +pub fn write_bytes(bytes: &[u8]) { + for c in bytes { + putchar(*c); + } +} + +/// Reads bytes from the console into the given mutable slice. +/// Returns the number of bytes read. +pub fn read_bytes(bytes: &mut [u8]) -> usize { + let mut read_len = 0; + while read_len < bytes.len() { + if let Some(c) = getchar() { + bytes[read_len] = c; + } else { + break; + } + read_len += 1; + } + read_len +} + pub(super) fn init() { COM1.lock().init(115200); } diff --git a/ulib/axstd/src/io/stdio.rs b/ulib/axstd/src/io/stdio.rs index 0b07f4bb6b..5bcdb238b9 100644 --- a/ulib/axstd/src/io/stdio.rs +++ b/ulib/axstd/src/io/stdio.rs @@ -12,12 +12,11 @@ impl Read for StdinRaw { fn read(&mut self, buf: &mut [u8]) -> io::Result { let mut read_len = 0; while read_len < buf.len() { - if let Some(c) = arceos_api::stdio::ax_console_read_byte() { - buf[read_len] = c; - read_len += 1; - } else { + let len = arceos_api::stdio::ax_console_read_bytes(buf[read_len..].as_mut())?; + if len == 0 { break; } + read_len += len; } Ok(read_len) }