aboutsummaryrefslogtreecommitdiff
path: root/cortex-m-semihosting/src/hio.rs
diff options
context:
space:
mode:
authorGravatar bors[bot] <26634292+bors[bot]@users.noreply.github.com> 2020-10-13 23:32:15 +0000
committerGravatar GitHub <noreply@github.com> 2020-10-13 23:32:15 +0000
commit432e5f527430394570d1d07454e26cc41d5b2936 (patch)
treed3cde25a18eabfc5f0342dbf2d31ab767f21bab9 /cortex-m-semihosting/src/hio.rs
parentf77d64a2d1505335e4a170d03a40993bb066fd02 (diff)
parentb51178fae6373d8dae95f2fb661e0635359e8bc0 (diff)
downloadcortex-m-432e5f527430394570d1d07454e26cc41d5b2936.tar.gz
cortex-m-432e5f527430394570d1d07454e26cc41d5b2936.tar.zst
cortex-m-432e5f527430394570d1d07454e26cc41d5b2936.zip
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.rs88
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(())
+}