cortex_m_semihosting/
hio.rs

1//! Host I/O
2
3use crate::nr;
4use core::{fmt, slice};
5
6/// A byte stream to the host (e.g., host's stdout or stderr).
7#[derive(Clone, Copy)]
8pub struct HostStream {
9    fd: usize,
10}
11
12impl HostStream {
13    /// Attempts to write an entire `buffer` into this sink
14    pub fn write_all(&mut self, buffer: &[u8]) -> Result<(), ()> {
15        write_all(self.fd, buffer)
16    }
17}
18
19impl fmt::Write for HostStream {
20    fn write_str(&mut self, s: &str) -> fmt::Result {
21        self.write_all(s.as_bytes()).map_err(|_| fmt::Error)
22    }
23}
24
25/// Construct a new handle to the host's standard error.
26pub fn hstderr() -> Result<HostStream, ()> {
27    // There is actually no stderr access in ARM Semihosting documentation. Use
28    // convention used in libgloss.
29    // See: libgloss/arm/syscalls.c, line 139.
30    // https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;a=blob;f=libgloss/arm/syscalls.c#l139
31    open(":tt\0", nr::open::W_APPEND)
32}
33
34/// Construct a new handle to the host's standard output.
35pub fn hstdout() -> Result<HostStream, ()> {
36    open(":tt\0", nr::open::W_TRUNC)
37}
38
39fn open(name: &str, mode: usize) -> Result<HostStream, ()> {
40    let name = name.as_bytes();
41    match unsafe { syscall!(OPEN, name.as_ptr(), mode, name.len() - 1) } as isize {
42        -1 => Err(()),
43        fd => Ok(HostStream { fd: fd as usize }),
44    }
45}
46
47fn write_all(fd: usize, mut buffer: &[u8]) -> Result<(), ()> {
48    while !buffer.is_empty() {
49        match unsafe { syscall!(WRITE, fd, buffer.as_ptr(), buffer.len()) } {
50            // Done
51            0 => return Ok(()),
52            // `n` bytes were not written
53            n if n <= buffer.len() => {
54                let offset = (buffer.len() - n) as isize;
55                buffer = unsafe { slice::from_raw_parts(buffer.as_ptr().offset(offset), n) }
56            }
57            #[cfg(feature = "jlink-quirks")]
58            // Error (-1) - should be an error but JLink can return -1, -2, -3,...
59            // For good measure, we allow up to negative 15.
60            n if n > 0xfffffff0 => return Ok(()),
61            // Error
62            _ => return Err(()),
63        }
64    }
65    Ok(())
66}