From 2f00036f6dfc7d7a841adfeccfa43bd6b2ba4eb2 Mon Sep 17 00:00:00 2001 From: Zhenchen Wang Date: Sun, 12 May 2024 16:35:21 +0800 Subject: [PATCH 1/2] docs: add documents for #[rustsbi(dynamic)]. Signed-off-by: Zhenchen Wang --- src/lib.rs | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index e537899..867fee4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -866,6 +866,44 @@ pub use sbi_spec::binary::{HartMask, Physical, SbiRet, SharedPtr}; /// # } /// ``` /// +/// When using the `#[rustsbi(dynamic)]` attribute, it is possible to include multiple +/// fields that indicate the same SBI extension. +/// +/// ```rust +/// # use rustsbi::RustSBI; +/// #[derive(RustSBI)] +/// #[rustsbi(dynamic)] +/// struct MySBI { +/// // Fields in `#[rustsbi(dynamic)]` structures are usually wrapped in `Option`s. +/// fence: Option, +/// rfnc: Option, +/// // ^ Both the two fields are identified as `rustsbi::Fence` implementation. +/// info: MyEnvInfo, +/// // ^ However, environment information should only be introduced *once*. +/// } +/// +/// // RustSBI will sequentially examine these fields, starting from the first one. +/// // Upon encountering the first `Option` that is `Some`, it will utilize this +/// // field as the implementation. +/// // i.e., if the first field `fence` in `MySBI` is `Some`, RustSBI uses `fence`. +/// // Else, if the second field `rfnc` is `Some`, RustSBI uses `rfnc`. +/// // Otherwise, RustSBI returns `SbiRet::not_supported`. +/// +/// # use sbi_spec::binary::{SbiRet, HartMask}; +/// # struct MyFence; +/// # impl rustsbi::Fence for MyFence { +/// # fn remote_fence_i(&self, _: HartMask) -> SbiRet { unimplemented!() } +/// # fn remote_sfence_vma(&self, _: HartMask, _: usize, _: usize) -> SbiRet { unimplemented!() } +/// # fn remote_sfence_vma_asid(&self, _: HartMask, _: usize, _: usize, _: usize) -> SbiRet { unimplemented!() } +/// # } +/// # struct MyEnvInfo; +/// # impl rustsbi::EnvInfo for MyEnvInfo { +/// # fn mvendorid(&self) -> usize { 1 } +/// # fn marchid(&self) -> usize { 2 } +/// # fn mimpid(&self) -> usize { 3 } +/// # } +/// ``` +/// /// The struct as derive input may include generics, specifically type generics, lifetimes, /// constant generics and where clauses. /// From c26897bf53385f0428990e34e7a2f47c5d439942 Mon Sep 17 00:00:00 2001 From: DongQing Date: Sun, 12 May 2024 17:04:11 +0800 Subject: [PATCH 2/2] docs: add instructions for derive macro usage Signed-off-by: DongQing --- src/lib.rs | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index e537899..e16c32e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -774,6 +774,52 @@ pub use sbi_spec::binary::{HartMask, Physical, SbiRet, SharedPtr}; /// Finally, when the context restores, the supervisor mode software (kernels, etc.) could get the /// SBI call result from register values. /// +/// Additionally, the macro also provides a dynamic way of building `RustSBI` trait implementations. +/// It allows developers to dynamically choose which device to use in the actual RustSBI implementation. +/// To use this feature, consider two structs namely `FenceOne` and `FenceTwo`, both implementing +/// RISC-V SBI Remote Fence extension. We can now derive `RustSBI` macro on `MySBI` wrapping those +/// two structs with `Option` type, annotated with `#[rustsbi(dynamic)]`: +/// `` +/// +/// ```rust +/// # use rustsbi::RustSBI; +/// #[derive(RustSBI)] +/// #[rustsbi(dynamic)] +/// struct MySBI { +/// fence: Option, +/// rfnc: Option, +/// # info: MyEnvInfo, +/// } +/// +/// struct FenceOne { /* fields */ } +/// +/// struct FenceTwo { /* fields */ } +/// +/// // Both `FenceOne` and `FenceTwo` implements `rustsbi::Fence`. +/// +/// # use sbi_spec::binary::{SbiRet, HartMask}; +/// # impl rustsbi::Fence for FenceOne { +/// # fn remote_fence_i(&self, _: HartMask) -> SbiRet { unimplemented!() } +/// # fn remote_sfence_vma(&self, _: HartMask, _: usize, _: usize) -> SbiRet { unimplemented!() } +/// # fn remote_sfence_vma_asid(&self, _: HartMask, _: usize, _: usize, _: usize) -> SbiRet { unimplemented!() } +/// # } +/// # impl rustsbi::Fence for FenceTwo { +/// # fn remote_fence_i(&self, _: HartMask) -> SbiRet { unimplemented!() } +/// # fn remote_sfence_vma(&self, _: HartMask, _: usize, _: usize) -> SbiRet { unimplemented!() } +/// # fn remote_sfence_vma_asid(&self, _: HartMask, _: usize, _: usize, _: usize) -> SbiRet { unimplemented!() } +/// # } +/// # struct MyEnvInfo; +/// # impl rustsbi::EnvInfo for MyEnvInfo { +/// # fn mvendorid(&self) -> usize { unimplemented!() } +/// # fn marchid(&self) -> usize { unimplemented!() } +/// # fn mimpid(&self) -> usize { unimplemented!() } +/// # } +/// ``` +/// +/// We have declared two fields, `fence` and `rfnc`, both of which are recognized by RustSBI as potential +/// candidates for the SBI Remote Fence extension. Dynamic RustSBI will probe both fields to determine +/// which field it should use for the SBI calls on the Remote Fence extension. +/// /// Now we have learned basic usages of the derive-macro `RustSBI`. We can dive deeper and use RustSBI /// in real cases with ease. Congratulations! ///