From 4b6e832a222e09f0e9e9021e68a6708e1fe34583 Mon Sep 17 00:00:00 2001 From: aarkegz Date: Wed, 7 Jan 2026 09:04:38 +0000 Subject: [PATCH 1/3] migrate to `crate_interface` 0.2, bump to 0.2 --- Cargo.toml | 6 +- axvisor_api_proc/Cargo.toml | 2 +- axvisor_api_proc/src/items.rs | 111 ----------- axvisor_api_proc/src/lib.rs | 283 +++++---------------------- examples/example.rs | 42 ++-- src/arch.rs | 24 +++ src/host.rs | 7 + src/lib.rs | 354 +++++++++++----------------------- src/memory.rs | 44 +++++ src/test.rs | 56 +++--- src/time.rs | 52 +++++ src/vmm.rs | 36 ++++ 12 files changed, 378 insertions(+), 639 deletions(-) delete mode 100644 axvisor_api_proc/src/items.rs create mode 100644 src/arch.rs create mode 100644 src/host.rs create mode 100644 src/memory.rs create mode 100644 src/time.rs create mode 100644 src/vmm.rs diff --git a/Cargo.toml b/Cargo.toml index a30c70c..b21e2f6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,7 @@ repository = "https://github.com/arceos-hypervisor/axvisor_api" [package] name = "axvisor_api" description = "Basic API for components of the Hypervisor on ArceOS" -version = "0.1.0" +version = "0.2.0" keywords = ["axvisor", "api", "embedded"] categories = ["embedded", "no-std"] authors.workspace = true @@ -22,8 +22,8 @@ license.workspace = true repository.workspace = true [dependencies] -axvisor_api_proc = { path = "axvisor_api_proc", version = "0.1.0"} +axvisor_api_proc = { path = "axvisor_api_proc", version = "0.2.0"} -crate_interface = "0.1" +crate_interface = "0.2" memory_addr = "0.4" axaddrspace = "0.1.0" diff --git a/axvisor_api_proc/Cargo.toml b/axvisor_api_proc/Cargo.toml index e01ae41..f080e76 100644 --- a/axvisor_api_proc/Cargo.toml +++ b/axvisor_api_proc/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "axvisor_api_proc" -version = "0.1.0" +version = "0.2.0" description = "Procedural macros for the `axvisor_api` crate" keywords = ["axvisor", "api", "embedded", "macros"] categories = ["development-tools::procedural-macro-helpers"] diff --git a/axvisor_api_proc/src/items.rs b/axvisor_api_proc/src/items.rs deleted file mode 100644 index 92654cf..0000000 --- a/axvisor_api_proc/src/items.rs +++ /dev/null @@ -1,111 +0,0 @@ -//! Definitions of custom items used in the `api_mod!` and `api_mod_impl!` macros. -//! -//! `api_mod!` and `api_mod_impl!` have very similar structures. - -use syn::{ - Attribute, Block, Ident, Item, Signature, Token, Visibility, braced, - parse::{Parse, ParseStream}, - token::Brace, -}; - -/// An API function, defined with the `extern fn` syntax. It represents both the definition and the implementation. For -/// the definition, `T` is `Token![;]`, and for the implementation, `T` is `syn::Block`. -pub struct ItemApiFn { - /// Attributes of the function. - pub attrs: Vec, - #[expect(dead_code)] - /// The `extern` keyword. - pub extern_token: Token![extern], - /// The function signature. - pub sig: Signature, - /// The body of the function, or a semicolon. - pub body: T, -} - -impl Parse for ItemApiFn { - fn parse(input: ParseStream) -> syn::Result { - let attrs = input.call(Attribute::parse_outer)?; - let extern_token = input.parse()?; - let sig = input.parse()?; - let body = input.parse()?; - - Ok(Self { - attrs, - extern_token, - sig, - body, - }) - } -} - -/// An item in a [`ItemApiMod`], which can be a regular [`Item`] or an [API function](`ItemApiFn`). As `ItemApiFn`, this -/// enum represents both the definition and the implementation. -pub enum ApiModItem { - Regular(Item), - ApiFn(ItemApiFn), -} - -impl Parse for ApiModItem { - fn parse(input: ParseStream) -> syn::Result { - // Attributes will be parsed twice, but it's not a big deal. - let forked = input.fork(); - let _ = forked.call(Attribute::parse_outer)?; - let is_api_fn = forked.peek(Token![extern]) && forked.peek2(Token![fn]); - drop(forked); - - if is_api_fn { - Ok(Self::ApiFn(input.parse()?)) - } else { - Ok(Self::Regular(input.parse()?)) - } - } -} - -/// A module that contains the definition or implementation of API functions, and marked by `#[api_mod]` or -/// `#[api_mod_impl]`. -pub struct ItemApiMod { - /// Attributes of the module. - pub attrs: Vec, - /// Visibility of the module. - pub vis: Visibility, - /// The `mod` keyword. - pub mod_token: Token![mod], - /// The identifier of the module. - pub ident: Ident, - #[expect(dead_code)] - /// The brace token. - pub brace_token: Brace, - /// The items in the module. - pub items: Vec>, -} - -impl Parse for ItemApiMod { - fn parse(input: ParseStream) -> syn::Result { - let attrs = input.call(Attribute::parse_outer)?; - let vis = input.parse()?; - let mod_token = input.parse()?; - let ident = input.parse()?; - - let content; - let brace_token = braced!(content in input); - let mut items = vec![]; - - while !content.is_empty() { - items.push(content.parse()?); - } - - Ok(Self { - attrs, - vis, - mod_token, - ident, - brace_token, - items, - }) - } -} - -/// A module that contains the definition of API functions, marked by `#[api_mod]`. -pub type ItemApiModDef = ItemApiMod; -/// A module that contains the implementation of API functions, marked by `#[api_mod_impl]`. -pub type ItemApiModImpl = ItemApiMod; diff --git a/axvisor_api_proc/src/lib.rs b/axvisor_api_proc/src/lib.rs index a538a10..f5deae7 100644 --- a/axvisor_api_proc/src/lib.rs +++ b/axvisor_api_proc/src/lib.rs @@ -2,14 +2,10 @@ use proc_macro::TokenStream as TokenStream1; use proc_macro_crate::{FoundCrate, crate_name}; use proc_macro2::{Span, TokenStream}; use quote::{quote, quote_spanned}; -use syn::{FnArg, Ident, Path, Token, spanned::Spanned}; - -mod items; - -use items::{ApiModItem, ItemApiFn, ItemApiModDef, ItemApiModImpl}; +use syn::{Ident, spanned::Spanned}; /// Find the path to the `axvisor_api` crate. -fn find_axvisor_api_crate() -> TokenStream { +fn axvisor_api_crate() -> TokenStream { match crate_name("axvisor_api") { Ok(FoundCrate::Itself) => quote! { crate }, Ok(FoundCrate::Name(name)) => { @@ -20,254 +16,63 @@ fn find_axvisor_api_crate() -> TokenStream { } } -/// Capitalize the first letter of a string. -/// -/// From: `https://stackoverflow.com/questions/38406793/why-is-capitalizing-the-first-letter-of-a-string-so-convoluted-in-rust` -fn capitalize_first_letter(s: &str) -> String { - let mut c = s.chars(); - match c.next() { - None => String::new(), - Some(f) => f.to_uppercase().collect::() + c.as_str(), - } -} - -/// Get the name of the API trait for an API module. -fn get_api_trait_name(module_name: impl AsRef, span: Span) -> Ident { - let module_name = module_name.as_ref(); - let trait_name = format!("Axvisor{}ApiTrait", capitalize_first_letter(module_name)); - Ident::new(&trait_name, span) -} - -/// Get the extra doc comments for an API module definition. -fn get_api_mod_def_extra_doc_comments( - mod_ident: &Ident, - api_fn_items: &Vec<&ItemApiFn>, -) -> TokenStream { - if api_fn_items.is_empty() { - return quote! { - #[doc = ""] - #[doc = "This module does not contain any API functions to be implemented."] - }; - } - - let mod_name = mod_ident.to_string(); - let api_fn_count = api_fn_items.len(); - let api_fn_count_hint = format!( - "This module contains {} API function{} to be implemented:", - api_fn_count, - if api_fn_count == 1 { "" } else { "s" } - ); - let api_fn_list = api_fn_items - .iter() - .map(|f| format!("- [`{0}`]({1}::{0})", f.sig.ident.to_string(), mod_name)); - - quote! { - #[doc = ""] - #[doc = #api_fn_count_hint] - #( - #[doc = #api_fn_list] - )* - } -} - -fn get_api_fn_def_extra_doc_comments() -> TokenStream { - quote! { - #[doc = ""] - #[doc = "This function is an API function and **should be implemented somewhere**."] - } +/// The namespace used for AxVisor APIs in +fn axvisor_api_namespace() -> Ident { + const AXVISOR_API_NS: &str = "AxVisorApi"; + Ident::new(AXVISOR_API_NS, Span::call_site()) } -/// Process an API module definition. -fn process_api_mod_def(module: ItemApiModDef) -> TokenStream { - let attrs = &module.attrs; - let vis = &module.vis; - let mod_token = &module.mod_token; - let mod_ident = &module.ident; - - // Split the items into regular items and API functions - let mut regular_items = vec![]; - let mut api_fn_items = vec![]; - - for item in &module.items { - match item { - ApiModItem::Regular(item) => regular_items.push(item), - ApiModItem::ApiFn(item) => api_fn_items.push(item), - } - } - - let extra_doc_comments = get_api_mod_def_extra_doc_comments(&mod_ident, &api_fn_items); - - if api_fn_items.is_empty() { - return quote! { - #(#attrs)* - #extra_doc_comments - #vis #mod_token #mod_ident { - #(#regular_items)* - } - }; - } - - let axvisor_api_path = find_axvisor_api_crate(); - - // Generate the API trait - let trait_ident = get_api_trait_name(mod_ident.to_string(), mod_token.span()); - let api_fn_attrs = api_fn_items - .iter() - .map(|item| &item.attrs) - .collect::>(); - let api_fn_signatures = api_fn_items - .iter() - .map(|item| &item.sig) - .collect::>(); - - let trait_def = quote! { - #[doc(hidden)] - #[#axvisor_api_path::__priv::crate_interface::def_interface] - #[allow(non_camel_case_types)] - pub trait #trait_ident { - #(#(#api_fn_attrs)* #api_fn_signatures;)* +macro_rules! assert_empty_attr { + ($attr:expr) => { + if !$attr.is_empty() { + return (quote_spanned! { + TokenStream::from($attr).span() => compile_error!("This attribute does not accept any arguments") + }).into(); } }; - - // Generate the API function implementations - let mut api_fn_impls = quote! {}; - for api_fn_item in api_fn_items { - let attrs = &api_fn_item.attrs; - let sig = &api_fn_item.sig; - let fn_name = &sig.ident; - let args = &sig - .inputs - .iter() - .map(|arg| match arg { - FnArg::Receiver(_) => panic!("API functions cannot have self arguments"), - FnArg::Typed(pat) => &pat.pat, - }) - .collect::>(); - - let extra_doc_comments = get_api_fn_def_extra_doc_comments(); - - api_fn_impls.extend(quote! { - #(#attrs)* - #extra_doc_comments - pub #sig { - #axvisor_api_path::__priv::crate_interface::call_interface!( - #trait_ident::#fn_name, #(#args),* - ) - } - }); - } - - quote! { - #(#attrs)* - #extra_doc_comments - #vis #mod_token #mod_ident { - #(#regular_items)* - - #api_fn_impls - - #trait_def - } - } -} - -/// Reuses the path to the module to be implemented, to make sure the `impl` block can find the correct trait. -fn get_implementee_reuse_ident(implementee: &Path) -> Ident { - let mut ident = String::from(if implementee.leading_colon.is_some() { - "__axvisor_api_implementee_abs" - } else { - "__axvisor_api_implementee_rel" - }); - - for seg in implementee.segments.iter() { - ident.push('_'); - ident.push_str(seg.ident.to_string().as_str()); - } - - Ident::new(&ident, implementee.span()) } -/// Process an API module implementation. -fn process_api_mod_impl(implementee: Path, input: ItemApiModImpl) -> TokenStream { - let attrs = &input.attrs; - let vis = &input.vis; - let mod_token = &input.mod_token; - let mod_ident = &input.ident; - - let implementee_name = match implementee.segments.last() { - Some(segment) => segment.ident.to_string(), - None => return quote! { compile_error!("Invalid implementee path") }, - }; - let implementee_trait_ident = get_api_trait_name(&implementee_name, implementee.span()); - // we should reuse the implementee mod path besides the implementing mod, to make sure the `impl` block can find - // the corrent trait. - let implementee_reuse_ident = get_implementee_reuse_ident(&implementee); - - let axvisor_api_path = find_axvisor_api_crate(); - - let mut regular_items = vec![]; - let mut api_fn_items = vec![]; - for item in input.items { - match item { - ApiModItem::Regular(item) => regular_items.push(item), - ApiModItem::ApiFn(item) => api_fn_items.push(item), - } - } - - let mut api_fn_impls = TokenStream::new(); - for api_fn_item in api_fn_items { - let attrs = &api_fn_item.attrs; - let sig = &api_fn_item.sig; - let body = &api_fn_item.body; +/// Define an AxVisor API interface. +/// +/// This macro is applied to a trait definition. It generates the necessary +/// boilerplate code to register the trait as an AxVisor API interface. No +/// arguments are accepted. +/// +/// This macro uses `crate_interface::def_interface` internally. +#[proc_macro_attribute] +pub fn api_def(attr: TokenStream1, input: TokenStream1) -> TokenStream1 { + assert_empty_attr!(attr); - api_fn_impls.extend(quote! { - #(#attrs)* - #sig #body - }); - } + let axvisor_api_path = axvisor_api_crate(); + let ns = axvisor_api_namespace(); + let input: TokenStream = syn::parse_macro_input!(input as TokenStream); quote! { - #[doc(hidden)] - use #implementee as #implementee_reuse_ident; - - #(#attrs)* - #vis #mod_token #mod_ident { - #(#regular_items)* - - #[doc(hidden)] - pub struct __Impl; - #[#axvisor_api_path::__priv::crate_interface::impl_interface] - impl super::#implementee_reuse_ident::#implementee_trait_ident for __Impl { - #api_fn_impls - } - } + #[#axvisor_api_path::__priv::crate_interface::def_interface(gen_caller, namespace = #ns)] + #input } + .into() } -#[proc_macro_attribute] -/// Define a module containing API functions. +/// Implement an AxVisor API interface. /// -/// The module can contain regular items and API functions. API functions are defined with the `extern fn` syntax. +/// This macro is applied to an `impl` block that implements a trait previously +/// defined with `api_def`. It generates the necessary boilerplate code to +/// register the implementation as an AxVisor API implementation. No arguments +/// are accepted. /// -/// **Does not work on outlined modules.** (i.e. `mod foo;` with content in `foo.rs`) -pub fn api_mod(attr: TokenStream1, input: TokenStream1) -> TokenStream1 { - if !attr.is_empty() { - return (quote_spanned! { - TokenStream::from(attr).span() => compile_error!("`api_mod` attribute does not accept any arguments") - }).into(); - } +/// This macro uses `crate_interface::impl_interface` internally. +#[proc_macro_attribute] +pub fn api_impl(attr: TokenStream1, input: TokenStream1) -> TokenStream1 { + assert_empty_attr!(attr); - process_api_mod_def(syn::parse_macro_input!(input as ItemApiModDef)).into() -} + let axvisor_api_path = axvisor_api_crate(); + let ns = axvisor_api_namespace(); + let input: TokenStream = syn::parse_macro_input!(input as TokenStream); -#[proc_macro_attribute] -/// Implement the API functions defined in another module. -/// -/// The module should contain the implementation of the API functions defined in another module. The path to the module -/// defining the APIs should be passed as the argument. -pub fn api_mod_impl(attr: TokenStream1, input: TokenStream1) -> TokenStream1 { - process_api_mod_impl( - syn::parse_macro_input!(attr as Path), - syn::parse_macro_input!(input as ItemApiModImpl), - ) + quote! { + #[#axvisor_api_path::__priv::crate_interface::impl_interface(namespace = #ns)] + #input + } .into() } diff --git a/examples/example.rs b/examples/example.rs index bc6a356..ddf8894 100644 --- a/examples/example.rs +++ b/examples/example.rs @@ -1,31 +1,43 @@ extern crate axvisor_api; extern crate memory_addr; -use axvisor_api::{__priv, api_mod, api_mod_impl}; +use axvisor_api::__priv; -#[api_mod] -/// Memory-related API pub mod some_demo { + use memory_addr::MemoryAddr; pub use memory_addr::PhysAddr; - /// Some function - extern fn some_func() -> PhysAddr; - /// Another function - extern fn another_func(addr: PhysAddr); + #[axvisor_api::api_def] + pub trait SomeDemoIf { + /// Some function provided by the implementer + fn some_func() -> PhysAddr; + /// Another function provided by the implementer + fn another_func(addr: PhysAddr); + } + + /// Some function provided by the API definer + pub fn provided_func() -> PhysAddr { + some_func().add(0x1000) + } } -#[api_mod_impl(some_demo)] -mod some_impl { - use memory_addr::{PhysAddr, pa}; +mod some_demo_impl { + use crate::some_demo::SomeDemoIf; - extern fn some_func() -> PhysAddr { - return pa!(0x42); - } + pub struct SomeDemoImpl; + + #[axvisor_api::api_impl] + impl SomeDemoIf for SomeDemoImpl { + fn some_func() -> memory_addr::PhysAddr { + memory_addr::pa!(0x42) + } - extern fn another_func(addr: PhysAddr) { - println!("Wow, the answer is {:?}", addr); + fn another_func(addr: memory_addr::PhysAddr) { + println!("Wow, the answer is {:?}", addr); + } } } fn main() { some_demo::another_func(some_demo::some_func()); + some_demo::another_func(some_demo::provided_func()); } diff --git a/src/arch.rs b/src/arch.rs new file mode 100644 index 0000000..62f78c1 --- /dev/null +++ b/src/arch.rs @@ -0,0 +1,24 @@ +//! Architecture-specific APIs. + +use super::{memory::PhysAddr, vmm::InterruptVector}; + +#[crate::api_def] +pub trait ArchIf { + /// Inject a virtual interrupt to the current virtual CPU. + #[cfg(target_arch = "aarch64")] + fn hardware_inject_virtual_interrupt(vector: InterruptVector); + + /// Get the TYPER register of the GIC distributor. Used in virtual GIC initialization. + #[cfg(target_arch = "aarch64")] + fn read_vgicd_typer() -> u32; + /// Get the IIDR register of the GIC distributor. Used in virtual GIC initialization. + #[cfg(target_arch = "aarch64")] + fn read_vgicd_iidr() -> u32; + + /// Get the base address of the GIC distributor in the host system. + #[cfg(target_arch = "aarch64")] + fn get_host_gicd_base() -> PhysAddr; + /// Get the base address of the GIC redistributor in the host system. + #[cfg(target_arch = "aarch64")] + fn get_host_gicr_base() -> PhysAddr; +} diff --git a/src/host.rs b/src/host.rs new file mode 100644 index 0000000..a854b1c --- /dev/null +++ b/src/host.rs @@ -0,0 +1,7 @@ +//! Host system related APIs. + +#[crate::api_def] +pub trait HostIf { + /// Get the total number of cpus in the host system. + fn get_host_cpu_num() -> usize; +} diff --git a/src/lib.rs b/src/lib.rs index 10a25ae..00f2a54 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,274 +1,142 @@ -//! `axvisor_api` is a library that provides: -//! - a set of Rust API for all components of the `axvisor` Hypervisor, including: -//! -//! - memory management, -//! - time and timer management, -//! - interrupt management, -//! - ... -//! -//! these APIs are defined here, should be implemented by the axvisor Hypervisor, and can be use by all components. -//! -//! - a standard way to define and implement APIs, including the [`api_mod`] and the [`api_mod_impl`] attributes, which -//! the components can utilize to define and implement their own APIs. +//! `axvisor_api` is the bottom-most crate of the AxVisor Hypervisor project. It +//! provides a standardized set of APIs for the components of the Hypervisor and +//! grants them access to OS-level and Hypervisor-level functionalities, like +//! memory allocation, address conversion, time and timer management, cross-vcpu +//! operations, and so on. +//! +//! `axvisor_api` is designed for two main purposes: +//! - **Replace generic-based API-injection mechanism.** +//! +//! Generic-based API-injection mechanism, for example: +//! +//! ```rust +//! pub trait VCpuHal { +//! /* ... */ +//! } +//! pub struct VCpu { +//! /* ... */ +//! # _marker: core::marker::PhantomData, +//! } +//! ``` +//! +//! has been widely used previously here and in other related projects. It's +//! definitely great, with zero overhead, good readability, and no link-time +//! magic. However, it turns out that passing generic parameters down through +//! multiple layers of modules and components is quite inconvenient, and it's +//! always a pain to decide how to categorize the APIs into different traits +//! properly. +//! +//! Finally, the author decided to just use a big monolithic trait for every +//! component, and use `crate_interface` to eliminate the generic parameter. +//! (Although there are multiple traits in this crate, technically in the +//! current implementation the link-time symbol space is used as a big +//! monolithic trait.) Theoretically, this may slightly increase the +//! difficulty of re-using a single component in a new software project, but +//! the author believes that it will reduce the overall complexity when not +//! one but a few related components are re-used together. +//! +//! - **Enable portability of the Hypervisor across different unikernels.** +//! +//! Technically, the whole AxVisor Hypervisor can be ported to different +//! unikernels by implementing the APIs defined in this crate (although not +//! tested yet). If such porting is successful, this crate can also be used as +//! a tested hardware-and-unikernel abstraction layer for other hypervisor +//! projects. +//! +//! This crate also provides a standard way to define and implement APIs, with +//! the [`api_def`] and [`api_impl`] procedural macros. They are built on top of +//! the `crate_interface` crate, which provides the low-level functionalities +//! of defining and implementing crate-level interfaces. //! //! # How to define and implement APIs //! //! ## Define APIs //! -//! To define APIs, you can use the `api_mod` attribute to define a module containing the API functions. An API -//! function is defined with the `extern fn` syntax. Note that Vanilla Rust does not support defining extern functions -//! in such a way, so the definition of the API functions can easily be distinguished from the regular functions. +//! To define APIs, you can use the `api_def` attribute on a trait defining the +//! API, with each API function defined as a regular function in the trait. It's +//! recommended to pack the trait definition and related definitions (like type +//! aliases) into a module for better organization. //! //! ```rust, standalone_crate -//! # use axvisor_api::{api_mod, __priv}; // some inconviniece brought by proc-macro-name and doctest +//! # // some inconviniece brought by proc-macro-name and doctest +//! # use axvisor_api::__priv; //! # fn main() {} -//! #[api_mod] -//! /// Memory-related API -//! pub mod memory_demo { -//! pub use memory_addr::PhysAddr; +//! mod example { +//! # // some inconviniece brought by proc-macro-name and doctest +//! # use axvisor_api::api_def; +//! /// Example API definition +//! #[api_def] +//! pub trait ExampleIf { +//! /// An example API function +//! fn example_func(arg: usize) -> usize; +//! /// Another example API function +//! fn another_func(); +//! } +//! } //! -//! /// Allocate a frame -//! extern fn alloc_frame() -> Option; -//! /// Deallocate a frame -//! extern fn dealloc_frame(addr: PhysAddr); +//! fn use_example_api() { +//! let result = example::example_func(42); +//! example::another_func(); //! } //! ``` //! -//! Defined APIs can be invoked by other components: +//! `api_def` will generate a caller function for each API function defined in +//! the trait, at the same level as the trait definition. The generated callers +//! can be used to invoke the API functions, as demonstrated above. //! -//! ```rust, no_run, standalone_crate -//! # use axvisor_api::{api_mod, __priv}; // some inconviniece brought by proc-macro-name and doctest -//! # fn main() {} -//! # #[api_mod] -//! # /// Memory-related API -//! # pub mod memory_demo { -//! # pub use memory_addr::PhysAddr; -//! # -//! # /// Allocate a frame -//! # extern fn alloc_frame() -> Option; -//! # /// Deallocate a frame -//! # extern fn dealloc_frame(addr: PhysAddr); -//! # } -//! struct SomeComponent; +//! ## Implement APIs //! -//! impl SomeComponent { -//! fn some_method() { -//! let frame = memory_demo::alloc_frame().unwrap(); -//! // Do something with the frame -//! memory_demo::dealloc_frame(frame); +//! Defined APIs should be implemented somewhere, unless they are not used +//! anywhere. To implement APIs, the implementer should define a empty struct +//! and implement the API trait for the struct, with the `api_impl` attribute on +//! the `impl` block. For example, +//! +//! ```rust, standalone_crate +//! # // some inconviniece brought by proc-macro-name and doctest +//! # use axvisor_api::{api_impl, __priv}; +//! mod example { +//! # // some inconviniece brought by proc-macro-name and doctest +//! # use axvisor_api::{api_def, __priv}; +//! /// Example API definition +//! #[api_def] +//! pub trait ExampleIf { +//! /// An example API function +//! fn example_func(arg: usize) -> usize; +//! /// Another example API function +//! fn another_func(); //! } //! } -//! ``` -//! -//! ## Implement APIs -//! -//! Defined APIs should be implemented by the Hypervisor, or other components that are able and responsible to do so. To -//! implement APIs, you can use the `api_mod_impl` attribute, with the path of the module defining the APIs as the -//! argument, on a module containing the implementation of the API functions. The implementations of the API functions -//! are also defined with the `extern fn` syntax. //! -//! ```rust, no_run, standalone_crate -//! # use axvisor_api::{api_mod, api_mod_impl, __priv}; // some inconviniece brought by proc-macro-name and doctest -//! # fn main() {} -//! # #[api_mod] -//! # /// Memory-related API -//! # pub mod memory_demo { -//! # pub use memory_addr::PhysAddr; -//! # -//! # /// Allocate a frame -//! # extern fn alloc_frame() -> Option; -//! # /// Deallocate a frame -//! # extern fn dealloc_frame(addr: PhysAddr); -//! # } -//! #[api_mod_impl(memory_demo)] -//! mod memory_impl { -//! use memory_addr::PhysAddr; +//! struct ExampleImpl; //! -//! extern fn alloc_frame() -> Option { -//! // Implementation of the `alloc_frame` API -//! todo!() +//! #[api_impl] +//! impl example::ExampleIf for ExampleImpl { +//! fn example_func(arg: usize) -> usize { +//! arg + 1 //! } //! -//! extern fn dealloc_frame(addr: PhysAddr) { -//! // Implementation of the `dealloc_frame` API -//! todo!() +//! fn another_func() { +//! println!("Another function called"); //! } //! } -//! ``` //! -//! ## Tricks behind the macros -//! -//! [`api_mod`] and [`api_mod_impl`] are wrappers around the great [`crate_interface`] crate, with some macro tricks to -//! make the usage more convenient. +//! fn main() { +//! let result = example::example_func(42); +//! assert_eq!(result, 43); +//! example::another_func(); // prints "Another function called" +//! } +//! ``` //! #![no_std] -pub use axvisor_api_proc::{api_mod, api_mod_impl}; - -#[api_mod] -/// Memory-related API. -pub mod memory { - pub use memory_addr::{PhysAddr, VirtAddr}; - - // API interfaces +pub use axvisor_api_proc::{api_def, api_impl}; - /// Allocate a frame. - extern fn alloc_frame() -> Option; - /// Allocate a number of contiguous frames, with a specified alignment. - extern fn alloc_contiguous_frames( - num_frames: usize, - frame_align_pow2: usize, - ) -> Option; - /// Deallocate a frame. - extern fn dealloc_frame(addr: PhysAddr); - /// Deallocate a number of contiguous frames. - extern fn dealloc_contiguous_frames(first_addr: PhysAddr, num_frames: usize); - /// Convert a physical address to a virtual address. - extern fn phys_to_virt(addr: PhysAddr) -> VirtAddr; - /// Convert a virtual address to a physical address. - extern fn virt_to_phys(addr: VirtAddr) -> PhysAddr; - - // Re-exports - // TODO: determine whether it's proper and acceptable to place this definition here in this mod. - /// [`AxMmHal`](axaddrspace::AxMmHal) implementation by axvisor_api. - #[doc(hidden)] - pub struct AxMmHalApiImpl; - - impl axaddrspace::AxMmHal for AxMmHalApiImpl { - fn alloc_frame() -> Option { - alloc_frame() - } - - fn dealloc_frame(addr: PhysAddr) { - dealloc_frame(addr) - } - - fn phys_to_virt(addr: PhysAddr) -> VirtAddr { - phys_to_virt(addr) - } - - fn virt_to_phys(addr: VirtAddr) -> PhysAddr { - virt_to_phys(addr) - } - } - - /// A physical frame which will be automatically deallocated when dropped. - pub type PhysFrame = axaddrspace::PhysFrame; -} - -#[api_mod] -/// Time-and-timer-related API. -pub mod time { - extern crate alloc; - use alloc::boxed::Box; - use core::time::Duration; - - /// Time value. - pub type TimeValue = Duration; - /// Nanoseconds count. - pub type Nanos = u64; - /// Tick count. - pub type Ticks = u64; - /// Cancel token, used to cancel a scheduled timer event. - pub type CancelToken = usize; - - /// Get the current tick count. - extern fn current_ticks() -> Ticks; - /// Get the current time in nanoseconds. - pub fn current_time_nanos() -> Nanos { - ticks_to_nanos(current_ticks()) - } - /// Get the current time. - pub fn current_time() -> TimeValue { - Duration::from_nanos(current_time_nanos()) - } - - /// Convert ticks to nanoseconds. - extern fn ticks_to_nanos(ticks: Ticks) -> Nanos; - /// Convert ticks to time. - pub fn ticks_to_time(ticks: Ticks) -> TimeValue { - Duration::from_nanos(ticks_to_nanos(ticks)) - } - /// Convert nanoseconds to ticks. - extern fn nanos_to_ticks(nanos: Nanos) -> Ticks; - /// Convert time to ticks. - pub fn time_to_ticks(time: TimeValue) -> Ticks { - nanos_to_ticks(time.as_nanos() as Nanos) - } - - /// Register a timer. - extern fn register_timer( - deadline: TimeValue, - callback: Box, - ) -> CancelToken; - /// Cancel a timer. - extern fn cancel_timer(token: CancelToken); -} - -#[api_mod] -/// Virtual machine management API. -pub mod vmm { - /// Virtual machine ID. - pub type VMId = usize; - /// Virtual CPU ID. - pub type VCpuId = usize; - /// Interrupt vector. - pub type InterruptVector = u8; - - /// Get the ID of the current virtual machine. - extern fn current_vm_id() -> VMId; - /// Get the ID of the current virtual CPU. - extern fn current_vcpu_id() -> VCpuId; - /// Get the number of virtual CPUs in a virtual machine. - extern fn vcpu_num(vm_id: VMId) -> Option; - /// Get the mask of active virtual CPUs in a virtual machine. - extern fn active_vcpus(vm_id: VMId) -> Option; - /// Get the number of virtual CPUs in the current virtual machine. - pub fn current_vm_vcpu_num() -> usize { - vcpu_num(current_vm_id()).unwrap() - } - /// Get the mask of active virtual CPUs in the current virtual machine. - pub fn current_vm_active_vcpus() -> usize { - active_vcpus(current_vm_id()).unwrap() - } - - /// Inject an interrupt to a virtual CPU. - extern fn inject_interrupt(vm_id: VMId, vcpu_id: VCpuId, vector: InterruptVector); - /// Notify that a virtual CPU timer has expired. - /// - /// TODO: determine whether we can skip this function. - extern fn notify_vcpu_timer_expired(vm_id: VMId, vcpu_id: VCpuId); -} - -#[api_mod] -pub mod host { - /// Get the total number of cpus in the host system. - extern fn get_host_cpu_num() -> usize; -} - -#[api_mod] -pub mod arch { - use super::vmm::InterruptVector; - - #[cfg(target_arch = "aarch64")] - /// AArch64-specific API. Inject a virtual interrupt to the current virtual CPU using gich. - extern fn hardware_inject_virtual_interrupt(vector: InterruptVector); - - #[cfg(target_arch = "aarch64")] - /// AArch64-specific API. Get the TYPER register of the GIC distributor. Used in virtual GIC initialization. - extern fn read_vgicd_typer() -> u32; - #[cfg(target_arch = "aarch64")] - /// AArch64-specific API. Get the IIDR register of the GIC distributor. Used in virtual GIC initialization. - extern fn read_vgicd_iidr() -> u32; - - #[cfg(target_arch = "aarch64")] - /// AArch64-specific API. Get the base address of the GIC distributor in the host system. - extern fn get_host_gicd_base() -> crate::memory::PhysAddr; - #[cfg(target_arch = "aarch64")] - /// AArch64-specific API. Get the base address of the GIC redistributor in the host system. - extern fn get_host_gicr_base() -> crate::memory::PhysAddr; -} +pub mod arch; +pub mod host; +pub mod memory; +pub mod time; +pub mod vmm; #[doc(hidden)] pub mod __priv { diff --git a/src/memory.rs b/src/memory.rs new file mode 100644 index 0000000..0cac453 --- /dev/null +++ b/src/memory.rs @@ -0,0 +1,44 @@ +//! Memory allocation and address translation APIs. + +pub use memory_addr::{PhysAddr, VirtAddr}; + +#[crate::api_def] +pub trait MemoryIf { + /// Allocate a frame. + fn alloc_frame() -> Option; + /// Allocate a number of contiguous frames, with a specified alignment. + fn alloc_contiguous_frames(num_frames: usize, frame_align_pow2: usize) -> Option; + /// Deallocate a frame allocated previously by [`alloc_frame`]. + fn dealloc_frame(addr: PhysAddr); + /// Deallocate a number of contiguous frames. + fn dealloc_contiguous_frames(first_addr: PhysAddr, num_frames: usize); + /// Convert a physical address to a virtual address. + fn phys_to_virt(addr: PhysAddr) -> VirtAddr; + /// Convert a virtual address to a physical address. + fn virt_to_phys(addr: VirtAddr) -> PhysAddr; +} + +/// [`AxMmHal`](axaddrspace::AxMmHal) implementation by axvisor_api. +#[doc(hidden)] +pub struct AxMmHalApiImpl; + +impl axaddrspace::AxMmHal for AxMmHalApiImpl { + fn alloc_frame() -> Option { + alloc_frame() + } + + fn dealloc_frame(addr: PhysAddr) { + dealloc_frame(addr) + } + + fn phys_to_virt(addr: PhysAddr) -> VirtAddr { + phys_to_virt(addr) + } + + fn virt_to_phys(addr: VirtAddr) -> PhysAddr { + virt_to_phys(addr) + } +} + +/// A physical frame which will be automatically deallocated when dropped. +pub type PhysFrame = axaddrspace::PhysFrame; diff --git a/src/test.rs b/src/test.rs index 4aff434..9dd4c0a 100644 --- a/src/test.rs +++ b/src/test.rs @@ -1,7 +1,5 @@ use memory_addr::{pa, va}; -/// A demonstration of the `memory` API implementation. -#[crate::api_mod_impl(crate::memory)] mod memory_impl { use core::sync::atomic::AtomicUsize; use memory_addr::{PhysAddr, VirtAddr, pa, va}; @@ -10,25 +8,38 @@ mod memory_impl { static RETURNED_SUM: AtomicUsize = AtomicUsize::new(0); pub const VA_PA_OFFSET: usize = 0x1000; - extern fn alloc_frame() -> Option { - let value = ALLOCATED.fetch_add(1, core::sync::atomic::Ordering::SeqCst); + pub struct MemoryIfImpl; - Some(pa!(value * 0x1000)) - } + #[crate::api_impl] + impl crate::memory::MemoryIf for MemoryIfImpl { + fn alloc_frame() -> Option { + let value = ALLOCATED.fetch_add(1, core::sync::atomic::Ordering::SeqCst); - extern fn alloc_contiguous_frames( - _num_frames: usize, - _frame_align_pow2: usize, - ) -> Option { - unimplemented!(); - } + Some(pa!(value * 0x1000)) + } - extern fn dealloc_frame(addr: PhysAddr) { - RETURNED_SUM.fetch_add(addr.as_usize(), core::sync::atomic::Ordering::SeqCst); - } + fn alloc_contiguous_frames( + _num_frames: usize, + _frame_align_pow2: usize, + ) -> Option { + unimplemented!(); + } + + fn dealloc_frame(addr: PhysAddr) { + RETURNED_SUM.fetch_add(addr.as_usize(), core::sync::atomic::Ordering::SeqCst); + } + + fn dealloc_contiguous_frames(_first_addr: PhysAddr, _num_frames: usize) { + unimplemented!(); + } + + fn phys_to_virt(addr: PhysAddr) -> VirtAddr { + va!(addr.as_usize() + VA_PA_OFFSET) // Example implementation + } - extern fn dealloc_contiguous_frames(_first_addr: PhysAddr, _num_frames: usize) { - unimplemented!(); + fn virt_to_phys(addr: VirtAddr) -> PhysAddr { + pa!(addr.as_usize() - VA_PA_OFFSET) // Example implementation + } } /// Get the sum of all returned physical addresses. @@ -42,14 +53,6 @@ mod memory_impl { ALLOCATED.store(0, core::sync::atomic::Ordering::SeqCst); RETURNED_SUM.store(0, core::sync::atomic::Ordering::SeqCst); } - - extern fn phys_to_virt(addr: PhysAddr) -> VirtAddr { - va!(addr.as_usize() + VA_PA_OFFSET) // Example implementation - } - - extern fn virt_to_phys(addr: VirtAddr) -> PhysAddr { - pa!(addr.as_usize() - VA_PA_OFFSET) // Example implementation - } } #[test] @@ -79,8 +82,7 @@ pub fn test_memory() { #[test] pub fn test_memory_phys_frame() { - use crate::memory; - use crate::memory::PhysFrame; + use crate::memory::{self, PhysFrame}; memory_impl::clear(); diff --git a/src/time.rs b/src/time.rs new file mode 100644 index 0000000..18fb933 --- /dev/null +++ b/src/time.rs @@ -0,0 +1,52 @@ +//! Time and timer APIs. + +extern crate alloc; + +use alloc::boxed::Box; +use core::time::Duration; + +/// Time value. +pub type TimeValue = Duration; +/// Nanoseconds count. +pub type Nanos = u64; +/// Tick count. +pub type Ticks = u64; +/// Cancel token, used to cancel a scheduled timer event. +pub type CancelToken = usize; + +#[crate::api_def] +pub trait TimeIf { + /// Get the current tick count. + fn current_ticks() -> Ticks; + /// Convert ticks to nanoseconds. + fn ticks_to_nanos(ticks: Ticks) -> Nanos; + /// Convert nanoseconds to ticks. + fn nanos_to_ticks(nanos: Nanos) -> Ticks; + /// Register a timer. + fn register_timer( + deadline: TimeValue, + callback: Box, + ) -> CancelToken; + /// Cancel a timer. + fn cancel_timer(token: CancelToken); +} + +/// Get the current time in nanoseconds. +pub fn current_time_nanos() -> Nanos { + ticks_to_nanos(current_ticks()) +} + +/// Get the current time. +pub fn current_time() -> TimeValue { + Duration::from_nanos(current_time_nanos()) +} + +/// Convert ticks to time. +pub fn ticks_to_time(ticks: Ticks) -> TimeValue { + Duration::from_nanos(ticks_to_nanos(ticks)) +} + +/// Convert time to ticks. +pub fn time_to_ticks(time: TimeValue) -> Ticks { + nanos_to_ticks(time.as_nanos() as Nanos) +} diff --git a/src/vmm.rs b/src/vmm.rs new file mode 100644 index 0000000..7d64def --- /dev/null +++ b/src/vmm.rs @@ -0,0 +1,36 @@ +//! Virtual machine management APIs. + +/// Virtual machine ID. +pub type VMId = usize; +/// Virtual CPU ID. +pub type VCpuId = usize; +/// Interrupt vector. +pub type InterruptVector = u8; + +#[crate::api_def] +pub trait VmmIf { + /// Get the ID of the current virtual machine. + fn current_vm_id() -> VMId; + /// Get the ID of the current virtual CPU. + fn current_vcpu_id() -> VCpuId; + /// Get the number of virtual CPUs in a virtual machine. + fn vcpu_num(vm_id: VMId) -> Option; + /// Get the mask of active virtual CPUs in a virtual machine. + fn active_vcpus(vm_id: VMId) -> Option; + /// Inject an interrupt to a virtual CPU. + fn inject_interrupt(vm_id: VMId, vcpu_id: VCpuId, vector: InterruptVector); + /// Notify that a virtual CPU timer has expired. + /// + /// TODO: determine whether we can skip this function. + fn notify_vcpu_timer_expired(vm_id: VMId, vcpu_id: VCpuId); +} + +/// Get the number of virtual CPUs in the current virtual machine. +pub fn current_vm_vcpu_num() -> usize { + vcpu_num(current_vm_id()).unwrap() +} + +/// Get the mask of active virtual CPUs in the current virtual machine. +pub fn current_vm_active_vcpus() -> usize { + active_vcpus(current_vm_id()).unwrap() +} From 9fb87a670076854031f36565655e8319cbb62175 Mon Sep 17 00:00:00 2001 From: aarkegz Date: Wed, 7 Jan 2026 09:09:45 +0000 Subject: [PATCH 2/3] fix missing docs --- src/arch.rs | 1 + src/host.rs | 1 + src/memory.rs | 1 + src/time.rs | 1 + src/vmm.rs | 1 + 5 files changed, 5 insertions(+) diff --git a/src/arch.rs b/src/arch.rs index 62f78c1..c11b030 100644 --- a/src/arch.rs +++ b/src/arch.rs @@ -2,6 +2,7 @@ use super::{memory::PhysAddr, vmm::InterruptVector}; +/// The API trait for architecture-specific functionalities. #[crate::api_def] pub trait ArchIf { /// Inject a virtual interrupt to the current virtual CPU. diff --git a/src/host.rs b/src/host.rs index a854b1c..5d27eab 100644 --- a/src/host.rs +++ b/src/host.rs @@ -1,5 +1,6 @@ //! Host system related APIs. +/// The API trait for host system functionalities. #[crate::api_def] pub trait HostIf { /// Get the total number of cpus in the host system. diff --git a/src/memory.rs b/src/memory.rs index 0cac453..d247610 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -2,6 +2,7 @@ pub use memory_addr::{PhysAddr, VirtAddr}; +/// The API trait for memory allocation and address translation functionalities. #[crate::api_def] pub trait MemoryIf { /// Allocate a frame. diff --git a/src/time.rs b/src/time.rs index 18fb933..ad11f59 100644 --- a/src/time.rs +++ b/src/time.rs @@ -14,6 +14,7 @@ pub type Ticks = u64; /// Cancel token, used to cancel a scheduled timer event. pub type CancelToken = usize; +/// The API trait for time and timer functionalities. #[crate::api_def] pub trait TimeIf { /// Get the current tick count. diff --git a/src/vmm.rs b/src/vmm.rs index 7d64def..5d3ee25 100644 --- a/src/vmm.rs +++ b/src/vmm.rs @@ -7,6 +7,7 @@ pub type VCpuId = usize; /// Interrupt vector. pub type InterruptVector = u8; +/// The API trait for virtual machine management functionalities. #[crate::api_def] pub trait VmmIf { /// Get the ID of the current virtual machine. From e524a4d68d3758bca5432e8156ee368bcf9f2368 Mon Sep 17 00:00:00 2001 From: aarkegz Date: Wed, 7 Jan 2026 09:19:00 +0000 Subject: [PATCH 3/3] fix documents, add lock for test --- axvisor_api_proc/src/lib.rs | 2 +- src/lib.rs | 10 +++++----- src/memory.rs | 3 ++- src/test.rs | 31 ++++++++++++++++++++++--------- src/time.rs | 2 +- 5 files changed, 31 insertions(+), 17 deletions(-) diff --git a/axvisor_api_proc/src/lib.rs b/axvisor_api_proc/src/lib.rs index f5deae7..b8f1c90 100644 --- a/axvisor_api_proc/src/lib.rs +++ b/axvisor_api_proc/src/lib.rs @@ -16,7 +16,7 @@ fn axvisor_api_crate() -> TokenStream { } } -/// The namespace used for AxVisor APIs in +/// The namespace used for AxVisor APIs when calling `crate_interface` macros. fn axvisor_api_namespace() -> Ident { const AXVISOR_API_NS: &str = "AxVisorApi"; Ident::new(AXVISOR_API_NS, Span::call_site()) diff --git a/src/lib.rs b/src/lib.rs index 00f2a54..fc50c81 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -58,11 +58,11 @@ //! aliases) into a module for better organization. //! //! ```rust, standalone_crate -//! # // some inconviniece brought by proc-macro-name and doctest +//! # // some inconvenience brought by proc-macro-name and doctest //! # use axvisor_api::__priv; //! # fn main() {} //! mod example { -//! # // some inconviniece brought by proc-macro-name and doctest +//! # // some inconvenience brought by proc-macro-name and doctest //! # use axvisor_api::api_def; //! /// Example API definition //! #[api_def] @@ -87,15 +87,15 @@ //! ## Implement APIs //! //! Defined APIs should be implemented somewhere, unless they are not used -//! anywhere. To implement APIs, the implementer should define a empty struct +//! anywhere. To implement APIs, the implementer should define an empty struct //! and implement the API trait for the struct, with the `api_impl` attribute on //! the `impl` block. For example, //! //! ```rust, standalone_crate -//! # // some inconviniece brought by proc-macro-name and doctest +//! # // some inconvenience brought by proc-macro-name and doctest //! # use axvisor_api::{api_impl, __priv}; //! mod example { -//! # // some inconviniece brought by proc-macro-name and doctest +//! # // some inconvenience brought by proc-macro-name and doctest //! # use axvisor_api::{api_def, __priv}; //! /// Example API definition //! #[api_def] diff --git a/src/memory.rs b/src/memory.rs index d247610..cc19682 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -11,7 +11,8 @@ pub trait MemoryIf { fn alloc_contiguous_frames(num_frames: usize, frame_align_pow2: usize) -> Option; /// Deallocate a frame allocated previously by [`alloc_frame`]. fn dealloc_frame(addr: PhysAddr); - /// Deallocate a number of contiguous frames. + /// Deallocate a number of contiguous frames allocated previously by + /// [`alloc_contiguous_frames`]. fn dealloc_contiguous_frames(first_addr: PhysAddr, num_frames: usize); /// Convert a physical address to a virtual address. fn phys_to_virt(addr: PhysAddr) -> VirtAddr; diff --git a/src/test.rs b/src/test.rs index 9dd4c0a..2dc1eb9 100644 --- a/src/test.rs +++ b/src/test.rs @@ -1,11 +1,17 @@ use memory_addr::{pa, va}; mod memory_impl { - use core::sync::atomic::AtomicUsize; + extern crate std; // in test only + use memory_addr::{PhysAddr, VirtAddr, pa, va}; + use std::sync::{ + Mutex, MutexGuard, + atomic::{AtomicUsize, Ordering}, + }; static ALLOCATED: AtomicUsize = AtomicUsize::new(0); static RETURNED_SUM: AtomicUsize = AtomicUsize::new(0); + static LOCK: Mutex<()> = Mutex::new(()); pub const VA_PA_OFFSET: usize = 0x1000; pub struct MemoryIfImpl; @@ -13,7 +19,7 @@ mod memory_impl { #[crate::api_impl] impl crate::memory::MemoryIf for MemoryIfImpl { fn alloc_frame() -> Option { - let value = ALLOCATED.fetch_add(1, core::sync::atomic::Ordering::SeqCst); + let value = ALLOCATED.fetch_add(1, Ordering::Relaxed); Some(pa!(value * 0x1000)) } @@ -26,7 +32,7 @@ mod memory_impl { } fn dealloc_frame(addr: PhysAddr) { - RETURNED_SUM.fetch_add(addr.as_usize(), core::sync::atomic::Ordering::SeqCst); + RETURNED_SUM.fetch_add(addr.as_usize(), Ordering::Relaxed); } fn dealloc_contiguous_frames(_first_addr: PhysAddr, _num_frames: usize) { @@ -46,12 +52,15 @@ mod memory_impl { /// /// Note that this function demonstrates that non-API functions work well in a module with the `api_mod_impl` attribute. pub fn get_returned_sum() -> usize { - RETURNED_SUM.load(core::sync::atomic::Ordering::SeqCst) + RETURNED_SUM.load(Ordering::Relaxed) } - pub fn clear() { - ALLOCATED.store(0, core::sync::atomic::Ordering::SeqCst); - RETURNED_SUM.store(0, core::sync::atomic::Ordering::SeqCst); + /// Start a test by acquiring the lock and resetting the internal state. + pub fn enter_test() -> MutexGuard<'static, ()> { + let guard = LOCK.lock().unwrap(); + ALLOCATED.store(0, Ordering::Relaxed); + RETURNED_SUM.store(0, Ordering::Relaxed); + guard } } @@ -59,7 +68,7 @@ mod memory_impl { pub fn test_memory() { use crate::memory; - memory_impl::clear(); + let guard = memory_impl::enter_test(); let frame1 = memory::alloc_frame(); let frame2 = memory::alloc_frame(); @@ -78,13 +87,15 @@ pub fn test_memory() { assert_eq!(memory::phys_to_virt(pa!(0)), va!(memory_impl::VA_PA_OFFSET)); assert_eq!(memory::virt_to_phys(va!(memory_impl::VA_PA_OFFSET)), pa!(0)); + + drop(guard); } #[test] pub fn test_memory_phys_frame() { use crate::memory::{self, PhysFrame}; - memory_impl::clear(); + let guard = memory_impl::enter_test(); let _ = memory::alloc_frame(); let frame1 = PhysFrame::alloc().unwrap(); @@ -101,4 +112,6 @@ pub fn test_memory_phys_frame() { assert_eq!(memory_impl::get_returned_sum(), 0x5000); drop(frame1); assert_eq!(memory_impl::get_returned_sum(), 0x6000); + + drop(guard); } diff --git a/src/time.rs b/src/time.rs index ad11f59..1e8129f 100644 --- a/src/time.rs +++ b/src/time.rs @@ -11,7 +11,7 @@ pub type TimeValue = Duration; pub type Nanos = u64; /// Tick count. pub type Ticks = u64; -/// Cancel token, used to cancel a scheduled timer event. +/// Cancel token, used to cancel a scheduled timer event. pub type CancelToken = usize; /// The API trait for time and timer functionalities.