      1
      2
      3
      4
      5
      6
      7
      8
      9
     10
     11
     12
     13
     14
     15
     16
     17
     18
     19
     20
     21
     22
     23
     24
     25
     26
     27
     28
     29
     30
     31
     32
     33
     34
     35
     36
     37
     38
     39
     40
     41
     42
     43
     44
     45
     46
     47
     48
     49
     50
     51
     52
     53
     54
     55
     56
     57
     58
     59
     60
     61
     62
     63
     64
     65
     66
     67
     68
     69
     70
     71
     72
     73
     74
     75
     76
     77
     78
     79
     80
     81
     82
     83
     84
     85
     86
     87
     88
     89
     90
     91
     92
     93
     94
     95
     96
     97
     98
     99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185

    //! Semihosting for ARM Cortex-M processors
    //!
    //! # What is semihosting?
    //!
    //! "Semihosting is a mechanism that enables code running on an ARM target to communicate and use
    //! the Input/Output facilities on a host computer that is running a debugger." - ARM
    //!
    //! # Interface
    //!
    //! This crate provides implementations of
    //! [`core::fmt::Write`](https://doc.rust-lang.org/core/fmt/trait.Write.html), so you can use it,
    //! in conjunction with
    //! [`core::format_args!`](https://doc.rust-lang.org/core/macro.format_args.html) or the [`write!` macro](https://doc.rust-lang.org/core/macro.write.html), for user-friendly construction and printing of formatted strings.
    //!
    //! Since semihosting operations are modeled as [system calls][sc], this crate exposes an untyped
    //! `syscall!` interface just like the [`sc`] crate does.
    //!
    //! [sc]: https://en.wikipedia.org/wiki/System_call
    //! [`sc`]: https://crates.io/crates/sc
    //!
    //! # Forewarning
    //!
    //! Semihosting operations are *very* slow. Like, each WRITE operation can take hundreds of
    //! milliseconds.
    //!
    //! # Example
    //!
    //! ## Using `hio::HStdout`
    //!
    //! This example will demonstrate how to print formatted strings.
    //!
    //! ```rust
    //! extern crate cortex_m_semihosting;
    //!
    //! use cortex_m_semihosting::hio;
    //! use core::fmt::Write;
    //!
    //! // This function will be called by the application
    //! fn print() -> Result<(), core::fmt::Error> {
    //!     let mut stdout = match hio::hstdout() {
    //!         Ok(fd) => fd,
    //!         Err(()) => return Err(core::fmt::Error),
    //!     };
    //!
    //!     let language = "Rust";
    //!     let ranking = 1;
    //!
    //!     write!(stdout, "{} on embedded is #{}!", language, ranking)?;
    //!
    //!     Ok(())
    //! }
    //! ```
    //!
    //! On the host side:
    //!
    //! ``` text
    //! $ openocd -f $INTERFACE -f $TARGET -l /tmp/openocd.log
    //! Open On-Chip Debugger 0.9.0 (2016-04-27-23:18)
    //! Licensed under GNU GPL v2
    //! For bug reports, read
    //!         http://openocd.org/doc/doxygen/bugs.html
    //! # the command will block at this point
    //! ```
    //!
    //! The OpenOCD logs will be redirected to `/tmp/openocd.log`. You can view those logs in "real
    //! time" using `tail`
    //!
    //! ``` text
    //! $ tail -f /tmp/openocd.log
    //! Info : Unable to match requested speed 1000 kHz, using 950 kHz
    //! Info : Unable to match requested speed 1000 kHz, using 950 kHz
    //! Info : clock speed 950 kHz
    //! Info : STLINK v1 JTAG v11 API v2 SWIM v0 VID 0x0483 PID 0x3744
    //! Info : using stlink api v2
    //! Info : nrf51.cpu: hardware has 4 breakpoints, 2 watchpoints
    //! ```
    //!
    //! Alternatively you could omit the `-l` flag from the `openocd` call, and the `tail -f` command
    //! but the OpenOCD output will have intermingled in it logs from its normal operation.
    //!
    //! Then, we run the program:
    //!
    //! ``` text
    //! $ arm-none-eabi-gdb hello-world
    //! (gdb) # Connect to OpenOCD
    //! (gdb) target remote :3333
    //!
    //! (gdb) # Enable OpenOCD's semihosting support
    //! (gdb) monitor arm semihosting enable
    //!
    //! (gdb) # Flash the program
    //! (gdb) load
    //!
    //! (gdb) # Run the program
    //! (gdb) continue
    //! ```
    //!
    //! And you'll see the output under OpenOCD's terminal
    //!
    //! ``` text
    //! # openocd -f $INTERFACE -f $TARGET -l /tmp/openocd.log
    //! (..)
    //! Rust on embedded is #1!
    //! ```
    //! ## Using the syscall interface
    //!
    //! This example will show how to print "Hello, world!" on the host.
    //!
    //! Target program:
    //!
    //! ```
    //! extern crate cortex_m_semihosting;
    //!
    //! // This function will be called by the application
    //! fn print() {
    //!     // File descriptor (on the host)
    //!     const STDOUT: usize = 1; // NOTE the host stdout may not always be fd 1
    //!     static MSG: &'static [u8] = b"Hello, world!\n";
    //!
    //!     // Signature: fn write(fd: usize, ptr: *const u8, len: usize) -> usize
    //!     let r = unsafe { syscall!(WRITE, STDOUT, MSG.as_ptr(), MSG.len()) };
    //! }
    //! ```
    //! Output and monitoring proceed as in the above example.
    //!
    //! # Optional features
    //!
    //! ## `inline-asm`
    //!
    //! When this feature is enabled semihosting is implemented using inline assembly (`asm!`) and
    //! compiling this crate requires nightly.
    //!
    //! When this feature is disabled semihosting is implemented using FFI calls into an external
    //! assembly file and compiling this crate works on stable and beta.
    //!
    //! # Reference
    //!
    //! For documentation about the semihosting operations, check:
    //!
    //! 'Chapter 8 - Semihosting' of the ['ARM Compiler toolchain Version 5.0'][pdf]
    //! manual.
    //!
    //! [pdf]: http://infocenter.arm.com/help/topic/com.arm.doc.dui0471e/DUI0471E_developing_for_arm_processors.pdf

    #![cfg_attr(feature = "inline-asm", feature(asm))]
    #![deny(missing_docs)]
    #![deny(warnings)]
    #![no_std]

    #[macro_use]
    mod macros;

    pub mod debug;
    pub mod hio;
    pub mod nr;

    #[cfg(all(thumb, not(feature = "inline-asm")))]
    extern "C" {
        fn __syscall(nr: usize, arg: usize) -> usize;
    }

    /// Performs a semihosting operation, takes a pointer to an argument block
    #[inline(always)]
    pub unsafe fn syscall<T>(nr: usize, arg: &T) -> usize {
        syscall1(nr, arg as *const T as usize)
    }

    /// Performs a semihosting operation, takes one integer as an argument
    #[inline(always)]
    pub unsafe fn syscall1(_nr: usize, _arg: usize) -> usize {
        match () {
            #[cfg(all(thumb, not(feature = "inline-asm")))]
            () => __syscall(_nr, _arg),

            #[cfg(all(thumb, feature = "inline-asm"))]
            () => {
                let mut nr = _nr;
                asm!("bkpt 0xAB" : "+{r0}"(nr) : "{r1}"(_arg) :: "volatile");
                nr
            }

            #[cfg(not(thumb))]
            () => unimplemented!(),
        }
    }

# Help

## Keyboard Shortcuts

`?`
  Show this help dialog
`S`
  Focus the search field
`↑`
  Move up in search results
`↓`
  Move down in search results
`↹`
  Switch tab
`⏎`
  Go to active search result
`+`
  Expand all sections
`-`
  Collapse all sections

## Search Tricks

Prefix searches with a type followed by a colon (e.g. `fn:`) to restrict the search to a given type.

Accepted types are: `fn`, `mod`, `struct`, `enum`, `trait`, `type`, `macro`, and `const`.

Search functions by type signature (e.g. `vec -> usize` or `* -> vec`)

Search multiple things at once by splitting your query with comma (e.g. `str,u8` or `String,struct:Vec,test`)