Răsfoiți Sursa

Merge branch 'main' of github.com:rustsbi/rustsbi into fix-typos

chenzongyao200127 5 zile în urmă
părinte
comite
3b1a18bb2e

+ 1 - 0
library/rustsbi/CHANGELOG.md

@@ -22,6 +22,7 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
 - susp: amend documentation on `system_suspend` function.
 - lib: replace map+unwrap_or with Option::map_or in impls
 - doc: lib: alter link to Prototyper firmware in documentation.
+- doc: lib: clarify error codes in documents of SBI IPI and RFENCE extensions
 
 ### Removed
 

+ 7 - 1
library/rustsbi/src/ipi.rs

@@ -8,7 +8,13 @@ pub trait Ipi {
     ///
     /// # Return value
     ///
-    /// Should return `SbiRet::success()` if IPI was sent to all the targeted harts successfully.
+    /// The possible return error codes returned in `SbiRet.error` are shown in the table below:
+    ///
+    /// | Return code               | Description
+    /// |:--------------------------|:----------------------------------------------
+    /// | `SbiRet::success()`       | IPI was sent to all the targeted harts successfully.
+    /// | `SbiRet::invalid_param()` | At least one hartid constructed from `hart_mask`, is not valid, i.e. either the hartid is not enabled by the platform or is not available to the supervisor.
+    /// | `SbiRet::failed()`        | The request failed for unspecified or unknown other reasons.
     fn send_ipi(&self, hart_mask: HartMask) -> SbiRet;
     /// Function internal to macros. Do not use.
     #[doc(hidden)]

+ 19 - 1
library/rustsbi/src/rfence.rs

@@ -10,7 +10,13 @@ pub trait Rfence {
     ///
     /// # Return value
     ///
-    /// Returns `SbiRet::success()` when a remote fence was sent to all the targeted harts successfully.
+    /// The possible return error codes returned in `SbiRet.error` are shown in the table below:
+    ///
+    /// | Return code               | Description
+    /// |:--------------------------|:----------------------------------------------
+    /// | `SbiRet::success()`       | A remote fence was sent to all the targeted harts successfully.
+    /// | `SbiRet::invalid_param()` | At least one hartid constructed from `hart_mask`, is not valid, i.e. either the hartid is not enabled by the platform or is not available to the supervisor.
+    /// | `SbiRet::failed()`        | The request failed for unspecified or unknown other reasons.
     fn remote_fence_i(&self, hart_mask: HartMask) -> SbiRet;
     /// Instructs the remote harts to execute one or more `SFENCE.VMA` instructions,
     /// covering the range of virtual addresses between `start_addr` and `size`.
@@ -23,6 +29,8 @@ pub trait Rfence {
     /// |:----------------------------|:----------------------------------------------
     /// | `SbiRet::success()`         | A remote fence was sent to all the targeted harts successfully.
     /// | `SbiRet::invalid_address()` | `start_addr` or `size` is not valid.
+    /// | `SbiRet::invalid_param()`   | At least one hartid constructed from `hart_mask`, is not valid, i.e. either the hartid is not enabled by the platform or is not available to the supervisor.
+    /// | `SbiRet::failed()`          | The request failed for unspecified or unknown other reasons.
     fn remote_sfence_vma(&self, hart_mask: HartMask, start_addr: usize, size: usize) -> SbiRet;
     /// Instruct the remote harts to execute one or more `SFENCE.VMA` instructions,
     /// covering the range of virtual addresses between `start_addr` and `size`.
@@ -36,6 +44,8 @@ pub trait Rfence {
     /// |:----------------------------|:----------------------------------------------
     /// | `SbiRet::success()`         | A remote fence was sent to all the targeted harts successfully.
     /// | `SbiRet::invalid_address()` | `start_addr` or `size` is not valid.
+    /// | `SbiRet::invalid_param()`   | Either `asid`, or at least one hartid constructed from `hart_mask`, is not valid, i.e. either the hartid is not enabled by the platform or is not available to the supervisor.
+    /// | `SbiRet::failed()`          | The request failed for unspecified or unknown other reasons.
     fn remote_sfence_vma_asid(
         &self,
         hart_mask: HartMask,
@@ -58,6 +68,8 @@ pub trait Rfence {
     /// | `SbiRet::success()`         | A remote fence was sent to all the targeted harts successfully.
     /// | `SbiRet::not_supported()`   | This function is not supported as it is not implemented or one of the target harts do not support the RISC-V hypervisor extension.
     /// | `SbiRet::invalid_address()` | `start_addr` or `size` is not valid.
+    /// | `SbiRet::invalid_param()`   | Either `vmid`, or at least one hartid constructed from `hart_mask`, is not valid, i.e. either the hartid is not enabled by the platform or is not available to the supervisor.
+    /// | `SbiRet::failed()`          | The request failed for unspecified or unknown other reasons.
     #[inline]
     fn remote_hfence_gvma_vmid(
         &self,
@@ -84,6 +96,8 @@ pub trait Rfence {
     /// | `SbiRet::success()`         | A remote fence was sent to all the targeted harts successfully.
     /// | `SbiRet::not_supported()`   | This function is not supported as it is not implemented or one of the target harts do not support the RISC-V hypervisor extension.
     /// | `SbiRet::invalid_address()` | `start_addr` or `size` is not valid.
+    /// | `SbiRet::invalid_param()`   | At least one hartid constructed from `hart_mask`, is not valid, i.e. either the hartid is not enabled by the platform or is not available to the supervisor.
+    /// | `SbiRet::failed()`          | The request failed for unspecified or unknown other reasons.
     #[inline]
     fn remote_hfence_gvma(&self, hart_mask: HartMask, start_addr: usize, size: usize) -> SbiRet {
         let _ = (hart_mask, start_addr, size);
@@ -105,6 +119,8 @@ pub trait Rfence {
     /// | `SbiRet::success()`         | A remote fence was sent to all the targeted harts successfully.
     /// | `SbiRet::not_supported()`   | This function is not supported as it is not implemented or one of the target harts do not support the RISC-V hypervisor extension.
     /// | `SbiRet::invalid_address()` | `start_addr` or `size` is not valid.
+    /// | `SbiRet::invalid_param()`   | Either `asid`, or at least one hartid constructed from `hart_mask`, is not valid, i.e. either the hartid is not enabled by the platform or is not available to the supervisor.
+    /// | `SbiRet::failed()`          | The request failed for unspecified or unknown other reasons.
     #[inline]
     fn remote_hfence_vvma_asid(
         &self,
@@ -131,6 +147,8 @@ pub trait Rfence {
     /// | `SbiRet::success()`         | A remote fence was sent to all the targeted harts successfully.
     /// | `SbiRet::not_supported()`   | This function is not supported as it is not implemented or one of the target harts do not support the RISC-V hypervisor extension.
     /// | `SbiRet::invalid_address()` | `start_addr` or `size` is not valid.
+    /// | `SbiRet::invalid_param()`   | At least one hartid constructed from `hart_mask`, is not valid, i.e. either the hartid is not enabled by the platform or is not available to the supervisor.
+    /// | `SbiRet::failed()`          | The request failed for unspecified or unknown other reasons.
     #[inline]
     fn remote_hfence_vvma(&self, hart_mask: HartMask, start_addr: usize, size: usize) -> SbiRet {
         let _ = (hart_mask, start_addr, size);

+ 2 - 0
library/sbi-rt/CHANGELOG.md

@@ -17,6 +17,7 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
 - rt: add DBTR extension support to SBI implementation.
 - dbtr: use `TriggerMask` structure in sbi-rt DBTR functions
 - rt: add structure for SSE, FWFT, DBTR, and MPXY extensions
+- rt: add SSE extension support to SBI implementation.
 
 ### Modified
 
@@ -28,6 +29,7 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
 
 - base: fix wrong `extension_id` of `Suspend` structure
 - binary: allow 8 arguments on internal function `sbi_call_6`.
+- lib: clarify error codes in documents of SBI IPI and RFENCE extensions.
 - Fix typos.
 
 ## [0.0.3] - 2024-02-08

+ 3 - 0
library/sbi-rt/src/lib.rs

@@ -40,6 +40,8 @@ mod cppc;
 mod nacl;
 // §16
 mod sta;
+// §17
+mod sse;
 // §18
 mod fwft;
 // §19
@@ -64,6 +66,7 @@ pub use pmu::*;
 pub use rfnc::*;
 pub use spi::*;
 pub use srst::*;
+pub use sse::*;
 pub use sta::*;
 pub use susp::*;
 pub use time::*;

+ 19 - 1
library/sbi-rt/src/rfnc.rs

@@ -14,7 +14,13 @@ use sbi_spec::{
 ///
 /// # Return value
 ///
-/// Returns `SbiRet::success()` when a remote fence was sent to all the targeted harts successfully.
+/// The possible return error codes returned in `SbiRet.error` are shown in the table below:
+///
+/// | Return code               | Description
+/// |:--------------------------|:----------------------------------------------
+/// | `SbiRet::success()`       | A remote fence was sent to all the targeted harts successfully.
+/// | `SbiRet::invalid_param()` | At least one hartid constructed from `hart_mask`, is not valid, i.e. either the hartid is not enabled by the platform or is not available to the supervisor.
+/// | `SbiRet::failed()`        | The request failed for unspecified or unknown other reasons.
 ///
 /// This function is defined in RISC-V SBI Specification chapter 8.1.
 #[inline]
@@ -37,6 +43,8 @@ pub fn remote_fence_i(hart_mask: HartMask) -> SbiRet {
 /// |:----------------------------|:----------------------------------------------
 /// | `SbiRet::success()`         | A remote fence was sent to all the targeted harts successfully.
 /// | `SbiRet::invalid_address()` | `start_addr` or `size` is not valid.
+/// | `SbiRet::invalid_param()`   | At least one hartid constructed from `hart_mask`, is not valid, i.e. either the hartid is not enabled by the platform or is not available to the supervisor.
+/// | `SbiRet::failed()`          | The request failed for unspecified or unknown other reasons.
 ///
 /// This function is defined in RISC-V SBI Specification chapter 8.2.
 #[inline]
@@ -67,6 +75,8 @@ pub fn remote_sfence_vma(hart_mask: HartMask, start_addr: usize, size: usize) ->
 /// |:----------------------------|:----------------------------------------------
 /// | `SbiRet::success()`         | A remote fence was sent to all the targeted harts successfully.
 /// | `SbiRet::invalid_address()` | `start_addr` or `size` is not valid.
+/// | `SbiRet::invalid_param()`   | Either `asid`, or at least one hartid constructed from `hart_mask`, is not valid, i.e. either the hartid is not enabled by the platform or is not available to the supervisor.
+/// | `SbiRet::failed()`          | The request failed for unspecified or unknown other reasons.
 ///
 /// This function is defined in RISC-V SBI Specification chapter 8.3.
 #[inline]
@@ -106,6 +116,8 @@ pub fn remote_sfence_vma_asid(
 /// | `SbiRet::success()`         | A remote fence was sent to all the targeted harts successfully.
 /// | `SbiRet::not_supported()`   | This function is not supported as it is not implemented or one of the target hart doesn’t support hypervisor extension.
 /// | `SbiRet::invalid_address()` | `start_addr` or `size` is not valid.
+/// | `SbiRet::invalid_param()`   | Either `vmid`, or at least one hartid constructed from `hart_mask`, is not valid, i.e. either the hartid is not enabled by the platform or is not available to the supervisor.
+/// | `SbiRet::failed()`          | The request failed for unspecified or unknown other reasons.
 ///
 /// This function is defined in RISC-V SBI Specification chapter 8.4.
 #[inline]
@@ -145,6 +157,8 @@ pub fn remote_hfence_gvma_vmid(
 /// | `SbiRet::success()`         | A remote fence was sent to all the targeted harts successfully.
 /// | `SbiRet::not_supported()`   | This function is not supported as it is not implemented or one of the target hart does not support hypervisor extension.
 /// | `SbiRet::invalid_address()` | `start_addr` or `size` is not valid.
+/// | `SbiRet::invalid_param()`   | At least one hartid constructed from `hart_mask`, is not valid, i.e. either the hartid is not enabled by the platform or is not available to the supervisor.
+/// | `SbiRet::failed()`          | The request failed for unspecified or unknown other reasons.
 ///
 /// This function is defined in RISC-V SBI Specification chapter 8.5.
 #[inline]
@@ -179,6 +193,8 @@ pub fn remote_hfence_gvma(hart_mask: HartMask, start_addr: usize, size: usize) -
 /// | `SbiRet::success()`         | A remote fence was sent to all the targeted harts successfully.
 /// | `SbiRet::not_supported()`   | This function is not supported as it is not implemented or one of the target hart does not support hypervisor extension.
 /// | `SbiRet::invalid_address()` | `start_addr` or `size` is not valid.
+/// | `SbiRet::invalid_param()`   | Either `asid`, or at least one hartid constructed from `hart_mask`, is not valid, i.e. either the hartid is not enabled by the platform or is not available to the supervisor.
+/// | `SbiRet::failed()`          | The request failed for unspecified or unknown other reasons.
 ///
 /// This function is defined in RISC-V SBI Specification chapter 8.6.
 #[inline]
@@ -218,6 +234,8 @@ pub fn remote_hfence_vvma_asid(
 /// | `SbiRet::success()`         | A remote fence was sent to all the targeted harts successfully.
 /// | `SbiRet::not_supported()`   | This function is not supported as it is not implemented or one of the target hart doesn’t support hypervisor extension.
 /// | `SbiRet::invalid_address()` | `start_addr` or `size` is not valid.
+/// | `SbiRet::invalid_param()`   | At least one hartid constructed from `hart_mask`, is not valid, i.e. either the hartid is not enabled by the platform or is not available to the supervisor.
+/// | `SbiRet::failed()`          | The request failed for unspecified or unknown other reasons.
 ///
 /// This function is defined in RISC-V SBI Specification chapter 8.7.
 #[inline]

+ 7 - 1
library/sbi-rt/src/spi.rs

@@ -13,7 +13,13 @@ use sbi_spec::{
 ///
 /// # Return value
 ///
-/// Should return `SbiRet::success()` if IPI was sent to all the targeted harts successfully.
+/// The possible return error codes returned in `SbiRet.error` are shown in the table below:
+///
+/// | Return code               | Description
+/// |:--------------------------|:----------------------------------------------
+/// | `SbiRet::success()`       | IPI was sent to all the targeted harts successfully.
+/// | `SbiRet::invalid_param()` | At least one hartid constructed from `hart_mask`, is not valid, i.e. either the hartid is not enabled by the platform or is not available to the supervisor.
+/// | `SbiRet::failed()`        | The request failed for unspecified or unknown other reasons.
 ///
 /// This function is defined in RISC-V SBI Specification chapter 7.1.
 #[inline]

+ 283 - 0
library/sbi-rt/src/sse.rs

@@ -0,0 +1,283 @@
+//! Chapter 17. Supervisor Software Events Extension (EID #0x535345 "SSE").
+
+use crate::binary::{sbi_call_0, sbi_call_1, sbi_call_2, sbi_call_3, sbi_call_5};
+use sbi_spec::{
+    binary::{SbiRet, SharedPtr},
+    sse::*,
+};
+
+/// Read a range of event attribute values from a software event.
+///
+/// The `event_id` parameter specifies the software event ID whereas `base_attr_id`
+/// and `attr_count` parameters specifies the range of event attribute IDs.
+///
+/// The event attribute values are written to a output shared memory which is specified
+/// by the `output` parameter where:
+///
+/// - The `output` parameter MUST be `XLEN / 8` bytes aligned
+/// - The size of output shared memory is assumed to be `(XLEN / 8) * attr_count`
+/// - The value of event attribute with ID `base_attr_id + i` should be read from offset `(XLEN / 8) * (base_attr_id + i)`
+///
+/// The possible error codes returned in sbiret.error are shown below.
+///
+/// # Return value
+///
+/// | Error code                  | Description
+/// |:----------------------------|:---------------------------------
+/// | `SbiRet::success()`         | Event attribute values read successfully.
+/// | `SbiRet::not_supported()`   | `event_id` is not reserved and valid, but the platform does not support it due to one or more missing dependencies (Hardware or SBI implementation).
+/// | `SbiRet::invalid_param()`   | `event_id` is invalid or `attr_count` is zero.
+/// | `SbiRet::bad_range()`       | One of the event attribute IDs in the range specified by `base_attr_id` and `attr_count` is reserved.
+/// | `SbiRet::invalid_address()` | The shared memory pointed to by the `output` parameter does not satisfy the requirements.
+/// | `SbiRet::failed()`          | The read failed for unspecified or unknown other reasons.
+#[doc(alias = "sbi_sse_read_attrs")]
+#[inline]
+pub fn sse_read_attrs(
+    event_id: u32,
+    base_attr_id: u32,
+    attr_count: u32,
+    output: SharedPtr<u8>,
+) -> SbiRet {
+    sbi_call_5(
+        EID_SSE,
+        READ_ATTRS,
+        event_id as _,
+        base_attr_id as _,
+        attr_count as _,
+        output.phys_addr_lo(),
+        output.phys_addr_hi(),
+    )
+}
+
+/// Write a range of event attribute values to a software event.
+///
+/// The event_id parameter specifies the software event ID whereas `base_attr_id` and
+/// `attr_count` parameters specifies the range of event attribute IDs.
+///
+/// The event attribute values are read from a input shared memory which is specified
+/// by the `input` parameter where:
+///
+/// - The `input` parameter MUST be `XLEN / 8` bytes aligned
+/// - The size of input shared memory is assumed to be `(XLEN / 8) * attr_count`
+/// - The value of event attribute with ID `base_attr_id + i` should be read from offset `(XLEN / 8) * (base_attr_id + i)`
+///
+/// For local events, the event attributes are updated only for the calling hart.
+/// For global events, the event attributes are updated for all the harts.
+/// The possible error codes returned in sbiret.error are shown below.
+///
+/// # Return value
+///
+/// | Error code                  | Description
+/// |:----------------------------|:---------------------------------
+/// | `SbiRet::success()`         | Event attribute values written successfully.
+/// | `SbiRet::not_supported()`   | `event_id` is not reserved and valid, but the platform does not support it due to one or more missing dependencies (Hardware or SBI implementation).
+/// | `SbiRet::invalid_param()`   | `event_id` is invalid or `attr_count` is zero.
+/// | `SbiRet::bad_range()`       | One of the event attribute IDs in the range specified by `base_attr_id` and `attr_count` is reserved or is read-only.
+/// | `SbiRet::invalid_address()` | The shared memory pointed to by the `input` parameter does not satisfy the requirements.
+/// | `SbiRet::failed()`          | The write failed for unspecified or unknown other reasons.
+#[doc(alias = "sbi_sse_write_attrs")]
+#[inline]
+pub fn sse_write_attrs(
+    event_id: u32,
+    base_attr_id: u32,
+    attr_count: u32,
+    input: SharedPtr<u8>,
+) -> SbiRet {
+    sbi_call_5(
+        EID_SSE,
+        WRITE_ATTRS,
+        event_id as _,
+        base_attr_id as _,
+        attr_count as _,
+        input.phys_addr_lo(),
+        input.phys_addr_hi(),
+    )
+}
+
+/// Register an event handler for the software event.
+///
+/// The `event_id` parameter specifies the event ID for which an event handler is being registered.
+/// The `handler_entry_pc` parameter MUST be 2-bytes aligned and specifies the `ENTRY_PC` event
+/// attribute of the software event whereas the `handler_entry_arg` parameter specifies the
+/// `ENTRY_ARG` event attribute of the software event.
+///
+/// For local events, the event is registered only for the calling hart.
+/// For global events, the event is registered for all the harts.
+///
+/// The event MUST be in `UNUSED` state otherwise this function will fail.
+///
+/// Upon success, the event state moves from `UNUSED` to `REGISTERED`. In case of an error, possible error codes are listed below.
+///
+/// # Return value
+///
+/// | Error code                  | Description
+/// |:----------------------------|:---------------------------------
+/// | `SbiRet::success()`         | Event handler is registered successfully.
+/// | `SbiRet::not_supported()`   | `event_id` is not reserved and valid, but the platform does not support it due to one or more missing dependencies (Hardware or SBI implementation).
+/// | `SbiRet::invalid_state()`   | `event_id` is valid but the event is not in `UNUSED` state.
+/// | `SbiRet::invalid_param()`   | `event_id` is invalid or `handler_entry_pc` is not 2-bytes aligned.    
+#[doc(alias = "sbi_sse_register")]
+#[inline]
+pub fn sse_register(event_id: u32, handler_entry_pc: usize, handler_entry_arg: usize) -> SbiRet {
+    sbi_call_3(
+        EID_SSE,
+        REGISTER,
+        event_id as _,
+        handler_entry_pc,
+        handler_entry_arg,
+    )
+}
+
+/// Unregister the event handler for given `event_id`.
+///
+/// For local events, the event is unregistered only for the calling hart.
+/// For global events, the event is unregistered for all the harts.
+///
+/// The event MUST be in `REGISTERED` state otherwise this function will fail.
+///
+/// Upon success, the event state moves from `REGISTERED` to `UNUSED`. In case of an error, possible error codes are listed below.
+///
+/// # Return value
+///
+/// | Error code                  | Description
+/// |:----------------------------|:---------------------------------
+/// | `SbiRet::success()`         | Event handler is unregistered successfully.
+/// | `SbiRet::not_supported()`   | `event_id` is not reserved and valid, but the platform does not support it due to one or more missing dependencies (Hardware or SBI implementation).
+/// | `SbiRet::invalid_state()`   | `event_id` is valid but the event is not in `REGISTERED` state.
+/// | `SbiRet::invalid_param()`   | `event_id` is invalid.
+#[doc(alias = "sbi_sse_unregister")]
+#[inline]
+pub fn sse_unregister(event_id: u32) -> SbiRet {
+    sbi_call_1(EID_SSE, UNREGISTER, event_id as _)
+}
+
+/// Enable the software event specified by the `event_id` parameter.
+///
+/// For local events, the event is enabled only for the calling hart.
+/// For global events, the event is enabled for all the harts.
+///
+/// The event MUST be in `REGISTERED` state otherwise this function will fail.
+///
+/// Upon success, the event state moves from `REGISTERED` to `ENABLED`. In case of an error, possible error codes are listed below.
+///
+/// # Return value
+///
+/// | Error code                  | Description
+/// |:----------------------------|:---------------------------------
+/// | `SbiRet::success()`         | Event is successfully enabled.
+/// | `SbiRet::not_supported()`   | `event_id` is not reserved and valid, but the platform does not support it due to one or more missing dependencies (Hardware or SBI implementation).
+/// | `SbiRet::invalid_param()`   | `event_id` is invalid.
+/// | `SbiRet::invalid_state()`   | `event_id` is valid but the event is not in `REGISTERED` state.
+#[doc(alias = "sbi_sse_enable")]
+#[inline]
+pub fn sse_enable(event_id: u32) -> SbiRet {
+    sbi_call_1(EID_SSE, ENABLE, event_id as _)
+}
+
+/// Disable the software event specified by the `event_id` parameter.
+///
+/// For local events, the event is disabled only for the calling hart.
+/// For global events, the event is disabled for all the harts.
+///
+/// The event MUST be in `ENABLED` state otherwise this function will fail.
+///
+/// Upon success, the event state moves from `ENABLED` to `REGISTERED`. In case of an error, possible error codes are listed below.
+///
+/// # Return value
+///
+/// | Error code                  | Description
+/// |:----------------------------|:---------------------------------
+/// | `SbiRet::success()`         | Event is successfully disabled.
+/// | `SbiRet::not_supported()`   | `event_id` is not reserved and valid, but the platform does not support it due to one or more missing dependencies (Hardware or SBI implementation).
+/// | `SbiRet::invalid_param()`   | `event_id` is invalid.
+/// | `SbiRet::invalid_state()`   | `event_id` is valid but the event is not in `ENABLED` state.
+#[doc(alias = "sbi_sse_disable")]
+#[inline]
+pub fn sse_disable(event_id: u32) -> SbiRet {
+    sbi_call_1(EID_SSE, DISABLE, event_id as _)
+}
+
+/// Complete the supervisor event handling for the highest priority event in `RUNNING` state on the calling hart.
+///
+/// If there were no events in `RUNNING` state on the calling hart then this function does nothing and returns `SBI_SUCCESS`
+/// otherwise it moves the highest priority event in `RUNNING` state to:
+///
+/// - `REGISTERED` if the event is configured as one-shot
+/// - `ENABLED` state otherwise
+///
+/// It then resumes the interrupted supervisor state.
+#[doc(alias = "sbi_sse_complete")]
+#[inline]
+pub fn sse_complete() -> SbiRet {
+    sbi_call_0(EID_SSE, COMPLETE)
+}
+
+/// The supervisor software can inject a software event with this function.
+///
+/// The `event_id` parameter refers to the ID of the event to be injected.
+///
+/// For local events, the `hart_id` parameter refers to the hart on which the event is to be injected.
+/// For global events, the `hart_id` parameter is ignored.
+///
+/// An event can only be injected if it is allowed by the event attribute.
+///
+/// If an event is injected from within an SSE event handler, if it is ready to be run,
+/// it will be handled according to the priority rules
+///
+/// - If it has a higher priority than the one currently running, then it will be handled immediately, effectively preempting the currently running one.
+/// - If it has a lower priority, it will be run after the one that is currently running completes.
+///
+/// In case of an error, possible error codes are listed below.
+///
+/// # Return value
+///
+/// | Error code                  | Description
+/// |:----------------------------|:---------------------------------
+/// | `SbiRet::success()`         | Event is successfully injected.
+/// | `SbiRet::not_supported()`   | `event_id` is not reserved and valid, but the platform does not support it due to one or more missing dependencies (Hardware or SBI implementation).
+/// | `SbiRet::invalid_param()`   | `event_id` is invalid or `hart_id` is invalid.
+/// | `SbiRet::failed()`          | The injection failed for unspecified or unknown other reasons.
+#[doc(alias = "sbi_sse_inject")]
+#[inline]
+pub fn sse_inject(event_id: u32, hart_id: usize) -> SbiRet {
+    sbi_call_2(EID_SSE, INJECT, event_id as _, hart_id)
+}
+
+/// Start receiving (or unmask) software events on the calling hart.
+/// In other words, the calling hart is ready to receive software events from the SBI implementation.
+///
+/// The software events are masked initially on all harts so the supervisor software must
+/// explicitly unmask software events on relevant harts at boot-time.
+///
+/// In case of an error, possible error codes are listed below.
+///
+/// # Return value
+///
+/// | Error code                  | Description
+/// |:----------------------------|:---------------------------------
+/// | `SbiRet::success()`         | Software events unmasked successfully on the calling hart.
+/// | `SbiRet::already_started()` | Software events were already unmasked on the calling hart.
+/// | `SbiRet::failed()`          | The request failed for unspecified or unknown other reasons.
+#[doc(alias = "sbi_sse_hart_unmask")]
+#[inline]
+pub fn sse_hart_unmask() -> SbiRet {
+    sbi_call_0(EID_SSE, HART_UNMASK)
+}
+
+/// Stop receiving (or mask) software events on the calling hart.
+/// In other words, the calling hart will no longer be ready to receive software events from the SBI implementation.
+///
+/// In case of an error, possible error codes are listed below.
+///
+/// # Return value
+///
+/// | Error code                  | Description
+/// |:----------------------------|:---------------------------------
+/// | `SbiRet::success()`         | Software events masked successfully on the calling hart.
+/// | `SbiRet::already_stopped()` | Software events were already masked on the calling hart.
+/// | `SbiRet::failed()`          | The request failed for unspecified or unknown other reasons.
+#[doc(alias = "sbi_sse_hart_mask")]
+#[inline]
+pub fn sse_hart_mask() -> SbiRet {
+    sbi_call_0(EID_SSE, HART_MASK)
+}

+ 2 - 0
library/sbi-spec/CHANGELOG.md

@@ -23,6 +23,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
 - examples: add an example on non-usize `HartMask` structure
 - examples: add an example for custom SBI error code
 - binary: add `TriggerMask` structure, it would be used in SBI DBTR extension
+- binary: add `SbiRet::denied_locked()` error code
 
 ### Modified
 
@@ -32,6 +33,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
 - base: implement `SbiRegister` for `i32`, `i64`, `i128` and `isize` primitive types
 - base: make HartMask and CounterMask generic over SBI registers
 - Add C language naming alias tags to all constants in the sbi-spec package
+- binary: refactor code to split binary structures into modules
 
 ### Fixed
 

+ 20 - 1935
library/sbi-spec/src/binary.rs

@@ -1,1937 +1,22 @@
 //! Chapter 3. Binary Encoding.
 
-use core::marker::PhantomData;
-
-/// SBI functions return type.
-///
-/// > SBI functions must return a pair of values in a0 and a1,
-/// > with a0 returning an error code.
-/// > This is analogous to returning the C structure `SbiRet`.
-///
-/// Note: if this structure is used in function return on conventional
-/// Rust code, it would not require pinning memory representation as
-/// extern C. The `repr(C)` is set in case that some users want to use
-/// this structure in FFI code.
-#[derive(Clone, Copy, PartialEq, Eq)]
-#[repr(C)]
-pub struct SbiRet<T = usize> {
-    /// Error number.
-    pub error: T,
-    /// Result value.
-    pub value: T,
-}
-
-/// SBI success state return value.
-#[doc(alias = "SBI_SUCCESS")]
-pub const RET_SUCCESS: usize = <usize as SbiRegister>::RET_SUCCESS;
-/// Error for SBI call failed for unknown reasons.
-#[doc(alias = "SBI_ERR_FAILED")]
-pub const RET_ERR_FAILED: usize = <usize as SbiRegister>::RET_ERR_FAILED;
-/// Error for target operation not supported.
-#[doc(alias = "SBI_ERR_NOT_SUPPORTED")]
-pub const RET_ERR_NOT_SUPPORTED: usize = <usize as SbiRegister>::RET_ERR_NOT_SUPPORTED;
-/// Error for invalid parameter.
-#[doc(alias = "SBI_ERR_INVALID_PARAM")]
-pub const RET_ERR_INVALID_PARAM: usize = <usize as SbiRegister>::RET_ERR_INVALID_PARAM;
-/// Error for denied.
-#[doc(alias = "SBI_ERR_DENIED")]
-pub const RET_ERR_DENIED: usize = <usize as SbiRegister>::RET_ERR_DENIED;
-/// Error for invalid address.
-#[doc(alias = "SBI_ERR_INVALID_ADDRESS")]
-pub const RET_ERR_INVALID_ADDRESS: usize = <usize as SbiRegister>::RET_ERR_INVALID_ADDRESS;
-/// Error for resource already available.
-#[doc(alias = "SBI_ERR_ALREADY_AVAILABLE")]
-pub const RET_ERR_ALREADY_AVAILABLE: usize = <usize as SbiRegister>::RET_ERR_ALREADY_AVAILABLE;
-/// Error for resource already started.
-#[doc(alias = "SBI_ERR_ALREADY_STARTED")]
-pub const RET_ERR_ALREADY_STARTED: usize = <usize as SbiRegister>::RET_ERR_ALREADY_STARTED;
-/// Error for resource already stopped.
-#[doc(alias = "SBI_ERR_ALREADY_STOPPED")]
-pub const RET_ERR_ALREADY_STOPPED: usize = <usize as SbiRegister>::RET_ERR_ALREADY_STOPPED;
-/// Error for shared memory not available.
-#[doc(alias = "SBI_ERR_NO_SHMEM")]
-pub const RET_ERR_NO_SHMEM: usize = <usize as SbiRegister>::RET_ERR_NO_SHMEM;
-/// Error for invalid state.
-#[doc(alias = "SBI_ERR_INVALID_STATE")]
-pub const RET_ERR_INVALID_STATE: usize = <usize as SbiRegister>::RET_ERR_INVALID_STATE;
-/// Error for bad or invalid range.
-#[doc(alias = "SBI_ERR_BAD_RANGE")]
-pub const RET_ERR_BAD_RANGE: usize = <usize as SbiRegister>::RET_ERR_BAD_RANGE;
-/// Error for failed due to timeout.
-#[doc(alias = "SBI_ERR_TIMEOUT")]
-pub const RET_ERR_TIMEOUT: usize = <usize as SbiRegister>::RET_ERR_TIMEOUT;
-/// Error for input or output error.
-#[doc(alias = "SBI_ERR_IO")]
-pub const RET_ERR_IO: usize = <usize as SbiRegister>::RET_ERR_IO;
-
-/// Data type of register that can be passed to the RISC-V SBI ABI.
-///
-/// This trait defines the requirements for types that are used as the underlying
-/// representation for both the `value` and `error` fields in the `SbiRet` structure.
-/// In most cases, this trait is implemented for primitive integer types (e.g., `usize`),
-/// but it can also be implemented for other types that satisfy the constraints.
-///
-/// # Examples
-///
-/// Implemented automatically for all types that satisfy `Copy`, `Eq`, and `Debug`.
-pub trait SbiRegister: Copy + Eq + Ord + core::fmt::Debug {
-    /// SBI success state return value.
-    const RET_SUCCESS: Self;
-    /// Error for SBI call failed for unknown reasons.
-    const RET_ERR_FAILED: Self;
-    /// Error for target operation not supported.
-    const RET_ERR_NOT_SUPPORTED: Self;
-    /// Error for invalid parameter.
-    const RET_ERR_INVALID_PARAM: Self;
-    /// Error for denied.
-    const RET_ERR_DENIED: Self;
-    /// Error for invalid address.
-    const RET_ERR_INVALID_ADDRESS: Self;
-    /// Error for resource already available.
-    const RET_ERR_ALREADY_AVAILABLE: Self;
-    /// Error for resource already started.
-    const RET_ERR_ALREADY_STARTED: Self;
-    /// Error for resource already stopped.
-    const RET_ERR_ALREADY_STOPPED: Self;
-    /// Error for shared memory not available.
-    const RET_ERR_NO_SHMEM: Self;
-    /// Error for invalid state.
-    const RET_ERR_INVALID_STATE: Self;
-    /// Error for bad or invalid range.
-    const RET_ERR_BAD_RANGE: Self;
-    /// Error for failed due to timeout.
-    const RET_ERR_TIMEOUT: Self;
-    /// Error for input or output error.
-    const RET_ERR_IO: Self;
-
-    /// Zero value for this type; this is used on `value` fields once `SbiRet` returns an error.
-    const ZERO: Self;
-    /// Full-ones value for this type; this is used on SBI mask structures like `CounterMask`
-    /// and `HartMask`.
-    const FULL_MASK: Self;
-
-    /// Converts an `SbiRet` of this type to a `Result` of self and `Error`.
-    fn into_result(ret: SbiRet<Self>) -> Result<Self, Error<Self>>;
-}
-
-macro_rules! impl_sbi_register {
-    ($ty:ty, $signed:ty) => {
-        impl SbiRegister for $ty {
-            const RET_SUCCESS: Self = 0;
-            const RET_ERR_FAILED: Self = -1 as $signed as $ty;
-            const RET_ERR_NOT_SUPPORTED: Self = -2 as $signed as $ty;
-            const RET_ERR_INVALID_PARAM: Self = -3 as $signed as $ty;
-            const RET_ERR_DENIED: Self = -4 as $signed as $ty;
-            const RET_ERR_INVALID_ADDRESS: Self = -5 as $signed as $ty;
-            const RET_ERR_ALREADY_AVAILABLE: Self = -6 as $signed as $ty;
-            const RET_ERR_ALREADY_STARTED: Self = -7 as $signed as $ty;
-            const RET_ERR_ALREADY_STOPPED: Self = -8 as $signed as $ty;
-            const RET_ERR_NO_SHMEM: Self = -9 as $signed as $ty;
-            const RET_ERR_INVALID_STATE: Self = -10 as $signed as $ty;
-            const RET_ERR_BAD_RANGE: Self = -11 as $signed as $ty;
-            const RET_ERR_TIMEOUT: Self = -12 as $signed as $ty;
-            const RET_ERR_IO: Self = -13 as $signed as $ty;
-            const ZERO: Self = 0;
-            const FULL_MASK: Self = !0;
-
-            fn into_result(ret: SbiRet<Self>) -> Result<Self, Error<Self>> {
-                match ret.error {
-                    Self::RET_SUCCESS => Ok(ret.value),
-                    Self::RET_ERR_FAILED => Err(Error::Failed),
-                    Self::RET_ERR_NOT_SUPPORTED => Err(Error::NotSupported),
-                    Self::RET_ERR_INVALID_PARAM => Err(Error::InvalidParam),
-                    Self::RET_ERR_DENIED => Err(Error::Denied),
-                    Self::RET_ERR_INVALID_ADDRESS => Err(Error::InvalidAddress),
-                    Self::RET_ERR_ALREADY_AVAILABLE => Err(Error::AlreadyAvailable),
-                    Self::RET_ERR_ALREADY_STARTED => Err(Error::AlreadyStarted),
-                    Self::RET_ERR_ALREADY_STOPPED => Err(Error::AlreadyStopped),
-                    Self::RET_ERR_NO_SHMEM => Err(Error::NoShmem),
-                    Self::RET_ERR_INVALID_STATE => Err(Error::InvalidState),
-                    Self::RET_ERR_BAD_RANGE => Err(Error::BadRange),
-                    Self::RET_ERR_TIMEOUT => Err(Error::Timeout),
-                    Self::RET_ERR_IO => Err(Error::Io),
-                    unknown => Err(Error::Custom(unknown as _)),
-                }
-            }
-        }
-    };
-}
-
-impl_sbi_register!(usize, isize);
-impl_sbi_register!(isize, isize);
-impl_sbi_register!(u32, i32);
-impl_sbi_register!(i32, i32);
-impl_sbi_register!(u64, i64);
-impl_sbi_register!(i64, i64);
-impl_sbi_register!(u128, i128);
-impl_sbi_register!(i128, i128);
-
-impl<T: SbiRegister + core::fmt::LowerHex> core::fmt::Debug for SbiRet<T> {
-    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
-        match T::into_result(*self) {
-            Ok(value) => write!(f, "{:?}", value),
-            Err(err) => match err {
-                Error::Failed => write!(f, "<SBI call failed>"),
-                Error::NotSupported => write!(f, "<SBI feature not supported>"),
-                Error::InvalidParam => write!(f, "<SBI invalid parameter>"),
-                Error::Denied => write!(f, "<SBI denied>"),
-                Error::InvalidAddress => write!(f, "<SBI invalid address>"),
-                Error::AlreadyAvailable => write!(f, "<SBI already available>"),
-                Error::AlreadyStarted => write!(f, "<SBI already started>"),
-                Error::AlreadyStopped => write!(f, "<SBI already stopped>"),
-                Error::NoShmem => write!(f, "<SBI shared memory not available>"),
-                Error::InvalidState => write!(f, "<SBI invalid state>"),
-                Error::BadRange => write!(f, "<SBI bad range>"),
-                Error::Timeout => write!(f, "<SBI timeout>"),
-                Error::Io => write!(f, "<SBI input/output error>"),
-                Error::Custom(unknown) => write!(f, "[SBI Unknown error: {:#x}]", unknown),
-            },
-        }
-    }
-}
-
-/// RISC-V SBI error in enumeration.
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub enum Error<T = usize> {
-    /// Error for SBI call failed for unknown reasons.
-    Failed,
-    /// Error for target operation not supported.
-    NotSupported,
-    /// Error for invalid parameter.
-    InvalidParam,
-    /// Error for denied.
-    Denied,
-    /// Error for invalid address.
-    InvalidAddress,
-    /// Error for resource already available.
-    AlreadyAvailable,
-    /// Error for resource already started.
-    AlreadyStarted,
-    /// Error for resource already stopped.
-    AlreadyStopped,
-    /// Error for shared memory not available.
-    NoShmem,
-    /// Error for invalid state.
-    InvalidState,
-    /// Error for bad or invalid range.
-    BadRange,
-    /// Error for failed due to timeout.
-    Timeout,
-    /// Error for input or output error.
-    Io,
-    /// Custom error code.
-    Custom(T),
-}
-
-impl<T: SbiRegister> SbiRet<T> {
-    /// Returns success SBI state with given `value`.
-    #[inline]
-    pub const fn success(value: T) -> Self {
-        Self {
-            error: T::RET_SUCCESS,
-            value,
-        }
-    }
-
-    /// The SBI call request failed for unknown reasons.
-    #[inline]
-    pub const fn failed() -> Self {
-        Self {
-            error: T::RET_ERR_FAILED,
-            value: T::ZERO,
-        }
-    }
-
-    /// SBI call failed due to not supported by target ISA,
-    /// operation type not supported,
-    /// or target operation type not implemented on purpose.
-    #[inline]
-    pub const fn not_supported() -> Self {
-        Self {
-            error: T::RET_ERR_NOT_SUPPORTED,
-            value: T::ZERO,
-        }
-    }
-
-    /// SBI call failed due to invalid hart mask parameter,
-    /// invalid target hart id,
-    /// invalid operation type,
-    /// or invalid resource index.
-    #[inline]
-    pub const fn invalid_param() -> Self {
-        Self {
-            error: T::RET_ERR_INVALID_PARAM,
-            value: T::ZERO,
-        }
-    }
-    /// SBI call denied for unsatisfied entry criteria, or insufficient access
-    /// permission to debug console or CPPC register.
-    #[inline]
-    pub const fn denied() -> Self {
-        Self {
-            error: T::RET_ERR_DENIED,
-            value: T::ZERO,
-        }
-    }
-
-    /// SBI call failed for invalid mask start address,
-    /// not a valid physical address parameter,
-    /// or the target address is prohibited by PMP to run in supervisor mode.
-    #[inline]
-    pub const fn invalid_address() -> Self {
-        Self {
-            error: T::RET_ERR_INVALID_ADDRESS,
-            value: T::ZERO,
-        }
-    }
-
-    /// SBI call failed for the target resource is already available,
-    /// e.g., the target hart is already started when caller still requests it to start.
-    #[inline]
-    pub const fn already_available() -> Self {
-        Self {
-            error: T::RET_ERR_ALREADY_AVAILABLE,
-            value: T::ZERO,
-        }
-    }
-
-    /// SBI call failed for the target resource is already started,
-    /// e.g., target performance counter is started.
-    #[inline]
-    pub const fn already_started() -> Self {
-        Self {
-            error: T::RET_ERR_ALREADY_STARTED,
-            value: T::ZERO,
-        }
-    }
-
-    /// SBI call failed for the target resource is already stopped,
-    /// e.g., target performance counter is stopped.
-    #[inline]
-    pub const fn already_stopped() -> Self {
-        Self {
-            error: T::RET_ERR_ALREADY_STOPPED,
-            value: T::ZERO,
-        }
-    }
-
-    /// SBI call failed for shared memory is not available,
-    /// e.g. nested acceleration shared memory is not available.
-    #[inline]
-    pub const fn no_shmem() -> Self {
-        Self {
-            error: T::RET_ERR_NO_SHMEM,
-            value: T::ZERO,
-        }
-    }
-
-    /// SBI call failed for invalid state,
-    /// e.g. register a software event but the event is not in unused state.
-    #[inline]
-    pub const fn invalid_state() -> Self {
-        Self {
-            error: T::RET_ERR_INVALID_STATE,
-            value: T::ZERO,
-        }
-    }
-
-    /// SBI call failed for bad or invalid range,
-    /// e.g. the software event is not exist in the specified range.
-    #[inline]
-    pub const fn bad_range() -> Self {
-        Self {
-            error: T::RET_ERR_BAD_RANGE,
-            value: T::ZERO,
-        }
-    }
-
-    /// SBI call failed for timeout,
-    /// e.g. message send timeout.
-    #[inline]
-    pub const fn timeout() -> Self {
-        Self {
-            error: T::RET_ERR_TIMEOUT,
-            value: T::ZERO,
-        }
-    }
-
-    /// SBI call failed for input or output error.
-    #[inline]
-    pub const fn io() -> Self {
-        Self {
-            error: T::RET_ERR_IO,
-            value: T::ZERO,
-        }
-    }
-}
-
-impl<T: SbiRegister> From<Error<T>> for SbiRet<T> {
-    #[inline]
-    fn from(value: Error<T>) -> Self {
-        match value {
-            Error::Failed => SbiRet::failed(),
-            Error::NotSupported => SbiRet::not_supported(),
-            Error::InvalidParam => SbiRet::invalid_param(),
-            Error::Denied => SbiRet::denied(),
-            Error::InvalidAddress => SbiRet::invalid_address(),
-            Error::AlreadyAvailable => SbiRet::already_available(),
-            Error::AlreadyStarted => SbiRet::already_started(),
-            Error::AlreadyStopped => SbiRet::already_stopped(),
-            Error::NoShmem => SbiRet::no_shmem(),
-            Error::InvalidState => SbiRet::invalid_state(),
-            Error::BadRange => SbiRet::bad_range(),
-            Error::Timeout => SbiRet::timeout(),
-            Error::Io => SbiRet::io(),
-            Error::Custom(error) => SbiRet {
-                error,
-                value: T::ZERO,
-            },
-        }
-    }
-}
-
-impl SbiRet {
-    /// Converts to a [`Result`] of value and error.
-    #[inline]
-    pub const fn into_result(self) -> Result<usize, Error> {
-        match self.error {
-            RET_SUCCESS => Ok(self.value),
-            RET_ERR_FAILED => Err(Error::Failed),
-            RET_ERR_NOT_SUPPORTED => Err(Error::NotSupported),
-            RET_ERR_INVALID_PARAM => Err(Error::InvalidParam),
-            RET_ERR_DENIED => Err(Error::Denied),
-            RET_ERR_INVALID_ADDRESS => Err(Error::InvalidAddress),
-            RET_ERR_ALREADY_AVAILABLE => Err(Error::AlreadyAvailable),
-            RET_ERR_ALREADY_STARTED => Err(Error::AlreadyStarted),
-            RET_ERR_ALREADY_STOPPED => Err(Error::AlreadyStopped),
-            RET_ERR_NO_SHMEM => Err(Error::NoShmem),
-            RET_ERR_INVALID_STATE => Err(Error::InvalidState),
-            RET_ERR_BAD_RANGE => Err(Error::BadRange),
-            RET_ERR_TIMEOUT => Err(Error::Timeout),
-            RET_ERR_IO => Err(Error::Io),
-            unknown => Err(Error::Custom(unknown as _)),
-        }
-    }
-
-    /// Returns `true` if current SBI return succeeded.
-    ///
-    /// # Examples
-    ///
-    /// Basic usage:
-    ///
-    /// ```
-    /// # use sbi_spec::binary::SbiRet;
-    /// let x = SbiRet::success(0);
-    /// assert_eq!(x.is_ok(), true);
-    ///
-    /// let x = SbiRet::failed();
-    /// assert_eq!(x.is_ok(), false);
-    /// ```
-    #[must_use = "if you intended to assert that this is ok, consider `.unwrap()` instead"]
-    #[inline]
-    pub const fn is_ok(&self) -> bool {
-        matches!(self.error, RET_SUCCESS)
-    }
-
-    /// Returns `true` if the SBI call succeeded and the value inside of it matches a predicate.
-    ///
-    /// # Examples
-    ///
-    /// Basic usage:
-    ///
-    /// ```
-    /// # use sbi_spec::binary::SbiRet;
-    /// let x = SbiRet::success(2);
-    /// assert_eq!(x.is_ok_and(|x| x > 1), true);
-    ///
-    /// let x = SbiRet::success(0);
-    /// assert_eq!(x.is_ok_and(|x| x > 1), false);
-    ///
-    /// let x = SbiRet::no_shmem();
-    /// assert_eq!(x.is_ok_and(|x| x > 1), false);
-    /// ```
-    #[must_use]
-    #[inline]
-    pub fn is_ok_and(self, f: impl FnOnce(usize) -> bool) -> bool {
-        self.into_result().is_ok_and(f)
-    }
-
-    /// Returns `true` if current SBI return is an error.
-    ///
-    /// # Examples
-    ///
-    /// Basic usage:
-    ///
-    /// ```
-    /// # use sbi_spec::binary::SbiRet;
-    /// let x = SbiRet::success(0);
-    /// assert_eq!(x.is_err(), false);
-    ///
-    /// let x = SbiRet::not_supported();
-    /// assert_eq!(x.is_err(), true);
-    /// ```
-    #[must_use = "if you intended to assert that this is err, consider `.unwrap_err()` instead"]
-    #[inline]
-    pub const fn is_err(&self) -> bool {
-        !self.is_ok()
-    }
-
-    /// Returns `true` if the result is an error and the value inside of it matches a predicate.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// # use sbi_spec::binary::{SbiRet, Error};
-    /// let x = SbiRet::denied();
-    /// assert_eq!(x.is_err_and(|x| x == Error::Denied), true);
-    ///
-    /// let x = SbiRet::invalid_address();
-    /// assert_eq!(x.is_err_and(|x| x == Error::Denied), false);
-    ///
-    /// let x = SbiRet::success(0);
-    /// assert_eq!(x.is_err_and(|x| x == Error::Denied), false);
-    /// ```
-    #[must_use]
-    #[inline]
-    pub fn is_err_and(self, f: impl FnOnce(Error) -> bool) -> bool {
-        self.into_result().is_err_and(f)
-    }
-
-    /// Converts from `SbiRet` to [`Option<usize>`].
-    ///
-    /// Converts `self` into an [`Option<usize>`], consuming `self`,
-    /// and discarding the error, if any.
-    ///
-    /// # Examples
-    ///
-    /// Basic usage:
-    ///
-    /// ```
-    /// # use sbi_spec::binary::SbiRet;
-    /// let x = SbiRet::success(2);
-    /// assert_eq!(x.ok(), Some(2));
-    ///
-    /// let x = SbiRet::invalid_param();
-    /// assert_eq!(x.ok(), None);
-    /// ```
-    // fixme: should be pub const fn once this function in Result is stabilized in constant
-    #[inline]
-    pub fn ok(self) -> Option<usize> {
-        self.into_result().ok()
-    }
-
-    /// Converts from `SbiRet` to [`Option<Error>`].
-    ///
-    /// Converts `self` into an [`Option<Error>`], consuming `self`,
-    /// and discarding the success value, if any.
-    ///
-    /// # Examples
-    ///
-    /// Basic usage:
-    ///
-    /// ```
-    /// # use sbi_spec::binary::{SbiRet, Error};
-    /// let x = SbiRet::success(2);
-    /// assert_eq!(x.err(), None);
-    ///
-    /// let x = SbiRet::denied();
-    /// assert_eq!(x.err(), Some(Error::Denied));
-    /// ```
-    // fixme: should be pub const fn once this function in Result is stabilized in constant
-    #[inline]
-    pub fn err(self) -> Option<Error> {
-        self.into_result().err()
-    }
-
-    /// Maps a `SbiRet` to `Result<U, Error>` by applying a function to a
-    /// contained success value, leaving an error value untouched.
-    ///
-    /// This function can be used to compose the results of two functions.
-    ///
-    /// # Examples
-    ///
-    /// Gets detail of a PMU counter and judge if it is a firmware counter.
-    ///
-    /// ```
-    /// # use sbi_spec::binary::SbiRet;
-    /// # use core::mem::size_of;
-    /// # mod sbi_rt {
-    /// #     use sbi_spec::binary::SbiRet;
-    /// #     const TYPE_MASK: usize = 1 << (core::mem::size_of::<usize>() - 1);
-    /// #     pub fn pmu_counter_get_info(_: usize) -> SbiRet { SbiRet::success(TYPE_MASK) }
-    /// # }
-    /// // We assume that counter index 42 is a firmware counter.
-    /// let counter_idx = 42;
-    /// // Masks PMU counter type by setting highest bit in `usize`.
-    /// const TYPE_MASK: usize = 1 << (size_of::<usize>() - 1);
-    /// // Highest bit of returned `counter_info` represents whether it's
-    /// // a firmware counter or a hardware counter.
-    /// let is_firmware_counter = sbi_rt::pmu_counter_get_info(counter_idx)
-    ///     .map(|counter_info| counter_info & TYPE_MASK != 0);
-    /// // If that bit is set, it is a firmware counter.
-    /// assert_eq!(is_firmware_counter, Ok(true));
-    /// ```
-    #[inline]
-    pub fn map<U, F: FnOnce(usize) -> U>(self, op: F) -> Result<U, Error> {
-        self.into_result().map(op)
-    }
-
-    /// Returns the provided default (if error),
-    /// or applies a function to the contained value (if success).
-    ///
-    /// Arguments passed to `map_or` are eagerly evaluated;
-    /// if you are passing the result of a function call,
-    /// it is recommended to use [`map_or_else`],
-    /// which is lazily evaluated.
-    ///
-    /// [`map_or_else`]: SbiRet::map_or_else
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// # use sbi_spec::binary::SbiRet;
-    /// let x = SbiRet::success(3);
-    /// assert_eq!(x.map_or(42, |v| v & 0b1), 1);
-    ///
-    /// let x = SbiRet::invalid_address();
-    /// assert_eq!(x.map_or(42, |v| v & 0b1), 42);
-    /// ```
-    #[inline]
-    pub fn map_or<U, F: FnOnce(usize) -> U>(self, default: U, f: F) -> U {
-        self.into_result().map_or(default, f)
-    }
-
-    /// Maps a `SbiRet` to `usize` value by applying fallback function `default` to
-    /// a contained error, or function `f` to a contained success value.
-    ///
-    /// This function can be used to unpack a successful result
-    /// while handling an error.
-    ///
-    /// # Examples
-    ///
-    /// Basic usage:
-    ///
-    /// ```
-    /// # use sbi_spec::binary::SbiRet;
-    /// let k = 21;
-    ///
-    /// let x = SbiRet::success(3);
-    /// assert_eq!(x.map_or_else(|e| k * 2, |v| v & 0b1), 1);
-    ///
-    /// let x = SbiRet::already_available();
-    /// assert_eq!(x.map_or_else(|e| k * 2, |v| v & 0b1), 42);
-    /// ```
-    #[inline]
-    pub fn map_or_else<U, D: FnOnce(Error) -> U, F: FnOnce(usize) -> U>(
-        self,
-        default: D,
-        f: F,
-    ) -> U {
-        self.into_result().map_or_else(default, f)
-    }
-
-    /// Maps a `SbiRet` to `Result<T, F>` by applying a function to a
-    /// contained error as [`Error`] struct, leaving success value untouched.
-    ///
-    /// This function can be used to pass through a successful result while handling
-    /// an error.
-    ///
-    /// # Examples
-    ///
-    /// Basic usage:
-    ///
-    /// ```
-    /// # use sbi_spec::binary::{SbiRet, Error};
-    /// fn stringify(x: Error) -> String {
-    ///     if x == Error::AlreadyStarted {
-    ///         "error: already started!".to_string()
-    ///     } else {
-    ///         "error: other error!".to_string()
-    ///     }
-    /// }
-    ///
-    /// let x = SbiRet::success(2);
-    /// assert_eq!(x.map_err(stringify), Ok(2));
-    ///
-    /// let x = SbiRet::already_started();
-    /// assert_eq!(x.map_err(stringify), Err("error: already started!".to_string()));
-    /// ```
-    #[inline]
-    pub fn map_err<F, O: FnOnce(Error) -> F>(self, op: O) -> Result<usize, F> {
-        self.into_result().map_err(op)
-    }
-
-    /// Calls a function with a reference to the contained value if current SBI call succeeded.
-    ///
-    /// Returns the original result.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// # use sbi_spec::binary::SbiRet;
-    /// // Assume that SBI debug console have read 512 bytes into a buffer.
-    /// let ret = SbiRet::success(512);
-    /// // Inspect the SBI DBCN call result.
-    /// let idx = ret
-    ///     .inspect(|x| println!("bytes written: {x}"))
-    ///     .map(|x| x - 1)
-    ///     .expect("SBI DBCN call failed");
-    /// assert_eq!(idx, 511);
-    /// ```
-    #[inline]
-    pub fn inspect<F: FnOnce(&usize)>(self, f: F) -> Self {
-        if let Ok(ref t) = self.into_result() {
-            f(t);
-        }
-
-        self
-    }
-
-    /// Calls a function with a reference to the contained value if current SBI result is an error.
-    ///
-    /// Returns the original result.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// # use sbi_spec::binary::SbiRet;
-    /// // Assume that SBI debug console write operation failed for invalid parameter.
-    /// let ret = SbiRet::invalid_param();
-    /// // Print the error if SBI DBCN call failed.
-    /// let ret = ret.inspect_err(|e| eprintln!("failed to read from SBI console: {e:?}"));
-    /// ```
-    #[inline]
-    pub fn inspect_err<F: FnOnce(&Error)>(self, f: F) -> Self {
-        if let Err(ref e) = self.into_result() {
-            f(e);
-        }
-
-        self
-    }
-
-    // TODO: pub fn iter(&self) -> Iter
-    // TODO: pub fn iter_mut(&mut self) -> IterMut
-
-    /// Returns the contained success value, consuming the `self` value.
-    ///
-    /// # Panics
-    ///
-    /// Panics if self is an SBI error with a panic message including the
-    /// passed message, and the content of the SBI state.
-    ///
-    /// # Examples
-    ///
-    /// Basic usage:
-    ///
-    /// ```should_panic
-    /// # use sbi_spec::binary::SbiRet;
-    /// let x = SbiRet::already_stopped();
-    /// x.expect("Testing expect"); // panics with `Testing expect`
-    /// ```
-    #[inline]
-    pub fn expect(self, msg: &str) -> usize {
-        self.into_result().expect(msg)
-    }
-
-    /// Returns the contained success value, consuming the `self` value.
-    ///
-    /// # Panics
-    ///
-    /// Panics if self is an SBI error, with a panic message provided by the
-    /// SBI error converted into [`Error`] struct.
-    ///
-    /// # Examples
-    ///
-    /// Basic usage:
-    ///
-    /// ```
-    /// # use sbi_spec::binary::SbiRet;
-    /// let x = SbiRet::success(2);
-    /// assert_eq!(x.unwrap(), 2);
-    /// ```
-    ///
-    /// ```should_panic
-    /// # use sbi_spec::binary::SbiRet;
-    /// let x = SbiRet::failed();
-    /// x.unwrap(); // panics
-    /// ```
-    #[inline]
-    pub fn unwrap(self) -> usize {
-        self.into_result().unwrap()
-    }
-
-    // Note: No unwrap_or_default as we cannot determine a meaningful default value for a successful SbiRet.
-
-    /// Returns the contained error as [`Error`] struct, consuming the `self` value.
-    ///
-    /// # Panics
-    ///
-    /// Panics if the self is SBI success value, with a panic message
-    /// including the passed message, and the content of the success value.
-    ///
-    /// # Examples
-    ///
-    /// Basic usage:
-    ///
-    /// ```should_panic
-    /// # use sbi_spec::binary::SbiRet;
-    /// let x = SbiRet::success(10);
-    /// x.expect_err("Testing expect_err"); // panics with `Testing expect_err`
-    /// ```
-    #[inline]
-    pub fn expect_err(self, msg: &str) -> Error {
-        self.into_result().expect_err(msg)
-    }
-
-    /// Returns the contained error as [`Error`] struct, consuming the `self` value.
-    ///
-    /// # Panics
-    ///
-    /// Panics if the self is SBI success value, with a custom panic message provided
-    /// by the success value.
-    ///
-    /// # Examples
-    ///
-    /// ```should_panic
-    /// # use sbi_spec::binary::SbiRet;
-    /// let x = SbiRet::success(2);
-    /// x.unwrap_err(); // panics with `2`
-    /// ```
-    ///
-    /// ```
-    /// # use sbi_spec::binary::{SbiRet, Error};
-    /// let x = SbiRet::not_supported();
-    /// assert_eq!(x.unwrap_err(), Error::NotSupported);
-    /// ```
-    #[inline]
-    pub fn unwrap_err(self) -> Error {
-        self.into_result().unwrap_err()
-    }
-
-    // TODO: pub fn into_ok(self) -> usize and pub fn into_err(self) -> Error
-    // once `unwrap_infallible` is stabilized
-
-    /// Returns `res` if self is success value, otherwise otherwise returns the contained error
-    /// of `self` as [`Error`] struct.
-    ///
-    /// Arguments passed to `and` are eagerly evaluated; if you are passing the
-    /// result of a function call, it is recommended to use [`and_then`], which is
-    /// lazily evaluated.
-    ///
-    /// [`and_then`]: SbiRet::and_then
-    ///
-    /// # Examples
-    ///
-    /// Basic usage:
-    ///
-    /// ```
-    /// # use sbi_spec::binary::{SbiRet, Error};
-    /// let x = SbiRet::success(2);
-    /// let y = SbiRet::invalid_param().into_result();
-    /// assert_eq!(x.and(y), Err(Error::InvalidParam));
-    ///
-    /// let x = SbiRet::denied();
-    /// let y = SbiRet::success(3).into_result();
-    /// assert_eq!(x.and(y), Err(Error::Denied));
-    ///
-    /// let x = SbiRet::invalid_address();
-    /// let y = SbiRet::already_available().into_result();
-    /// assert_eq!(x.and(y), Err(Error::InvalidAddress));
-    ///
-    /// let x = SbiRet::success(4);
-    /// let y = SbiRet::success(5).into_result();
-    /// assert_eq!(x.and(y), Ok(5));
-    /// ```
-    // fixme: should be pub const fn once this function in Result is stabilized in constant
-    // fixme: should parameter be `res: SbiRet`?
-    #[inline]
-    pub fn and<U>(self, res: Result<U, Error>) -> Result<U, Error> {
-        self.into_result().and(res)
-    }
-
-    /// Calls `op` if self is success value, otherwise returns the contained error
-    /// as [`Error`] struct.
-    ///
-    /// This function can be used for control flow based on `SbiRet` values.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// # use sbi_spec::binary::{SbiRet, Error};
-    /// fn sq_then_to_string(x: usize) -> Result<String, Error> {
-    ///     x.checked_mul(x).map(|sq| sq.to_string()).ok_or(Error::Failed)
-    /// }
-    ///
-    /// assert_eq!(SbiRet::success(2).and_then(sq_then_to_string), Ok(4.to_string()));
-    /// assert_eq!(SbiRet::success(1_000_000_000_000).and_then(sq_then_to_string), Err(Error::Failed));
-    /// assert_eq!(SbiRet::invalid_param().and_then(sq_then_to_string), Err(Error::InvalidParam));
-    /// ```
-    #[inline]
-    pub fn and_then<U, F: FnOnce(usize) -> Result<U, Error>>(self, op: F) -> Result<U, Error> {
-        self.into_result().and_then(op)
-    }
-
-    /// Returns `res` if self is SBI error, otherwise returns the success value of `self`.
-    ///
-    /// Arguments passed to `or` are eagerly evaluated; if you are passing the
-    /// result of a function call, it is recommended to use [`or_else`], which is
-    /// lazily evaluated.
-    ///
-    /// [`or_else`]: Result::or_else
-    ///
-    /// # Examples
-    ///
-    /// Basic usage:
-    ///
-    /// ```
-    /// # use sbi_spec::binary::{SbiRet, Error};
-    /// let x = SbiRet::success(2);
-    /// let y = SbiRet::invalid_param().into_result();
-    /// assert_eq!(x.or(y), Ok(2));
-    ///
-    /// let x = SbiRet::denied();
-    /// let y = SbiRet::success(3).into_result();
-    /// assert_eq!(x.or(y), Ok(3));
-    ///
-    /// let x = SbiRet::invalid_address();
-    /// let y = SbiRet::already_available().into_result();
-    /// assert_eq!(x.or(y), Err(Error::AlreadyAvailable));
-    ///
-    /// let x = SbiRet::success(4);
-    /// let y = SbiRet::success(100).into_result();
-    /// assert_eq!(x.or(y), Ok(4));
-    /// ```
-    // fixme: should be pub const fn once this function in Result is stabilized in constant
-    // fixme: should parameter be `res: SbiRet`?
-    #[inline]
-    pub fn or<F>(self, res: Result<usize, F>) -> Result<usize, F> {
-        self.into_result().or(res)
-    }
-
-    /// Calls `op` if self is SBI error, otherwise returns the success value of `self`.
-    ///
-    /// This function can be used for control flow based on result values.
-    ///
-    ///
-    /// # Examples
-    ///
-    /// Basic usage:
-    ///
-    /// ```
-    /// # use sbi_spec::binary::{SbiRet, Error};
-    /// fn is_failed(x: Error) -> Result<usize, bool> { Err(x == Error::Failed) }
-    ///
-    /// assert_eq!(SbiRet::success(2).or_else(is_failed), Ok(2));
-    /// assert_eq!(SbiRet::failed().or_else(is_failed), Err(true));
-    /// ```
-    #[inline]
-    pub fn or_else<F, O: FnOnce(Error) -> Result<usize, F>>(self, op: O) -> Result<usize, F> {
-        self.into_result().or_else(op)
-    }
-
-    /// Returns the contained success value or a provided default.
-    ///
-    /// Arguments passed to `unwrap_or` are eagerly evaluated; if you are passing
-    /// the result of a function call, it is recommended to use [`unwrap_or_else`],
-    /// which is lazily evaluated.
-    ///
-    /// [`unwrap_or_else`]: SbiRet::unwrap_or_else
-    ///
-    /// # Examples
-    ///
-    /// Basic usage:
-    ///
-    /// ```
-    /// # use sbi_spec::binary::SbiRet;
-    /// let default = 2;
-    /// let x = SbiRet::success(9);
-    /// assert_eq!(x.unwrap_or(default), 9);
-    ///
-    /// let x = SbiRet::invalid_param();
-    /// assert_eq!(x.unwrap_or(default), default);
-    /// ```
-    // fixme: should be pub const fn once this function in Result is stabilized in constant
-    #[inline]
-    pub fn unwrap_or(self, default: usize) -> usize {
-        self.into_result().unwrap_or(default)
-    }
-
-    /// Returns the contained success value or computes it from a closure.
-    ///
-    /// # Examples
-    ///
-    /// Basic usage:
-    ///
-    /// ```
-    /// # use sbi_spec::binary::{SbiRet, Error};
-    /// fn invalid_use_zero(x: Error) -> usize { if x == Error::InvalidParam { 0 } else { 3 } }
-    ///
-    /// assert_eq!(SbiRet::success(2).unwrap_or_else(invalid_use_zero), 2);
-    /// assert_eq!(SbiRet::invalid_param().unwrap_or_else(invalid_use_zero), 0);
-    /// ```
-    #[inline]
-    pub fn unwrap_or_else<F: FnOnce(Error) -> usize>(self, op: F) -> usize {
-        self.into_result().unwrap_or_else(op)
-    }
-
-    /// Returns the contained success value, consuming the `self` value,
-    /// without checking that the `SbiRet` contains an error value.
-    ///
-    /// # Safety
-    ///
-    /// Calling this method on an `SbiRet` containing an error value results
-    /// in *undefined behavior*.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// # use sbi_spec::binary::{SbiRet, Error};
-    /// let x = SbiRet::success(3);
-    /// assert_eq!(unsafe { x.unwrap_unchecked() }, 3);
-    /// ```
-    ///
-    /// ```no_run
-    /// # use sbi_spec::binary::SbiRet;
-    /// let x = SbiRet::no_shmem();
-    /// unsafe { x.unwrap_unchecked(); } // Undefined behavior!
-    /// ```
-    #[inline]
-    pub unsafe fn unwrap_unchecked(self) -> usize {
-        unsafe { self.into_result().unwrap_unchecked() }
-    }
-
-    /// Returns the contained `Error` value, consuming the `self` value,
-    /// without checking that the `SbiRet` does not contain a success value.
-    ///
-    /// # Safety
-    ///
-    /// Calling this method on an `SbiRet` containing a success value results
-    /// in *undefined behavior*.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// # use sbi_spec::binary::SbiRet;
-    /// let x = SbiRet::success(4);
-    /// unsafe { x.unwrap_unchecked(); } // Undefined behavior!
-    /// ```
-    ///
-    /// ```
-    /// # use sbi_spec::binary::{SbiRet, Error};
-    /// let x = SbiRet::failed();
-    /// assert_eq!(unsafe { x.unwrap_err_unchecked() }, Error::Failed);
-    /// ```
-    #[inline]
-    pub unsafe fn unwrap_err_unchecked(self) -> Error {
-        unsafe { self.into_result().unwrap_err_unchecked() }
-    }
-}
-
-impl IntoIterator for SbiRet {
-    type Item = usize;
-    type IntoIter = core::result::IntoIter<usize>;
-
-    /// Returns a consuming iterator over the possibly contained value.
-    ///
-    /// The iterator yields one value if the result contains a success value, otherwise none.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// # use sbi_spec::binary::SbiRet;
-    /// let x = SbiRet::success(5);
-    /// let v: Vec<usize> = x.into_iter().collect();
-    /// assert_eq!(v, [5]);
-    ///
-    /// let x = SbiRet::not_supported();
-    /// let v: Vec<usize> = x.into_iter().collect();
-    /// assert_eq!(v, []);
-    /// ```
-    #[inline]
-    fn into_iter(self) -> Self::IntoIter {
-        self.into_result().into_iter()
-    }
-}
-
-// TODO: implement Try and FromResidual for SbiRet once those traits are stablized
-/*
-impl core::ops::Try for SbiRet {
-    type Output = usize;
-    type Residual = Result<core::convert::Infallible, Error>;
-
-    #[inline]
-    fn from_output(output: Self::Output) -> Self {
-        SbiRet::success(output)
-    }
-
-    #[inline]
-    fn branch(self) -> core::ops::ControlFlow<Self::Residual, Self::Output> {
-        self.into_result().branch()
-    }
-}
-
-impl core::ops::FromResidual<Result<core::convert::Infallible, Error>> for SbiRet {
-    #[inline]
-    #[track_caller]
-    fn from_residual(residual: Result<core::convert::Infallible, Error>) -> Self {
-        match residual {
-            Err(e) => e.into(),
-        }
-    }
-}
-
-/// ```
-/// # use sbi_spec::binary::SbiRet;
-/// fn test() -> SbiRet {
-///     let value = SbiRet::failed()?;
-///     SbiRet::success(0)
-/// }
-/// assert_eq!(test(), SbiRet::failed());
-/// ```
-mod test_try_trait_for_sbiret {}
-*/
-
-/// Check if the implementation can contains the provided `bit`.
-#[inline]
-pub(crate) const fn valid_bit(base: usize, bit: usize) -> bool {
-    if bit < base {
-        // invalid index, under minimum range.
-        false
-    } else if (bit - base) >= usize::BITS as usize {
-        // invalid index, over max range.
-        false
-    } else {
-        true
-    }
-}
-
-/// Check if the implementation contains the provided `bit`.
-///
-/// ## Parameters
-///
-/// - `mask`: bitmask defining the range of bits.
-/// - `base`: the starting bit index. (default: `0`)
-/// - `ignore`: if `base` is equal to this value, ignore the `mask` parameter, and consider all `bit`s set.
-/// - `bit`: the bit index to check for membership in the `mask`.
-#[inline]
-pub(crate) const fn has_bit(mask: usize, base: usize, ignore: usize, bit: usize) -> bool {
-    if base == ignore {
-        // ignore the `mask`, consider all `bit`s as set.
-        true
-    } else if !valid_bit(base, bit) {
-        false
-    } else {
-        // index is in range, check if it is set in the mask.
-        mask & (1 << (bit - base)) != 0
-    }
-}
-
-/// Hart mask structure in SBI function calls.
-#[repr(C)]
-#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
-pub struct HartMask<T = usize> {
-    hart_mask: T,
-    hart_mask_base: T,
-}
-
-impl<T: SbiRegister> HartMask<T> {
-    /// Special value to ignore the `mask`, and consider all `bit`s as set.
-    pub const IGNORE_MASK: T = T::FULL_MASK;
-
-    /// Construct a [HartMask] from mask value and base hart id.
-    #[inline]
-    pub const fn from_mask_base(hart_mask: T, hart_mask_base: T) -> Self {
-        Self {
-            hart_mask,
-            hart_mask_base,
-        }
-    }
-
-    /// Construct a [HartMask] that selects all available harts on the current environment.
-    ///
-    /// According to the RISC-V SBI Specification, `hart_mask_base` can be set to `-1` (i.e. `usize::MAX`)
-    /// to indicate that `hart_mask` shall be ignored and all available harts must be considered.
-    /// In case of this function in the `sbi-spec` crate, we fill in `usize::MAX` in `hart_mask_base`
-    /// parameter to match the RISC-V SBI standard, while choosing 0 as the ignored `hart_mask` value.
-    #[inline]
-    pub const fn all() -> Self {
-        Self {
-            hart_mask: T::ZERO,
-            hart_mask_base: T::FULL_MASK,
-        }
-    }
-
-    /// Gets the special value for ignoring the `mask` parameter.
-    #[inline]
-    pub const fn ignore_mask(&self) -> T {
-        Self::IGNORE_MASK
-    }
-
-    /// Returns `mask` and `base` parameters from the [HartMask].
-    #[inline]
-    pub const fn into_inner(self) -> (T, T) {
-        (self.hart_mask, self.hart_mask_base)
-    }
-}
-
-// FIXME: implement for T: SbiRegister once we can implement this using const traits.
-// Ref: https://rust-lang.github.io/rust-project-goals/2024h2/const-traits.html
-impl HartMask<usize> {
-    /// Returns whether the [HartMask] contains the provided `hart_id`.
-    #[inline]
-    pub const fn has_bit(self, hart_id: usize) -> bool {
-        has_bit(
-            self.hart_mask,
-            self.hart_mask_base,
-            Self::IGNORE_MASK,
-            hart_id,
-        )
-    }
-
-    /// Insert a hart id into this [HartMask].
-    ///
-    /// Returns error when `hart_id` is invalid.
-    #[inline]
-    pub const fn insert(&mut self, hart_id: usize) -> Result<(), MaskError> {
-        if self.hart_mask_base == Self::IGNORE_MASK {
-            Ok(())
-        } else if valid_bit(self.hart_mask_base, hart_id) {
-            self.hart_mask |= 1usize << (hart_id - self.hart_mask_base);
-            Ok(())
-        } else {
-            Err(MaskError::InvalidBit)
-        }
-    }
-
-    /// Remove a hart id from this [HartMask].
-    ///
-    /// Returns error when `hart_id` is invalid, or it has been ignored.
-    #[inline]
-    pub const fn remove(&mut self, hart_id: usize) -> Result<(), MaskError> {
-        if self.hart_mask_base == Self::IGNORE_MASK {
-            Err(MaskError::Ignored)
-        } else if valid_bit(self.hart_mask_base, hart_id) {
-            self.hart_mask &= !(1usize << (hart_id - self.hart_mask_base));
-            Ok(())
-        } else {
-            Err(MaskError::InvalidBit)
-        }
-    }
-
-    /// Returns [HartIds] of self.
-    #[inline]
-    pub const fn iter(&self) -> HartIds {
-        HartIds {
-            inner: match self.hart_mask_base {
-                Self::IGNORE_MASK => UnvisitedMask::Range(0, usize::MAX),
-                _ => UnvisitedMask::MaskBase(self.hart_mask, self.hart_mask_base),
-            },
-        }
-    }
-}
-
-impl IntoIterator for HartMask {
-    type Item = usize;
-
-    type IntoIter = HartIds;
-
-    #[inline]
-    fn into_iter(self) -> Self::IntoIter {
-        self.iter()
-    }
-}
-
-/// Iterator structure for `HartMask`.
-///
-/// It will iterate hart id from low to high.
-#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
-pub struct HartIds {
-    inner: UnvisitedMask,
-}
-
-#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
-enum UnvisitedMask {
-    MaskBase(usize, usize),
-    Range(usize, usize),
-}
-
-impl Iterator for HartIds {
-    type Item = usize;
-
-    #[inline]
-    fn next(&mut self) -> Option<Self::Item> {
-        match &mut self.inner {
-            UnvisitedMask::MaskBase(0, _base) => None,
-            UnvisitedMask::MaskBase(unvisited_mask, base) => {
-                let low_bit = unvisited_mask.trailing_zeros();
-                let hart_id = usize::try_from(low_bit).unwrap() + *base;
-                *unvisited_mask &= !(1usize << low_bit);
-                Some(hart_id)
-            }
-            UnvisitedMask::Range(start, end) => {
-                assert!(start <= end);
-                if *start < *end {
-                    let ans = *start;
-                    *start += 1;
-                    Some(ans)
-                } else {
-                    None
-                }
-            }
-        }
-    }
-
-    #[inline]
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        match self.inner {
-            UnvisitedMask::MaskBase(unvisited_mask, _base) => {
-                let exact_popcnt = usize::try_from(unvisited_mask.count_ones()).unwrap();
-                (exact_popcnt, Some(exact_popcnt))
-            }
-            UnvisitedMask::Range(start, end) => {
-                assert!(start <= end);
-                let exact_num_harts = end - start;
-                (exact_num_harts, Some(exact_num_harts))
-            }
-        }
-    }
-
-    #[inline]
-    fn count(self) -> usize {
-        self.size_hint().0
-    }
-
-    #[inline]
-    fn last(mut self) -> Option<Self::Item> {
-        self.next_back()
-    }
-
-    #[inline]
-    fn min(mut self) -> Option<Self::Item> {
-        self.next()
-    }
-
-    #[inline]
-    fn max(mut self) -> Option<Self::Item> {
-        self.next_back()
-    }
-
-    #[inline]
-    fn is_sorted(self) -> bool {
-        true
-    }
-
-    // TODO: implement fn advance_by once it's stablized: https://github.com/rust-lang/rust/issues/77404
-    // #[inline]
-    // fn advance_by(&mut self, n: usize) -> Result<(), core::num::NonZero<usize>> { ... }
-}
-
-impl DoubleEndedIterator for HartIds {
-    #[inline]
-    fn next_back(&mut self) -> Option<Self::Item> {
-        match &mut self.inner {
-            UnvisitedMask::MaskBase(0, _base) => None,
-            UnvisitedMask::MaskBase(unvisited_mask, base) => {
-                let high_bit = unvisited_mask.leading_zeros();
-                let hart_id = usize::try_from(usize::BITS - high_bit - 1).unwrap() + *base;
-                *unvisited_mask &= !(1usize << (usize::BITS - high_bit - 1));
-                Some(hart_id)
-            }
-            UnvisitedMask::Range(start, end) => {
-                assert!(start <= end);
-                if *start < *end {
-                    let ans = *end;
-                    *end -= 1;
-                    Some(ans)
-                } else {
-                    None
-                }
-            }
-        }
-    }
-
-    // TODO: implement advance_back_by once stablized.
-    // #[inline]
-    // fn advance_back_by(&mut self, n: usize) -> Result<(), core::num::NonZero<usize>> { ... }
-}
-
-impl ExactSizeIterator for HartIds {}
-
-impl core::iter::FusedIterator for HartIds {}
-
-/// Error of mask modification.
-#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
-pub enum MaskError {
-    /// This mask has been ignored.
-    Ignored,
-    /// Request bit is invalid.
-    InvalidBit,
-}
-
-/// Counter index mask structure in SBI function calls for the `PMU` extension §11.
-#[repr(C)]
-#[derive(Debug, Copy, Clone, Eq, PartialEq)]
-pub struct CounterMask<T = usize> {
-    counter_idx_mask: T,
-    counter_idx_base: T,
-}
-
-impl<T: SbiRegister> CounterMask<T> {
-    /// Special value to ignore the `mask`, and consider all `bit`s as set.
-    pub const IGNORE_MASK: T = T::FULL_MASK;
-
-    /// Construct a [CounterMask] from mask value and base counter index.
-    #[inline]
-    pub const fn from_mask_base(counter_idx_mask: T, counter_idx_base: T) -> Self {
-        Self {
-            counter_idx_mask,
-            counter_idx_base,
-        }
-    }
-
-    /// Gets the special value for ignoring the `mask` parameter.
-    #[inline]
-    pub const fn ignore_mask(&self) -> T {
-        Self::IGNORE_MASK
-    }
-
-    /// Returns `mask` and `base` parameters from the [CounterMask].
-    #[inline]
-    pub const fn into_inner(self) -> (T, T) {
-        (self.counter_idx_mask, self.counter_idx_base)
-    }
-}
-
-// FIXME: implement for T: SbiRegister once we can implement this using const traits.
-// Ref: https://rust-lang.github.io/rust-project-goals/2024h2/const-traits.html
-impl CounterMask<usize> {
-    /// Returns whether the [CounterMask] contains the provided `counter`.
-    #[inline]
-    pub const fn has_bit(self, counter: usize) -> bool {
-        has_bit(
-            self.counter_idx_mask,
-            self.counter_idx_base,
-            Self::IGNORE_MASK,
-            counter,
-        )
-    }
-}
-
-/// Debug trigger mask structure for the `DBTR` extension §19.
-#[repr(C)]
-#[derive(Debug, Copy, Clone, Eq, PartialEq)]
-pub struct TriggerMask<T = usize> {
-    trig_idx_base: T,
-    trig_idx_mask: T,
-}
-
-impl<T: SbiRegister> TriggerMask<T> {
-    /// Construct a [TriggerMask] from mask value and base counter index.
-    ///
-    /// The `trig_idx_base` specifies the starting trigger index, while the `trig_idx_mask` is a
-    /// bitmask indicating which triggers, relative to the base, are to be operated.
-    #[inline]
-    pub const fn from_mask_base(trig_idx_mask: T, trig_idx_base: T) -> Self {
-        Self {
-            trig_idx_mask,
-            trig_idx_base,
-        }
-    }
-
-    /// Returns `mask` and `base` parameters from the [TriggerMask].
-    #[inline]
-    pub const fn into_inner(self) -> (T, T) {
-        (self.trig_idx_mask, self.trig_idx_base)
-    }
-}
-
-/// Physical slice wrapper with type annotation.
-///
-/// This struct wraps slices in RISC-V physical memory by low and high part of the
-/// physical base address as well as its length. It is usually used by SBI extensions
-/// as parameter types to pass base address and length parameters on physical memory
-/// other than a virtual one.
-///
-/// Generic parameter `P` represents a hint of how this physical slice would be used.
-/// For example, `Physical<&[u8]>` represents an immutable reference to physical byte slice,
-/// while `Physical<&mut [u8]>` represents a mutable one.
-///
-/// An SBI implementation should load or store memory using both `phys_addr_lo` and
-/// `phys_addr_hi` combined as base address. A supervisor program (kernels etc.)
-/// should provide continuous physical memory, wrapping its reference using this structure
-/// before passing into SBI runtime.
-#[derive(Clone, Copy)]
-pub struct Physical<P> {
-    num_bytes: usize,
-    phys_addr_lo: usize,
-    phys_addr_hi: usize,
-    _marker: PhantomData<P>,
-}
-
-impl<P> Physical<P> {
-    /// Create a physical memory slice by length and physical address.
-    #[inline]
-    pub const fn new(num_bytes: usize, phys_addr_lo: usize, phys_addr_hi: usize) -> Self {
-        Self {
-            num_bytes,
-            phys_addr_lo,
-            phys_addr_hi,
-            _marker: core::marker::PhantomData,
-        }
-    }
-
-    /// Returns length of the physical memory slice.
-    #[inline]
-    pub const fn num_bytes(&self) -> usize {
-        self.num_bytes
-    }
-
-    /// Returns low-part base address of physical memory slice.
-    #[inline]
-    pub const fn phys_addr_lo(&self) -> usize {
-        self.phys_addr_lo
-    }
-
-    /// Returns high-part base address of physical memory slice.
-    #[inline]
-    pub const fn phys_addr_hi(&self) -> usize {
-        self.phys_addr_hi
-    }
-}
-
-/// Shared memory physical address raw pointer with type annotation.
-///
-/// This is a structure wrapping a raw pointer to the value of the type `T` without
-/// a pointer metadata. `SharedPtr`'s are _thin_; they won't include metadata
-/// as RISC-V SBI does not provide an approach to pass them via SBI calls,
-/// thus the length of type `T` should be decided independently of raw
-/// pointer structure.
-///
-/// `SharedPtr` can be used as a parameter to pass the shared memory physical pointer
-///  with a given base address in RISC-V SBI calls. For example, a `SharedPtr<[u8; 64]>`
-/// would represent a fixed-size 64 byte array on a RISC-V SBI function argument
-/// type.
-///
-/// This structure cannot be dereferenced directly with physical addresses,
-/// because on RISC-V systems the physical address space could be larger than the
-/// virtual ones. Hence, this structure describes the physical memory range by
-/// two `usize` values: the upper `phys_addr_hi` and lower `phys_addr_lo`.
-///
-/// RISC-V SBI extensions may declare special pointer values for shared memory
-/// raw pointers. For example, SBI STA declares that steal-time information
-/// should stop from reporting when the SBI call is invoked using all-ones
-/// bitwise shared pointer, i.e. `phys_addr_hi` and `phys_addr_lo` both equals
-/// `usize::MAX`. `SharedPtr` can be constructed using such special values
-/// by providing them to the `SharedPtr::new` function.
-///
-/// # Requirements
-///
-/// If an SBI function needs to pass a shared memory physical address range to
-/// the SBI implementation (or higher privilege mode), then this physical memory
-/// address range MUST satisfy the following requirements:
-///
-/// * The SBI implementation MUST check that the supervisor-mode software is
-///   allowed to access the specified physical memory range with the access
-///   type requested (read and/or write).
-/// * The SBI implementation MUST access the specified physical memory range
-///   using the PMA attributes.
-/// * The data in the shared memory MUST follow little-endian byte ordering.
-///
-/// *NOTE:* If the supervisor-mode software accesses the same physical memory
-/// range using a memory type different from the PMA, then a loss of coherence
-/// or unexpected memory ordering may occur. The invoking software should
-/// follow the rules and sequences defined in the RISC-V Svpbmt specification
-/// to prevent the loss of coherence and memory ordering.
-///
-/// It is recommended that a memory physical address passed to an SBI function
-/// should use at least two `usize` parameters to support platforms
-/// which have memory physical addresses wider than `XLEN` bits.
-// FIXME: should constrain with `T: Thin` once ptr_metadata feature is stabled;
-// RISC-V SBI does not provide an approach to pass pointer metadata by SBI calls.
-pub struct SharedPtr<T> {
-    phys_addr_lo: usize,
-    phys_addr_hi: usize,
-    _marker: PhantomData<*mut T>,
-}
-
-// FIXME: we should consider strict provenance rules for this pointer-like structure
-// once feature strict_provenance is stabled.
-impl<T> SharedPtr<T> {
-    /// Create a shared physical memory pointer by physical address.
-    #[inline]
-    pub const fn new(phys_addr_lo: usize, phys_addr_hi: usize) -> Self {
-        Self {
-            phys_addr_lo,
-            phys_addr_hi,
-            _marker: PhantomData,
-        }
-    }
-
-    /// Returns low-part physical address of the shared physical memory pointer.
-    #[inline]
-    pub const fn phys_addr_lo(self) -> usize {
-        self.phys_addr_lo
-    }
-
-    /// Returns high-part physical address of the shared physical memory pointer.
-    #[inline]
-    pub const fn phys_addr_hi(self) -> usize {
-        self.phys_addr_hi
-    }
-}
-
-impl<T> Clone for SharedPtr<T> {
-    #[inline(always)]
-    fn clone(&self) -> Self {
-        *self
-    }
-}
-
-impl<T> Copy for SharedPtr<T> {}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    #[test]
-    #[rustfmt::skip]
-    fn rustsbi_sbi_ret_constructors() {
-        assert_eq!(SbiRet::success(0), SbiRet { value: 0, error: 0 });
-        assert_eq!(SbiRet::success(1037), SbiRet { value: 1037, error: 0 });
-        assert_eq!(SbiRet::success(usize::MAX), SbiRet { value: usize::MAX, error: 0 });
-
-        assert_eq!(SbiRet::failed(), SbiRet { value: 0, error: usize::MAX - 1 + 1 });
-        assert_eq!(SbiRet::not_supported(), SbiRet { value: 0, error: usize::MAX - 2 + 1 });
-        assert_eq!(SbiRet::invalid_param(), SbiRet { value: 0, error: usize::MAX - 3 + 1 });
-        assert_eq!(SbiRet::denied(), SbiRet { value: 0, error: usize::MAX - 4 + 1 });
-        assert_eq!(SbiRet::invalid_address(), SbiRet { value: 0, error: usize::MAX - 5 + 1 });
-        assert_eq!(SbiRet::already_available(), SbiRet { value: 0, error: usize::MAX - 6 + 1 });
-        assert_eq!(SbiRet::already_started(), SbiRet { value: 0, error: usize::MAX - 7 + 1 });
-        assert_eq!(SbiRet::already_stopped(), SbiRet { value: 0, error: usize::MAX - 8 + 1 });
-        assert_eq!(SbiRet::no_shmem(), SbiRet { value: 0, error: usize::MAX - 9 + 1 });
-        assert_eq!(SbiRet::invalid_state(), SbiRet { value: 0, error: usize::MAX - 10 + 1 });
-        assert_eq!(SbiRet::bad_range(), SbiRet { value: 0, error: usize::MAX - 11 + 1 });
-        assert_eq!(SbiRet::timeout(), SbiRet { value: 0, error: usize::MAX - 12 + 1 });
-        assert_eq!(SbiRet::io(), SbiRet { value: 0, error: usize::MAX - 13 + 1 });
-    }
-
-    #[test]
-    fn rustsbi_hart_mask() {
-        let mask = HartMask::from_mask_base(0b1, 400);
-        assert!(!mask.has_bit(0));
-        assert!(mask.has_bit(400));
-        assert!(!mask.has_bit(401));
-        let mask = HartMask::from_mask_base(0b110, 500);
-        assert!(!mask.has_bit(0));
-        assert!(!mask.has_bit(500));
-        assert!(mask.has_bit(501));
-        assert!(mask.has_bit(502));
-        assert!(!mask.has_bit(500 + (usize::BITS as usize)));
-        let max_bit = 1 << (usize::BITS - 1);
-        let mask = HartMask::from_mask_base(max_bit, 600);
-        assert!(mask.has_bit(600 + (usize::BITS as usize) - 1));
-        assert!(!mask.has_bit(600 + (usize::BITS as usize)));
-        let mask = HartMask::from_mask_base(0b11, usize::MAX - 1);
-        assert!(!mask.has_bit(usize::MAX - 2));
-        assert!(mask.has_bit(usize::MAX - 1));
-        assert!(mask.has_bit(usize::MAX));
-        assert!(!mask.has_bit(0));
-        // hart_mask_base == usize::MAX is special, it means hart_mask should be ignored
-        // and this hart mask contains all harts available
-        let mask = HartMask::from_mask_base(0, usize::MAX);
-        for i in 0..5 {
-            assert!(mask.has_bit(i));
-        }
-        assert!(mask.has_bit(usize::MAX));
-
-        let mut mask = HartMask::from_mask_base(0, 1);
-        assert!(!mask.has_bit(1));
-        assert!(mask.insert(1).is_ok());
-        assert!(mask.has_bit(1));
-        assert!(mask.remove(1).is_ok());
-        assert!(!mask.has_bit(1));
-    }
-
-    #[test]
-    fn rustsbi_hart_ids_iterator() {
-        let mask = HartMask::from_mask_base(0b101011, 1);
-        // Test the `next` method of `HartIds` structure.
-        let mut hart_ids = mask.iter();
-        assert_eq!(hart_ids.next(), Some(1));
-        assert_eq!(hart_ids.next(), Some(2));
-        assert_eq!(hart_ids.next(), Some(4));
-        assert_eq!(hart_ids.next(), Some(6));
-        assert_eq!(hart_ids.next(), None);
-        // `HartIds` structures are fused, meaning they return `None` forever once iteration finished.
-        assert_eq!(hart_ids.next(), None);
-
-        // Test `for` loop on mask (`HartMask`) as `IntoIterator`.
-        let mut ans = [0; 4];
-        let mut idx = 0;
-        for hart_id in mask {
-            ans[idx] = hart_id;
-            idx += 1;
-        }
-        assert_eq!(ans, [1, 2, 4, 6]);
-
-        // Test `Iterator` methods on `HartIds`.
-        let mut hart_ids = mask.iter();
-        assert_eq!(hart_ids.size_hint(), (4, Some(4)));
-        let _ = hart_ids.next();
-        assert_eq!(hart_ids.size_hint(), (3, Some(3)));
-        let _ = hart_ids.next();
-        let _ = hart_ids.next();
-        assert_eq!(hart_ids.size_hint(), (1, Some(1)));
-        let _ = hart_ids.next();
-        assert_eq!(hart_ids.size_hint(), (0, Some(0)));
-        let _ = hart_ids.next();
-        assert_eq!(hart_ids.size_hint(), (0, Some(0)));
-
-        let mut hart_ids = mask.iter();
-        assert_eq!(hart_ids.count(), 4);
-        let _ = hart_ids.next();
-        assert_eq!(hart_ids.count(), 3);
-        let _ = hart_ids.next();
-        let _ = hart_ids.next();
-        let _ = hart_ids.next();
-        assert_eq!(hart_ids.count(), 0);
-        let _ = hart_ids.next();
-        assert_eq!(hart_ids.count(), 0);
-
-        let hart_ids = mask.iter();
-        assert_eq!(hart_ids.last(), Some(6));
-
-        let mut hart_ids = mask.iter();
-        assert_eq!(hart_ids.nth(2), Some(4));
-        let mut hart_ids = mask.iter();
-        assert_eq!(hart_ids.nth(0), Some(1));
-
-        let mut iter = mask.iter().step_by(2);
-        assert_eq!(iter.next(), Some(1));
-        assert_eq!(iter.next(), Some(4));
-        assert_eq!(iter.next(), None);
-
-        let mask_2 = HartMask::from_mask_base(0b1001101, 64);
-        let mut iter = mask.iter().chain(mask_2);
-        assert_eq!(iter.next(), Some(1));
-        assert_eq!(iter.next(), Some(2));
-        assert_eq!(iter.next(), Some(4));
-        assert_eq!(iter.next(), Some(6));
-        assert_eq!(iter.next(), Some(64));
-        assert_eq!(iter.next(), Some(66));
-        assert_eq!(iter.next(), Some(67));
-        assert_eq!(iter.next(), Some(70));
-        assert_eq!(iter.next(), None);
-
-        let mut iter = mask.iter().zip(mask_2);
-        assert_eq!(iter.next(), Some((1, 64)));
-        assert_eq!(iter.next(), Some((2, 66)));
-        assert_eq!(iter.next(), Some((4, 67)));
-        assert_eq!(iter.next(), Some((6, 70)));
-        assert_eq!(iter.next(), None);
-
-        fn to_plic_context_id(hart_id_machine: usize) -> usize {
-            hart_id_machine * 2
-        }
-        let mut iter = mask.iter().map(to_plic_context_id);
-        assert_eq!(iter.next(), Some(2));
-        assert_eq!(iter.next(), Some(4));
-        assert_eq!(iter.next(), Some(8));
-        assert_eq!(iter.next(), Some(12));
-        assert_eq!(iter.next(), None);
-
-        let mut channel_received = [0; 4];
-        let mut idx = 0;
-        let mut channel_send = |hart_id| {
-            channel_received[idx] = hart_id;
-            idx += 1;
-        };
-        mask.iter().for_each(|value| channel_send(value));
-        assert_eq!(channel_received, [1, 2, 4, 6]);
-
-        let is_in_cluster_1 = |hart_id: &usize| *hart_id >= 4 && *hart_id < 7;
-        let mut iter = mask.iter().filter(is_in_cluster_1);
-        assert_eq!(iter.next(), Some(4));
-        assert_eq!(iter.next(), Some(6));
-        assert_eq!(iter.next(), None);
-
-        let if_in_cluster_1_get_plic_context_id = |hart_id: usize| {
-            if hart_id >= 4 && hart_id < 7 {
-                Some(hart_id * 2)
-            } else {
-                None
-            }
-        };
-        let mut iter = mask.iter().filter_map(if_in_cluster_1_get_plic_context_id);
-        assert_eq!(iter.next(), Some(8));
-        assert_eq!(iter.next(), Some(12));
-        assert_eq!(iter.next(), None);
-
-        let mut iter = mask.iter().enumerate();
-        assert_eq!(iter.next(), Some((0, 1)));
-        assert_eq!(iter.next(), Some((1, 2)));
-        assert_eq!(iter.next(), Some((2, 4)));
-        assert_eq!(iter.next(), Some((3, 6)));
-        assert_eq!(iter.next(), None);
-        let mut ans = [(0, 0); 4];
-        let mut idx = 0;
-        for (i, hart_id) in mask.iter().enumerate() {
-            ans[idx] = (i, hart_id);
-            idx += 1;
-        }
-        assert_eq!(ans, [(0, 1), (1, 2), (2, 4), (3, 6)]);
-
-        let mut iter = mask.iter().peekable();
-        assert_eq!(iter.peek(), Some(&1));
-        assert_eq!(iter.next(), Some(1));
-        assert_eq!(iter.peek(), Some(&2));
-        assert_eq!(iter.next(), Some(2));
-        assert_eq!(iter.peek(), Some(&4));
-        assert_eq!(iter.next(), Some(4));
-        assert_eq!(iter.peek(), Some(&6));
-        assert_eq!(iter.next(), Some(6));
-        assert_eq!(iter.peek(), None);
-        assert_eq!(iter.next(), None);
-
-        // TODO: other iterator tests.
-
-        assert!(mask.iter().is_sorted());
-        assert!(mask.iter().is_sorted_by(|a, b| a <= b));
-
-        // Reverse iterator as `DoubleEndedIterator`.
-        let mut iter = mask.iter().rev();
-        assert_eq!(iter.next(), Some(6));
-        assert_eq!(iter.next(), Some(4));
-        assert_eq!(iter.next(), Some(2));
-        assert_eq!(iter.next(), Some(1));
-        assert_eq!(iter.next(), None);
-
-        // Special iterator values.
-        let nothing = HartMask::from_mask_base(0, 1000);
-        assert!(nothing.iter().eq([]));
-
-        let all_mask_bits_set = HartMask::from_mask_base(usize::MAX, 1000);
-        let range = 1000..(1000 + usize::BITS as usize);
-        assert!(all_mask_bits_set.iter().eq(range));
-
-        let all_harts = HartMask::all();
-        let mut iter = all_harts.iter();
-        assert_eq!(iter.size_hint(), (usize::MAX, Some(usize::MAX)));
-        // Don't use `Iterator::eq` here; it would literally run `Iterator::try_for_each` from 0 to usize::MAX
-        // which will cost us forever to run the test.
-        assert_eq!(iter.next(), Some(0));
-        assert_eq!(iter.size_hint(), (usize::MAX - 1, Some(usize::MAX - 1)));
-        assert_eq!(iter.next(), Some(1));
-        assert_eq!(iter.next(), Some(2));
-        // skip 500 elements
-        let _ = iter.nth(500 - 1);
-        assert_eq!(iter.next(), Some(503));
-        assert_eq!(iter.size_hint(), (usize::MAX - 504, Some(usize::MAX - 504)));
-        assert_eq!(iter.next_back(), Some(usize::MAX));
-        assert_eq!(iter.next_back(), Some(usize::MAX - 1));
-        assert_eq!(iter.size_hint(), (usize::MAX - 506, Some(usize::MAX - 506)));
-
-        // A common usage of `HartMask::all`, we assume that this platform filters out hart 0..=3.
-        let environment_available_hart_ids = 4..128;
-        // `hart_mask_iter` contains 64..=usize::MAX.
-        let hart_mask_iter = all_harts.iter().skip(64);
-        let filtered_iter = environment_available_hart_ids.filter(|&x| {
-            hart_mask_iter
-                .clone()
-                .find(|&y| y >= x)
-                .map_or(false, |y| y == x)
-        });
-        assert!(filtered_iter.eq(64..128));
-
-        // The following operations should have O(1) complexity.
-        let all_harts = HartMask::all();
-        assert_eq!(all_harts.iter().count(), usize::MAX);
-        assert_eq!(all_harts.iter().last(), Some(usize::MAX));
-        assert_eq!(all_harts.iter().min(), Some(0));
-        assert_eq!(all_harts.iter().max(), Some(usize::MAX));
-        assert!(all_harts.iter().is_sorted());
-
-        let partial_all_harts = {
-            let mut ans = HartMask::all().iter();
-            let _ = ans.nth(65536 - 1);
-            let _ = ans.nth_back(4096 - 1);
-            ans
-        };
-        assert_eq!(partial_all_harts.clone().count(), usize::MAX - 65536 - 4096);
-        assert_eq!(partial_all_harts.clone().last(), Some(usize::MAX - 4096));
-        assert_eq!(partial_all_harts.clone().min(), Some(65536));
-        assert_eq!(partial_all_harts.clone().max(), Some(usize::MAX - 4096));
-        assert!(partial_all_harts.is_sorted());
-
-        let nothing = HartMask::from_mask_base(0, 1000);
-        assert_eq!(nothing.iter().count(), 0);
-        assert_eq!(nothing.iter().last(), None);
-        assert_eq!(nothing.iter().min(), None);
-        assert_eq!(nothing.iter().max(), None);
-        assert!(nothing.iter().is_sorted());
-
-        let mask = HartMask::from_mask_base(0b101011, 1);
-        assert_eq!(mask.iter().count(), 4);
-        assert_eq!(mask.iter().last(), Some(6));
-        assert_eq!(mask.iter().min(), Some(1));
-        assert_eq!(mask.iter().max(), Some(6));
-        assert!(mask.iter().is_sorted());
-
-        let all_mask_bits_set = HartMask::from_mask_base(usize::MAX, 1000);
-        let last = 1000 + usize::BITS as usize - 1;
-        assert_eq!(all_mask_bits_set.iter().count(), usize::BITS as usize);
-        assert_eq!(all_mask_bits_set.iter().last(), Some(last));
-        assert_eq!(all_mask_bits_set.iter().min(), Some(1000));
-        assert_eq!(all_mask_bits_set.iter().max(), Some(last));
-        assert!(all_mask_bits_set.iter().is_sorted());
-    }
-
-    #[test]
-    fn rustsbi_counter_index_mask() {
-        let mask = CounterMask::from_mask_base(0b1, 400);
-        assert!(!mask.has_bit(0));
-        assert!(mask.has_bit(400));
-        assert!(!mask.has_bit(401));
-        let mask = CounterMask::from_mask_base(0b110, 500);
-        assert!(!mask.has_bit(0));
-        assert!(!mask.has_bit(500));
-        assert!(mask.has_bit(501));
-        assert!(mask.has_bit(502));
-        assert!(!mask.has_bit(500 + (usize::BITS as usize)));
-        let max_bit = 1 << (usize::BITS - 1);
-        let mask = CounterMask::from_mask_base(max_bit, 600);
-        assert!(mask.has_bit(600 + (usize::BITS as usize) - 1));
-        assert!(!mask.has_bit(600 + (usize::BITS as usize)));
-        let mask = CounterMask::from_mask_base(0b11, usize::MAX - 1);
-        assert!(!mask.has_bit(usize::MAX - 2));
-        assert!(mask.has_bit(usize::MAX - 1));
-        assert!(mask.has_bit(usize::MAX));
-        assert!(!mask.has_bit(0));
-        let mask = CounterMask::from_mask_base(0, usize::MAX);
-        let null_mask = CounterMask::from_mask_base(0, 0);
-        (0..=usize::BITS as usize).for_each(|i| {
-            assert!(mask.has_bit(i));
-            assert!(!null_mask.has_bit(i));
-        });
-        assert!(mask.has_bit(usize::MAX));
-    }
-
-    #[test]
-    fn rustsbi_mask_non_usize() {
-        assert_eq!(CounterMask::<i32>::IGNORE_MASK, -1);
-        assert_eq!(CounterMask::<i64>::IGNORE_MASK, -1);
-        assert_eq!(CounterMask::<i128>::IGNORE_MASK, -1);
-        assert_eq!(CounterMask::<u32>::IGNORE_MASK, u32::MAX);
-        assert_eq!(CounterMask::<u64>::IGNORE_MASK, u64::MAX);
-        assert_eq!(CounterMask::<u128>::IGNORE_MASK, u128::MAX);
-
-        assert_eq!(HartMask::<i32>::IGNORE_MASK, -1);
-        assert_eq!(HartMask::<i64>::IGNORE_MASK, -1);
-        assert_eq!(HartMask::<i128>::IGNORE_MASK, -1);
-        assert_eq!(HartMask::<u32>::IGNORE_MASK, u32::MAX);
-        assert_eq!(HartMask::<u64>::IGNORE_MASK, u64::MAX);
-        assert_eq!(HartMask::<u128>::IGNORE_MASK, u128::MAX);
-
-        assert_eq!(HartMask::<i32>::all(), HartMask::from_mask_base(0, -1));
-    }
-}
+// SBI return value and error codes.
+mod sbi_ret;
+pub use sbi_ret::{Error, SbiRegister, SbiRet, id::*};
+
+// Masks.
+mod mask_commons;
+pub use mask_commons::MaskError;
+
+mod counter_mask;
+mod hart_mask;
+mod trigger_mask;
+pub use counter_mask::CounterMask;
+pub use hart_mask::{HartIds, HartMask};
+pub use trigger_mask::TriggerMask;
+
+// Pointers.
+mod physical_slice;
+mod shared_physical_ptr;
+pub use physical_slice::Physical;
+pub use shared_physical_ptr::SharedPtr;

+ 95 - 0
library/sbi-spec/src/binary/counter_mask.rs

@@ -0,0 +1,95 @@
+use super::{mask_commons::has_bit, sbi_ret::SbiRegister};
+
+/// Counter index mask structure in SBI function calls for the `PMU` extension §11.
+#[repr(C)]
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+pub struct CounterMask<T = usize> {
+    counter_idx_mask: T,
+    counter_idx_base: T,
+}
+
+impl<T: SbiRegister> CounterMask<T> {
+    /// Special value to ignore the `mask`, and consider all `bit`s as set.
+    pub const IGNORE_MASK: T = T::FULL_MASK;
+
+    /// Construct a [CounterMask] from mask value and base counter index.
+    #[inline]
+    pub const fn from_mask_base(counter_idx_mask: T, counter_idx_base: T) -> Self {
+        Self {
+            counter_idx_mask,
+            counter_idx_base,
+        }
+    }
+
+    /// Gets the special value for ignoring the `mask` parameter.
+    #[inline]
+    pub const fn ignore_mask(&self) -> T {
+        Self::IGNORE_MASK
+    }
+
+    /// Returns `mask` and `base` parameters from the [CounterMask].
+    #[inline]
+    pub const fn into_inner(self) -> (T, T) {
+        (self.counter_idx_mask, self.counter_idx_base)
+    }
+}
+
+// FIXME: implement for T: SbiRegister once we can implement this using const traits.
+// Ref: https://rust-lang.github.io/rust-project-goals/2024h2/const-traits.html
+impl CounterMask<usize> {
+    /// Returns whether the [CounterMask] contains the provided `counter`.
+    #[inline]
+    pub const fn has_bit(self, counter: usize) -> bool {
+        has_bit(
+            self.counter_idx_mask,
+            self.counter_idx_base,
+            Self::IGNORE_MASK,
+            counter,
+        )
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn rustsbi_counter_index_mask() {
+        let mask = CounterMask::from_mask_base(0b1, 400);
+        assert!(!mask.has_bit(0));
+        assert!(mask.has_bit(400));
+        assert!(!mask.has_bit(401));
+        let mask = CounterMask::from_mask_base(0b110, 500);
+        assert!(!mask.has_bit(0));
+        assert!(!mask.has_bit(500));
+        assert!(mask.has_bit(501));
+        assert!(mask.has_bit(502));
+        assert!(!mask.has_bit(500 + (usize::BITS as usize)));
+        let max_bit = 1 << (usize::BITS - 1);
+        let mask = CounterMask::from_mask_base(max_bit, 600);
+        assert!(mask.has_bit(600 + (usize::BITS as usize) - 1));
+        assert!(!mask.has_bit(600 + (usize::BITS as usize)));
+        let mask = CounterMask::from_mask_base(0b11, usize::MAX - 1);
+        assert!(!mask.has_bit(usize::MAX - 2));
+        assert!(mask.has_bit(usize::MAX - 1));
+        assert!(mask.has_bit(usize::MAX));
+        assert!(!mask.has_bit(0));
+        let mask = CounterMask::from_mask_base(0, usize::MAX);
+        let null_mask = CounterMask::from_mask_base(0, 0);
+        (0..=usize::BITS as usize).for_each(|i| {
+            assert!(mask.has_bit(i));
+            assert!(!null_mask.has_bit(i));
+        });
+        assert!(mask.has_bit(usize::MAX));
+    }
+
+    #[test]
+    fn rustsbi_counter_mask_non_usize() {
+        assert_eq!(CounterMask::<i32>::IGNORE_MASK, -1);
+        assert_eq!(CounterMask::<i64>::IGNORE_MASK, -1);
+        assert_eq!(CounterMask::<i128>::IGNORE_MASK, -1);
+        assert_eq!(CounterMask::<u32>::IGNORE_MASK, u32::MAX);
+        assert_eq!(CounterMask::<u64>::IGNORE_MASK, u64::MAX);
+        assert_eq!(CounterMask::<u128>::IGNORE_MASK, u128::MAX);
+    }
+}

+ 525 - 0
library/sbi-spec/src/binary/hart_mask.rs

@@ -0,0 +1,525 @@
+use super::{
+    mask_commons::{MaskError, has_bit, valid_bit},
+    sbi_ret::SbiRegister,
+};
+
+/// Hart mask structure in SBI function calls.
+#[repr(C)]
+#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
+pub struct HartMask<T = usize> {
+    hart_mask: T,
+    hart_mask_base: T,
+}
+
+impl<T: SbiRegister> HartMask<T> {
+    /// Special value to ignore the `mask`, and consider all `bit`s as set.
+    pub const IGNORE_MASK: T = T::FULL_MASK;
+
+    /// Construct a [HartMask] from mask value and base hart id.
+    #[inline]
+    pub const fn from_mask_base(hart_mask: T, hart_mask_base: T) -> Self {
+        Self {
+            hart_mask,
+            hart_mask_base,
+        }
+    }
+
+    /// Construct a [HartMask] that selects all available harts on the current environment.
+    ///
+    /// According to the RISC-V SBI Specification, `hart_mask_base` can be set to `-1` (i.e. `usize::MAX`)
+    /// to indicate that `hart_mask` shall be ignored and all available harts must be considered.
+    /// In case of this function in the `sbi-spec` crate, we fill in `usize::MAX` in `hart_mask_base`
+    /// parameter to match the RISC-V SBI standard, while choosing 0 as the ignored `hart_mask` value.
+    #[inline]
+    pub const fn all() -> Self {
+        Self {
+            hart_mask: T::ZERO,
+            hart_mask_base: T::FULL_MASK,
+        }
+    }
+
+    /// Gets the special value for ignoring the `mask` parameter.
+    #[inline]
+    pub const fn ignore_mask(&self) -> T {
+        Self::IGNORE_MASK
+    }
+
+    /// Returns `mask` and `base` parameters from the [HartMask].
+    #[inline]
+    pub const fn into_inner(self) -> (T, T) {
+        (self.hart_mask, self.hart_mask_base)
+    }
+}
+
+// FIXME: implement for T: SbiRegister once we can implement this using const traits.
+// Ref: https://rust-lang.github.io/rust-project-goals/2024h2/const-traits.html
+impl HartMask<usize> {
+    /// Returns whether the [HartMask] contains the provided `hart_id`.
+    #[inline]
+    pub const fn has_bit(self, hart_id: usize) -> bool {
+        has_bit(
+            self.hart_mask,
+            self.hart_mask_base,
+            Self::IGNORE_MASK,
+            hart_id,
+        )
+    }
+
+    /// Insert a hart id into this [HartMask].
+    ///
+    /// Returns error when `hart_id` is invalid.
+    #[inline]
+    pub const fn insert(&mut self, hart_id: usize) -> Result<(), MaskError> {
+        if self.hart_mask_base == Self::IGNORE_MASK {
+            Ok(())
+        } else if valid_bit(self.hart_mask_base, hart_id) {
+            self.hart_mask |= 1usize << (hart_id - self.hart_mask_base);
+            Ok(())
+        } else {
+            Err(MaskError::InvalidBit)
+        }
+    }
+
+    /// Remove a hart id from this [HartMask].
+    ///
+    /// Returns error when `hart_id` is invalid, or it has been ignored.
+    #[inline]
+    pub const fn remove(&mut self, hart_id: usize) -> Result<(), MaskError> {
+        if self.hart_mask_base == Self::IGNORE_MASK {
+            Err(MaskError::Ignored)
+        } else if valid_bit(self.hart_mask_base, hart_id) {
+            self.hart_mask &= !(1usize << (hart_id - self.hart_mask_base));
+            Ok(())
+        } else {
+            Err(MaskError::InvalidBit)
+        }
+    }
+
+    /// Returns [HartIds] of self.
+    #[inline]
+    pub const fn iter(&self) -> HartIds {
+        HartIds {
+            inner: match self.hart_mask_base {
+                Self::IGNORE_MASK => UnvisitedMask::Range(0, usize::MAX),
+                _ => UnvisitedMask::MaskBase(self.hart_mask, self.hart_mask_base),
+            },
+        }
+    }
+}
+
+impl IntoIterator for HartMask {
+    type Item = usize;
+
+    type IntoIter = HartIds;
+
+    #[inline]
+    fn into_iter(self) -> Self::IntoIter {
+        self.iter()
+    }
+}
+
+/// Iterator structure for `HartMask`.
+///
+/// It will iterate hart id from low to high.
+#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
+pub struct HartIds {
+    inner: UnvisitedMask,
+}
+
+#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
+enum UnvisitedMask {
+    MaskBase(usize, usize),
+    Range(usize, usize),
+}
+
+impl Iterator for HartIds {
+    type Item = usize;
+
+    #[inline]
+    fn next(&mut self) -> Option<Self::Item> {
+        match &mut self.inner {
+            UnvisitedMask::MaskBase(0, _base) => None,
+            UnvisitedMask::MaskBase(unvisited_mask, base) => {
+                let low_bit = unvisited_mask.trailing_zeros();
+                let hart_id = usize::try_from(low_bit).unwrap() + *base;
+                *unvisited_mask &= !(1usize << low_bit);
+                Some(hart_id)
+            }
+            UnvisitedMask::Range(start, end) => {
+                assert!(start <= end);
+                if *start < *end {
+                    let ans = *start;
+                    *start += 1;
+                    Some(ans)
+                } else {
+                    None
+                }
+            }
+        }
+    }
+
+    #[inline]
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        match self.inner {
+            UnvisitedMask::MaskBase(unvisited_mask, _base) => {
+                let exact_popcnt = usize::try_from(unvisited_mask.count_ones()).unwrap();
+                (exact_popcnt, Some(exact_popcnt))
+            }
+            UnvisitedMask::Range(start, end) => {
+                assert!(start <= end);
+                let exact_num_harts = end - start;
+                (exact_num_harts, Some(exact_num_harts))
+            }
+        }
+    }
+
+    #[inline]
+    fn count(self) -> usize {
+        self.size_hint().0
+    }
+
+    #[inline]
+    fn last(mut self) -> Option<Self::Item> {
+        self.next_back()
+    }
+
+    #[inline]
+    fn min(mut self) -> Option<Self::Item> {
+        self.next()
+    }
+
+    #[inline]
+    fn max(mut self) -> Option<Self::Item> {
+        self.next_back()
+    }
+
+    #[inline]
+    fn is_sorted(self) -> bool {
+        true
+    }
+
+    // TODO: implement fn advance_by once it's stabilized: https://github.com/rust-lang/rust/issues/77404
+    // #[inline]
+    // fn advance_by(&mut self, n: usize) -> Result<(), core::num::NonZero<usize>> { ... }
+}
+
+impl DoubleEndedIterator for HartIds {
+    #[inline]
+    fn next_back(&mut self) -> Option<Self::Item> {
+        match &mut self.inner {
+            UnvisitedMask::MaskBase(0, _base) => None,
+            UnvisitedMask::MaskBase(unvisited_mask, base) => {
+                let high_bit = unvisited_mask.leading_zeros();
+                let hart_id = usize::try_from(usize::BITS - high_bit - 1).unwrap() + *base;
+                *unvisited_mask &= !(1usize << (usize::BITS - high_bit - 1));
+                Some(hart_id)
+            }
+            UnvisitedMask::Range(start, end) => {
+                assert!(start <= end);
+                if *start < *end {
+                    let ans = *end;
+                    *end -= 1;
+                    Some(ans)
+                } else {
+                    None
+                }
+            }
+        }
+    }
+
+    // TODO: implement advance_back_by once stabilized.
+    // #[inline]
+    // fn advance_back_by(&mut self, n: usize) -> Result<(), core::num::NonZero<usize>> { ... }
+}
+
+impl ExactSizeIterator for HartIds {}
+
+impl core::iter::FusedIterator for HartIds {}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn rustsbi_hart_mask() {
+        let mask = HartMask::from_mask_base(0b1, 400);
+        assert!(!mask.has_bit(0));
+        assert!(mask.has_bit(400));
+        assert!(!mask.has_bit(401));
+        let mask = HartMask::from_mask_base(0b110, 500);
+        assert!(!mask.has_bit(0));
+        assert!(!mask.has_bit(500));
+        assert!(mask.has_bit(501));
+        assert!(mask.has_bit(502));
+        assert!(!mask.has_bit(500 + (usize::BITS as usize)));
+        let max_bit = 1 << (usize::BITS - 1);
+        let mask = HartMask::from_mask_base(max_bit, 600);
+        assert!(mask.has_bit(600 + (usize::BITS as usize) - 1));
+        assert!(!mask.has_bit(600 + (usize::BITS as usize)));
+        let mask = HartMask::from_mask_base(0b11, usize::MAX - 1);
+        assert!(!mask.has_bit(usize::MAX - 2));
+        assert!(mask.has_bit(usize::MAX - 1));
+        assert!(mask.has_bit(usize::MAX));
+        assert!(!mask.has_bit(0));
+        // hart_mask_base == usize::MAX is special, it means hart_mask should be ignored
+        // and this hart mask contains all harts available
+        let mask = HartMask::from_mask_base(0, usize::MAX);
+        for i in 0..5 {
+            assert!(mask.has_bit(i));
+        }
+        assert!(mask.has_bit(usize::MAX));
+
+        let mut mask = HartMask::from_mask_base(0, 1);
+        assert!(!mask.has_bit(1));
+        assert!(mask.insert(1).is_ok());
+        assert!(mask.has_bit(1));
+        assert!(mask.remove(1).is_ok());
+        assert!(!mask.has_bit(1));
+    }
+
+    #[test]
+    fn rustsbi_hart_ids_iterator() {
+        let mask = HartMask::from_mask_base(0b101011, 1);
+        // Test the `next` method of `HartIds` structure.
+        let mut hart_ids = mask.iter();
+        assert_eq!(hart_ids.next(), Some(1));
+        assert_eq!(hart_ids.next(), Some(2));
+        assert_eq!(hart_ids.next(), Some(4));
+        assert_eq!(hart_ids.next(), Some(6));
+        assert_eq!(hart_ids.next(), None);
+        // `HartIds` structures are fused, meaning they return `None` forever once iteration finished.
+        assert_eq!(hart_ids.next(), None);
+
+        // Test `for` loop on mask (`HartMask`) as `IntoIterator`.
+        let mut ans = [0; 4];
+        let mut idx = 0;
+        for hart_id in mask {
+            ans[idx] = hart_id;
+            idx += 1;
+        }
+        assert_eq!(ans, [1, 2, 4, 6]);
+
+        // Test `Iterator` methods on `HartIds`.
+        let mut hart_ids = mask.iter();
+        assert_eq!(hart_ids.size_hint(), (4, Some(4)));
+        let _ = hart_ids.next();
+        assert_eq!(hart_ids.size_hint(), (3, Some(3)));
+        let _ = hart_ids.next();
+        let _ = hart_ids.next();
+        assert_eq!(hart_ids.size_hint(), (1, Some(1)));
+        let _ = hart_ids.next();
+        assert_eq!(hart_ids.size_hint(), (0, Some(0)));
+        let _ = hart_ids.next();
+        assert_eq!(hart_ids.size_hint(), (0, Some(0)));
+
+        let mut hart_ids = mask.iter();
+        assert_eq!(hart_ids.count(), 4);
+        let _ = hart_ids.next();
+        assert_eq!(hart_ids.count(), 3);
+        let _ = hart_ids.next();
+        let _ = hart_ids.next();
+        let _ = hart_ids.next();
+        assert_eq!(hart_ids.count(), 0);
+        let _ = hart_ids.next();
+        assert_eq!(hart_ids.count(), 0);
+
+        let hart_ids = mask.iter();
+        assert_eq!(hart_ids.last(), Some(6));
+
+        let mut hart_ids = mask.iter();
+        assert_eq!(hart_ids.nth(2), Some(4));
+        let mut hart_ids = mask.iter();
+        assert_eq!(hart_ids.nth(0), Some(1));
+
+        let mut iter = mask.iter().step_by(2);
+        assert_eq!(iter.next(), Some(1));
+        assert_eq!(iter.next(), Some(4));
+        assert_eq!(iter.next(), None);
+
+        let mask_2 = HartMask::from_mask_base(0b1001101, 64);
+        let mut iter = mask.iter().chain(mask_2);
+        assert_eq!(iter.next(), Some(1));
+        assert_eq!(iter.next(), Some(2));
+        assert_eq!(iter.next(), Some(4));
+        assert_eq!(iter.next(), Some(6));
+        assert_eq!(iter.next(), Some(64));
+        assert_eq!(iter.next(), Some(66));
+        assert_eq!(iter.next(), Some(67));
+        assert_eq!(iter.next(), Some(70));
+        assert_eq!(iter.next(), None);
+
+        let mut iter = mask.iter().zip(mask_2);
+        assert_eq!(iter.next(), Some((1, 64)));
+        assert_eq!(iter.next(), Some((2, 66)));
+        assert_eq!(iter.next(), Some((4, 67)));
+        assert_eq!(iter.next(), Some((6, 70)));
+        assert_eq!(iter.next(), None);
+
+        fn to_plic_context_id(hart_id_machine: usize) -> usize {
+            hart_id_machine * 2
+        }
+        let mut iter = mask.iter().map(to_plic_context_id);
+        assert_eq!(iter.next(), Some(2));
+        assert_eq!(iter.next(), Some(4));
+        assert_eq!(iter.next(), Some(8));
+        assert_eq!(iter.next(), Some(12));
+        assert_eq!(iter.next(), None);
+
+        let mut channel_received = [0; 4];
+        let mut idx = 0;
+        let mut channel_send = |hart_id| {
+            channel_received[idx] = hart_id;
+            idx += 1;
+        };
+        mask.iter().for_each(|value| channel_send(value));
+        assert_eq!(channel_received, [1, 2, 4, 6]);
+
+        let is_in_cluster_1 = |hart_id: &usize| *hart_id >= 4 && *hart_id < 7;
+        let mut iter = mask.iter().filter(is_in_cluster_1);
+        assert_eq!(iter.next(), Some(4));
+        assert_eq!(iter.next(), Some(6));
+        assert_eq!(iter.next(), None);
+
+        let if_in_cluster_1_get_plic_context_id = |hart_id: usize| {
+            if hart_id >= 4 && hart_id < 7 {
+                Some(hart_id * 2)
+            } else {
+                None
+            }
+        };
+        let mut iter = mask.iter().filter_map(if_in_cluster_1_get_plic_context_id);
+        assert_eq!(iter.next(), Some(8));
+        assert_eq!(iter.next(), Some(12));
+        assert_eq!(iter.next(), None);
+
+        let mut iter = mask.iter().enumerate();
+        assert_eq!(iter.next(), Some((0, 1)));
+        assert_eq!(iter.next(), Some((1, 2)));
+        assert_eq!(iter.next(), Some((2, 4)));
+        assert_eq!(iter.next(), Some((3, 6)));
+        assert_eq!(iter.next(), None);
+        let mut ans = [(0, 0); 4];
+        let mut idx = 0;
+        for (i, hart_id) in mask.iter().enumerate() {
+            ans[idx] = (i, hart_id);
+            idx += 1;
+        }
+        assert_eq!(ans, [(0, 1), (1, 2), (2, 4), (3, 6)]);
+
+        let mut iter = mask.iter().peekable();
+        assert_eq!(iter.peek(), Some(&1));
+        assert_eq!(iter.next(), Some(1));
+        assert_eq!(iter.peek(), Some(&2));
+        assert_eq!(iter.next(), Some(2));
+        assert_eq!(iter.peek(), Some(&4));
+        assert_eq!(iter.next(), Some(4));
+        assert_eq!(iter.peek(), Some(&6));
+        assert_eq!(iter.next(), Some(6));
+        assert_eq!(iter.peek(), None);
+        assert_eq!(iter.next(), None);
+
+        // TODO: other iterator tests.
+
+        assert!(mask.iter().is_sorted());
+        assert!(mask.iter().is_sorted_by(|a, b| a <= b));
+
+        // Reverse iterator as `DoubleEndedIterator`.
+        let mut iter = mask.iter().rev();
+        assert_eq!(iter.next(), Some(6));
+        assert_eq!(iter.next(), Some(4));
+        assert_eq!(iter.next(), Some(2));
+        assert_eq!(iter.next(), Some(1));
+        assert_eq!(iter.next(), None);
+
+        // Special iterator values.
+        let nothing = HartMask::from_mask_base(0, 1000);
+        assert!(nothing.iter().eq([]));
+
+        let all_mask_bits_set = HartMask::from_mask_base(usize::MAX, 1000);
+        let range = 1000..(1000 + usize::BITS as usize);
+        assert!(all_mask_bits_set.iter().eq(range));
+
+        let all_harts = HartMask::all();
+        let mut iter = all_harts.iter();
+        assert_eq!(iter.size_hint(), (usize::MAX, Some(usize::MAX)));
+        // Don't use `Iterator::eq` here; it would literally run `Iterator::try_for_each` from 0 to usize::MAX
+        // which will cost us forever to run the test.
+        assert_eq!(iter.next(), Some(0));
+        assert_eq!(iter.size_hint(), (usize::MAX - 1, Some(usize::MAX - 1)));
+        assert_eq!(iter.next(), Some(1));
+        assert_eq!(iter.next(), Some(2));
+        // skip 500 elements
+        let _ = iter.nth(500 - 1);
+        assert_eq!(iter.next(), Some(503));
+        assert_eq!(iter.size_hint(), (usize::MAX - 504, Some(usize::MAX - 504)));
+        assert_eq!(iter.next_back(), Some(usize::MAX));
+        assert_eq!(iter.next_back(), Some(usize::MAX - 1));
+        assert_eq!(iter.size_hint(), (usize::MAX - 506, Some(usize::MAX - 506)));
+
+        // A common usage of `HartMask::all`, we assume that this platform filters out hart 0..=3.
+        let environment_available_hart_ids = 4..128;
+        // `hart_mask_iter` contains 64..=usize::MAX.
+        let hart_mask_iter = all_harts.iter().skip(64);
+        let filtered_iter = environment_available_hart_ids.filter(|&x| {
+            hart_mask_iter
+                .clone()
+                .find(|&y| y >= x)
+                .map_or(false, |y| y == x)
+        });
+        assert!(filtered_iter.eq(64..128));
+
+        // The following operations should have O(1) complexity.
+        let all_harts = HartMask::all();
+        assert_eq!(all_harts.iter().count(), usize::MAX);
+        assert_eq!(all_harts.iter().last(), Some(usize::MAX));
+        assert_eq!(all_harts.iter().min(), Some(0));
+        assert_eq!(all_harts.iter().max(), Some(usize::MAX));
+        assert!(all_harts.iter().is_sorted());
+
+        let partial_all_harts = {
+            let mut ans = HartMask::all().iter();
+            let _ = ans.nth(65536 - 1);
+            let _ = ans.nth_back(4096 - 1);
+            ans
+        };
+        assert_eq!(partial_all_harts.clone().count(), usize::MAX - 65536 - 4096);
+        assert_eq!(partial_all_harts.clone().last(), Some(usize::MAX - 4096));
+        assert_eq!(partial_all_harts.clone().min(), Some(65536));
+        assert_eq!(partial_all_harts.clone().max(), Some(usize::MAX - 4096));
+        assert!(partial_all_harts.is_sorted());
+
+        let nothing = HartMask::from_mask_base(0, 1000);
+        assert_eq!(nothing.iter().count(), 0);
+        assert_eq!(nothing.iter().last(), None);
+        assert_eq!(nothing.iter().min(), None);
+        assert_eq!(nothing.iter().max(), None);
+        assert!(nothing.iter().is_sorted());
+
+        let mask = HartMask::from_mask_base(0b101011, 1);
+        assert_eq!(mask.iter().count(), 4);
+        assert_eq!(mask.iter().last(), Some(6));
+        assert_eq!(mask.iter().min(), Some(1));
+        assert_eq!(mask.iter().max(), Some(6));
+        assert!(mask.iter().is_sorted());
+
+        let all_mask_bits_set = HartMask::from_mask_base(usize::MAX, 1000);
+        let last = 1000 + usize::BITS as usize - 1;
+        assert_eq!(all_mask_bits_set.iter().count(), usize::BITS as usize);
+        assert_eq!(all_mask_bits_set.iter().last(), Some(last));
+        assert_eq!(all_mask_bits_set.iter().min(), Some(1000));
+        assert_eq!(all_mask_bits_set.iter().max(), Some(last));
+        assert!(all_mask_bits_set.iter().is_sorted());
+    }
+
+    #[test]
+    fn rustsbi_hart_mask_non_usize() {
+        assert_eq!(HartMask::<i32>::IGNORE_MASK, -1);
+        assert_eq!(HartMask::<i64>::IGNORE_MASK, -1);
+        assert_eq!(HartMask::<i128>::IGNORE_MASK, -1);
+        assert_eq!(HartMask::<u32>::IGNORE_MASK, u32::MAX);
+        assert_eq!(HartMask::<u64>::IGNORE_MASK, u64::MAX);
+        assert_eq!(HartMask::<u128>::IGNORE_MASK, u128::MAX);
+
+        assert_eq!(HartMask::<i32>::all(), HartMask::from_mask_base(0, -1));
+    }
+}

+ 45 - 0
library/sbi-spec/src/binary/mask_commons.rs

@@ -0,0 +1,45 @@
+//! Common SBI mask operations and structures.
+
+/// Check if the implementation can contains the provided `bit`.
+#[inline]
+pub(crate) const fn valid_bit(base: usize, bit: usize) -> bool {
+    if bit < base {
+        // invalid index, under minimum range.
+        false
+    } else if (bit - base) >= usize::BITS as usize {
+        // invalid index, over max range.
+        false
+    } else {
+        true
+    }
+}
+
+/// Check if the implementation contains the provided `bit`.
+///
+/// ## Parameters
+///
+/// - `mask`: bitmask defining the range of bits.
+/// - `base`: the starting bit index. (default: `0`)
+/// - `ignore`: if `base` is equal to this value, ignore the `mask` parameter, and consider all `bit`s set.
+/// - `bit`: the bit index to check for membership in the `mask`.
+#[inline]
+pub(crate) const fn has_bit(mask: usize, base: usize, ignore: usize, bit: usize) -> bool {
+    if base == ignore {
+        // ignore the `mask`, consider all `bit`s as set.
+        true
+    } else if !valid_bit(base, bit) {
+        false
+    } else {
+        // index is in range, check if it is set in the mask.
+        mask & (1 << (bit - base)) != 0
+    }
+}
+
+/// Error of mask modification.
+#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
+pub enum MaskError {
+    /// This mask has been ignored.
+    Ignored,
+    /// Request bit is invalid.
+    InvalidBit,
+}

+ 55 - 0
library/sbi-spec/src/binary/physical_slice.rs

@@ -0,0 +1,55 @@
+use core::marker::PhantomData;
+
+/// Physical slice wrapper with type annotation.
+///
+/// This struct wraps slices in RISC-V physical memory by low and high part of the
+/// physical base address as well as its length. It is usually used by SBI extensions
+/// as parameter types to pass base address and length parameters on physical memory
+/// other than a virtual one.
+///
+/// Generic parameter `P` represents a hint of how this physical slice would be used.
+/// For example, `Physical<&[u8]>` represents an immutable reference to physical byte slice,
+/// while `Physical<&mut [u8]>` represents a mutable one.
+///
+/// An SBI implementation should load or store memory using both `phys_addr_lo` and
+/// `phys_addr_hi` combined as base address. A supervisor program (kernels etc.)
+/// should provide continuous physical memory, wrapping its reference using this structure
+/// before passing into SBI runtime.
+#[derive(Clone, Copy)]
+pub struct Physical<P> {
+    num_bytes: usize,
+    phys_addr_lo: usize,
+    phys_addr_hi: usize,
+    _marker: PhantomData<P>,
+}
+
+impl<P> Physical<P> {
+    /// Create a physical memory slice by length and physical address.
+    #[inline]
+    pub const fn new(num_bytes: usize, phys_addr_lo: usize, phys_addr_hi: usize) -> Self {
+        Self {
+            num_bytes,
+            phys_addr_lo,
+            phys_addr_hi,
+            _marker: core::marker::PhantomData,
+        }
+    }
+
+    /// Returns length of the physical memory slice.
+    #[inline]
+    pub const fn num_bytes(&self) -> usize {
+        self.num_bytes
+    }
+
+    /// Returns low-part base address of physical memory slice.
+    #[inline]
+    pub const fn phys_addr_lo(&self) -> usize {
+        self.phys_addr_lo
+    }
+
+    /// Returns high-part base address of physical memory slice.
+    #[inline]
+    pub const fn phys_addr_hi(&self) -> usize {
+        self.phys_addr_hi
+    }
+}

+ 1146 - 0
library/sbi-spec/src/binary/sbi_ret.rs

@@ -0,0 +1,1146 @@
+/// SBI functions return type.
+///
+/// > SBI functions must return a pair of values in a0 and a1,
+/// > with a0 returning an error code.
+/// > This is analogous to returning the C structure `SbiRet`.
+///
+/// Note: if this structure is used in function return on conventional
+/// Rust code, it would not require pinning memory representation as
+/// extern C. The `repr(C)` is set in case that some users want to use
+/// this structure in FFI code.
+#[derive(Clone, Copy, PartialEq, Eq)]
+#[repr(C)]
+pub struct SbiRet<T = usize> {
+    /// Error number.
+    pub error: T,
+    /// Result value.
+    pub value: T,
+}
+
+/// Standard RISC-V SBI error IDs in `usize`.
+pub mod id {
+    use super::SbiRegister;
+
+    /// SBI success state return value.
+    #[doc(alias = "SBI_SUCCESS")]
+    pub const RET_SUCCESS: usize = <usize as SbiRegister>::RET_SUCCESS;
+    /// Error for SBI call failed for unknown reasons.
+    #[doc(alias = "SBI_ERR_FAILED")]
+    pub const RET_ERR_FAILED: usize = <usize as SbiRegister>::RET_ERR_FAILED;
+    /// Error for target operation not supported.
+    #[doc(alias = "SBI_ERR_NOT_SUPPORTED")]
+    pub const RET_ERR_NOT_SUPPORTED: usize = <usize as SbiRegister>::RET_ERR_NOT_SUPPORTED;
+    /// Error for invalid parameter.
+    #[doc(alias = "SBI_ERR_INVALID_PARAM")]
+    pub const RET_ERR_INVALID_PARAM: usize = <usize as SbiRegister>::RET_ERR_INVALID_PARAM;
+    /// Error for denied.
+    #[doc(alias = "SBI_ERR_DENIED")]
+    pub const RET_ERR_DENIED: usize = <usize as SbiRegister>::RET_ERR_DENIED;
+    /// Error for invalid address.
+    #[doc(alias = "SBI_ERR_INVALID_ADDRESS")]
+    pub const RET_ERR_INVALID_ADDRESS: usize = <usize as SbiRegister>::RET_ERR_INVALID_ADDRESS;
+    /// Error for resource already available.
+    #[doc(alias = "SBI_ERR_ALREADY_AVAILABLE")]
+    pub const RET_ERR_ALREADY_AVAILABLE: usize = <usize as SbiRegister>::RET_ERR_ALREADY_AVAILABLE;
+    /// Error for resource already started.
+    #[doc(alias = "SBI_ERR_ALREADY_STARTED")]
+    pub const RET_ERR_ALREADY_STARTED: usize = <usize as SbiRegister>::RET_ERR_ALREADY_STARTED;
+    /// Error for resource already stopped.
+    #[doc(alias = "SBI_ERR_ALREADY_STOPPED")]
+    pub const RET_ERR_ALREADY_STOPPED: usize = <usize as SbiRegister>::RET_ERR_ALREADY_STOPPED;
+    /// Error for shared memory not available.
+    #[doc(alias = "SBI_ERR_NO_SHMEM")]
+    pub const RET_ERR_NO_SHMEM: usize = <usize as SbiRegister>::RET_ERR_NO_SHMEM;
+    /// Error for invalid state.
+    #[doc(alias = "SBI_ERR_INVALID_STATE")]
+    pub const RET_ERR_INVALID_STATE: usize = <usize as SbiRegister>::RET_ERR_INVALID_STATE;
+    /// Error for bad or invalid range.
+    #[doc(alias = "SBI_ERR_BAD_RANGE")]
+    pub const RET_ERR_BAD_RANGE: usize = <usize as SbiRegister>::RET_ERR_BAD_RANGE;
+    /// Error for failed due to timeout.
+    #[doc(alias = "SBI_ERR_TIMEOUT")]
+    pub const RET_ERR_TIMEOUT: usize = <usize as SbiRegister>::RET_ERR_TIMEOUT;
+    /// Error for input or output error.
+    #[doc(alias = "SBI_ERR_IO")]
+    pub const RET_ERR_IO: usize = <usize as SbiRegister>::RET_ERR_IO;
+    /// Error for denied or not allowed due to lock status.
+    #[doc(alias = "SBI_ERR_DENIED_LOCKED")]
+    pub const RET_ERR_DENIED_LOCKED: usize = <usize as SbiRegister>::RET_ERR_DENIED_LOCKED;
+    // ^^ Note: remember to add a test case in `rustsbi_sbi_ret_constructors` in this file,
+    // and `test_binary` in lib.rs after adding an error number!
+}
+// Use each constants in `id` module, so that any `match` operations will not treat constant
+// names (`RET_ERR_*`) as newly defined variable names.
+use id::*;
+
+/// Data type of register that can be passed to the RISC-V SBI ABI.
+///
+/// This trait defines the requirements for types that are used as the underlying
+/// representation for both the `value` and `error` fields in the `SbiRet` structure.
+/// In most cases, this trait is implemented for primitive integer types (e.g., `usize`),
+/// but it can also be implemented for other types that satisfy the constraints.
+///
+/// # Examples
+///
+/// Implemented automatically for all types that satisfy `Copy`, `Eq`, and `Debug`.
+pub trait SbiRegister: Copy + Eq + Ord + core::fmt::Debug {
+    /// SBI success state return value.
+    const RET_SUCCESS: Self;
+    /// Error for SBI call failed for unknown reasons.
+    const RET_ERR_FAILED: Self;
+    /// Error for target operation not supported.
+    const RET_ERR_NOT_SUPPORTED: Self;
+    /// Error for invalid parameter.
+    const RET_ERR_INVALID_PARAM: Self;
+    /// Error for denied.
+    const RET_ERR_DENIED: Self;
+    /// Error for invalid address.
+    const RET_ERR_INVALID_ADDRESS: Self;
+    /// Error for resource already available.
+    const RET_ERR_ALREADY_AVAILABLE: Self;
+    /// Error for resource already started.
+    const RET_ERR_ALREADY_STARTED: Self;
+    /// Error for resource already stopped.
+    const RET_ERR_ALREADY_STOPPED: Self;
+    /// Error for shared memory not available.
+    const RET_ERR_NO_SHMEM: Self;
+    /// Error for invalid state.
+    const RET_ERR_INVALID_STATE: Self;
+    /// Error for bad or invalid range.
+    const RET_ERR_BAD_RANGE: Self;
+    /// Error for failed due to timeout.
+    const RET_ERR_TIMEOUT: Self;
+    /// Error for input or output error.
+    const RET_ERR_IO: Self;
+    /// Error for denied or not allowed due to lock status.
+    const RET_ERR_DENIED_LOCKED: Self;
+
+    /// Zero value for this type; this is used on `value` fields once `SbiRet` returns an error.
+    const ZERO: Self;
+    /// Full-ones value for this type; this is used on SBI mask structures like `CounterMask`
+    /// and `HartMask`.
+    const FULL_MASK: Self;
+
+    /// Converts an `SbiRet` of this type to a `Result` of self and `Error`.
+    fn into_result(ret: SbiRet<Self>) -> Result<Self, Error<Self>>;
+}
+
+macro_rules! impl_sbi_register {
+    ($ty:ty, $signed:ty) => {
+        impl SbiRegister for $ty {
+            const RET_SUCCESS: Self = 0;
+            const RET_ERR_FAILED: Self = -1 as $signed as $ty;
+            const RET_ERR_NOT_SUPPORTED: Self = -2 as $signed as $ty;
+            const RET_ERR_INVALID_PARAM: Self = -3 as $signed as $ty;
+            const RET_ERR_DENIED: Self = -4 as $signed as $ty;
+            const RET_ERR_INVALID_ADDRESS: Self = -5 as $signed as $ty;
+            const RET_ERR_ALREADY_AVAILABLE: Self = -6 as $signed as $ty;
+            const RET_ERR_ALREADY_STARTED: Self = -7 as $signed as $ty;
+            const RET_ERR_ALREADY_STOPPED: Self = -8 as $signed as $ty;
+            const RET_ERR_NO_SHMEM: Self = -9 as $signed as $ty;
+            const RET_ERR_INVALID_STATE: Self = -10 as $signed as $ty;
+            const RET_ERR_BAD_RANGE: Self = -11 as $signed as $ty;
+            const RET_ERR_TIMEOUT: Self = -12 as $signed as $ty;
+            const RET_ERR_IO: Self = -13 as $signed as $ty;
+            const RET_ERR_DENIED_LOCKED: Self = -14 as $signed as $ty;
+            const ZERO: Self = 0;
+            const FULL_MASK: Self = !0;
+
+            fn into_result(ret: SbiRet<Self>) -> Result<Self, Error<Self>> {
+                match ret.error {
+                    Self::RET_SUCCESS => Ok(ret.value),
+                    Self::RET_ERR_FAILED => Err(Error::Failed),
+                    Self::RET_ERR_NOT_SUPPORTED => Err(Error::NotSupported),
+                    Self::RET_ERR_INVALID_PARAM => Err(Error::InvalidParam),
+                    Self::RET_ERR_DENIED => Err(Error::Denied),
+                    Self::RET_ERR_INVALID_ADDRESS => Err(Error::InvalidAddress),
+                    Self::RET_ERR_ALREADY_AVAILABLE => Err(Error::AlreadyAvailable),
+                    Self::RET_ERR_ALREADY_STARTED => Err(Error::AlreadyStarted),
+                    Self::RET_ERR_ALREADY_STOPPED => Err(Error::AlreadyStopped),
+                    Self::RET_ERR_NO_SHMEM => Err(Error::NoShmem),
+                    Self::RET_ERR_INVALID_STATE => Err(Error::InvalidState),
+                    Self::RET_ERR_BAD_RANGE => Err(Error::BadRange),
+                    Self::RET_ERR_TIMEOUT => Err(Error::Timeout),
+                    Self::RET_ERR_IO => Err(Error::Io),
+                    Self::RET_ERR_DENIED_LOCKED => Err(Error::DeniedLocked),
+                    unknown => Err(Error::Custom(unknown as _)),
+                }
+            }
+        }
+    };
+}
+
+impl_sbi_register!(usize, isize);
+impl_sbi_register!(isize, isize);
+impl_sbi_register!(u32, i32);
+impl_sbi_register!(i32, i32);
+impl_sbi_register!(u64, i64);
+impl_sbi_register!(i64, i64);
+impl_sbi_register!(u128, i128);
+impl_sbi_register!(i128, i128);
+
+impl<T: SbiRegister + core::fmt::LowerHex> core::fmt::Debug for SbiRet<T> {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+        match T::into_result(*self) {
+            Ok(value) => write!(f, "{:?}", value),
+            Err(err) => match err {
+                Error::Failed => write!(f, "<SBI call failed>"),
+                Error::NotSupported => write!(f, "<SBI feature not supported>"),
+                Error::InvalidParam => write!(f, "<SBI invalid parameter>"),
+                Error::Denied => write!(f, "<SBI denied>"),
+                Error::InvalidAddress => write!(f, "<SBI invalid address>"),
+                Error::AlreadyAvailable => write!(f, "<SBI already available>"),
+                Error::AlreadyStarted => write!(f, "<SBI already started>"),
+                Error::AlreadyStopped => write!(f, "<SBI already stopped>"),
+                Error::NoShmem => write!(f, "<SBI shared memory not available>"),
+                Error::InvalidState => write!(f, "<SBI invalid state>"),
+                Error::BadRange => write!(f, "<SBI bad range>"),
+                Error::Timeout => write!(f, "<SBI timeout>"),
+                Error::Io => write!(f, "<SBI input/output error>"),
+                Error::DeniedLocked => write!(f, "<SBI denied due to locked status>"),
+                Error::Custom(unknown) => write!(f, "[SBI Unknown error: {:#x}]", unknown),
+            },
+        }
+    }
+}
+
+/// RISC-V SBI error in enumeration.
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum Error<T = usize> {
+    /// Error for SBI call failed for unknown reasons.
+    Failed,
+    /// Error for target operation not supported.
+    NotSupported,
+    /// Error for invalid parameter.
+    InvalidParam,
+    /// Error for denied.
+    Denied,
+    /// Error for invalid address.
+    InvalidAddress,
+    /// Error for resource already available.
+    AlreadyAvailable,
+    /// Error for resource already started.
+    AlreadyStarted,
+    /// Error for resource already stopped.
+    AlreadyStopped,
+    /// Error for shared memory not available.
+    NoShmem,
+    /// Error for invalid state.
+    InvalidState,
+    /// Error for bad or invalid range.
+    BadRange,
+    /// Error for failed due to timeout.
+    Timeout,
+    /// Error for input or output error.
+    Io,
+    /// Error for denied or not allowed due to lock status.
+    DeniedLocked,
+    /// Custom error code.
+    Custom(T),
+}
+
+impl<T: SbiRegister> SbiRet<T> {
+    /// Returns success SBI state with given `value`.
+    #[inline]
+    pub const fn success(value: T) -> Self {
+        Self {
+            error: T::RET_SUCCESS,
+            value,
+        }
+    }
+
+    /// The SBI call request failed for unknown reasons.
+    #[inline]
+    pub const fn failed() -> Self {
+        Self {
+            error: T::RET_ERR_FAILED,
+            value: T::ZERO,
+        }
+    }
+
+    /// SBI call failed due to not supported by target ISA,
+    /// operation type not supported,
+    /// or target operation type not implemented on purpose.
+    #[inline]
+    pub const fn not_supported() -> Self {
+        Self {
+            error: T::RET_ERR_NOT_SUPPORTED,
+            value: T::ZERO,
+        }
+    }
+
+    /// SBI call failed due to invalid hart mask parameter,
+    /// invalid target hart id,
+    /// invalid operation type,
+    /// or invalid resource index.
+    #[inline]
+    pub const fn invalid_param() -> Self {
+        Self {
+            error: T::RET_ERR_INVALID_PARAM,
+            value: T::ZERO,
+        }
+    }
+    /// SBI call denied for unsatisfied entry criteria, or insufficient access
+    /// permission to debug console or CPPC register.
+    #[inline]
+    pub const fn denied() -> Self {
+        Self {
+            error: T::RET_ERR_DENIED,
+            value: T::ZERO,
+        }
+    }
+
+    /// SBI call failed for invalid mask start address,
+    /// not a valid physical address parameter,
+    /// or the target address is prohibited by PMP to run in supervisor mode.
+    #[inline]
+    pub const fn invalid_address() -> Self {
+        Self {
+            error: T::RET_ERR_INVALID_ADDRESS,
+            value: T::ZERO,
+        }
+    }
+
+    /// SBI call failed for the target resource is already available,
+    /// e.g., the target hart is already started when caller still requests it to start.
+    #[inline]
+    pub const fn already_available() -> Self {
+        Self {
+            error: T::RET_ERR_ALREADY_AVAILABLE,
+            value: T::ZERO,
+        }
+    }
+
+    /// SBI call failed for the target resource is already started,
+    /// e.g., target performance counter is started.
+    #[inline]
+    pub const fn already_started() -> Self {
+        Self {
+            error: T::RET_ERR_ALREADY_STARTED,
+            value: T::ZERO,
+        }
+    }
+
+    /// SBI call failed for the target resource is already stopped,
+    /// e.g., target performance counter is stopped.
+    #[inline]
+    pub const fn already_stopped() -> Self {
+        Self {
+            error: T::RET_ERR_ALREADY_STOPPED,
+            value: T::ZERO,
+        }
+    }
+
+    /// SBI call failed for shared memory is not available,
+    /// e.g. nested acceleration shared memory is not available.
+    #[inline]
+    pub const fn no_shmem() -> Self {
+        Self {
+            error: T::RET_ERR_NO_SHMEM,
+            value: T::ZERO,
+        }
+    }
+
+    /// SBI call failed for invalid state,
+    /// e.g. register a software event but the event is not in unused state.
+    #[inline]
+    pub const fn invalid_state() -> Self {
+        Self {
+            error: T::RET_ERR_INVALID_STATE,
+            value: T::ZERO,
+        }
+    }
+
+    /// SBI call failed for bad or invalid range,
+    /// e.g. the software event is not exist in the specified range.
+    #[inline]
+    pub const fn bad_range() -> Self {
+        Self {
+            error: T::RET_ERR_BAD_RANGE,
+            value: T::ZERO,
+        }
+    }
+
+    /// SBI call failed for timeout,
+    /// e.g. message send timeout.
+    #[inline]
+    pub const fn timeout() -> Self {
+        Self {
+            error: T::RET_ERR_TIMEOUT,
+            value: T::ZERO,
+        }
+    }
+
+    /// SBI call failed for input or output error.
+    #[inline]
+    pub const fn io() -> Self {
+        Self {
+            error: T::RET_ERR_IO,
+            value: T::ZERO,
+        }
+    }
+    /// SBI call failed for denied or not allowed due to lock status.
+    #[inline]
+    pub const fn denied_locked() -> Self {
+        Self {
+            error: T::RET_ERR_DENIED_LOCKED,
+            value: T::ZERO,
+        }
+    }
+}
+
+impl<T: SbiRegister> From<Error<T>> for SbiRet<T> {
+    #[inline]
+    fn from(value: Error<T>) -> Self {
+        match value {
+            Error::Failed => SbiRet::failed(),
+            Error::NotSupported => SbiRet::not_supported(),
+            Error::InvalidParam => SbiRet::invalid_param(),
+            Error::Denied => SbiRet::denied(),
+            Error::InvalidAddress => SbiRet::invalid_address(),
+            Error::AlreadyAvailable => SbiRet::already_available(),
+            Error::AlreadyStarted => SbiRet::already_started(),
+            Error::AlreadyStopped => SbiRet::already_stopped(),
+            Error::NoShmem => SbiRet::no_shmem(),
+            Error::InvalidState => SbiRet::invalid_state(),
+            Error::BadRange => SbiRet::bad_range(),
+            Error::Timeout => SbiRet::timeout(),
+            Error::Io => SbiRet::io(),
+            Error::DeniedLocked => SbiRet::denied_locked(),
+            Error::Custom(error) => SbiRet {
+                error,
+                value: T::ZERO,
+            },
+        }
+    }
+}
+
+impl SbiRet {
+    /// Converts to a [`Result`] of value and error.
+    #[inline]
+    pub const fn into_result(self) -> Result<usize, Error> {
+        match self.error {
+            RET_SUCCESS => Ok(self.value),
+            RET_ERR_FAILED => Err(Error::Failed),
+            RET_ERR_NOT_SUPPORTED => Err(Error::NotSupported),
+            RET_ERR_INVALID_PARAM => Err(Error::InvalidParam),
+            RET_ERR_DENIED => Err(Error::Denied),
+            RET_ERR_INVALID_ADDRESS => Err(Error::InvalidAddress),
+            RET_ERR_ALREADY_AVAILABLE => Err(Error::AlreadyAvailable),
+            RET_ERR_ALREADY_STARTED => Err(Error::AlreadyStarted),
+            RET_ERR_ALREADY_STOPPED => Err(Error::AlreadyStopped),
+            RET_ERR_NO_SHMEM => Err(Error::NoShmem),
+            RET_ERR_INVALID_STATE => Err(Error::InvalidState),
+            RET_ERR_BAD_RANGE => Err(Error::BadRange),
+            RET_ERR_TIMEOUT => Err(Error::Timeout),
+            RET_ERR_IO => Err(Error::Io),
+            RET_ERR_DENIED_LOCKED => Err(Error::DeniedLocked),
+            unknown => Err(Error::Custom(unknown as _)),
+        }
+    }
+
+    /// Returns `true` if current SBI return succeeded.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// # use sbi_spec::binary::SbiRet;
+    /// let x = SbiRet::success(0);
+    /// assert_eq!(x.is_ok(), true);
+    ///
+    /// let x = SbiRet::failed();
+    /// assert_eq!(x.is_ok(), false);
+    /// ```
+    #[must_use = "if you intended to assert that this is ok, consider `.unwrap()` instead"]
+    #[inline]
+    pub const fn is_ok(&self) -> bool {
+        matches!(self.error, RET_SUCCESS)
+    }
+
+    /// Returns `true` if the SBI call succeeded and the value inside of it matches a predicate.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// # use sbi_spec::binary::SbiRet;
+    /// let x = SbiRet::success(2);
+    /// assert_eq!(x.is_ok_and(|x| x > 1), true);
+    ///
+    /// let x = SbiRet::success(0);
+    /// assert_eq!(x.is_ok_and(|x| x > 1), false);
+    ///
+    /// let x = SbiRet::no_shmem();
+    /// assert_eq!(x.is_ok_and(|x| x > 1), false);
+    /// ```
+    #[must_use]
+    #[inline]
+    pub fn is_ok_and(self, f: impl FnOnce(usize) -> bool) -> bool {
+        self.into_result().is_ok_and(f)
+    }
+
+    /// Returns `true` if current SBI return is an error.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// # use sbi_spec::binary::SbiRet;
+    /// let x = SbiRet::success(0);
+    /// assert_eq!(x.is_err(), false);
+    ///
+    /// let x = SbiRet::not_supported();
+    /// assert_eq!(x.is_err(), true);
+    /// ```
+    #[must_use = "if you intended to assert that this is err, consider `.unwrap_err()` instead"]
+    #[inline]
+    pub const fn is_err(&self) -> bool {
+        !self.is_ok()
+    }
+
+    /// Returns `true` if the result is an error and the value inside of it matches a predicate.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use sbi_spec::binary::{SbiRet, Error};
+    /// let x = SbiRet::denied();
+    /// assert_eq!(x.is_err_and(|x| x == Error::Denied), true);
+    ///
+    /// let x = SbiRet::invalid_address();
+    /// assert_eq!(x.is_err_and(|x| x == Error::Denied), false);
+    ///
+    /// let x = SbiRet::success(0);
+    /// assert_eq!(x.is_err_and(|x| x == Error::Denied), false);
+    /// ```
+    #[must_use]
+    #[inline]
+    pub fn is_err_and(self, f: impl FnOnce(Error) -> bool) -> bool {
+        self.into_result().is_err_and(f)
+    }
+
+    /// Converts from `SbiRet` to [`Option<usize>`].
+    ///
+    /// Converts `self` into an [`Option<usize>`], consuming `self`,
+    /// and discarding the error, if any.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// # use sbi_spec::binary::SbiRet;
+    /// let x = SbiRet::success(2);
+    /// assert_eq!(x.ok(), Some(2));
+    ///
+    /// let x = SbiRet::invalid_param();
+    /// assert_eq!(x.ok(), None);
+    /// ```
+    // fixme: should be pub const fn once this function in Result is stabilized in constant
+    #[inline]
+    pub fn ok(self) -> Option<usize> {
+        self.into_result().ok()
+    }
+
+    /// Converts from `SbiRet` to [`Option<Error>`].
+    ///
+    /// Converts `self` into an [`Option<Error>`], consuming `self`,
+    /// and discarding the success value, if any.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// # use sbi_spec::binary::{SbiRet, Error};
+    /// let x = SbiRet::success(2);
+    /// assert_eq!(x.err(), None);
+    ///
+    /// let x = SbiRet::denied();
+    /// assert_eq!(x.err(), Some(Error::Denied));
+    /// ```
+    // fixme: should be pub const fn once this function in Result is stabilized in constant
+    #[inline]
+    pub fn err(self) -> Option<Error> {
+        self.into_result().err()
+    }
+
+    /// Maps a `SbiRet` to `Result<U, Error>` by applying a function to a
+    /// contained success value, leaving an error value untouched.
+    ///
+    /// This function can be used to compose the results of two functions.
+    ///
+    /// # Examples
+    ///
+    /// Gets detail of a PMU counter and judge if it is a firmware counter.
+    ///
+    /// ```
+    /// # use sbi_spec::binary::SbiRet;
+    /// # use core::mem::size_of;
+    /// # mod sbi_rt {
+    /// #     use sbi_spec::binary::SbiRet;
+    /// #     const TYPE_MASK: usize = 1 << (core::mem::size_of::<usize>() - 1);
+    /// #     pub fn pmu_counter_get_info(_: usize) -> SbiRet { SbiRet::success(TYPE_MASK) }
+    /// # }
+    /// // We assume that counter index 42 is a firmware counter.
+    /// let counter_idx = 42;
+    /// // Masks PMU counter type by setting highest bit in `usize`.
+    /// const TYPE_MASK: usize = 1 << (size_of::<usize>() - 1);
+    /// // Highest bit of returned `counter_info` represents whether it's
+    /// // a firmware counter or a hardware counter.
+    /// let is_firmware_counter = sbi_rt::pmu_counter_get_info(counter_idx)
+    ///     .map(|counter_info| counter_info & TYPE_MASK != 0);
+    /// // If that bit is set, it is a firmware counter.
+    /// assert_eq!(is_firmware_counter, Ok(true));
+    /// ```
+    #[inline]
+    pub fn map<U, F: FnOnce(usize) -> U>(self, op: F) -> Result<U, Error> {
+        self.into_result().map(op)
+    }
+
+    /// Returns the provided default (if error),
+    /// or applies a function to the contained value (if success).
+    ///
+    /// Arguments passed to `map_or` are eagerly evaluated;
+    /// if you are passing the result of a function call,
+    /// it is recommended to use [`map_or_else`],
+    /// which is lazily evaluated.
+    ///
+    /// [`map_or_else`]: SbiRet::map_or_else
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use sbi_spec::binary::SbiRet;
+    /// let x = SbiRet::success(3);
+    /// assert_eq!(x.map_or(42, |v| v & 0b1), 1);
+    ///
+    /// let x = SbiRet::invalid_address();
+    /// assert_eq!(x.map_or(42, |v| v & 0b1), 42);
+    /// ```
+    #[inline]
+    pub fn map_or<U, F: FnOnce(usize) -> U>(self, default: U, f: F) -> U {
+        self.into_result().map_or(default, f)
+    }
+
+    /// Maps a `SbiRet` to `usize` value by applying fallback function `default` to
+    /// a contained error, or function `f` to a contained success value.
+    ///
+    /// This function can be used to unpack a successful result
+    /// while handling an error.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// # use sbi_spec::binary::SbiRet;
+    /// let k = 21;
+    ///
+    /// let x = SbiRet::success(3);
+    /// assert_eq!(x.map_or_else(|e| k * 2, |v| v & 0b1), 1);
+    ///
+    /// let x = SbiRet::already_available();
+    /// assert_eq!(x.map_or_else(|e| k * 2, |v| v & 0b1), 42);
+    /// ```
+    #[inline]
+    pub fn map_or_else<U, D: FnOnce(Error) -> U, F: FnOnce(usize) -> U>(
+        self,
+        default: D,
+        f: F,
+    ) -> U {
+        self.into_result().map_or_else(default, f)
+    }
+
+    /// Maps a `SbiRet` to `Result<T, F>` by applying a function to a
+    /// contained error as [`Error`] struct, leaving success value untouched.
+    ///
+    /// This function can be used to pass through a successful result while handling
+    /// an error.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// # use sbi_spec::binary::{SbiRet, Error};
+    /// fn stringify(x: Error) -> String {
+    ///     if x == Error::AlreadyStarted {
+    ///         "error: already started!".to_string()
+    ///     } else {
+    ///         "error: other error!".to_string()
+    ///     }
+    /// }
+    ///
+    /// let x = SbiRet::success(2);
+    /// assert_eq!(x.map_err(stringify), Ok(2));
+    ///
+    /// let x = SbiRet::already_started();
+    /// assert_eq!(x.map_err(stringify), Err("error: already started!".to_string()));
+    /// ```
+    #[inline]
+    pub fn map_err<F, O: FnOnce(Error) -> F>(self, op: O) -> Result<usize, F> {
+        self.into_result().map_err(op)
+    }
+
+    /// Calls a function with a reference to the contained value if current SBI call succeeded.
+    ///
+    /// Returns the original result.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use sbi_spec::binary::SbiRet;
+    /// // Assume that SBI debug console have read 512 bytes into a buffer.
+    /// let ret = SbiRet::success(512);
+    /// // Inspect the SBI DBCN call result.
+    /// let idx = ret
+    ///     .inspect(|x| println!("bytes written: {x}"))
+    ///     .map(|x| x - 1)
+    ///     .expect("SBI DBCN call failed");
+    /// assert_eq!(idx, 511);
+    /// ```
+    #[inline]
+    pub fn inspect<F: FnOnce(&usize)>(self, f: F) -> Self {
+        if let Ok(ref t) = self.into_result() {
+            f(t);
+        }
+
+        self
+    }
+
+    /// Calls a function with a reference to the contained value if current SBI result is an error.
+    ///
+    /// Returns the original result.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use sbi_spec::binary::SbiRet;
+    /// // Assume that SBI debug console write operation failed for invalid parameter.
+    /// let ret = SbiRet::invalid_param();
+    /// // Print the error if SBI DBCN call failed.
+    /// let ret = ret.inspect_err(|e| eprintln!("failed to read from SBI console: {e:?}"));
+    /// ```
+    #[inline]
+    pub fn inspect_err<F: FnOnce(&Error)>(self, f: F) -> Self {
+        if let Err(ref e) = self.into_result() {
+            f(e);
+        }
+
+        self
+    }
+
+    // TODO: pub fn iter(&self) -> Iter
+    // TODO: pub fn iter_mut(&mut self) -> IterMut
+
+    /// Returns the contained success value, consuming the `self` value.
+    ///
+    /// # Panics
+    ///
+    /// Panics if self is an SBI error with a panic message including the
+    /// passed message, and the content of the SBI state.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```should_panic
+    /// # use sbi_spec::binary::SbiRet;
+    /// let x = SbiRet::already_stopped();
+    /// x.expect("Testing expect"); // panics with `Testing expect`
+    /// ```
+    #[inline]
+    pub fn expect(self, msg: &str) -> usize {
+        self.into_result().expect(msg)
+    }
+
+    /// Returns the contained success value, consuming the `self` value.
+    ///
+    /// # Panics
+    ///
+    /// Panics if self is an SBI error, with a panic message provided by the
+    /// SBI error converted into [`Error`] struct.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// # use sbi_spec::binary::SbiRet;
+    /// let x = SbiRet::success(2);
+    /// assert_eq!(x.unwrap(), 2);
+    /// ```
+    ///
+    /// ```should_panic
+    /// # use sbi_spec::binary::SbiRet;
+    /// let x = SbiRet::failed();
+    /// x.unwrap(); // panics
+    /// ```
+    #[inline]
+    pub fn unwrap(self) -> usize {
+        self.into_result().unwrap()
+    }
+
+    // Note: No unwrap_or_default as we cannot determine a meaningful default value for a successful SbiRet.
+
+    /// Returns the contained error as [`Error`] struct, consuming the `self` value.
+    ///
+    /// # Panics
+    ///
+    /// Panics if the self is SBI success value, with a panic message
+    /// including the passed message, and the content of the success value.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```should_panic
+    /// # use sbi_spec::binary::SbiRet;
+    /// let x = SbiRet::success(10);
+    /// x.expect_err("Testing expect_err"); // panics with `Testing expect_err`
+    /// ```
+    #[inline]
+    pub fn expect_err(self, msg: &str) -> Error {
+        self.into_result().expect_err(msg)
+    }
+
+    /// Returns the contained error as [`Error`] struct, consuming the `self` value.
+    ///
+    /// # Panics
+    ///
+    /// Panics if the self is SBI success value, with a custom panic message provided
+    /// by the success value.
+    ///
+    /// # Examples
+    ///
+    /// ```should_panic
+    /// # use sbi_spec::binary::SbiRet;
+    /// let x = SbiRet::success(2);
+    /// x.unwrap_err(); // panics with `2`
+    /// ```
+    ///
+    /// ```
+    /// # use sbi_spec::binary::{SbiRet, Error};
+    /// let x = SbiRet::not_supported();
+    /// assert_eq!(x.unwrap_err(), Error::NotSupported);
+    /// ```
+    #[inline]
+    pub fn unwrap_err(self) -> Error {
+        self.into_result().unwrap_err()
+    }
+
+    // TODO: pub fn into_ok(self) -> usize and pub fn into_err(self) -> Error
+    // once `unwrap_infallible` is stabilized
+
+    /// Returns `res` if self is success value, otherwise otherwise returns the contained error
+    /// of `self` as [`Error`] struct.
+    ///
+    /// Arguments passed to `and` are eagerly evaluated; if you are passing the
+    /// result of a function call, it is recommended to use [`and_then`], which is
+    /// lazily evaluated.
+    ///
+    /// [`and_then`]: SbiRet::and_then
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// # use sbi_spec::binary::{SbiRet, Error};
+    /// let x = SbiRet::success(2);
+    /// let y = SbiRet::invalid_param().into_result();
+    /// assert_eq!(x.and(y), Err(Error::InvalidParam));
+    ///
+    /// let x = SbiRet::denied();
+    /// let y = SbiRet::success(3).into_result();
+    /// assert_eq!(x.and(y), Err(Error::Denied));
+    ///
+    /// let x = SbiRet::invalid_address();
+    /// let y = SbiRet::already_available().into_result();
+    /// assert_eq!(x.and(y), Err(Error::InvalidAddress));
+    ///
+    /// let x = SbiRet::success(4);
+    /// let y = SbiRet::success(5).into_result();
+    /// assert_eq!(x.and(y), Ok(5));
+    /// ```
+    // fixme: should be pub const fn once this function in Result is stabilized in constant
+    // fixme: should parameter be `res: SbiRet`?
+    #[inline]
+    pub fn and<U>(self, res: Result<U, Error>) -> Result<U, Error> {
+        self.into_result().and(res)
+    }
+
+    /// Calls `op` if self is success value, otherwise returns the contained error
+    /// as [`Error`] struct.
+    ///
+    /// This function can be used for control flow based on `SbiRet` values.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use sbi_spec::binary::{SbiRet, Error};
+    /// fn sq_then_to_string(x: usize) -> Result<String, Error> {
+    ///     x.checked_mul(x).map(|sq| sq.to_string()).ok_or(Error::Failed)
+    /// }
+    ///
+    /// assert_eq!(SbiRet::success(2).and_then(sq_then_to_string), Ok(4.to_string()));
+    /// assert_eq!(SbiRet::success(1_000_000_000_000).and_then(sq_then_to_string), Err(Error::Failed));
+    /// assert_eq!(SbiRet::invalid_param().and_then(sq_then_to_string), Err(Error::InvalidParam));
+    /// ```
+    #[inline]
+    pub fn and_then<U, F: FnOnce(usize) -> Result<U, Error>>(self, op: F) -> Result<U, Error> {
+        self.into_result().and_then(op)
+    }
+
+    /// Returns `res` if self is SBI error, otherwise returns the success value of `self`.
+    ///
+    /// Arguments passed to `or` are eagerly evaluated; if you are passing the
+    /// result of a function call, it is recommended to use [`or_else`], which is
+    /// lazily evaluated.
+    ///
+    /// [`or_else`]: Result::or_else
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// # use sbi_spec::binary::{SbiRet, Error};
+    /// let x = SbiRet::success(2);
+    /// let y = SbiRet::invalid_param().into_result();
+    /// assert_eq!(x.or(y), Ok(2));
+    ///
+    /// let x = SbiRet::denied();
+    /// let y = SbiRet::success(3).into_result();
+    /// assert_eq!(x.or(y), Ok(3));
+    ///
+    /// let x = SbiRet::invalid_address();
+    /// let y = SbiRet::already_available().into_result();
+    /// assert_eq!(x.or(y), Err(Error::AlreadyAvailable));
+    ///
+    /// let x = SbiRet::success(4);
+    /// let y = SbiRet::success(100).into_result();
+    /// assert_eq!(x.or(y), Ok(4));
+    /// ```
+    // fixme: should be pub const fn once this function in Result is stabilized in constant
+    // fixme: should parameter be `res: SbiRet`?
+    #[inline]
+    pub fn or<F>(self, res: Result<usize, F>) -> Result<usize, F> {
+        self.into_result().or(res)
+    }
+
+    /// Calls `op` if self is SBI error, otherwise returns the success value of `self`.
+    ///
+    /// This function can be used for control flow based on result values.
+    ///
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// # use sbi_spec::binary::{SbiRet, Error};
+    /// fn is_failed(x: Error) -> Result<usize, bool> { Err(x == Error::Failed) }
+    ///
+    /// assert_eq!(SbiRet::success(2).or_else(is_failed), Ok(2));
+    /// assert_eq!(SbiRet::failed().or_else(is_failed), Err(true));
+    /// ```
+    #[inline]
+    pub fn or_else<F, O: FnOnce(Error) -> Result<usize, F>>(self, op: O) -> Result<usize, F> {
+        self.into_result().or_else(op)
+    }
+
+    /// Returns the contained success value or a provided default.
+    ///
+    /// Arguments passed to `unwrap_or` are eagerly evaluated; if you are passing
+    /// the result of a function call, it is recommended to use [`unwrap_or_else`],
+    /// which is lazily evaluated.
+    ///
+    /// [`unwrap_or_else`]: SbiRet::unwrap_or_else
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// # use sbi_spec::binary::SbiRet;
+    /// let default = 2;
+    /// let x = SbiRet::success(9);
+    /// assert_eq!(x.unwrap_or(default), 9);
+    ///
+    /// let x = SbiRet::invalid_param();
+    /// assert_eq!(x.unwrap_or(default), default);
+    /// ```
+    // fixme: should be pub const fn once this function in Result is stabilized in constant
+    #[inline]
+    pub fn unwrap_or(self, default: usize) -> usize {
+        self.into_result().unwrap_or(default)
+    }
+
+    /// Returns the contained success value or computes it from a closure.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// # use sbi_spec::binary::{SbiRet, Error};
+    /// fn invalid_use_zero(x: Error) -> usize { if x == Error::InvalidParam { 0 } else { 3 } }
+    ///
+    /// assert_eq!(SbiRet::success(2).unwrap_or_else(invalid_use_zero), 2);
+    /// assert_eq!(SbiRet::invalid_param().unwrap_or_else(invalid_use_zero), 0);
+    /// ```
+    #[inline]
+    pub fn unwrap_or_else<F: FnOnce(Error) -> usize>(self, op: F) -> usize {
+        self.into_result().unwrap_or_else(op)
+    }
+
+    /// Returns the contained success value, consuming the `self` value,
+    /// without checking that the `SbiRet` contains an error value.
+    ///
+    /// # Safety
+    ///
+    /// Calling this method on an `SbiRet` containing an error value results
+    /// in *undefined behavior*.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use sbi_spec::binary::{SbiRet, Error};
+    /// let x = SbiRet::success(3);
+    /// assert_eq!(unsafe { x.unwrap_unchecked() }, 3);
+    /// ```
+    ///
+    /// ```no_run
+    /// # use sbi_spec::binary::SbiRet;
+    /// let x = SbiRet::no_shmem();
+    /// unsafe { x.unwrap_unchecked(); } // Undefined behavior!
+    /// ```
+    #[inline]
+    pub unsafe fn unwrap_unchecked(self) -> usize {
+        unsafe { self.into_result().unwrap_unchecked() }
+    }
+
+    /// Returns the contained `Error` value, consuming the `self` value,
+    /// without checking that the `SbiRet` does not contain a success value.
+    ///
+    /// # Safety
+    ///
+    /// Calling this method on an `SbiRet` containing a success value results
+    /// in *undefined behavior*.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// # use sbi_spec::binary::SbiRet;
+    /// let x = SbiRet::success(4);
+    /// unsafe { x.unwrap_unchecked(); } // Undefined behavior!
+    /// ```
+    ///
+    /// ```
+    /// # use sbi_spec::binary::{SbiRet, Error};
+    /// let x = SbiRet::failed();
+    /// assert_eq!(unsafe { x.unwrap_err_unchecked() }, Error::Failed);
+    /// ```
+    #[inline]
+    pub unsafe fn unwrap_err_unchecked(self) -> Error {
+        unsafe { self.into_result().unwrap_err_unchecked() }
+    }
+}
+
+impl IntoIterator for SbiRet {
+    type Item = usize;
+    type IntoIter = core::result::IntoIter<usize>;
+
+    /// Returns a consuming iterator over the possibly contained value.
+    ///
+    /// The iterator yields one value if the result contains a success value, otherwise none.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use sbi_spec::binary::SbiRet;
+    /// let x = SbiRet::success(5);
+    /// let v: Vec<usize> = x.into_iter().collect();
+    /// assert_eq!(v, [5]);
+    ///
+    /// let x = SbiRet::not_supported();
+    /// let v: Vec<usize> = x.into_iter().collect();
+    /// assert_eq!(v, []);
+    /// ```
+    #[inline]
+    fn into_iter(self) -> Self::IntoIter {
+        self.into_result().into_iter()
+    }
+}
+
+// TODO: implement Try and FromResidual for SbiRet once those traits are stabilized
+/*
+impl core::ops::Try for SbiRet {
+    type Output = usize;
+    type Residual = Result<core::convert::Infallible, Error>;
+
+    #[inline]
+    fn from_output(output: Self::Output) -> Self {
+        SbiRet::success(output)
+    }
+
+    #[inline]
+    fn branch(self) -> core::ops::ControlFlow<Self::Residual, Self::Output> {
+        self.into_result().branch()
+    }
+}
+
+impl core::ops::FromResidual<Result<core::convert::Infallible, Error>> for SbiRet {
+    #[inline]
+    #[track_caller]
+    fn from_residual(residual: Result<core::convert::Infallible, Error>) -> Self {
+        match residual {
+            Err(e) => e.into(),
+        }
+    }
+}
+
+/// ```
+/// # use sbi_spec::binary::SbiRet;
+/// fn test() -> SbiRet {
+///     let value = SbiRet::failed()?;
+///     SbiRet::success(0)
+/// }
+/// assert_eq!(test(), SbiRet::failed());
+/// ```
+mod test_try_trait_for_sbiret {}
+*/
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    #[rustfmt::skip]
+    fn rustsbi_sbi_ret_constructors() {
+        assert_eq!(SbiRet::success(0), SbiRet { value: 0, error: 0 });
+        assert_eq!(SbiRet::success(1037), SbiRet { value: 1037, error: 0 });
+        assert_eq!(SbiRet::success(usize::MAX), SbiRet { value: usize::MAX, error: 0 });
+
+        assert_eq!(SbiRet::failed(), SbiRet { value: 0, error: usize::MAX - 1 + 1 });
+        assert_eq!(SbiRet::not_supported(), SbiRet { value: 0, error: usize::MAX - 2 + 1 });
+        assert_eq!(SbiRet::invalid_param(), SbiRet { value: 0, error: usize::MAX - 3 + 1 });
+        assert_eq!(SbiRet::denied(), SbiRet { value: 0, error: usize::MAX - 4 + 1 });
+        assert_eq!(SbiRet::invalid_address(), SbiRet { value: 0, error: usize::MAX - 5 + 1 });
+        assert_eq!(SbiRet::already_available(), SbiRet { value: 0, error: usize::MAX - 6 + 1 });
+        assert_eq!(SbiRet::already_started(), SbiRet { value: 0, error: usize::MAX - 7 + 1 });
+        assert_eq!(SbiRet::already_stopped(), SbiRet { value: 0, error: usize::MAX - 8 + 1 });
+        assert_eq!(SbiRet::no_shmem(), SbiRet { value: 0, error: usize::MAX - 9 + 1 });
+        assert_eq!(SbiRet::invalid_state(), SbiRet { value: 0, error: usize::MAX - 10 + 1 });
+        assert_eq!(SbiRet::bad_range(), SbiRet { value: 0, error: usize::MAX - 11 + 1 });
+        assert_eq!(SbiRet::timeout(), SbiRet { value: 0, error: usize::MAX - 12 + 1 });
+        assert_eq!(SbiRet::io(), SbiRet { value: 0, error: usize::MAX - 13 + 1 });
+        assert_eq!(SbiRet::denied_locked(), SbiRet { value: 0, error: usize::MAX - 14 + 1 });
+    }
+}

+ 91 - 0
library/sbi-spec/src/binary/shared_physical_ptr.rs

@@ -0,0 +1,91 @@
+use core::marker::PhantomData;
+
+/// Shared memory physical address raw pointer with type annotation.
+///
+/// This is a structure wrapping a raw pointer to the value of the type `T` without
+/// a pointer metadata. `SharedPtr`'s are _thin_; they won't include metadata
+/// as RISC-V SBI does not provide an approach to pass them via SBI calls,
+/// thus the length of type `T` should be decided independently of raw
+/// pointer structure.
+///
+/// `SharedPtr` can be used as a parameter to pass the shared memory physical pointer
+///  with a given base address in RISC-V SBI calls. For example, a `SharedPtr<[u8; 64]>`
+/// would represent a fixed-size 64 byte array on a RISC-V SBI function argument
+/// type.
+///
+/// This structure cannot be dereferenced directly with physical addresses,
+/// because on RISC-V systems the physical address space could be larger than the
+/// virtual ones. Hence, this structure describes the physical memory range by
+/// two `usize` values: the upper `phys_addr_hi` and lower `phys_addr_lo`.
+///
+/// RISC-V SBI extensions may declare special pointer values for shared memory
+/// raw pointers. For example, SBI STA declares that steal-time information
+/// should stop from reporting when the SBI call is invoked using all-ones
+/// bitwise shared pointer, i.e. `phys_addr_hi` and `phys_addr_lo` both equals
+/// `usize::MAX`. `SharedPtr` can be constructed using such special values
+/// by providing them to the `SharedPtr::new` function.
+///
+/// # Requirements
+///
+/// If an SBI function needs to pass a shared memory physical address range to
+/// the SBI implementation (or higher privilege mode), then this physical memory
+/// address range MUST satisfy the following requirements:
+///
+/// * The SBI implementation MUST check that the supervisor-mode software is
+///   allowed to access the specified physical memory range with the access
+///   type requested (read and/or write).
+/// * The SBI implementation MUST access the specified physical memory range
+///   using the PMA attributes.
+/// * The data in the shared memory MUST follow little-endian byte ordering.
+///
+/// *NOTE:* If the supervisor-mode software accesses the same physical memory
+/// range using a memory type different from the PMA, then a loss of coherence
+/// or unexpected memory ordering may occur. The invoking software should
+/// follow the rules and sequences defined in the RISC-V Svpbmt specification
+/// to prevent the loss of coherence and memory ordering.
+///
+/// It is recommended that a memory physical address passed to an SBI function
+/// should use at least two `usize` parameters to support platforms
+/// which have memory physical addresses wider than `XLEN` bits.
+// FIXME: should constrain with `T: Thin` once ptr_metadata feature is stabled;
+// RISC-V SBI does not provide an approach to pass pointer metadata by SBI calls.
+pub struct SharedPtr<T> {
+    phys_addr_lo: usize,
+    phys_addr_hi: usize,
+    _marker: PhantomData<*mut T>,
+}
+
+// FIXME: we should consider strict provenance rules for this pointer-like structure
+// once feature strict_provenance is stabled.
+impl<T> SharedPtr<T> {
+    /// Create a shared physical memory pointer by physical address.
+    #[inline]
+    pub const fn new(phys_addr_lo: usize, phys_addr_hi: usize) -> Self {
+        Self {
+            phys_addr_lo,
+            phys_addr_hi,
+            _marker: PhantomData,
+        }
+    }
+
+    /// Returns low-part physical address of the shared physical memory pointer.
+    #[inline]
+    pub const fn phys_addr_lo(self) -> usize {
+        self.phys_addr_lo
+    }
+
+    /// Returns high-part physical address of the shared physical memory pointer.
+    #[inline]
+    pub const fn phys_addr_hi(self) -> usize {
+        self.phys_addr_hi
+    }
+}
+
+impl<T> Clone for SharedPtr<T> {
+    #[inline(always)]
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+
+impl<T> Copy for SharedPtr<T> {}

+ 29 - 0
library/sbi-spec/src/binary/trigger_mask.rs

@@ -0,0 +1,29 @@
+use super::sbi_ret::SbiRegister;
+
+/// Debug trigger mask structure for the `DBTR` extension §19.
+#[repr(C)]
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+pub struct TriggerMask<T = usize> {
+    trig_idx_base: T,
+    trig_idx_mask: T,
+}
+
+impl<T: SbiRegister> TriggerMask<T> {
+    /// Construct a [TriggerMask] from mask value and base counter index.
+    ///
+    /// The `trig_idx_base` specifies the starting trigger index, while the `trig_idx_mask` is a
+    /// bitmask indicating which triggers, relative to the base, are to be operated.
+    #[inline]
+    pub const fn from_mask_base(trig_idx_mask: T, trig_idx_base: T) -> Self {
+        Self {
+            trig_idx_mask,
+            trig_idx_base,
+        }
+    }
+
+    /// Returns `mask` and `base` parameters from the [TriggerMask].
+    #[inline]
+    pub const fn into_inner(self) -> (T, T) {
+        (self.trig_idx_mask, self.trig_idx_base)
+    }
+}

+ 5 - 0
library/sbi-spec/src/lib.rs

@@ -92,6 +92,11 @@ mod tests {
         const_assert_eq!(-7, RET_ERR_ALREADY_STARTED as isize);
         const_assert_eq!(-8, RET_ERR_ALREADY_STOPPED as isize);
         const_assert_eq!(-9, RET_ERR_NO_SHMEM as isize);
+        const_assert_eq!(-10, RET_ERR_INVALID_STATE as isize);
+        const_assert_eq!(-11, RET_ERR_BAD_RANGE as isize);
+        const_assert_eq!(-12, RET_ERR_TIMEOUT as isize);
+        const_assert_eq!(-13, RET_ERR_IO as isize);
+        const_assert_eq!(-14, RET_ERR_DENIED_LOCKED as isize);
     }
     // §4
     #[test]

+ 1 - 1
library/sbi-testing/src/dbcn.rs

@@ -6,7 +6,7 @@ use sbi_spec::binary::Physical;
 /// Debug console extension test cases.
 #[derive(Clone, Debug)]
 pub enum Case {
-    /// Can't procceed test for debug console extension does not exist.
+    /// Can't proceed test for debug console extension does not exist.
     NotExist,
     /// Test begin.
     Begin,