lib.rs 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  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. //! And since the most used semihosting operation is writing to the host's
  18. //! stdout, convenience `hprint` and `hprintln` macros are provided.
  19. //!
  20. //! # Forewarning
  21. //!
  22. //! Semihosting operations are *very* slow. Like, each WRITE operation can take
  23. //! hundreds of milliseconds.
  24. //!
  25. //! # Example
  26. //!
  27. //! This example will show how to print "Hello, world!" on the host.
  28. //!
  29. //! Target program:
  30. //!
  31. //! ```
  32. //! fn main() {
  33. //! // File descriptor (on the host)
  34. //! const STDOUT: usize = 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. //! // (Or you could have just written `hprintln!("Hello, world!")`)
  41. //! // ..
  42. //! }
  43. //! ```
  44. //!
  45. //! On the host side:
  46. //!
  47. //! ``` text
  48. //! $ openocd -f $INTERFACE -f $TARGET -l /tmp/openocd.log
  49. //! Open On-Chip Debugger 0.9.0 (2016-04-27-23:18)
  50. //! Licensed under GNU GPL v2
  51. //! For bug reports, read
  52. //! http://openocd.org/doc/doxygen/bugs.html
  53. //! # the command will block at this point
  54. //! ```
  55. //!
  56. //! The OpenOCD logs will be redirected to `/tmp/openocd.log`. You can view
  57. //! those logs in "real time" using `watch` + `tail`
  58. //!
  59. //! ``` text
  60. //! $ watch 'tail /tmp/openocd.log'
  61. //! Every 2.0s: tail /tmp/openocd.log
  62. //!
  63. //! Info : Unable to match requested speed 1000 kHz, using 950 kHz
  64. //! Info : Unable to match requested speed 1000 kHz, using 950 kHz
  65. //! Info : clock speed 950 kHz
  66. //! Info : STLINK v1 JTAG v11 API v2 SWIM v0 VID 0x0483 PID 0x3744
  67. //! Info : using stlink api v2
  68. //! Info : nrf51.cpu: hardware has 4 breakpoints, 2 watchpoints
  69. //! ```
  70. //!
  71. //! Then, we run the program:
  72. //!
  73. //! ``` text
  74. //! $ arm-none-eabi-gdb hello-world
  75. //! # Connect to OpenOCD
  76. //! (gdb) target remote :3333
  77. //!
  78. //! # Enable OpenOCD's semihosting support
  79. //! (gdb) monitor arm semihosting enable
  80. //!
  81. //! # Flash the program
  82. //! (gdb) load
  83. //!
  84. //! # Run the program
  85. //! (gdb) continue
  86. //! ```
  87. //!
  88. //! And you'll see the output under OpenOCD's terminal
  89. //!
  90. //! ``` text
  91. //! # openocd -f $INTERFACE -f $TARGET -l /tmp/openocd.log
  92. //! (..)
  93. //! Hello, world!
  94. //! ```
  95. //!
  96. //! # Reference
  97. //!
  98. //! For documentation about the semihosting operations, check:
  99. //!
  100. //! 'Chapter 8 - Semihosting' of the ['ARM Compiler toolchain Version 5.0'][pdf]
  101. //! manual.
  102. //!
  103. //! [pdf]: http://infocenter.arm.com/help/topic/com.arm.doc.dui0471e/DUI0471E_developing_for_arm_processors.pdf
  104. #![feature(asm)]
  105. #![no_std]
  106. #[macro_use]
  107. mod macros;
  108. pub mod io;
  109. pub mod nr;
  110. /// Performs a semihosting operation
  111. #[inline(always)]
  112. #[cfg(target_arch = "arm")]
  113. pub unsafe fn syscall<T>(mut nr: usize, arg: &T) -> usize {
  114. asm!("bkpt 0xAB"
  115. : "+{r0}"(nr)
  116. : "{r1}"(arg)
  117. : "memory"
  118. : "volatile");
  119. nr
  120. }
  121. #[cfg(not(target_arch = "arm"))]
  122. pub unsafe fn syscall<T>(_nr: usize, _arg: &T) -> usize {
  123. 0
  124. }