├── .gitignore ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── Makefile ├── README.md ├── applevisor-sys ├── .gitignore ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── Makefile ├── README.md ├── entitlements.xml └── src │ └── lib.rs ├── entitlements.xml └── src └── lib.rs /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | debug/ 4 | target/ 5 | 6 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 7 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 8 | Cargo.lock 9 | 10 | # These are backup files generated by rustfmt 11 | **/*.rs.bk 12 | 13 | # MSVC Windows builds of rustc generate these, which store debugging information 14 | *.pdb 15 | 16 | **/.DS_Store 17 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "applevisor" 3 | version = "0.1.3" 4 | authors = ["lyte "] 5 | edition = "2021" 6 | description = "Rust bindings for the Apple Silicon Hypervisor Framework" 7 | documentation = "https://docs.rs/applevisor" 8 | readme = "README.md" 9 | repository = "https://github.com/impalabs/applevisor" 10 | license = "MIT OR Apache-2.0" 11 | keywords = ["apple", "hypervisor", "macos", "virtualization", "aarch64"] 12 | categories = ["os::macos-apis", "hardware-support", "api-bindings", "virtualization"] 13 | 14 | [dependencies] 15 | applevisor-sys = { version = "0.1.3", default-features = false } 16 | concat-idents = { version = "1.1.5", optional = true } 17 | 18 | [features] 19 | default = [ "dep:concat-idents" ] 20 | simd_nightly = [ "applevisor-sys/simd_nightly" ] 21 | 22 | [package.metadata.docs.rs] 23 | targets = ["x86_64-apple-darwin", "aarch64-apple-darwin"] 24 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014-2020 The Rust Project Developers 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CODESIGN=codesign 2 | CARGO=cargo 3 | CARGO_NIGHTLY=$(CARGO) +nightly 4 | 5 | ENTITLEMENTS=entitlements.xml 6 | TARGET=applevisor 7 | TARGET_DEBUG=target/debug/$(TARGET) 8 | TARGET_RELEASE=target/release/$(TARGET) 9 | 10 | .PHONY: build-tests tests build-tests-nightly tests-nightly 11 | 12 | build-tests: 13 | $(CARGO) test --no-run 14 | $(CODESIGN) --sign - --entitlements "$(ENTITLEMENTS)" --deep --force \ 15 | $(shell $(CARGO) test --no-run --message-format=json | \ 16 | jq -r "select(.profile.test == true) | .filenames[]") 17 | 18 | tests: build-tests 19 | $(CARGO) test --tests -- --nocapture --test-threads=1 20 | 21 | build-tests-nightly: 22 | $(CARGO_NIGHTLY) test --features=simd_nightly --no-run 23 | $(CODESIGN) --sign - --entitlements "$(ENTITLEMENTS)" --deep --force \ 24 | $(shell $(CARGO_NIGHTLY) test --features=simd_nightly --no-run --message-format=json | \ 25 | jq -r "select(.profile.test == true) | .filenames[]") 26 | 27 | tests-nightly: build-tests-nightly 28 | $(CARGO_NIGHTLY) test --tests --features=simd_nightly -- --nocapture --test-threads=1 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | APPLEVISOR 3 |
4 | Rust bindings for the Apple Silicon Hypervisor Framework 5 |

6 | 7 |
8 | 9 |

10 | shields.io license 11 | shields.io version 12 | shields.io platform 13 |
14 | shields.io crates.io 15 | shields.io crates.io 16 |

17 | 18 |
19 | 20 | ## Table of contents 21 | 22 | * [Getting Started](#getting-started) 23 | * [Self-Signed Binaries and Hypervisor Entitlement](#self-signed-binaries-and-hypervisor-entitlement) 24 | * [Compilation Workflow](#compilation-workflow) 25 | * [Documentation](#documentation) 26 | * [Example](#example) 27 | * [Running the Tests](#running-the-tests) 28 | * [Author](#author) 29 | 30 | 31 | This library can be used to build Rust applications leveraging the [`Hypervisor`](https://developer.apple.com/documentation/hypervisor) framework on Apple Silicon. 32 | 33 | ## Getting Started 34 | 35 | ### Self-Signed Binaries and Hypervisor Entitlement 36 | 37 | To be able to reach the Hypervisor Framework, a binary executable has to have been granted the [hypervisor entitlement](https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_security_hypervisor). 38 | 39 | You can add this entitlement to a binary located at `/path/to/binary` by using the `entitlements.xml` file found at the root of the repository and the following command: 40 | 41 | ``` 42 | codesign --sign - --entitlements entitlements.xml --deep --force /path/to/binary 43 | ``` 44 | 45 | ### Compilation Workflow 46 | 47 | Create a Rust project and add Applevisor as a dependency in `Cargo.toml`. You can either pull it from [crates.io](https://crates.io/crates/applevisor) ... 48 | 49 | ```toml 50 | # Check which version is the latest, this part of the README might not be updated 51 | # in future releases. 52 | applevisor = "0.1.3" 53 | ``` 54 | 55 | ... or directly from the [GitHub repository](https://github.com/impalabs/applevisor). 56 | 57 | ```toml 58 | applevisor = { git="https://github.com/impalabs/applevisor", branch="master" } 59 | ``` 60 | 61 | Create a file called `entitlements.txt` in the project's root directory and add the following: 62 | 63 | ```xml 64 | 65 | 66 | 67 | 68 | com.apple.security.hypervisor 69 | 70 | 71 | 72 | ``` 73 | 74 | Write code and then build the project. 75 | 76 | ``` 77 | cargo build --release 78 | ``` 79 | 80 | Sign the binary and grant the hypervisor entitlement. 81 | 82 | ``` 83 | codesign --sign - --entitlements entitlements.xml --deep --force target/release/${PROJECT_NAME} 84 | ``` 85 | 86 | Run the binary. 87 | 88 | ``` 89 | target/release/${PROJECT_NAME} 90 | ``` 91 | 92 | ## Documentation 93 | 94 | The documentation is available online at the following address: [https://docs.rs/applevisor](https://docs.rs/applevisor) 95 | 96 | Alternatively, you can generate the documentation using `cargo`: 97 | 98 | ``` 99 | cargo doc --open 100 | ``` 101 | 102 | ## Example 103 | 104 | The following example: 105 | 106 | * creates a virtual machine for the current process; 107 | * creates a virtual CPU; 108 | * enables the hypervisor's debug features to be able to use breakpoints later on; 109 | * creates a physical memory mapping of 0x1000 bytes and maps it at address 0x4000 with RWX 110 | permissions; 111 | * writes the instructions `mov x0, #0x42; brk #0;` at address 0x4000; 112 | * sets PC to 0x4000; 113 | * starts the vCPU and runs our program; 114 | * returns when it encounters the breakpoint. 115 | 116 | ```rust 117 | use applevisor::*; 118 | 119 | fn main() { 120 | // Creates a new virtual machine. There can be one, and only one, per process. Operations 121 | // on the virtual machine remains possible as long as this object is valid. 122 | let _vm = VirtualMachine::new().unwrap(); 123 | 124 | // Creates a new virtual CPU. This object abstracts operations that can be performed on 125 | // CPUs, such as starting and stopping them, changing their registers, etc. 126 | let vcpu = Vcpu::new().unwrap(); 127 | 128 | // Enables debug features for the hypervisor. This is optional, but it might be required 129 | // for certain features to work, such as breakpoints. 130 | assert!(vcpu.set_trap_debug_exceptions(true).is_ok()); 131 | assert!(vcpu.set_trap_debug_reg_accesses(true).is_ok()); 132 | 133 | // Creates a mapping object that represents a 0x1000-byte physical memory range. 134 | let mut mem = Mapping::new(0x1000).unwrap(); 135 | 136 | // This mapping needs to be mapped to effectively allocate physical memory for the guest. 137 | // Here we map the region at address 0x4000 and set the permissions to Read-Write-Execute. 138 | assert_eq!(mem.map(0x4000, MemPerms::RWX), Ok(())); 139 | 140 | // Writes a `mov x0, #0x42` instruction at address 0x4000. 141 | assert_eq!(mem.write_dword(0x4000, 0xd2800840), Ok(4)); 142 | // Writes a `brk #0` instruction at address 0x4004. 143 | assert_eq!(mem.write_dword(0x4004, 0xd4200000), Ok(4)); 144 | 145 | // Sets PC to 0x4000. 146 | assert!(vcpu.set_reg(Reg::PC, 0x4000).is_ok()); 147 | 148 | // Starts the Vcpu. It will execute our mov and breakpoint instructions before stopping. 149 | assert!(vcpu.run().is_ok()); 150 | 151 | // The *exit information* can be used to used to retrieve different pieces of 152 | // information about the CPU exit status (e.g. exception type, fault address, etc.). 153 | let _exit_info = vcpu.get_exit_info(); 154 | 155 | // If everything went as expected, the value in X0 is 0x42. 156 | assert_eq!(vcpu.get_reg(Reg::X0), Ok(0x42)); 157 | } 158 | ``` 159 | 160 | Feel free to also have a look at the [Hyperpom](https://github.com/impalabs/hyperpom) project's source code for a real-life example of how these bindings are used. 161 | 162 | ## Running the Tests 163 | 164 | To run tests using the `Makefile` provided with the project, you'll first need to install [`jq`](https://stedolan.github.io/jq/download/). You can do so using `brew`: 165 | 166 | ``` 167 | brew install jq 168 | ``` 169 | 170 | You can then run the tests with the provided `Makefile` using the following command: 171 | 172 | ``` 173 | make tests 174 | ``` 175 | 176 | ## Author 177 | 178 | * [**Maxime Peterlin**](https://twitter.com/lyte__) - contact@impalabs.com 179 | -------------------------------------------------------------------------------- /applevisor-sys/.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | debug/ 4 | target/ 5 | 6 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 7 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 8 | Cargo.lock 9 | 10 | # These are backup files generated by rustfmt 11 | **/*.rs.bk 12 | 13 | # MSVC Windows builds of rustc generate these, which store debugging information 14 | *.pdb 15 | -------------------------------------------------------------------------------- /applevisor-sys/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "applevisor-sys" 3 | version = "0.1.3" 4 | authors = ["lyte "] 5 | edition = "2021" 6 | description = "Unsafe rust bindings for the Apple Silicon Hypervisor Framework" 7 | documentation = "https://docs.rs/applevisor-sys" 8 | readme = "README.md" 9 | repository = "https://github.com/impalabs/applevisor" 10 | license = "MIT OR Apache-2.0" 11 | keywords = ["apple", "hypervisor", "macos", "virtualization", "aarch64"] 12 | categories = ["os::macos-apis", "hardware-support", "api-bindings", "virtualization"] 13 | 14 | [dependencies] 15 | libc = "0.2" 16 | 17 | [features] 18 | default = [] 19 | simd_nightly = [] 20 | 21 | [package.metadata.docs.rs] 22 | targets = ["x86_64-apple-darwin", "aarch64-apple-darwin"] 23 | -------------------------------------------------------------------------------- /applevisor-sys/LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | -------------------------------------------------------------------------------- /applevisor-sys/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014-2020 The Rust Project Developers 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /applevisor-sys/Makefile: -------------------------------------------------------------------------------- 1 | CODESIGN=codesign 2 | CARGO=cargo 3 | CARGO_NIGHTLY=$(CARGO) +nightly 4 | 5 | ENTITLEMENTS=entitlements.xml 6 | TARGET=applevisor-sys 7 | TARGET_DEBUG=target/debug/$(TARGET) 8 | TARGET_RELEASE=target/release/$(TARGET) 9 | 10 | .PHONY: build-test tests build-test-nightly tests-nightly 11 | 12 | build-tests: 13 | $(CARGO) test --no-run 14 | $(CODESIGN) --sign - --entitlements "$(ENTITLEMENTS)" --deep --force \ 15 | $(shell $(CARGO) test --no-run --message-format=json | \ 16 | jq -r "select(.profile.test == true) | .filenames[]") 17 | 18 | tests: build-tests 19 | $(CARGO) test --tests -- --nocapture --test-threads=1 20 | 21 | build-tests-nightly: 22 | $(CARGO_NIGHTLY) test --features=simd_nightly --no-run 23 | $(CODESIGN) --sign - --entitlements "$(ENTITLEMENTS)" --deep --force \ 24 | $(shell $(CARGO_NIGHTLY) test --features=simd_nightly --no-run --message-format=json | \ 25 | jq -r "select(.profile.test == true) | .filenames[]") 26 | 27 | tests-nightly: build-tests-nightly 28 | $(CARGO_NIGHTLY) test --tests --features=simd_nightly -- --nocapture --test-threads=1 29 | -------------------------------------------------------------------------------- /applevisor-sys/README.md: -------------------------------------------------------------------------------- 1 |

2 | APPLEVISOR-SYS 3 |
4 | Unsafe Rust bindings for the Apple Silicon Hypervisor Framework 5 |

6 | 7 |
8 | 9 |

10 | shields.io license 11 | shields.io version 12 | shields.io platform 13 |
14 | shields.io crates.io 15 | shields.io crates.io 16 |

17 | 18 |
19 | 20 | These unsafe bindings provide access to the Apple Silicon `Hypervisor.framework` from Rust programs. It is recommended to use the safe version of this library available at the following locations: 21 | 22 | * [Applevisor GitHub repository](https://github.com/impalabs/applevisor) 23 | * [Applevisor crates.io page](https://crates.io/crates/applevisor) 24 | * [Applevisor docs.rs page](https://docs.rs/applevisor) 25 | -------------------------------------------------------------------------------- /applevisor-sys/entitlements.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.hypervisor 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /applevisor-sys/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Unsafe Rust bindings for the Apple Silicon Hypervisor.framework 2 | //! 3 | //! These unsafe bindings provide access to the Apple Silicon `Hypervisor.framework` from Rust 4 | //! programs. It is recommended to use the safe version of this library available at the following 5 | //! locations: 6 | //! 7 | //! * [Applevisor GitHub repository](https://github.com/impalabs/applevisor) 8 | //! * [Applevisor crates.io page](https://crates.io/crates/applevisor) 9 | //! * [Applevisor docs.rs page](https://docs.rs/applevisor) 10 | 11 | #![cfg_attr(feature = "simd_nightly", feature(portable_simd), feature(simd_ffi))] 12 | #![allow(non_camel_case_types)] 13 | #![allow(improper_ctypes)] 14 | 15 | use core::ffi::c_void; 16 | 17 | #[cfg_attr(target_os = "macos", link(name = "Hypervisor", kind = "framework"))] 18 | extern "C" {} 19 | 20 | /// The return type of framework functions. 21 | pub type hv_return_t = i32; 22 | 23 | /// Errors returned by Hypervisor functions. 24 | #[repr(C)] 25 | #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] 26 | pub enum hv_error_t { 27 | /// The operation completed successfully. 28 | HV_SUCCESS = 0, 29 | /// The operation was unsuccessful. 30 | HV_ERROR = 0xfae94001, 31 | /// The operation was unsuccessful because the owning resource was busy. 32 | HV_BUSY = 0xfae94002, 33 | /// The operation was unsuccessful because the function call had an invalid argument. 34 | HV_BAD_ARGUMENT = 0xfae94003, 35 | /// The operation was unsuccessful because the guest is in an illegal state. 36 | HV_ILLEGAL_GUEST_STATE = 0xfae94004, 37 | /// The operation was unsuccessful because the host had no resources available to complete the 38 | /// request. 39 | HV_NO_RESOURCES = 0xfae94005, 40 | /// The operation was unsuccessful because no VM or vCPU was available. 41 | HV_NO_DEVICE = 0xfae94006, 42 | /// The system didn’t allow the requested operation. 43 | HV_DENIED = 0xfae94007, 44 | /// HV_FAULT 45 | HV_FAULT = 0xfae94008, 46 | /// The operation requested isn’t supported by the hypervisor. 47 | HV_UNSUPPORTED = 0xfae9400f, 48 | } 49 | 50 | // ----------------------------------------------------------------------------------------------- 51 | // Virtual Machine Management 52 | // ----------------------------------------------------------------------------------------------- 53 | 54 | /// The type that defines a virtual-machine configuration. 55 | pub type hv_vm_config_t = *mut c_void; 56 | 57 | extern "C" { 58 | /// Creates a VM instance for the current process. 59 | /// 60 | /// # Parameters 61 | /// 62 | /// * `config`: The configuration of the vCPU, which must be nil. 63 | /// 64 | /// # Return Value 65 | /// 66 | /// `HV_SUCCESS` if the operation was successful, otherwise an error code specified in 67 | /// [`hv_return_t`]. 68 | pub fn hv_vm_create(config: hv_vm_config_t) -> hv_return_t; 69 | 70 | /// Destroys the VM instance associated with the current process. 71 | /// 72 | /// # Return value 73 | /// 74 | /// `HV_SUCCESS` if the operation was successful, otherwise an error code specified in 75 | /// [`hv_return_t`]. 76 | pub fn hv_vm_destroy() -> hv_return_t; 77 | } 78 | 79 | // ----------------------------------------------------------------------------------------------- 80 | // vCPU Management - Configuration 81 | // ----------------------------------------------------------------------------------------------- 82 | 83 | /// The type that defines a vCPU configuration. 84 | pub type hv_vcpu_config_t = *mut c_void; 85 | 86 | /// The type that defines feature registers. 87 | #[repr(C)] 88 | #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] 89 | pub enum hv_feature_reg_t { 90 | /// The value that identifies debug feature register 0, EL1 (DFR0_EL1). 91 | HV_FEATURE_REG_ID_AA64DFR0_EL1, 92 | /// The value that identifies debug feature register 1, EL1 (DFR1_EL1). 93 | HV_FEATURE_REG_ID_AA64DFR1_EL1, 94 | /// The value that identifies instruction set attribute register 0, EL1 (ISAR0_EL1). 95 | HV_FEATURE_REG_ID_AA64ISAR0_EL1, 96 | /// The value that identifies instruction set attribute register 1, EL1 (ISAR_EL1). 97 | HV_FEATURE_REG_ID_AA64ISAR1_EL1, 98 | /// The value that identifies memory model feature register 0, EL1(MMFR0_EL1). 99 | HV_FEATURE_REG_ID_AA64MMFR0_EL1, 100 | /// The value that identifies memory model feature register 1, EL1 (MMFR1_EL1). 101 | HV_FEATURE_REG_ID_AA64MMFR1_EL1, 102 | /// The value that identifies memory model feature register 2, EL1 (MMFR2_EL1). 103 | HV_FEATURE_REG_ID_AA64MMFR2_EL1, 104 | /// The value that identifies processor feature register 0, EL1 (PFR0_EL1). 105 | HV_FEATURE_REG_ID_AA64PFR0_EL1, 106 | /// The value that identifies processor feature register 1, EL1 (PFR1_EL1). 107 | HV_FEATURE_REG_ID_AA64PFR1_EL1, 108 | /// The value that describes Cache Type Register, EL0. 109 | HV_FEATURE_REG_CTR_EL0, 110 | /// The value that describes Cache Level ID Register, EL1. 111 | HV_FEATURE_REG_CLIDR_EL1, 112 | /// The values that describes Data Cache Zero ID Register, EL0. 113 | HV_FEATURE_REG_DCZID_EL0, 114 | } 115 | 116 | /// The structure that describes an instruction or data cache element. 117 | #[repr(C)] 118 | #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] 119 | pub enum hv_cache_type_t { 120 | /// The value that describes a cached data value. 121 | HV_CACHE_TYPE_DATA, 122 | /// The value that describes a cached instuction value. 123 | HV_CACHE_TYPE_INSTRUCTION, 124 | } 125 | 126 | extern "C" { 127 | /// Creates a vCPU configuration object. 128 | /// 129 | /// # Return 130 | /// 131 | /// A new vCPU configuration object. 132 | pub fn hv_vcpu_config_create() -> hv_vcpu_config_t; 133 | 134 | /// Gets the value of a feature register. 135 | /// 136 | /// # Parameters 137 | /// 138 | /// * `config`: The vCPU configuration. 139 | /// * `feature_reg`: The ID of the feature register. 140 | /// * `value`: The value of `feature_reg` on output. Undefined if the call doesn’t succeed. 141 | /// 142 | /// # Return Value 143 | /// 144 | /// `HV_SUCCESS` if the operation was successful, otherwise an error code specified in 145 | /// [`hv_return_t`]. 146 | pub fn hv_vcpu_config_get_feature_reg( 147 | config: hv_vcpu_config_t, 148 | feature_reg: hv_feature_reg_t, 149 | value: *mut u64, 150 | ) -> hv_return_t; 151 | 152 | /// Returns the Cache Size ID Register (CCSIDR_EL1) values for the vCPU configuration and 153 | /// cache type you specify. 154 | /// 155 | /// # Parameters 156 | /// 157 | /// * `config`: The vCPU configuration. 158 | /// * `cache_type`: The cache type from the available [`hv_cache_type_t`] types. 159 | /// * `values`: A pointer to the location for the return values. 160 | /// 161 | /// # Return Value 162 | /// 163 | /// A [`hv_return_t`] value that indicates that result of the function. 164 | pub fn hv_vcpu_config_get_ccsidr_el1_sys_reg_values( 165 | config: hv_vcpu_config_t, 166 | cache_type: hv_cache_type_t, 167 | values: *mut u64, 168 | ) -> hv_return_t; 169 | } 170 | 171 | // ----------------------------------------------------------------------------------------------- 172 | // vCPU Management - Creation and Destruction 173 | // ----------------------------------------------------------------------------------------------- 174 | 175 | /// An opaque value that represents a vCPU instance. 176 | pub type hv_vcpu_t = u64; 177 | 178 | /// The structure that describes information about an exit from the virtual CPU (vCPU) to the host. 179 | #[repr(C)] 180 | #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] 181 | pub struct hv_vcpu_exit_exception_t { 182 | /// The vCPU exception syndrome causing the exception. 183 | pub syndrome: u64, 184 | /// The vCPU virtual address of the exception. 185 | pub virtual_address: u64, 186 | /// The intermediate physical address of the exception in the client. 187 | pub physical_address: u64, 188 | } 189 | 190 | /// The type that describes the event that triggered a guest exit to the host. 191 | #[repr(C)] 192 | #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] 193 | pub enum hv_exit_reason_t { 194 | /// The value that identifies exits requested by exit handler on the host. 195 | HV_EXIT_REASON_CANCELED, 196 | /// The value that identifies traps caused by the guest operations. 197 | HV_EXIT_REASON_EXCEPTION, 198 | /// The value that identifies when the virtual timer enters the pending state. 199 | HV_EXIT_REASON_VTIMER_ACTIVATED, 200 | /// The value that identifies unexpected exits. 201 | HV_EXIT_REASON_UNKNOWN, 202 | } 203 | 204 | /// Information about an exit from the vCPU to the host. 205 | #[repr(C)] 206 | #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] 207 | pub struct hv_vcpu_exit_t { 208 | /// Information about an exit from the vcpu to the host. 209 | pub reason: hv_exit_reason_t, 210 | /// Information about an exit exception from the vcpu to the host. 211 | pub exception: hv_vcpu_exit_exception_t, 212 | } 213 | 214 | extern "C" { 215 | /// Returns the maximum number of vCPUs that the hypervisor supports. 216 | /// 217 | /// # Parameters 218 | /// 219 | /// * `max_vcpu_count`: The maximum number of vCPUs on output. Undefined if the call doesn’t 220 | /// succeed. 221 | /// 222 | /// # Return Value 223 | /// 224 | /// `HV_SUCCESS` if the operation was successful, otherwise an error code specified in 225 | /// [`hv_return_t`]. 226 | pub fn hv_vm_get_max_vcpu_count(max_vcpu_count: *mut u32) -> hv_return_t; 227 | 228 | /// Creates a vCPU instance for the current thread. 229 | /// 230 | /// # Parameters 231 | /// 232 | /// * `vcpu`: An argument that the hypervisor populates with the instance of a vCPU on a 233 | /// successful return. 234 | /// * `exit`: The pointer to the vCPU exit information. The function hv_vcpu_run updates this 235 | /// structure on return. 236 | /// * `config`: The configuration of the vCPU or nil for a default configuration. 237 | /// 238 | /// # Return Value 239 | /// 240 | /// `HV_SUCCESS` if the operation was successful, otherwise an error code specified in 241 | /// [`hv_return_t`]. 242 | pub fn hv_vcpu_create( 243 | vcpu: *mut hv_vcpu_t, 244 | exit: *mut *const hv_vcpu_exit_t, 245 | config: hv_vcpu_config_t, 246 | ) -> hv_return_t; 247 | 248 | /// Destroys the vCPU instance associated with the current thread. 249 | /// 250 | /// # Parameters 251 | /// 252 | /// * `vcpu`: The instance of the vCPU. 253 | /// 254 | /// # Return Value 255 | /// 256 | /// `HV_SUCCESS` if the operation was successful, otherwise an error code specified in 257 | /// [`hv_return_t`]. 258 | pub fn hv_vcpu_destroy(vcpu: hv_vcpu_t) -> hv_return_t; 259 | } 260 | 261 | // ----------------------------------------------------------------------------------------------- 262 | // vCPU Management - Runtime 263 | // ----------------------------------------------------------------------------------------------- 264 | 265 | /// The type that defines the vCPU’s interrupts. 266 | #[repr(C)] 267 | #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] 268 | pub enum hv_interrupt_type_t { 269 | /// ARM Fast Interrupt Request. 270 | HV_INTERRUPT_TYPE_FIQ, 271 | /// ARM Interrupt Request. 272 | HV_INTERRUPT_TYPE_IRQ, 273 | } 274 | 275 | extern "C" { 276 | /// Starts the execution of a vCPU. 277 | /// 278 | /// # Parameters 279 | /// 280 | /// * `vcpu`: The instance of the vCPU. 281 | /// 282 | /// # Return Value 283 | /// 284 | /// `HV_SUCCESS` if the operation was successful, otherwise an error code specified in 285 | /// [`hv_return_t`]. 286 | pub fn hv_vcpu_run(vcpu: hv_vcpu_t) -> hv_return_t; 287 | 288 | /// Forces an immediate exit of a set of vCPUs of the VM. 289 | /// 290 | /// # Parameters 291 | /// 292 | /// * `vcpus`: An array of vCPU instances. 293 | /// * `vcpu_count`: The number of vCPUs in the array. 294 | /// 295 | /// # Return Value 296 | /// 297 | /// `HV_SUCCESS` if the operation was successful, otherwise an error code specified in 298 | /// [`hv_return_t`]. 299 | pub fn hv_vcpus_exit(vcpus: *const hv_vcpu_t, vcpu_count: u32) -> hv_return_t; 300 | 301 | /// Gets pending interrupts for a vCPU. 302 | /// 303 | /// # Parameters 304 | /// 305 | /// * `vcpu`: The instance of the vCPU. 306 | /// * `type`: The interrupt from Interrupt Constants. 307 | /// * `pending`: A variable that indicates whether, on output, the interrupt of type is 308 | /// pending or not. 309 | /// 310 | /// # Return Value 311 | /// 312 | /// `HV_SUCCESS` if the operation was successful, otherwise an error code specified in 313 | /// [`hv_return_t`]. 314 | pub fn hv_vcpu_get_pending_interrupt( 315 | vcpu: hv_vcpu_t, 316 | _type: hv_interrupt_type_t, 317 | pending: *mut bool, 318 | ) -> hv_return_t; 319 | 320 | /// Sets pending interrupts for a vCPU. 321 | /// 322 | /// # Parameters 323 | /// 324 | /// * `vcpu`: The instance of the vCPU. 325 | /// * `type`: The interrupt from Interrupt Constants. 326 | /// * `pending`: A Boolean that indicates whether the interrupt is pending. 327 | /// 328 | /// # Return Value 329 | /// 330 | /// `HV_SUCCESS` if the operation was successful, otherwise an error code specified in 331 | /// [`hv_return_t`]. 332 | pub fn hv_vcpu_set_pending_interrupt( 333 | vcpu: hv_vcpu_t, 334 | _type: hv_interrupt_type_t, 335 | pending: bool, 336 | ) -> hv_return_t; 337 | 338 | /// Returns, by reference, the cumulative execution time of a vCPU, in nanoseconds. 339 | /// 340 | /// # Parameters 341 | /// 342 | /// * `vcpu`: The instance of the vCPU. 343 | /// * `time`: The execution time on output, in nanoseconds. 344 | /// 345 | /// # Return Value 346 | /// 347 | /// `HV_SUCCESS` if the operation was successful, otherwise an error code specified in 348 | /// [`hv_return_t`]. 349 | pub fn hv_vcpu_get_exec_time(vcpu: hv_vcpu_t, time: *mut u64) -> hv_return_t; 350 | } 351 | 352 | // ----------------------------------------------------------------------------------------------- 353 | // vCPU Management - General Registers 354 | // ----------------------------------------------------------------------------------------------- 355 | 356 | /// The type that defines general registers. 357 | #[repr(C)] 358 | #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] 359 | pub enum hv_reg_t { 360 | /// The value that identifies register X0. 361 | HV_REG_X0, 362 | /// The value that identifies register X1. 363 | HV_REG_X1, 364 | /// The value that identifies register X2. 365 | HV_REG_X2, 366 | /// The value that identifies register X3. 367 | HV_REG_X3, 368 | /// The value that identifies register X4. 369 | HV_REG_X4, 370 | /// The value that identifies register X5. 371 | HV_REG_X5, 372 | /// The value that identifies register X6. 373 | HV_REG_X6, 374 | /// The value that identifies register X7. 375 | HV_REG_X7, 376 | /// The value that identifies register X8. 377 | HV_REG_X8, 378 | /// The value that identifies register X9. 379 | HV_REG_X9, 380 | /// The value that identifies register X10. 381 | HV_REG_X10, 382 | /// The value that identifies register X11. 383 | HV_REG_X11, 384 | /// The value that identifies register X12. 385 | HV_REG_X12, 386 | /// The value that identifies register X13. 387 | HV_REG_X13, 388 | /// The value that identifies register X14. 389 | HV_REG_X14, 390 | /// The value that identifies register X15. 391 | HV_REG_X15, 392 | /// The value that identifies register X16. 393 | HV_REG_X16, 394 | /// The value that identifies register X17. 395 | HV_REG_X17, 396 | /// The value that identifies register X18. 397 | HV_REG_X18, 398 | /// The value that identifies register X19. 399 | HV_REG_X19, 400 | /// The value that identifies register X20. 401 | HV_REG_X20, 402 | /// The value that identifies register X21. 403 | HV_REG_X21, 404 | /// The value that identifies register X22. 405 | HV_REG_X22, 406 | /// The value that identifies register X23. 407 | HV_REG_X23, 408 | /// The value that identifies register X24. 409 | HV_REG_X24, 410 | /// The value that identifies register X25. 411 | HV_REG_X25, 412 | /// The value that identifies register X26. 413 | HV_REG_X26, 414 | /// The value that identifies register X27. 415 | HV_REG_X27, 416 | /// The value that identifies register X28. 417 | HV_REG_X28, 418 | /// The value that identifies register X29. 419 | HV_REG_X29, 420 | /// The value that identifies register X30. 421 | HV_REG_X30, 422 | /// The value that identifies the program counter (PC). 423 | HV_REG_PC, 424 | /// The value that identifies the floating-point control register (FPCR). 425 | HV_REG_FPCR, 426 | /// The value that identifies the floating-point status register (FPSR). 427 | HV_REG_FPSR, 428 | /// The value that identifies the current program status register (CPSR). 429 | HV_REG_CPSR, 430 | } 431 | 432 | impl hv_reg_t { 433 | /// The value that identifies the frame pointer (FP). 434 | pub const HV_REG_FP: Self = Self::HV_REG_X29; 435 | /// The value that identifies the link register (LR). 436 | pub const HV_REG_LR: Self = Self::HV_REG_X30; 437 | } 438 | 439 | extern "C" { 440 | /// Gets the current value of a vCPU register. 441 | /// 442 | /// # Parameters 443 | /// 444 | /// * `vcpu`: The vCPU instance. 445 | /// * `reg`: The ID of the general register. 446 | /// * `value`: The value of the register reg on output. 447 | /// 448 | /// # Return Value 449 | /// 450 | /// `HV_SUCCESS` if the operation was successful, otherwise an error code specified in 451 | /// [`hv_return_t`]. 452 | pub fn hv_vcpu_get_reg(vcpu: hv_vcpu_t, reg: hv_reg_t, value: *mut u64) -> hv_return_t; 453 | 454 | /// Sets the value of a vCPU register. 455 | /// 456 | /// # Parameters 457 | /// 458 | /// * `vcpu`: The vCPU instance. 459 | /// * `reg`: The ID of the general register. 460 | /// * `value`: The new value of the register. 461 | /// 462 | /// # Return Value 463 | /// 464 | /// `HV_SUCCESS` if the operation was successful, otherwise an error code specified in 465 | /// [`hv_return_t`]. 466 | pub fn hv_vcpu_set_reg(vcpu: hv_vcpu_t, reg: hv_reg_t, value: u64) -> hv_return_t; 467 | } 468 | 469 | // ----------------------------------------------------------------------------------------------- 470 | // vCPU Management - SIMD & Floating-Point Registers 471 | // ----------------------------------------------------------------------------------------------- 472 | 473 | /// The value that represents an ARM SIMD and FP register. 474 | #[cfg(feature = "simd_nightly")] 475 | pub type hv_simd_fp_uchar16_t = std::simd::i8x16; 476 | #[cfg(not(feature = "simd_nightly"))] 477 | pub type hv_simd_fp_uchar16_t = u128; 478 | 479 | /// The type that defines SIMD and floating-point registers. 480 | #[repr(C)] 481 | #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] 482 | pub enum hv_simd_fp_reg_t { 483 | /// The value representing SIMD register Q0. 484 | HV_SIMD_FP_REG_Q0, 485 | /// The value representing SIMD register Q1. 486 | HV_SIMD_FP_REG_Q1, 487 | /// The value representing SIMD register Q2. 488 | HV_SIMD_FP_REG_Q2, 489 | /// The value representing SIMD register Q3. 490 | HV_SIMD_FP_REG_Q3, 491 | /// The value representing SIMD register Q4. 492 | HV_SIMD_FP_REG_Q4, 493 | /// The value representing SIMD register Q5. 494 | HV_SIMD_FP_REG_Q5, 495 | /// The value representing SIMD register Q6. 496 | HV_SIMD_FP_REG_Q6, 497 | /// The value representing SIMD register Q7. 498 | HV_SIMD_FP_REG_Q7, 499 | /// The value representing SIMD register Q8. 500 | HV_SIMD_FP_REG_Q8, 501 | /// The value representing SIMD register Q9. 502 | HV_SIMD_FP_REG_Q9, 503 | /// The value representing SIMD register Q10. 504 | HV_SIMD_FP_REG_Q10, 505 | /// The value representing SIMD register Q11. 506 | HV_SIMD_FP_REG_Q11, 507 | /// The value representing SIMD register Q12. 508 | HV_SIMD_FP_REG_Q12, 509 | /// The value representing SIMD register Q13. 510 | HV_SIMD_FP_REG_Q13, 511 | /// The value representing SIMD register Q14. 512 | HV_SIMD_FP_REG_Q14, 513 | /// The value representing SIMD register Q15. 514 | HV_SIMD_FP_REG_Q15, 515 | /// The value representing SIMD register Q16. 516 | HV_SIMD_FP_REG_Q16, 517 | /// The value representing SIMD register Q17. 518 | HV_SIMD_FP_REG_Q17, 519 | /// The value representing SIMD register Q18. 520 | HV_SIMD_FP_REG_Q18, 521 | /// The value representing SIMD register Q19. 522 | HV_SIMD_FP_REG_Q19, 523 | /// The value representing SIMD register Q20. 524 | HV_SIMD_FP_REG_Q20, 525 | /// The value representing SIMD register Q21. 526 | HV_SIMD_FP_REG_Q21, 527 | /// The value representing SIMD register Q22. 528 | HV_SIMD_FP_REG_Q22, 529 | /// The value representing SIMD register Q23. 530 | HV_SIMD_FP_REG_Q23, 531 | /// The value representing SIMD register Q24. 532 | HV_SIMD_FP_REG_Q24, 533 | /// The value representing SIMD register Q25. 534 | HV_SIMD_FP_REG_Q25, 535 | /// The value representing SIMD register Q26. 536 | HV_SIMD_FP_REG_Q26, 537 | /// The value representing SIMD register Q27. 538 | HV_SIMD_FP_REG_Q27, 539 | /// The value representing SIMD register Q28. 540 | HV_SIMD_FP_REG_Q28, 541 | /// The value representing SIMD register Q29. 542 | HV_SIMD_FP_REG_Q29, 543 | /// The value representing SIMD register Q30. 544 | HV_SIMD_FP_REG_Q30, 545 | /// The value representing SIMD register Q31. 546 | HV_SIMD_FP_REG_Q31, 547 | } 548 | 549 | extern "C" { 550 | /// Gets the current value of a vCPU SIMD and FP register. 551 | /// 552 | /// # Parameters 553 | /// 554 | /// * `vcpu`: The vCPU instance. 555 | /// * `reg`: The ID of the SIMD and FP register. 556 | /// * `value`: The value of the register reg on output. 557 | /// 558 | /// # Return Value 559 | /// 560 | /// `HV_SUCCESS` if the operation was successful, otherwise an error code specified in 561 | /// [`hv_return_t`]. 562 | pub fn hv_vcpu_get_simd_fp_reg( 563 | vcpu: hv_vcpu_t, 564 | reg: hv_simd_fp_reg_t, 565 | value: *mut hv_simd_fp_uchar16_t, 566 | ) -> hv_return_t; 567 | 568 | /// Sets the value of a vCPU SIMD&FP register. 569 | /// 570 | /// # Parameters 571 | /// 572 | /// * `vcpu`: The vCPU instance. 573 | /// * `reg`: The ID of the SIMD and FP register. 574 | /// * `value`: The new value of the register. 575 | /// 576 | /// # Return Value 577 | /// 578 | /// `HV_SUCCESS` if the operation was successful, otherwise an error code specified in 579 | /// [`hv_return_t`]. 580 | pub fn hv_vcpu_set_simd_fp_reg( 581 | vcpu: hv_vcpu_t, 582 | reg: hv_simd_fp_reg_t, 583 | value: hv_simd_fp_uchar16_t, 584 | ) -> hv_return_t; 585 | } 586 | 587 | // ----------------------------------------------------------------------------------------------- 588 | // vCPU Management - System Registers 589 | // ----------------------------------------------------------------------------------------------- 590 | 591 | /// The type of system registers. 592 | #[repr(C)] 593 | #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] 594 | pub enum hv_sys_reg_t { 595 | /// The value that represents the system register DBGBVR0_EL1. 596 | HV_SYS_REG_DBGBVR0_EL1 = 0x8004, 597 | /// The value that represents the system register DBGBCR0_EL1. 598 | HV_SYS_REG_DBGBCR0_EL1 = 0x8005, 599 | /// The value that represents the system register DBGWVR0_EL1. 600 | HV_SYS_REG_DBGWVR0_EL1 = 0x8006, 601 | /// The value that represents the system register DBGWCR0_EL1. 602 | HV_SYS_REG_DBGWCR0_EL1 = 0x8007, 603 | /// The value that represents the system register DBGBVR1_EL1. 604 | HV_SYS_REG_DBGBVR1_EL1 = 0x800c, 605 | /// The value that represents the system register DBGBCR1_EL1. 606 | HV_SYS_REG_DBGBCR1_EL1 = 0x800d, 607 | /// The value that represents the system register DBGWVR1_EL1. 608 | HV_SYS_REG_DBGWVR1_EL1 = 0x800e, 609 | /// The value that represents the system register DBGWCR1_EL1. 610 | HV_SYS_REG_DBGWCR1_EL1 = 0x800f, 611 | /// The value that represents the system register MDCCINT_EL1. 612 | HV_SYS_REG_MDCCINT_EL1 = 0x8010, 613 | /// The value that represents the system register MDSCR_EL1. 614 | HV_SYS_REG_MDSCR_EL1 = 0x8012, 615 | /// The value that represents the system register DBGBVR2_EL1. 616 | HV_SYS_REG_DBGBVR2_EL1 = 0x8014, 617 | /// The value that represents the system register DBGBCR2_EL1. 618 | HV_SYS_REG_DBGBCR2_EL1 = 0x8015, 619 | /// The value that represents the system register DBGWVR2_EL1. 620 | HV_SYS_REG_DBGWVR2_EL1 = 0x8016, 621 | /// The value that represents the system register DBGWCR2_EL1. 622 | HV_SYS_REG_DBGWCR2_EL1 = 0x8017, 623 | /// The value that represents the system register DBGBVR3_EL1. 624 | HV_SYS_REG_DBGBVR3_EL1 = 0x801c, 625 | /// The value that represents the system register DBGBCR3_EL1. 626 | HV_SYS_REG_DBGBCR3_EL1 = 0x801d, 627 | /// The value that represents the system register DBGWVR3_EL1. 628 | HV_SYS_REG_DBGWVR3_EL1 = 0x801e, 629 | /// The value that represents the system register DBGWCR3_EL1. 630 | HV_SYS_REG_DBGWCR3_EL1 = 0x801f, 631 | /// The value that represents the system register DBGBVR4_EL1. 632 | HV_SYS_REG_DBGBVR4_EL1 = 0x8024, 633 | /// The value that represents the system register DBGBCR4_EL1. 634 | HV_SYS_REG_DBGBCR4_EL1 = 0x8025, 635 | /// The value that represents the system register DBGWVR4_EL1. 636 | HV_SYS_REG_DBGWVR4_EL1 = 0x8026, 637 | /// The value that represents the system register DBGWCR4_EL1. 638 | HV_SYS_REG_DBGWCR4_EL1 = 0x8027, 639 | /// The value that represents the system register DBGBVR5_EL1. 640 | HV_SYS_REG_DBGBVR5_EL1 = 0x802c, 641 | /// The value that represents the system register DBGBCR5_EL1. 642 | HV_SYS_REG_DBGBCR5_EL1 = 0x802d, 643 | /// The value that represents the system register DBGWVR5_EL1. 644 | HV_SYS_REG_DBGWVR5_EL1 = 0x802e, 645 | /// The value that represents the system register DBGWCR5_EL1. 646 | HV_SYS_REG_DBGWCR5_EL1 = 0x802f, 647 | /// The value that represents the system register DBGBVR6_EL1. 648 | HV_SYS_REG_DBGBVR6_EL1 = 0x8034, 649 | /// The value that represents the system register DBGBCR6_EL1. 650 | HV_SYS_REG_DBGBCR6_EL1 = 0x8035, 651 | /// The value that represents the system register DBGWVR6_EL1. 652 | HV_SYS_REG_DBGWVR6_EL1 = 0x8036, 653 | /// The value that represents the system register DBGWCR6_EL1. 654 | HV_SYS_REG_DBGWCR6_EL1 = 0x8037, 655 | /// The value that represents the system register DBGBVR7_EL1. 656 | HV_SYS_REG_DBGBVR7_EL1 = 0x803c, 657 | /// The value that represents the system register DBGBCR7_EL1. 658 | HV_SYS_REG_DBGBCR7_EL1 = 0x803d, 659 | /// The value that represents the system register DBGWVR7_EL1. 660 | HV_SYS_REG_DBGWVR7_EL1 = 0x803e, 661 | /// The value that represents the system register DBGWCR7_EL1. 662 | HV_SYS_REG_DBGWCR7_EL1 = 0x803f, 663 | /// The value that represents the system register DBGBVR8_EL1. 664 | HV_SYS_REG_DBGBVR8_EL1 = 0x8044, 665 | /// The value that represents the system register DBGBCR8_EL1. 666 | HV_SYS_REG_DBGBCR8_EL1 = 0x8045, 667 | /// The value that represents the system register DBGWVR8_EL1. 668 | HV_SYS_REG_DBGWVR8_EL1 = 0x8046, 669 | /// The value that represents the system register DBGWCR8_EL1. 670 | HV_SYS_REG_DBGWCR8_EL1 = 0x8047, 671 | /// The value that represents the system register DBGBVR9_EL1. 672 | HV_SYS_REG_DBGBVR9_EL1 = 0x804c, 673 | /// The value that represents the system register DBGBCR9_EL1. 674 | HV_SYS_REG_DBGBCR9_EL1 = 0x804d, 675 | /// The value that represents the system register DBGWVR9_EL1. 676 | HV_SYS_REG_DBGWVR9_EL1 = 0x804e, 677 | /// The value that represents the system register DBGWCR9_EL1. 678 | HV_SYS_REG_DBGWCR9_EL1 = 0x804f, 679 | /// The value that represents the system register DBGBVR10_EL1. 680 | HV_SYS_REG_DBGBVR10_EL1 = 0x8054, 681 | /// The value that represents the system register DBGBCR10_EL1. 682 | HV_SYS_REG_DBGBCR10_EL1 = 0x8055, 683 | /// The value that represents the system register DBGWVR10_EL1. 684 | HV_SYS_REG_DBGWVR10_EL1 = 0x8056, 685 | /// The value that represents the system register DBGWCR10_EL1. 686 | HV_SYS_REG_DBGWCR10_EL1 = 0x8057, 687 | /// The value that represents the system register DBGBVR11_EL1. 688 | HV_SYS_REG_DBGBVR11_EL1 = 0x805c, 689 | /// The value that represents the system register DBGBCR11_EL1. 690 | HV_SYS_REG_DBGBCR11_EL1 = 0x805d, 691 | /// The value that represents the system register DBGWVR11_EL1. 692 | HV_SYS_REG_DBGWVR11_EL1 = 0x805e, 693 | /// The value that represents the system register DBGWCR11_EL1. 694 | HV_SYS_REG_DBGWCR11_EL1 = 0x805f, 695 | /// The value that represents the system register DBGBVR12_EL1. 696 | HV_SYS_REG_DBGBVR12_EL1 = 0x8064, 697 | /// The value that represents the system register DBGBCR12_EL1. 698 | HV_SYS_REG_DBGBCR12_EL1 = 0x8065, 699 | /// The value that represents the system register DBGWVR12_EL1. 700 | HV_SYS_REG_DBGWVR12_EL1 = 0x8066, 701 | /// The value that represents the system register DBGWCR12_EL1. 702 | HV_SYS_REG_DBGWCR12_EL1 = 0x8067, 703 | /// The value that represents the system register DBGBVR13_EL1. 704 | HV_SYS_REG_DBGBVR13_EL1 = 0x806c, 705 | /// The value that represents the system register DBGBCR13_EL1. 706 | HV_SYS_REG_DBGBCR13_EL1 = 0x806d, 707 | /// The value that represents the system register DBGWVR13_EL1. 708 | HV_SYS_REG_DBGWVR13_EL1 = 0x806e, 709 | /// The value that represents the system register DBGWCR13_EL1. 710 | HV_SYS_REG_DBGWCR13_EL1 = 0x806f, 711 | /// The value that represents the system register DBGBVR14_EL1. 712 | HV_SYS_REG_DBGBVR14_EL1 = 0x8074, 713 | /// The value that represents the system register DBGBCR14_EL1. 714 | HV_SYS_REG_DBGBCR14_EL1 = 0x8075, 715 | /// The value that represents the system register DBGWVR14_EL1. 716 | HV_SYS_REG_DBGWVR14_EL1 = 0x8076, 717 | /// The value that represents the system register DBGWCR14_EL1. 718 | HV_SYS_REG_DBGWCR14_EL1 = 0x8077, 719 | /// The value that represents the system register DBGBVR15_EL1. 720 | HV_SYS_REG_DBGBVR15_EL1 = 0x807c, 721 | /// The value that represents the system register DBGBCR15_EL1. 722 | HV_SYS_REG_DBGBCR15_EL1 = 0x807d, 723 | /// The value that represents the system register DBGWVR15_EL1. 724 | HV_SYS_REG_DBGWVR15_EL1 = 0x807e, 725 | /// The value that represents the system register DBGWCR15_EL1. 726 | HV_SYS_REG_DBGWCR15_EL1 = 0x807f, 727 | /// The value that represents the system register MIDR_EL1. 728 | HV_SYS_REG_MIDR_EL1 = 0xc000, 729 | /// The value that represents the system register MPIDR_EL1. 730 | HV_SYS_REG_MPIDR_EL1 = 0xc005, 731 | /// The value that describes the AArch64 Processor Feature Register 0. 732 | HV_SYS_REG_ID_AA64PFR0_EL1 = 0xc020, 733 | /// The value that describes the AArch64 Processor Feature Register 1. 734 | HV_SYS_REG_ID_AA64PFR1_EL1 = 0xc021, 735 | /// The value that describes the AArch64 Debug Feature Register 0. 736 | HV_SYS_REG_ID_AA64DFR0_EL1 = 0xc028, 737 | /// The value that describes the AArch64 Debug Feature Register 1. 738 | HV_SYS_REG_ID_AA64DFR1_EL1 = 0xc029, 739 | /// The value that describes the AArch64 Instruction Set Attribute Register 0. 740 | HV_SYS_REG_ID_AA64ISAR0_EL1 = 0xc030, 741 | /// The value that describes the AArch64 Instruction Set Attribute Register 1. 742 | HV_SYS_REG_ID_AA64ISAR1_EL1 = 0xc031, 743 | /// The value that describes the AArch64 Memory Model Feature Register 0. 744 | HV_SYS_REG_ID_AA64MMFR0_EL1 = 0xc038, 745 | /// The value that describes the AArch64 Memory Model Feature Register 1. 746 | HV_SYS_REG_ID_AA64MMFR1_EL1 = 0xc039, 747 | /// The value that describes the AArch64 Memory Model Feature Register 2. 748 | HV_SYS_REG_ID_AA64MMFR2_EL1 = 0xc03a, 749 | /// The value that represents the system register SCTLR_EL1. 750 | HV_SYS_REG_SCTLR_EL1 = 0xc080, 751 | /// The value that represents the system register CPACR_EL1. 752 | HV_SYS_REG_CPACR_EL1 = 0xc082, 753 | /// The value that represents the system register TTBR0_EL1. 754 | HV_SYS_REG_TTBR0_EL1 = 0xc100, 755 | /// The value that represents the system register TTBR1_EL1. 756 | HV_SYS_REG_TTBR1_EL1 = 0xc101, 757 | /// The value that represents the system register TCR_EL1. 758 | HV_SYS_REG_TCR_EL1 = 0xc102, 759 | /// The value that represents the system register APIAKEYLO_EL1. 760 | HV_SYS_REG_APIAKEYLO_EL1 = 0xc108, 761 | /// The value that represents the system register APIAKEYHI_EL1. 762 | HV_SYS_REG_APIAKEYHI_EL1 = 0xc109, 763 | /// The value that represents the system register APIBKEYLO_EL1. 764 | HV_SYS_REG_APIBKEYLO_EL1 = 0xc10a, 765 | /// The value that represents the system register APIBKEYHI_EL1. 766 | HV_SYS_REG_APIBKEYHI_EL1 = 0xc10b, 767 | /// The value that represents the system register APDAKEYLO_EL1. 768 | HV_SYS_REG_APDAKEYLO_EL1 = 0xc110, 769 | /// The value that represents the system register APDAKEYHI_EL1. 770 | HV_SYS_REG_APDAKEYHI_EL1 = 0xc111, 771 | /// The value that represents the system register APDBKEYLO_EL1. 772 | HV_SYS_REG_APDBKEYLO_EL1 = 0xc112, 773 | /// The value that represents the system register APDBKEYHI_EL1. 774 | HV_SYS_REG_APDBKEYHI_EL1 = 0xc113, 775 | /// The value that represents the system register APGAKEYLO_EL1. 776 | HV_SYS_REG_APGAKEYLO_EL1 = 0xc118, 777 | /// The value that represents the system register APGAKEYHI_EL1. 778 | HV_SYS_REG_APGAKEYHI_EL1 = 0xc119, 779 | /// The value that represents the system register SPSR_EL1. 780 | HV_SYS_REG_SPSR_EL1 = 0xc200, 781 | /// The value that represents the system register ELR_EL1. 782 | HV_SYS_REG_ELR_EL1 = 0xc201, 783 | /// The value that represents the system register SP_EL0. 784 | HV_SYS_REG_SP_EL0 = 0xc208, 785 | /// The value that represents the system register AFSR0_EL1. 786 | HV_SYS_REG_AFSR0_EL1 = 0xc288, 787 | /// The value that represents the system register AFSR1_EL1. 788 | HV_SYS_REG_AFSR1_EL1 = 0xc289, 789 | /// The value that represents the system register ESR_EL1. 790 | HV_SYS_REG_ESR_EL1 = 0xc290, 791 | /// The value that represents the system register FAR_EL1. 792 | HV_SYS_REG_FAR_EL1 = 0xc300, 793 | /// The value that represents the system register PAR_EL1. 794 | HV_SYS_REG_PAR_EL1 = 0xc3a0, 795 | /// The value that represents the system register MAIR_EL1. 796 | HV_SYS_REG_MAIR_EL1 = 0xc510, 797 | /// The value that represents the system register AMAIR_EL1. 798 | HV_SYS_REG_AMAIR_EL1 = 0xc518, 799 | /// The value that represents the system register VBAR_EL1. 800 | HV_SYS_REG_VBAR_EL1 = 0xc600, 801 | /// The value that represents the system register CONTEXTIDR_EL1. 802 | HV_SYS_REG_CONTEXTIDR_EL1 = 0xc681, 803 | /// The value that represents the system register TPIDR_EL1. 804 | HV_SYS_REG_TPIDR_EL1 = 0xc684, 805 | /// The value that represents the system register CNTKCTL_EL1. 806 | HV_SYS_REG_CNTKCTL_EL1 = 0xc708, 807 | /// The value that represents the system register CSSELR_EL1. 808 | HV_SYS_REG_CSSELR_EL1 = 0xd000, 809 | /// The value that represents the system register TPIDR_EL0. 810 | HV_SYS_REG_TPIDR_EL0 = 0xde82, 811 | /// The value that represents the system register TPIDRRO_EL0. 812 | HV_SYS_REG_TPIDRRO_EL0 = 0xde83, 813 | /// The value that represents the system register CNTV_CTL_EL0. 814 | HV_SYS_REG_CNTV_CTL_EL0 = 0xdf19, 815 | /// The value that represents the system register CNTV_CVAL_EL0. 816 | HV_SYS_REG_CNTV_CVAL_EL0 = 0xdf1a, 817 | /// The value that represents the system register SP_EL1. 818 | HV_SYS_REG_SP_EL1 = 0xe208, 819 | } 820 | 821 | extern "C" { 822 | /// Gets the current value of a vCPU system register. 823 | /// 824 | /// # Parameters 825 | /// 826 | /// * `vcpu`: The vCPU instance. 827 | /// * `reg`: The ID of the system register. 828 | /// * `value`: The value of the register reg on output. 829 | /// 830 | /// # Return Value 831 | /// 832 | /// `HV_SUCCESS` if the operation was successful, otherwise an error code specified in 833 | /// [`hv_return_t`]. 834 | pub fn hv_vcpu_get_sys_reg(vcpu: hv_vcpu_t, reg: hv_sys_reg_t, value: *mut u64) -> hv_return_t; 835 | 836 | /// Sets the value of a vCPU system register. 837 | /// 838 | /// # Parameters 839 | /// 840 | /// * `vcpu`: The vCPU instance. 841 | /// * `reg`: The ID of the system register. 842 | /// * `value`: The new value of the register. 843 | /// 844 | /// # Return Value 845 | /// 846 | /// `HV_SUCCESS` if the operation was successful, otherwise an error code specified in 847 | /// [`hv_return_t`]. 848 | pub fn hv_vcpu_set_sys_reg(vcpu: hv_vcpu_t, reg: hv_sys_reg_t, value: u64) -> hv_return_t; 849 | } 850 | 851 | // ----------------------------------------------------------------------------------------------- 852 | // vCPU Management - Trap Configuration 853 | // ----------------------------------------------------------------------------------------------- 854 | 855 | extern "C" { 856 | /// Gets whether debug exceptions exit the guest. 857 | /// 858 | /// # Parameters 859 | /// 860 | /// * `vcpu`: The vCPU instance. 861 | /// * `value`: Indicates whether debug exceptions in the guest trap to the host on output. 862 | /// 863 | /// # Return Value 864 | /// 865 | /// `HV_SUCCESS` if the operation was successful, otherwise an error code specified in 866 | /// [`hv_return_t`]. 867 | pub fn hv_vcpu_get_trap_debug_exceptions(vcpu: hv_vcpu_t, value: *mut bool) -> hv_return_t; 868 | 869 | /// Sets whether debug exceptions exit the guest. 870 | /// 871 | /// # Parameters 872 | /// 873 | /// * `vcpu`: The vCPU instance. 874 | /// * `value`: A Boolean value that if true indicates debug exceptions in the guest trap to 875 | /// the host. 876 | /// 877 | /// # Return Value 878 | /// 879 | /// `HV_SUCCESS` if the operation was successful, otherwise an error code specified in 880 | /// [`hv_return_t`]. 881 | pub fn hv_vcpu_set_trap_debug_exceptions(vcpu: hv_vcpu_t, value: bool) -> hv_return_t; 882 | 883 | /// Gets whether debug-register accesses exit the guest. 884 | /// 885 | /// # Parameters 886 | /// 887 | /// * `vcpu`: The vCPU instance. 888 | /// * `value`: Indicates whether debug-register accesses in the guest trap to the host on 889 | /// output. 890 | /// 891 | /// # Return Value 892 | /// 893 | /// `HV_SUCCESS` if the operation was successful, otherwise an error code specified in 894 | /// [`hv_return_t`]. 895 | pub fn hv_vcpu_get_trap_debug_reg_accesses(vcpu: hv_vcpu_t, value: *mut bool) -> hv_return_t; 896 | 897 | /// Sets whether debug-register accesses exit the guest. 898 | /// 899 | /// # Parameters 900 | /// 901 | /// * `vcpu`: The vCPU instance. 902 | /// * `value`: A Boolean value that if true indicates debug-register accesses in the guest 903 | /// trap to the host. 904 | /// 905 | /// # Return Value 906 | /// 907 | /// `HV_SUCCESS` if the operation was successful, otherwise an error code specified in 908 | /// [`hv_return_t`]. 909 | pub fn hv_vcpu_set_trap_debug_reg_accesses(vcpu: hv_vcpu_t, value: bool) -> hv_return_t; 910 | } 911 | 912 | // ----------------------------------------------------------------------------------------------- 913 | // Memory Management 914 | // ----------------------------------------------------------------------------------------------- 915 | 916 | /// The type of an intermediate physical address, which is a guest physical address space of the 917 | /// VM. 918 | pub type hv_ipa_t = u64; 919 | /// The permissions for guest physical memory regions. 920 | pub type hv_memory_flags_t = u64; 921 | 922 | /// The value that represents the memory-read permission. 923 | pub const HV_MEMORY_READ: hv_memory_flags_t = 1u64 << 0; 924 | /// The value that represents the memory-write permission. 925 | pub const HV_MEMORY_WRITE: hv_memory_flags_t = 1u64 << 1; 926 | /// The value that represents the memory-execute permission. 927 | pub const HV_MEMORY_EXEC: hv_memory_flags_t = 1u64 << 2; 928 | 929 | extern "C" { 930 | /// Maps a region in the virtual address space of the current process into the guest physical 931 | /// address space of the VM. 932 | /// 933 | /// # Parameters 934 | /// 935 | /// * `addr`: The address in the current process. It must be page-aligned. 936 | /// * `ipa`: The address in the intermediate physical address space. It must be page-aligned. 937 | /// * `size`: The size of the mapped region in bytes. It must be a multiple of the page size. 938 | /// * `flags`: The permissions for the mapped region. For a list of valid options, see 939 | /// [`hv_memory_flags_t`]. 940 | /// 941 | /// # Return Value 942 | /// 943 | /// `HV_SUCCESS` if the operation was successful, otherwise an error code specified in 944 | /// [`hv_return_t`]. 945 | pub fn hv_vm_map( 946 | addr: *const c_void, 947 | ipa: hv_ipa_t, 948 | size: usize, 949 | flags: hv_memory_flags_t, 950 | ) -> hv_return_t; 951 | 952 | /// Unmaps a region in the guest physical address space of the VM. 953 | /// 954 | /// # Parameters 955 | /// 956 | /// * `ipa`: The address in the intermediate physical address space. It must be page-aligned. 957 | /// * `size`: The size of the region to unmap, in bytes. It must be a multiple of the page 958 | /// size. 959 | /// 960 | /// # Return Value 961 | /// 962 | /// `HV_SUCCESS` if the operation was successful, otherwise an error code specified in 963 | /// [`hv_return_t`]. 964 | pub fn hv_vm_unmap(ipa: hv_ipa_t, size: usize) -> hv_return_t; 965 | 966 | /// Modifies the permissions of a region in the guest physical address space of the VM. 967 | /// 968 | /// # Parameters 969 | /// 970 | /// * `ipa`: The address in the intermediate physical address space. It must be page-aligned. 971 | /// * `size`: The size of the region to unmap, in bytes. It must be a multiple of the page 972 | /// size. 973 | /// * `flags`: The permissions for the protected region. For a list of valid options, see 974 | /// [`hv_memory_flags_t. 975 | /// 976 | /// # Return Value 977 | /// 978 | /// `HV_SUCCESS` if the operation was successful, otherwise an error code specified in 979 | /// [`hv_return_t`]. 980 | pub fn hv_vm_protect(ipa: hv_ipa_t, size: usize, flags: hv_memory_flags_t) -> hv_return_t; 981 | } 982 | 983 | // ----------------------------------------------------------------------------------------------- 984 | // Timer Functions 985 | // ----------------------------------------------------------------------------------------------- 986 | 987 | extern "C" { 988 | /// Gets the virtual timer mask. 989 | /// 990 | /// # Parameters 991 | /// 992 | /// * `vcpu`: The ID of the vCPU instance. 993 | /// * `vtimer_is_masked`: The value of the mask. 994 | /// 995 | /// # Return Value 996 | /// 997 | /// `HV_SUCCESS` if the operation was successful, otherwise an error code specified in 998 | /// [`hv_return_t`]. 999 | pub fn hv_vcpu_get_vtimer_mask(vcpu: hv_vcpu_t, vtimer_is_masked: *mut bool) -> hv_return_t; 1000 | 1001 | /// Sets or clears the virtual timer mask. 1002 | /// 1003 | /// # Parameters 1004 | /// 1005 | /// * `vcpu`: The ID of the vCPU instance. 1006 | /// * `vtimer_is_masked`: A Boolean value that indicates whether the vTimer has a mask set. 1007 | /// 1008 | /// # Return Value 1009 | /// 1010 | /// `HV_SUCCESS` if the operation was successful, otherwise an error code specified in 1011 | /// [`hv_return_t`]. 1012 | pub fn hv_vcpu_set_vtimer_mask(vcpu: hv_vcpu_t, vtimer_is_masked: bool) -> hv_return_t; 1013 | 1014 | /// Returns the vTimer offset for the vCPU ID you specify. 1015 | /// 1016 | /// # Parameters 1017 | /// 1018 | /// * `vcpu`: The ID of the vCPU instance. 1019 | /// * `vtimer_offset`: A pointer to vTimer offset; the Hypervisor writes to this value on 1020 | /// success. 1021 | /// 1022 | /// # Return Value 1023 | /// 1024 | /// `HV_SUCCESS` if the operation was successful, otherwise an error code specified in 1025 | /// [`hv_return_t`]. 1026 | pub fn hv_vcpu_get_vtimer_offset(vcpu: hv_vcpu_t, vtimer_offset: *mut u64) -> hv_return_t; 1027 | 1028 | /// Sets the vTimer offset to a value that you provide. 1029 | /// 1030 | /// # Parameters 1031 | /// 1032 | /// * `vcpu`: The ID of the vCPU instance. 1033 | /// * `vtimer_offset`: The new vTimer offset. 1034 | /// 1035 | /// # Return Value 1036 | /// 1037 | /// `HV_SUCCESS` if the operation was successful, otherwise an error code specified in 1038 | /// [`hv_return_t`]. 1039 | pub fn hv_vcpu_set_vtimer_offset(vcpu: hv_vcpu_t, vtimer_offset: u64) -> hv_return_t; 1040 | } 1041 | 1042 | #[cfg(test)] 1043 | mod tests { 1044 | // Tests must be run with `--test-threads=1`, since only one VM instance is allowed per 1045 | // process. Tests could fail because `hv_vm_create` is called multiple times in concurrent 1046 | // threads. 1047 | 1048 | use super::*; 1049 | use std::alloc::{alloc, Layout}; 1050 | use std::ptr; 1051 | 1052 | #[test] 1053 | fn vm_create_destroy() { 1054 | let config = ptr::null_mut(); 1055 | // Creates a VM instance for the current process. 1056 | let ret = unsafe { hv_vm_create(config) }; 1057 | assert_eq!(ret, hv_error_t::HV_SUCCESS as i32); 1058 | // Trying to create a second instance leads to a HV_BUSY error. 1059 | let ret = unsafe { hv_vm_create(config) }; 1060 | assert_eq!(ret, hv_error_t::HV_BUSY as i32); 1061 | // Destroys the process instance. 1062 | let ret = unsafe { hv_vm_destroy() }; 1063 | assert_eq!(ret, hv_error_t::HV_SUCCESS as i32); 1064 | } 1065 | 1066 | #[test] 1067 | pub fn vcpu_create_destroy() { 1068 | let config = ptr::null_mut(); 1069 | // Creates a VM instance for the current process. 1070 | let ret = unsafe { hv_vm_create(config) }; 1071 | assert_eq!(ret, hv_error_t::HV_SUCCESS as i32); 1072 | // Retrieves the maximum number of vCPU. 1073 | let mut max_vcpu_count = 0; 1074 | let ret = unsafe { hv_vm_get_max_vcpu_count(&mut max_vcpu_count) }; 1075 | assert_eq!(ret, hv_error_t::HV_SUCCESS as i32); 1076 | // Creates a vCPU. 1077 | let mut vcpu: hv_vcpu_t = 0; 1078 | let layout = Layout::new::(); 1079 | let ret = unsafe { 1080 | let exit = alloc(layout) as *mut *const hv_vcpu_exit_t; 1081 | hv_vcpu_create(&mut vcpu, exit, config) 1082 | }; 1083 | assert_eq!(ret, hv_error_t::HV_SUCCESS as i32); 1084 | // Destroys a vCPU. 1085 | let ret = unsafe { hv_vcpu_destroy(vcpu) }; 1086 | assert_eq!(ret, hv_error_t::HV_SUCCESS as i32); 1087 | // Destroys the process instance. 1088 | let ret = unsafe { hv_vm_destroy() }; 1089 | assert_eq!(ret, hv_error_t::HV_SUCCESS as i32); 1090 | } 1091 | } 1092 | -------------------------------------------------------------------------------- /entitlements.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.hypervisor 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Rust bindings for the Apple Silicon Hypervisor.framework 2 | //! 3 | //! This library can be used to build Rust applications leveraging the 4 | //! [`Hypervisor`](https://developer.apple.com/documentation/hypervisor) framework on 5 | //! Apple Silicon. 6 | //! 7 | //! ### Self-Signed Binaries and Hypervisor Entitlement 8 | //! 9 | //! To be able to reach the Hypervisor Framework, a binary executable has to have been granted the 10 | //! [hypervisor entitlement](https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_security_hypervisor). 11 | //! 12 | //! You can add this entitlement to a binary located at `/path/to/binary` by using the 13 | //! `entitlements.xml` file found at the root of the repository and the following command: 14 | //! 15 | //! ``` 16 | //! codesign --sign - --entitlements entitlements.xml --deep --force /path/to/binary 17 | //! ``` 18 | //! 19 | //! ### Compilation Workflow 20 | //! 21 | //! Create a Rust project and add Applevisor as a dependency in `Cargo.toml`. You can either pull 22 | //! it from [crates.io](https://crates.io/crates/applevisor) ... 23 | //! 24 | //! ```toml 25 | //! # Check which version is the latest, this part of the README might not be updated 26 | //! # in future releases. 27 | //! applevisor = "0.1.3" 28 | //! ``` 29 | //! 30 | //! ... or directly from the GitHub repository. 31 | //! 32 | //! ```toml 33 | //! applevisor = { git="https://github.com/impalabs/applevisor", branch="master" } 34 | //! ``` 35 | //! 36 | //! Create a file called `entitlements.txt` in the project's root directory and add the following: 37 | //! 38 | //! ```xml 39 | //! 40 | //! 41 | //! 42 | //! 43 | //! com.apple.security.hypervisor 44 | //! 45 | //! 46 | //! 47 | //! ``` 48 | //! 49 | //! Write code and then build the project. 50 | //! 51 | //! ``` 52 | //! cargo build --release 53 | //! ``` 54 | //! 55 | //! Sign the binary and grant the hypervisor entitlement. 56 | //! 57 | //! ``` 58 | //! codesign --sign - --entitlements entitlements.xml --deep --force target/release/${PROJECT_NAME} 59 | //! ``` 60 | //! 61 | //! Run the binary. 62 | //! 63 | //! ``` 64 | //! target/release/${PROJECT_NAME} 65 | //! ``` 66 | //! 67 | //! ### Example 68 | //! 69 | //! The following example: 70 | //! 71 | //! * creates a virtual machine for the current process; 72 | //! * creates a virtual CPU; 73 | //! * enables the hypervisor's debug features to be able to use breakpoints later on; 74 | //! * creates a physical memory mapping of 0x1000 bytes and maps it at address 0x4000 with RWX 75 | //! permissions; 76 | //! * writes the instructions `mov x0, #0x42; brk #0;` at address 0x4000; 77 | //! * sets PC to 0x4000; 78 | //! * starts the vCPU and runs our program; 79 | //! * returns when it encounters the breakpoint. 80 | //! 81 | //! ```no_run 82 | //! use applevisor::*; 83 | //! 84 | //! fn main() { 85 | //! // Creates a new virtual machine. There can be one, and only one, per process. Operations 86 | //! // on the virtual machine remains possible as long as this object is valid. 87 | //! let _vm = VirtualMachine::new().unwrap(); 88 | //! 89 | //! // Creates a new virtual CPU. This object abstracts operations that can be performed on 90 | //! // CPUs, such as starting and stopping them, changing their registers, etc. 91 | //! let vcpu = Vcpu::new().unwrap(); 92 | //! 93 | //! // Enables debug features for the hypervisor. This is optional, but it might be required 94 | //! // for certain features to work, such as breakpoints. 95 | //! assert!(vcpu.set_trap_debug_exceptions(true).is_ok()); 96 | //! assert!(vcpu.set_trap_debug_reg_accesses(true).is_ok()); 97 | //! 98 | //! // Creates a mapping object that represents a 0x1000-byte physical memory range. 99 | //! let mut mem = Mapping::new(0x1000).unwrap(); 100 | //! 101 | //! // This mapping needs to be mapped to effectively allocate physical memory for the guest. 102 | //! // Here we map the region at address 0x4000 and set the permissions to Read-Write-Execute. 103 | //! // Note that physical memory page sizes on Apple Silicon are 0x4000-aligned, you might 104 | //! // encounter errors if you don't respect the alignment. 105 | //! assert_eq!(mem.map(0x4000, MemPerms::RWX), Ok(())); 106 | //! 107 | //! // Writes a `mov x0, #0x42` instruction at address 0x4000. 108 | //! assert_eq!(mem.write_dword(0x4000, 0xd2800840), Ok(4)); 109 | //! // Writes a `brk #0` instruction at address 0x4004. 110 | //! assert_eq!(mem.write_dword(0x4004, 0xd4200000), Ok(4)); 111 | //! 112 | //! // Sets PC to 0x4000. 113 | //! assert!(vcpu.set_reg(Reg::PC, 0x4000).is_ok()); 114 | //! 115 | //! // Starts the Vcpu. It will execute our mov and breakpoint instructions before stopping. 116 | //! assert!(vcpu.run().is_ok()); 117 | //! 118 | //! // The *exit information* can be used to used to retrieve different pieces of information 119 | //! // about the CPU exit status (e.g. exception type, fault address, etc.). 120 | //! let _exit_info = vcpu.get_exit_info(); 121 | //! 122 | //! // If everything went as expected, the value in X0 is 0x42. 123 | //! assert_eq!(vcpu.get_reg(Reg::X0), Ok(0x42)); 124 | //! } 125 | //! ``` 126 | //! 127 | //! Feel free to also have a look at the [Hyperpom](https://github.com/impalabs/hyperpom) 128 | //! project's source code for a real-life example of how these bindings are used. 129 | 130 | #![cfg_attr(feature = "simd_nightly", feature(portable_simd), feature(simd_ffi), feature(concat_idents))] 131 | 132 | use core::ffi::c_void; 133 | use core::ptr; 134 | use std::alloc; 135 | use std::hash::{Hash, Hasher}; 136 | use std::sync::{Arc, RwLock}; 137 | 138 | #[cfg(feature = "simd_nightly")] 139 | use std::simd; 140 | 141 | #[cfg(not(feature = "simd_nightly"))] 142 | use concat_idents::concat_idents; 143 | 144 | use applevisor_sys::hv_cache_type_t::*; 145 | use applevisor_sys::hv_exit_reason_t::*; 146 | use applevisor_sys::hv_feature_reg_t::*; 147 | use applevisor_sys::hv_interrupt_type_t::*; 148 | use applevisor_sys::hv_reg_t::*; 149 | use applevisor_sys::hv_simd_fp_reg_t::*; 150 | use applevisor_sys::hv_sys_reg_t::*; 151 | use applevisor_sys::*; 152 | 153 | // ----------------------------------------------------------------------------------------------- 154 | // Macros 155 | // ----------------------------------------------------------------------------------------------- 156 | 157 | /// Macro that calls an ffi hypervisor function and wraps the resulting return value in a 158 | /// [`Result`]. 159 | macro_rules! hv_unsafe_call { 160 | ($x:expr) => {{ 161 | let ret = unsafe { $x }; 162 | match ret { 163 | x if x == hv_error_t::HV_SUCCESS as i32 => Ok(()), 164 | code => Err(HypervisorError::from(code)), 165 | } 166 | }}; 167 | } 168 | 169 | /// Macro that generates an enum `$dst` corresponding to the raw C enum `$src`. 170 | /// Also generates the [`Into`] trait implementation that converts a `$dst` variant into the 171 | /// corresponding `$src`. 172 | macro_rules! gen_enum { 173 | ( 174 | $(#[$cmt:meta])* $dst: ident, 175 | $src: ident, 176 | $prefix:ident, 177 | $(#[$var_cmt:meta] $variant: ident,)* 178 | ) => { 179 | $(#[$cmt])* 180 | #[allow(non_camel_case_types)] 181 | #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] 182 | pub enum $dst { 183 | $( 184 | #[$var_cmt] 185 | $variant, 186 | )* 187 | } 188 | 189 | #[cfg(feature = "simd_nightly")] 190 | #[allow(clippy::from_over_into)] 191 | impl Into<$src> for $dst { 192 | fn into(self) -> $src { 193 | match self { 194 | $($dst::$variant => concat_idents!($prefix, $variant),)* 195 | } 196 | } 197 | } 198 | 199 | #[cfg(not(feature = "simd_nightly"))] 200 | #[allow(clippy::from_over_into)] 201 | impl Into<$src> for $dst { 202 | fn into(self) -> $src { 203 | match self { 204 | $($dst::$variant => concat_idents!(x = $prefix, $variant { x }),)* 205 | } 206 | } 207 | } 208 | } 209 | } 210 | 211 | // ----------------------------------------------------------------------------------------------- 212 | // Constants 213 | // ----------------------------------------------------------------------------------------------- 214 | 215 | gen_enum!( 216 | /// The type that defines feature registers. 217 | FeatureReg, 218 | hv_feature_reg_t, 219 | HV_FEATURE_REG_, 220 | /// The value that identifies debug feature register 0, EL1 (DFR0_EL1). 221 | ID_AA64DFR0_EL1, 222 | /// The value that identifies debug feature register 1, EL1 (DFR1_EL1). 223 | ID_AA64DFR1_EL1, 224 | /// The value that identifies instruction set attribute register 0, EL1 (ISAR0_EL1). 225 | ID_AA64ISAR0_EL1, 226 | /// The value that identifies instruction set attribute register 1, EL1 (ISAR_EL1). 227 | ID_AA64ISAR1_EL1, 228 | /// The value that identifies memory model feature register 0, EL1(MMFR0_EL1). 229 | ID_AA64MMFR0_EL1, 230 | /// The value that identifies memory model feature register 1, EL1 (MMFR1_EL1). 231 | ID_AA64MMFR1_EL1, 232 | /// The value that identifies memory model feature register 2, EL1 (MMFR2_EL1). 233 | ID_AA64MMFR2_EL1, 234 | /// The value that identifies processor feature register 0, EL1 (PFR0_EL1). 235 | ID_AA64PFR0_EL1, 236 | /// The value that identifies processor feature register 1, EL1 (PFR1_EL1). 237 | ID_AA64PFR1_EL1, 238 | /// The value that describes Cache Type Register, EL0. 239 | CTR_EL0, 240 | /// The value that describes Cache Level ID Register, EL1. 241 | CLIDR_EL1, 242 | /// The values that describes Data Cache Zero ID Register, EL0. 243 | DCZID_EL0, 244 | ); 245 | 246 | gen_enum!( 247 | /// The structure that describes an instruction or data cache element. 248 | CacheType, 249 | hv_cache_type_t, 250 | HV_CACHE_TYPE_, 251 | /// The value that describes a cached data value. 252 | DATA, 253 | /// The value that describes a cached instuction value. 254 | INSTRUCTION, 255 | ); 256 | 257 | gen_enum!( 258 | /// The type that describes the event that triggered a guest exit to the host. 259 | ExitReason, 260 | hv_exit_reason_t, 261 | HV_EXIT_REASON_, 262 | /// The value that identifies exits requested by exit handler on the host. 263 | CANCELED, 264 | /// The value that identifies traps caused by the guest operations. 265 | EXCEPTION, 266 | /// The value that identifies when the virtual timer enters the pending state. 267 | VTIMER_ACTIVATED, 268 | /// The value that identifies unexpected exits. 269 | UNKNOWN, 270 | ); 271 | 272 | impl From for ExitReason { 273 | fn from(src: hv_exit_reason_t) -> Self { 274 | match src { 275 | HV_EXIT_REASON_CANCELED => ExitReason::CANCELED, 276 | HV_EXIT_REASON_EXCEPTION => ExitReason::EXCEPTION, 277 | HV_EXIT_REASON_VTIMER_ACTIVATED => ExitReason::VTIMER_ACTIVATED, 278 | HV_EXIT_REASON_UNKNOWN => ExitReason::UNKNOWN, 279 | } 280 | } 281 | } 282 | 283 | gen_enum!( 284 | /// The type that defines the vCPU’s interrupts. 285 | InterruptType, 286 | hv_interrupt_type_t, 287 | HV_INTERRUPT_TYPE_, 288 | /// ARM Fast Interrupt Request. 289 | FIQ, 290 | /// ARM Interrupt Request. 291 | IRQ, 292 | ); 293 | 294 | gen_enum!( 295 | /// The type that defines general registers. 296 | Reg, 297 | hv_reg_t, 298 | HV_REG_, 299 | /// The value that identifies register X0. 300 | X0, 301 | /// The value that identifies register X1. 302 | X1, 303 | /// The value that identifies register X2. 304 | X2, 305 | /// The value that identifies register X3. 306 | X3, 307 | /// The value that identifies register X4. 308 | X4, 309 | /// The value that identifies register X5. 310 | X5, 311 | /// The value that identifies register X6. 312 | X6, 313 | /// The value that identifies register X7. 314 | X7, 315 | /// The value that identifies register X8. 316 | X8, 317 | /// The value that identifies register X9. 318 | X9, 319 | /// The value that identifies register X10. 320 | X10, 321 | /// The value that identifies register X11. 322 | X11, 323 | /// The value that identifies register X12. 324 | X12, 325 | /// The value that identifies register X13. 326 | X13, 327 | /// The value that identifies register X14. 328 | X14, 329 | /// The value that identifies register X15. 330 | X15, 331 | /// The value that identifies register X16. 332 | X16, 333 | /// The value that identifies register X17. 334 | X17, 335 | /// The value that identifies register X18. 336 | X18, 337 | /// The value that identifies register X19. 338 | X19, 339 | /// The value that identifies register X20. 340 | X20, 341 | /// The value that identifies register X21. 342 | X21, 343 | /// The value that identifies register X22. 344 | X22, 345 | /// The value that identifies register X23. 346 | X23, 347 | /// The value that identifies register X24. 348 | X24, 349 | /// The value that identifies register X25. 350 | X25, 351 | /// The value that identifies register X26. 352 | X26, 353 | /// The value that identifies register X27. 354 | X27, 355 | /// The value that identifies register X28. 356 | X28, 357 | /// The value that identifies register X29. 358 | X29, 359 | /// The value that identifies register X30. 360 | X30, 361 | /// The value that identifies the program counter (PC). 362 | PC, 363 | /// The value that identifies the floating-point control register (FPCR). 364 | FPCR, 365 | /// The value that identifies the floating-point status register (FPSR). 366 | FPSR, 367 | /// The value that identifies the current program status register (CPSR). 368 | CPSR, 369 | ); 370 | 371 | impl Reg { 372 | /// The value that identifies the frame pointer (FP). 373 | pub const FP: Self = Self::X29; 374 | /// The value that identifies the link register (LR). 375 | pub const LR: Self = Self::X30; 376 | } 377 | 378 | gen_enum!( 379 | /// The type that defines SIMD and floating-point registers. 380 | SimdFpReg, 381 | hv_simd_fp_reg_t, 382 | HV_SIMD_FP_REG_, 383 | /// The value representing SIMD register Q0. 384 | Q0, 385 | /// The value representing SIMD register Q1. 386 | Q1, 387 | /// The value representing SIMD register Q2. 388 | Q2, 389 | /// The value representing SIMD register Q3. 390 | Q3, 391 | /// The value representing SIMD register Q4. 392 | Q4, 393 | /// The value representing SIMD register Q5. 394 | Q5, 395 | /// The value representing SIMD register Q6. 396 | Q6, 397 | /// The value representing SIMD register Q7. 398 | Q7, 399 | /// The value representing SIMD register Q8. 400 | Q8, 401 | /// The value representing SIMD register Q9. 402 | Q9, 403 | /// The value representing SIMD register Q10. 404 | Q10, 405 | /// The value representing SIMD register Q11. 406 | Q11, 407 | /// The value representing SIMD register Q12. 408 | Q12, 409 | /// The value representing SIMD register Q13. 410 | Q13, 411 | /// The value representing SIMD register Q14. 412 | Q14, 413 | /// The value representing SIMD register Q15. 414 | Q15, 415 | /// The value representing SIMD register Q16. 416 | Q16, 417 | /// The value representing SIMD register Q17. 418 | Q17, 419 | /// The value representing SIMD register Q18. 420 | Q18, 421 | /// The value representing SIMD register Q19. 422 | Q19, 423 | /// The value representing SIMD register Q20. 424 | Q20, 425 | /// The value representing SIMD register Q21. 426 | Q21, 427 | /// The value representing SIMD register Q22. 428 | Q22, 429 | /// The value representing SIMD register Q23. 430 | Q23, 431 | /// The value representing SIMD register Q24. 432 | Q24, 433 | /// The value representing SIMD register Q25. 434 | Q25, 435 | /// The value representing SIMD register Q26. 436 | Q26, 437 | /// The value representing SIMD register Q27. 438 | Q27, 439 | /// The value representing SIMD register Q28. 440 | Q28, 441 | /// The value representing SIMD register Q29. 442 | Q29, 443 | /// The value representing SIMD register Q30. 444 | Q30, 445 | /// The value representing SIMD register Q31. 446 | Q31, 447 | ); 448 | 449 | gen_enum!( 450 | /// The type of system registers. 451 | SysReg, 452 | hv_sys_reg_t, 453 | HV_SYS_REG_, 454 | /// The value that represents the system register DBGBVR0_EL1. 455 | DBGBVR0_EL1, 456 | /// The value that represents the system register DBGBCR0_EL1. 457 | DBGBCR0_EL1, 458 | /// The value that represents the system register DBGWVR0_EL1. 459 | DBGWVR0_EL1, 460 | /// The value that represents the system register DBGWCR0_EL1. 461 | DBGWCR0_EL1, 462 | /// The value that represents the system register DBGBVR1_EL1. 463 | DBGBVR1_EL1, 464 | /// The value that represents the system register DBGBCR1_EL1. 465 | DBGBCR1_EL1, 466 | /// The value that represents the system register DBGWVR1_EL1. 467 | DBGWVR1_EL1, 468 | /// The value that represents the system register DBGWCR1_EL1. 469 | DBGWCR1_EL1, 470 | /// The value that represents the system register MDCCINT_EL1. 471 | MDCCINT_EL1, 472 | /// The value that represents the system register MDSCR_EL1. 473 | MDSCR_EL1, 474 | /// The value that represents the system register DBGBVR2_EL1. 475 | DBGBVR2_EL1, 476 | /// The value that represents the system register DBGBCR2_EL1. 477 | DBGBCR2_EL1, 478 | /// The value that represents the system register DBGWVR2_EL1. 479 | DBGWVR2_EL1, 480 | /// The value that represents the system register DBGWCR2_EL1. 481 | DBGWCR2_EL1, 482 | /// The value that represents the system register DBGBVR3_EL1. 483 | DBGBVR3_EL1, 484 | /// The value that represents the system register DBGBCR3_EL1. 485 | DBGBCR3_EL1, 486 | /// The value that represents the system register DBGWVR3_EL1. 487 | DBGWVR3_EL1, 488 | /// The value that represents the system register DBGWCR3_EL1. 489 | DBGWCR3_EL1, 490 | /// The value that represents the system register DBGBVR4_EL1. 491 | DBGBVR4_EL1, 492 | /// The value that represents the system register DBGBCR4_EL1. 493 | DBGBCR4_EL1, 494 | /// The value that represents the system register DBGWVR4_EL1. 495 | DBGWVR4_EL1, 496 | /// The value that represents the system register DBGWCR4_EL1. 497 | DBGWCR4_EL1, 498 | /// The value that represents the system register DBGBVR5_EL1. 499 | DBGBVR5_EL1, 500 | /// The value that represents the system register DBGBCR5_EL1. 501 | DBGBCR5_EL1, 502 | /// The value that represents the system register DBGWVR5_EL1. 503 | DBGWVR5_EL1, 504 | /// The value that represents the system register DBGWCR5_EL1. 505 | DBGWCR5_EL1, 506 | /// The value that represents the system register DBGBVR6_EL1. 507 | DBGBVR6_EL1, 508 | /// The value that represents the system register DBGBCR6_EL1. 509 | DBGBCR6_EL1, 510 | /// The value that represents the system register DBGWVR6_EL1. 511 | DBGWVR6_EL1, 512 | /// The value that represents the system register DBGWCR6_EL1. 513 | DBGWCR6_EL1, 514 | /// The value that represents the system register DBGBVR7_EL1. 515 | DBGBVR7_EL1, 516 | /// The value that represents the system register DBGBCR7_EL1. 517 | DBGBCR7_EL1, 518 | /// The value that represents the system register DBGWVR7_EL1. 519 | DBGWVR7_EL1, 520 | /// The value that represents the system register DBGWCR7_EL1. 521 | DBGWCR7_EL1, 522 | /// The value that represents the system register DBGBVR8_EL1. 523 | DBGBVR8_EL1, 524 | /// The value that represents the system register DBGBCR8_EL1. 525 | DBGBCR8_EL1, 526 | /// The value that represents the system register DBGWVR8_EL1. 527 | DBGWVR8_EL1, 528 | /// The value that represents the system register DBGWCR8_EL1. 529 | DBGWCR8_EL1, 530 | /// The value that represents the system register DBGBVR9_EL1. 531 | DBGBVR9_EL1, 532 | /// The value that represents the system register DBGBCR9_EL1. 533 | DBGBCR9_EL1, 534 | /// The value that represents the system register DBGWVR9_EL1. 535 | DBGWVR9_EL1, 536 | /// The value that represents the system register DBGWCR9_EL1. 537 | DBGWCR9_EL1, 538 | /// The value that represents the system register DBGBVR10_EL1. 539 | DBGBVR10_EL1, 540 | /// The value that represents the system register DBGBCR10_EL1. 541 | DBGBCR10_EL1, 542 | /// The value that represents the system register DBGWVR10_EL1. 543 | DBGWVR10_EL1, 544 | /// The value that represents the system register DBGWCR10_EL1. 545 | DBGWCR10_EL1, 546 | /// The value that represents the system register DBGBVR11_EL1. 547 | DBGBVR11_EL1, 548 | /// The value that represents the system register DBGBCR11_EL1. 549 | DBGBCR11_EL1, 550 | /// The value that represents the system register DBGWVR11_EL1. 551 | DBGWVR11_EL1, 552 | /// The value that represents the system register DBGWCR11_EL1. 553 | DBGWCR11_EL1, 554 | /// The value that represents the system register DBGBVR12_EL1. 555 | DBGBVR12_EL1, 556 | /// The value that represents the system register DBGBCR12_EL1. 557 | DBGBCR12_EL1, 558 | /// The value that represents the system register DBGWVR12_EL1. 559 | DBGWVR12_EL1, 560 | /// The value that represents the system register DBGWCR12_EL1. 561 | DBGWCR12_EL1, 562 | /// The value that represents the system register DBGBVR13_EL1. 563 | DBGBVR13_EL1, 564 | /// The value that represents the system register DBGBCR13_EL1. 565 | DBGBCR13_EL1, 566 | /// The value that represents the system register DBGWVR13_EL1. 567 | DBGWVR13_EL1, 568 | /// The value that represents the system register DBGWCR13_EL1. 569 | DBGWCR13_EL1, 570 | /// The value that represents the system register DBGBVR14_EL1. 571 | DBGBVR14_EL1, 572 | /// The value that represents the system register DBGBCR14_EL1. 573 | DBGBCR14_EL1, 574 | /// The value that represents the system register DBGWVR14_EL1. 575 | DBGWVR14_EL1, 576 | /// The value that represents the system register DBGWCR14_EL1. 577 | DBGWCR14_EL1, 578 | /// The value that represents the system register DBGBVR15_EL1. 579 | DBGBVR15_EL1, 580 | /// The value that represents the system register DBGBCR15_EL1. 581 | DBGBCR15_EL1, 582 | /// The value that represents the system register DBGWVR15_EL1. 583 | DBGWVR15_EL1, 584 | /// The value that represents the system register DBGWCR15_EL1. 585 | DBGWCR15_EL1, 586 | /// The value that represents the system register MIDR_EL1. 587 | MIDR_EL1, 588 | /// The value that represents the system register MPIDR_EL1. 589 | MPIDR_EL1, 590 | /// The value that describes the AArch64 Processor Feature Register 0. 591 | ID_AA64PFR0_EL1, 592 | /// The value that describes the AArch64 Processor Feature Register 1. 593 | ID_AA64PFR1_EL1, 594 | /// The value that describes the AArch64 Debug Feature Register 0. 595 | ID_AA64DFR0_EL1, 596 | /// The value that describes the AArch64 Debug Feature Register 1. 597 | ID_AA64DFR1_EL1, 598 | /// The value that describes the AArch64 Instruction Set Attribute Register 0. 599 | ID_AA64ISAR0_EL1, 600 | /// The value that describes the AArch64 Instruction Set Attribute Register 1. 601 | ID_AA64ISAR1_EL1, 602 | /// The value that describes the AArch64 Memory Model Feature Register 0. 603 | ID_AA64MMFR0_EL1, 604 | /// The value that describes the AArch64 Memory Model Feature Register 1. 605 | ID_AA64MMFR1_EL1, 606 | /// The value that describes the AArch64 Memory Model Feature Register 2. 607 | ID_AA64MMFR2_EL1, 608 | /// The value that represents the system register SCTLR_EL1. 609 | SCTLR_EL1, 610 | /// The value that represents the system register CPACR_EL1. 611 | CPACR_EL1, 612 | /// The value that represents the system register TTBR0_EL1. 613 | TTBR0_EL1, 614 | /// The value that represents the system register TTBR1_EL1. 615 | TTBR1_EL1, 616 | /// The value that represents the system register TCR_EL1. 617 | TCR_EL1, 618 | /// The value that represents the system register APIAKEYLO_EL1. 619 | APIAKEYLO_EL1, 620 | /// The value that represents the system register APIAKEYHI_EL1. 621 | APIAKEYHI_EL1, 622 | /// The value that represents the system register APIBKEYLO_EL1. 623 | APIBKEYLO_EL1, 624 | /// The value that represents the system register APIBKEYHI_EL1. 625 | APIBKEYHI_EL1, 626 | /// The value that represents the system register APDAKEYLO_EL1. 627 | APDAKEYLO_EL1, 628 | /// The value that represents the system register APDAKEYHI_EL1. 629 | APDAKEYHI_EL1, 630 | /// The value that represents the system register APDBKEYLO_EL1. 631 | APDBKEYLO_EL1, 632 | /// The value that represents the system register APDBKEYHI_EL1. 633 | APDBKEYHI_EL1, 634 | /// The value that represents the system register APGAKEYLO_EL1. 635 | APGAKEYLO_EL1, 636 | /// The value that represents the system register APGAKEYHI_EL1. 637 | APGAKEYHI_EL1, 638 | /// The value that represents the system register SPSR_EL1. 639 | SPSR_EL1, 640 | /// The value that represents the system register ELR_EL1. 641 | ELR_EL1, 642 | /// The value that represents the system register SP_EL0. 643 | SP_EL0, 644 | /// The value that represents the system register AFSR0_EL1. 645 | AFSR0_EL1, 646 | /// The value that represents the system register AFSR1_EL1. 647 | AFSR1_EL1, 648 | /// The value that represents the system register ESR_EL1. 649 | ESR_EL1, 650 | /// The value that represents the system register FAR_EL1. 651 | FAR_EL1, 652 | /// The value that represents the system register PAR_EL1. 653 | PAR_EL1, 654 | /// The value that represents the system register MAIR_EL1. 655 | MAIR_EL1, 656 | /// The value that represents the system register AMAIR_EL1. 657 | AMAIR_EL1, 658 | /// The value that represents the system register VBAR_EL1. 659 | VBAR_EL1, 660 | /// The value that represents the system register CONTEXTIDR_EL1. 661 | CONTEXTIDR_EL1, 662 | /// The value that represents the system register TPIDR_EL1. 663 | TPIDR_EL1, 664 | /// The value that represents the system register CNTKCTL_EL1. 665 | CNTKCTL_EL1, 666 | /// The value that represents the system register CSSELR_EL1. 667 | CSSELR_EL1, 668 | /// The value that represents the system register TPIDR_EL0. 669 | TPIDR_EL0, 670 | /// The value that represents the system register TPIDRRO_EL0. 671 | TPIDRRO_EL0, 672 | /// The value that represents the system register CNTV_CTL_EL0. 673 | CNTV_CTL_EL0, 674 | /// The value that represents the system register CNTV_CVAL_EL0. 675 | CNTV_CVAL_EL0, 676 | /// The value that represents the system register SP_EL1. 677 | SP_EL1, 678 | ); 679 | 680 | // ----------------------------------------------------------------------------------------------- 681 | // Errors 682 | // ----------------------------------------------------------------------------------------------- 683 | 684 | /// Convenient Result type for hypervisor errors. 685 | pub type Result = core::result::Result; 686 | 687 | /// The error type for hypervisor errors. 688 | #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] 689 | pub enum HypervisorError { 690 | /// A bad argument was provided to the function called. 691 | BadArgument, 692 | /// The owning resource is busy. 693 | Busy, 694 | /// The operation was denied by the system. 695 | Denied, 696 | /// The operation was unsuccessful. 697 | Error, 698 | /// An hypervisor fault occured. 699 | Fault, 700 | /// The guest is in an illegal state. 701 | IllegalState, 702 | /// No VM or vCPU available. 703 | NoDevice, 704 | /// No host resources available to complete the request. 705 | NoResources, 706 | /// An unknown error type. 707 | Unknown(hv_return_t), 708 | /// The operation is not supported. 709 | Unsupported, 710 | } 711 | 712 | impl HypervisorError { 713 | /// Returns a description for a given hypervisor error. 714 | pub(crate) fn as_str(&self) -> &'static str { 715 | match self { 716 | Self::BadArgument => "function call has an invalid argument", 717 | Self::Busy => "owning resource is busy", 718 | Self::Denied => "operation not allowed by the system", 719 | Self::Error => "operation unsuccessful", 720 | Self::Fault => "hypervisor fault", 721 | Self::IllegalState => "guest in an illegal state", 722 | Self::NoDevice => "no VM or vCPU available", 723 | Self::NoResources => "no host resources available to complete the request", 724 | Self::Unknown(_) => "unknown error", 725 | Self::Unsupported => "unsupported operation", 726 | } 727 | } 728 | } 729 | 730 | impl From for HypervisorError { 731 | fn from(code: hv_return_t) -> Self { 732 | match code { 733 | x if x == hv_error_t::HV_BAD_ARGUMENT as hv_return_t => Self::BadArgument, 734 | x if x == hv_error_t::HV_BUSY as hv_return_t => Self::Busy, 735 | x if x == hv_error_t::HV_DENIED as hv_return_t => Self::Denied, 736 | x if x == hv_error_t::HV_ERROR as hv_return_t => Self::Error, 737 | x if x == hv_error_t::HV_FAULT as hv_return_t => Self::Fault, 738 | x if x == hv_error_t::HV_ILLEGAL_GUEST_STATE as hv_return_t => Self::IllegalState, 739 | x if x == hv_error_t::HV_NO_DEVICE as hv_return_t => Self::NoDevice, 740 | x if x == hv_error_t::HV_NO_RESOURCES as hv_return_t => Self::NoResources, 741 | x if x == hv_error_t::HV_UNSUPPORTED as hv_return_t => Self::Unsupported, 742 | _ => Self::Unknown(code), 743 | } 744 | } 745 | } 746 | 747 | #[allow(clippy::from_over_into)] 748 | impl Into for HypervisorError { 749 | fn into(self) -> hv_return_t { 750 | match self { 751 | Self::BadArgument => hv_error_t::HV_BAD_ARGUMENT as hv_return_t, 752 | Self::Busy => hv_error_t::HV_BUSY as hv_return_t, 753 | Self::Denied => hv_error_t::HV_DENIED as hv_return_t, 754 | Self::Error => hv_error_t::HV_ERROR as hv_return_t, 755 | Self::Fault => hv_error_t::HV_FAULT as hv_return_t, 756 | Self::IllegalState => hv_error_t::HV_ILLEGAL_GUEST_STATE as hv_return_t, 757 | Self::NoDevice => hv_error_t::HV_NO_DEVICE as hv_return_t, 758 | Self::NoResources => hv_error_t::HV_NO_RESOURCES as hv_return_t, 759 | Self::Unsupported => hv_error_t::HV_UNSUPPORTED as hv_return_t, 760 | Self::Unknown(code) => code, 761 | } 762 | } 763 | } 764 | 765 | impl std::error::Error for HypervisorError {} 766 | 767 | impl core::fmt::Display for HypervisorError { 768 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 769 | write!( 770 | f, 771 | "{} (error {:#08x})", 772 | self.as_str(), 773 | Into::::into(*self) 774 | ) 775 | } 776 | } 777 | 778 | impl core::fmt::Debug for HypervisorError { 779 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 780 | f.debug_struct("HypervisorError") 781 | .field("code", &Into::::into(*self)) 782 | .field("description", &self.as_str()) 783 | .finish() 784 | } 785 | } 786 | 787 | // ----------------------------------------------------------------------------------------------- 788 | // Virtual Machine 789 | // ----------------------------------------------------------------------------------------------- 790 | 791 | unsafe impl Sync for VirtualMachine {} 792 | 793 | /// Represents the unique virtual machine instance of the current process. 794 | #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] 795 | pub struct VirtualMachine { 796 | /// The virtual machine configuration. 797 | config: hv_vm_config_t, 798 | } 799 | 800 | impl VirtualMachine { 801 | /// Creates a new virtual machine instance for the current process. 802 | pub fn new() -> Result { 803 | let config = ptr::null_mut(); 804 | hv_unsafe_call!(hv_vm_create(config))?; 805 | Ok(Self { config }) 806 | } 807 | } 808 | 809 | /// Destroys the virtual machine context of the current process. 810 | /// 811 | /// Panics if it can't be destroyed. 812 | impl core::ops::Drop for VirtualMachine { 813 | fn drop(&mut self) { 814 | hv_unsafe_call!(hv_vm_destroy()).expect("Could not properly destroy VM context"); 815 | } 816 | } 817 | 818 | // ----------------------------------------------------------------------------------------------- 819 | // Memory Management 820 | // ----------------------------------------------------------------------------------------------- 821 | 822 | /// Represents the access permissions of a memory range. 823 | #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] 824 | pub enum MemPerms { 825 | /// No permssion. 826 | None, 827 | /// Read permission. 828 | Read, 829 | /// Write permission. 830 | Write, 831 | /// Execute permission. 832 | Exec, 833 | /// Read and write permissions. 834 | ReadWrite, 835 | /// Read and execute permissions. 836 | ReadExec, 837 | /// Write and execute permissions. 838 | WriteExec, 839 | /// Read, write and execute permissions. 840 | ReadWriteExec, 841 | } 842 | 843 | /// Permissions aliases. 844 | impl MemPerms { 845 | /// Read permission alias. 846 | pub const R: Self = Self::Read; 847 | /// Write permission alias. 848 | pub const W: Self = Self::Write; 849 | /// Execute permission alias. 850 | pub const X: Self = Self::Exec; 851 | /// Read and write permissions alias. 852 | pub const RW: Self = Self::ReadWrite; 853 | /// Read and execute permissions alias. 854 | pub const RX: Self = Self::ReadExec; 855 | /// Write and execute permissions alias. 856 | pub const WX: Self = Self::WriteExec; 857 | /// Read, write and execute permissions alias. 858 | pub const RWX: Self = Self::ReadWriteExec; 859 | } 860 | 861 | #[allow(clippy::from_over_into)] 862 | impl Into for MemPerms { 863 | fn into(self) -> hv_memory_flags_t { 864 | match self { 865 | Self::None => 0, 866 | Self::R => HV_MEMORY_READ, 867 | Self::W => HV_MEMORY_WRITE, 868 | Self::X => HV_MEMORY_EXEC, 869 | Self::RW => HV_MEMORY_READ | HV_MEMORY_WRITE, 870 | Self::RX => HV_MEMORY_READ | HV_MEMORY_EXEC, 871 | Self::WX => HV_MEMORY_WRITE | HV_MEMORY_EXEC, 872 | Self::RWX => HV_MEMORY_READ | HV_MEMORY_WRITE | HV_MEMORY_EXEC, 873 | } 874 | } 875 | } 876 | 877 | impl core::fmt::Display for MemPerms { 878 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 879 | let perms = match *self { 880 | MemPerms::None => "---", 881 | MemPerms::R => "R--", 882 | MemPerms::W => "-W-", 883 | MemPerms::X => "--X", 884 | MemPerms::RW => "RW-", 885 | MemPerms::RX => "R-X", 886 | MemPerms::WX => "-WX", 887 | MemPerms::RWX => "RWX", 888 | }; 889 | write!(f, "{}", perms) 890 | } 891 | } 892 | 893 | impl std::ops::BitOr for MemPerms { 894 | type Output = Self; 895 | 896 | fn bitor(self, rhs: Self) -> Self::Output { 897 | let raw = Into::::into(self); 898 | let rhs_raw = Into::::into(rhs); 899 | match raw | rhs_raw { 900 | x if x == HV_MEMORY_READ => Self::R, 901 | x if x == HV_MEMORY_WRITE => Self::W, 902 | x if x == HV_MEMORY_EXEC => Self::X, 903 | x if x == HV_MEMORY_READ | HV_MEMORY_WRITE => Self::RW, 904 | x if x == HV_MEMORY_READ | HV_MEMORY_EXEC => Self::RX, 905 | x if x == HV_MEMORY_WRITE | HV_MEMORY_EXEC => Self::WX, 906 | x if x == HV_MEMORY_READ | HV_MEMORY_WRITE | HV_MEMORY_EXEC => Self::RWX, 907 | _ => Self::None, 908 | } 909 | } 910 | } 911 | 912 | /// The size of a memory page on Apple Silicon. 913 | pub const PAGE_SIZE: usize = 0x4000; 914 | 915 | /// Represents a host memory allocation. 916 | #[derive(Clone, Debug, Eq)] 917 | pub(crate) struct MemAlloc { 918 | /// Host address. 919 | addr: *const c_void, 920 | /// Memory layout associated with `addr`. 921 | layout: alloc::Layout, 922 | /// Allocation size. 923 | size: usize, 924 | } 925 | 926 | impl MemAlloc { 927 | /// Creates a new memory allocation for the host using [`std::alloc`]. 928 | pub(crate) fn new(size: usize) -> std::result::Result { 929 | let layout = alloc::Layout::from_size_align(size, PAGE_SIZE)?.pad_to_align(); 930 | let addr = unsafe { alloc::alloc_zeroed(layout) } as *const c_void; 931 | Ok(MemAlloc { 932 | addr, 933 | layout, 934 | size: layout.size(), 935 | }) 936 | } 937 | } 938 | 939 | impl PartialEq for MemAlloc { 940 | fn eq(&self, other: &Self) -> bool { 941 | self.addr == other.addr && self.size == other.size 942 | } 943 | } 944 | 945 | impl Hash for MemAlloc { 946 | fn hash(&self, state: &mut H) { 947 | self.addr.hash(state); 948 | self.size.hash(state); 949 | } 950 | } 951 | 952 | impl std::ops::Drop for MemAlloc { 953 | fn drop(&mut self) { 954 | unsafe { alloc::dealloc(self.addr as *mut u8, self.layout) } 955 | } 956 | } 957 | 958 | /// Represents a memory mapping between a host-allocated memory range and the one that 959 | /// corresponds in the hypervisor guest. 960 | #[derive(Clone, Debug, Hash, Eq, PartialEq)] 961 | pub struct MappingInner { 962 | host_alloc: MemAlloc, 963 | guest_addr: Option, 964 | size: usize, 965 | perms: MemPerms, 966 | } 967 | 968 | /// Represents a memory range exclusive to a single thread. 969 | /// 970 | /// **Note:** a memory mapping is available to all vCPU running in a given VM instance, but only 971 | /// one vCPU-owning thread can access it. 972 | #[derive(Clone, Debug, Hash, Eq, PartialEq)] 973 | pub struct Mapping { 974 | inner: MappingInner, 975 | } 976 | 977 | impl Mappable for Mapping { 978 | fn new(size: usize) -> std::result::Result { 979 | let host_alloc = MemAlloc::new(size)?; 980 | Ok(Self { 981 | inner: MappingInner { 982 | host_alloc, 983 | guest_addr: None, 984 | size, 985 | perms: MemPerms::None, 986 | }, 987 | }) 988 | } 989 | 990 | fn map(&mut self, guest_addr: u64, perms: MemPerms) -> Result<()> { 991 | Self::map_inner(&mut self.inner, guest_addr, perms) 992 | } 993 | 994 | fn unmap(&mut self) -> Result<()> { 995 | Self::unmap_inner(&mut self.inner) 996 | } 997 | 998 | fn protect(&mut self, perms: MemPerms) -> Result<()> { 999 | Self::protect_inner(&mut self.inner, perms) 1000 | } 1001 | 1002 | fn read(&self, guest_addr: u64, data: &mut [u8]) -> Result { 1003 | Self::read_inner(&self.inner, guest_addr, data) 1004 | } 1005 | 1006 | fn write(&mut self, guest_addr: u64, data: &[u8]) -> Result { 1007 | Self::write_inner(&mut self.inner, guest_addr, data) 1008 | } 1009 | 1010 | fn get_host_addr(&self) -> *const u8 { 1011 | self.inner.host_alloc.addr as *const u8 1012 | } 1013 | 1014 | fn get_guest_addr(&self) -> Option { 1015 | self.inner.guest_addr 1016 | } 1017 | 1018 | fn get_size(&self) -> usize { 1019 | self.inner.size 1020 | } 1021 | } 1022 | 1023 | impl std::ops::Drop for Mapping { 1024 | fn drop(&mut self) { 1025 | let _ = self.unmap(); 1026 | } 1027 | } 1028 | 1029 | /// Represents a memory range shared among multiple threads. 1030 | /// 1031 | /// **Note:** a memory mapping is available to all vCPU running in a given VM instance, but any 1032 | /// vCPU-owning thread with a reference to this mapping can access it. 1033 | #[derive(Clone, Debug)] 1034 | pub struct MappingShared { 1035 | inner: Arc>, 1036 | } 1037 | 1038 | unsafe impl Send for MappingShared {} 1039 | 1040 | impl PartialEq for MappingShared { 1041 | fn eq(&self, other: &Self) -> bool { 1042 | Arc::ptr_eq(&self.inner, &other.inner) 1043 | } 1044 | } 1045 | 1046 | impl Mappable for MappingShared { 1047 | fn new(size: usize) -> std::result::Result { 1048 | let host_alloc = MemAlloc::new(size)?; 1049 | Ok(Self { 1050 | inner: Arc::new(RwLock::new(MappingInner { 1051 | host_alloc, 1052 | guest_addr: None, 1053 | size, 1054 | perms: MemPerms::None, 1055 | })), 1056 | }) 1057 | } 1058 | 1059 | fn map(&mut self, guest_addr: u64, perms: MemPerms) -> Result<()> { 1060 | let mut inner = self.inner.write().unwrap(); 1061 | Self::map_inner(&mut inner, guest_addr, perms) 1062 | } 1063 | 1064 | fn unmap(&mut self) -> Result<()> { 1065 | let mut inner = self.inner.write().unwrap(); 1066 | Self::unmap_inner(&mut inner) 1067 | } 1068 | 1069 | fn protect(&mut self, perms: MemPerms) -> Result<()> { 1070 | let mut inner = self.inner.write().unwrap(); 1071 | Self::protect_inner(&mut inner, perms) 1072 | } 1073 | 1074 | fn read(&self, guest_addr: u64, data: &mut [u8]) -> Result { 1075 | let inner = self.inner.read().unwrap(); 1076 | Self::read_inner(&inner, guest_addr, data) 1077 | } 1078 | 1079 | fn write(&mut self, guest_addr: u64, data: &[u8]) -> Result { 1080 | let mut inner = self.inner.write().unwrap(); 1081 | Self::write_inner(&mut inner, guest_addr, data) 1082 | } 1083 | 1084 | fn get_host_addr(&self) -> *const u8 { 1085 | self.inner.read().unwrap().host_alloc.addr as *const u8 1086 | } 1087 | 1088 | fn get_guest_addr(&self) -> Option { 1089 | self.inner.read().unwrap().guest_addr 1090 | } 1091 | 1092 | fn get_size(&self) -> usize { 1093 | self.inner.read().unwrap().size 1094 | } 1095 | } 1096 | 1097 | impl Hash for MappingShared { 1098 | fn hash(&self, state: &mut H) { 1099 | let inner = self.inner.read().unwrap(); 1100 | inner.hash(state); 1101 | } 1102 | } 1103 | 1104 | impl std::ops::Drop for MappingShared { 1105 | fn drop(&mut self) { 1106 | let _ = self.unmap(); 1107 | } 1108 | } 1109 | 1110 | pub trait Mappable { 1111 | /// Creates a new allocation object. 1112 | fn new(size: usize) -> std::result::Result 1113 | where 1114 | Self: Sized; 1115 | 1116 | /// Maps the host allocation in the guest. 1117 | fn map(&mut self, guest_addr: u64, perms: MemPerms) -> Result<()>; 1118 | 1119 | /// Maps the host allocation in the guest. 1120 | fn unmap(&mut self) -> Result<()>; 1121 | 1122 | /// Changes the protections of memory mapping in the guest. 1123 | fn protect(&mut self, perms: MemPerms) -> Result<()>; 1124 | 1125 | /// Reads from a memory mapping in the guest at address `guest_addr`. 1126 | fn read(&self, guest_addr: u64, data: &mut [u8]) -> Result; 1127 | 1128 | /// Writes to a memory mapping in the guest at address `guest_addr`. 1129 | fn write(&mut self, guest_addr: u64, data: &[u8]) -> Result; 1130 | 1131 | /// Retrieves the memory mapping's host address. 1132 | fn get_host_addr(&self) -> *const u8; 1133 | 1134 | /// Retrieves the memory mapping's guest address. 1135 | fn get_guest_addr(&self) -> Option; 1136 | 1137 | /// Retrieves the memory mapping's size. 1138 | fn get_size(&self) -> usize; 1139 | 1140 | /// Underlying memory mapping function. 1141 | fn map_inner(inner: &mut MappingInner, guest_addr: u64, perms: MemPerms) -> Result<()> 1142 | where 1143 | Self: Sized, 1144 | { 1145 | // Returns if the mapping is already mapped. 1146 | if inner.guest_addr.is_some() { 1147 | return Err(HypervisorError::Busy); 1148 | } 1149 | // Maps the mapping in the guest. 1150 | hv_unsafe_call!(hv_vm_map( 1151 | inner.host_alloc.addr, 1152 | guest_addr, 1153 | inner.host_alloc.size, 1154 | Into::::into(perms) 1155 | ))?; 1156 | // Updates the inner mapping. 1157 | inner.guest_addr = Some(guest_addr); 1158 | inner.perms = perms; 1159 | Ok(()) 1160 | } 1161 | 1162 | /// Underlying memory unmapping function. 1163 | fn unmap_inner(inner: &mut MappingInner) -> Result<()> 1164 | where 1165 | Self: Sized, 1166 | { 1167 | // Returns if the mapping is not mapped. 1168 | let guest_addr = inner.guest_addr.ok_or(HypervisorError::Error)?; 1169 | // Unmaps the mapping from the guest. 1170 | hv_unsafe_call!(hv_vm_unmap(guest_addr, inner.host_alloc.size))?; 1171 | // Updates the inner mapping. 1172 | inner.guest_addr = None; 1173 | Ok(()) 1174 | } 1175 | 1176 | /// Underlying memory protection function. 1177 | fn protect_inner(inner: &mut MappingInner, perms: MemPerms) -> Result<()> 1178 | where 1179 | Self: Sized, 1180 | { 1181 | // Returns if the mapping is not mapped. 1182 | let guest_addr = inner.guest_addr.ok_or(HypervisorError::Error)?; 1183 | // Changes the guest mapping's protections. 1184 | hv_unsafe_call!(hv_vm_protect( 1185 | guest_addr, 1186 | inner.host_alloc.size, 1187 | Into::::into(perms) 1188 | ))?; 1189 | // Updates the inner mapping. 1190 | inner.perms = perms; 1191 | Ok(()) 1192 | } 1193 | 1194 | /// Underlying memory read function. 1195 | fn read_inner(inner: &MappingInner, guest_addr: u64, data: &mut [u8]) -> Result 1196 | where 1197 | Self: Sized, 1198 | { 1199 | // Returns if the mapping is not mapped. 1200 | let inner_guest_addr = inner.guest_addr.ok_or(HypervisorError::Error)?; 1201 | // Checks the guest addr provided is in the guest memory range. 1202 | let size = data.len(); 1203 | if guest_addr < inner_guest_addr 1204 | || guest_addr.checked_add(size as u64).unwrap() 1205 | > inner_guest_addr 1206 | .checked_add(inner.host_alloc.size as u64) 1207 | .unwrap() 1208 | { 1209 | return Err(HypervisorError::BadArgument); 1210 | } 1211 | // Computes the corresponding host address. 1212 | let offset = guest_addr - inner_guest_addr; 1213 | let host_addr = inner.host_alloc.addr as u64 + offset; 1214 | // Copies data from the memory mapping into the slice. 1215 | unsafe { 1216 | ptr::copy( 1217 | host_addr as *const c_void, 1218 | data.as_mut_ptr() as *mut c_void, 1219 | size, 1220 | ); 1221 | }; 1222 | Ok(size) 1223 | } 1224 | 1225 | /// Reads one byte at address `guest_addr`. 1226 | #[inline] 1227 | fn read_byte(&self, guest_addr: u64) -> Result { 1228 | let mut data = [0; 1]; 1229 | assert_eq!(self.read(guest_addr, &mut data)?, 1); 1230 | Ok(data[0]) 1231 | } 1232 | 1233 | /// Reads one word at address `guest_addr`. 1234 | #[inline] 1235 | fn read_word(&self, guest_addr: u64) -> Result { 1236 | let mut data = [0; 2]; 1237 | assert_eq!(self.read(guest_addr, &mut data)?, 2); 1238 | Ok(u16::from_le_bytes(data[..2].try_into().unwrap())) 1239 | } 1240 | 1241 | /// Reads one dword at address `guest_addr`. 1242 | #[inline] 1243 | fn read_dword(&self, guest_addr: u64) -> Result { 1244 | let mut data = [0; 4]; 1245 | assert_eq!(self.read(guest_addr, &mut data)?, 4); 1246 | Ok(u32::from_le_bytes(data[..4].try_into().unwrap())) 1247 | } 1248 | 1249 | /// Reads one qword at address `guest_addr`. 1250 | #[inline] 1251 | fn read_qword(&self, guest_addr: u64) -> Result { 1252 | let mut data = [0; 8]; 1253 | assert_eq!(self.read(guest_addr, &mut data)?, 8); 1254 | Ok(u64::from_le_bytes(data[..8].try_into().unwrap())) 1255 | } 1256 | 1257 | /// Underlying memory write function. 1258 | fn write_inner(inner: &mut MappingInner, guest_addr: u64, data: &[u8]) -> Result 1259 | where 1260 | Self: Sized, 1261 | { 1262 | let size = data.len(); 1263 | // Returns if the mapping is not mapped. 1264 | let inner_guest_addr = inner.guest_addr.ok_or(HypervisorError::Error)?; 1265 | // Checks the guest addr provided is in the guest memory range. 1266 | if guest_addr < inner_guest_addr 1267 | || guest_addr.checked_add(size as u64).unwrap() 1268 | > inner_guest_addr 1269 | .checked_add(inner.host_alloc.size as u64) 1270 | .unwrap() 1271 | { 1272 | return Err(HypervisorError::BadArgument); 1273 | } 1274 | // Computes the corresponding host address. 1275 | let offset = guest_addr - inner_guest_addr; 1276 | let host_addr = inner.host_alloc.addr as u64 + offset; 1277 | // Copies data from the input vector. 1278 | unsafe { 1279 | ptr::copy( 1280 | data.as_ptr() as *const c_void, 1281 | host_addr as *mut c_void, 1282 | size, 1283 | ); 1284 | }; 1285 | Ok(size) 1286 | } 1287 | 1288 | /// Writes one byte at address `guest_addr`. 1289 | #[inline] 1290 | fn write_byte(&mut self, guest_addr: u64, data: u8) -> Result { 1291 | self.write(guest_addr, &[data]) 1292 | } 1293 | 1294 | /// Writes one word at address `guest_addr`. 1295 | #[inline] 1296 | fn write_word(&mut self, guest_addr: u64, data: u16) -> Result { 1297 | self.write(guest_addr, &data.to_le_bytes()) 1298 | } 1299 | 1300 | /// Writes one dword at address `guest_addr`. 1301 | #[inline] 1302 | fn write_dword(&mut self, guest_addr: u64, data: u32) -> Result { 1303 | self.write(guest_addr, &data.to_le_bytes()) 1304 | } 1305 | 1306 | /// Writes one qword at address `guest_addr`. 1307 | #[inline] 1308 | fn write_qword(&mut self, guest_addr: u64, data: u64) -> Result { 1309 | self.write(guest_addr, &data.to_le_bytes()) 1310 | } 1311 | } 1312 | 1313 | // ----------------------------------------------------------------------------------------------- 1314 | // vCPU Management - Configuration 1315 | // ----------------------------------------------------------------------------------------------- 1316 | 1317 | /// Represents a vCPU configuration. 1318 | #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] 1319 | pub struct VcpuConfig(hv_vcpu_config_t); 1320 | 1321 | impl Default for VcpuConfig { 1322 | fn default() -> Self { 1323 | Self::new() 1324 | } 1325 | } 1326 | 1327 | impl VcpuConfig { 1328 | /// Instanciates a new configuration. 1329 | pub fn new() -> Self { 1330 | let config = unsafe { hv_vcpu_config_create() }; 1331 | VcpuConfig(config) 1332 | } 1333 | 1334 | /// Instanciates a new empty configuration. 1335 | pub fn empty() -> Self { 1336 | VcpuConfig(ptr::null_mut()) 1337 | } 1338 | 1339 | /// Retrieves the value of a feature register. 1340 | pub fn get_feature_reg(&self, reg: FeatureReg) -> Result { 1341 | let mut value = 0; 1342 | hv_unsafe_call!(hv_vcpu_config_get_feature_reg( 1343 | self.0, 1344 | Into::::into(reg), 1345 | &mut value 1346 | ))?; 1347 | Ok(value) 1348 | } 1349 | 1350 | /// Returns the Cache Size ID Register (CCSIDR_EL1) values for the vCPU configuration and 1351 | /// cache type you specify. 1352 | pub fn get_ccsidr_el1_sys_reg_values(&self, cache_type: CacheType) -> Result { 1353 | let mut value = 0; 1354 | hv_unsafe_call!(hv_vcpu_config_get_ccsidr_el1_sys_reg_values( 1355 | self.0, 1356 | Into::::into(cache_type), 1357 | &mut value 1358 | ))?; 1359 | Ok(value) 1360 | } 1361 | } 1362 | 1363 | // ----------------------------------------------------------------------------------------------- 1364 | // vCPU 1365 | // ----------------------------------------------------------------------------------------------- 1366 | 1367 | /// Represents a vCPU instance. 1368 | #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] 1369 | pub struct VcpuInstance(hv_vcpu_t); 1370 | 1371 | pub type VcpuExitException = hv_vcpu_exit_exception_t; 1372 | 1373 | /// Represents vCPU exit info. 1374 | #[derive(Clone, Eq, PartialEq, Debug)] 1375 | pub struct VcpuExit { 1376 | pub reason: ExitReason, 1377 | pub exception: VcpuExitException, 1378 | } 1379 | 1380 | impl From for VcpuExit { 1381 | fn from(exit: hv_vcpu_exit_t) -> Self { 1382 | VcpuExit { 1383 | reason: ExitReason::from(exit.reason), 1384 | exception: exit.exception, 1385 | } 1386 | } 1387 | } 1388 | 1389 | impl std::fmt::Display for VcpuExit { 1390 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 1391 | match self.reason { 1392 | ExitReason::EXCEPTION => { 1393 | writeln!(f, 1394 | "EXCEPTION => [syndrome: {:016x}, virtual addr: {:016x}, physical addr: {:016x}]", 1395 | self.exception.syndrome, self.exception.virtual_address, 1396 | self.exception.physical_address) 1397 | } 1398 | ExitReason::CANCELED => writeln!(f, "CANCELED"), 1399 | ExitReason::VTIMER_ACTIVATED => writeln!(f, "VTIMER_ACTIVATED"), 1400 | ExitReason::UNKNOWN => writeln!(f, "UNKNOWN"), 1401 | } 1402 | } 1403 | } 1404 | 1405 | /// Represents a Virtual CPU. 1406 | #[derive(Clone, Eq, PartialEq, Debug)] 1407 | pub struct Vcpu { 1408 | vcpu: VcpuInstance, 1409 | config: VcpuConfig, 1410 | exit: *const hv_vcpu_exit_t, 1411 | } 1412 | 1413 | impl Vcpu { 1414 | /// Creates a new vCPU. 1415 | pub fn new() -> Result { 1416 | Vcpu::with_config(VcpuConfig::empty()) 1417 | } 1418 | 1419 | /// Creates a new vCPU with a user-provided config. 1420 | pub fn with_config(config: VcpuConfig) -> Result { 1421 | let mut vcpu = VcpuInstance(0); 1422 | let mut exit = ptr::null_mut() as *const hv_vcpu_exit_t; 1423 | hv_unsafe_call!(hv_vcpu_create(&mut vcpu.0, &mut exit, config.0))?; 1424 | Ok(Self { vcpu, exit, config }) 1425 | } 1426 | 1427 | /// Returns the [`VcpuInstance`] associated with the Vcpu. 1428 | pub fn get_instance(&self) -> VcpuInstance { 1429 | self.vcpu 1430 | } 1431 | 1432 | /// Returns the Vcpu ID (the integer associated to the corresponding [`VcpuInstance`]). 1433 | pub fn get_id(&self) -> u64 { 1434 | self.vcpu.0 1435 | } 1436 | 1437 | /// Returns the maximum number of vCPUs that can be created by the hypervisor. 1438 | pub fn get_max_count() -> Result { 1439 | let mut count = 0; 1440 | hv_unsafe_call!(hv_vm_get_max_vcpu_count(&mut count))?; 1441 | Ok(count) 1442 | } 1443 | 1444 | /// Starts the vCPU. 1445 | pub fn run(&self) -> Result<()> { 1446 | hv_unsafe_call!(hv_vcpu_run(self.vcpu.0)) 1447 | } 1448 | 1449 | /// Stops all vCPUs in the input array. 1450 | pub fn stop(vcpus: &[VcpuInstance]) -> Result<()> { 1451 | let vcpus = vcpus.iter().map(|v| v.0).collect::>(); 1452 | hv_unsafe_call!(hv_vcpus_exit(vcpus.as_ptr(), vcpus.len() as u32)) 1453 | } 1454 | 1455 | /// Gets vCPU exit info. 1456 | pub fn get_exit_info(&self) -> VcpuExit { 1457 | VcpuExit::from(unsafe { *self.exit }) 1458 | } 1459 | 1460 | /// Gets pending interrupts for a vCPU. 1461 | pub fn get_pending_interrupt(&self, intr: InterruptType) -> Result { 1462 | let mut pending = false; 1463 | hv_unsafe_call!(hv_vcpu_get_pending_interrupt( 1464 | self.vcpu.0, 1465 | Into::::into(intr), 1466 | &mut pending 1467 | ))?; 1468 | Ok(pending) 1469 | } 1470 | 1471 | /// Sets pending interrupts for a vCPU. 1472 | pub fn set_pending_interrupt(&self, intr: InterruptType, pending: bool) -> Result<()> { 1473 | hv_unsafe_call!(hv_vcpu_set_pending_interrupt( 1474 | self.vcpu.0, 1475 | Into::::into(intr), 1476 | pending 1477 | )) 1478 | } 1479 | 1480 | /// Gets the value of a vCPU general purpose register. 1481 | pub fn get_reg(&self, reg: Reg) -> Result { 1482 | let mut value = 0; 1483 | hv_unsafe_call!(hv_vcpu_get_reg( 1484 | self.vcpu.0, 1485 | Into::::into(reg), 1486 | &mut value 1487 | ))?; 1488 | Ok(value) 1489 | } 1490 | 1491 | /// Sets the value of a vCPU general purpose register. 1492 | pub fn set_reg(&self, reg: Reg, value: u64) -> Result<()> { 1493 | hv_unsafe_call!(hv_vcpu_set_reg( 1494 | self.vcpu.0, 1495 | Into::::into(reg), 1496 | value 1497 | )) 1498 | } 1499 | 1500 | #[cfg(feature = "simd_nightly")] 1501 | /// Gets the value of a vCPU floating point register 1502 | pub fn get_simd_fp_reg(&self, reg: SimdFpReg) -> Result { 1503 | let mut value = simd::i8x16::from_array([0; 16]); 1504 | hv_unsafe_call!(hv_vcpu_get_simd_fp_reg( 1505 | self.vcpu.0, 1506 | Into::::into(reg), 1507 | &mut value 1508 | ))?; 1509 | Ok(value) 1510 | } 1511 | 1512 | #[cfg(feature = "simd_nightly")] 1513 | /// Sets the value of a vCPU floating point register 1514 | pub fn set_simd_fp_reg(&self, reg: SimdFpReg, value: simd::i8x16) -> Result<()> { 1515 | hv_unsafe_call!(hv_vcpu_set_simd_fp_reg( 1516 | self.vcpu.0, 1517 | Into::::into(reg), 1518 | value 1519 | )) 1520 | } 1521 | 1522 | #[cfg(not(feature = "simd_nightly"))] 1523 | /// Gets the value of a vCPU floating point register 1524 | pub fn get_simd_fp_reg(&self, reg: SimdFpReg) -> Result { 1525 | let mut value = 0; 1526 | hv_unsafe_call!(hv_vcpu_get_simd_fp_reg( 1527 | self.vcpu.0, 1528 | Into::::into(reg), 1529 | &mut value 1530 | ))?; 1531 | Ok(value) 1532 | } 1533 | 1534 | #[cfg(not(feature = "simd_nightly"))] 1535 | /// Sets the value of a vCPU floating point register 1536 | pub fn set_simd_fp_reg(&self, reg: SimdFpReg, value: u128) -> Result<()> { 1537 | hv_unsafe_call!(hv_vcpu_set_simd_fp_reg( 1538 | self.vcpu.0, 1539 | Into::::into(reg), 1540 | value 1541 | )) 1542 | } 1543 | 1544 | /// Gets the value of a vCPU system register. 1545 | pub fn get_sys_reg(&self, reg: SysReg) -> Result { 1546 | let mut value = 0; 1547 | hv_unsafe_call!(hv_vcpu_get_sys_reg( 1548 | self.vcpu.0, 1549 | Into::::into(reg), 1550 | &mut value 1551 | ))?; 1552 | Ok(value) 1553 | } 1554 | 1555 | /// Sets the value of a vCPU general purpose register. 1556 | pub fn set_sys_reg(&self, reg: SysReg, value: u64) -> Result<()> { 1557 | hv_unsafe_call!(hv_vcpu_set_sys_reg( 1558 | self.vcpu.0, 1559 | Into::::into(reg), 1560 | value 1561 | )) 1562 | } 1563 | 1564 | /// Gets whether debug exceptions exit the guest. 1565 | pub fn get_trap_debug_exceptions(&self) -> Result { 1566 | let mut value = false; 1567 | hv_unsafe_call!(hv_vcpu_get_trap_debug_exceptions(self.vcpu.0, &mut value))?; 1568 | Ok(value) 1569 | } 1570 | 1571 | /// Sets whether debug exceptions exit the guest. 1572 | pub fn set_trap_debug_exceptions(&self, value: bool) -> Result<()> { 1573 | hv_unsafe_call!(hv_vcpu_set_trap_debug_exceptions(self.vcpu.0, value)) 1574 | } 1575 | 1576 | /// Gets whether debug-register accesses exit the guest. 1577 | pub fn get_trap_debug_reg_accesses(&self) -> Result { 1578 | let mut value = false; 1579 | hv_unsafe_call!(hv_vcpu_get_trap_debug_reg_accesses(self.vcpu.0, &mut value))?; 1580 | Ok(value) 1581 | } 1582 | 1583 | /// Sets whether debug-register accesses exit the guest. 1584 | pub fn set_trap_debug_reg_accesses(&self, value: bool) -> Result<()> { 1585 | hv_unsafe_call!(hv_vcpu_set_trap_debug_reg_accesses(self.vcpu.0, value)) 1586 | } 1587 | 1588 | /// Returns the cumulative execution time of a vCPU, in nanoseconds. 1589 | pub fn get_exec_time(&self) -> Result { 1590 | let mut time = 0; 1591 | hv_unsafe_call!(hv_vcpu_get_exec_time(self.vcpu.0, &mut time))?; 1592 | Ok(time) 1593 | } 1594 | 1595 | /// Gets the virtual timer mask. 1596 | pub fn get_vtimer_mask(&self) -> Result { 1597 | let mut vtimer_is_masked = false; 1598 | hv_unsafe_call!(hv_vcpu_get_vtimer_mask(self.vcpu.0, &mut vtimer_is_masked))?; 1599 | Ok(vtimer_is_masked) 1600 | } 1601 | 1602 | /// Sets or clears the virtual timer mask. 1603 | pub fn set_vtimer_mask(&self, vtimer_is_masked: bool) -> Result<()> { 1604 | hv_unsafe_call!(hv_vcpu_set_vtimer_mask(self.vcpu.0, vtimer_is_masked)) 1605 | } 1606 | 1607 | /// Returns the vTimer offset for the vCPU ID you specify. 1608 | pub fn get_vtimer_offset(&self) -> Result { 1609 | let mut vtimer_offset = 0; 1610 | hv_unsafe_call!(hv_vcpu_get_vtimer_offset(self.vcpu.0, &mut vtimer_offset))?; 1611 | Ok(vtimer_offset) 1612 | } 1613 | 1614 | /// Sets the vTimer offset to a value that you provide. 1615 | pub fn set_vtimer_offset(&self, vtimer_offset: u64) -> Result<()> { 1616 | hv_unsafe_call!(hv_vcpu_set_vtimer_offset(self.vcpu.0, vtimer_offset)) 1617 | } 1618 | } 1619 | 1620 | impl std::ops::Drop for Vcpu { 1621 | fn drop(&mut self) { 1622 | hv_unsafe_call!(hv_vcpu_destroy(self.vcpu.0)) 1623 | .expect("Could not properly destroy vCPU instance"); 1624 | } 1625 | } 1626 | 1627 | impl std::fmt::Display for Vcpu { 1628 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 1629 | writeln!(f, "EL0:")?; 1630 | writeln!( 1631 | f, 1632 | " X0: {:016x} X1: {:016x} X2: {:016x} X3: {:016x}", 1633 | self.get_reg(Reg::X0).unwrap(), 1634 | self.get_reg(Reg::X1).unwrap(), 1635 | self.get_reg(Reg::X2).unwrap(), 1636 | self.get_reg(Reg::X3).unwrap() 1637 | )?; 1638 | writeln!( 1639 | f, 1640 | " X4: {:016x} X5: {:016x} X6: {:016x} X7: {:016x}", 1641 | self.get_reg(Reg::X4).unwrap(), 1642 | self.get_reg(Reg::X5).unwrap(), 1643 | self.get_reg(Reg::X6).unwrap(), 1644 | self.get_reg(Reg::X7).unwrap() 1645 | )?; 1646 | writeln!( 1647 | f, 1648 | " X8: {:016x} X9: {:016x} X10: {:016x} X11: {:016x}", 1649 | self.get_reg(Reg::X8).unwrap(), 1650 | self.get_reg(Reg::X9).unwrap(), 1651 | self.get_reg(Reg::X10).unwrap(), 1652 | self.get_reg(Reg::X11).unwrap() 1653 | )?; 1654 | writeln!( 1655 | f, 1656 | " X12: {:016x} X13: {:016x} X14: {:016x} X15: {:016x}", 1657 | self.get_reg(Reg::X12).unwrap(), 1658 | self.get_reg(Reg::X13).unwrap(), 1659 | self.get_reg(Reg::X14).unwrap(), 1660 | self.get_reg(Reg::X15).unwrap() 1661 | )?; 1662 | writeln!( 1663 | f, 1664 | " X16: {:016x} X17: {:016x} X18: {:016x} X19: {:016x}", 1665 | self.get_reg(Reg::X16).unwrap(), 1666 | self.get_reg(Reg::X17).unwrap(), 1667 | self.get_reg(Reg::X18).unwrap(), 1668 | self.get_reg(Reg::X19).unwrap() 1669 | )?; 1670 | writeln!( 1671 | f, 1672 | " X20: {:016x} X21: {:016x} X22: {:016x} X23: {:016x}", 1673 | self.get_reg(Reg::X20).unwrap(), 1674 | self.get_reg(Reg::X21).unwrap(), 1675 | self.get_reg(Reg::X22).unwrap(), 1676 | self.get_reg(Reg::X23).unwrap() 1677 | )?; 1678 | writeln!( 1679 | f, 1680 | " X24: {:016x} X25: {:016x} X26: {:016x} X27: {:016x}", 1681 | self.get_reg(Reg::X24).unwrap(), 1682 | self.get_reg(Reg::X25).unwrap(), 1683 | self.get_reg(Reg::X26).unwrap(), 1684 | self.get_reg(Reg::X27).unwrap() 1685 | )?; 1686 | writeln!( 1687 | f, 1688 | " X28: {:016x} X29: {:016x} LR: {:016x} PC: {:016x}", 1689 | self.get_reg(Reg::X28).unwrap(), 1690 | self.get_reg(Reg::X29).unwrap(), 1691 | self.get_reg(Reg::LR).unwrap(), 1692 | self.get_reg(Reg::PC).unwrap() 1693 | )?; 1694 | writeln!( 1695 | f, 1696 | " SP: {:016x}", 1697 | self.get_sys_reg(SysReg::SP_EL0).unwrap() 1698 | )?; 1699 | writeln!(f, "EL1:")?; 1700 | writeln!( 1701 | f, 1702 | " SCTLR: {:016x} SP: {:016x}", 1703 | self.get_sys_reg(SysReg::SCTLR_EL1).unwrap(), 1704 | self.get_sys_reg(SysReg::SP_EL1).unwrap() 1705 | )?; 1706 | writeln!( 1707 | f, 1708 | " CPSR: {:016x} SPSR: {:016x}", 1709 | self.get_reg(Reg::CPSR).unwrap(), 1710 | self.get_sys_reg(SysReg::SPSR_EL1).unwrap() 1711 | )?; 1712 | writeln!( 1713 | f, 1714 | " FAR: {:016x} PAR: {:016x}", 1715 | self.get_sys_reg(SysReg::FAR_EL1).unwrap(), 1716 | self.get_sys_reg(SysReg::PAR_EL1).unwrap() 1717 | )?; 1718 | writeln!( 1719 | f, 1720 | " ESR: {:016x} ELR: {:016x}", 1721 | self.get_sys_reg(SysReg::ESR_EL1).unwrap(), 1722 | self.get_sys_reg(SysReg::ELR_EL1).unwrap() 1723 | ) 1724 | } 1725 | } 1726 | 1727 | // ----------------------------------------------------------------------------------------------- 1728 | // Tests 1729 | // ----------------------------------------------------------------------------------------------- 1730 | 1731 | #[cfg(test)] 1732 | mod tests { 1733 | use super::*; 1734 | 1735 | // ------------------------------------------------------------------------------------------- 1736 | // Virtual Machine 1737 | 1738 | #[test] 1739 | fn vm_create_destroy() { 1740 | { 1741 | // Creating a first VM instance should work! 1742 | let vm1 = VirtualMachine::new(); 1743 | assert!(vm1.is_ok()); 1744 | // Creating a second instance should fail. 1745 | let vm2 = VirtualMachine::new(); 1746 | assert_eq!(vm2, Err(HypervisorError::Busy)); 1747 | // Dropping the process vm instance... 1748 | } 1749 | // ... now creating a new instance should work. 1750 | let vm3 = VirtualMachine::new(); 1751 | assert!(vm3.is_ok()); 1752 | } 1753 | 1754 | // ------------------------------------------------------------------------------------------- 1755 | // Memory Management 1756 | 1757 | #[test] 1758 | fn memory_map_unmap() { 1759 | let _vm = VirtualMachine::new().unwrap(); 1760 | // Creating a new mapping of size 0x1000. 1761 | let mut mem = Mapping::new(0x1000).unwrap(); 1762 | // Mapping it at a non-page-aligned address in the guest should not work... 1763 | assert_eq!( 1764 | mem.map(0x1000, MemPerms::RW), 1765 | Err(HypervisorError::BadArgument) 1766 | ); 1767 | // ... but a page-aligned address should. 1768 | assert_eq!(mem.map(0x4000, MemPerms::RW), Ok(())); 1769 | // Unmapping it should also work. 1770 | assert_eq!(mem.unmap(), Ok(())); 1771 | // Mapping it twice should not work though. 1772 | assert_eq!(mem.map(0x4000, MemPerms::RW), Ok(())); 1773 | assert_eq!(mem.map(0x4000, MemPerms::RW), Err(HypervisorError::Busy)); 1774 | // Creating a second mapping of size 0x1000. 1775 | let mut mem2 = Mapping::new(0x1000).unwrap(); 1776 | // Mapping it at the location of the first one should not work. 1777 | assert_eq!(mem2.map(0x4000, MemPerms::RW), Err(HypervisorError::Error)); 1778 | } 1779 | 1780 | #[test] 1781 | fn memory_map_same_address() { 1782 | let _vm = VirtualMachine::new().unwrap(); 1783 | // Creating two mappings of size 0x1000. 1784 | let mut mem1 = Mapping::new(0x1000).unwrap(); 1785 | let mut mem2 = Mapping::new(0x1000).unwrap(); 1786 | // Maps the two mappings at the same address. 1787 | assert_eq!(mem1.map(0x4000, MemPerms::RW), Ok(())); 1788 | assert_eq!(mem2.map(0x4000, MemPerms::RW), Err(HypervisorError::Error)); 1789 | 1790 | let mut mem3 = Mapping::new(0x1000).unwrap(); 1791 | assert_eq!(mem3.map(0x20000, MemPerms::RW), Ok(())); 1792 | } 1793 | 1794 | #[test] 1795 | fn memory_read_write_protect() { 1796 | let _vm = VirtualMachine::new().unwrap(); 1797 | let mut mem = Mapping::new(0x1000).unwrap(); 1798 | // Mapping memory as Read/Write 1799 | assert_eq!(mem.map(0x10000, MemPerms::RW), Ok(())); 1800 | // Writing 0xdeadbeef in the guest allocated memory. 1801 | assert_eq!(mem.write_dword(0x12345, 0xdeadbeef), Ok(4)); 1802 | // Reading at the same location and making sure we're reading 0xdeadbeef. 1803 | assert_eq!(mem.read_dword(0x12345), Ok(0xdeadbeef)); 1804 | // Testing all write functions 1805 | assert_eq!(mem.write(0x10000, &vec![0x10, 0x11, 0x12, 0x13]), Ok(4)); 1806 | assert_eq!(mem.write_byte(0x10010, 0x41), Ok(1)); 1807 | assert_eq!(mem.write_word(0x10020, 0x4242), Ok(2)); 1808 | assert_eq!(mem.write_dword(0x10030, 0x43434343), Ok(4)); 1809 | assert_eq!(mem.write_qword(0x10040, 0x4444444444444444), Ok(8)); 1810 | // Testing all read functions 1811 | let mut data = [0; 4]; 1812 | let ret = mem.read(0x10000, &mut data); 1813 | assert_eq!(ret, Ok(4)); 1814 | assert_eq!(data, [0x10, 0x11, 0x12, 0x13]); 1815 | assert_eq!(mem.read_byte(0x10010), Ok(0x41)); 1816 | assert_eq!(mem.read_word(0x10020), Ok(0x4242)); 1817 | assert_eq!(mem.read_dword(0x10030), Ok(0x43434343)); 1818 | assert_eq!(mem.read_qword(0x10040), Ok(0x4444444444444444)); 1819 | // Changing the mapping permissions 1820 | assert_eq!(mem.protect(MemPerms::R), Ok(())); 1821 | } 1822 | 1823 | #[test] 1824 | #[ignore] 1825 | fn memory_map_unmap_threads() { 1826 | let mut mem1 = MappingShared::new(0x1000).unwrap(); 1827 | mem1.map(0, MemPerms::RW).expect("could not map memory"); 1828 | let mem2 = mem1.clone(); 1829 | let mut mem3 = mem1.clone(); 1830 | 1831 | let t1 = std::thread::spawn(move || { 1832 | println!( 1833 | "write val 0xdeadbeef = {:?}", 1834 | mem1.write_dword(0, 0xdeadbeef) 1835 | ); 1836 | std::thread::sleep(std::time::Duration::from_millis(5000)); 1837 | }); 1838 | 1839 | let t2 = std::thread::spawn(move || { 1840 | std::thread::sleep(std::time::Duration::from_millis(2000)); 1841 | println!("read val = {:?}", mem2.read_dword(0)); 1842 | std::thread::sleep(std::time::Duration::from_millis(2000)); 1843 | println!("read val = {:?}", mem2.read_dword(0)); 1844 | }); 1845 | 1846 | let t3 = std::thread::spawn(move || { 1847 | std::thread::sleep(std::time::Duration::from_millis(3000)); 1848 | println!("write val 0 = {:?}", mem3.write_dword(0, 0)); 1849 | std::thread::sleep(std::time::Duration::from_millis(7000)); 1850 | }); 1851 | 1852 | t1.join().expect("could not join 1st thread"); 1853 | t2.join().expect("could not join 2nd thread"); 1854 | t3.join().expect("could not join 3rd thread"); 1855 | } 1856 | 1857 | // ------------------------------------------------------------------------------------------- 1858 | // Vcpu 1859 | 1860 | #[test] 1861 | fn vcpu_config_create_get_values() { 1862 | let config = VcpuConfig::new(); 1863 | // Reading feature reg from the config. 1864 | assert!(config.get_feature_reg(FeatureReg::ID_AA64DFR0_EL1).is_ok()); 1865 | assert!(config.get_feature_reg(FeatureReg::ID_AA64DFR1_EL1).is_ok()); 1866 | assert!(config.get_feature_reg(FeatureReg::ID_AA64ISAR0_EL1).is_ok()); 1867 | assert!(config.get_feature_reg(FeatureReg::ID_AA64ISAR1_EL1).is_ok()); 1868 | assert!(config.get_feature_reg(FeatureReg::ID_AA64MMFR0_EL1).is_ok()); 1869 | assert!(config.get_feature_reg(FeatureReg::ID_AA64MMFR1_EL1).is_ok()); 1870 | assert!(config.get_feature_reg(FeatureReg::ID_AA64MMFR2_EL1).is_ok()); 1871 | assert!(config.get_feature_reg(FeatureReg::ID_AA64PFR0_EL1).is_ok()); 1872 | assert!(config.get_feature_reg(FeatureReg::ID_AA64PFR1_EL1).is_ok()); 1873 | assert!(config.get_feature_reg(FeatureReg::CTR_EL0).is_ok()); 1874 | assert!(config.get_feature_reg(FeatureReg::CLIDR_EL1).is_ok()); 1875 | assert!(config.get_feature_reg(FeatureReg::DCZID_EL0).is_ok()); 1876 | // Reading the Cache Size ID Register. 1877 | assert!(config 1878 | .get_ccsidr_el1_sys_reg_values(CacheType::DATA) 1879 | .is_ok()); 1880 | assert!(config 1881 | .get_ccsidr_el1_sys_reg_values(CacheType::INSTRUCTION) 1882 | .is_ok()); 1883 | } 1884 | 1885 | #[test] 1886 | fn vcpu_get_count() { 1887 | // let vm = VirtualMachine::new(); 1888 | assert!(Vcpu::get_max_count().is_ok()); 1889 | } 1890 | 1891 | #[test] 1892 | fn vcpu_create_destroy() { 1893 | let _vm = VirtualMachine::new().unwrap(); 1894 | let mut mem = Mapping::new(0x1000).unwrap(); 1895 | // Creating a vCPU in the main thread should work. 1896 | let vcpu1 = Vcpu::new(); 1897 | assert!(vcpu1.is_ok()); 1898 | // Creating a second one should fail. 1899 | let vcpu2 = Vcpu::new(); 1900 | assert_eq!(vcpu2, Err(HypervisorError::Busy)); 1901 | mem.map(0, MemPerms::RW).expect("could not map memory"); 1902 | let t = std::thread::spawn(move || { 1903 | assert!(Vcpu::new().is_ok()); 1904 | }); 1905 | t.join().expect("could not join thread"); 1906 | } 1907 | 1908 | #[test] 1909 | fn vcpu_get_set_registers() { 1910 | let _vm = VirtualMachine::new().unwrap(); 1911 | let vcpu = Vcpu::new().unwrap(); 1912 | // Setting GP registers 1913 | assert_eq!(vcpu.set_reg(Reg::X0, 0x01010101), Ok(())); 1914 | assert_eq!(vcpu.set_reg(Reg::X1, 0x12121212), Ok(())); 1915 | assert_eq!(vcpu.set_reg(Reg::X2, 0x23232323), Ok(())); 1916 | assert_eq!(vcpu.set_reg(Reg::X3, 0x34343434), Ok(())); 1917 | assert_eq!(vcpu.set_reg(Reg::X4, 0x45454545), Ok(())); 1918 | // Getting GP registers' values 1919 | assert_eq!(vcpu.get_reg(Reg::X0), Ok(0x01010101)); 1920 | assert_eq!(vcpu.get_reg(Reg::X1), Ok(0x12121212)); 1921 | assert_eq!(vcpu.get_reg(Reg::X2), Ok(0x23232323)); 1922 | assert_eq!(vcpu.get_reg(Reg::X3), Ok(0x34343434)); 1923 | assert_eq!(vcpu.get_reg(Reg::X4), Ok(0x45454545)); 1924 | 1925 | #[cfg(not(feature = "simd_nightly"))] 1926 | { 1927 | // Setting floating point registers 1928 | let simd1 = u128::from_le_bytes([0x1; 16]); 1929 | let simd2 = u128::from_le_bytes([0x2; 16]); 1930 | let simd3 = u128::from_le_bytes([0x3; 16]); 1931 | let simd4 = u128::from_le_bytes([0x4; 16]); 1932 | let simd5 = u128::from_le_bytes([0x5; 16]); 1933 | assert_eq!(vcpu.set_simd_fp_reg(SimdFpReg::Q0, simd1), Ok(())); 1934 | assert_eq!(vcpu.set_simd_fp_reg(SimdFpReg::Q1, simd2), Ok(())); 1935 | assert_eq!(vcpu.set_simd_fp_reg(SimdFpReg::Q2, simd3), Ok(())); 1936 | assert_eq!(vcpu.set_simd_fp_reg(SimdFpReg::Q3, simd4), Ok(())); 1937 | assert_eq!(vcpu.set_simd_fp_reg(SimdFpReg::Q4, simd5), Ok(())); 1938 | // Getting floating point registers' values 1939 | assert_eq!(vcpu.get_simd_fp_reg(SimdFpReg::Q0), Ok(simd1)); 1940 | assert_eq!(vcpu.get_simd_fp_reg(SimdFpReg::Q1), Ok(simd2)); 1941 | assert_eq!(vcpu.get_simd_fp_reg(SimdFpReg::Q2), Ok(simd3)); 1942 | assert_eq!(vcpu.get_simd_fp_reg(SimdFpReg::Q3), Ok(simd4)); 1943 | assert_eq!(vcpu.get_simd_fp_reg(SimdFpReg::Q4), Ok(simd5)); 1944 | } 1945 | #[cfg(feature = "simd_nightly")] 1946 | { 1947 | // Setting floating point registers 1948 | let simd1 = simd::i8x16::from_array([0x1; 16]); 1949 | let simd2 = simd::i8x16::from_array([0x2; 16]); 1950 | let simd3 = simd::i8x16::from_array([0x3; 16]); 1951 | let simd4 = simd::i8x16::from_array([0x4; 16]); 1952 | let simd5 = simd::i8x16::from_array([0x5; 16]); 1953 | assert_eq!(vcpu.set_simd_fp_reg(SimdFpReg::Q0, simd1), Ok(())); 1954 | assert_eq!(vcpu.set_simd_fp_reg(SimdFpReg::Q1, simd2), Ok(())); 1955 | assert_eq!(vcpu.set_simd_fp_reg(SimdFpReg::Q2, simd3), Ok(())); 1956 | assert_eq!(vcpu.set_simd_fp_reg(SimdFpReg::Q3, simd4), Ok(())); 1957 | assert_eq!(vcpu.set_simd_fp_reg(SimdFpReg::Q4, simd5), Ok(())); 1958 | // Getting floating point registers' values 1959 | assert_eq!(vcpu.get_simd_fp_reg(SimdFpReg::Q0), Ok(simd1)); 1960 | assert_eq!(vcpu.get_simd_fp_reg(SimdFpReg::Q1), Ok(simd2)); 1961 | assert_eq!(vcpu.get_simd_fp_reg(SimdFpReg::Q2), Ok(simd3)); 1962 | assert_eq!(vcpu.get_simd_fp_reg(SimdFpReg::Q3), Ok(simd4)); 1963 | assert_eq!(vcpu.get_simd_fp_reg(SimdFpReg::Q4), Ok(simd5)); 1964 | } 1965 | } 1966 | 1967 | #[test] 1968 | fn vcpu_run() { 1969 | let _vm = VirtualMachine::new().unwrap(); 1970 | let vcpu = Vcpu::new().unwrap(); 1971 | let mut mem = Mapping::new(0x1000).unwrap(); 1972 | assert_eq!(mem.map(0x4000, MemPerms::RWX), Ok(())); 1973 | // Writes a `mov x0, #0x42` instruction at address 0x4000. 1974 | assert_eq!(mem.write_dword(0x4000, 0xd2800840), Ok(4)); 1975 | // Writes a `brk #0` instruction at address 0x4004. 1976 | assert_eq!(mem.write_dword(0x4004, 0xd4200000), Ok(4)); 1977 | // Sets PC to 0x4000. 1978 | assert!(vcpu.set_reg(Reg::PC, 0x4000).is_ok()); 1979 | // Starts the Vcpu. 1980 | assert!(vcpu.run().is_ok()); 1981 | let _exit_info = vcpu.get_exit_info(); 1982 | assert_eq!(vcpu.get_reg(Reg::X0), Ok(0x42)); 1983 | } 1984 | } 1985 | --------------------------------------------------------------------------------