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
//! 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 //! //! 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 //! //! This example will show how to print "Hello, world!" on the host. //! //! Target program: //! //! ``` //! #[macro_use] //! extern crate cortex_m_semihosting; //! //! fn main() { //! // 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()) }; //! } //! ``` //! //! 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 //! # Connect to OpenOCD //! (gdb) target remote :3333 //! //! # Enable OpenOCD's semihosting support //! (gdb) monitor arm semihosting enable //! //! # Flash the program //! (gdb) load //! //! # 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 //! (..) //! Hello, world! //! ``` //! //! # 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 #![deny(missing_docs)] #![deny(warnings)] #![feature(asm)] #![no_std] #[macro_use] mod macros; pub mod debug; pub mod hio; pub mod nr; /// Performs a semihosting operation, takes a pointer to an argument block #[inline(always)] #[cfg(target_arch = "arm")] pub unsafe fn syscall<T>(mut nr: usize, arg: &T) -> usize { asm!("bkpt 0xAB" : "+{r0}"(nr) : "{r1}"(arg) : "memory" : "volatile"); nr } /// Performs a semihosting operation, takes a pointer to an argument block #[cfg(not(target_arch = "arm"))] pub unsafe fn syscall<T>(_nr: usize, _arg: &T) -> usize { 0 } /// Performs a semihosting operation, takes one integer as an argument #[inline(always)] #[cfg(target_arch = "arm")] pub unsafe fn syscall1(mut nr: usize, arg: usize) -> usize { asm!("bkpt 0xAB" : "+{r0}"(nr) : "{r1}"(arg) : "memory" : "volatile"); nr } /// Performs a semihosting operation, takes one integer as an argument #[cfg(not(target_arch = "arm"))] pub unsafe fn syscall1(_nr: usize, _arg: usize) -> usize { 0 }