diff options
author | 2020-10-13 23:32:15 +0000 | |
---|---|---|
committer | 2020-10-13 23:32:15 +0000 | |
commit | 432e5f527430394570d1d07454e26cc41d5b2936 (patch) | |
tree | d3cde25a18eabfc5f0342dbf2d31ab767f21bab9 /cortex-m-semihosting/src/hio.rs | |
parent | f77d64a2d1505335e4a170d03a40993bb066fd02 (diff) | |
parent | b51178fae6373d8dae95f2fb661e0635359e8bc0 (diff) | |
download | cortex-m-432e5f527430394570d1d07454e26cc41d5b2936.tar.gz cortex-m-432e5f527430394570d1d07454e26cc41d5b2936.tar.zst cortex-m-432e5f527430394570d1d07454e26cc41d5b2936.zip |
Merge #263p-sh-v0.5.3c-m-sh-v0.3.5
263: Import cortex-m-semihosting and panic-semihosting into this repo r=adamgreig a=jonas-schievink
Motivation:
* Allows writing QEMU tests for `cortex-m`'s functionality that use semihosting to control QEMU. Previously these crates would pull in another cortex-m version, which doesn't work. Now they have a `path` dependency on the root crate.
* Lets us share the outline-inline-assembly setup and `cargo-xtask` in general.
* Lets us share CI and bot setup between more crates.
* 2 fewer repos to triage and keep track of (I'll transfer their issues after this is merged).
I also want to import cortex-m-rt, but I'll do that in a later PR.
CI was updated to build-test all crates with all or most feature combinations, like it did before.
Co-authored-by: Jonas Schievink <jonasschievink@gmail.com>
Diffstat (limited to 'cortex-m-semihosting/src/hio.rs')
-rw-r--r-- | cortex-m-semihosting/src/hio.rs | 88 |
1 files changed, 88 insertions, 0 deletions
diff --git a/cortex-m-semihosting/src/hio.rs b/cortex-m-semihosting/src/hio.rs new file mode 100644 index 0000000..61ac749 --- /dev/null +++ b/cortex-m-semihosting/src/hio.rs @@ -0,0 +1,88 @@ +//! Host I/O + +use core::{fmt, slice}; +use crate::nr; + +/// Host's standard error +#[derive(Clone, Copy)] +pub struct HStderr { + fd: usize, +} + +impl HStderr { + /// Attempts to write an entire `buffer` into this sink + pub fn write_all(&mut self, buffer: &[u8]) -> Result<(), ()> { + write_all(self.fd, buffer) + } +} + +impl fmt::Write for HStderr { + fn write_str(&mut self, s: &str) -> fmt::Result { + self.write_all(s.as_bytes()).map_err(|_| fmt::Error) + } +} + +/// Host's standard output +#[derive(Clone, Copy)] +pub struct HStdout { + fd: usize, +} + +impl HStdout { + /// Attempts to write an entire `buffer` into this sink + pub fn write_all(&mut self, buffer: &[u8]) -> Result<(), ()> { + write_all(self.fd, buffer) + } +} + +impl fmt::Write for HStdout { + fn write_str(&mut self, s: &str) -> fmt::Result { + self.write_all(s.as_bytes()).map_err(|_| fmt::Error) + } +} + +/// Construct a new handle to the host's standard error. +pub fn hstderr() -> Result<HStderr, ()> { + // There is actually no stderr access in ARM Semihosting documentation. Use + // convention used in libgloss. + // See: libgloss/arm/syscalls.c, line 139. + // https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;a=blob;f=libgloss/arm/syscalls.c#l139 + open(":tt\0", nr::open::W_APPEND).map(|fd| HStderr { fd }) +} + +/// Construct a new handle to the host's standard output. +pub fn hstdout() -> Result<HStdout, ()> { + open(":tt\0", nr::open::W_TRUNC).map(|fd| HStdout { fd }) +} + +fn open(name: &str, mode: usize) -> Result<usize, ()> { + let name = name.as_bytes(); + match unsafe { syscall!(OPEN, name.as_ptr(), mode, name.len() - 1) } as + isize { + -1 => Err(()), + fd => Ok(fd as usize), + } +} + +fn write_all(fd: usize, mut buffer: &[u8]) -> Result<(), ()> { + while !buffer.is_empty() { + match unsafe { syscall!(WRITE, fd, buffer.as_ptr(), buffer.len()) } { + // Done + 0 => return Ok(()), + // `n` bytes were not written + n if n <= buffer.len() => { + let offset = (buffer.len() - n) as isize; + buffer = unsafe { + slice::from_raw_parts(buffer.as_ptr().offset(offset), n) + } + } + #[cfg(feature = "jlink-quirks")] + // Error (-1) - should be an error but JLink can return -1, -2, -3,... + // For good measure, we allow up to negative 15. + n if n > 0xfffffff0 => return Ok(()), + // Error + _ => return Err(()), + } + } + Ok(()) +} |