ecall.rs 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. //! 这个模块将会处理所有的SBI调用陷入
  2. // 你应该在riscv-rt或其它中断处理函数里,调用这个模块的内容
  3. mod base;
  4. mod hsm;
  5. mod ipi;
  6. mod legacy;
  7. mod srst;
  8. mod timer;
  9. mod rfence;
  10. mod pmu;
  11. pub const EXTENSION_BASE: usize = 0x10;
  12. pub const EXTENSION_TIMER: usize = 0x54494D45;
  13. pub const EXTENSION_IPI: usize = 0x735049;
  14. pub const EXTENSION_RFENCE: usize = 0x52464E43;
  15. pub const EXTENSION_HSM: usize = 0x48534D;
  16. pub const EXTENSION_SRST: usize = 0x53525354;
  17. pub const EXTENSION_PMU: usize = 0x504D55;
  18. const LEGACY_SET_TIMER: usize = 0x0;
  19. const LEGACY_CONSOLE_PUTCHAR: usize = 0x01;
  20. const LEGACY_CONSOLE_GETCHAR: usize = 0x02;
  21. // const LEGACY_CLEAR_IPI: usize = 0x03;
  22. const LEGACY_SEND_IPI: usize = 0x04;
  23. // const LEGACY_REMOTE_FENCE_I: usize = 0x05;
  24. // const LEGACY_REMOTE_SFENCE_VMA: usize = 0x06;
  25. // const LEGACY_REMOTE_SFENCE_VMA_ASID: usize = 0x07;
  26. const LEGACY_SHUTDOWN: usize = 0x08;
  27. /// Supervisor environment call handler function
  28. ///
  29. /// This function is used by platform runtime to handle environment call `ecall` instruction.
  30. ///
  31. /// You should call this function in your runtime's exception handler.
  32. /// If the incoming exception is caused by supervisor `ecall`,
  33. /// call this function with parameters extracted from trap frame.
  34. /// After this function returns, store the return value into `a0` and `a1` parameters.
  35. ///
  36. /// This function also adapts to the legacy functions.
  37. /// If the supervisor called any of legacy function, the `a0` and `a1` parameter
  38. /// is transferred to `SbiRet`'s error and value respectively.
  39. /// So you should store the result into `a0` and `a1` in any function calls including legacy functions.
  40. ///
  41. /// # Example
  42. ///
  43. /// A typical usage:
  44. ///
  45. /// ```no_run
  46. /// #[exception]
  47. /// fn handle_exception(ctx: &mut TrapFrame) {
  48. /// if mcause::read().cause() == Trap::Exception(Exception::SupervisorEnvCall) {
  49. /// let params = [ctx.a0, ctx.a1, ctx.a2, ctx.a3, ctx.a4, ctx.a5];
  50. /// let ans = rustsbi::ecall(ctx.a7, ctx.a6, params);
  51. /// ctx.a0 = ans.error;
  52. /// ctx.a1 = ans.value;
  53. /// mepc::write(mepc::read().wrapping_add(4));
  54. /// }
  55. /// // other conditions..
  56. /// }
  57. /// ```
  58. ///
  59. /// Do not forget to advance `mepc` by 4 after an ecall is handled.
  60. /// This skips the `ecall` instruction itself which is 4-byte long in all conditions.
  61. #[inline]
  62. pub fn handle_ecall(extension: usize, function: usize, param: [usize; 6]) -> SbiRet {
  63. match extension {
  64. EXTENSION_RFENCE => rfence::handle_ecall_rfence(function, param[0], param[1], param[2], param[3], param[4]),
  65. EXTENSION_TIMER => match () {
  66. #[cfg(target_pointer_width = "64")]
  67. () => timer::handle_ecall_timer_64(function, param[0]),
  68. #[cfg(target_pointer_width = "32")]
  69. () => timer::handle_ecall_timer_32(function, param[0], param[1]),
  70. },
  71. EXTENSION_IPI => ipi::handle_ecall_ipi(function, param[0], param[1]),
  72. EXTENSION_BASE => base::handle_ecall_base(function, param[0]),
  73. EXTENSION_HSM => hsm::handle_ecall_hsm(function, param[0], param[1], param[2]),
  74. EXTENSION_SRST => srst::handle_ecall_srst(function, param[0], param[1]),
  75. EXTENSION_PMU => match () {
  76. #[cfg(target_pointer_width = "64")]
  77. () => pmu::handle_ecall_pmu_64(function, param[0], param[1], param[2], param[3], param[4]),
  78. #[cfg(target_pointer_width = "32")]
  79. () => pmu::handle_ecall_pmu_32(function, param[0], param[1], param[2], param[3], param[4], param[5]),
  80. },
  81. LEGACY_SET_TIMER => match () {
  82. #[cfg(target_pointer_width = "64")]
  83. () => legacy::set_timer_64(param[0]),
  84. #[cfg(target_pointer_width = "32")]
  85. () => legacy::set_timer_32(param[0], param[1]),
  86. }
  87. .legacy_void(param[0], param[1]),
  88. LEGACY_CONSOLE_PUTCHAR => legacy::console_putchar(param[0]).legacy_void(param[0], param[1]),
  89. LEGACY_CONSOLE_GETCHAR => legacy::console_getchar().legacy_return(param[1]),
  90. LEGACY_SEND_IPI => legacy::send_ipi(param[0]).legacy_void(param[0], param[1]),
  91. LEGACY_SHUTDOWN => legacy::shutdown().legacy_void(param[0], param[1]),
  92. _ => SbiRet::not_supported(),
  93. }
  94. }
  95. /// Call result returned by SBI
  96. ///
  97. /// After `handle_ecall` finished, you should save returned `error` in `a0`, and `value` in `a1`.
  98. #[repr(C)] // ensure that return value follows RISC-V SBI calling convention
  99. pub struct SbiRet {
  100. /// Error number
  101. pub error: usize,
  102. /// Result value
  103. pub value: usize,
  104. }
  105. const SBI_SUCCESS: usize = 0;
  106. const SBI_ERR_FAILED: usize = usize::from_ne_bytes(isize::to_ne_bytes(-1));
  107. const SBI_ERR_NOT_SUPPORTED: usize = usize::from_ne_bytes(isize::to_ne_bytes(-2));
  108. const SBI_ERR_INVALID_PARAM: usize = usize::from_ne_bytes(isize::to_ne_bytes(-3));
  109. // const SBI_ERR_DENIED: usize = usize::from_ne_bytes(isize::to_ne_bytes(-4));
  110. const SBI_ERR_INVALID_ADDRESS: usize = usize::from_ne_bytes(isize::to_ne_bytes(-5));
  111. const SBI_ERR_ALREADY_AVAILABLE: usize = usize::from_ne_bytes(isize::to_ne_bytes(-6));
  112. const SBI_ERR_ALREADY_STARTED: usize = usize::from_ne_bytes(isize::to_ne_bytes(-7));
  113. const SBI_ERR_ALREADY_STOPPED: usize = usize::from_ne_bytes(isize::to_ne_bytes(-8));
  114. impl SbiRet {
  115. /// Return success SBI state with given value.
  116. pub fn ok(value: usize) -> SbiRet {
  117. SbiRet {
  118. error: SBI_SUCCESS,
  119. value,
  120. }
  121. }
  122. /// The SBI call request failed for unknown reasons.
  123. pub fn failed() -> SbiRet {
  124. SbiRet {
  125. error: SBI_ERR_FAILED,
  126. value: 0,
  127. }
  128. }
  129. /// SBI call failed due to not supported by target ISA, operation type not supported,
  130. /// or target operation type not implemented on purpose.
  131. pub fn not_supported() -> SbiRet {
  132. SbiRet {
  133. error: SBI_ERR_NOT_SUPPORTED,
  134. value: 0,
  135. }
  136. }
  137. /// SBI call failed due to invalid hart mask parameter, invalid target hart id, invalid operation type
  138. /// or invalid resource index.
  139. pub fn invalid_param() -> SbiRet {
  140. SbiRet {
  141. error: SBI_ERR_INVALID_PARAM,
  142. value: 0,
  143. }
  144. }
  145. /// SBI call failed for invalid mask start address, not a valid physical address parameter,
  146. /// or the target address is prohibited by PMP to run in supervisor mode.
  147. pub fn invalid_address() -> SbiRet {
  148. SbiRet {
  149. error: SBI_ERR_INVALID_ADDRESS,
  150. value: 0,
  151. }
  152. }
  153. /// SBI call failed for the target resource is already available, e.g. the target hart is already
  154. /// started when caller still request it to start.
  155. pub fn already_available() -> SbiRet {
  156. SbiRet {
  157. error: SBI_ERR_ALREADY_AVAILABLE,
  158. value: 0,
  159. }
  160. }
  161. /// SBI call failed for the target resource is already started, e.g. target performance counter is started.
  162. pub fn already_started() -> SbiRet {
  163. SbiRet {
  164. error: SBI_ERR_ALREADY_STARTED,
  165. value: 0,
  166. }
  167. }
  168. /// SBI call failed for the target resource is already stopped, e.g. target performance counter is stopped.
  169. pub fn already_stopped() -> SbiRet {
  170. SbiRet {
  171. error: SBI_ERR_ALREADY_STOPPED,
  172. value: 0,
  173. }
  174. }
  175. pub(crate) fn legacy_ok(legacy_value: usize) -> SbiRet {
  176. SbiRet {
  177. error: legacy_value,
  178. value: 0,
  179. }
  180. }
  181. // only used for legacy where a0, a1 return value is not modified
  182. pub(crate) fn legacy_void(self, a0: usize, a1: usize) -> SbiRet {
  183. SbiRet {
  184. error: a0,
  185. value: a1,
  186. }
  187. }
  188. pub(crate) fn legacy_return(self, a1: usize) -> SbiRet {
  189. SbiRet {
  190. error: self.error,
  191. value: a1,
  192. }
  193. }
  194. }