4
0

lib.rs 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. //! Semihosting for ARM Cortex-M processors
  2. //!
  3. //! # What is semihosting?
  4. //!
  5. //! "Semihosting is a mechanism that enables code running on an ARM target to
  6. //! communicate and use the Input/Output facilities on a host computer that is
  7. //! running a debugger." - ARM
  8. //!
  9. //! # Interface
  10. //!
  11. //! Since semihosting operations are modeled as [system calls][sc], this crate
  12. //! exposes an untyped `syscall!` interface just like the [`sc`] crate does.
  13. //!
  14. //! [sc]: https://en.wikipedia.org/wiki/System_call
  15. //! [`sc`]: https://crates.io/crates/sc
  16. //!
  17. //! # Forewarning
  18. //!
  19. //! Semihosting operations are *very* slow. Like, each WRITE operation can take
  20. //! hundreds of milliseconds.
  21. //!
  22. //! # Example
  23. //!
  24. //! This example will show how to print "Hello, world!" on the host.
  25. //!
  26. //! Target program:
  27. //!
  28. //! ```
  29. //! #[macro_use]
  30. //! extern crate cortex_m_semihosting;
  31. //!
  32. //! fn main() {
  33. //! // File descriptor (on the host)
  34. //! const STDOUT: usize = 1; // NOTE the host stdout may not always be fd 1
  35. //! static MSG: &'static [u8] = b"Hello, world!\n";
  36. //!
  37. //! // Signature: fn write(fd: usize, ptr: *const u8, len: usize) -> usize
  38. //! let r = unsafe { syscall!(WRITE, STDOUT, MSG.as_ptr(), MSG.len()) };
  39. //! }
  40. //! ```
  41. //!
  42. //! On the host side:
  43. //!
  44. //! ``` text
  45. //! $ openocd -f $INTERFACE -f $TARGET -l /tmp/openocd.log
  46. //! Open On-Chip Debugger 0.9.0 (2016-04-27-23:18)
  47. //! Licensed under GNU GPL v2
  48. //! For bug reports, read
  49. //! http://openocd.org/doc/doxygen/bugs.html
  50. //! # the command will block at this point
  51. //! ```
  52. //!
  53. //! The OpenOCD logs will be redirected to `/tmp/openocd.log`. You can view
  54. //! those logs in "real time" using `tail`
  55. //!
  56. //! ``` text
  57. //! $ tail -f /tmp/openocd.log
  58. //! Info : Unable to match requested speed 1000 kHz, using 950 kHz
  59. //! Info : Unable to match requested speed 1000 kHz, using 950 kHz
  60. //! Info : clock speed 950 kHz
  61. //! Info : STLINK v1 JTAG v11 API v2 SWIM v0 VID 0x0483 PID 0x3744
  62. //! Info : using stlink api v2
  63. //! Info : nrf51.cpu: hardware has 4 breakpoints, 2 watchpoints
  64. //! ```
  65. //!
  66. //! Alternatively you could omit the `-l` flag from the `openocd` call, and the
  67. //! `tail -f` command but the OpenOCD output will have intermingled in it logs
  68. //! from its normal operation.
  69. //!
  70. //! Then, we run the program:
  71. //!
  72. //! ``` text
  73. //! $ arm-none-eabi-gdb hello-world
  74. //! # Connect to OpenOCD
  75. //! (gdb) target remote :3333
  76. //!
  77. //! # Enable OpenOCD's semihosting support
  78. //! (gdb) monitor arm semihosting enable
  79. //!
  80. //! # Flash the program
  81. //! (gdb) load
  82. //!
  83. //! # Run the program
  84. //! (gdb) continue
  85. //! ```
  86. //!
  87. //! And you'll see the output under OpenOCD's terminal
  88. //!
  89. //! ``` text
  90. //! # openocd -f $INTERFACE -f $TARGET -l /tmp/openocd.log
  91. //! (..)
  92. //! Hello, world!
  93. //! ```
  94. //!
  95. //! # Reference
  96. //!
  97. //! For documentation about the semihosting operations, check:
  98. //!
  99. //! 'Chapter 8 - Semihosting' of the ['ARM Compiler toolchain Version 5.0'][pdf]
  100. //! manual.
  101. //!
  102. //! [pdf]: http://infocenter.arm.com/help/topic/com.arm.doc.dui0471e/DUI0471E_developing_for_arm_processors.pdf
  103. #![deny(missing_docs)]
  104. #![deny(warnings)]
  105. #![feature(asm)]
  106. #![no_std]
  107. #[macro_use]
  108. mod macros;
  109. pub mod debug;
  110. pub mod hio;
  111. pub mod nr;
  112. /// Performs a semihosting operation, takes a pointer to an argument block
  113. #[inline(always)]
  114. #[cfg(target_arch = "arm")]
  115. pub unsafe fn syscall<T>(mut nr: usize, arg: &T) -> usize {
  116. asm!("bkpt 0xAB"
  117. : "+{r0}"(nr)
  118. : "{r1}"(arg)
  119. : "memory"
  120. : "volatile");
  121. nr
  122. }
  123. /// Performs a semihosting operation, takes a pointer to an argument block
  124. #[cfg(not(target_arch = "arm"))]
  125. pub unsafe fn syscall<T>(_nr: usize, _arg: &T) -> usize {
  126. 0
  127. }
  128. /// Performs a semihosting operation, takes one integer as an argument
  129. #[inline(always)]
  130. #[cfg(target_arch = "arm")]
  131. pub unsafe fn syscall1(mut nr: usize, arg: usize) -> usize {
  132. asm!("bkpt 0xAB"
  133. : "+{r0}"(nr)
  134. : "{r1}"(arg)
  135. : "memory"
  136. : "volatile");
  137. nr
  138. }
  139. /// Performs a semihosting operation, takes one integer as an argument
  140. #[cfg(not(target_arch = "arm"))]
  141. pub unsafe fn syscall1(_nr: usize, _arg: usize) -> usize {
  142. 0
  143. }