diff options
| author | Sean Cross <sean@xobs.io> | 2022-11-07 11:10:42 +0800 |
|---|---|---|
| committer | Sean Cross <sean@xobs.io> | 2023-08-22 20:25:38 +0800 |
| commit | 4af7d2cf8d452d72d836ef316c01ceaebd6387bf (patch) | |
| tree | 94e332b71a4f9508f141a811205346225f2088ae | |
| parent | 10dad67f89a320c315c6c758dffe0bee610cbbfa (diff) | |
| download | rust-4af7d2cf8d452d72d836ef316c01ceaebd6387bf.tar.gz rust-4af7d2cf8d452d72d836ef316c01ceaebd6387bf.zip | |
std: xous: add output support for stdio
Add support for stdout. This enables basic console printing via `println!()`. Output is written to the log server. Signed-off-by: Sean Cross <sean@xobs.io>
| -rw-r--r-- | library/std/src/sys/xous/mod.rs | 1 | ||||
| -rw-r--r-- | library/std/src/sys/xous/stdio.rs | 131 |
2 files changed, 131 insertions, 1 deletions
diff --git a/library/std/src/sys/xous/mod.rs b/library/std/src/sys/xous/mod.rs index 3c9eed10127..6a5b9fdd08d 100644 --- a/library/std/src/sys/xous/mod.rs +++ b/library/std/src/sys/xous/mod.rs @@ -26,7 +26,6 @@ pub mod path; pub mod pipe; #[path = "../unsupported/process.rs"] pub mod process; -#[path = "../unsupported/stdio.rs"] pub mod stdio; #[path = "../unsupported/thread.rs"] pub mod thread; diff --git a/library/std/src/sys/xous/stdio.rs b/library/std/src/sys/xous/stdio.rs new file mode 100644 index 00000000000..2ac694641ba --- /dev/null +++ b/library/std/src/sys/xous/stdio.rs @@ -0,0 +1,131 @@ +use crate::io; + +pub struct Stdin; +pub struct Stdout {} +pub struct Stderr; + +use crate::os::xous::ffi::{lend, try_lend, try_scalar, Connection}; +use crate::os::xous::services::{log_server, try_connect, LogScalar}; + +impl Stdin { + pub const fn new() -> Stdin { + Stdin + } +} + +impl io::Read for Stdin { + fn read(&mut self, _buf: &mut [u8]) -> io::Result<usize> { + Ok(0) + } +} + +impl Stdout { + pub const fn new() -> Stdout { + Stdout {} + } +} + +impl io::Write for Stdout { + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { + #[repr(align(4096))] + struct LendBuffer([u8; 4096]); + let mut lend_buffer = LendBuffer([0u8; 4096]); + let connection = log_server(); + for chunk in buf.chunks(lend_buffer.0.len()) { + for (dest, src) in lend_buffer.0.iter_mut().zip(chunk) { + *dest = *src; + } + lend(connection, 1, &lend_buffer.0, 0, chunk.len()).unwrap(); + } + Ok(buf.len()) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +impl Stderr { + pub const fn new() -> Stderr { + Stderr + } +} + +impl io::Write for Stderr { + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { + #[repr(align(4096))] + struct LendBuffer([u8; 4096]); + let mut lend_buffer = LendBuffer([0u8; 4096]); + let connection = log_server(); + for chunk in buf.chunks(lend_buffer.0.len()) { + for (dest, src) in lend_buffer.0.iter_mut().zip(chunk) { + *dest = *src; + } + lend(connection, 1, &lend_buffer.0, 0, chunk.len()).unwrap(); + } + Ok(buf.len()) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +pub const STDIN_BUF_SIZE: usize = 0; + +pub fn is_ebadf(_err: &io::Error) -> bool { + true +} + +#[derive(Copy, Clone)] +pub struct PanicWriter { + log: Connection, + gfx: Option<Connection>, +} + +impl io::Write for PanicWriter { + fn write(&mut self, s: &[u8]) -> core::result::Result<usize, io::Error> { + for c in s.chunks(core::mem::size_of::<usize>() * 4) { + // Text is grouped into 4x `usize` words. The id is 1100 plus + // the number of characters in this message. + // Ignore errors since we're already panicking. + try_scalar(self.log, LogScalar::AppendPanicMessage(&c).into()).ok(); + } + + // Serialize the text to the graphics panic handler, only if we were able + // to acquire a connection to it. Text length is encoded in the `valid` field, + // the data itself in the buffer. Typically several messages are require to + // fully transmit the entire panic message. + if let Some(gfx) = self.gfx { + #[repr(C, align(4096))] + struct Request([u8; 4096]); + let mut request = Request([0u8; 4096]); + for (&s, d) in s.iter().zip(request.0.iter_mut()) { + *d = s; + } + try_lend(gfx, 0 /* AppendPanicText */, &request.0, 0, s.len()).ok(); + } + Ok(s.len()) + } + + // Tests show that this does not seem to be reliably called at the end of a panic + // print, so, we can't rely on this to e.g. trigger a graphics update. + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +pub fn panic_output() -> Option<impl io::Write> { + // Generally this won't fail because every server has already connected, so + // this is likely to succeed. + let log = log_server(); + + // Send the "We're panicking" message (1000). + try_scalar(log, LogScalar::BeginPanic.into()).ok(); + + // This is will fail in the case that the connection table is full, or if the + // graphics server is not running. Most servers do not already have this connection. + let gfx = try_connect("panic-to-screen!"); + + Some(PanicWriter { log, gfx }) +} |
