|
| 1 | +use crate::cell::RefCell; |
1 | 2 | use crate::io;
|
| 3 | +thread_local! { static PANIC_WRITER: RefCell<Option<PanicWriter>> = RefCell::new(None) } |
2 | 4 |
|
3 | 5 | pub struct Stdin;
|
4 | 6 | pub struct Stdout {}
|
@@ -32,14 +34,7 @@ impl io::Write for Stdout {
|
32 | 34 | for (dest, src) in lend_buffer.0.iter_mut().zip(chunk) {
|
33 | 35 | *dest = *src;
|
34 | 36 | }
|
35 |
| - crate::os::xous::ffi::lend( |
36 |
| - connection, |
37 |
| - 1, |
38 |
| - &lend_buffer.0, |
39 |
| - 0, |
40 |
| - chunk.len(), |
41 |
| - ) |
42 |
| - .unwrap(); |
| 37 | + crate::os::xous::ffi::lend(connection, 1, &lend_buffer.0, 0, chunk.len()).unwrap(); |
43 | 38 | }
|
44 | 39 | Ok(buf.len())
|
45 | 40 | }
|
@@ -71,6 +66,95 @@ pub fn is_ebadf(_err: &io::Error) -> bool {
|
71 | 66 | true
|
72 | 67 | }
|
73 | 68 |
|
74 |
| -pub fn panic_output() -> Option<Vec<u8>> { |
75 |
| - None |
| 69 | +#[derive(Copy, Clone)] |
| 70 | +pub struct PanicWriter { |
| 71 | + conn: crate::os::xous::ffi::Connection, |
| 72 | + gfx_conn: Option<crate::os::xous::ffi::Connection>, |
| 73 | +} |
| 74 | + |
| 75 | +impl PanicWriter { |
| 76 | + // Group `usize` bytes into a `usize` and return it, beginning |
| 77 | + // from `offset` * sizeof(usize) bytes from the start. For example, |
| 78 | + // `group_or_null([1,2,3,4,5,6,7,8], 1)` on a 32-bit system will |
| 79 | + // return a usize with 5678 packed into it. |
| 80 | + fn group_or_null(data: &[u8], offset: usize) -> usize { |
| 81 | + let start = offset * core::mem::size_of::<usize>(); |
| 82 | + let mut out_array = [0u8; core::mem::size_of::<usize>()]; |
| 83 | + if start < data.len() { |
| 84 | + for (dest, src) in out_array.iter_mut().zip(&data[start..]) { |
| 85 | + *dest = *src; |
| 86 | + } |
| 87 | + } |
| 88 | + usize::from_le_bytes(out_array) |
| 89 | + } |
| 90 | +} |
| 91 | + |
| 92 | +impl io::Write for PanicWriter { |
| 93 | + fn write(&mut self, s: &[u8]) -> core::result::Result<usize, io::Error> { |
| 94 | + for c in s.chunks(core::mem::size_of::<usize>() * 4) { |
| 95 | + // Text is grouped into 4x `usize` words. The id is 1100 plus |
| 96 | + // the number of characters in this message. |
| 97 | + // Ignore errors since we're already panicking. |
| 98 | + crate::os::xous::ffi::try_scalar( |
| 99 | + self.conn, |
| 100 | + [ |
| 101 | + 1100 + c.len(), |
| 102 | + Self::group_or_null(&c, 0), |
| 103 | + Self::group_or_null(&c, 1), |
| 104 | + Self::group_or_null(&c, 2), |
| 105 | + Self::group_or_null(&c, 3), |
| 106 | + ], |
| 107 | + ) |
| 108 | + .ok(); |
| 109 | + } |
| 110 | + |
| 111 | + // Serialze the text to the graphics panic handler, only if we were able |
| 112 | + // to acquire a connection to it. Text length is encoded in the `valid` field, |
| 113 | + // the data itself in the buffer. Typically several messages are require to |
| 114 | + // fully transmit the entire panic message. |
| 115 | + if let Some(connection) = self.gfx_conn { |
| 116 | + #[repr(align(4096))] |
| 117 | + struct Request([u8; 4096]); |
| 118 | + let mut request = Request([0u8; 4096]); |
| 119 | + for (&s, d) in s.iter().zip(request.0.iter_mut()) { |
| 120 | + *d = s; |
| 121 | + } |
| 122 | + crate::os::xous::ffi::try_lend( |
| 123 | + connection, |
| 124 | + 0, /* AppendPanicText */ |
| 125 | + &request.0, |
| 126 | + 0, |
| 127 | + s.len(), |
| 128 | + ) |
| 129 | + .ok(); |
| 130 | + } |
| 131 | + Ok(s.len()) |
| 132 | + } |
| 133 | + |
| 134 | + // Tests show that this does not seem to be reliably called at the end of a panic |
| 135 | + // print, so, we can't rely on this to e.g. trigger a graphics update. |
| 136 | + fn flush(&mut self) -> io::Result<()> { |
| 137 | + Ok(()) |
| 138 | + } |
| 139 | +} |
| 140 | + |
| 141 | +pub fn panic_output() -> Option<impl io::Write> { |
| 142 | + PANIC_WRITER.with(|pwr| { |
| 143 | + if pwr.borrow().is_none() { |
| 144 | + // Generally this won't fail because every server has already allocated this connection. |
| 145 | + let conn = crate::os::xous::services::log_server(); |
| 146 | + |
| 147 | + // This is possibly fallible in the case that the connection table is full, |
| 148 | + // and we can't make the connection to the graphics server. Most servers do not already |
| 149 | + // have this connection. |
| 150 | + let gfx_conn = crate::os::xous::services::try_connect("panic-to-screen!"); |
| 151 | + |
| 152 | + let pw = PanicWriter { conn, gfx_conn }; |
| 153 | + |
| 154 | + // Send the "We're panicking" message (1000). |
| 155 | + crate::os::xous::ffi::scalar(conn, [1000 /* BeginPanic */, 0, 0, 0, 0]).ok(); |
| 156 | + *pwr.borrow_mut() = Some(pw); |
| 157 | + } |
| 158 | + *pwr.borrow() |
| 159 | + }) |
76 | 160 | }
|
0 commit comments