binary.rs 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997
  1. //! Chapter 3. Binary Encoding.
  2. use core::marker::PhantomData;
  3. /// SBI functions return type.
  4. ///
  5. /// > SBI functions must return a pair of values in a0 and a1,
  6. /// > with a0 returning an error code.
  7. /// > This is analogous to returning the C structure `SbiRet`.
  8. ///
  9. /// Note: if this structure is used in function return on conventional
  10. /// Rust code, it would not require pinning memory representation as
  11. /// extern C. The `repr(C)` is set in case that some users want to use
  12. /// this structure in FFI code.
  13. #[derive(Clone, Copy, PartialEq, Eq)]
  14. #[repr(C)]
  15. pub struct SbiRet {
  16. /// Error number.
  17. pub error: usize,
  18. /// Result value.
  19. pub value: usize,
  20. }
  21. /// SBI success state return value.
  22. pub const RET_SUCCESS: usize = 0;
  23. /// Error for SBI call failed for unknown reasons.
  24. pub const RET_ERR_FAILED: usize = -1isize as _;
  25. /// Error for target operation not supported.
  26. pub const RET_ERR_NOT_SUPPORTED: usize = -2isize as _;
  27. /// Error for invalid parameter.
  28. pub const RET_ERR_INVALID_PARAM: usize = -3isize as _;
  29. /// Error for denied (unused in standard extensions).
  30. pub const RET_ERR_DENIED: usize = -4isize as _;
  31. /// Error for invalid address.
  32. pub const RET_ERR_INVALID_ADDRESS: usize = -5isize as _;
  33. /// Error for resource already available.
  34. pub const RET_ERR_ALREADY_AVAILABLE: usize = -6isize as _;
  35. /// Error for resource already started.
  36. pub const RET_ERR_ALREADY_STARTED: usize = -7isize as _;
  37. /// Error for resource already stopped.
  38. pub const RET_ERR_ALREADY_STOPPED: usize = -8isize as _;
  39. /// Error for shared memory not available.
  40. pub const RET_ERR_NO_SHMEM: usize = -9isize as _;
  41. impl core::fmt::Debug for SbiRet {
  42. fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
  43. match self.error {
  44. RET_SUCCESS => self.value.fmt(f),
  45. RET_ERR_FAILED => write!(f, "<SBI call failed>"),
  46. RET_ERR_NOT_SUPPORTED => write!(f, "<SBI feature not supported>"),
  47. RET_ERR_INVALID_PARAM => write!(f, "<SBI invalid parameter>"),
  48. RET_ERR_DENIED => write!(f, "<SBI denied>"),
  49. RET_ERR_INVALID_ADDRESS => write!(f, "<SBI invalid address>"),
  50. RET_ERR_ALREADY_AVAILABLE => write!(f, "<SBI already available>"),
  51. RET_ERR_ALREADY_STARTED => write!(f, "<SBI already started>"),
  52. RET_ERR_ALREADY_STOPPED => write!(f, "<SBI already stopped>"),
  53. RET_ERR_NO_SHMEM => write!(f, "<SBI shared memory not available>"),
  54. unknown => write!(f, "[SBI Unknown error: {unknown:#x}]"),
  55. }
  56. }
  57. }
  58. /// RISC-V SBI error in enumeration.
  59. #[derive(Debug, Clone, Copy, PartialEq, Eq)]
  60. pub enum Error {
  61. /// Error for SBI call failed for unknown reasons.
  62. Failed,
  63. /// Error for target operation not supported.
  64. NotSupported,
  65. /// Error for invalid parameter.
  66. InvalidParam,
  67. /// Error for denied (unused in standard extensions).
  68. Denied,
  69. /// Error for invalid address.
  70. InvalidAddress,
  71. /// Error for resource already available.
  72. AlreadyAvailable,
  73. /// Error for resource already started.
  74. AlreadyStarted,
  75. /// Error for resource already stopped.
  76. AlreadyStopped,
  77. /// Error for shared memory not available.
  78. NoShmem,
  79. /// Custom error code.
  80. Custom(isize),
  81. }
  82. impl SbiRet {
  83. /// Returns success SBI state with given `value`.
  84. #[inline]
  85. pub const fn success(value: usize) -> Self {
  86. Self {
  87. error: RET_SUCCESS,
  88. value,
  89. }
  90. }
  91. /// The SBI call request failed for unknown reasons.
  92. #[inline]
  93. pub const fn failed() -> Self {
  94. Self {
  95. error: RET_ERR_FAILED,
  96. value: 0,
  97. }
  98. }
  99. /// SBI call failed due to not supported by target ISA,
  100. /// operation type not supported,
  101. /// or target operation type not implemented on purpose.
  102. #[inline]
  103. pub const fn not_supported() -> Self {
  104. Self {
  105. error: RET_ERR_NOT_SUPPORTED,
  106. value: 0,
  107. }
  108. }
  109. /// SBI call failed due to invalid hart mask parameter,
  110. /// invalid target hart id,
  111. /// invalid operation type,
  112. /// or invalid resource index.
  113. #[inline]
  114. pub const fn invalid_param() -> Self {
  115. Self {
  116. error: RET_ERR_INVALID_PARAM,
  117. value: 0,
  118. }
  119. }
  120. /// SBI call denied.
  121. ///
  122. /// As the time this document was written,
  123. /// there is currently no function in SBI standard that returns this error.
  124. /// However, custom extensions or future standard functions may return this
  125. /// error if appropriate.
  126. #[inline]
  127. pub const fn denied() -> Self {
  128. Self {
  129. error: RET_ERR_DENIED,
  130. value: 0,
  131. }
  132. }
  133. /// SBI call failed for invalid mask start address,
  134. /// not a valid physical address parameter,
  135. /// or the target address is prohibited by PMP to run in supervisor mode.
  136. #[inline]
  137. pub const fn invalid_address() -> Self {
  138. Self {
  139. error: RET_ERR_INVALID_ADDRESS,
  140. value: 0,
  141. }
  142. }
  143. /// SBI call failed for the target resource is already available,
  144. /// e.g., the target hart is already started when caller still requests it to start.
  145. #[inline]
  146. pub const fn already_available() -> Self {
  147. Self {
  148. error: RET_ERR_ALREADY_AVAILABLE,
  149. value: 0,
  150. }
  151. }
  152. /// SBI call failed for the target resource is already started,
  153. /// e.g., target performance counter is started.
  154. #[inline]
  155. pub const fn already_started() -> Self {
  156. Self {
  157. error: RET_ERR_ALREADY_STARTED,
  158. value: 0,
  159. }
  160. }
  161. /// SBI call failed for the target resource is already stopped,
  162. /// e.g., target performance counter is stopped.
  163. #[inline]
  164. pub const fn already_stopped() -> Self {
  165. Self {
  166. error: RET_ERR_ALREADY_STOPPED,
  167. value: 0,
  168. }
  169. }
  170. /// SBI call failed for shared memory is not available,
  171. /// e.g. nested acceleration shared memory is not available.
  172. #[inline]
  173. pub const fn no_shmem() -> Self {
  174. Self {
  175. error: RET_ERR_NO_SHMEM,
  176. value: 0,
  177. }
  178. }
  179. }
  180. impl SbiRet {
  181. /// Converts to a [`Result`] of value and error.
  182. #[inline]
  183. pub const fn into_result(self) -> Result<usize, Error> {
  184. match self.error {
  185. RET_SUCCESS => Ok(self.value),
  186. RET_ERR_FAILED => Err(Error::Failed),
  187. RET_ERR_NOT_SUPPORTED => Err(Error::NotSupported),
  188. RET_ERR_INVALID_PARAM => Err(Error::InvalidParam),
  189. RET_ERR_DENIED => Err(Error::Denied),
  190. RET_ERR_INVALID_ADDRESS => Err(Error::InvalidAddress),
  191. RET_ERR_ALREADY_AVAILABLE => Err(Error::AlreadyAvailable),
  192. RET_ERR_ALREADY_STARTED => Err(Error::AlreadyStarted),
  193. RET_ERR_ALREADY_STOPPED => Err(Error::AlreadyStopped),
  194. RET_ERR_NO_SHMEM => Err(Error::NoShmem),
  195. unknown => Err(Error::Custom(unknown as _)),
  196. }
  197. }
  198. /// Returns `true` if current SBI return succeeded.
  199. ///
  200. /// # Examples
  201. ///
  202. /// Basic usage:
  203. ///
  204. /// ```
  205. /// # use sbi_spec::binary::SbiRet;
  206. /// let x = SbiRet::success(0);
  207. /// assert_eq!(x.is_ok(), true);
  208. ///
  209. /// let x = SbiRet::failed();
  210. /// assert_eq!(x.is_ok(), false);
  211. /// ```
  212. #[must_use = "if you intended to assert that this is ok, consider `.unwrap()` instead"]
  213. #[inline]
  214. pub const fn is_ok(&self) -> bool {
  215. matches!(self.error, RET_SUCCESS)
  216. }
  217. /// Returns `true` if current SBI return is an error.
  218. ///
  219. /// # Examples
  220. ///
  221. /// Basic usage:
  222. ///
  223. /// ```
  224. /// # use sbi_spec::binary::SbiRet;
  225. /// let x = SbiRet::success(0);
  226. /// assert_eq!(x.is_err(), false);
  227. ///
  228. /// let x = SbiRet::not_supported();
  229. /// assert_eq!(x.is_err(), true);
  230. /// ```
  231. #[must_use = "if you intended to assert that this is err, consider `.unwrap_err()` instead"]
  232. #[inline]
  233. pub const fn is_err(&self) -> bool {
  234. !self.is_ok()
  235. }
  236. /// Converts from `SbiRet` to [`Option<usize>`].
  237. ///
  238. /// Converts `self` into an [`Option<usize>`], consuming `self`,
  239. /// and discarding the error, if any.
  240. ///
  241. /// # Examples
  242. ///
  243. /// Basic usage:
  244. ///
  245. /// ```
  246. /// # use sbi_spec::binary::SbiRet;
  247. /// let x = SbiRet::success(2);
  248. /// assert_eq!(x.ok(), Some(2));
  249. ///
  250. /// let x = SbiRet::invalid_param();
  251. /// assert_eq!(x.ok(), None);
  252. /// ```
  253. // fixme: should be pub const fn once this function in Result is stablized in constant
  254. #[inline]
  255. pub fn ok(self) -> Option<usize> {
  256. self.into_result().ok()
  257. }
  258. /// Converts from `SbiRet` to [`Option<Error>`].
  259. ///
  260. /// Converts `self` into an [`Option<Error>`], consuming `self`,
  261. /// and discarding the success value, if any.
  262. ///
  263. /// # Examples
  264. ///
  265. /// Basic usage:
  266. ///
  267. /// ```
  268. /// # use sbi_spec::binary::{SbiRet, Error};
  269. /// let x = SbiRet::success(2);
  270. /// assert_eq!(x.err(), None);
  271. ///
  272. /// let x = SbiRet::denied();
  273. /// assert_eq!(x.err(), Some(Error::Denied));
  274. /// ```
  275. // fixme: should be pub const fn once this function in Result is stablized in constant
  276. #[inline]
  277. pub fn err(self) -> Option<Error> {
  278. self.into_result().err()
  279. }
  280. /// Maps a `SbiRet` to `Result<U, Error>` by applying a function to a
  281. /// contained success value, leaving an error value untouched.
  282. ///
  283. /// This function can be used to compose the results of two functions.
  284. ///
  285. /// # Examples
  286. ///
  287. /// Gets detail of a PMU counter and judge if it is a firmware counter.
  288. ///
  289. /// ```
  290. /// # use sbi_spec::binary::SbiRet;
  291. /// # use core::mem::size_of;
  292. /// # mod sbi_rt {
  293. /// # use sbi_spec::binary::SbiRet;
  294. /// # const TYPE_MASK: usize = 1 << (core::mem::size_of::<usize>() - 1);
  295. /// # pub fn pmu_counter_get_info(_: usize) -> SbiRet { SbiRet::success(TYPE_MASK) }
  296. /// # }
  297. /// // We assume that counter index 42 is a firmware counter.
  298. /// let counter_idx = 42;
  299. /// // Masks PMU counter type by setting highest bit in `usize`.
  300. /// const TYPE_MASK: usize = 1 << (size_of::<usize>() - 1);
  301. /// // Highest bit of returned `counter_info` represents whether it's
  302. /// // a firmware counter or a hardware counter.
  303. /// let is_firmware_counter = sbi_rt::pmu_counter_get_info(counter_idx)
  304. /// .map(|counter_info| counter_info & TYPE_MASK != 0);
  305. /// // If that bit is set, it is a firmware counter.
  306. /// assert_eq!(is_firmware_counter, Ok(true));
  307. /// ```
  308. #[inline]
  309. pub fn map<U, F: FnOnce(usize) -> U>(self, op: F) -> Result<U, Error> {
  310. self.into_result().map(op)
  311. }
  312. /// Returns the provided default (if error),
  313. /// or applies a function to the contained value (if success).
  314. ///
  315. /// Arguments passed to `map_or` are eagerly evaluated;
  316. /// if you are passing the result of a function call,
  317. /// it is recommended to use [`map_or_else`],
  318. /// which is lazily evaluated.
  319. ///
  320. /// [`map_or_else`]: SbiRet::map_or_else
  321. ///
  322. /// # Examples
  323. ///
  324. /// ```
  325. /// # use sbi_spec::binary::SbiRet;
  326. /// let x = SbiRet::success(3);
  327. /// assert_eq!(x.map_or(42, |v| v & 0b1), 1);
  328. ///
  329. /// let x = SbiRet::invalid_address();
  330. /// assert_eq!(x.map_or(42, |v| v & 0b1), 42);
  331. /// ```
  332. #[inline]
  333. pub fn map_or<U, F: FnOnce(usize) -> U>(self, default: U, f: F) -> U {
  334. self.into_result().map_or(default, f)
  335. }
  336. /// Maps a `SbiRet` to `usize` value by applying fallback function `default` to
  337. /// a contained error, or function `f` to a contained success value.
  338. ///
  339. /// This function can be used to unpack a successful result
  340. /// while handling an error.
  341. ///
  342. /// # Examples
  343. ///
  344. /// Basic usage:
  345. ///
  346. /// ```
  347. /// # use sbi_spec::binary::SbiRet;
  348. /// let k = 21;
  349. ///
  350. /// let x = SbiRet::success(3);
  351. /// assert_eq!(x.map_or_else(|e| k * 2, |v| v & 0b1), 1);
  352. ///
  353. /// let x = SbiRet::already_available();
  354. /// assert_eq!(x.map_or_else(|e| k * 2, |v| v & 0b1), 42);
  355. /// ```
  356. #[inline]
  357. pub fn map_or_else<U, D: FnOnce(Error) -> U, F: FnOnce(usize) -> U>(
  358. self,
  359. default: D,
  360. f: F,
  361. ) -> U {
  362. self.into_result().map_or_else(default, f)
  363. }
  364. /// Maps a `SbiRet` to `Result<T, F>` by applying a function to a
  365. /// contained error as [`Error`] struct, leaving success value untouched.
  366. ///
  367. /// This function can be used to pass through a successful result while handling
  368. /// an error.
  369. ///
  370. /// # Examples
  371. ///
  372. /// Basic usage:
  373. ///
  374. /// ```
  375. /// # use sbi_spec::binary::{SbiRet, Error};
  376. /// fn stringify(x: Error) -> String {
  377. /// if x == Error::AlreadyStarted {
  378. /// "error: already started!".to_string()
  379. /// } else {
  380. /// "error: other error!".to_string()
  381. /// }
  382. /// }
  383. ///
  384. /// let x = SbiRet::success(2);
  385. /// assert_eq!(x.map_err(stringify), Ok(2));
  386. ///
  387. /// let x = SbiRet::already_started();
  388. /// assert_eq!(x.map_err(stringify), Err("error: already started!".to_string()));
  389. /// ```
  390. #[inline]
  391. pub fn map_err<F, O: FnOnce(Error) -> F>(self, op: O) -> Result<usize, F> {
  392. self.into_result().map_err(op)
  393. }
  394. /// Returns the contained success value, consuming the `self` value.
  395. ///
  396. /// # Panics
  397. ///
  398. /// Panics if self is an SBI error with a panic message including the
  399. /// passed message, and the content of the SBI state.
  400. ///
  401. /// # Examples
  402. ///
  403. /// Basic usage:
  404. ///
  405. /// ```should_panic
  406. /// # use sbi_spec::binary::SbiRet;
  407. /// let x = SbiRet::already_stopped();
  408. /// x.expect("Testing expect"); // panics with `Testing expect`
  409. /// ```
  410. #[inline]
  411. pub fn expect(self, msg: &str) -> usize {
  412. self.into_result().expect(msg)
  413. }
  414. /// Returns the contained success value, consuming the `self` value.
  415. ///
  416. /// # Panics
  417. ///
  418. /// Panics if self is an SBI error, with a panic message provided by the
  419. /// SBI error converted into [`Error`] struct.
  420. ///
  421. /// # Examples
  422. ///
  423. /// Basic usage:
  424. ///
  425. /// ```
  426. /// # use sbi_spec::binary::SbiRet;
  427. /// let x = SbiRet::success(2);
  428. /// assert_eq!(x.unwrap(), 2);
  429. /// ```
  430. ///
  431. /// ```should_panic
  432. /// # use sbi_spec::binary::SbiRet;
  433. /// let x = SbiRet::failed();
  434. /// x.unwrap(); // panics
  435. /// ```
  436. #[inline]
  437. pub fn unwrap(self) -> usize {
  438. self.into_result().unwrap()
  439. }
  440. /// Returns the contained error as [`Error`] struct, consuming the `self` value.
  441. ///
  442. /// # Panics
  443. ///
  444. /// Panics if the self is SBI success value, with a panic message
  445. /// including the passed message, and the content of the success value.
  446. ///
  447. /// # Examples
  448. ///
  449. /// Basic usage:
  450. ///
  451. /// ```should_panic
  452. /// # use sbi_spec::binary::SbiRet;
  453. /// let x = SbiRet::success(10);
  454. /// x.expect_err("Testing expect_err"); // panics with `Testing expect_err`
  455. /// ```
  456. #[inline]
  457. pub fn expect_err(self, msg: &str) -> Error {
  458. self.into_result().expect_err(msg)
  459. }
  460. /// Returns the contained error as [`Error`] struct, consuming the `self` value.
  461. ///
  462. /// # Panics
  463. ///
  464. /// Panics if the self is SBI success value, with a custom panic message provided
  465. /// by the success value.
  466. ///
  467. /// # Examples
  468. ///
  469. /// ```should_panic
  470. /// # use sbi_spec::binary::SbiRet;
  471. /// let x = SbiRet::success(2);
  472. /// x.unwrap_err(); // panics with `2`
  473. /// ```
  474. ///
  475. /// ```
  476. /// # use sbi_spec::binary::{SbiRet, Error};
  477. /// let x = SbiRet::not_supported();
  478. /// assert_eq!(x.unwrap_err(), Error::NotSupported);
  479. /// ```
  480. #[inline]
  481. pub fn unwrap_err(self) -> Error {
  482. self.into_result().unwrap_err()
  483. }
  484. /// Returns `res` if self is success value, otherwise otherwise returns the contained error
  485. /// of `self` as [`Error`] struct.
  486. ///
  487. /// Arguments passed to `and` are eagerly evaluated; if you are passing the
  488. /// result of a function call, it is recommended to use [`and_then`], which is
  489. /// lazily evaluated.
  490. ///
  491. /// [`and_then`]: SbiRet::and_then
  492. ///
  493. /// # Examples
  494. ///
  495. /// Basic usage:
  496. ///
  497. /// ```
  498. /// # use sbi_spec::binary::{SbiRet, Error};
  499. /// let x = SbiRet::success(2);
  500. /// let y = SbiRet::invalid_param().into_result();
  501. /// assert_eq!(x.and(y), Err(Error::InvalidParam));
  502. ///
  503. /// let x = SbiRet::denied();
  504. /// let y = SbiRet::success(3).into_result();
  505. /// assert_eq!(x.and(y), Err(Error::Denied));
  506. ///
  507. /// let x = SbiRet::invalid_address();
  508. /// let y = SbiRet::already_available().into_result();
  509. /// assert_eq!(x.and(y), Err(Error::InvalidAddress));
  510. ///
  511. /// let x = SbiRet::success(4);
  512. /// let y = SbiRet::success(5).into_result();
  513. /// assert_eq!(x.and(y), Ok(5));
  514. /// ```
  515. // fixme: should be pub const fn once this function in Result is stablized in constant
  516. // fixme: should parameter be `res: SbiRet`?
  517. #[inline]
  518. pub fn and(self, res: Result<usize, Error>) -> Result<usize, Error> {
  519. self.into_result().and(res)
  520. }
  521. /// Calls `op` if self is success value, otherwise returns the contained error
  522. /// as [`Error`] struct.
  523. ///
  524. /// This function can be used for control flow based on `SbiRet` values.
  525. ///
  526. /// # Examples
  527. ///
  528. /// ```
  529. /// # use sbi_spec::binary::{SbiRet, Error};
  530. /// fn sq_then_to_string(x: usize) -> Result<String, Error> {
  531. /// x.checked_mul(x).map(|sq| sq.to_string()).ok_or(Error::Failed)
  532. /// }
  533. ///
  534. /// assert_eq!(SbiRet::success(2).and_then(sq_then_to_string), Ok(4.to_string()));
  535. /// assert_eq!(SbiRet::success(1_000_000_000_000).and_then(sq_then_to_string), Err(Error::Failed));
  536. /// assert_eq!(SbiRet::invalid_param().and_then(sq_then_to_string), Err(Error::InvalidParam));
  537. /// ```
  538. #[inline]
  539. pub fn and_then<U, F: FnOnce(usize) -> Result<U, Error>>(self, op: F) -> Result<U, Error> {
  540. self.into_result().and_then(op)
  541. }
  542. /// Returns `res` if self is SBI error, otherwise returns the success value of `self`.
  543. ///
  544. /// Arguments passed to `or` are eagerly evaluated; if you are passing the
  545. /// result of a function call, it is recommended to use [`or_else`], which is
  546. /// lazily evaluated.
  547. ///
  548. /// [`or_else`]: Result::or_else
  549. ///
  550. /// # Examples
  551. ///
  552. /// Basic usage:
  553. ///
  554. /// ```
  555. /// # use sbi_spec::binary::{SbiRet, Error};
  556. /// let x = SbiRet::success(2);
  557. /// let y = SbiRet::invalid_param().into_result();
  558. /// assert_eq!(x.or(y), Ok(2));
  559. ///
  560. /// let x = SbiRet::denied();
  561. /// let y = SbiRet::success(3).into_result();
  562. /// assert_eq!(x.or(y), Ok(3));
  563. ///
  564. /// let x = SbiRet::invalid_address();
  565. /// let y = SbiRet::already_available().into_result();
  566. /// assert_eq!(x.or(y), Err(Error::AlreadyAvailable));
  567. ///
  568. /// let x = SbiRet::success(4);
  569. /// let y = SbiRet::success(100).into_result();
  570. /// assert_eq!(x.or(y), Ok(4));
  571. /// ```
  572. // fixme: should be pub const fn once this function in Result is stablized in constant
  573. // fixme: should parameter be `res: SbiRet`?
  574. #[inline]
  575. pub fn or<F>(self, res: Result<usize, F>) -> Result<usize, F> {
  576. self.into_result().or(res)
  577. }
  578. /// Calls `op` if self is SBI error, otherwise returns the success value of `self`.
  579. ///
  580. /// This function can be used for control flow based on result values.
  581. ///
  582. ///
  583. /// # Examples
  584. ///
  585. /// Basic usage:
  586. ///
  587. /// ```
  588. /// # use sbi_spec::binary::{SbiRet, Error};
  589. /// fn is_failed(x: Error) -> Result<usize, bool> { Err(x == Error::Failed) }
  590. ///
  591. /// assert_eq!(SbiRet::success(2).or_else(is_failed), Ok(2));
  592. /// assert_eq!(SbiRet::failed().or_else(is_failed), Err(true));
  593. /// ```
  594. #[inline]
  595. pub fn or_else<F, O: FnOnce(Error) -> Result<usize, F>>(self, op: O) -> Result<usize, F> {
  596. self.into_result().or_else(op)
  597. }
  598. /// Returns the contained success value or a provided default.
  599. ///
  600. /// Arguments passed to `unwrap_or` are eagerly evaluated; if you are passing
  601. /// the result of a function call, it is recommended to use [`unwrap_or_else`],
  602. /// which is lazily evaluated.
  603. ///
  604. /// [`unwrap_or_else`]: SbiRet::unwrap_or_else
  605. ///
  606. /// # Examples
  607. ///
  608. /// Basic usage:
  609. ///
  610. /// ```
  611. /// # use sbi_spec::binary::SbiRet;
  612. /// let default = 2;
  613. /// let x = SbiRet::success(9);
  614. /// assert_eq!(x.unwrap_or(default), 9);
  615. ///
  616. /// let x = SbiRet::invalid_param();
  617. /// assert_eq!(x.unwrap_or(default), default);
  618. /// ```
  619. // fixme: should be pub const fn once this function in Result is stablized in constant
  620. #[inline]
  621. pub fn unwrap_or(self, default: usize) -> usize {
  622. self.into_result().unwrap_or(default)
  623. }
  624. /// Returns the contained success value or computes it from a closure.
  625. ///
  626. /// # Examples
  627. ///
  628. /// Basic usage:
  629. ///
  630. /// ```
  631. /// # use sbi_spec::binary::{SbiRet, Error};
  632. /// fn invalid_use_zero(x: Error) -> usize { if x == Error::InvalidParam { 0 } else { 3 } }
  633. ///
  634. /// assert_eq!(SbiRet::success(2).unwrap_or_else(invalid_use_zero), 2);
  635. /// assert_eq!(SbiRet::invalid_param().unwrap_or_else(invalid_use_zero), 0);
  636. /// ```
  637. #[inline]
  638. pub fn unwrap_or_else<F: FnOnce(Error) -> usize>(self, op: F) -> usize {
  639. self.into_result().unwrap_or_else(op)
  640. }
  641. }
  642. /// Check if the implementation contains the provided `bit`.
  643. ///
  644. /// ## Parameters
  645. ///
  646. /// - `mask`: bitmask defining the range of bits.
  647. /// - `base`: the starting bit index. (default: `0`)
  648. /// - `ignore`: if `base` is equal to this value, ignore the `mask` parameter, and consider all `bit`s set.
  649. /// - `bit`: the bit index to check for membership in the `mask`.
  650. pub(crate) const fn has_bit(mask: usize, base: usize, ignore: usize, bit: usize) -> bool {
  651. if base == ignore {
  652. // ignore the `mask`, consider all `bit`s as set.
  653. true
  654. } else if bit < base {
  655. // invalid index, under minimum range.
  656. false
  657. } else if (bit - base) >= usize::BITS as usize {
  658. // invalid index, over max range.
  659. false
  660. } else {
  661. // index is in range, check if it is set in the mask.
  662. mask & (1 << (bit - base)) != 0
  663. }
  664. }
  665. /// Hart mask structure in SBI function calls.
  666. #[repr(C)]
  667. #[derive(Debug, Copy, Clone, Eq, PartialEq)]
  668. pub struct HartMask {
  669. hart_mask: usize,
  670. hart_mask_base: usize,
  671. }
  672. impl HartMask {
  673. /// Special value to ignore the `mask`, and consider all `bit`s as set.
  674. pub const IGNORE_MASK: usize = usize::MAX;
  675. /// Construct a [HartMask] from mask value and base hart id.
  676. #[inline]
  677. pub const fn from_mask_base(hart_mask: usize, hart_mask_base: usize) -> Self {
  678. Self {
  679. hart_mask,
  680. hart_mask_base,
  681. }
  682. }
  683. /// Gets the special value for ignoring the `mask` parameter.
  684. #[inline]
  685. pub const fn ignore_mask(&self) -> usize {
  686. Self::IGNORE_MASK
  687. }
  688. /// Returns `mask` and `base` parameters from the [HartMask].
  689. #[inline]
  690. pub const fn into_inner(self) -> (usize, usize) {
  691. (self.hart_mask, self.hart_mask_base)
  692. }
  693. /// Returns whether the [HartMask] contains the provided `hart_id`.
  694. #[inline]
  695. pub const fn has_bit(self, hart_id: usize) -> bool {
  696. has_bit(
  697. self.hart_mask,
  698. self.hart_mask_base,
  699. Self::IGNORE_MASK,
  700. hart_id,
  701. )
  702. }
  703. }
  704. /// Counter index mask structure in SBI function calls for the `PMU` extension §11.
  705. #[repr(C)]
  706. #[derive(Debug, Copy, Clone, Eq, PartialEq)]
  707. pub struct CounterMask {
  708. counter_idx_mask: usize,
  709. counter_idx_base: usize,
  710. }
  711. impl CounterMask {
  712. /// Special value to ignore the `mask`, and consider all `bit`s as set.
  713. pub const IGNORE_MASK: usize = usize::MAX;
  714. /// Construct a [CounterMask] from mask value and base counter index.
  715. #[inline]
  716. pub const fn from_mask_base(counter_idx_mask: usize, counter_idx_base: usize) -> Self {
  717. Self {
  718. counter_idx_mask,
  719. counter_idx_base,
  720. }
  721. }
  722. /// Gets the special value for ignoring the `mask` parameter.
  723. #[inline]
  724. pub const fn ignore_mask(&self) -> usize {
  725. Self::IGNORE_MASK
  726. }
  727. /// Returns `mask` and `base` parameters from the [CounterMask].
  728. #[inline]
  729. pub const fn into_inner(self) -> (usize, usize) {
  730. (self.counter_idx_mask, self.counter_idx_base)
  731. }
  732. /// Returns whether the [CounterMask] contains the provided `counter`.
  733. #[inline]
  734. pub const fn has_bit(self, counter: usize) -> bool {
  735. has_bit(
  736. self.counter_idx_mask,
  737. self.counter_idx_base,
  738. Self::IGNORE_MASK,
  739. counter,
  740. )
  741. }
  742. }
  743. /// Physical slice wrapper with type annotation.
  744. ///
  745. /// This struct wraps slices in RISC-V physical memory by low and high part of the
  746. /// physical base address as well as its length. It is usually used by SBI extensions
  747. /// as parameter types to pass base address and length parameters on physical memory
  748. /// other than a virtual one.
  749. ///
  750. /// Generic parameter `P` represents a hint of how this physical slice would be used.
  751. /// For example, `Physical<&[u8]>` represents an immutable reference to physical byte slice,
  752. /// while `Physical<&mut [u8]>` represents a mutable one.
  753. ///
  754. /// An SBI implementation should load or store memory using both `phys_addr_lo` and
  755. /// `phys_addr_hi` combined as base address. A supervisor program (kernels etc.)
  756. /// should provide continuous physical memory, wrapping its reference using this structure
  757. /// before passing into SBI runtime.
  758. #[derive(Clone, Copy)]
  759. pub struct Physical<P> {
  760. num_bytes: usize,
  761. phys_addr_lo: usize,
  762. phys_addr_hi: usize,
  763. _marker: PhantomData<P>,
  764. }
  765. impl<P> Physical<P> {
  766. /// Create a physical memory slice by length and physical address.
  767. #[inline]
  768. pub const fn new(num_bytes: usize, phys_addr_lo: usize, phys_addr_hi: usize) -> Self {
  769. Self {
  770. num_bytes,
  771. phys_addr_lo,
  772. phys_addr_hi,
  773. _marker: core::marker::PhantomData,
  774. }
  775. }
  776. /// Returns length of the physical memory slice.
  777. #[inline]
  778. pub const fn num_bytes(&self) -> usize {
  779. self.num_bytes
  780. }
  781. /// Returns low-part base address of physical memory slice.
  782. #[inline]
  783. pub const fn phys_addr_lo(&self) -> usize {
  784. self.phys_addr_lo
  785. }
  786. /// Returns high-part base address of physical memory slice.
  787. #[inline]
  788. pub const fn phys_addr_hi(&self) -> usize {
  789. self.phys_addr_hi
  790. }
  791. }
  792. /// Shared memory physical address raw pointer with type annotation.
  793. ///
  794. /// This is a structure wrapping a raw pointer to the value of the type `T` without
  795. /// a pointer metadata. `SharedPtr`'s are _thin_; they won't include metadata
  796. /// as RISC-V SBI does not provide an approach to pass them via SBI calls,
  797. /// thus the length of type `T` should be decided independently of raw
  798. /// pointer structure.
  799. ///
  800. /// `SharedPtr` can be used as a parameter to pass the shared memory physical pointer
  801. /// with a given base address in RISC-V SBI calls. For example, a `SharedPtr<[u8; 64]>`
  802. /// would represent a fixed-size 64 byte array on a RISC-V SBI function argument
  803. /// type.
  804. ///
  805. /// This structure cannot be dereferenced directly with physical addresses,
  806. /// because on RISC-V systems the physical address space could be larger than the
  807. /// virtual ones. Hence, this structure describes the physical memory range by
  808. /// two `usize` values: the upper `phys_addr_hi` and lower `phys_addr_lo`.
  809. ///
  810. /// RISC-V SBI extensions may declare special pointer values for shared memory
  811. /// raw pointers. For example, SBI STA declares that steal-time information
  812. /// should stop from reporting when the SBI call is invoked using all-ones
  813. /// bitwise shared pointer, i.e. `phys_addr_hi` and `phys_addr_lo` both equals
  814. /// `usize::MAX`. `SharedPtr` can be constructed using such special values
  815. /// by providing them to the `SharedPtr::new` function.
  816. ///
  817. /// # Requirements
  818. ///
  819. /// If an SBI function needs to pass a shared memory physical address range to
  820. /// the SBI implementation (or higher privilege mode), then this physical memory
  821. /// address range MUST satisfy the following requirements:
  822. ///
  823. /// * The SBI implementation MUST check that the supervisor-mode software is
  824. /// allowed to access the specified physical memory range with the access
  825. /// type requested (read and/or write).
  826. /// * The SBI implementation MUST access the specified physical memory range
  827. /// using the PMA attributes.
  828. /// * The data in the shared memory MUST follow little-endian byte ordering.
  829. ///
  830. /// *NOTE:* If the supervisor-mode software accesses the same physical memory
  831. /// range using a memory type different from the PMA, then a loss of coherence
  832. /// or unexpected memory ordering may occur. The invoking software should
  833. /// follow the rules and sequences defined in the RISC-V Svpbmt specification
  834. /// to prevent the loss of coherence and memory ordering.
  835. ///
  836. /// It is recommended that a memory physical address passed to an SBI function
  837. /// should use at least two `usize` parameters to support platforms
  838. /// which have memory physical addresses wider than `XLEN` bits.
  839. // FIXME: should constrain with `T: Thin` once ptr_metadata feature is stabled;
  840. // RISC-V SBI does not provide an approach to pass pointer metadata by SBI calls.
  841. pub struct SharedPtr<T> {
  842. phys_addr_lo: usize,
  843. phys_addr_hi: usize,
  844. _marker: PhantomData<*mut T>,
  845. }
  846. // FIXME: we should consider strict provenance rules for this pointer-like structure
  847. // once feature strict_provenance is stabled.
  848. impl<T> SharedPtr<T> {
  849. /// Create a shared physical memory pointer by physical address.
  850. #[inline]
  851. pub const fn new(phys_addr_lo: usize, phys_addr_hi: usize) -> Self {
  852. Self {
  853. phys_addr_lo,
  854. phys_addr_hi,
  855. _marker: PhantomData,
  856. }
  857. }
  858. /// Returns low-part physical address of the shared physical memory pointer.
  859. #[inline]
  860. pub const fn phys_addr_lo(self) -> usize {
  861. self.phys_addr_lo
  862. }
  863. /// Returns high-part physical address of the shared physical memory pointer.
  864. #[inline]
  865. pub const fn phys_addr_hi(self) -> usize {
  866. self.phys_addr_hi
  867. }
  868. }
  869. impl<T> Clone for SharedPtr<T> {
  870. #[inline(always)]
  871. fn clone(&self) -> Self {
  872. *self
  873. }
  874. }
  875. impl<T> Copy for SharedPtr<T> {}
  876. #[cfg(test)]
  877. mod tests {
  878. use super::*;
  879. #[test]
  880. fn rustsbi_hart_mask() {
  881. let mask = HartMask::from_mask_base(0b1, 400);
  882. assert!(!mask.has_bit(0));
  883. assert!(mask.has_bit(400));
  884. assert!(!mask.has_bit(401));
  885. let mask = HartMask::from_mask_base(0b110, 500);
  886. assert!(!mask.has_bit(0));
  887. assert!(!mask.has_bit(500));
  888. assert!(mask.has_bit(501));
  889. assert!(mask.has_bit(502));
  890. assert!(!mask.has_bit(500 + (usize::BITS as usize)));
  891. let max_bit = 1 << (usize::BITS - 1);
  892. let mask = HartMask::from_mask_base(max_bit, 600);
  893. assert!(mask.has_bit(600 + (usize::BITS as usize) - 1));
  894. assert!(!mask.has_bit(600 + (usize::BITS as usize)));
  895. let mask = HartMask::from_mask_base(0b11, usize::MAX - 1);
  896. assert!(!mask.has_bit(usize::MAX - 2));
  897. assert!(mask.has_bit(usize::MAX - 1));
  898. assert!(mask.has_bit(usize::MAX));
  899. assert!(!mask.has_bit(0));
  900. // hart_mask_base == usize::MAX is special, it means hart_mask should be ignored
  901. // and this hart mask contains all harts available
  902. let mask = HartMask::from_mask_base(0, usize::MAX);
  903. for i in 0..5 {
  904. assert!(mask.has_bit(i));
  905. }
  906. assert!(mask.has_bit(usize::MAX));
  907. }
  908. #[test]
  909. fn rustsbi_counter_index_mask() {
  910. let mask = CounterMask::from_mask_base(0b1, 400);
  911. assert!(!mask.has_bit(0));
  912. assert!(mask.has_bit(400));
  913. assert!(!mask.has_bit(401));
  914. let mask = CounterMask::from_mask_base(0b110, 500);
  915. assert!(!mask.has_bit(0));
  916. assert!(!mask.has_bit(500));
  917. assert!(mask.has_bit(501));
  918. assert!(mask.has_bit(502));
  919. assert!(!mask.has_bit(500 + (usize::BITS as usize)));
  920. let max_bit = 1 << (usize::BITS - 1);
  921. let mask = CounterMask::from_mask_base(max_bit, 600);
  922. assert!(mask.has_bit(600 + (usize::BITS as usize) - 1));
  923. assert!(!mask.has_bit(600 + (usize::BITS as usize)));
  924. let mask = CounterMask::from_mask_base(0b11, usize::MAX - 1);
  925. assert!(!mask.has_bit(usize::MAX - 2));
  926. assert!(mask.has_bit(usize::MAX - 1));
  927. assert!(mask.has_bit(usize::MAX));
  928. assert!(!mask.has_bit(0));
  929. let mask = CounterMask::from_mask_base(0, usize::MAX);
  930. let null_mask = CounterMask::from_mask_base(0, 0);
  931. (0..=usize::BITS as usize).for_each(|i| {
  932. assert!(mask.has_bit(i));
  933. assert!(!null_mask.has_bit(i));
  934. });
  935. assert!(mask.has_bit(usize::MAX));
  936. }
  937. }