legacy_stdio.rs 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. //! 这个模块的两个宏应该公开
  2. //! 如果制造实例的时候,给定了stdout,那么就会打印到这个stdout里面
  3. use crate::util::AmoOnceRef;
  4. use core::fmt;
  5. /// Legacy standard input/output
  6. pub trait LegacyStdio: Send + Sync {
  7. /// Get a character from legacy stdin
  8. fn getchar(&self) -> u8;
  9. /// Put a character into legacy stdout
  10. fn putchar(&self, ch: u8);
  11. fn write_str(&self, s: &str) {
  12. for byte in s.as_bytes() {
  13. self.putchar(*byte)
  14. }
  15. }
  16. }
  17. static LEGACY_STDIO: AmoOnceRef<dyn LegacyStdio> = AmoOnceRef::new();
  18. #[inline]
  19. pub fn init_legacy_stdio(stdio: &'static dyn LegacyStdio) {
  20. if !LEGACY_STDIO.try_call_once(stdio) {
  21. panic!("load sbi module when already loaded")
  22. }
  23. }
  24. #[inline]
  25. pub fn legacy_stdio_putchar(ch: u8) {
  26. if let Some(stdio) = LEGACY_STDIO.get() {
  27. stdio.putchar(ch)
  28. }
  29. }
  30. #[inline]
  31. pub fn legacy_stdio_getchar() -> usize {
  32. if let Some(stdio) = LEGACY_STDIO.get() {
  33. stdio.getchar() as usize
  34. } else {
  35. // According to RISC-V SBI spec 0.3.1-rc1, Section 4.3, this function returns -1
  36. // when fails to read from debug console. Thank you @duskmoon314
  37. usize::from_ne_bytes(isize::to_ne_bytes(-1))
  38. }
  39. }
  40. #[inline]
  41. pub(crate) fn probe_legacy_stdio() -> bool {
  42. LEGACY_STDIO.get().is_some()
  43. }
  44. struct Stdout;
  45. impl fmt::Write for Stdout {
  46. #[inline]
  47. fn write_str(&mut self, s: &str) -> fmt::Result {
  48. if let Some(stdio) = LEGACY_STDIO.get() {
  49. stdio.write_str(s);
  50. }
  51. Ok(())
  52. }
  53. }
  54. #[inline]
  55. #[doc(hidden)]
  56. pub fn _print(args: fmt::Arguments) {
  57. use fmt::Write;
  58. Stdout.write_fmt(args).unwrap();
  59. }
  60. /// Prints to the legacy debug console.
  61. ///
  62. /// This is only supported when there exists legacy extension;
  63. /// otherwise platform caller should use an early kernel input/output device
  64. /// declared in platform specific hardware.
  65. #[macro_export]
  66. macro_rules! print {
  67. ($($arg:tt)*) => ($crate::legacy_stdio::_print(core::format_args!($($arg)*)));
  68. }
  69. /// Prints to the legacy debug console, with a newline.
  70. ///
  71. /// This is only supported when there exists legacy extension;
  72. /// otherwise platform caller should use an early kernel input/output device
  73. /// declared in platform specific hardware.
  74. #[macro_export]
  75. macro_rules! println {
  76. () => ($crate::print!("\r\n"));
  77. ($($arg:tt)*) => {
  78. $crate::legacy_stdio::_print(core::format_args!($($arg)*));
  79. $crate::print!("\r\n");
  80. }
  81. }