hsm.rs 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. use core::{
  2. cell::UnsafeCell,
  3. hint::spin_loop,
  4. sync::atomic::{AtomicUsize, Ordering},
  5. };
  6. use riscv::register::mstatus::MPP;
  7. use rustsbi::{spec::hsm::hart_state, SbiRet};
  8. use crate::board::BOARD;
  9. use crate::riscv_spec::current_hartid;
  10. use crate::sbi::hart_context::NextStage;
  11. use crate::sbi::trap_stack::ROOT_STACK;
  12. /// Special state indicating a hart is in the process of starting.
  13. const HART_STATE_START_PENDING_EXT: usize = usize::MAX;
  14. type HsmState = AtomicUsize;
  15. /// Cell for managing hart state and shared data between harts.
  16. pub(crate) struct HsmCell<T> {
  17. status: HsmState,
  18. inner: UnsafeCell<Option<T>>,
  19. }
  20. impl<T> HsmCell<T> {
  21. /// Creates a new HsmCell with STOPPED state and no inner data.
  22. pub const fn new() -> Self {
  23. Self {
  24. status: HsmState::new(hart_state::STOPPED),
  25. inner: UnsafeCell::new(None),
  26. }
  27. }
  28. /// Gets a local view of this cell for the current hart.
  29. ///
  30. /// # Safety
  31. ///
  32. /// Caller must ensure this cell belongs to the current hart.
  33. #[inline]
  34. pub unsafe fn local(&self) -> LocalHsmCell<'_, T> {
  35. LocalHsmCell(self)
  36. }
  37. /// Gets a remote view of this cell for accessing from other harts.
  38. #[inline]
  39. pub fn remote(&self) -> RemoteHsmCell<'_, T> {
  40. RemoteHsmCell(self)
  41. }
  42. }
  43. /// View of HsmCell for operations on the current hart.
  44. pub struct LocalHsmCell<'a, T>(&'a HsmCell<T>);
  45. /// View of HsmCell for operations from other harts.
  46. pub struct RemoteHsmCell<'a, T>(&'a HsmCell<T>);
  47. // Mark HsmCell as safe to share between threads
  48. unsafe impl<T: Send> Sync for HsmCell<T> {}
  49. unsafe impl<T: Send> Send for HsmCell<T> {}
  50. impl<T> LocalHsmCell<'_, T> {
  51. /// Attempts to transition hart from START_PENDING to STARTED state.
  52. ///
  53. /// Returns inner data if successful, otherwise returns current state.
  54. #[inline]
  55. pub fn start(&self) -> Result<T, usize> {
  56. loop {
  57. match self.0.status.compare_exchange(
  58. hart_state::START_PENDING,
  59. hart_state::STARTED,
  60. Ordering::AcqRel,
  61. Ordering::Relaxed,
  62. ) {
  63. Ok(_) => break Ok(unsafe { (*self.0.inner.get()).take().unwrap() }),
  64. Err(HART_STATE_START_PENDING_EXT) => spin_loop(),
  65. Err(s) => break Err(s),
  66. }
  67. }
  68. }
  69. /// Transitions hart to STOPPED state.
  70. #[allow(unused)]
  71. #[inline]
  72. pub fn stop(&self) {
  73. self.0.status.store(hart_state::STOPPED, Ordering::Release)
  74. }
  75. /// Transitions hart to SUSPENDED state.
  76. #[allow(unused)]
  77. #[inline]
  78. pub fn suspend(&self) {
  79. self.0
  80. .status
  81. .store(hart_state::SUSPENDED, Ordering::Relaxed)
  82. }
  83. /// Transitions hart to STARTED state.
  84. #[allow(unused)]
  85. #[inline]
  86. pub fn resume(&self) {
  87. self.0.status.store(hart_state::STARTED, Ordering::Relaxed)
  88. }
  89. }
  90. impl<T: core::fmt::Debug> RemoteHsmCell<'_, T> {
  91. /// Attempts to start a stopped hart by providing startup data.
  92. ///
  93. /// Returns true if successful, false if hart was not in STOPPED state.
  94. #[inline]
  95. pub fn start(&self, t: T) -> bool {
  96. if self
  97. .0
  98. .status
  99. .compare_exchange(
  100. hart_state::STOPPED,
  101. HART_STATE_START_PENDING_EXT,
  102. Ordering::Acquire,
  103. Ordering::Relaxed,
  104. )
  105. .is_ok()
  106. {
  107. unsafe { *self.0.inner.get() = Some(t) };
  108. self.0
  109. .status
  110. .store(hart_state::START_PENDING, Ordering::Release);
  111. true
  112. } else {
  113. false
  114. }
  115. }
  116. /// Gets the current state of the hart.
  117. #[allow(unused)]
  118. #[inline]
  119. pub fn sbi_get_status(&self) -> usize {
  120. match self.0.status.load(Ordering::Relaxed) {
  121. HART_STATE_START_PENDING_EXT => hart_state::START_PENDING,
  122. normal => normal,
  123. }
  124. }
  125. /// Checks if hart can receive IPIs (must be STARTED or SUSPENDED).
  126. #[allow(unused)]
  127. #[inline]
  128. pub fn allow_ipi(&self) -> bool {
  129. matches!(
  130. self.0.status.load(Ordering::Relaxed),
  131. hart_state::STARTED | hart_state::SUSPENDED
  132. )
  133. }
  134. }
  135. /// Gets the local HSM cell for the current hart.
  136. pub(crate) fn local_hsm() -> LocalHsmCell<'static, NextStage> {
  137. unsafe {
  138. ROOT_STACK
  139. .get_unchecked_mut(current_hartid())
  140. .hart_context()
  141. .hsm
  142. .local()
  143. }
  144. }
  145. /// Gets a remote view of the current hart's HSM cell.
  146. pub(crate) fn local_remote_hsm() -> RemoteHsmCell<'static, NextStage> {
  147. unsafe {
  148. ROOT_STACK
  149. .get_unchecked_mut(current_hartid())
  150. .hart_context()
  151. .hsm
  152. .remote()
  153. }
  154. }
  155. /// Gets a remote view of any hart's HSM cell.
  156. #[allow(unused)]
  157. pub(crate) fn remote_hsm(hart_id: usize) -> Option<RemoteHsmCell<'static, NextStage>> {
  158. unsafe {
  159. ROOT_STACK
  160. .get_mut(hart_id)
  161. .map(|x| x.hart_context().hsm.remote())
  162. }
  163. }
  164. /// Implementation of SBI HSM (Hart State Management) extension.
  165. pub(crate) struct SbiHsm;
  166. impl rustsbi::Hsm for SbiHsm {
  167. /// Starts execution on a stopped hart.
  168. fn hart_start(&self, hartid: usize, start_addr: usize, opaque: usize) -> SbiRet {
  169. match remote_hsm(hartid) {
  170. Some(remote) => {
  171. if remote.start(NextStage {
  172. start_addr,
  173. opaque,
  174. next_mode: MPP::Supervisor,
  175. }) {
  176. unsafe {
  177. BOARD.sbi.ipi.as_ref().unwrap().set_msip(hartid);
  178. }
  179. SbiRet::success(0)
  180. } else {
  181. SbiRet::already_started()
  182. }
  183. }
  184. None => SbiRet::invalid_param(),
  185. }
  186. }
  187. /// Stops execution on the current hart.
  188. #[inline]
  189. fn hart_stop(&self) -> SbiRet {
  190. local_hsm().stop();
  191. unsafe {
  192. riscv::register::mie::clear_msoft();
  193. }
  194. riscv::asm::wfi();
  195. SbiRet::success(0)
  196. }
  197. /// Gets the current state of a hart.
  198. #[inline]
  199. fn hart_get_status(&self, hartid: usize) -> SbiRet {
  200. match remote_hsm(hartid) {
  201. Some(remote) => SbiRet::success(remote.sbi_get_status()),
  202. None => SbiRet::invalid_param(),
  203. }
  204. }
  205. /// Suspends execution on the current hart.
  206. fn hart_suspend(&self, suspend_type: u32, _resume_addr: usize, _opaque: usize) -> SbiRet {
  207. use rustsbi::spec::hsm::suspend_type::{NON_RETENTIVE, RETENTIVE};
  208. if matches!(suspend_type, NON_RETENTIVE | RETENTIVE) {
  209. local_hsm().suspend();
  210. unsafe {
  211. BOARD.sbi.ipi.as_ref().unwrap().clear_msip(current_hartid());
  212. }
  213. unsafe {
  214. riscv::register::mie::set_msoft();
  215. }
  216. riscv::asm::wfi();
  217. local_hsm().resume();
  218. SbiRet::success(0)
  219. } else {
  220. SbiRet::not_supported()
  221. }
  222. }
  223. }