hio.rs 2.1 KB

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