mod.rs 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. //! 这个模块将会处理所有的 SBI 调用陷入,你应该在中断处理函数里调用 `handle_ecall`
  2. // §4
  3. mod base;
  4. // §6
  5. mod time;
  6. // §7
  7. mod spi;
  8. // §8
  9. mod rfnc;
  10. // §9
  11. mod hsm;
  12. // §10
  13. mod srst;
  14. // §11
  15. mod pmu;
  16. #[cfg(feature = "legacy")]
  17. use crate::{
  18. ipi::send_ipi, legacy_stdio_getchar, legacy_stdio_putchar, reset::legacy_reset, HartMask,
  19. };
  20. use sbi_spec::{self as spec, binary::SbiRet};
  21. /// Supervisor environment call handler function
  22. ///
  23. /// This function is used by platform runtime to handle environment call `ecall` instruction.
  24. ///
  25. /// You should call this function in your runtime's exception handler.
  26. /// If the incoming exception is caused by supervisor `ecall`,
  27. /// call this function with parameters extracted from trap frame.
  28. /// After this function returns, store the return value into `a0` and `a1` parameters.
  29. ///
  30. /// This function also adapts to the legacy functions.
  31. /// If the supervisor called any of legacy function, the `a0` and `a1` parameter
  32. /// is transferred to error and value field of `SbiRet` respectively.
  33. /// In this case, implementations should always store the result into `a0` and `a1` in
  34. /// any environment call functions including legacy functions.
  35. ///
  36. /// # Example
  37. ///
  38. /// A typical usage:
  39. ///
  40. /// ```no_run
  41. /// # use riscv::register::{mepc, mcause::{self, Trap, Exception}};
  42. /// # struct TrapFrame { a0: usize, a1: usize, a2: usize, a3: usize,
  43. /// # a4: usize, a5: usize, a6: usize, a7: usize }
  44. /// extern "C" fn rust_handle_exception(ctx: &mut TrapFrame) {
  45. /// if mcause::read().cause() == Trap::Exception(Exception::SupervisorEnvCall) {
  46. /// let params = [ctx.a0, ctx.a1, ctx.a2, ctx.a3, ctx.a4, ctx.a5];
  47. /// let ans = rustsbi::ecall(ctx.a7, ctx.a6, params);
  48. /// ctx.a0 = ans.error;
  49. /// ctx.a1 = ans.value;
  50. /// mepc::write(mepc::read().wrapping_add(4));
  51. /// }
  52. /// // other conditions..
  53. /// }
  54. /// ```
  55. ///
  56. /// Do not forget to advance `mepc` by 4 after an ecall is handled.
  57. /// This skips the `ecall` instruction itself which is 4-byte long in all conditions.
  58. #[inline]
  59. pub fn handle_ecall(extension: usize, function: usize, param: [usize; 6]) -> SbiRet {
  60. match extension {
  61. spec::rfnc::EID_RFNC => {
  62. rfnc::handle_ecall(function, param[0], param[1], param[2], param[3], param[4])
  63. }
  64. spec::time::EID_TIME => match () {
  65. #[cfg(target_pointer_width = "64")]
  66. () => time::handle_ecall(function, param[0]),
  67. #[cfg(target_pointer_width = "32")]
  68. () => time::handle_ecall(function, param[0], param[1]),
  69. },
  70. spec::spi::EID_SPI => spi::handle_ecall(function, param[0], param[1]),
  71. spec::base::EID_BASE => base::handle_ecall(function, param[0]),
  72. spec::hsm::EID_HSM => hsm::handle_ecall(function, param[0], param[1], param[2]),
  73. spec::srst::EID_SRST => srst::handle_ecall(function, param[0], param[1]),
  74. spec::pmu::EID_PMU => match () {
  75. #[cfg(target_pointer_width = "64")]
  76. () => pmu::handle_ecall(function, param[0], param[1], param[2], param[3], param[4]),
  77. #[cfg(target_pointer_width = "32")]
  78. () => pmu::handle_ecall(
  79. function, param[0], param[1], param[2], param[3], param[4], param[5],
  80. ),
  81. },
  82. // handle legacy callings.
  83. //
  84. // legacy 调用不使用 a1 返回值,总把 a1 填回 `SbiRet::value` 来模拟非 legacy 的行为。
  85. #[cfg(feature = "legacy")]
  86. spec::legacy::LEGACY_SET_TIMER => {
  87. match () {
  88. #[cfg(target_pointer_width = "64")]
  89. () => crate::timer::set_timer(param[0] as _),
  90. #[cfg(target_pointer_width = "32")]
  91. () => crate::timer::set_timer(concat_u32(param[1] as _, param[0] as _)),
  92. };
  93. SbiRet {
  94. error: param[0],
  95. value: param[1],
  96. }
  97. }
  98. #[cfg(feature = "legacy")]
  99. spec::legacy::LEGACY_CONSOLE_PUTCHAR => {
  100. legacy_stdio_putchar(param[0] as _);
  101. SbiRet {
  102. error: param[0],
  103. value: param[1],
  104. }
  105. }
  106. #[cfg(feature = "legacy")]
  107. spec::legacy::LEGACY_CONSOLE_GETCHAR => SbiRet {
  108. error: legacy_stdio_getchar(),
  109. value: param[1],
  110. },
  111. #[cfg(feature = "legacy")]
  112. spec::legacy::LEGACY_SEND_IPI => {
  113. send_ipi(unsafe { HartMask::legacy_from_addr(param[0]) });
  114. SbiRet {
  115. error: param[0],
  116. value: param[1],
  117. }
  118. }
  119. #[cfg(feature = "legacy")]
  120. spec::legacy::LEGACY_CLEAR_IPI => {
  121. unsafe {
  122. riscv::register::mip::clear_ssoft();
  123. }
  124. SbiRet {
  125. error: param[0],
  126. value: param[1],
  127. }
  128. }
  129. #[cfg(feature = "legacy")]
  130. spec::legacy::LEGACY_SHUTDOWN => legacy_reset(),
  131. _ => SbiRet::not_supported(),
  132. }
  133. }
  134. #[cfg(target_pointer_width = "32")]
  135. #[inline]
  136. const fn concat_u32(h: usize, l: usize) -> u64 {
  137. ((h as u64) << 32) | (l as u64)
  138. }