Skip to content

Commit 4af7d2c

Browse files
committed
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>
1 parent 10dad67 commit 4af7d2c

File tree

2 files changed

+131
-1
lines changed

2 files changed

+131
-1
lines changed

library/std/src/sys/xous/mod.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ pub mod path;
2626
pub mod pipe;
2727
#[path = "../unsupported/process.rs"]
2828
pub mod process;
29-
#[path = "../unsupported/stdio.rs"]
3029
pub mod stdio;
3130
#[path = "../unsupported/thread.rs"]
3231
pub mod thread;

library/std/src/sys/xous/stdio.rs

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
use crate::io;
2+
3+
pub struct Stdin;
4+
pub struct Stdout {}
5+
pub struct Stderr;
6+
7+
use crate::os::xous::ffi::{lend, try_lend, try_scalar, Connection};
8+
use crate::os::xous::services::{log_server, try_connect, LogScalar};
9+
10+
impl Stdin {
11+
pub const fn new() -> Stdin {
12+
Stdin
13+
}
14+
}
15+
16+
impl io::Read for Stdin {
17+
fn read(&mut self, _buf: &mut [u8]) -> io::Result<usize> {
18+
Ok(0)
19+
}
20+
}
21+
22+
impl Stdout {
23+
pub const fn new() -> Stdout {
24+
Stdout {}
25+
}
26+
}
27+
28+
impl io::Write for Stdout {
29+
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
30+
#[repr(align(4096))]
31+
struct LendBuffer([u8; 4096]);
32+
let mut lend_buffer = LendBuffer([0u8; 4096]);
33+
let connection = log_server();
34+
for chunk in buf.chunks(lend_buffer.0.len()) {
35+
for (dest, src) in lend_buffer.0.iter_mut().zip(chunk) {
36+
*dest = *src;
37+
}
38+
lend(connection, 1, &lend_buffer.0, 0, chunk.len()).unwrap();
39+
}
40+
Ok(buf.len())
41+
}
42+
43+
fn flush(&mut self) -> io::Result<()> {
44+
Ok(())
45+
}
46+
}
47+
48+
impl Stderr {
49+
pub const fn new() -> Stderr {
50+
Stderr
51+
}
52+
}
53+
54+
impl io::Write for Stderr {
55+
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
56+
#[repr(align(4096))]
57+
struct LendBuffer([u8; 4096]);
58+
let mut lend_buffer = LendBuffer([0u8; 4096]);
59+
let connection = log_server();
60+
for chunk in buf.chunks(lend_buffer.0.len()) {
61+
for (dest, src) in lend_buffer.0.iter_mut().zip(chunk) {
62+
*dest = *src;
63+
}
64+
lend(connection, 1, &lend_buffer.0, 0, chunk.len()).unwrap();
65+
}
66+
Ok(buf.len())
67+
}
68+
69+
fn flush(&mut self) -> io::Result<()> {
70+
Ok(())
71+
}
72+
}
73+
74+
pub const STDIN_BUF_SIZE: usize = 0;
75+
76+
pub fn is_ebadf(_err: &io::Error) -> bool {
77+
true
78+
}
79+
80+
#[derive(Copy, Clone)]
81+
pub struct PanicWriter {
82+
log: Connection,
83+
gfx: Option<Connection>,
84+
}
85+
86+
impl io::Write for PanicWriter {
87+
fn write(&mut self, s: &[u8]) -> core::result::Result<usize, io::Error> {
88+
for c in s.chunks(core::mem::size_of::<usize>() * 4) {
89+
// Text is grouped into 4x `usize` words. The id is 1100 plus
90+
// the number of characters in this message.
91+
// Ignore errors since we're already panicking.
92+
try_scalar(self.log, LogScalar::AppendPanicMessage(&c).into()).ok();
93+
}
94+
95+
// Serialize the text to the graphics panic handler, only if we were able
96+
// to acquire a connection to it. Text length is encoded in the `valid` field,
97+
// the data itself in the buffer. Typically several messages are require to
98+
// fully transmit the entire panic message.
99+
if let Some(gfx) = self.gfx {
100+
#[repr(C, align(4096))]
101+
struct Request([u8; 4096]);
102+
let mut request = Request([0u8; 4096]);
103+
for (&s, d) in s.iter().zip(request.0.iter_mut()) {
104+
*d = s;
105+
}
106+
try_lend(gfx, 0 /* AppendPanicText */, &request.0, 0, s.len()).ok();
107+
}
108+
Ok(s.len())
109+
}
110+
111+
// Tests show that this does not seem to be reliably called at the end of a panic
112+
// print, so, we can't rely on this to e.g. trigger a graphics update.
113+
fn flush(&mut self) -> io::Result<()> {
114+
Ok(())
115+
}
116+
}
117+
118+
pub fn panic_output() -> Option<impl io::Write> {
119+
// Generally this won't fail because every server has already connected, so
120+
// this is likely to succeed.
121+
let log = log_server();
122+
123+
// Send the "We're panicking" message (1000).
124+
try_scalar(log, LogScalar::BeginPanic.into()).ok();
125+
126+
// This is will fail in the case that the connection table is full, or if the
127+
// graphics server is not running. Most servers do not already have this connection.
128+
let gfx = try_connect("panic-to-screen!");
129+
130+
Some(PanicWriter { log, gfx })
131+
}

0 commit comments

Comments
 (0)