├── .platform ├── .gitignore ├── CODEOWNERS ├── .gitmodules ├── coverage_config_aarch64.json ├── coverage_config_x86_64.json ├── .github └── dependabot.yml ├── .cargo └── config ├── src ├── x86_64 │ ├── mod.rs │ ├── serialize.rs │ └── fam_wrappers.rs ├── arm64 │ ├── mod.rs │ ├── fam_wrappers.rs │ └── serialize.rs ├── riscv64 │ ├── mod.rs │ ├── fam_wrappers.rs │ └── serialize.rs ├── lib.rs └── serialize.rs ├── Cargo.toml ├── .buildkite └── custom-tests.json ├── README.md ├── CHANGELOG.md ├── CONTRIBUTING.md └── LICENSE /.platform: -------------------------------------------------------------------------------- 1 | x86_64 2 | aarch64 3 | riscv64 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | Cargo.lock 4 | .idea 5 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Add the list of code owners here (using their GitHub username) 2 | * gatekeeper-PullAssigner 3 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "rust-vmm-ci"] 2 | path = rust-vmm-ci 3 | url = https://github.com/rust-vmm/rust-vmm-ci.git 4 | -------------------------------------------------------------------------------- /coverage_config_aarch64.json: -------------------------------------------------------------------------------- 1 | { 2 | "coverage_score": 60.9, 3 | "exclude_path": "", 4 | "crate_features": "fam-wrappers,serde" 5 | } 6 | -------------------------------------------------------------------------------- /coverage_config_x86_64.json: -------------------------------------------------------------------------------- 1 | { 2 | "coverage_score": 79.17, 3 | "exclude_path": ".*bindings\\.rs", 4 | "crate_features": "fam-wrappers,serde" 5 | } 6 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: gitsubmodule 4 | directory: "/" 5 | schedule: 6 | interval: monthly 7 | open-pull-requests-limit: 10 8 | -------------------------------------------------------------------------------- /.cargo/config: -------------------------------------------------------------------------------- 1 | # This workaround is needed because the linker is unable to find __addtf3, 2 | # __multf3 and __subtf3. 3 | # Related issue: https://github.com/rust-lang/compiler-builtins/issues/201 4 | [target.aarch64-unknown-linux-musl] 5 | rustflags = [ "-C", "target-feature=+crt-static", "-C", "link-arg=-lgcc"] 6 | -------------------------------------------------------------------------------- /src/x86_64/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | #[allow(clippy::undocumented_unsafe_blocks)] 4 | #[allow(clippy::all)] 5 | pub mod bindings; 6 | #[cfg(feature = "fam-wrappers")] 7 | pub mod fam_wrappers; 8 | 9 | #[cfg(feature = "serde")] 10 | mod serialize; 11 | 12 | pub use self::bindings::*; 13 | #[cfg(feature = "fam-wrappers")] 14 | pub use self::fam_wrappers::*; 15 | -------------------------------------------------------------------------------- /src/arm64/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #[allow(clippy::all)] 5 | #[allow(clippy::undocumented_unsafe_blocks)] 6 | pub mod bindings; 7 | #[cfg(feature = "fam-wrappers")] 8 | pub mod fam_wrappers; 9 | 10 | #[cfg(feature = "serde")] 11 | mod serialize; 12 | 13 | pub use self::bindings::*; 14 | #[cfg(feature = "fam-wrappers")] 15 | pub use self::fam_wrappers::*; 16 | -------------------------------------------------------------------------------- /src/riscv64/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2024 © Institute of Software, CAS. All rights reserved. 2 | // Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | #[allow(clippy::all)] 6 | #[allow(clippy::undocumented_unsafe_blocks)] 7 | pub mod bindings; 8 | #[cfg(feature = "fam-wrappers")] 9 | pub mod fam_wrappers; 10 | 11 | #[cfg(feature = "serde")] 12 | mod serialize; 13 | 14 | pub use self::bindings::*; 15 | #[cfg(feature = "fam-wrappers")] 16 | pub use self::fam_wrappers::*; 17 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "kvm-bindings" 3 | version = "0.10.0" 4 | authors = ["Amazon firecracker team "] 5 | description = "Rust FFI bindings to KVM generated using bindgen." 6 | repository = "https://github.com/rust-vmm/kvm-bindings" 7 | readme = "README.md" 8 | keywords = ["kvm"] 9 | license = "Apache-2.0" 10 | 11 | [package.metadata.docs.rs] 12 | all-features = true 13 | rustdoc-args = ["--cfg", "docsrs"] 14 | 15 | [features] 16 | fam-wrappers = ["vmm-sys-util"] 17 | # It is not needed to enable the `serde` feature of `vmm-sys-util` here, because due to how cargo merges features, 18 | # if a downstream crate enables vmm-sys-util in its Cargo.toml, it will get enabled globally. 19 | serde = ["dep:serde", "serde/derive", "dep:zerocopy"] 20 | 21 | 22 | [dependencies] 23 | vmm-sys-util = { version = "0.12.1", optional = true } 24 | serde = { version = "1.0.0", optional = true, features = ["derive"] } 25 | zerocopy = { version = "0.7.32", optional = true, features = ["derive"] } 26 | 27 | [dev-dependencies] 28 | bincode = "1.3.3" 29 | serde_json = "1.0.125" 30 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //! Rust FFI bindings to KVM, generated using [bindgen](https://crates.io/crates/bindgen). 5 | 6 | #![allow(non_upper_case_globals)] 7 | #![allow(non_camel_case_types)] 8 | #![allow(non_snake_case)] 9 | #![cfg_attr(docsrs, feature(doc_auto_cfg))] 10 | 11 | #[cfg(feature = "fam-wrappers")] 12 | #[macro_use] 13 | extern crate vmm_sys_util; 14 | 15 | #[cfg(feature = "serde")] 16 | extern crate serde; 17 | 18 | #[cfg(feature = "serde")] 19 | extern crate zerocopy; 20 | 21 | #[cfg(feature = "serde")] 22 | #[macro_use] 23 | mod serialize; 24 | 25 | #[cfg(target_arch = "x86_64")] 26 | mod x86_64; 27 | #[cfg(target_arch = "x86_64")] 28 | pub use self::x86_64::*; 29 | 30 | #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] 31 | mod arm64; 32 | #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] 33 | pub use self::arm64::*; 34 | 35 | #[cfg(target_arch = "riscv64")] 36 | mod riscv64; 37 | #[cfg(target_arch = "riscv64")] 38 | pub use self::riscv64::*; 39 | -------------------------------------------------------------------------------- /.buildkite/custom-tests.json: -------------------------------------------------------------------------------- 1 | { 2 | "tests": [ 3 | { 4 | "test_name": "build-fam-gnu", 5 | "command": "cargo build --release --features=fam-wrappers", 6 | "platform": [ 7 | "x86_64", 8 | "aarch64", 9 | "riscv64" 10 | ] 11 | }, 12 | { 13 | "test_name": "build-fam-musl", 14 | "command": "cargo build --release --features=fam-wrappers --target {target_platform}-unknown-linux-musl", 15 | "platform": [ 16 | "x86_64", 17 | "aarch64" 18 | ] 19 | }, 20 | { 21 | "test_name": "build-serde-gnu", 22 | "command": "cargo build --release --features=serde", 23 | "platform": [ 24 | "x86_64", 25 | "aarch64", 26 | "riscv64" 27 | ] 28 | }, 29 | { 30 | "test_name": "build-serde-musl", 31 | "command": "cargo build --release --features=serde --target {target_platform}-unknown-linux-musl", 32 | "platform": [ 33 | "x86_64", 34 | "aarch64" 35 | ] 36 | } 37 | ] 38 | } 39 | -------------------------------------------------------------------------------- /src/arm64/fam_wrappers.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use vmm_sys_util::fam::{FamStruct, FamStructWrapper}; 5 | 6 | use arm64::bindings::*; 7 | 8 | // There is no constant in the kernel as far as the maximum number 9 | // of registers on arm, but KVM_GET_REG_LIST usually returns around 450. 10 | const ARM64_REGS_MAX: usize = 500; 11 | 12 | // Implement the FamStruct trait for kvm_reg_list. 13 | generate_fam_struct_impl!(kvm_reg_list, u64, reg, u64, n, ARM64_REGS_MAX); 14 | 15 | // Implement the PartialEq trait for kvm_reg_list. 16 | impl PartialEq for kvm_reg_list { 17 | fn eq(&self, other: &kvm_reg_list) -> bool { 18 | // No need to call entries's eq, FamStructWrapper's PartialEq will do it for you 19 | self.n == other.n 20 | } 21 | } 22 | 23 | /// Wrapper over the `kvm_reg_list` structure. 24 | /// 25 | /// The `kvm_reg_list` structure contains a flexible array member. For details check the 26 | /// [KVM API](https://www.kernel.org/doc/Documentation/virtual/kvm/api.txt) 27 | /// documentation on `kvm_reg_list`. To provide safe access to 28 | /// the array elements, this type is implemented using 29 | /// [FamStructWrapper](../vmm_sys_util/fam/struct.FamStructWrapper.html). 30 | pub type RegList = FamStructWrapper; 31 | 32 | #[cfg(test)] 33 | mod tests { 34 | use super::RegList; 35 | 36 | #[test] 37 | fn test_reg_list_eq() { 38 | let mut wrapper = RegList::new(1).unwrap(); 39 | assert_eq!(wrapper.as_slice().len(), 1); 40 | 41 | let mut wrapper2 = wrapper.clone(); 42 | assert!(wrapper == wrapper2); 43 | 44 | wrapper.as_mut_slice()[0] = 1; 45 | assert!(wrapper != wrapper2); 46 | wrapper2.as_mut_slice()[0] = 1; 47 | assert!(wrapper == wrapper2); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/riscv64/fam_wrappers.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2024 © Institute of Software, CAS. All rights reserved. 2 | // Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | use vmm_sys_util::fam::{FamStruct, FamStructWrapper}; 6 | 7 | use riscv64::bindings::*; 8 | 9 | // There is no constant in the kernel as far as the maximum number 10 | // of registers on RISC-V, but KVM_GET_REG_LIST usually returns around 160. 11 | const RISCV64_REGS_MAX: usize = 200; 12 | 13 | // Implement the FamStruct trait for kvm_reg_list. 14 | generate_fam_struct_impl!(kvm_reg_list, u64, reg, u64, n, RISCV64_REGS_MAX); 15 | 16 | // Implement the PartialEq trait for kvm_reg_list. 17 | impl PartialEq for kvm_reg_list { 18 | fn eq(&self, other: &kvm_reg_list) -> bool { 19 | // No need to call entries's eq, FamStructWrapper's PartialEq will do it for you 20 | self.n == other.n 21 | } 22 | } 23 | 24 | /// Wrapper over the `kvm_reg_list` structure. 25 | /// 26 | /// The `kvm_reg_list` structure contains a flexible array member. For details check the 27 | /// [KVM API KVM_GET_REG_LIST](https://docs.kernel.org/virt/kvm/api.html#kvm-get-reg-list) 28 | /// documentation. To provide safe access to the array elements, this type is 29 | /// implemented using [FamStructWrapper](../vmm_sys_util/fam/struct.FamStructWrapper.html). 30 | pub type RegList = FamStructWrapper; 31 | 32 | #[cfg(test)] 33 | mod tests { 34 | use super::RegList; 35 | 36 | #[test] 37 | fn test_reg_list_eq() { 38 | let mut wrapper = RegList::new(1).unwrap(); 39 | assert_eq!(wrapper.as_slice().len(), 1); 40 | 41 | let mut wrapper2 = wrapper.clone(); 42 | assert!(wrapper == wrapper2); 43 | 44 | wrapper.as_mut_slice()[0] = 1; 45 | assert!(wrapper != wrapper2); 46 | wrapper2.as_mut_slice()[0] = 1; 47 | assert!(wrapper == wrapper2); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # This repository was archived on November 4th 2024, due to its contents being transferred to the [`rust-vmm/kvm`](https://github.com/rust-vmm/kvm) repository. 2 | 3 | [![Crates.io](https://img.shields.io/crates/v/kvm-bindings.svg)](https://crates.io/crates/kvm-bindings) 4 | ![](https://img.shields.io/crates/l/kvm-bindings.svg) 5 | # kvm-bindings 6 | Rust FFI bindings to KVM, generated using 7 | [bindgen](https://crates.io/crates/bindgen). It currently has support for the 8 | following target architectures: 9 | - x86_64 10 | - arm64 11 | - riscv64 12 | 13 | The bindings exported by this crate are statically generated using header files 14 | associated with a specific kernel version, and are not automatically synced with 15 | the kernel version running on a particular host. The user must ensure that 16 | specific structures, members, or constants are supported and valid for the 17 | kernel version they are using. For example, the `immediate_exit` field from the 18 | `kvm_run` structure is only meaningful if the `KVM_CAP_IMMEDIATE_EXIT` 19 | capability is available. Using invalid fields or features may lead to undefined 20 | behaviour. 21 | 22 | ## Usage 23 | First, add the following to your `Cargo.toml`: 24 | ```toml 25 | kvm-bindings = "0.3" 26 | ``` 27 | Next, add this to your crate root: 28 | ```rust 29 | extern crate kvm_bindings; 30 | ``` 31 | 32 | This crate also offers safe wrappers over FAM structs - FFI structs that have 33 | a Flexible Array Member in their definition. 34 | These safe wrappers can be used if the `fam-wrappers` feature is enabled for 35 | this crate. Example: 36 | ```toml 37 | kvm-bindings = { version = "0.3", features = ["fam-wrappers"]} 38 | ``` 39 | 40 | ## Dependencies 41 | The crate has an `optional` dependency to 42 | [vmm-sys-util](https://crates.io/crates/vmm-sys-util) when enabling the 43 | `fam-wrappers` feature. 44 | 45 | It also has an optional dependency on [`serde`](serde.rs) when enabling the 46 | `serde` feature, to allow serialization of bindings. Serialization of 47 | bindings happens as opaque binary blobs via [`zerocopy`](https://google.github.io/comprehensive-rust/bare-metal/useful-crates/zerocopy.html). 48 | Due to the kernel's ABI compatibility, this means that bindings serialized 49 | in version `x` of `kvm-bindings` can be deserialized in version `y` of the 50 | crate, even if the bindings have had been regenerated in the meantime. 51 | 52 | ## Regenerating Bindings 53 | 54 | Please see [`CONTRIBUTING.md`](CONTRIBUTING.md) for details on how to generate the bindings 55 | or add support for new architectures. 56 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | ## [Unreleased] 3 | 4 | ### Added 5 | 6 | ### Changed 7 | 8 | ### Removed 9 | 10 | ## [0.10.0] 11 | 12 | ### Added 13 | 14 | - RISC-V KVM bindings for Linux kernel v6.9, including serialization support. 15 | 16 | ## [0.9.1] 17 | 18 | ### Changed 19 | 20 | - Fixed and validated manual (De)Serialize implementations to work with 21 | `serde_json` crate. 22 | 23 | ## [0.9.0] 24 | 25 | ### Changed 26 | 27 | - Replaced the v6.2 bindings of arm64, x86\_64 with the v6.9 ones. 28 | 29 | ### Removed 30 | 31 | - Removed v6.2 bindings. 32 | 33 | ## [0.8.2] 34 | 35 | ### Changed 36 | 37 | - Improve performance of bindings deserialization by \~5% by avoiding 38 | a temporary allocation. 39 | 40 | ## [0.8.1] 41 | 42 | ### Fixed 43 | 44 | - Implement `Default` for `kvm_xsave2`, which fixes usage of `Xsave` 45 | unconditionally causing compile errors in downstream crates. 46 | 47 | ## [0.8.0] 48 | 49 | ### Added 50 | 51 | - An opt-in feature `serde` that enables [`serde`](https://serde.rs)-based 52 | (de)serialization of various bindings. 53 | 54 | ## [0.7.0] 55 | 56 | ### Changed 57 | - API change in the bindings from upstream kernel changes: 58 | * system\_event has been made into a new union 59 | - The x86 module has been renamed to x86\_64 for consistency (matches the kernel 60 | architecture directory name) 61 | - Added all features to the generated docs.rs documentation. 62 | 63 | ### Removed 64 | 65 | - Dropped "x86" (32-bit) x86 support 66 | 67 | ## [0.6.0] 68 | 69 | ### Changed 70 | 71 | - Updated vmm-sys-utils dependency to 0.11.0 72 | - Switched to specifying dependencies using caret requirements 73 | instead of comparision requirements 74 | 75 | ### Added 76 | 77 | - Implement `PartialEq` for fam\_wrappers 78 | 79 | ## [0.5.0] 80 | 81 | ### Changed 82 | 83 | - Replaced the v4.20 bindings with the v5.13 ones. 84 | 85 | ### Removed 86 | 87 | - Removed v4.14 bindings. 88 | 89 | ## [0.4.0] 90 | 91 | - vmm-sys-utils dependency bumped to match kvm-ioctls. 92 | 93 | ## [0.3.0] 94 | 95 | ### Added 96 | 97 | - Enabled `fam-wrappers` support on arm and arm64. 98 | - Added fam-wrapper for the arm specific `kvm_reg_list` struct. 99 | 100 | ## [0.2.0] 101 | 102 | ### Added 103 | 104 | - Added opt-in feature `fam-wrappers` that enables exporting 105 | safe wrappers over generated structs with flexible array 106 | members. This optional feature has an external dependency 107 | on `vmm-sys-util`. 108 | - Added safe fam-wrappers for `kvm_msr_list`, `kvm_msrs`, 109 | and `kvm_cpuid2`. 110 | 111 | ## [0.1.1] 112 | 113 | ### Changed 114 | 115 | - Do not enforce rust Edition 2018. 116 | 117 | ## [0.1.0] 118 | 119 | ### Added 120 | 121 | - KVM bindings for Linux kernel version 4.14 and 4.20 with 122 | support for arm, arm64, x86 and x86_64. 123 | -------------------------------------------------------------------------------- /src/serialize.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | //! Module containing serialization utilities 4 | 5 | /// Macro that generates serde::Serialize and serde::Deserialize implementations for the given types. 6 | /// This macro assumes that the types implement zerocopy::FromBytes and zerocopy::AsBytes, and uses 7 | /// these implementations to serialize as opaque byte arrays. During deserialization, it will 8 | /// try to deserialize as a `Vec`. If this deserialized `Vec` has a length that equals `size_of::`, 9 | /// it will transmute to `T` (using zerocopy), otherwise the `Vec` will either be zero-padded, or truncated. 10 | /// This will hopefully allow live update of bindings across kernel versions even if the kernel adds 11 | /// new fields to the end of some struct (we heavily rely on the kernel not making ABI breaking changes here). 12 | macro_rules! serde_impls { 13 | ($($typ: ty),*) => { 14 | $( 15 | impl Serialize for $typ { 16 | fn serialize(&self, serializer: S) -> Result 17 | where 18 | S: Serializer 19 | { 20 | let bytes = self.as_bytes(); 21 | serializer.serialize_bytes(bytes) 22 | } 23 | } 24 | 25 | impl<'de> Deserialize<'de> for $typ { 26 | fn deserialize(deserializer: D) -> Result 27 | where 28 | D: Deserializer<'de> 29 | { 30 | struct BytesVisitor; 31 | 32 | impl<'a> serde::de::Visitor<'a> for BytesVisitor { 33 | type Value = [u8; std::mem::size_of::<$typ>()]; 34 | 35 | fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { 36 | formatter.write_str("a byte array") 37 | } 38 | 39 | fn visit_bytes(self, bytes: &[u8]) -> Result { 40 | let mut backing = [0u8; std::mem::size_of::<$typ>()]; 41 | let limit = bytes.len().min(backing.len()); 42 | backing[..limit].copy_from_slice(&bytes[..limit]); 43 | Ok(backing) 44 | } 45 | 46 | fn visit_seq>(self, mut seq: A) -> Result { 47 | let mut backing = [0u8; std::mem::size_of::<$typ>()]; 48 | 49 | for backing_byte in &mut backing { 50 | let Some(byte) = seq.next_element()? else { break }; 51 | 52 | *backing_byte = byte; 53 | } 54 | 55 | Ok(backing) 56 | } 57 | } 58 | 59 | let backing = deserializer.deserialize_bytes(BytesVisitor)?; 60 | 61 | Ok(transmute!(backing)) 62 | } 63 | } 64 | )* 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/arm64/serialize.rs: -------------------------------------------------------------------------------- 1 | use bindings::{ 2 | kvm_mp_state, kvm_one_reg, kvm_regs, kvm_vcpu_init, user_fpsimd_state, user_pt_regs, 3 | }; 4 | use serde::{Deserialize, Deserializer, Serialize, Serializer}; 5 | use zerocopy::{transmute, AsBytes}; 6 | 7 | serde_impls! { 8 | user_pt_regs, 9 | user_fpsimd_state, 10 | kvm_regs, 11 | kvm_vcpu_init, 12 | kvm_mp_state, 13 | kvm_one_reg 14 | } 15 | 16 | #[cfg(test)] 17 | mod tests { 18 | use bindings::*; 19 | use serde::{Deserialize, Serialize}; 20 | 21 | fn is_serde Deserialize<'de> + Default>() { 22 | let serialized = bincode::serialize(&T::default()).unwrap(); 23 | let deserialized = bincode::deserialize::(serialized.as_ref()).unwrap(); 24 | let serialized_again = bincode::serialize(&deserialized).unwrap(); 25 | // Compare the serialized state after a roundtrip, to work around issues with 26 | // bindings not implementing `PartialEq`. 27 | assert_eq!(serialized, serialized_again); 28 | } 29 | 30 | #[test] 31 | fn static_assert_serde_implementations() { 32 | // This test statically (= at compile-time) asserts that various bindgen generated 33 | // structures implement serde's `Serialize` and `Deserialize` traits. 34 | // This is to make sure that we do not accidentally remove those implementations 35 | // when regenerating bindings. If this test fails to compile, please add 36 | // 37 | // #[cfg_attr( 38 | // feature = "serde", 39 | // derive(zerocopy::AsBytes, zerocopy::FromBytes, zerocopy::FromZeroes) 40 | // )] 41 | // 42 | // to all structures causing compilation errors (we need the zerocopy traits, as the 43 | // `Serialize` and `Deserialize` implementations are provided by the `serde_impls!` macro 44 | // above, which implements serialization based on zerocopy's `FromBytes` and `AsBytes` 45 | // traits that it expects to be derived). 46 | // 47 | // NOTE: This only include "top-level" items, and does not list out bindgen-anonymous types 48 | // (e.g. types like `kvm_vcpu_events__bindgen_ty_5`). These types can change name across 49 | // bindgen versions. If after re-adding the derives to all the below items you can compile 50 | // errors about anonymous types not implementing `Serialize`/`Deserialize`, please also add 51 | // the derives to all anonymous types references in the definitions of the below items. 52 | 53 | is_serde::(); 54 | is_serde::(); 55 | is_serde::(); 56 | is_serde::(); 57 | is_serde::(); 58 | is_serde::(); 59 | } 60 | 61 | fn is_serde_json Deserialize<'de> + Default>() { 62 | let serialized = serde_json::to_string(&T::default()).unwrap(); 63 | let deserialized = serde_json::from_str::(serialized.as_ref()).unwrap(); 64 | let serialized_again = serde_json::to_string(&deserialized).unwrap(); 65 | // Compare the serialized state after a roundtrip, to work around issues with 66 | // bindings not implementing `PartialEq`. 67 | assert_eq!(serialized, serialized_again); 68 | } 69 | 70 | #[test] 71 | fn test_json_serde() { 72 | is_serde_json::(); 73 | is_serde_json::(); 74 | is_serde_json::(); 75 | is_serde_json::(); 76 | is_serde_json::(); 77 | is_serde_json::(); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to kvm-bindings 2 | 3 | ## Dependencies 4 | 5 | ### Bindgen 6 | The bindings are currently generated using 7 | [bindgen](https://crates.io/crates/bindgen) version 0.70.1: 8 | ```bash 9 | cargo install bindgen-cli --vers 0.70.1 10 | ``` 11 | 12 | ### Linux Kernel 13 | Generating bindings depends on the Linux kernel, so you need to have the 14 | repository on your machine: 15 | 16 | ```bash 17 | git clone https://github.com/torvalds/linux.git 18 | ``` 19 | 20 | ## Updating bindings / adding a new architecture 21 | 22 | When adding a new architecture, the bindings must be generated for all existing 23 | versions for consistency reasons. 24 | 25 | ### Example for arm64 and kernel version 6.9 26 | 27 | For this example we assume that you have both linux and kvm-bindings 28 | repositories in your root. 29 | 30 | ```bash 31 | # Step 1 (if adding a new architecture): Create a new module using the name of the architecture in src/ 32 | pushd kvm-bindings 33 | mkdir src/arm64 34 | popd 35 | 36 | # linux is the repository that you cloned at the previous step. 37 | pushd linux 38 | # Step 2: Checkout the version you want to generate the bindings for. 39 | git checkout v6.9 40 | 41 | # Step 3: Generate the bindings. 42 | # This will generate the headers for the targeted architecture and place them 43 | # in the user specified directory 44 | 45 | export ARCH=arm64 46 | make headers_install ARCH=$ARCH INSTALL_HDR_PATH="$ARCH"_headers 47 | pushd "$ARCH"_headers 48 | bindgen include/linux/kvm.h -o bindings.rs \ 49 | --impl-debug --with-derive-default \ 50 | --with-derive-partialeq --impl-partialeq \ 51 | -- -Iinclude 52 | popd 53 | 54 | # Step 4: Copy the generated file to the arm64 module. 55 | popd 56 | cp linux/"$ARCH"_headers/bindings.rs kvm-bindings/src/arm64 57 | 58 | ``` 59 | 60 | Steps 2, 3 and 4 must be repeated for all existing architectures. 61 | 62 | Now that we have the bindings generated, for a new architecture we can copy the 63 | module file from one of the existing modules. 64 | 65 | ```bash 66 | cp arm/mod.rs arm64/ 67 | ``` 68 | 69 | Also, you will need to add the new architecture to `kvm-bindings/lib.rs`. 70 | 71 | When regenerating bindings, care must be taken to re-add various `zerocopy` 72 | derives under the `serde` feature. All items that require derives are 73 | listed in the `x86_64/serialize.rs` and `arm64/serialize.rs` inside the 74 | `serde_impls!` macro invocation, and missing derives will cause these 75 | modules to fail compilation. For all items listed here, the following 76 | derive should be present: 77 | 78 | ```rs 79 | #[cfg_attr( 80 | feature = "serde", 81 | derive(zerocopy::AsBytes, zerocopy::FromBytes, zerocopy::FromZeroes) 82 | )] 83 | ``` 84 | 85 | Any types whose name contains a suffix akin to `__bindgen_ty_` and 86 | which is contained in any struct listed in `serialize.rs` will also need 87 | to have this derive added (otherwise compilation will fail). Note that 88 | these types are not explicitly listed in `serialize.rs`, as their names 89 | can change across `bindgen.rs` versions. 90 | 91 | Lastly, in `x86_64/bindings.rs`, the derives also need to be added to 92 | `struct __BindgenBitfieldUnit` and `struct __IncompleteArrayField`. 93 | Additionally, these structs need to have their layout changed from `#[repr(C)]` 94 | to `#[repr(transparent)]`. This is needed because `zerocopy` traits can only be 95 | derived on generic structures that are `repr(transparent)` or `repr(packed)`. 96 | 97 | ### Future Improvements 98 | All the above steps are scriptable, so in the next iteration I will add a 99 | script to generate the bindings. 100 | 101 | # Testing 102 | 103 | This crate is tested using 104 | [rust-vmm-ci](https://github.com/rust-vmm/rust-vmm-ci) and 105 | [Buildkite](https://buildkite.com/) pipelines. Each new feature added to this crate must be 106 | accompanied by Buildkite steps for testing the following: 107 | - Release builds (using musl/gnu) with the new feature on arm and x86 108 | - Coverage test as specified in the 109 | [rust-vmm-ci readme](https://github.com/rust-vmm/rust-vmm-ci#getting-started-with-rust-vmm-ci). 110 | -------------------------------------------------------------------------------- /src/riscv64/serialize.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2024 © Institute of Software, CAS. All rights reserved. 2 | // Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | use bindings::{ 6 | kvm_mp_state, kvm_one_reg, kvm_riscv_aia_csr, kvm_riscv_config, kvm_riscv_core, kvm_riscv_csr, 7 | kvm_riscv_sbi_sta, kvm_riscv_smstateen_csr, kvm_riscv_timer, user_regs_struct, 8 | }; 9 | use serde::{Deserialize, Deserializer, Serialize, Serializer}; 10 | use zerocopy::{transmute, AsBytes}; 11 | 12 | serde_impls! { 13 | kvm_mp_state, 14 | kvm_one_reg, 15 | kvm_riscv_config, 16 | kvm_riscv_core, 17 | user_regs_struct, 18 | kvm_riscv_csr, 19 | kvm_riscv_aia_csr, 20 | kvm_riscv_smstateen_csr, 21 | kvm_riscv_timer, 22 | kvm_riscv_sbi_sta 23 | } 24 | 25 | #[cfg(test)] 26 | mod tests { 27 | use bindings::*; 28 | use serde::{Deserialize, Serialize}; 29 | 30 | fn is_serde Deserialize<'de> + Default>() { 31 | let serialized = bincode::serialize(&T::default()).unwrap(); 32 | let deserialized = bincode::deserialize::(serialized.as_ref()).unwrap(); 33 | let serialized_again = bincode::serialize(&deserialized).unwrap(); 34 | // Compare the serialized state after a roundtrip, to work around issues with 35 | // bindings not implementing `PartialEq`. 36 | assert_eq!(serialized, serialized_again); 37 | } 38 | 39 | #[test] 40 | fn static_assert_serde_implementations() { 41 | // This test statically (= at compile-time) asserts that various bindgen generated 42 | // structures implement serde's `Serialize` and `Deserialize` traits. 43 | // This is to make sure that we do not accidentally remove those implementations 44 | // when regenerating bindings. If this test fails to compile, please add 45 | // 46 | // #[cfg_attr( 47 | // feature = "serde", 48 | // derive(zerocopy::AsBytes, zerocopy::FromBytes, zerocopy::FromZeroes) 49 | // )] 50 | // 51 | // to all structures causing compilation errors (we need the zerocopy traits, as the 52 | // `Serialize` and `Deserialize` implementations are provided by the `serde_impls!` macro 53 | // above, which implements serialization based on zerocopy's `FromBytes` and `AsBytes` 54 | // traits that it expects to be derived). 55 | // 56 | // NOTE: This only include "top-level" items, and does not list out bindgen-anonymous types 57 | // (e.g. types like `kvm_vcpu_events__bindgen_ty_5`). These types can change name across 58 | // bindgen versions. If after re-adding the derives to all the below items you can compile 59 | // errors about anonymous types not implementing `Serialize`/`Deserialize`, please also add 60 | // the derives to all anonymous types references in the definitions of the below items. 61 | 62 | is_serde::(); 63 | is_serde::(); 64 | is_serde::(); 65 | is_serde::(); 66 | is_serde::(); 67 | is_serde::(); 68 | is_serde::(); 69 | is_serde::(); 70 | is_serde::(); 71 | is_serde::(); 72 | } 73 | 74 | fn is_serde_json Deserialize<'de> + Default>() { 75 | let serialized = serde_json::to_string(&T::default()).unwrap(); 76 | let deserialized = serde_json::from_str::(serialized.as_ref()).unwrap(); 77 | let serialized_again = serde_json::to_string(&deserialized).unwrap(); 78 | // Compare the serialized state after a roundtrip, to work around issues with 79 | // bindings not implementing `PartialEq`. 80 | assert_eq!(serialized, serialized_again); 81 | } 82 | 83 | #[test] 84 | fn test_json_serde() { 85 | is_serde_json::(); 86 | is_serde_json::(); 87 | is_serde_json::(); 88 | is_serde_json::(); 89 | is_serde_json::(); 90 | is_serde_json::(); 91 | is_serde_json::(); 92 | is_serde_json::(); 93 | is_serde_json::(); 94 | is_serde_json::(); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/x86_64/serialize.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use bindings::{ 5 | kvm_clock_data, kvm_cpuid2, kvm_cpuid_entry2, kvm_debugregs, kvm_dtable, kvm_irqchip, 6 | kvm_irqchip__bindgen_ty_1, kvm_lapic_state, kvm_mp_state, kvm_msr_entry, kvm_msrs, 7 | kvm_pit_channel_state, kvm_pit_state2, kvm_regs, kvm_segment, kvm_sregs, kvm_vcpu_events, 8 | kvm_xcr, kvm_xcrs, kvm_xsave, 9 | }; 10 | use serde::{Deserialize, Deserializer, Serialize, Serializer}; 11 | use zerocopy::{transmute, AsBytes, FromBytes, FromZeroes}; 12 | 13 | serde_impls!( 14 | kvm_regs, 15 | kvm_segment, 16 | kvm_dtable, 17 | kvm_sregs, 18 | kvm_msr_entry, 19 | kvm_cpuid_entry2, 20 | kvm_pit_channel_state, 21 | kvm_pit_state2, 22 | kvm_vcpu_events, 23 | kvm_debugregs, 24 | kvm_xcr, 25 | kvm_xcrs, 26 | kvm_mp_state, 27 | kvm_clock_data, 28 | kvm_lapic_state, 29 | kvm_msrs, 30 | kvm_cpuid2, 31 | kvm_xsave, 32 | kvm_irqchip 33 | ); 34 | 35 | // SAFETY: zerocopy's derives explicitly disallow deriving for unions where 36 | // the fields have different sizes, due to the smaller fields having padding. 37 | // Miri however does not complain about these implementations (e.g. about 38 | // reading the "padding" for one union field as valid data for a bigger one) 39 | unsafe impl FromZeroes for kvm_irqchip__bindgen_ty_1 { 40 | fn only_derive_is_allowed_to_implement_this_trait() 41 | where 42 | Self: Sized, 43 | { 44 | } 45 | } 46 | 47 | // SAFETY: zerocopy's derives explicitly disallow deriving for unions where 48 | // the fields have different sizes, due to the smaller fields having padding. 49 | // Miri however does not complain about these implementations (e.g. about 50 | // reading the "padding" for one union field as valid data for a bigger one) 51 | unsafe impl FromBytes for kvm_irqchip__bindgen_ty_1 { 52 | fn only_derive_is_allowed_to_implement_this_trait() 53 | where 54 | Self: Sized, 55 | { 56 | } 57 | } 58 | 59 | // SAFETY: zerocopy's derives explicitly disallow deriving for unions where 60 | // the fields have different sizes, due to the smaller fields having padding. 61 | // Miri however does not complain about these implementations (e.g. about 62 | // reading the "padding" for one union field as valid data for a bigger one) 63 | unsafe impl AsBytes for kvm_irqchip__bindgen_ty_1 { 64 | fn only_derive_is_allowed_to_implement_this_trait() 65 | where 66 | Self: Sized, 67 | { 68 | } 69 | } 70 | 71 | #[cfg(test)] 72 | mod tests { 73 | use super::*; 74 | use bindings::*; 75 | 76 | fn is_serde Deserialize<'de> + Default>() { 77 | let serialized = bincode::serialize(&T::default()).unwrap(); 78 | let deserialized = bincode::deserialize::(serialized.as_ref()).unwrap(); 79 | let serialized_again = bincode::serialize(&deserialized).unwrap(); 80 | // Compare the serialized state after a roundtrip, to work around issues with 81 | // bindings not implementing `PartialEq`. 82 | assert_eq!(serialized, serialized_again); 83 | } 84 | 85 | #[test] 86 | fn static_assert_serde_implementations() { 87 | // This test statically (= at compile-time) asserts that various bindgen generated 88 | // structures implement serde's `Serialize` and `Deserialize` traits. 89 | // This is to make sure that we do not accidentally remove those implementations 90 | // when regenerating bindings. If this test fails to compile, please add 91 | // 92 | // #[cfg_attr( 93 | // feature = "serde", 94 | // derive(zerocopy::AsBytes, zerocopy::FromBytes, zerocopy::FromZeroes) 95 | // )] 96 | // 97 | // to all structures causing compilation errors (we need the zerocopy traits, as the 98 | // `Serialize` and `Deserialize` implementations are provided by the `serde_impls!` macro 99 | // above, which implements serialization based on zerocopy's `FromBytes` and `AsBytes` 100 | // traits that it expects to be derived). 101 | // 102 | // NOTE: This only include "top-level" items, and does not list out bindgen-anonymous types 103 | // (e.g. types like `kvm_vcpu_events__bindgen_ty_5`). These types can change name across 104 | // bindgen versions. If after re-adding the derives to all the below items you can compile 105 | // errors about anonymous types not implementing `Serialize`/`Deserialize`, please also add 106 | // the derives to all anonymous types references in the definitions of the below items. 107 | 108 | is_serde::(); 109 | is_serde::(); 110 | is_serde::(); 111 | is_serde::(); 112 | is_serde::(); 113 | is_serde::(); 114 | is_serde::(); 115 | is_serde::(); 116 | is_serde::(); 117 | is_serde::(); 118 | is_serde::(); 119 | is_serde::(); 120 | is_serde::(); 121 | is_serde::(); 122 | is_serde::(); 123 | is_serde::(); 124 | is_serde::(); 125 | } 126 | 127 | fn is_serde_json Deserialize<'de> + Default>() { 128 | let serialized = serde_json::to_string(&T::default()).unwrap(); 129 | let deserialized = serde_json::from_str::(serialized.as_ref()).unwrap(); 130 | let serialized_again = serde_json::to_string(&deserialized).unwrap(); 131 | // Compare the serialized state after a roundtrip, to work around issues with 132 | // bindings not implementing `PartialEq`. 133 | assert_eq!(serialized, serialized_again); 134 | } 135 | 136 | #[test] 137 | fn test_json_serde() { 138 | is_serde_json::(); 139 | is_serde_json::(); 140 | is_serde_json::(); 141 | is_serde_json::(); 142 | is_serde_json::(); 143 | is_serde_json::(); 144 | is_serde_json::(); 145 | is_serde_json::(); 146 | is_serde_json::(); 147 | is_serde_json::(); 148 | is_serde_json::(); 149 | is_serde_json::(); 150 | is_serde_json::(); 151 | is_serde_json::(); 152 | is_serde_json::(); 153 | is_serde_json::(); 154 | is_serde_json::(); 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /src/x86_64/fam_wrappers.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use vmm_sys_util::fam::{FamStruct, FamStructWrapper}; 5 | 6 | use x86_64::bindings::*; 7 | 8 | /// Maximum number of CPUID entries that can be returned by a call to KVM ioctls. 9 | /// 10 | /// See arch/x86/include/asm/kvm_host.h 11 | pub const KVM_MAX_CPUID_ENTRIES: usize = 80; 12 | 13 | /// Maximum number of MSRs KVM supports (See arch/x86/kvm/x86.c). 14 | pub const KVM_MAX_MSR_ENTRIES: usize = 256; 15 | 16 | // Implement the FamStruct trait for kvm_cpuid2. 17 | generate_fam_struct_impl!( 18 | kvm_cpuid2, 19 | kvm_cpuid_entry2, 20 | entries, 21 | u32, 22 | nent, 23 | KVM_MAX_CPUID_ENTRIES 24 | ); 25 | 26 | // Implement the PartialEq trait for kvm_cpuid2. 27 | // 28 | // Note: 29 | // This PartialEq implementation should not be used directly, instead FamStructWrapper 30 | // should be used. FamStructWrapper provides us with an PartialEq implementation, 31 | // and it will determine the entire contents of the entries array. But requires 32 | // type T to implement `Default + FamStruct + PartialEq`, so we implement PartialEq here 33 | // and only need to determine the header field. 34 | impl PartialEq for kvm_cpuid2 { 35 | fn eq(&self, other: &kvm_cpuid2) -> bool { 36 | // No need to call entries's eq, FamStructWrapper's PartialEq will do it for you 37 | self.nent == other.nent && self.padding == other.padding 38 | } 39 | } 40 | 41 | /// Wrapper over the `kvm_cpuid2` structure. 42 | /// 43 | /// The `kvm_cpuid2` structure contains a flexible array member. For details check the 44 | /// [KVM API](https://www.kernel.org/doc/Documentation/virtual/kvm/api.txt) 45 | /// documentation on `kvm_cpuid2`. To provide safe access to 46 | /// the array elements, this type is implemented using 47 | /// [FamStructWrapper](../vmm_sys_util/fam/struct.FamStructWrapper.html). 48 | pub type CpuId = FamStructWrapper; 49 | 50 | // Implement the FamStruct trait for kvm_msrs. 51 | generate_fam_struct_impl!( 52 | kvm_msrs, 53 | kvm_msr_entry, 54 | entries, 55 | u32, 56 | nmsrs, 57 | KVM_MAX_MSR_ENTRIES 58 | ); 59 | 60 | // Implement the PartialEq trait for kvm_msrs. 61 | impl PartialEq for kvm_msrs { 62 | fn eq(&self, other: &kvm_msrs) -> bool { 63 | // No need to call entries's eq, FamStructWrapper's PartialEq will do it for you 64 | self.nmsrs == other.nmsrs && self.pad == other.pad 65 | } 66 | } 67 | 68 | /// Wrapper over the `kvm_msrs` structure. 69 | /// 70 | /// The `kvm_msrs` structure contains a flexible array member. For details check the 71 | /// [KVM API](https://www.kernel.org/doc/Documentation/virtual/kvm/api.txt) 72 | /// documentation on `kvm_msrs`. To provide safe access to 73 | /// the array elements, this type is implemented using 74 | /// [FamStructWrapper](../vmm_sys_util/fam/struct.FamStructWrapper.html). 75 | pub type Msrs = FamStructWrapper; 76 | 77 | // Implement the FamStruct trait for kvm_msr_list. 78 | generate_fam_struct_impl!(kvm_msr_list, u32, indices, u32, nmsrs, KVM_MAX_MSR_ENTRIES); 79 | 80 | // Implement the PartialEq trait for kvm_msr_list. 81 | impl PartialEq for kvm_msr_list { 82 | fn eq(&self, other: &kvm_msr_list) -> bool { 83 | // No need to call entries's eq, FamStructWrapper's PartialEq will do it for you 84 | self.nmsrs == other.nmsrs 85 | } 86 | } 87 | 88 | /// Wrapper over the `kvm_msr_list` structure. 89 | /// 90 | /// The `kvm_msr_list` structure contains a flexible array member. For details check the 91 | /// [KVM API](https://www.kernel.org/doc/Documentation/virtual/kvm/api.txt) 92 | /// documentation on `kvm_msr_list`. To provide safe access to 93 | /// the array elements, this type is implemented using 94 | /// [FamStructWrapper](../vmm_sys_util/fam/struct.FamStructWrapper.html). 95 | pub type MsrList = FamStructWrapper; 96 | 97 | /// Helper structure to treat post-5.17 [`kvm_xsave`] as a FamStruct. 98 | /// 99 | /// See also: [`Xsave`]. 100 | #[repr(C)] 101 | #[derive(Debug, Default)] 102 | pub struct kvm_xsave2 { 103 | /// The length, in bytes, of the FAM in [`kvm_xsave`]. 104 | /// 105 | /// Note that `KVM_CHECK_EXTENSION(KVM_CAP_XSAVE2)` returns the size of the entire 106 | /// `kvm_xsave` structure, e.g. the sum of header and FAM. Thus, this `len` field 107 | /// is equal to `KVM_CHECK_EXTENSION(KVM_CAP_XSAVE2) - 4096`. 108 | pub len: usize, 109 | pub xsave: kvm_xsave, 110 | } 111 | 112 | // SAFETY: 113 | // - `kvm_xsave2` is a POD 114 | // - `kvm_xsave2` contains a flexible array member as its final field, due to `kvm_xsave` containing 115 | // one, and being `repr(C)` 116 | // - `Entry` is a POD 117 | unsafe impl FamStruct for kvm_xsave2 { 118 | type Entry = __u32; 119 | 120 | fn len(&self) -> usize { 121 | self.len 122 | } 123 | 124 | unsafe fn set_len(&mut self, len: usize) { 125 | self.len = len; 126 | } 127 | 128 | fn max_len() -> usize { 129 | __u32::MAX as usize 130 | } 131 | 132 | fn as_slice(&self) -> &[::Entry] { 133 | let len = self.len(); 134 | // SAFETY: By the invariants that the caller of `set_len` has to uphold, `len` matches 135 | // the actual in-memory length of the FAM 136 | unsafe { self.xsave.extra.as_slice(len) } 137 | } 138 | 139 | fn as_mut_slice(&mut self) -> &mut [::Entry] { 140 | let len = self.len(); 141 | // SAFETY: By the invariants that the caller of `set_len` has to uphold, `len` matches 142 | // the actual in-memory length of the FAM 143 | unsafe { self.xsave.extra.as_mut_slice(len) } 144 | } 145 | } 146 | 147 | /// Wrapper over the post-5.17 [`kvm_xsave`] structure. 148 | /// 149 | /// In linux 5.17, kvm_xsave got turned into a FamStruct by adding the flexible "extra" member 150 | /// to its definition. However, unlike all other such structs, it does not contain a "length" 151 | /// field. Instead, the length of the flexible array member has to be determined by querying 152 | /// the [`KVM_CAP_XSAVE2`] capability. This requires access to a VM file descriptor, and thus 153 | /// cannot happen in the [`FamStruct::len`] trait method. To work around this, we define a wrapper 154 | /// struct that caches the length of a previous `KVM_CHECK_EXTENSION(KVM_CAP_XSAVE2)` call, 155 | /// and implement [`FamStruct`] for this wrapper. Then in kvm-ioctls, we can expose a function 156 | /// that first queries `KVM_CAP_XSAVE2`, then invokes [`KVM_GET_XSAVE2`] to retrives the `kvm_xsave` 157 | /// structure, and finally combine them into the [`kvm_xsave2`] helper structure to be managed as a 158 | /// `FamStruct`. 159 | pub type Xsave = FamStructWrapper; 160 | 161 | #[cfg(test)] 162 | mod tests { 163 | use super::{CpuId, MsrList, Msrs, Xsave}; 164 | use x86_64::bindings::kvm_cpuid_entry2; 165 | 166 | use vmm_sys_util::fam::FamStruct; 167 | 168 | #[test] 169 | fn test_cpuid_eq() { 170 | let entries = &[kvm_cpuid_entry2::default(); 2]; 171 | let mut wrapper = CpuId::from_entries(entries).unwrap(); 172 | assert_eq!(wrapper.as_slice().len(), 2); 173 | 174 | let mut wrapper2 = wrapper.clone(); 175 | assert!(wrapper == wrapper2); 176 | 177 | wrapper.as_mut_slice()[1].index = 1; 178 | assert!(wrapper != wrapper2); 179 | wrapper2.as_mut_slice()[1].index = 1; 180 | assert!(wrapper == wrapper2); 181 | } 182 | #[test] 183 | fn test_msrs_eq() { 184 | let mut wrapper = Msrs::new(2).unwrap(); 185 | assert_eq!(wrapper.as_slice().len(), 2); 186 | 187 | let mut wrapper2 = wrapper.clone(); 188 | assert!(wrapper == wrapper2); 189 | // SAFETY: We are not modifying the `nmsrs` field 190 | unsafe { 191 | wrapper.as_mut_fam_struct().pad = 1; 192 | } 193 | assert!(wrapper != wrapper2); 194 | // SAFETY: We are not modifying the `nmsrs` field 195 | unsafe { 196 | wrapper2.as_mut_fam_struct().pad = 1; 197 | } 198 | assert!(wrapper == wrapper2); 199 | 200 | wrapper.as_mut_slice()[1].data = 1; 201 | assert!(wrapper != wrapper2); 202 | assert!(wrapper.as_slice() != wrapper2.as_slice()); 203 | wrapper2.as_mut_slice()[1].data = 1; 204 | assert!(wrapper == wrapper2); 205 | assert!(wrapper.as_slice() == wrapper2.as_slice()); 206 | } 207 | #[test] 208 | fn test_msrs_list_eq() { 209 | let mut wrapper = MsrList::new(1).unwrap(); 210 | assert_eq!(wrapper.as_slice().len(), 1); 211 | 212 | let mut wrapper2 = wrapper.clone(); 213 | assert!(wrapper == wrapper2); 214 | 215 | wrapper.as_mut_slice()[0] = 1; 216 | assert!(wrapper != wrapper2); 217 | wrapper2.as_mut_slice()[0] = 1; 218 | assert!(wrapper == wrapper2); 219 | } 220 | #[test] 221 | fn test_xsave() { 222 | let wrapper = Xsave::new(1).unwrap(); 223 | assert_eq!(wrapper.as_slice().len(), 1); 224 | assert_eq!(wrapper.as_fam_struct_ref().len(), 1); 225 | assert_eq!(wrapper.as_fam_struct_ref().len, 1); 226 | } 227 | } 228 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | --------------------------------------------------------------------------------