diff --git a/.gitignore b/.gitignore index bc8218e7..14144c9b 100644 --- a/.gitignore +++ b/.gitignore @@ -54,9 +54,11 @@ # Rust *.lock -cmake/rust/constants.rs -example/default_rust/src/target/ -syscall/tests/target/ +syscall/constants.rs +syscall/Cargo.toml +syscall/target +example/default_rust/Cargo.toml +example/default_rust/target # Others .vscode/ diff --git a/CMakeLists.txt b/CMakeLists.txt index aa67ac00..e6b85d90 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,7 +22,12 @@ cmake_minimum_required(VERSION 3.13) project(hypervisor C CXX ASM) +if(${CMAKE_VERSION} GREATER_EQUAL "3.20") + cmake_policy(SET CMP0115 OLD) +endif() + include(${CMAKE_CURRENT_LIST_DIR}/cmake/init_build.cmake) +add_subdirectory(syscall) if(NOT CMAKE_BUILD_TYPE STREQUAL CODECOV) if(HYPERVISOR_BUILD_LOADER) diff --git a/README.md b/README.md index 2afeef97..51da1989 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ ![Bareflank](https://github.com/Bareflank/hypervisor/raw/master/.github/images/hypervisor_logo.png) ## Description -The Bareflank Hypervisor is an open source hypervisor Software Development Toolkit (SDK), led by Assured Information Security, Inc. (AIS), that provides the tools needed to rapidly prototype and create your own hypervisor on 64bit versions of Intel, AMD and ARMv8 CPUs (RISC-V and PowerPC also planned). The Bareflank SDK is intended for instructional/research purposes as it only provides enough virtualization support to start/stop a hypervisor. Bareflank can also be used as the foundation to create your own, fully functional hypervisor as it uses the MIT license, includes 100% unit test coverage and compliance for AUTOSAR and ASIL/D. If you are looking for a complete hypervisor (and not an SDK), please see [MicroV](https://github.com/Bareflank/microv). If you are looking for a minimal SDK for education or to perform research, this is the project for you. If you are simply looking for a reference hypervisor, please see [SimpleVisor](https://github.com/ionescu007/SimpleVisor). +The Bareflank Hypervisor is an open source hypervisor Software Development Toolkit (SDK) for Rust and C++, led by Assured Information Security, Inc. (AIS), that provides the tools needed to rapidly prototype and create your own hypervisor on 64bit versions of Intel and AMD (ARMv8 CPUs, RISC-V and PowerPC also planned). The Bareflank SDK is intended for instructional/research purposes as it only provides enough virtualization support to start/stop a hypervisor. Bareflank can also be used as the foundation to create your own, fully functional hypervisor as it uses the MIT license, includes 100% unit test coverage and compliance for AUTOSAR. If you are looking for a complete hypervisor (and not an SDK), please see [MicroV](https://github.com/Bareflank/microv). If you are looking for a minimal SDK for education or to perform research, this is the project for you. If you are simply looking for a reference hypervisor, please see [SimpleVisor](https://github.com/ionescu007/SimpleVisor). Bareflank uses a layered, modular approach, that lets you pick just how much complexity you need in your project when creating your own custom hypervisor: - [BSL](https://github.com/Bareflank/bsl): provides a header-only, AUTOSAR @@ -12,7 +12,7 @@ Bareflank uses a layered, modular approach, that lets you pick just how much com implementation of the LLVM Clang-Tidy static analysis tool to ensure compliance with AUTOSAR. - [PAL](https://github.com/Bareflank/pal): provides auto-generated intrinsics - APIs for Intel, AMD and ARM on any combination of OS. + APIs for Intel, AMD and ARM on any combination of OS and language. - [hypervisor](https://github.com/Bareflank/hypervisor): provides the base SDK including the loader, the Bareflank microkernel and support applications. Although this repo is labeled "hypervisor", this repo only provides the base @@ -24,7 +24,8 @@ Bareflank uses a layered, modular approach, that lets you pick just how much com - [MicroV](https://github.com/Bareflank/microv): This is the project led by Assured Information Security, Inc. (AIS) the provides a fully functional hypervisor that uses the Bareflank SDK as it's foundation. If you are looking - for an actual hypervisor, this is the project you are looking for. + for an actual hypervisor and not an SDK, this is the project you are looking + for. ## **Quick start** ![GitHub release (latest by date)](https://img.shields.io/github/v/release/bareflank/hypervisor?color=brightgreen) @@ -240,65 +241,23 @@ Finally, we will configure the project, telling the build system how to find our cd ~/working/build cmake \ ../hypervisor \ - -DHYPERVISOR_EXTENSIONS=example_default \ -DHYPERVISOR_EXTENSIONS_DIR=$PWD/../extension \ -DFETCHCONTENT_SOURCE_DIR_BSL=$PWD/../bsl ``` -The `HYPERVISOR_EXTENSIONS` variable tells CMake what the name of the resulting binary is that represents your extension. Specifically, in your extension's CMakeLists.txt, there will be a call to `install()` like `install(TARGETS example_default DESTINATION bin)`. You set `HYPERVISOR_EXTENSIONS` to the value after `TARGETS`. In the case above, since we copied the default example, we set `HYPERVISOR_EXTENSIONS` to `example_default`. - `HYPERVISOR_EXTENSIONS_DIR` defines the location of your extension. Note that the path must be an absolute path, which is why we used the absolute path of the build folder as a starting point and then worked out the location of the extension folder from there. `FETCHCONTENT_SOURCE_DIR_BSL` is optional. This tells the build system where to find the BSL. Since we already cloned the BSL into our working directory, we can use it instead of asking the build system to automatically fetch the BSL for us. This is great for offline builds, or builds where you are rerunning cmake a lot and don't want to wait for the BSL to download each time. The rest of the usage instructions above can be used to start/stop your custom hypervisor. For more information about what ABIs the microkernel provides your extension with, please see the [Microkernel Syscall Specification](https://github.com/Bareflank/hypervisor/blob/master/docs/Microkernel%20Syscall%20Specification.md) in the docs folder. We also provide an example implementation of this ABI as a set of C++ APIs that you can use if you would like. This example set of APIs can be seen in the [syscall/include/mk_interface.hpp](https://github.com/Bareflank/hypervisor/blob/master/syscall/include/mk_interface.hpp) file. -## **Raspberry Pi 4** -Yes, ARMv8 is supported by Bareflank. Specifically, Bareflank aims to support -systems that adhere to the [ServerReady](https://developer.arm.com/architectures/platform-design/server-systems) -specification using UEFI. To get the Raspberry Pi 4 to run Bareflank, you will -need the following: -- A [Raspberry Pi 4](https://www.raspberrypi.org/products/raspberry-pi-4-desktop-kit/). - Other kits exist, but it is important that you have most of the things that - come with this kit. -- An SD card loaded with [UEFI](https://github.com/pftf/RPi4). The SD card - will only be used to boot UEFI. -- A USB 3.0 USB stick. Make sure it is low profile as all of the USB devices - that will be plugged in get cramped and wide USB sticks will not fit. -- A compatible keyboard and mouse. Not all keyboards seem to work. Likely a - keyboard and mouse that is well supported by Linux will work fine, which - does not include Corsair devices. Or, just buy the kit above which works - great. -- A [USB serial cable](https://www.amazon.com/ADAFRUIT-Industries-954-Serial-Raspberry/dp/B00DJUHGHI/ref=sr_1_3?dchild=1&keywords=raspberry+pi+4+serial+cable&qid=1622228033&sr=8-3) - Do not use the voltage line (the red cable, meaning only use the black, green - and white cables). If you use the voltage line, the Raspberry Pi 4 will be - powered from this USB cable, which causes all sorts of instability issues - including crashing and certain devices not powering on during reboots. - Instead, use the power cable that comes in the kit above, and only use the - USB cable for serial. -- A [power cable switch](https://www.amazon.com/iUniker-Raspberry-Switch-Supply-Type-C/dp/B07V8G2SYZ/ref=sr_1_5?dchild=1&keywords=raspberry+pi+4+power+cable&qid=1622228153&sr=8-5) - is a nice optional feature. Each time you make a mod to the hypervisor you - will need to reboot, and this will prevent you from having to unplug the - Raspberry Pi 4 all the time as it doesn't have a power or reset switch. -- Ubuntu Server 21.04 or higher. This is important. No other versions of Linux - seem to work. Most versions of Linux for the Raspberry Pi 4 as pre-build - images. These images are not compliant with the ServerReady spec and therefore - do not support UEFI. Ubuntu 21.04 Sever Edition has an ISO version for ARM - that installs fine on the Raspberry Pi 4. Install Ubuntu onto the USB stick. - UEFI will make the USB stick FS0, allowing you to use the commands in the - UEFI section of this readme to compile and test. -- Late Launch is not supported, meaning you must use UEFI. - -It is possible that the microkernel is missing APIs for configuring certain -features on the ARMv8 CPU. If this is the case, please feel free to propose -whatever changes are needed to support your research. - ## **Resources** [![Join the chat](https://img.shields.io/badge/chat-on%20Slack-brightgreen.svg)](https://bareflank.herokuapp.com/) The Bareflank hypervisor provides a ton of useful resources to learn how to use the library including: -- **Documentation**: +- **Specification**: - **Examples**: +- **Integration Tests**: If you have any questions, bugs, or feature requests, please feel free to ask on any of the following: - **Slack**: diff --git a/cmake/config/default.cmake b/cmake/config/default.cmake index 0693c7c4..ee26e386 100644 --- a/cmake/config/default.cmake +++ b/cmake/config/default.cmake @@ -103,14 +103,6 @@ else() set(HYPERVISOR_DEFAULT_EFI_FS0 ${HYPERVISOR_EFI_FS0}) endif() -bf_add_config( - CONFIG_NAME HYPERVISOR_EXTENSIONS - CONFIG_TYPE STRING - DEFAULT_VAL "example_default" - DESCRIPTION "Define the extension list used by the build system" - SKIP_VALIDATION -) - bf_add_config( CONFIG_NAME HYPERVISOR_EXTENSIONS_DIR CONFIG_TYPE STRING diff --git a/cmake/depend/bsl.cmake b/cmake/depend/bsl.cmake index f70958fa..d4114839 100644 --- a/cmake/depend/bsl.cmake +++ b/cmake/depend/bsl.cmake @@ -19,7 +19,7 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -set(GIT_TAG 4215efc76ff0997a44f39a16f6f84b487cef5bf6) +set(GIT_TAG 6509cfff948fa34b98585512d7be33a36e2f9522) FetchContent_Declare( bsl diff --git a/cmake/ext_cross_compile/CMakeLists.txt b/cmake/ext_cross_compile/CMakeLists.txt index 6838d8a2..ef3af9f2 100644 --- a/cmake/ext_cross_compile/CMakeLists.txt +++ b/cmake/ext_cross_compile/CMakeLists.txt @@ -28,8 +28,9 @@ add_subdirectory(../../loader loader) add_subdirectory(../../runtime runtime) add_subdirectory(../../syscall syscall) add_subdirectory(../../lib lib) -add_subdirectory(../../kernel/integration integration) -if(DEFINED HYPERVISOR_EXTENSIONS_DIR) - add_subdirectory(${HYPERVISOR_EXTENSIONS_DIR} extension) +if(BUILD_TESTS AND NOT HYPERVISOR_BUILD_TESTS_OVERRIDE) + add_subdirectory(../../kernel/integration integration) endif() + +add_subdirectory(${HYPERVISOR_EXTENSIONS_DIR} extension) diff --git a/cmake/ext_cross_compile/Cargo.toml b/cmake/ext_cross_compile/Cargo.toml new file mode 100644 index 00000000..63d50db2 --- /dev/null +++ b/cmake/ext_cross_compile/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "rust" +version = "1.0.0" +edition = "2018" + +[lib] +path = "lib.rs" +crate-type = ["staticlib"] + +[features] +default = ["GenuineIntel","debug_level_v"] +debug_level_v = [] +debug_level_vv = [] +debug_level_vvv = [] +disable_color = [] +release_mode = [] +AuthenticAMD = [] +GenuineIntel = [] + +[dependencies] +bsl = { path = "C:/working/bsl" } +syscall = { path = "C:/working/hypervisor/syscall" } diff --git a/cmake/ext_cross_compile/src/Cargo.toml b/cmake/ext_cross_compile/src/Cargo.toml new file mode 100644 index 00000000..63d50db2 --- /dev/null +++ b/cmake/ext_cross_compile/src/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "rust" +version = "1.0.0" +edition = "2018" + +[lib] +path = "lib.rs" +crate-type = ["staticlib"] + +[features] +default = ["GenuineIntel","debug_level_v"] +debug_level_v = [] +debug_level_vv = [] +debug_level_vvv = [] +disable_color = [] +release_mode = [] +AuthenticAMD = [] +GenuineIntel = [] + +[dependencies] +bsl = { path = "C:/working/bsl" } +syscall = { path = "C:/working/hypervisor/syscall" } diff --git a/cmake/function/hypervisor_add_cmake_args.cmake b/cmake/function/hypervisor_add_cmake_args.cmake index b2e7f490..c1e26911 100644 --- a/cmake/function/hypervisor_add_cmake_args.cmake +++ b/cmake/function/hypervisor_add_cmake_args.cmake @@ -61,7 +61,6 @@ macro(hypervisor_add_cmake_args) endif() list(APPEND CMAKE_ARGS - -DHYPERVISOR_EXTENSIONS=${HYPERVISOR_EXTENSIONS} -DHYPERVISOR_EXTENSIONS_DIR=${HYPERVISOR_EXTENSIONS_DIR} -DHYPERVISOR_TARGET_ARCH=${HYPERVISOR_TARGET_ARCH} -DHYPERVISOR_CXX_LINKER=${HYPERVISOR_CXX_LINKER} diff --git a/cmake/function/hypervisor_add_info.cmake b/cmake/function/hypervisor_add_info.cmake index c291e33f..0e8d726d 100644 --- a/cmake/function/hypervisor_add_info.cmake +++ b/cmake/function/hypervisor_add_info.cmake @@ -44,11 +44,6 @@ macro(hypervisor_add_info) ) endif() - add_custom_command(TARGET info - COMMAND ${CMAKE_COMMAND} -E echo "${BF_COLOR_YLW} HYPERVISOR_EXTENSIONS ${BF_COLOR_CYN}${HYPERVISOR_EXTENSIONS}${BF_COLOR_RST}" - VERBATIM - ) - add_custom_command(TARGET info COMMAND ${CMAKE_COMMAND} -E echo "${BF_COLOR_YLW} HYPERVISOR_EXTENSIONS_DIR ${BF_COLOR_CYN}${HYPERVISOR_EXTENSIONS_DIR}${BF_COLOR_RST}" VERBATIM diff --git a/cmake/init_build.cmake b/cmake/init_build.cmake index 956e215e..0696d6d2 100644 --- a/cmake/init_build.cmake +++ b/cmake/init_build.cmake @@ -41,6 +41,8 @@ include(${CMAKE_CURRENT_LIST_DIR}/target/loader_load.cmake) include(${CMAKE_CURRENT_LIST_DIR}/target/loader_unload.cmake) include(${CMAKE_CURRENT_LIST_DIR}/target/loader_clean.cmake) include(${CMAKE_CURRENT_LIST_DIR}/target/loader_quick.cmake) +include(${CMAKE_CURRENT_LIST_DIR}/target/rust_clean.cmake) +include(${CMAKE_CURRENT_LIST_DIR}/target/rust_fmt.cmake) include(${CMAKE_CURRENT_LIST_DIR}/target/copy_to_efi_partition.cmake) include(${CMAKE_CURRENT_LIST_DIR}/write_constants.cmake) diff --git a/cmake/mk_cross_compile/cmake/rust/constants.rs b/cmake/mk_cross_compile/cmake/rust/constants.rs deleted file mode 100644 index c85a71c4..00000000 --- a/cmake/mk_cross_compile/cmake/rust/constants.rs +++ /dev/null @@ -1,4 +0,0 @@ -/* ---- AUTO GENERATED ---- */ - -pub const HYPERVISOR_PAGE_SIZE:u64 = 0x1000; - diff --git a/cmake/rust/Cargo.toml b/cmake/rust/Cargo.toml deleted file mode 100644 index 8e56f937..00000000 --- a/cmake/rust/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "cmake" -version = "0.1.0" -edition = "2018" - -[lib] -path = "lib.rs" diff --git a/cmake/silence.cmake b/cmake/silence.cmake index 9635160d..9ae539db 100644 --- a/cmake/silence.cmake +++ b/cmake/silence.cmake @@ -42,7 +42,6 @@ hypervisor_silence(ENABLE_COLOR) hypervisor_silence(BSL_DEBUG_LEVEL) hypervisor_silence(BSL_PAGE_SIZE) -hypervisor_silence(HYPERVISOR_EXTENSIONS) hypervisor_silence(HYPERVISOR_EXTENSIONS_DIR) hypervisor_silence(HYPERVISOR_TARGET_ARCH) hypervisor_silence(HYPERVISOR_CXX_LINKER) diff --git a/cmake/target/copy_to_efi_partition.cmake b/cmake/target/copy_to_efi_partition.cmake index 039d7a7f..90aeed79 100644 --- a/cmake/target/copy_to_efi_partition.cmake +++ b/cmake/target/copy_to_efi_partition.cmake @@ -23,8 +23,8 @@ if(HYPERVISOR_BUILD_EFI) if(CMAKE_SYSTEM_NAME STREQUAL "Linux") add_custom_target(copy_to_efi_partition COMMAND sudo cmake -E copy ${CMAKE_BINARY_DIR}/efi_cross_compile/bin/bareflank_efi_loader ${HYPERVISOR_EFI_FS0}/start_bareflank.efi - COMMAND sudo cmake -E copy ${CMAKE_BINARY_DIR}/mk_cross_compile/bin/kernel ${HYPERVISOR_EFI_FS0}/bareflank_kernel - COMMAND sudo cmake -E copy ${CMAKE_BINARY_DIR}/ext_cross_compile/bin/${HYPERVISOR_EXTENSIONS} ${HYPERVISOR_EFI_FS0}/bareflank_extension0 + COMMAND sudo cmake -E copy ${CMAKE_BINARY_DIR}/kernel_bin ${HYPERVISOR_EFI_FS0}/bareflank_kernel + COMMAND sudo cmake -E copy ${CMAKE_BINARY_DIR}/extension_bin ${HYPERVISOR_EFI_FS0}/bareflank_extension COMMAND sudo cmake -E copy ${CMAKE_SOURCE_DIR}/utils/Shell.efi ${HYPERVISOR_EFI_FS0}/bareflank_efi_shell.efi VERBATIM ) @@ -33,8 +33,8 @@ if(HYPERVISOR_BUILD_EFI) COMMAND mountvol X: /d | true COMMAND mountvol X: /s | true COMMAND cmake -E copy ${CMAKE_BINARY_DIR}/efi_cross_compile/bin/bareflank_efi_loader ${HYPERVISOR_EFI_FS0}/start_bareflank.efi - COMMAND cmake -E copy ${CMAKE_BINARY_DIR}/mk_cross_compile/bin/kernel ${HYPERVISOR_EFI_FS0}/bareflank_kernel - COMMAND cmake -E copy ${CMAKE_BINARY_DIR}/ext_cross_compile/bin/${HYPERVISOR_EXTENSIONS} ${HYPERVISOR_EFI_FS0}/bareflank_extension0 + COMMAND cmake -E copy ${CMAKE_BINARY_DIR}/kernel_bin ${HYPERVISOR_EFI_FS0}/bareflank_kernel + COMMAND cmake -E copy ${CMAKE_BINARY_DIR}/extension_bin ${HYPERVISOR_EFI_FS0}/bareflank_extension COMMAND cmake -E copy ${CMAKE_SOURCE_DIR}/utils/Shell.efi ${HYPERVISOR_EFI_FS0}/bareflank_efi_shell.efi COMMAND mountvol X: /d | true VERBATIM diff --git a/cmake/target/rust_clean.cmake b/cmake/target/rust_clean.cmake new file mode 100644 index 00000000..086791d4 --- /dev/null +++ b/cmake/target/rust_clean.cmake @@ -0,0 +1,35 @@ +# +# Copyright (C) 2020 Assured Information Security, Inc. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +add_custom_target(rust-clean + COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_SOURCE_DIR}/syscall/target + COMMAND ${CMAKE_COMMAND} -E remove ${CMAKE_SOURCE_DIR}/syscall/Cargo.lock + COMMAND ${CMAKE_COMMAND} -E remove ${CMAKE_SOURCE_DIR}/syscall/Cargo.toml + COMMAND ${CMAKE_COMMAND} -E remove ${CMAKE_SOURCE_DIR}/syscall/constants.rs + COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_SOURCE_DIR}/syscall/CMakeLists.txt + COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_SOURCE_DIR}/example/default_rust/target + COMMAND ${CMAKE_COMMAND} -E remove ${CMAKE_SOURCE_DIR}/example/default_rust/Cargo.lock + COMMAND ${CMAKE_COMMAND} -E remove ${CMAKE_SOURCE_DIR}/example/default_rust/Cargo.toml + COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_SOURCE_DIR}/example/default_rust/CMakeLists.txt + COMMAND ${CMAKE_COMMAND} -E remove ${CMAKE_BINARY_DIR}/rust/syscall_rust_files.txt + COMMAND ${CMAKE_COMMAND} -E remove ${CMAKE_BINARY_DIR}/ext_cross_compile/build/rust_files.txt + VERBATIM +) diff --git a/cmake/target/rust_fmt.cmake b/cmake/target/rust_fmt.cmake new file mode 100644 index 00000000..aa30b7ce --- /dev/null +++ b/cmake/target/rust_fmt.cmake @@ -0,0 +1,26 @@ +# +# Copyright (C) 2020 Assured Information Security, Inc. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +add_custom_target(rust-fmt + COMMAND ${CMAKE_COMMAND} -E chdir ${CMAKE_SOURCE_DIR}/syscall cargo fmt + COMMAND ${CMAKE_COMMAND} -E chdir ${CMAKE_SOURCE_DIR}/example/default_rust cargo fmt + VERBATIM +) diff --git a/cmake/validate.cmake b/cmake/validate.cmake index b1e1cf18..4f0a45b3 100644 --- a/cmake/validate.cmake +++ b/cmake/validate.cmake @@ -25,11 +25,6 @@ if(HYPERVISOR_TARGET_ARCH STREQUAL "aarch64") endif() endif() -list(LENGTH HYPERVISOR_EXTENSIONS HYPERVISOR_EXTENSIONS_LENGTH) -if(NOT HYPERVISOR_EXTENSIONS_LENGTH EQUAL 1) - message(FATAL_ERROR "More than one extension is currently not supported") -endif() - if(NOT EXISTS "${HYPERVISOR_EXTENSIONS_DIR}") message(FATAL_ERROR "HYPERVISOR_EXTENSIONS_DIR does not exist: ${HYPERVISOR_EXTENSIONS_DIR}") endif() diff --git a/docs/Microkernel Syscall Specification.md b/docs/Microkernel Syscall Specification.md index 0bf056eb..f8a00dc1 100644 --- a/docs/Microkernel Syscall Specification.md +++ b/docs/Microkernel Syscall Specification.md @@ -7,6 +7,8 @@ - [1.4. Constants, Structures, Enumerations, and Bit Fields](#14-constants-structures-enumerations-and-bit-fields) - [1.4.1. Handle Type](#141-handle-type) - [1.4.2. Register Type](#142-register-type) + - [1.4.2.1. AMD](#1421-amd) + - [1.4.2.2. Intel](#1422-intel) - [1.4.3. Exit Type](#143-exit-type) - [1.4.4. Bootstrap Callback Handler Type](#144-bootstrap-callback-handler-type) - [1.4.5. VMExit Callback Handler Type](#145-vmexit-callback-handler-type) @@ -40,7 +42,7 @@ - [2.9. Control Syscalls](#29-control-syscalls) - [2.9.1. bf_control_op_exit, OP=0x0, IDX=0x0](#291-bf_control_op_exit-op0x0-idx0x0) - [2.9.2. bf_control_op_wait, OP=0x0, IDX=0x1](#292-bf_control_op_wait-op0x0-idx0x1) - - [2.9.2. bf_control_op_again, OP=0x0, IDX=0x2](#292-bf_control_op_again-op0x0-idx0x2) + - [2.9.3. bf_control_op_again, OP=0x0, IDX=0x2](#293-bf_control_op_again-op0x0-idx0x2) - [2.10. Handle Syscalls](#210-handle-syscalls) - [2.10.1. bf_handle_op_open_handle, OP=0x1, IDX=0x0](#2101-bf_handle_op_open_handle-op0x1-idx0x0) - [2.10.2. bf_handle_op_close_handle, OP=0x1, IDX=0x1](#2102-bf_handle_op_close_handle-op0x1-idx0x1) @@ -60,44 +62,42 @@ - [2.12.2. bf_callback_op_register_vmexit, OP=0x3, IDX=0x1](#2122-bf_callback_op_register_vmexit-op0x3-idx0x1) - [2.12.3. bf_callback_op_register_fail, OP=0x3, IDX=0x2](#2123-bf_callback_op_register_fail-op0x3-idx0x2) - [2.13. Virtual Machine Syscalls](#213-virtual-machine-syscalls) - - [2.13.2. bf_vm_op_create_vm, OP=0x4, IDX=0x0](#2132-bf_vm_op_create_vm-op0x4-idx0x0) - - [2.13.3. bf_vm_op_destroy_vm, OP=0x4, IDX=0x1](#2133-bf_vm_op_destroy_vm-op0x4-idx0x1) + - [2.13.1. bf_vm_op_create_vm, OP=0x4, IDX=0x0](#2131-bf_vm_op_create_vm-op0x4-idx0x0) + - [2.13.2. bf_vm_op_destroy_vm, OP=0x4, IDX=0x1](#2132-bf_vm_op_destroy_vm-op0x4-idx0x1) - [2.13.3. bf_vm_op_map_direct, OP=0x4, IDX=0x2](#2133-bf_vm_op_map_direct-op0x4-idx0x2) - - [2.13.3. bf_vm_op_unmap_direct, OP=0x4, IDX=0x3](#2133-bf_vm_op_unmap_direct-op0x4-idx0x3) - - [2.13.3. bf_vm_op_unmap_direct_broadcast, OP=0x4, IDX=0x4](#2133-bf_vm_op_unmap_direct_broadcast-op0x4-idx0x4) - - [2.15.3. bf_vm_op_tlb_flush, OP=0x4, IDX=0x5](#2153-bf_vm_op_tlb_flush-op0x4-idx0x5) + - [2.13.4. bf_vm_op_unmap_direct, OP=0x4, IDX=0x3](#2134-bf_vm_op_unmap_direct-op0x4-idx0x3) + - [2.13.5. bf_vm_op_unmap_direct_broadcast, OP=0x4, IDX=0x4](#2135-bf_vm_op_unmap_direct_broadcast-op0x4-idx0x4) + - [2.13.6. bf_vm_op_tlb_flush, OP=0x4, IDX=0x5](#2136-bf_vm_op_tlb_flush-op0x4-idx0x5) - [2.14. Virtual Processor Syscalls](#214-virtual-processor-syscalls) - - [2.14.2. bf_vp_op_create_vp, OP=0x5, IDX=0x0](#2142-bf_vp_op_create_vp-op0x5-idx0x0) - - [2.14.3. bf_vp_op_destroy_vp, OP=0x5, IDX=0x1](#2143-bf_vp_op_destroy_vp-op0x5-idx0x1) - - [2.14.5. Virtual Processor State Syscalls](#2145-virtual-processor-state-syscalls) - - [2.14.7. bf_vs_op_create_vs, OP=0x6, IDX=0x0](#2147-bf_vs_op_create_vs-op0x6-idx0x0) - - [2.14.8. bf_vs_op_destroy_vs, OP=0x6, IDX=0x1](#2148-bf_vs_op_destroy_vs-op0x6-idx0x1) - - [2.14.9. bf_vs_op_init_as_root, OP=0x6, IDX=0x2](#2149-bf_vs_op_init_as_root-op0x6-idx0x2) - - [2.14.10. bf_vs_op_read, OP=0x6, IDX=0x3](#21410-bf_vs_op_read-op0x6-idx0x3) - - [2.14.11. bf_vs_op_write, OP=0x6, IDX=0x4](#21411-bf_vs_op_write-op0x6-idx0x4) - - [2.14.12. bf_vs_op_run, OP=0x6, IDX=0x5](#21412-bf_vs_op_run-op0x6-idx0x5) - - [2.14.13. bf_vs_op_run_current, OP=0x6, IDX=0x6](#21413-bf_vs_op_run_current-op0x6-idx0x6) - - [2.14.14. bf_vs_op_advance_ip_and_run_impl, OP=0x6, IDX=0x7](#21414-bf_vs_op_advance_ip_and_run_impl-op0x6-idx0x7) - - [2.14.15. bf_vs_op_advance_ip_and_run_current, OP=0x6, IDX=0x8](#21415-bf_vs_op_advance_ip_and_run_current-op0x6-idx0x8) - - [2.14.16. bf_vs_op_promote, OP=0x6, IDX=0x9](#21416-bf_vs_op_promote-op0x6-idx0x9) - - [2.14.17. bf_vs_op_clear, OP=0x6, IDX=0xA](#21417-bf_vs_op_clear-op0x6-idx0xa) - - [2.14.17. bf_vs_op_migrate, OP=0x6, IDX=0xB](#21417-bf_vs_op_migrate-op0x6-idx0xb) - - [2.14.17. bf_vs_op_set_active, OP=0x6, IDX=0xC](#21417-bf_vs_op_set_active-op0x6-idx0xc) - - [2.14.17. bf_vs_op_advance_ip_and_set_active, OP=0x6, IDX=0xD](#21417-bf_vs_op_advance_ip_and_set_active-op0x6-idx0xd) - - [2.15.3. bf_vs_op_tlb_flush, OP=0x6, IDX=0xE](#2153-bf_vs_op_tlb_flush-op0x6-idx0xe) - - [2.15. Intrinsic Syscalls](#215-intrinsic-syscalls) - - [2.15.1. bf_intrinsic_op_rdmsr, OP=0x7, IDX=0x0](#2151-bf_intrinsic_op_rdmsr-op0x7-idx0x0) - - [2.15.2. bf_intrinsic_op_wrmsr, OP=0x7, IDX=0x1](#2152-bf_intrinsic_op_wrmsr-op0x7-idx0x1) - - [2.16. Mem Syscalls](#216-mem-syscalls) - - [2.16.1. bf_mem_op_alloc_page, OP=0x8, IDX=0x0](#2161-bf_mem_op_alloc_page-op0x8-idx0x0) - - [2.16.2. bf_mem_op_free_page, OP=0x8, IDX=0x1](#2162-bf_mem_op_free_page-op0x8-idx0x1) - - [2.16.3. bf_mem_op_alloc_huge, OP=0x8, IDX=0x2](#2163-bf_mem_op_alloc_huge-op0x8-idx0x2) - - [2.16.4. bf_mem_op_free_huge, OP=0x8, IDX=0x3](#2164-bf_mem_op_free_huge-op0x8-idx0x3) + - [2.14.1. bf_vp_op_create_vp, OP=0x5, IDX=0x0](#2141-bf_vp_op_create_vp-op0x5-idx0x0) + - [2.14.2. bf_vp_op_destroy_vp, OP=0x5, IDX=0x1](#2142-bf_vp_op_destroy_vp-op0x5-idx0x1) + - [2.15. Virtual Processor State Syscalls](#215-virtual-processor-state-syscalls) + - [2.15.1. bf_vs_op_create_vs, OP=0x6, IDX=0x0](#2151-bf_vs_op_create_vs-op0x6-idx0x0) + - [2.15.2. bf_vs_op_destroy_vs, OP=0x6, IDX=0x1](#2152-bf_vs_op_destroy_vs-op0x6-idx0x1) + - [2.15.3. bf_vs_op_init_as_root, OP=0x6, IDX=0x2](#2153-bf_vs_op_init_as_root-op0x6-idx0x2) + - [2.15.4. bf_vs_op_read, OP=0x6, IDX=0x3](#2154-bf_vs_op_read-op0x6-idx0x3) + - [2.15.5. bf_vs_op_write, OP=0x6, IDX=0x4](#2155-bf_vs_op_write-op0x6-idx0x4) + - [2.15.6. bf_vs_op_run, OP=0x6, IDX=0x5](#2156-bf_vs_op_run-op0x6-idx0x5) + - [2.15.7. bf_vs_op_run_current, OP=0x6, IDX=0x6](#2157-bf_vs_op_run_current-op0x6-idx0x6) + - [2.15.8. bf_vs_op_advance_ip_and_run_impl, OP=0x6, IDX=0x7](#2158-bf_vs_op_advance_ip_and_run_impl-op0x6-idx0x7) + - [2.15.9. bf_vs_op_advance_ip_and_run_current, OP=0x6, IDX=0x8](#2159-bf_vs_op_advance_ip_and_run_current-op0x6-idx0x8) + - [2.15.10. bf_vs_op_promote, OP=0x6, IDX=0x9](#21510-bf_vs_op_promote-op0x6-idx0x9) + - [2.15.11. bf_vs_op_clear, OP=0x6, IDX=0xA](#21511-bf_vs_op_clear-op0x6-idx0xa) + - [2.15.12. bf_vs_op_migrate, OP=0x6, IDX=0xB](#21512-bf_vs_op_migrate-op0x6-idx0xb) + - [2.15.13. bf_vs_op_set_active, OP=0x6, IDX=0xC](#21513-bf_vs_op_set_active-op0x6-idx0xc) + - [2.15.14. bf_vs_op_advance_ip_and_set_active, OP=0x6, IDX=0xD](#21514-bf_vs_op_advance_ip_and_set_active-op0x6-idx0xd) + - [2.15.15. bf_vs_op_tlb_flush, OP=0x6, IDX=0xE](#21515-bf_vs_op_tlb_flush-op0x6-idx0xe) + - [2.16. Intrinsic Syscalls](#216-intrinsic-syscalls) + - [2.16.1. bf_intrinsic_op_rdmsr, OP=0x7, IDX=0x0](#2161-bf_intrinsic_op_rdmsr-op0x7-idx0x0) + - [2.16.2. bf_intrinsic_op_wrmsr, OP=0x7, IDX=0x1](#2162-bf_intrinsic_op_wrmsr-op0x7-idx0x1) + - [2.17. Mem Syscalls](#217-mem-syscalls) + - [2.17.1. bf_mem_op_alloc_page, OP=0x8, IDX=0x0](#2171-bf_mem_op_alloc_page-op0x8-idx0x0) + - [2.17.2. bf_mem_op_free_page, OP=0x8, IDX=0x1](#2172-bf_mem_op_free_page-op0x8-idx0x1) + - [2.17.3. bf_mem_op_alloc_huge, OP=0x8, IDX=0x2](#2173-bf_mem_op_alloc_huge-op0x8-idx0x2) + - [2.17.4. bf_mem_op_free_huge, OP=0x8, IDX=0x3](#2174-bf_mem_op_free_huge-op0x8-idx0x3) # 1. Introduction -TBD - This specification is specific to 64bit Intel and AMD processors conforming to the amd64 specification. Future revisions of this specification may include ARM64 conforming to the aarch64 specification as well. ## 1.1. Reserved Values @@ -149,11 +149,303 @@ The bf_handle_t structure is an opaque structure containing the handle used by m Defines which register a syscall is requesting. +#### 1.4.2.1. AMD + **enum, uint64_t: bf_reg_t** | Name | Value | Description | | :--- | :---- | :---------- | +| bf_reg_t_unsupported | 0 | defines the unsupported register | +| bf_reg_t_rbx | 1 | defines the rbx register | +| bf_reg_t_rcx | 2 | defines the rcx register | +| bf_reg_t_rdx | 3 | defines the rdx register | +| bf_reg_t_rbp | 4 | defines the rbp register | +| bf_reg_t_rsi | 5 | defines the rsi register | +| bf_reg_t_rdi | 6 | defines the rdi register | +| bf_reg_t_r8 | 7 | defines the r8 register | +| bf_reg_t_r9 | 8 | defines the r9 register | +| bf_reg_t_r10 | 9 | defines the r10 register | +| bf_reg_t_r11 | 10 | defines the r11 register | +| bf_reg_t_r12 | 11 | defines the r12 register | +| bf_reg_t_r13 | 12 | defines the r13 register | +| bf_reg_t_r14 | 13 | defines the r14 register | +| bf_reg_t_r15 | 14 | defines the r15 register | +| bf_reg_t_intercept_cr_read | 15 | defines the intercept_cr_read register | +| bf_reg_t_intercept_cr_write | 16 | defines the intercept_cr_write register | +| bf_reg_t_intercept_dr_read | 17 | defines the intercept_dr_read register | +| bf_reg_t_intercept_dr_write | 18 | defines the intercept_dr_write register | +| bf_reg_t_intercept_exception | 19 | defines the intercept_exception register | +| bf_reg_t_intercept_instruction1 | 20 | defines the intercept_instruction1 register | +| bf_reg_t_intercept_instruction2 | 21 | defines the intercept_instruction2 register | +| bf_reg_t_intercept_instruction3 | 22 | defines the intercept_instruction3 register | +| bf_reg_t_pause_filter_threshold | 23 | defines the pause_filter_threshold register | +| bf_reg_t_pause_filter_count | 24 | defines the pause_filter_count register | +| bf_reg_t_iopm_base_pa | 25 | defines the iopm_base_pa register | +| bf_reg_t_msrpm_base_pa | 26 | defines the msrpm_base_pa register | +| bf_reg_t_tsc_offset | 27 | defines the tsc_offset register | +| bf_reg_t_guest_asid | 28 | defines the guest_asid register | +| bf_reg_t_tlb_control | 29 | defines the tlb_control register | +| bf_reg_t_virtual_interrupt_a | 30 | defines the virtual_interrupt_a register | +| bf_reg_t_virtual_interrupt_b | 31 | defines the virtual_interrupt_b register | +| bf_reg_t_exitcode | 32 | defines the exitcode register | +| bf_reg_t_exitinfo1 | 33 | defines the exitinfo1 register | +| bf_reg_t_exitinfo2 | 34 | defines the exitinfo2 register | +| bf_reg_t_exitininfo | 35 | defines the exitininfo register | +| bf_reg_t_ctls1 | 36 | defines the ctls1 register | +| bf_reg_t_avic_apic_bar | 37 | defines the avic_apic_bar register | +| bf_reg_t_guest_pa_of_ghcb | 38 | defines the guest_pa_of_ghcb register | +| bf_reg_t_eventinj | 39 | defines the eventinj register | +| bf_reg_t_n_cr3 | 40 | defines the n_cr3 register | +| bf_reg_t_ctls2 | 41 | defines the ctls2 register | +| bf_reg_t_vmcb_clean_bits | 42 | defines the vmcb_clean_bits register | +| bf_reg_t_nrip | 43 | defines the nrip register | +| bf_reg_t_number_of_bytes_fetched | 44 | defines the number_of_bytes_fetched register | +| bf_reg_t_avic_apic_backing_page_ptr | 45 | defines the avic_apic_backing_page_ptr register | +| bf_reg_t_avic_logical_table_ptr | 46 | defines the avic_logical_table_ptr register | +| bf_reg_t_avic_physical_table_ptr | 47 | defines the avic_physical_table_ptr register | +| bf_reg_t_vmsa_ptr | 48 | defines the vmsa_ptr register | +| bf_reg_t_es_selector | 49 | defines the es_selector register | +| bf_reg_t_es_attrib | 50 | defines the es_attrib register | +| bf_reg_t_es_limit | 51 | defines the es_limit register | +| bf_reg_t_es_base | 52 | defines the es_base register | +| bf_reg_t_cs_selector | 53 | defines the cs_selector register | +| bf_reg_t_cs_attrib | 54 | defines the cs_attrib register | +| bf_reg_t_cs_limit | 55 | defines the cs_limit register | +| bf_reg_t_cs_base | 56 | defines the cs_base register | +| bf_reg_t_ss_selector | 57 | defines the ss_selector register | +| bf_reg_t_ss_attrib | 58 | defines the ss_attrib register | +| bf_reg_t_ss_limit | 59 | defines the ss_limit register | +| bf_reg_t_ss_base | 60 | defines the ss_base register | +| bf_reg_t_ds_selector | 61 | defines the ds_selector register | +| bf_reg_t_ds_attrib | 62 | defines the ds_attrib register | +| bf_reg_t_ds_limit | 63 | defines the ds_limit register | +| bf_reg_t_ds_base | 64 | defines the ds_base register | +| bf_reg_t_fs_selector | 65 | defines the fs_selector register | +| bf_reg_t_fs_attrib | 66 | defines the fs_attrib register | +| bf_reg_t_fs_limit | 67 | defines the fs_limit register | +| bf_reg_t_fs_base | 68 | defines the fs_base register | +| bf_reg_t_gs_selector | 69 | defines the gs_selector register | +| bf_reg_t_gs_attrib | 70 | defines the gs_attrib register | +| bf_reg_t_gs_limit | 71 | defines the gs_limit register | +| bf_reg_t_gs_base | 72 | defines the gs_base register | +| bf_reg_t_gdtr_selector | 73 | defines the gdtr_selector register | +| bf_reg_t_gdtr_attrib | 74 | defines the gdtr_attrib register | +| bf_reg_t_gdtr_limit | 75 | defines the gdtr_limit register | +| bf_reg_t_gdtr_base | 76 | defines the gdtr_base register | +| bf_reg_t_ldtr_selector | 77 | defines the ldtr_selector register | +| bf_reg_t_ldtr_attrib | 78 | defines the ldtr_attrib register | +| bf_reg_t_ldtr_limit | 79 | defines the ldtr_limit register | +| bf_reg_t_ldtr_base | 80 | defines the ldtr_base register | +| bf_reg_t_idtr_selector | 81 | defines the idtr_selector register | +| bf_reg_t_idtr_attrib | 82 | defines the idtr_attrib register | +| bf_reg_t_idtr_limit | 83 | defines the idtr_limit register | +| bf_reg_t_idtr_base | 84 | defines the idtr_base register | +| bf_reg_t_tr_selector | 85 | defines the tr_selector register | +| bf_reg_t_tr_attrib | 86 | defines the tr_attrib register | +| bf_reg_t_tr_limit | 87 | defines the tr_limit register | +| bf_reg_t_tr_base | 88 | defines the tr_base register | +| bf_reg_t_cpl | 89 | defines the cpl register | +| bf_reg_t_efer | 90 | defines the efer register | +| bf_reg_t_cr4 | 91 | defines the cr4 register | +| bf_reg_t_cr3 | 92 | defines the cr3 register | +| bf_reg_t_cr0 | 93 | defines the cr0 register | +| bf_reg_t_dr7 | 94 | defines the dr7 register | +| bf_reg_t_dr6 | 95 | defines the dr6 register | +| bf_reg_t_rflags | 96 | defines the rflags register | +| bf_reg_t_rip | 97 | defines the rip register | +| bf_reg_t_rsp | 98 | defines the rsp register | +| bf_reg_t_rax | 99 | defines the rax register | +| bf_reg_t_star | 100 | defines the star register | +| bf_reg_t_lstar | 101 | defines the lstar register | +| bf_reg_t_cstar | 102 | defines the cstar register | +| bf_reg_t_fmask | 103 | defines the fmask register | +| bf_reg_t_kernel_gs_base | 104 | defines the kernel_gs_base register | +| bf_reg_t_sysenter_cs | 105 | defines the sysenter_cs register | +| bf_reg_t_sysenter_esp | 106 | defines the sysenter_esp register | +| bf_reg_t_sysenter_eip | 107 | defines the sysenter_eip register | +| bf_reg_t_cr2 | 108 | defines the cr2 register | +| bf_reg_t_pat | 109 | defines the pat register | +| bf_reg_t_dbgctl | 110 | defines the dbgctl register | +| bf_reg_t_br_from | 111 | defines the br_from register | +| bf_reg_t_br_to | 112 | defines the br_to register | +| bf_reg_t_lastexcpfrom | 113 | defines the lastexcpfrom register | +| bf_reg_t_lastexcpto | 114 | defines the lastexcpto register | +| bf_reg_t_cr8 | 115 | defines the cr8 register | +| bf_reg_t_dr0 | 116 | defines the dr0 register | +| bf_reg_t_dr1 | 117 | defines the dr1 register | +| bf_reg_t_dr2 | 118 | defines the dr2 register | +| bf_reg_t_dr3 | 119 | defines the dr3 register | +| bf_reg_t_xcr0 | 120 | defines the xcr0 register | +| bf_reg_t_invalid | 121 | defines the invalid register | -TBD +#### 1.4.2.2. Intel + +**enum, uint64_t: bf_reg_t** +| Name | Value | Description | +| :--- | :---- | :---------- | +| BF_REG_T_UNSUPPORTED | 0 | defines the unsupported register | +| BF_REG_T_RAX | 1 | defines the rax register | +| BF_REG_T_RBX | 2 | defines the rbx register | +| BF_REG_T_RCX | 3 | defines the rcx register | +| BF_REG_T_RDX | 4 | defines the rdx register | +| BF_REG_T_RBP | 5 | defines the rbp register | +| BF_REG_T_RSI | 6 | defines the rsi register | +| BF_REG_T_RDI | 7 | defines the rdi register | +| BF_REG_T_R8 | 8 | defines the r8 register | +| BF_REG_T_R9 | 9 | defines the r9 register | +| BF_REG_T_R10 | 10 | defines the r10 register | +| BF_REG_T_R11 | 11 | defines the r11 register | +| BF_REG_T_R12 | 12 | defines the r12 register | +| BF_REG_T_R13 | 13 | defines the r13 register | +| BF_REG_T_R14 | 14 | defines the r14 register | +| BF_REG_T_R15 | 15 | defines the r15 register | +| BF_REG_T_CR2 | 16 | defines the cr2 register | +| BF_REG_T_DR6 | 17 | defines the dr6 register | +| BF_REG_T_STAR | 18 | defines the star register | +| BF_REG_T_LSTAR | 19 | defines the lstar register | +| BF_REG_T_CSTAR | 20 | defines the cstar register | +| BF_REG_T_FMASK | 21 | defines the fmask register | +| BF_REG_T_KERNEL_GS_BASE | 22 | defines the kernel_gs_base register | +| BF_REG_T_VIRTUAL_PROCESSOR_IDENTIFIER | 23 | defines the virtual_processor_identifier register | +| BF_REG_T_POSTED_INTERRUPT_NOTIFICATION_VECTOR | 24 | defines the posted_interrupt_notification_vector register | +| BF_REG_T_EPTP_INDEX | 25 | defines the eptp_index register | +| BF_REG_T_ES_SELECTOR | 26 | defines the es_selector register | +| BF_REG_T_CS_SELECTOR | 27 | defines the cs_selector register | +| BF_REG_T_SS_SELECTOR | 28 | defines the ss_selector register | +| BF_REG_T_DS_SELECTOR | 29 | defines the ds_selector register | +| BF_REG_T_FS_SELECTOR | 30 | defines the fs_selector register | +| BF_REG_T_GS_SELECTOR | 31 | defines the gs_selector register | +| BF_REG_T_LDTR_SELECTOR | 32 | defines the ldtr_selector register | +| BF_REG_T_TR_SELECTOR | 33 | defines the tr_selector register | +| BF_REG_T_INTERRUPT_STATUS | 34 | defines the interrupt_status register | +| BF_REG_T_PML_INDEX | 35 | defines the pml_index register | +| BF_REG_T_ADDRESS_OF_IO_BITMAP_A | 36 | defines the address_of_io_bitmap_a register | +| BF_REG_T_ADDRESS_OF_IO_BITMAP_B | 37 | defines the address_of_io_bitmap_b register | +| BF_REG_T_ADDRESS_OF_MSR_BITMAPS | 38 | defines the address_of_msr_bitmaps register | +| BF_REG_T_VMEXIT_MSR_STORE_ADDRESS | 39 | defines the vmexit_msr_store_address register | +| BF_REG_T_VMEXIT_MSR_LOAD_ADDRESS | 40 | defines the vmexit_msr_load_address register | +| BF_REG_T_VMENTRY_MSR_LOAD_ADDRESS | 41 | defines the vmentry_msr_load_address register | +| BF_REG_T_EXECUTIVE_VMCS_POINTER | 42 | defines the executive_vmcs_pointer register | +| BF_REG_T_PML_ADDRESS | 43 | defines the pml_address register | +| BF_REG_T_TSC_OFFSET | 44 | defines the tsc_offset register | +| BF_REG_T_VIRTUAL_APIC_ADDRESS | 45 | defines the virtual_apic_address register | +| BF_REG_T_APIC_ACCESS_ADDRESS | 46 | defines the apic_access_address register | +| BF_REG_T_POSTED_INTERRUPT_DESCRIPTOR_ADDRESS | 47 | defines the posted_interrupt_descriptor_address register | +| BF_REG_T_VM_FUNCTION_CONTROLS | 48 | defines the vm_function_controls register | +| BF_REG_T_EPT_POINTER | 49 | defines the ept_pointer register | +| BF_REG_T_EOI_EXIT_BITMAP0 | 50 | defines the eoi_exit_bitmap0 register | +| BF_REG_T_EOI_EXIT_BITMAP1 | 51 | defines the eoi_exit_bitmap1 register | +| BF_REG_T_EOI_EXIT_BITMAP2 | 52 | defines the eoi_exit_bitmap2 register | +| BF_REG_T_EOI_EXIT_BITMAP3 | 53 | defines the eoi_exit_bitmap3 register | +| BF_REG_T_EPTP_LIST_ADDRESS | 54 | defines the eptp_list_address register | +| BF_REG_T_VMREAD_BITMAP_ADDRESS | 55 | defines the vmread_bitmap_address register | +| BF_REG_T_VMWRITE_BITMAP_ADDRESS | 56 | defines the vmwrite_bitmap_address register | +| BF_REG_T_VIRT_EXCEPTION_INFORMATION_ADDRESS | 57 | defines the virt_exception_information_address register | +| BF_REG_T_XSS_EXITING_BITMAP | 58 | defines the xss_exiting_bitmap register | +| BF_REG_T_ENCLS_EXITING_BITMAP | 59 | defines the encls_exiting_bitmap register | +| BF_REG_T_SUB_PAGE_PERMISSION_TABLE_POINTER | 60 | defines the sub_page_permission_table_pointer register | +| BF_REG_T_TSC_MULTIPLIER | 61 | defines the tsc_multiplier register | +| BF_REG_T_PHYSICAL_ADDRESS | 62 | defines the physical_address register | +| BF_REG_T_VMCS_LINK_POINTER | 63 | defines the vmcs_link_pointer register | +| BF_REG_T_DEBUGCTL | 64 | defines the debugctl register | +| BF_REG_T_PAT | 65 | defines the pat register | +| BF_REG_T_EFER | 66 | defines the efer register | +| BF_REG_T_PERF_GLOBAL_CTRL | 67 | defines the perf_global_ctrl register | +| BF_REG_T_PDPTE0 | 68 | defines the pdpte0 register | +| BF_REG_T_PDPTE1 | 69 | defines the pdpte1 register | +| BF_REG_T_PDPTE2 | 70 | defines the pdpte2 register | +| BF_REG_T_PDPTE3 | 71 | defines the pdpte3 register | +| BF_REG_T_BNDCFGS | 72 | defines the bndcfgs register | +| BF_REG_T_RTIT_CTL | 73 | defines the rtit_ctl register | +| BF_REG_T_PIN_BASED_VM_EXECUTION_CTLS | 74 | defines the pin_based_vm_execution_ctls register | +| BF_REG_T_PRIMARY_PROC_BASED_VM_EXECUTION_CTLS | 75 | defines the primary_proc_based_vm_execution_ctls register | +| BF_REG_T_EXCEPTION_BITMAP | 76 | defines the exception_bitmap register | +| BF_REG_T_PAGE_FAULT_ERROR_CODE_MASK | 77 | defines the page_fault_error_code_mask register | +| BF_REG_T_PAGE_FAULT_ERROR_CODE_MATCH | 78 | defines the page_fault_error_code_match register | +| BF_REG_T_CR3_TARGET_COUNT | 79 | defines the cr3_target_count register | +| BF_REG_T_VMEXIT_CTLS | 80 | defines the vmexit_ctls register | +| BF_REG_T_VMEXIT_MSR_STORE_COUNT | 81 | defines the vmexit_msr_store_count register | +| BF_REG_T_VMEXIT_MSR_LOAD_COUNT | 82 | defines the vmexit_msr_load_count register | +| BF_REG_T_VMENTRY_CTLS | 83 | defines the vmentry_ctls register | +| BF_REG_T_VMENTRY_MSR_LOAD_COUNT | 84 | defines the vmentry_msr_load_count register | +| BF_REG_T_VMENTRY_INTERRUPT_INFORMATION_FIELD | 85 | defines the vmentry_interrupt_information_field register | +| BF_REG_T_VMENTRY_EXCEPTION_ERROR_CODE | 86 | defines the vmentry_exception_error_code register | +| BF_REG_T_VMENTRY_INSTRUCTION_LENGTH | 87 | defines the vmentry_instruction_length register | +| BF_REG_T_TPR_THRESHOLD | 88 | defines the tpr_threshold register | +| BF_REG_T_SECONDARY_PROC_BASED_VM_EXECUTION_CTLS | 89 | defines the secondary_proc_based_vm_execution_ctls register | +| BF_REG_T_PLE_GAP | 90 | defines the ple_gap register | +| BF_REG_T_PLE_WINDOW | 91 | defines the ple_window register | +| BF_REG_T_VM_INSTRUCTION_ERROR | 92 | defines the vm_instruction_error register | +| BF_REG_T_EXIT_REASON | 93 | defines the exit_reason register | +| BF_REG_T_VMEXIT_INTERRUPTION_INFORMATION | 94 | defines the vmexit_interruption_information register | +| BF_REG_T_VMEXIT_INTERRUPTION_ERROR_CODE | 95 | defines the vmexit_interruption_error_code register | +| BF_REG_T_IDT_VECTORING_INFORMATION_FIELD | 96 | defines the idt_vectoring_information_field register | +| BF_REG_T_IDT_VECTORING_ERROR_CODE | 97 | defines the idt_vectoring_error_code register | +| BF_REG_T_VMEXIT_INSTRUCTION_LENGTH | 98 | defines the vmexit_instruction_length register | +| BF_REG_T_VMEXIT_INSTRUCTION_INFORMATION | 99 | defines the vmexit_instruction_information register | +| BF_REG_T_ES_LIMIT | 100 | defines the es_limit register | +| BF_REG_T_CS_LIMIT | 101 | defines the cs_limit register | +| BF_REG_T_SS_LIMIT | 102 | defines the ss_limit register | +| BF_REG_T_DS_LIMIT | 103 | defines the ds_limit register | +| BF_REG_T_FS_LIMIT | 104 | defines the fs_limit register | +| BF_REG_T_GS_LIMIT | 105 | defines the gs_limit register | +| BF_REG_T_LDTR_LIMIT | 106 | defines the ldtr_limit register | +| BF_REG_T_TR_LIMIT | 107 | defines the tr_limit register | +| BF_REG_T_GDTR_LIMIT | 108 | defines the gdtr_limit register | +| BF_REG_T_IDTR_LIMIT | 109 | defines the idtr_limit register | +| BF_REG_T_ES_ATTRIB | 110 | defines the es_attrib register | +| BF_REG_T_CS_ATTRIB | 111 | defines the cs_attrib register | +| BF_REG_T_SS_ATTRIB | 112 | defines the ss_attrib register | +| BF_REG_T_DS_ATTRIB | 113 | defines the ds_attrib register | +| BF_REG_T_FS_ATTRIB | 114 | defines the fs_attrib register | +| BF_REG_T_GS_ATTRIB | 115 | defines the gs_attrib register | +| BF_REG_T_LDTR_ATTRIB | 116 | defines the ldtr_attrib register | +| BF_REG_T_TR_ATTRIB | 117 | defines the tr_attrib register | +| BF_REG_T_INTERRUPTIBILITY_STATE | 118 | defines the interruptibility_state register | +| BF_REG_T_ACTIVITY_STATE | 119 | defines the activity_state register | +| BF_REG_T_SMBASE | 120 | defines the smbase register | +| BF_REG_T_SYSENTER_CS | 121 | defines the sysenter_cs register | +| BF_REG_T_VMX_PREEMPTION_TIMER_VALUE | 122 | defines the vmx_preemption_timer_value register | +| BF_REG_T_CR0_GUEST_HOST_MASK | 123 | defines the cr0_guest_host_mask register | +| BF_REG_T_CR4_GUEST_HOST_MASK | 124 | defines the cr4_guest_host_mask register | +| BF_REG_T_CR0_READ_SHADOW | 125 | defines the cr0_read_shadow register | +| BF_REG_T_CR4_READ_SHADOW | 126 | defines the cr4_read_shadow register | +| BF_REG_T_CR3_TARGET_VALUE0 | 127 | defines the cr3_target_value0 register | +| BF_REG_T_CR3_TARGET_VALUE1 | 128 | defines the cr3_target_value1 register | +| BF_REG_T_CR3_TARGET_VALUE2 | 129 | defines the cr3_target_value2 register | +| BF_REG_T_CR3_TARGET_VALUE3 | 130 | defines the cr3_target_value3 register | +| BF_REG_T_EXIT_QUALIFICATION | 131 | defines the exit_qualification register | +| BF_REG_T_IO_RCX | 132 | defines the io_rcx register | +| BF_REG_T_IO_RSI | 133 | defines the io_rsi register | +| BF_REG_T_IO_RDI | 134 | defines the io_rdi register | +| BF_REG_T_IO_RIP | 135 | defines the io_rip register | +| BF_REG_T_LINEAR_ADDRESS | 136 | defines the linear_address register | +| BF_REG_T_CR0 | 137 | defines the cr0 register | +| BF_REG_T_CR3 | 138 | defines the cr3 register | +| BF_REG_T_CR4 | 139 | defines the cr4 register | +| BF_REG_T_ES_BASE | 140 | defines the es_base register | +| BF_REG_T_CS_BASE | 141 | defines the cs_base register | +| BF_REG_T_SS_BASE | 142 | defines the ss_base register | +| BF_REG_T_DS_BASE | 143 | defines the ds_base register | +| BF_REG_T_FS_BASE | 144 | defines the fs_base register | +| BF_REG_T_GS_BASE | 145 | defines the gs_base register | +| BF_REG_T_LDTR_BASE | 146 | defines the ldtr_base register | +| BF_REG_T_TR_BASE | 147 | defines the tr_base register | +| BF_REG_T_GDTR_BASE | 148 | defines the gdtr_base register | +| BF_REG_T_IDTR_BASE | 149 | defines the idtr_base register | +| BF_REG_T_DR7 | 150 | defines the dr7 register | +| BF_REG_T_RSP | 151 | defines the rsp register | +| BF_REG_T_RIP | 152 | defines the rip register | +| BF_REG_T_RFLAGS | 153 | defines the rflags register | +| BF_REG_T_PENDING_DEBUG_EXCEPTIONS | 154 | defines the pending_debug_exceptions register | +| BF_REG_T_SYSENTER_ESP | 155 | defines the sysenter_esp register | +| BF_REG_T_SYSENTER_EIP | 156 | defines the sysenter_eip register | +| BF_REG_T_CR8 | 157 | defines the cr8 register | +| BF_REG_T_DR0 | 158 | defines the dr0 register | +| BF_REG_T_DR1 | 159 | defines the dr1 register | +| BF_REG_T_DR2 | 160 | defines the dr2 register | +| BF_REG_T_DR3 | 161 | defines the dr3 register | +| BF_REG_T_XCR0 | 162 | defines the xcr0 register | +| BF_REG_T_INVALID | 163 | defines the invalid register | ### 1.4.3. Exit Type @@ -614,7 +906,7 @@ This syscall tells the microkernel that the extension would like to wait for a c | :---- | :---------- | | 0x0000000000000001 | Defines the index for bf_control_op_wait | -### 2.9.2. bf_control_op_again, OP=0x0, IDX=0x2 +### 2.9.3. bf_control_op_again, OP=0x0, IDX=0x2 This syscall tells the microkernel that the extension would like to try again from a fast fail callback. This syscall is a blocking syscall that never returns and should be used to return from the fail_entry function. @@ -851,7 +1143,7 @@ A Virtual Machine or VM virtually represents a physical computer. Although the m One important resource within the microkernel that changes when a VM changes is the direct map each extension is given. When a VM changes, the direct map an extension uses to access physical memory also changes. -### 2.13.2. bf_vm_op_create_vm, OP=0x4, IDX=0x0 +### 2.13.1. bf_vm_op_create_vm, OP=0x4, IDX=0x0 This syscall tells the microkernel to create a VM and return its ID. @@ -871,7 +1163,7 @@ This syscall tells the microkernel to create a VM and return its ID. | :---- | :---------- | | 0x0000000000000000 | Defines the index for bf_vm_op_create_vm | -### 2.13.3. bf_vm_op_destroy_vm, OP=0x4, IDX=0x1 +### 2.13.2. bf_vm_op_destroy_vm, OP=0x4, IDX=0x1 This syscall tells the microkernel to destroy a VM given an ID. @@ -911,7 +1203,7 @@ This syscall tells the microkernel to map a physical address into the VM's direc | :---- | :---------- | | 0x0000000000000002 | Defines the index for bf_vm_op_map_direct | -### 2.13.3. bf_vm_op_unmap_direct, OP=0x4, IDX=0x3 +### 2.13.4. bf_vm_op_unmap_direct, OP=0x4, IDX=0x3 This syscall tells the microkernel to unmap a previously mapped virtual address in the direct map. Unlike bf_vm_op_unmap_direct_broadcast, this syscall does not flush the TLB on any other PP, meaning this unmap is local to the PP the call is made on. Attempting to unmap a virtual address from the direct map that has been accessed on any other PP other than the PP this syscall is executed on will result in undefined behavior. This syscall is designed to support mapping and then immediately unmapping a physical address on a single PP during a single VMExit. It can also be used to map on a PP and then use unmap on the same PP during multiple VMExits, but special care must be taken to ensure no other PP can access the map, otherwise UB will occur. @@ -929,7 +1221,7 @@ This syscall tells the microkernel to unmap a previously mapped virtual address | :---- | :---------- | | 0x0000000000000003 | Defines the index for bf_vm_op_unmap_direct | -### 2.13.3. bf_vm_op_unmap_direct_broadcast, OP=0x4, IDX=0x4 +### 2.13.5. bf_vm_op_unmap_direct_broadcast, OP=0x4, IDX=0x4 This syscall tells the microkernel to unmap a previously mapped virtual address in the direct map. Unlike bf_vm_op_unmap_direct, this syscall performs a broadcast TLB flush which means it can be safely used on all direct mapped addresses. The downside of using this function is that it can be a lot slower than bf_vm_op_unmap_direct, especially on systems with a lot of PPs. @@ -947,7 +1239,7 @@ This syscall tells the microkernel to unmap a previously mapped virtual address | :---- | :---------- | | 0x0000000000000004 | Defines the index for bf_vm_op_unmap_direct_broadcast | -### 2.15.3. bf_vm_op_tlb_flush, OP=0x4, IDX=0x5 +### 2.13.6. bf_vm_op_tlb_flush, OP=0x4, IDX=0x5 Given the ID of a VM, invalidates the VM's TLB on the PP that this is executed on. @@ -965,11 +1257,9 @@ Given the ID of a VM, invalidates the VM's TLB on the PP that this is executed o ## 2.14. Virtual Processor Syscalls -A Virtual Processor or VP virtually represents a PP. Although the microkernel has an internal representation of a VP, it doesn't understand what a VP is outside of resource management, and it is up to the extension to define what a VM is and how it should operate. +A Virtual Processor or VP virtually represents a PP. Although the microkernel has an internal representation of a VP, it doesn't understand what a VP is outside of resource management, and it is up to the extension to define what a VP is and how it should operate. -Once a VP is run, it is assigned to the VM it was run on, and cannot be run on any other VM for the remainder of it's lifetime. A VP is also assigned to a specific PP (physical processor). Unlike the assigned VM, the assigned PP can be changed by migrating the VP to another PP. - -### 2.14.2. bf_vp_op_create_vp, OP=0x5, IDX=0x0 +### 2.14.1. bf_vp_op_create_vp, OP=0x5, IDX=0x0 This syscall tells the microkernel to create a VP given the ID of the VM the VP will be assigned to. Upon success, this syscall returns the ID of the newly created VP. @@ -991,7 +1281,7 @@ This syscall tells the microkernel to create a VP given the ID of the VM the VP | :---- | :---------- | | 0x0000000000000000 | Defines the index for bf_vp_op_create_vp | -### 2.14.3. bf_vp_op_destroy_vp, OP=0x5, IDX=0x1 +### 2.14.2. bf_vp_op_destroy_vp, OP=0x5, IDX=0x1 This syscall tells the microkernel to destroy a VP given an ID. @@ -1007,11 +1297,11 @@ This syscall tells the microkernel to destroy a VP given an ID. | :---- | :---------- | | 0x0000000000000001 | Defines the index for bf_vp_op_destroy_vp | -## 2.14.5. Virtual Processor State Syscalls +## 2.15. Virtual Processor State Syscalls -TODO +A Virtual Processor State or VS virtually represents a PP's state. Most operations performed by an extension will be through a VS. When a VS is created, it is assigned to a VP and PP. To change the PP, a VS must be migrated. -### 2.14.7. bf_vs_op_create_vs, OP=0x6, IDX=0x0 +### 2.15.1. bf_vs_op_create_vs, OP=0x6, IDX=0x0 This syscall tells the microkernel to create a VS given the IDs of the VP and PP the VS will be assigned to. Upon success, this syscall returns the ID of the newly created VS. @@ -1035,7 +1325,7 @@ This syscall tells the microkernel to create a VS given the IDs of the VP and PP | :---- | :---------- | | 0x0000000000000000 | Defines the index for bf_vs_op_create_vs | -### 2.14.8. bf_vs_op_destroy_vs, OP=0x6, IDX=0x1 +### 2.15.2. bf_vs_op_destroy_vs, OP=0x6, IDX=0x1 This syscall tells the microkernel to destroy a VS given an ID. @@ -1051,7 +1341,7 @@ This syscall tells the microkernel to destroy a VS given an ID. | :---- | :---------- | | 0x0000000000000001 | Defines the index for bf_vs_op_destroy_vs | -### 2.14.9. bf_vs_op_init_as_root, OP=0x6, IDX=0x2 +### 2.15.3. bf_vs_op_init_as_root, OP=0x6, IDX=0x2 This syscall tells the microkernel to initialize a VS using the root VP state provided by the loader using the current PPID. @@ -1067,7 +1357,7 @@ This syscall tells the microkernel to initialize a VS using the root VP state pr | :---- | :---------- | | 0x0000000000000002 | Defines the index for bf_vs_op_init_as_root | -### 2.14.10. bf_vs_op_read, OP=0x6, IDX=0x3 +### 2.15.4. bf_vs_op_read, OP=0x6, IDX=0x3 Reads a CPU register from the VS given a bf_reg_t. Note that the bf_reg_t is architecture-specific. @@ -1089,7 +1379,7 @@ Reads a CPU register from the VS given a bf_reg_t. Note that the bf_reg_t is arc | :---- | :---------- | | 0x0000000000000003 | Defines the index for bf_vs_op_read | -### 2.14.11. bf_vs_op_write, OP=0x6, IDX=0x4 +### 2.15.5. bf_vs_op_write, OP=0x6, IDX=0x4 Writes to a CPU register in the VS given a bf_reg_t and the value to write. Note that the bf_reg_t is architecture-specific. @@ -1107,9 +1397,9 @@ Writes to a CPU register in the VS given a bf_reg_t and the value to write. Note | :---- | :---------- | | 0x0000000000000004 | Defines the index for bf_vs_op_write | -### 2.14.12. bf_vs_op_run, OP=0x6, IDX=0x5 +### 2.15.6. bf_vs_op_run, OP=0x6, IDX=0x5 -TODO +Executes a VS given the ID of the VM, VP and VS to execute. The VS must be assigned to the provided VP and the provided VP must be assigned to the provided VM. The VP and VS must not be executing on any other PP, and the VS must be assigned to the PP this syscall is executed on. Upon success, this syscall will not return. **Input:** | Register Name | Bits | Description | @@ -1127,7 +1417,7 @@ TODO | :---- | :---------- | | 0x0000000000000005 | Defines the index for bf_vs_op_run | -### 2.14.13. bf_vs_op_run_current, OP=0x6, IDX=0x6 +### 2.15.7. bf_vs_op_run_current, OP=0x6, IDX=0x6 bf_vs_op_run_current tells the microkernel to execute the currently active VS, VP and VM. @@ -1141,9 +1431,9 @@ bf_vs_op_run_current tells the microkernel to execute the currently active VS, V | :---- | :---------- | | 0x0000000000000006 | Defines the index for bf_vs_op_run_current | -### 2.14.14. bf_vs_op_advance_ip_and_run_impl, OP=0x6, IDX=0x7 +### 2.15.8. bf_vs_op_advance_ip_and_run_impl, OP=0x6, IDX=0x7 -TODO +Advances the IP and executes a VS given the ID of the VM, VP and VS to execute. The VS must be assigned to the provided VP and the provided VP must be assigned to the provided VM. The VP and VS must not be executing on any other PP, and the VS must be assigned to the PP this syscall is executed on. Upon success, this syscall will not return. **Input:** | Register Name | Bits | Description | @@ -1157,9 +1447,9 @@ TODO | :---- | :---------- | | 0x0000000000000007 | Defines the index for bf_vs_op_advance_ip_and_run_impl | -### 2.14.15. bf_vs_op_advance_ip_and_run_current, OP=0x6, IDX=0x8 +### 2.15.9. bf_vs_op_advance_ip_and_run_current, OP=0x6, IDX=0x8 -TODO +bf_vs_op_advance_ip_and_run_current tells the microkernel to advance the IP of and execute the currently active VS, VP and VM. **Input:** | Register Name | Bits | Description | @@ -1171,7 +1461,7 @@ TODO | :---- | :---------- | | 0x0000000000000008 | Defines the index for bf_vs_op_advance_ip_and_run_current | -### 2.14.16. bf_vs_op_promote, OP=0x6, IDX=0x9 +### 2.15.10. bf_vs_op_promote, OP=0x6, IDX=0x9 bf_vs_op_promote tells the microkernel to promote the requested VS. bf_vs_op_promote will stop the hypervisor on the physical processor and replace its state with the state in the given VS. Note that this syscall only returns on error. @@ -1187,7 +1477,7 @@ bf_vs_op_promote tells the microkernel to promote the requested VS. bf_vs_op_pro | :---- | :---------- | | 0x0000000000000009 | Defines the index for bf_vs_op_promote | -### 2.14.17. bf_vs_op_clear, OP=0x6, IDX=0xA +### 2.15.11. bf_vs_op_clear, OP=0x6, IDX=0xA bf_vs_op_clear tells the microkernel to clear the VS's hardware cache, if one exists. How this is used depends entirely on the hardware and is associated with AMD's VMCB Clean Bits, and Intel's VMClear instruction. See the associated documentation for more details. On AMD, this ABI clears the entire VMCB. For more fine grained control, use the write ABIs to manually modify the VMCB. @@ -1203,9 +1493,9 @@ bf_vs_op_clear tells the microkernel to clear the VS's hardware cache, if one ex | :---- | :---------- | | 0x000000000000000A | Defines the index for bf_vs_op_clear | -### 2.14.17. bf_vs_op_migrate, OP=0x6, IDX=0xB +### 2.15.12. bf_vs_op_migrate, OP=0x6, IDX=0xB -TODO +Migrates a VS to the provided PP. The VS must not be active. **Input:** | Register Name | Bits | Description | @@ -1221,7 +1511,7 @@ TODO | :---- | :---------- | | 0x000000000000000B | Defines the index for bf_vs_op_migrate | -### 2.14.17. bf_vs_op_set_active, OP=0x6, IDX=0xC +### 2.15.13. bf_vs_op_set_active, OP=0x6, IDX=0xC Sets the active VM, VP and VS to the provided VM, VP and VS. @@ -1241,7 +1531,7 @@ Sets the active VM, VP and VS to the provided VM, VP and VS. | :---- | :---------- | | 0x000000000000000C | Defines the index for bf_vs_op_set_active | -### 2.14.17. bf_vs_op_advance_ip_and_set_active, OP=0x6, IDX=0xD +### 2.15.14. bf_vs_op_advance_ip_and_set_active, OP=0x6, IDX=0xD Advances the IP of the current VS and then sets the active VM, VP and VS to the provided VM, VP and VS. @@ -1261,7 +1551,7 @@ Advances the IP of the current VS and then sets the active VM, VP and VS to the | :---- | :---------- | | 0x000000000000000D | Defines the index for bf_vs_op_advance_ip_and_set_active | -### 2.15.3. bf_vs_op_tlb_flush, OP=0x6, IDX=0xE +### 2.15.15. bf_vs_op_tlb_flush, OP=0x6, IDX=0xE Given the ID of a VS, invalidates a TLB entry for a given GLA on the PP that this is executed on. @@ -1278,9 +1568,9 @@ Given the ID of a VS, invalidates a TLB entry for a given GLA on the PP that thi | :---- | :---------- | | 0x000000000000000E | Defines the index for bf_vs_op_tlb_flush | -## 2.15. Intrinsic Syscalls +## 2.16. Intrinsic Syscalls -### 2.15.1. bf_intrinsic_op_rdmsr, OP=0x7, IDX=0x0 +### 2.16.1. bf_intrinsic_op_rdmsr, OP=0x7, IDX=0x0 Reads an MSR directly from the CPU given the address of the MSR to read. Note that this is specific to Intel/AMD only. Also note that not all MSRs can be written to, and which MSRs that can be written to is up to the microkernel's internal policy as well as which architecture the hypervisor is running on. @@ -1301,7 +1591,7 @@ Reads an MSR directly from the CPU given the address of the MSR to read. Note th | :---- | :---------- | | 0x0000000000000000 | Defines the index for bf_intrinsic_op_rdmsr | -### 2.15.2. bf_intrinsic_op_wrmsr, OP=0x7, IDX=0x1 +### 2.16.2. bf_intrinsic_op_wrmsr, OP=0x7, IDX=0x1 Writes to an MSR directly from the CPU given the address of the MSR to write and the value to write. Note that this is specific to Intel/AMD only. Also note that not all MSRs can be written to, and which MSRs that can be written to is up to the microkernel's internal policy as well as which architecture the hypervisor is running on. @@ -1318,7 +1608,7 @@ Writes to an MSR directly from the CPU given the address of the MSR to write and | :---- | :---------- | | 0x0000000000000001 | Defines the index for bf_intrinsic_op_wrmsr | -## 2.16. Mem Syscalls +## 2.17. Mem Syscalls Each extension has access to several different memory pools: - The page pool (used for allocating pages) @@ -1335,7 +1625,7 @@ Thread-Local Storage (TLS) memory (typically allocated using `thread_local`) pro The direct map provides an extension with a means to access any physical address by accessing the direct map region of the virtual address space (depends on the hypervisor's configuration). By default, on Intel/AMD with 4-level paging, this region starts at 0x0000600000000000, but it can be changed using CMake. An extension can access any physical address by simply adding 0x0000600000000000 to the physical address and dereferencing the resulting value. When a VM is destroyed, all physical memory maps associated with that VM will be removed. The direct map is also where page and huge page allocations are mapped, providing an extension with a simple means for performing a virtual address to physical address (and vice versa) translations. -### 2.16.1. bf_mem_op_alloc_page, OP=0x8, IDX=0x0 +### 2.17.1. bf_mem_op_alloc_page, OP=0x8, IDX=0x0 bf_mem_op_alloc_page allocates a page, and maps this page into the direct map of the VM. @@ -1355,7 +1645,7 @@ bf_mem_op_alloc_page allocates a page, and maps this page into the direct map of | :---- | :---------- | | 0x0000000000000000 | Defines the index for bf_mem_op_alloc_page | -### 2.16.2. bf_mem_op_free_page, OP=0x8, IDX=0x1 +### 2.17.2. bf_mem_op_free_page, OP=0x8, IDX=0x1 Frees a page previously allocated by bf_mem_op_alloc_page. This operation is optional and not all microkernels may implement it. @@ -1375,7 +1665,7 @@ Frees a page previously allocated by bf_mem_op_alloc_page. This operation is opt | 0x0000000000000001 | Defines the index for bf_mem_op_free_page | -### 2.16.3. bf_mem_op_alloc_huge, OP=0x8, IDX=0x2 +### 2.17.3. bf_mem_op_alloc_huge, OP=0x8, IDX=0x2 bf_mem_op_alloc_huge allocates a physically contiguous block of memory. When allocating a page, the extension should keep in mind the following: - The total memory available to allocate from this pool is extremely limited. This should only be used when absolutely needed, and extensions should not expect more than 1 MB (might be less) of total memory available. @@ -1398,7 +1688,7 @@ bf_mem_op_alloc_huge allocates a physically contiguous block of memory. When all | :---- | :---------- | | 0x0000000000000002 | Defines the index for bf_mem_op_alloc_huge | -### 2.16.4. bf_mem_op_free_huge, OP=0x8, IDX=0x3 +### 2.17.4. bf_mem_op_free_huge, OP=0x8, IDX=0x3 Frees memory previously allocated by bf_mem_op_alloc_huge. This operation is optional and not all microkernels may implement it. diff --git a/example/README.md b/example/README.md deleted file mode 100644 index 2009a832..00000000 --- a/example/README.md +++ /dev/null @@ -1,31 +0,0 @@ -# Description - -The goal of each of these examples is to provide a starting point for creating your own extensions. For more information about how to create your own extension, please see [Writing Your Own Extensions](https://github.com/Bareflank/hypervisor#writing-your-own-extensions). - -## default - -This example provide the minimum extension that is needed to start/stop the hypervisor. In other words, this is your typical "Hello World" example. If you plan to implement everything yourself, this is a good starting point. This example is also the "default" example if you don't specify an extension manually in the build system. - -## rdtsc -TBD - demonstrates how to hook the execution of the RDTSC and RDTSCP instructions. - -## msr -TBD - demonstrates how to hook the execution of specific MSR instructions using the MSR bitmap. - -## cr -TBD - demonstrates how to hook the execution of the control registers and properly emulate their execution, including how to hide certain bits from the OS using the control register shadows. - -## io -TBD - demonstrates how to hook the execution of port IO instructions. - -## ept -TBD - basic EPT example including how to handle the MTTRs on Intel. Just enough to turn EPT on. - -## uefi -TBD - Provides enough EPT, Unrestricted Guest Support, CR0/CR4 and INIT/SIPI logic to start the hypervisor from UEFI and then boot Windows/Linux - -## interrupts -TBD - Provides an example of how to trap on external interrupts and inject them back into the root OS. - -## ddimon -TBD - Provides an example with functionality similar to DdiMon from HyperPlatform, capable of hooking kernel level functions and monitoring there execution. diff --git a/example/default/CMakeLists.txt b/example/default/CMakeLists.txt index 5e752680..e23c15ab 100644 --- a/example/default/CMakeLists.txt +++ b/example/default/CMakeLists.txt @@ -130,7 +130,9 @@ if(HYPERVISOR_TARGET_ARCH STREQUAL "AuthenticAMD" OR HYPERVISOR_TARGET_ARCH STRE if(HYPERVISOR_TARGET_ARCH STREQUAL "AuthenticAMD") list(APPEND HEADERS ${CMAKE_CURRENT_LIST_DIR}/src/x64/amd/dispatch_vmexit.hpp + ${CMAKE_CURRENT_LIST_DIR}/src/x64/amd/gs_initialize.hpp ${CMAKE_CURRENT_LIST_DIR}/src/x64/amd/gs_t.hpp + ${CMAKE_CURRENT_LIST_DIR}/src/x64/amd/tls_initialize.hpp ${CMAKE_CURRENT_LIST_DIR}/src/x64/amd/tls_t.hpp ${CMAKE_CURRENT_LIST_DIR}/src/x64/amd/vs_t.hpp ) @@ -141,7 +143,9 @@ if(HYPERVISOR_TARGET_ARCH STREQUAL "AuthenticAMD" OR HYPERVISOR_TARGET_ARCH STRE ${CMAKE_CURRENT_LIST_DIR}/src/x64/intel/dispatch_vmexit_nmi_window.hpp ${CMAKE_CURRENT_LIST_DIR}/src/x64/intel/dispatch_vmexit_nmi.hpp ${CMAKE_CURRENT_LIST_DIR}/src/x64/intel/dispatch_vmexit.hpp + ${CMAKE_CURRENT_LIST_DIR}/src/x64/intel/gs_initialize.hpp ${CMAKE_CURRENT_LIST_DIR}/src/x64/intel/gs_t.hpp + ${CMAKE_CURRENT_LIST_DIR}/src/x64/intel/tls_initialize.hpp ${CMAKE_CURRENT_LIST_DIR}/src/x64/intel/tls_t.hpp ${CMAKE_CURRENT_LIST_DIR}/src/x64/intel/vs_t.hpp ) diff --git a/example/default/src/x64/amd/vs_t.hpp b/example/default/src/x64/amd/vs_t.hpp index fadbe83d..f6ad8187 100644 --- a/example/default/src/x64/amd/vs_t.hpp +++ b/example/default/src/x64/amd/vs_t.hpp @@ -141,9 +141,7 @@ namespace example bsl::safe_u16 const &vpid, bsl::safe_u16 const &ppid) noexcept -> bsl::safe_u16 { - auto const vsid{this->id()}; - - bsl::expects(vsid != syscall::BF_INVALID_ID); + bsl::expects(this->id() != syscall::BF_INVALID_ID); bsl::expects(allocated_status_t::deallocated == m_allocated); bsl::expects(vpid.is_valid_and_checked()); @@ -178,7 +176,7 @@ namespace example m_assigned_ppid = ~ppid; m_allocated = allocated_status_t::allocated; - return vsid; + return this->id(); } /// diff --git a/example/default/src/x64/intel/vs_t.hpp b/example/default/src/x64/intel/vs_t.hpp index 096073e8..6f0c7057 100644 --- a/example/default/src/x64/intel/vs_t.hpp +++ b/example/default/src/x64/intel/vs_t.hpp @@ -40,21 +40,6 @@ namespace example { - /// - /// @brief Returns the masked version of the VMCS control fields - /// - /// - /// @param val the value of the control fields read from the MSRs - /// @return The masked version of the control fields. - /// - [[nodiscard]] constexpr auto - ctls_mask(bsl::safe_u64 const &val) noexcept -> bsl::safe_u64 - { - constexpr auto mask{0x00000000FFFFFFFF_u64}; - constexpr auto shift{32_u64}; - return ((val & mask) & (val >> shift)).checked(); - }; - /// /// @brief Defines the extension's notion of a VS /// @@ -157,9 +142,8 @@ namespace example bsl::safe_u16 const &ppid) noexcept -> bsl::safe_u16 { syscall::bf_reg_t mut_idx{}; - auto const vsid{this->id()}; - bsl::expects(vsid != syscall::BF_INVALID_ID); + bsl::expects(this->id() != syscall::BF_INVALID_ID); bsl::expects(allocated_status_t::deallocated == m_allocated); bsl::expects(vpid.is_valid_and_checked()); @@ -167,17 +151,16 @@ namespace example bsl::expects(ppid.is_valid_and_checked()); bsl::expects(ppid != syscall::BF_INVALID_ID); - bsl::discard(gs); bsl::discard(tls); bsl::discard(intrinsic); - auto const vmcs_vpid_val{bsl::safe_u64::magic_1()}; + constexpr auto vmcs_vpid_val{0x1_u64}; constexpr auto vmcs_vpid_idx{syscall::bf_reg_t::bf_reg_t_virtual_processor_identifier}; - bsl::expects(mut_sys.bf_vs_op_write(vsid, vmcs_vpid_idx, vmcs_vpid_val)); + bsl::expects(mut_sys.bf_vs_op_write(this->id(), vmcs_vpid_idx, vmcs_vpid_val)); constexpr auto vmcs_link_ptr_val{0xFFFFFFFFFFFFFFFF_u64}; constexpr auto vmcs_link_ptr_idx{syscall::bf_reg_t::bf_reg_t_vmcs_link_pointer}; - bsl::expects(mut_sys.bf_vs_op_write(vsid, vmcs_link_ptr_idx, vmcs_link_ptr_val)); + bsl::expects(mut_sys.bf_vs_op_write(this->id(), vmcs_link_ptr_idx, vmcs_link_ptr_val)); bsl::safe_u64 mut_pin_ctls{}; bsl::safe_u64 mut_proc_ctls{}; @@ -208,22 +191,25 @@ namespace example mut_proc2_ctls |= enable_uwait; mut_idx = syscall::bf_reg_t::bf_reg_t_pin_based_vm_execution_ctls; - bsl::expects(mut_sys.bf_vs_op_write(vsid, mut_idx, mut_pin_ctls)); + bsl::expects(mut_sys.bf_vs_op_write(this->id(), mut_idx, mut_pin_ctls)); mut_idx = syscall::bf_reg_t::bf_reg_t_primary_proc_based_vm_execution_ctls; - bsl::expects(mut_sys.bf_vs_op_write(vsid, mut_idx, mut_proc_ctls)); + bsl::expects(mut_sys.bf_vs_op_write(this->id(), mut_idx, mut_proc_ctls)); mut_idx = syscall::bf_reg_t::bf_reg_t_vmexit_ctls; - bsl::expects(mut_sys.bf_vs_op_write(vsid, mut_idx, mut_exit_ctls)); + bsl::expects(mut_sys.bf_vs_op_write(this->id(), mut_idx, mut_exit_ctls)); mut_idx = syscall::bf_reg_t::bf_reg_t_vmentry_ctls; - bsl::expects(mut_sys.bf_vs_op_write(vsid, mut_idx, mut_entry_ctls)); + bsl::expects(mut_sys.bf_vs_op_write(this->id(), mut_idx, mut_entry_ctls)); mut_idx = syscall::bf_reg_t::bf_reg_t_secondary_proc_based_vm_execution_ctls; - bsl::expects(mut_sys.bf_vs_op_write(vsid, mut_idx, mut_proc2_ctls)); + bsl::expects(mut_sys.bf_vs_op_write(this->id(), mut_idx, mut_proc2_ctls)); - if (mut_sys.is_vs_a_root_vs(vsid)) { - bsl::expects(mut_sys.bf_vs_op_init_as_root(vsid)); + mut_idx = syscall::bf_reg_t::bf_reg_t_address_of_msr_bitmaps; + bsl::expects(mut_sys.bf_vs_op_write(this->id(), mut_idx, gs.msr_bitmap_phys)); + + if (mut_sys.is_vs_a_root_vs(this->id())) { + bsl::expects(mut_sys.bf_vs_op_init_as_root(this->id())); } else { bsl::touch(); @@ -233,7 +219,7 @@ namespace example m_assigned_ppid = ~ppid; m_allocated = allocated_status_t::allocated; - return vsid; + return this->id(); } /// diff --git a/example/default_rust/src/.cargo/config.toml b/example/default_rust/.cargo/config.toml similarity index 100% rename from example/default_rust/src/.cargo/config.toml rename to example/default_rust/.cargo/config.toml diff --git a/example/default_rust/CMakeLists.txt b/example/default_rust/CMakeLists.txt index 3b348bb7..9c909d59 100644 --- a/example/default_rust/CMakeLists.txt +++ b/example/default_rust/CMakeLists.txt @@ -42,6 +42,85 @@ include(ExternalProject) # Rust # ------------------------------------------------------------------------------ +# NOTE: +# - Autogenerate the Cargo.toml with the configuration from CMake so that +# both projects match. +# + +if(NOT EXISTS ${CMAKE_BINARY_DIR}/rust_files.txt) + + # -------------------------------------------------------------------------- + # Rebuild Flag + # -------------------------------------------------------------------------- + + set(HYPERVISOR_CONSTANTS ${CMAKE_BINARY_DIR}/rust_files.txt) + file(WRITE ${CMAKE_BINARY_DIR}/rust_files.txt "touched\n") + + # -------------------------------------------------------------------------- + # Cargo.toml + # -------------------------------------------------------------------------- + + set(HYPERVISOR_CARGO_TOML ${CMAKE_CURRENT_LIST_DIR}/Cargo.toml) + + file(WRITE ${HYPERVISOR_CARGO_TOML} "[package]\n") + file(APPEND ${HYPERVISOR_CARGO_TOML} "name = \"rust\"\n") + file(APPEND ${HYPERVISOR_CARGO_TOML} "version = \"1.0.0\"\n") + file(APPEND ${HYPERVISOR_CARGO_TOML} "edition = \"2018\"\n") + file(APPEND ${HYPERVISOR_CARGO_TOML} "\n") + file(APPEND ${HYPERVISOR_CARGO_TOML} "[lib]\n") + file(APPEND ${HYPERVISOR_CARGO_TOML} "path = \"src/lib.rs\"\n") + file(APPEND ${HYPERVISOR_CARGO_TOML} "crate-type = [\"staticlib\"]\n") + file(APPEND ${HYPERVISOR_CARGO_TOML} "\n") + file(APPEND ${HYPERVISOR_CARGO_TOML} "[features]\n") + + set(SYSCALL_DEFAULT_FEATURES "[\"custom_print_thread_id\"") + + if(HYPERVISOR_TARGET_ARCH STREQUAL "AuthenticAMD") + set(SYSCALL_DEFAULT_FEATURES "${SYSCALL_DEFAULT_FEATURES},\"AuthenticAMD\"") + endif() + + if(HYPERVISOR_TARGET_ARCH STREQUAL "GenuineIntel") + set(SYSCALL_DEFAULT_FEATURES "${SYSCALL_DEFAULT_FEATURES},\"GenuineIntel\"") + endif() + + if(NOT ENABLE_COLOR) + set(SYSCALL_DEFAULT_FEATURES "${SYSCALL_DEFAULT_FEATURES},\"disable_color\"") + endif() + + if(BSL_DEBUG_LEVEL STREQUAL "bsl::V") + set(SYSCALL_DEFAULT_FEATURES "${SYSCALL_DEFAULT_FEATURES},\"debug_level_v\"") + endif() + + if(BSL_DEBUG_LEVEL STREQUAL "bsl::VV") + set(SYSCALL_DEFAULT_FEATURES "${SYSCALL_DEFAULT_FEATURES},\"debug_level_v\",\"debug_level_vv\"") + endif() + + if(BSL_DEBUG_LEVEL STREQUAL "bsl::VVV") + set(SYSCALL_DEFAULT_FEATURES "${SYSCALL_DEFAULT_FEATURES},\"debug_level_v\",\"debug_level_vv\",\"debug_level_vvv\"") + endif() + + if(CMAKE_BUILD_TYPE STREQUAL RELEASE OR CMAKE_BUILD_TYPE STREQUAL MINSIZEREL) + set(SYSCALL_DEFAULT_FEATURES "${SYSCALL_DEFAULT_FEATURES},\"release_mode\"]") + else() + set(SYSCALL_DEFAULT_FEATURES "${SYSCALL_DEFAULT_FEATURES}]") + endif() + + file(APPEND ${HYPERVISOR_CARGO_TOML} "default = ${SYSCALL_DEFAULT_FEATURES}\n") + file(APPEND ${HYPERVISOR_CARGO_TOML} "debug_level_v = []\n") + file(APPEND ${HYPERVISOR_CARGO_TOML} "debug_level_vv = []\n") + file(APPEND ${HYPERVISOR_CARGO_TOML} "debug_level_vvv = []\n") + file(APPEND ${HYPERVISOR_CARGO_TOML} "disable_color = []\n") + file(APPEND ${HYPERVISOR_CARGO_TOML} "release_mode = []\n") + file(APPEND ${HYPERVISOR_CARGO_TOML} "AuthenticAMD = []\n") + file(APPEND ${HYPERVISOR_CARGO_TOML} "GenuineIntel = []\n") + file(APPEND ${HYPERVISOR_CARGO_TOML} "custom_print_thread_id = []\n") + file(APPEND ${HYPERVISOR_CARGO_TOML} "\n") + + file(APPEND ${HYPERVISOR_CARGO_TOML} "[dependencies]\n") + file(APPEND ${HYPERVISOR_CARGO_TOML} "bsl = { path = \"${bsl_SOURCE_DIR}\", features = ${SYSCALL_DEFAULT_FEATURES} }\n") + file(APPEND ${HYPERVISOR_CARGO_TOML} "syscall = { path = \"${hypervisor_SOURCE_DIR}/syscall\", features = ${SYSCALL_DEFAULT_FEATURES} }\n") +endif() + # NOTE: # - CMake cannot build Rust code, so we need to use cargo for that. To get # the build system to do this, we will use external project add, and provide @@ -68,12 +147,13 @@ ExternalProject_Add( TMP_DIR ${CMAKE_BINARY_DIR}/rust_compile/tmp BINARY_DIR ${CMAKE_BINARY_DIR}/rust_compile/build LOG_DIR ${CMAKE_BINARY_DIR}/rust_compile/logs - SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/src + SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR} UPDATE_COMMAND cmake -E echo -- Checking for changes - CONFIGURE_COMMAND cmake -E chdir ${CMAKE_CURRENT_LIST_DIR}/src rustup override set nightly > log.txt 2> log.txt - BUILD_COMMAND cmake -E chdir ${CMAKE_CURRENT_LIST_DIR}/src cargo build -Z build-std=core ${CARGO_MODE_ARG} - BUILD_BYPRODUCTS ${CMAKE_CURRENT_LIST_DIR}/src/target/x86_64-unknown-none/${CARGO_MODE}/librust.a - INSTALL_COMMAND cmake -E echo -- Checking for changes + CONFIGURE_COMMAND cmake -E chdir ${CMAKE_CURRENT_LIST_DIR} rustup override set nightly + BUILD_COMMAND cmake -E chdir ${CMAKE_CURRENT_LIST_DIR} cargo build -Z build-std=core ${CARGO_MODE_ARG} + BUILD_BYPRODUCTS ${CMAKE_CURRENT_LIST_DIR}/target/x86_64-unknown-none/${CARGO_MODE}/librust.a + INSTALL_COMMAND cmake -E echo -- Skip + LOG_CONFIGURE ON ) # NOTE: @@ -89,14 +169,22 @@ add_library(rust STATIC IMPORTED) # set_target_properties(rust - PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_LIST_DIR}/src/target/x86_64-unknown-none/${CARGO_MODE}/librust.a + PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_LIST_DIR}/target/x86_64-unknown-none/${CARGO_MODE}/librust.a ) # ------------------------------------------------------------------------------ # Executable # ------------------------------------------------------------------------------ -add_executable(example_default_rust empty.cpp) +add_executable(extension_bin empty.cpp) + +# ------------------------------------------------------------------------------ +# Source Files +# ------------------------------------------------------------------------------ + +if(HYPERVISOR_TARGET_ARCH STREQUAL "AuthenticAMD" OR HYPERVISOR_TARGET_ARCH STREQUAL "GenuineIntel") + target_sources(extension_bin PRIVATE src/x64/intrinsic_cpuid_impl.S) +endif() # ------------------------------------------------------------------------------ # Libraries @@ -112,7 +200,7 @@ add_executable(example_default_rust empty.cpp) # old implementation, or write your own. # -target_link_libraries(example_default_rust PRIVATE +target_link_libraries(extension_bin PRIVATE runtime syscall rust @@ -125,7 +213,7 @@ target_link_libraries(example_default_rust PRIVATE # we don't do this, we could end up with order issues in parallel builds. # -add_dependencies(example_default_rust rust_compile) +add_dependencies(extension_bin rust_compile) # ------------------------------------------------------------------------------ # Strip @@ -138,5 +226,5 @@ add_dependencies(example_default_rust rust_compile) # if(CMAKE_BUILD_TYPE STREQUAL RELEASE OR CMAKE_BUILD_TYPE STREQUAL MINSIZEREL) - add_custom_command(TARGET example_default_rust POST_BUILD COMMAND ${CMAKE_STRIP} example_default_rust) + add_custom_command(TARGET extension_bin POST_BUILD COMMAND ${CMAKE_STRIP} extension_bin) endif() diff --git a/cmake/rust/lib.rs b/example/default_rust/include/allocated_status_t.rs similarity index 75% rename from cmake/rust/lib.rs rename to example/default_rust/include/allocated_status_t.rs index 3eb78c78..1d7a77fa 100644 --- a/cmake/rust/lib.rs +++ b/example/default_rust/include/allocated_status_t.rs @@ -22,4 +22,15 @@ /// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE /// SOFTWARE. -pub const HYPERVISOR_PAGE_SIZE: u64 = 0x1000; +/// +/// @brief Defines the allocation status of a resource +/// +#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)] +pub enum AllocatedStatusT { + /// @brief defines the deallocated state for a resource + Deallocated, + /// @brief defines the allocated state for a resource + Allocated, + /// @brief defines the zombie state for a resource + Zombie, +} diff --git a/example/default_rust/src/Cargo.toml b/example/default_rust/src/Cargo.toml deleted file mode 100644 index 68f0f384..00000000 --- a/example/default_rust/src/Cargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[package] -name = "rust" -version = "0.1.0" -edition = "2018" - -[lib] -path = "lib.rs" -crate-type = ["staticlib"] diff --git a/example/default_rust/src/dispatch_bootstrap.rs b/example/default_rust/src/dispatch_bootstrap.rs new file mode 100644 index 00000000..81fad81e --- /dev/null +++ b/example/default_rust/src/dispatch_bootstrap.rs @@ -0,0 +1,100 @@ +/// @copyright +/// Copyright (C) 2020 Assured Information Security, Inc. +/// +/// @copyright +/// Permission is hereby granted, free of charge, to any person obtaining a copy +/// of this software and associated documentation files (the "Software"), to deal +/// in the Software without restriction, including without limitation the rights +/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +/// copies of the Software, and to permit persons to whom the Software is +/// furnished to do so, subject to the following conditions: +/// +/// @copyright +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// @copyright +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +/// SOFTWARE. + +/// +/// @brief Dispatches the bootstrap process as needed. Note that +/// the bootstrap callback is only called when starting the +/// hypervisor on root VPs. +/// +/// +/// @param gs the gs_t to use +/// @param tls the tls_t to use +/// @param sys the bf_syscall_t to use +/// @param intrinsic the intrinsic_t to use +/// @param vp_pool the vp_pool_t to use +/// @param vs_pool the vs_pool_t to use +/// @param ppid the ID of the PP to bootstrap +/// @return Returns bsl::errc_success on success, bsl::errc_failure +/// and friends otherwise +/// +pub fn dispatch_bootstrap( + gs: &crate::GsT, + tls: &mut crate::TlsT, + sys: &mut syscall::BfSyscallT, + intrinsic: &crate::IntrinsicT, + vp_pool: &mut crate::VpPoolT, + vs_pool: &mut crate::VsPoolT, + ppid: bsl::SafeU16, +) -> bsl::ErrcType { + bsl::expects(ppid.is_valid_and_checked()); + bsl::expects(ppid != syscall::BF_INVALID_ID); + + let ret = crate::tls_initialize(tls, sys, intrinsic); + if !ret { + print_v!("{}", bsl::here()); + return bsl::errc_failure; + } + + // NOTE: + // - In order to execcute bf_vs_op_run, which is what executes + // the hypervisor, we must have a VM, VP and VS. + // - The root VM is already created for us, so we don't need to + // create this ourselves. You only need to create VM's if you + // plan to add guest support with your extensions. + // + + let vmid = syscall::BF_ROOT_VMID; + + // NOTE: + // - The VP in this simple example does nothing, but we still need + // to create one. The VP is used when you have more than one VS + // per VP (e.g., if you are implementing HyperV's VSM, or nested + // virtualization support). Otherwise, you will always have one + // VS for each VP, and they will appear as the same thing. + // - The VS is what stores the state associated with the VS. It + // is the thing that does most of the work, including storing + // the VMCS/VMCB and other CPU register state that is needed. + // + + let vpid = vp_pool.allocate(gs, tls, sys, intrinsic, vmid); + if vpid.is_invalid() { + print_v!("{}", bsl::here()); + return bsl::errc_failure; + } + + let vsid = vs_pool.allocate(gs, tls, sys, intrinsic, vpid, ppid); + if vsid.is_invalid() { + print_v!("{}", bsl::here()); + return bsl::errc_failure; + } + + // NOTE: + // - Run the newly created VP on behalf of the root VM using the + // newly created and initialized VS. Note that this version of + // the run function should only be used when starting the + // hypervisor, or switching the VM, VP or VS as it is slow. + // + + return sys.bf_vs_op_run(vmid, vpid, vsid); +} diff --git a/example/default_rust/src/dispatch_fail.rs b/example/default_rust/src/dispatch_fail.rs new file mode 100644 index 00000000..9824e7e1 --- /dev/null +++ b/example/default_rust/src/dispatch_fail.rs @@ -0,0 +1,83 @@ +/// @copyright +/// Copyright (C) 2020 Assured Information Security, Inc. +/// +/// @copyright +/// Permission is hereby granted, free of charge, to any person obtaining a copy +/// of this software and associated documentation files (the "Software"), to deal +/// in the Software without restriction, including without limitation the rights +/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +/// copies of the Software, and to permit persons to whom the Software is +/// furnished to do so, subject to the following conditions: +/// +/// @copyright +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// @copyright +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +/// SOFTWARE. + +/// +/// @brief Dispatches the fail as needed, or returns an error so +/// that the microkernel can halt the PP. +/// +/// +/// @param gs the gs_t to use +/// @param tls the tls_t to use +/// @param sys the bf_syscall_t to use +/// @param intrinsic the intrinsic_t to use +/// @param vp_pool the vp_pool_t to use +/// @param vs_pool the vs_pool_t to use +/// @param errc the reason for the failure, which is CPU +/// specific. On x86, this is a combination of the exception +/// vector and error code. +/// @param addr contains a faulting address if the fail reason +/// is associated with an error that involves a faulting address ( +/// for example like a page fault). Otherwise, the value of this +/// input is undefined. +/// @return Returns bsl::errc_success on success, bsl::errc_failure +/// and friends otherwise +/// +pub fn dispatch_fail( + gs: &crate::GsT, + tls: &crate::TlsT, + sys: &syscall::BfSyscallT, + intrinsic: &crate::IntrinsicT, + vp_pool: &crate::VpPoolT, + vs_pool: &crate::VsPoolT, + errc: bsl::SafeU64, + addr: bsl::SafeU64, +) -> bsl::ErrcType { + bsl::expects(errc.is_valid_and_checked()); + bsl::expects(addr.is_valid_and_checked()); + + bsl::discard(gs); + bsl::discard(tls); + bsl::discard(sys); + bsl::discard(intrinsic); + bsl::discard(vp_pool); + bsl::discard(vs_pool); + + // NOTE: + // - Tells the microkernel that we didn't handle the fast fail. + // When this occurs, the microkernel will halt this PP. In most + // cases, there are only two options for how to handle a fail: + // - Do the following, and report an error and halt. + // - Return to a parent VS and continue execution from there, + // which is typically only possible if you are implementing + // more than one VP/VS per PP (e.g., when implementing guest + // support, VSM support or nested virtualization support). + // + // - Another use case is integration testing. We can also use this + // to generate faults that we can recover from to ensure the + // fault system works properly during testing. + // + + alert!("this extension does not support handling fast fail events\n"); + return bsl::errc_failure; +} diff --git a/example/default_rust/src/lib.rs b/example/default_rust/src/lib.rs index a5e6cd12..d9997511 100644 --- a/example/default_rust/src/lib.rs +++ b/example/default_rust/src/lib.rs @@ -1,24 +1,371 @@ +// @copyright +// Copyright (C) 2020 Assured Information Security, Inc. +// +// @copyright +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// @copyright +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// @copyright +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +// ----------------------------------------------------------------------------- +// Includes +// ----------------------------------------------------------------------------- + #![no_std] +#![feature(thread_local)] +#![feature(panic_info_message)] -use core::panic::PanicInfo; +#[macro_use] +extern crate bsl; +extern crate syscall; -mod constants; -mod println; +macro_rules! print_thread_id { + ($($arg:tt)*) => { + unsafe { + print!( + " [{}{:04x}{}:{}{:04x}{}:{}{:04x}{}:{}{:04x}{}:{}{:04x}{}:{}US{}]", + bsl::cyn, + syscall::bf_tls_extid_impl(), + bsl::rst, + bsl::cyn, + syscall::bf_tls_vmid_impl(), + bsl::rst, + bsl::cyn, + syscall::bf_tls_vpid_impl(), + bsl::rst, + bsl::cyn, + syscall::bf_tls_vsid_impl(), + bsl::rst, + bsl::cyn, + syscall::bf_tls_ppid_impl(), + bsl::rst, + bsl::blu, + bsl::rst + ); + } + }; +} -#[path = "../../../syscall/include/rust/bf_types.rs"] -mod bf_types; -#[path = "../../../syscall/include/rust/bf_constants.rs"] -mod bf_constants; +#[path = "../include/allocated_status_t.rs"] +#[doc(hidden)] +pub mod allocated_status_t; +pub use allocated_status_t::*; + +#[cfg(feature = "AuthenticAMD")] +#[path = "x64/amd/gs_t.rs"] +#[doc(hidden)] +pub mod gs_t; + +#[cfg(feature = "GenuineIntel")] +#[path = "x64/intel/gs_t.rs"] +#[doc(hidden)] +pub mod gs_t; + +#[cfg(feature = "AuthenticAMD")] +#[path = "x64/amd/tls_t.rs"] +#[doc(hidden)] +pub mod tls_t; + +#[cfg(feature = "GenuineIntel")] +#[path = "x64/intel/tls_t.rs"] +#[doc(hidden)] +pub mod tls_t; + +#[cfg(feature = "AuthenticAMD")] +#[path = "x64/intrinsic_t.rs"] +#[doc(hidden)] +pub mod intrinsic_t; + +#[cfg(feature = "GenuineIntel")] +#[path = "x64/intrinsic_t.rs"] +#[doc(hidden)] +pub mod intrinsic_t; + +pub use gs_t::*; +pub use intrinsic_t::*; +pub use tls_t::*; + +#[cfg(feature = "AuthenticAMD")] +#[path = "x64/amd/gs_initialize.rs"] +#[doc(hidden)] +pub mod gs_initialize; + +#[cfg(feature = "GenuineIntel")] +#[path = "x64/intel/gs_initialize.rs"] +#[doc(hidden)] +pub mod gs_initialize; + +#[cfg(feature = "AuthenticAMD")] +#[path = "x64/amd/tls_initialize.rs"] +#[doc(hidden)] +pub mod tls_initialize; + +#[cfg(feature = "GenuineIntel")] +#[path = "x64/intel/tls_initialize.rs"] +#[doc(hidden)] +pub mod tls_initialize; + +pub use gs_initialize::*; +pub use tls_initialize::*; + +#[path = "vp_t.rs"] +#[doc(hidden)] +pub mod vp_t; +pub use vp_t::*; + +#[path = "vp_pool_t.rs"] +#[doc(hidden)] +pub mod vp_pool_t; +pub use vp_pool_t::*; + +#[cfg(feature = "AuthenticAMD")] +#[path = "x64/amd/vs_t.rs"] +#[doc(hidden)] +pub mod vs_t; + +#[cfg(feature = "GenuineIntel")] +#[path = "x64/intel/vs_t.rs"] +#[doc(hidden)] +pub mod vs_t; + +pub use vs_t::*; + +#[path = "vs_pool_t.rs"] +#[doc(hidden)] +pub mod vs_pool_t; +pub use vs_pool_t::*; + +#[path = "dispatch_bootstrap.rs"] +#[doc(hidden)] +pub mod dispatch_bootstrap; +pub use dispatch_bootstrap::*; + +#[cfg(feature = "AuthenticAMD")] +#[path = "x64/amd/dispatch_vmexit.rs"] +#[doc(hidden)] +pub mod dispatch_vmexit; + +#[cfg(feature = "GenuineIntel")] +#[path = "x64/intel/dispatch_vmexit.rs"] +#[doc(hidden)] +pub mod dispatch_vmexit; + +pub use dispatch_vmexit::*; + +#[path = "dispatch_fail.rs"] +#[doc(hidden)] +pub mod dispatch_fail; +pub use dispatch_fail::*; + +// ----------------------------------------------------------------------------- +// Globals +// ----------------------------------------------------------------------------- + +// TODO: +// - The use of globals requires the use of unsafe, which is not good. We +// should find a way to ensure that we can have global storage for all of +// entry points, but without the need for unsafe. +// + +static mut G_SYS: syscall::BfSyscallT = syscall::BfSyscallT::new(); +static mut G_INTRINSIC: crate::IntrinsicT = crate::IntrinsicT::new(); + +static mut G_VP_POOL: crate::VpPoolT = crate::VpPoolT::new(); +static mut G_VS_POOL: crate::VsPoolT = crate::VsPoolT::new(); + +static mut G_GS: crate::GsT = crate::GsT::new(); + +#[thread_local] +static mut G_TLS: crate::TlsT = crate::TlsT::new(); + +// ----------------------------------------------------------------------------- +// Entry Functions +// ----------------------------------------------------------------------------- #[no_mangle] -pub fn ext_main_entry() -> i32 { - println!("hello world {}\n", 42); - return 0; +fn putchar(c: u8) { + unsafe { + syscall::bf_debug_op_write_c_impl(c); + } +} + +#[no_mangle] +fn bootstrap_entry(ppid: u16) { + let ret: bsl::ErrcType; + + // NOTE: + // - Call into the bootstrap handler. This entry point serves as a + // trampoline between C and C++. Specifically, the microkernel + // cannot call a member function directly, and can only call + // a C style function. + // + + unsafe { + ret = dispatch_bootstrap( + &G_GS, + &mut G_TLS, + &mut G_SYS, + &G_INTRINSIC, + &mut G_VP_POOL, + &mut G_VS_POOL, + bsl::to_u16(ppid), + ); + } + + if !ret { + print_v!("{}", bsl::here()); + syscall::bf_control_op_exit(); + return; + } + + // NOTE: + // - This code should never be reached. The bootstrap handler should + // always call one of the "run" ABIs to return back to the + // microkernel when a bootstrap is finished. If this is called, it + // is because the bootstrap handler returned with an error. + // + + syscall::bf_control_op_exit(); +} + +#[no_mangle] +fn vmexit_entry(vsid: u16, exit_reason: u64) { + let ret: bsl::ErrcType; + + // NOTE: + // - Call into the bootstrap handler. This entry point serves as a + // trampoline between C and C++. Specifically, the microkernel + // cannot call a member function directly, and can only call + // a C style function. + // + + unsafe { + ret = dispatch_vmexit( + &G_GS, + &G_TLS, + &mut G_SYS, + &G_INTRINSIC, + &G_VP_POOL, + &G_VS_POOL, + bsl::to_u16(vsid), + bsl::to_u64(exit_reason), + ); + } + + if !ret { + print_v!("{}", bsl::here()); + syscall::bf_control_op_exit(); + return; + } + + // NOTE: + // - This code should never be reached. The VMExit handler should + // always call one of the "run" ABIs to return back to the + // microkernel when a VMExit is finished. If this is called, it + // is because the VMExit handler returned with an error. + // + + syscall::bf_control_op_exit(); +} + +#[no_mangle] +fn fail_entry(errc: u64, addr: u64) { + let ret: bsl::ErrcType; + + // NOTE: + // - Call into the fast fail handler. This entry point serves as a + // trampoline between C and C++. Specifically, the microkernel + // cannot call a member function directly, and can only call + // a C style function. + // + + unsafe { + ret = dispatch_fail( + &G_GS, + &G_TLS, + &G_SYS, + &G_INTRINSIC, + &G_VP_POOL, + &G_VS_POOL, + bsl::to_u64(errc), + bsl::to_u64(addr), + ); + } + + if !ret { + print_v!("{}", bsl::here()); + syscall::bf_control_op_exit(); + return; + } + + // NOTE: + // - This code should never be reached. The fast fail handler should + // always call one of the "run" ABIs to return back to the + // microkernel when a fast fail is finished. If this is called, it + // is because the fast fail handler returned with an error. + // + + syscall::bf_control_op_exit(); +} + +#[no_mangle] +pub fn ext_main_entry(version: u32) -> i32 { + let mut ret: bsl::ErrcType; + + unsafe { + ret = G_SYS.initialize( + bsl::to_u32(version), + bootstrap_entry as bsl::CPtrT, + vmexit_entry as bsl::CPtrT, + fail_entry as bsl::CPtrT, + ); + } + if !ret { + print_v!("{}", bsl::here()); + syscall::bf_control_op_exit(); + return bsl::exit_failure; + } + + unsafe { + ret = gs_initialize(&mut G_GS, &G_SYS, &G_INTRINSIC); + } + if !ret { + print_v!("{}", bsl::here()); + syscall::bf_control_op_exit(); + return bsl::exit_failure; + } + + unsafe { + G_VP_POOL.initialize(&G_GS, &G_TLS, &G_SYS, &G_INTRINSIC); + G_VS_POOL.initialize(&G_GS, &G_TLS, &G_SYS, &G_INTRINSIC); + } + + syscall::bf_control_op_wait(); + return bsl::exit_success; } #[panic_handler] -pub fn panic_implementation(info: &PanicInfo) -> ! { - println!("panic: {}\n", info); - loop{} -} +pub fn panic_implementation(info: &core::panic::PanicInfo<'_>) -> ! { + match info.message() { + Some(s) => print!("{}", s), + None => print!("unknown panic occurred\n"), + } + syscall::bf_control_op_exit(); + loop {} +} diff --git a/example/default_rust/src/println.rs b/example/default_rust/src/println.rs deleted file mode 100644 index c9af97d7..00000000 --- a/example/default_rust/src/println.rs +++ /dev/null @@ -1,81 +0,0 @@ -/// @copyright -/// Copyright (C) 2020 Assured Information Security, Inc. -/// -/// @copyright -/// Permission is hereby granted, free of charge, to any person obtaining a copy -/// of this software and associated documentation files (the "Software"), to deal -/// in the Software without restriction, including without limitation the rights -/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -/// copies of the Software, and to permit persons to whom the Software is -/// furnished to do so, subject to the following conditions: -/// -/// @copyright -/// The above copyright notice and this permission notice shall be included in -/// all copies or substantial portions of the Software. -/// -/// @copyright -/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -/// SOFTWARE. - -use core::fmt; -use core::fmt::Write; - -extern "C" { - pub fn bf_debug_op_write_c_impl(c:u8); -} - -pub struct Writer; - -impl Writer { - pub fn write_string(&mut self, s: &str) { - for byte in s.bytes() { - unsafe { - bf_debug_op_write_c_impl(byte); - } - } - } -} - -impl fmt::Write for Writer { - fn write_str(&mut self, s: &str) -> fmt::Result { - self.write_string(s); - return Ok(()); - } -} - -#[macro_export] -macro_rules! print { - ($($arg:tt)*) => ($crate::println::_print(format_args!($($arg)*))); -} - -#[macro_export] -macro_rules! println { - () => ($crate::print!("\n")); - ($($arg:tt)*) => ($crate::print!("{}\n", format_args!($($arg)*))); -} - -#[doc(hidden)] -pub fn _print(args: fmt::Arguments) { - Writer.write_fmt(args).unwrap(); -} - -/// ---------------------------------------------------------------------------- -/// Unit Tests -/// ---------------------------------------------------------------------------- - -#[cfg(test)] -mod tests { - #[no_mangle] - fn bf_debug_op_write_c_impl(_c:u8) { - } - - #[test] - fn tests() { - println!("hello world {}\n", 42); - } -} diff --git a/example/default_rust/src/vp_pool_t.rs b/example/default_rust/src/vp_pool_t.rs new file mode 100644 index 00000000..541f217b --- /dev/null +++ b/example/default_rust/src/vp_pool_t.rs @@ -0,0 +1,222 @@ +/// @copyright +/// Copyright (C) 2020 Assured Information Security, Inc. +/// +/// @copyright +/// Permission is hereby granted, free of charge, to any person obtaining a copy +/// of this software and associated documentation files (the "Software"), to deal +/// in the Software without restriction, including without limitation the rights +/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +/// copies of the Software, and to permit persons to whom the Software is +/// furnished to do so, subject to the following conditions: +/// +/// @copyright +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// @copyright +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +/// SOFTWARE. + +pub struct VpPoolT { + m_pool: [crate::VpT; *syscall::HYPERVISOR_MAX_VPS.get_unsafe()], +} + +impl VpPoolT { + /// + /// @brief Returns the VpT associated with the provided vpid. + /// + /// + /// @param vpid the ID of the VpT to get + /// @return Returns the VpT associated with the provided vpid. + /// + fn get_vp(&mut self, vpid: bsl::SafeU16) -> &mut crate::VpT { + bsl::expects(vpid.is_valid_and_checked()); + bsl::expects(vpid < bsl::to_u16(self.m_pool.len())); + return &mut self.m_pool[bsl::to_umx(vpid).get()]; + } + + /// + /// @brief Returns the VpT associated with the provided vpid. + /// + /// + /// @param vpid the ID of the VpT to get + /// @return Returns the VpT associated with the provided vpid. + /// + fn get_vp_const(&self, vpid: bsl::SafeU16) -> &crate::VpT { + bsl::expects(vpid.is_valid_and_checked()); + bsl::expects(vpid < bsl::to_u16(self.m_pool.len())); + return &self.m_pool[bsl::to_umx(vpid).get()]; + } + + /// + /// @brief creates a new VpPoolT + /// + pub const fn new() -> Self { + Self { + m_pool: [crate::VpT::new(); *syscall::HYPERVISOR_MAX_VPS.get_unsafe()], + } + } + + /// + /// @brief Initializes this vp_pool_t + /// + /// + /// @param gs the gs_t to use + /// @param tls the tls_t to use + /// @param sys the bf_syscall_t to use + /// @param intrinsic the intrinsic_t to use + /// + pub fn initialize( + &mut self, + gs: &crate::GsT, + tls: &crate::TlsT, + sys: &syscall::BfSyscallT, + intrinsic: &crate::IntrinsicT, + ) { + for i in 0..self.m_pool.len() { + self.m_pool[i].initialize(gs, tls, sys, intrinsic, bsl::to_u16(i)); + } + } + + /// + /// @brief Release the vp_pool_t. + /// + /// + /// @param gs the gs_t to use + /// @param tls the tls_t to use + /// @param sys the bf_syscall_t to use + /// @param intrinsic the intrinsic_t to use + /// + pub fn release( + &mut self, + gs: &crate::GsT, + tls: &crate::TlsT, + sys: &syscall::BfSyscallT, + intrinsic: &crate::IntrinsicT, + ) { + for i in 0..self.m_pool.len() { + self.m_pool[i].release(gs, tls, sys, intrinsic); + } + } + + /// + /// @brief Allocates a VP and returns it's ID + /// + /// + /// @param gs the gs_t to use + /// @param tls the tls_t to use + /// @param sys the bf_syscall_t to use + /// @param intrinsic the intrinsic_t to use + /// @param vmid the ID of the VM to assign the newly created VP to + /// @return Returns ID of the newly allocated VpT. Returns + /// bsl::SafeU16::failure() on failure. + /// + pub fn allocate( + &mut self, + gs: &crate::GsT, + tls: &crate::TlsT, + sys: &mut syscall::BfSyscallT, + intrinsic: &crate::IntrinsicT, + vmid: bsl::SafeU16, + ) -> bsl::SafeU16 { + // NOTE: + // - Ask the microkernel to create a VP and return the ID of the + // newly created VP. + // + + let vpid = sys.bf_vp_op_create_vp(vmid); + if vpid.is_invalid() { + print_v!("{}", bsl::here()); + return bsl::SafeU16::failure(); + } + + // NOTE: + // - Once a VP has been created, the microkernel returns the ID + // of the newly created VP. We can use this ID to determine + // which VpT to allocate. + // + + return self.get_vp(vpid).allocate(gs, tls, sys, intrinsic, vmid); + } + + /// + /// @brief Deallocates the requested VpT + /// + /// + /// @param gs the gs_t to use + /// @param tls the tls_t to use + /// @param sys the bf_syscall_t to use + /// @param intrinsic the intrinsic_t to use + /// @param vpid the ID of the VpT to deallocate + /// + pub fn deallocate( + &mut self, + gs: &crate::GsT, + tls: &crate::TlsT, + sys: &mut syscall::BfSyscallT, + intrinsic: &crate::IntrinsicT, + vpid: bsl::SafeU16, + ) { + let vp = self.get_vp(vpid); + + // NOTE: + // - If the requested VP was allocated, we need to tell the + // microkernel to destroy it. Once that is done we can + // deallocate the VpT so that it can be used again in the + // future. + // + + if vp.is_allocated() { + bsl::expects(sys.bf_vp_op_destroy_vp(vpid)); + vp.deallocate(gs, tls, sys, intrinsic); + } else { + bsl::touch(); + } + } + + /// + /// @brief Returns true if the requested VpT is allocated, + /// false otherwise + /// + /// + /// @param vpid the ID of the VpT to query + /// @return Returns true if the requested VpT is allocated, + /// false otherwise + /// + pub fn is_allocated(&self, vpid: bsl::SafeU16) -> bool { + return self.get_vp_const(vpid).is_allocated(); + } + + /// + /// @brief Returns true if the requested VpT is deallocated, + /// false otherwise + /// + /// + /// @param vpid the ID of the VpT to query + /// @return Returns true if the requested VpT is deallocated, + /// false otherwise + /// + pub fn is_deallocated(&self, vpid: bsl::SafeU16) -> bool { + return self.get_vp_const(vpid).is_deallocated(); + } + + /// + /// @brief Returns the ID of the VM the requested VpT is assigned + /// to. If the VpT is not assigned, syscall::BF_INVALID_ID is + /// returned. + /// + /// + /// @param vpid the ID of the VpT to query + /// @return Returns the ID of the VM the requested VpT is assigned + /// to. If the VpT is not assigned, syscall::BF_INVALID_ID is + /// returned. + /// + pub fn assigned_vm(&self, vpid: bsl::SafeU16) -> bsl::SafeU16 { + return self.get_vp_const(vpid).assigned_vm(); + } +} diff --git a/example/default_rust/src/vp_t.rs b/example/default_rust/src/vp_t.rs new file mode 100644 index 00000000..29f3c2a3 --- /dev/null +++ b/example/default_rust/src/vp_t.rs @@ -0,0 +1,203 @@ +/// @copyright +/// Copyright (C) 2020 Assured Information Security, Inc. +/// +/// @copyright +/// Permission is hereby granted, free of charge, to any person obtaining a copy +/// of this software and associated documentation files (the "Software"), to deal +/// in the Software without restriction, including without limitation the rights +/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +/// copies of the Software, and to permit persons to whom the Software is +/// furnished to do so, subject to the following conditions: +/// +/// @copyright +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// @copyright +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +/// SOFTWARE. + +#[derive(Debug, Copy, Clone)] +pub struct VpT { + /// @brief stores the ID associated with this dVpT + m_id: bsl::SafeU16, + /// @brief stores whether or not this dVpT is allocated. + m_allocated: crate::AllocatedStatusT, + /// @brief stores the ID of the VM this dVpT is assigned to + m_assigned_vmid: bsl::SafeU16, +} + +impl VpT { + /// + /// @brief creates a new VpT + /// + pub const fn new() -> Self { + Self { + m_id: bsl::SafeU16::new(0), + m_allocated: crate::AllocatedStatusT::Deallocated, + m_assigned_vmid: bsl::SafeU16::new(0), + } + } + + /// + /// @brief Initializes this dVpT + /// + /// + /// @param gs the gs_t to use + /// @param tls the tls_t to use + /// @param sys the bf_syscall_t to use + /// @param intrinsic the intrinsic_t to use + /// @param i the ID for this dVpT + /// + pub fn initialize( + &mut self, + gs: &crate::GsT, + tls: &crate::TlsT, + sys: &syscall::BfSyscallT, + intrinsic: &crate::IntrinsicT, + i: bsl::SafeU16, + ) { + bsl::expects(self.id() == syscall::BF_INVALID_ID); + bsl::expects(self.m_allocated == crate::AllocatedStatusT::Deallocated); + + bsl::expects(i.is_valid_and_checked()); + bsl::expects(i != syscall::BF_INVALID_ID); + + bsl::discard(gs); + bsl::discard(tls); + bsl::discard(sys); + bsl::discard(intrinsic); + + self.m_id = !i; + } + + /// + /// @brief Release the dVpT. + /// + /// + /// @param gs the gs_t to use + /// @param tls the tls_t to use + /// @param sys the bf_syscall_t to use + /// @param intrinsic the intrinsic_t to use + /// + pub fn release( + &mut self, + gs: &crate::GsT, + tls: &crate::TlsT, + sys: &syscall::BfSyscallT, + intrinsic: &crate::IntrinsicT, + ) { + self.deallocate(gs, tls, sys, intrinsic); + self.m_id = bsl::SafeU16::default(); + } + + /// + /// @brief Returns the ID of this dVpT + /// + /// + /// @return Returns the ID of this dVpT + /// + pub fn id(&self) -> bsl::SafeU16 { + bsl::ensures(self.m_id.is_valid_and_checked()); + return !self.m_id; + } + + /// + /// @brief Allocates the dVpT and returns it's ID + /// + /// + /// @param gs the gs_t to use + /// @param tls the tls_t to use + /// @param sys the bf_syscall_t to use + /// @param intrinsic the intrinsic_t to use + /// @param vmid the ID of the VM to assign the dVpT to + /// @return Returns ID of this dVpT + /// + pub fn allocate( + &mut self, + gs: &crate::GsT, + tls: &crate::TlsT, + sys: &syscall::BfSyscallT, + intrinsic: &crate::IntrinsicT, + vmid: bsl::SafeU16, + ) -> bsl::SafeU16 { + bsl::expects(self.id() != syscall::BF_INVALID_ID); + bsl::expects(crate::AllocatedStatusT::Deallocated == self.m_allocated); + + bsl::expects(vmid.is_valid_and_checked()); + bsl::expects(vmid != syscall::BF_INVALID_ID); + + bsl::discard(gs); + bsl::discard(tls); + bsl::discard(sys); + bsl::discard(intrinsic); + + self.m_assigned_vmid = !vmid; + self.m_allocated = crate::AllocatedStatusT::Allocated; + + return self.id(); + } + + /// + /// @brief Deallocates the dVpT + /// + /// + /// @param gs the gs_t to use + /// @param tls the tls_t to use + /// @param sys the bf_syscall_t to use + /// @param intrinsic the intrinsic_t to use + /// + pub fn deallocate( + &mut self, + gs: &crate::GsT, + tls: &crate::TlsT, + sys: &syscall::BfSyscallT, + intrinsic: &crate::IntrinsicT, + ) { + bsl::discard(gs); + bsl::discard(tls); + bsl::discard(sys); + bsl::discard(intrinsic); + + self.m_assigned_vmid = bsl::SafeU16::default(); + self.m_allocated = crate::AllocatedStatusT::Deallocated; + } + + /// + /// @brief Returns true if this dVpT is allocated, false otherwise + /// + /// + /// @return Returns true if this dVpT is allocated, false otherwise + /// + pub fn is_allocated(&self) -> bool { + return self.m_allocated == crate::AllocatedStatusT::Allocated; + } + + /// + /// @brief Returns true if this dVpT is deallocated, false otherwise + /// + /// + /// @return Returns true if this dVpT is deallocated, false otherwise + /// + pub fn is_deallocated(&self) -> bool { + return self.m_allocated == crate::AllocatedStatusT::Deallocated; + } + + /// + /// @brief Returns the ID of the VM this dVpT is assigned to. If + /// this dVpT is not assigned, syscall::BF_INVALID_ID is returned. + /// + /// + /// @return Returns the ID of the VM this dVpT is assigned to. If + /// this dVpT is not assigned, syscall::BF_INVALID_ID is returned. + /// + pub fn assigned_vm(&self) -> bsl::SafeU16 { + bsl::ensures(self.m_assigned_vmid.is_valid_and_checked()); + return !self.m_assigned_vmid; + } +} diff --git a/example/default_rust/src/vs_pool_t.rs b/example/default_rust/src/vs_pool_t.rs new file mode 100644 index 00000000..e2f0c3f3 --- /dev/null +++ b/example/default_rust/src/vs_pool_t.rs @@ -0,0 +1,241 @@ +/// @copyright +/// Copyright (C) 2020 Assured Information Security, Inc. +/// +/// @copyright +/// Permission is hereby granted, free of charge, to any person obtaining a copy +/// of this software and associated documentation files (the "Software"), to deal +/// in the Software without restriction, including without limitation the rights +/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +/// copies of the Software, and to permit persons to whom the Software is +/// furnished to do so, subject to the following conditions: +/// +/// @copyright +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// @copyright +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +/// SOFTWARE. + +pub struct VsPoolT { + m_pool: [crate::VsT; *syscall::HYPERVISOR_MAX_VSS.get_unsafe()], +} + +impl VsPoolT { + /// + /// @brief Returns the VsT associated with the provided vsid. + /// + /// + /// @param vsid the ID of the VsT to get + /// @return Returns the VsT associated with the provided vsid. + /// + fn get_vs(&mut self, vsid: bsl::SafeU16) -> &mut crate::VsT { + bsl::expects(vsid.is_valid_and_checked()); + bsl::expects(vsid < bsl::to_u16(self.m_pool.len())); + return &mut self.m_pool[bsl::to_umx(vsid).get()]; + } + + /// + /// @brief Returns the VsT associated with the provided vsid. + /// + /// + /// @param vsid the ID of the VsT to get + /// @return Returns the VsT associated with the provided vsid. + /// + fn get_vs_const(&self, vsid: bsl::SafeU16) -> &crate::VsT { + bsl::expects(vsid.is_valid_and_checked()); + bsl::expects(vsid < bsl::to_u16(self.m_pool.len())); + return &self.m_pool[bsl::to_umx(vsid).get()]; + } + + /// + /// @brief creates a new VsPoolT + /// + pub const fn new() -> Self { + Self { + m_pool: [crate::VsT::new(); *syscall::HYPERVISOR_MAX_VSS.get_unsafe()], + } + } + + /// + /// @brief Initializes this vp_pool_t + /// + /// + /// @param gs the gs_t to use + /// @param tls the tls_t to use + /// @param sys the bf_syscall_t to use + /// @param intrinsic the intrinsic_t to use + /// + pub fn initialize( + &mut self, + gs: &crate::GsT, + tls: &crate::TlsT, + sys: &syscall::BfSyscallT, + intrinsic: &crate::IntrinsicT, + ) { + for i in 0..self.m_pool.len() { + self.m_pool[i].initialize(gs, tls, sys, intrinsic, bsl::to_u16(i)); + } + } + + /// + /// @brief Release the vp_pool_t. + /// + /// + /// @param gs the gs_t to use + /// @param tls the tls_t to use + /// @param sys the bf_syscall_t to use + /// @param intrinsic the intrinsic_t to use + /// + pub fn release( + &mut self, + gs: &crate::GsT, + tls: &crate::TlsT, + sys: &syscall::BfSyscallT, + intrinsic: &crate::IntrinsicT, + ) { + for i in 0..self.m_pool.len() { + self.m_pool[i].release(gs, tls, sys, intrinsic); + } + } + + /// + /// @brief Allocates a VP and returns it's ID + /// + /// + /// @param gs the gs_t to use + /// @param tls the tls_t to use + /// @param sys the bf_syscall_t to use + /// @param intrinsic the intrinsic_t to use + /// @param vpid the ID of the VP to assign the newly created VP to + /// @param ppid the ID of the PP to assign the newly created VP to + /// @return Returns ID of the newly allocated VsT. Returns + /// bsl::SafeU16::failure() on failure. + /// + pub fn allocate( + &mut self, + gs: &crate::GsT, + tls: &crate::TlsT, + sys: &mut syscall::BfSyscallT, + intrinsic: &crate::IntrinsicT, + vpid: bsl::SafeU16, + ppid: bsl::SafeU16, + ) -> bsl::SafeU16 { + // NOTE: + // - Ask the microkernel to create a VP and return the ID of the + // newly created VP. + // + + let vsid = sys.bf_vs_op_create_vs(vpid, ppid); + if vsid.is_invalid() { + print_v!("{}", bsl::here()); + return bsl::SafeU16::failure(); + } + + // NOTE: + // - Once a VP has been created, the microkernel returns the ID + // of the newly created VP. We can use this ID to determine + // which VsT to allocate. + // + + return self + .get_vs(vsid) + .allocate(gs, tls, sys, intrinsic, vpid, ppid); + } + + /// + /// @brief Deallocates the requested VsT + /// + /// + /// @param gs the gs_t to use + /// @param tls the tls_t to use + /// @param sys the bf_syscall_t to use + /// @param intrinsic the intrinsic_t to use + /// @param vsid the ID of the VsT to deallocate + /// + pub fn deallocate( + &mut self, + gs: &crate::GsT, + tls: &crate::TlsT, + sys: &mut syscall::BfSyscallT, + intrinsic: &crate::IntrinsicT, + vsid: bsl::SafeU16, + ) { + let vs = self.get_vs(vsid); + + // NOTE: + // - If the requested VP was allocated, we need to tell the + // microkernel to destroy it. Once that is done we can + // deallocate the VsT so that it can be used again in the + // future. + // + + if vs.is_allocated() { + bsl::expects(sys.bf_vs_op_destroy_vs(vsid)); + vs.deallocate(gs, tls, sys, intrinsic); + } else { + bsl::touch(); + } + } + + /// + /// @brief Returns true if the requested VsT is allocated, + /// false otherwise + /// + /// + /// @param vpid the ID of the VsT to query + /// @return Returns true if the requested VsT is allocated, + /// false otherwise + /// + pub fn is_allocated(&self, vpid: bsl::SafeU16) -> bool { + return self.get_vs_const(vpid).is_allocated(); + } + + /// + /// @brief Returns true if the requested VsT is deallocated, + /// false otherwise + /// + /// + /// @param vpid the ID of the VsT to query + /// @return Returns true if the requested VsT is deallocated, + /// false otherwise + /// + pub fn is_deallocated(&self, vpid: bsl::SafeU16) -> bool { + return self.get_vs_const(vpid).is_deallocated(); + } + + /// + /// @brief Returns the ID of the VP the requested VsT is assigned + /// to. If the VsT is not assigned, syscall::BF_INVALID_ID is + /// returned. + /// + /// + /// @param vpid the ID of the VsT to query + /// @return Returns the ID of the VP the requested VsT is assigned + /// to. If the VsT is not assigned, syscall::BF_INVALID_ID is + /// returned. + /// + pub fn assigned_vp(&self, vpid: bsl::SafeU16) -> bsl::SafeU16 { + return self.get_vs_const(vpid).assigned_vp(); + } + + /// + /// @brief Returns the ID of the PP the requested VsT is assigned + /// to. If the VsT is not assigned, syscall::BF_INVALID_ID is + /// returned. + /// + /// + /// @param vpid the ID of the VsT to query + /// @return Returns the ID of the PP the requested VsT is assigned + /// to. If the VsT is not assigned, syscall::BF_INVALID_ID is + /// returned. + /// + pub fn assigned_pp(&self, vpid: bsl::SafeU16) -> bsl::SafeU16 { + return self.get_vs_const(vpid).assigned_pp(); + } +} diff --git a/example/default_rust/src/x64/amd/dispatch_vmexit.rs b/example/default_rust/src/x64/amd/dispatch_vmexit.rs new file mode 100644 index 00000000..d41d6f1c --- /dev/null +++ b/example/default_rust/src/x64/amd/dispatch_vmexit.rs @@ -0,0 +1,71 @@ +/// @copyright +/// Copyright (C) 2020 Assured Information Security, Inc. +/// +/// @copyright +/// Permission is hereby granted, free of charge, to any person obtaining a copy +/// of this software and associated documentation files (the "Software"), to deal +/// in the Software without restriction, including without limitation the rights +/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +/// copies of the Software, and to permit persons to whom the Software is +/// furnished to do so, subject to the following conditions: +/// +/// @copyright +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// @copyright +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +/// SOFTWARE. + +const EXIT_REASON_CPUID: u64 = 0x72; + +#[path = "../dispatch_vmexit_cpuid.rs"] +#[doc(hidden)] +pub mod dispatch_vmexit_cpuid; +pub use dispatch_vmexit_cpuid::*; + +/// +/// @brief Dispatches the VMExit. +/// +/// +/// @param gs the gs_t to use +/// @param tls the tls_t to use +/// @param sys the bf_syscall_t to use +/// @param intrinsic the intrinsic_t to use +/// @param vp_pool the vp_pool_t to use +/// @param vs_pool the vs_pool_t to use +/// @param vsid the ID of the VS that generated the VMExit +/// @param exit_reason the exit reason associated with the VMExit +/// @return Returns bsl::errc_success on success, bsl::errc_failure +/// and friends otherwise +/// +pub fn dispatch_vmexit( + gs: &crate::GsT, + tls: &crate::TlsT, + sys: &mut syscall::BfSyscallT, + intrinsic: &crate::IntrinsicT, + vp_pool: &crate::VpPoolT, + vs_pool: &crate::VsPoolT, + vsid: bsl::SafeU16, + exit_reason: bsl::SafeU64, +) -> bsl::ErrcType { + bsl::discard(vp_pool); + bsl::discard(vs_pool); + + match exit_reason.get() { + EXIT_REASON_CPUID => return crate::dispatch_vmexit_cpuid(gs, tls, sys, intrinsic, vsid), + + _ => {} + } + + error!("unsupported vmexit: {:#018x}\n", exit_reason); + syscall::bf_debug_op_dump_vs(vsid); + print_v!("{}", bsl::here()); + + return bsl::errc_failure; +} diff --git a/example/nested_paging/x64/range_t.hpp b/example/default_rust/src/x64/amd/gs_initialize.rs similarity index 68% rename from example/nested_paging/x64/range_t.hpp rename to example/default_rust/src/x64/amd/gs_initialize.rs index 57bd63ca..2912ec29 100644 --- a/example/nested_paging/x64/range_t.hpp +++ b/example/default_rust/src/x64/amd/gs_initialize.rs @@ -22,27 +22,24 @@ /// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE /// SOFTWARE. -#ifndef RANGE_T_HPP -#define RANGE_T_HPP +/// +/// @brief Initializes the Global Storage (GS). +/// +/// +/// @param gs the gs_t to use +/// @param sys the bf_syscall_t to use +/// @param intrinsic the intrinsic_t to use +/// @return Returns bsl::errc_success on success, bsl::errc_failure +/// and friends otherwise +/// +pub fn gs_initialize( + gs: &crate::GsT, + sys: &syscall::BfSyscallT, + intrinsic: &crate::IntrinsicT, +) -> bsl::ErrcType { + bsl::discard(gs); + bsl::discard(sys); + bsl::discard(intrinsic); -#include - -namespace example -{ - /// - /// @brief Defines a MTRR range used by the mtrr_t class. - /// - struct range_t final - { - /// @brief Defines the range's address - bsl::safe_umx addr; - /// @brief Defines the range's size in bytes - bsl::safe_umx size; - /// @brief Defines the range's memory type - bsl::safe_umx type; - /// @brief Defines if the range is the default range - bool dflt; - }; + return bsl::errc_success; } - -#endif diff --git a/example/nested_paging/x64/amd/npdt_t.hpp b/example/default_rust/src/x64/amd/gs_t.rs similarity index 67% rename from example/nested_paging/x64/amd/npdt_t.hpp rename to example/default_rust/src/x64/amd/gs_t.rs index 476e7729..73bd8262 100644 --- a/example/nested_paging/x64/amd/npdt_t.hpp +++ b/example/default_rust/src/x64/amd/gs_t.rs @@ -22,34 +22,23 @@ /// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE /// SOFTWARE. -#ifndef NPDT_T_HPP -#define NPDT_T_HPP +/// +/// @brief Defines the extension's Global Storage (GS). +/// Extensions can use this to store global variables as needed. +/// The gs_t can also be used during unit testing to store testing +/// specific logic and data to ensure tests can support constexpr +/// style unit testing. Also note that this is stored in the arch +/// specific folders as it usually needs to store arch specific +/// resources. +/// +#[derive(Debug, Default, Copy, Clone)] +pub struct GsT {} -#include - -#include -#include -#include - -#pragma pack(push, 1) - -namespace example -{ - /// @brief defined the expected size of the npdt_t struct - constexpr bsl::safe_umx NUM_NPDT_ENTRIES{bsl::to_umx(512)}; - - /// @struct example::npdt_t - /// +impl GsT { /// - /// @brief Defines the layout of a page-directory table (npdt). + /// @brief creates a new GsT /// - struct npdt_t final - { - /// @brief stores the entires in the table - bsl::array entries; - }; + pub const fn new() -> Self { + Self {} + } } - -#pragma pack(pop) - -#endif diff --git a/example/default_rust/src/x64/amd/tls_initialize.rs b/example/default_rust/src/x64/amd/tls_initialize.rs new file mode 100644 index 00000000..1803aa8c --- /dev/null +++ b/example/default_rust/src/x64/amd/tls_initialize.rs @@ -0,0 +1,45 @@ +/// @copyright +/// Copyright (C) 2020 Assured Information Security, Inc. +/// +/// @copyright +/// Permission is hereby granted, free of charge, to any person obtaining a copy +/// of this software and associated documentation files (the "Software"), to deal +/// in the Software without restriction, including without limitation the rights +/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +/// copies of the Software, and to permit persons to whom the Software is +/// furnished to do so, subject to the following conditions: +/// +/// @copyright +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// @copyright +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +/// SOFTWARE. + +/// +/// @brief Initializes the Thread Local Storage (TLS). +/// +/// +/// @param tls the tls_t to use +/// @param sys the bf_syscall_t to use +/// @param intrinsic the intrinsic_t to use +/// @return Returns bsl::errc_success on success, bsl::errc_failure +/// and friends otherwise +/// +pub fn tls_initialize( + tls: &crate::TlsT, + sys: &syscall::BfSyscallT, + intrinsic: &crate::IntrinsicT, +) -> bsl::ErrcType { + bsl::discard(tls); + bsl::discard(sys); + bsl::discard(intrinsic); + + return bsl::errc_success; +} diff --git a/example/nested_paging/x64/amd/npt_t.hpp b/example/default_rust/src/x64/amd/tls_t.rs similarity index 52% rename from example/nested_paging/x64/amd/npt_t.hpp rename to example/default_rust/src/x64/amd/tls_t.rs index 0a30fad4..396fd8e1 100644 --- a/example/nested_paging/x64/amd/npt_t.hpp +++ b/example/default_rust/src/x64/amd/tls_t.rs @@ -22,34 +22,32 @@ /// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE /// SOFTWARE. -#ifndef NPT_T_HPP -#define NPT_T_HPP +/// +/// @brief Defines the extension's Thread Local Storage (TLS). +/// Extensions can use this to store data specific to a PP as needed. +/// The tls_t can also be used during unit testing to store testing +/// specific logic and data to ensure tests can support constexpr +/// style unit testing. Also note that this is stored in the arch +/// specific folders as it usually needs to store arch specific +/// resources. In this simple example, we leave this empty. +/// +/// +/// @note IMPORTANT: Extensions are limited to a single 4k page for the +/// TLS data. Technically, extensions are given 2 4k pages, but one of +/// the pages is dedicated to TLS data defined by the specification +/// and populated by the microkernel (e.g., the general purpose +/// registers and ID information). For this reason, if more than a +/// page is needed, the TLS block should store pointers to memory that +/// is allocated. +/// +#[derive(Debug, Default, Copy, Clone)] +pub struct TlsT {} -#include - -#include -#include -#include - -#pragma pack(push, 1) - -namespace example -{ - /// @brief defined the expected size of the npt_t struct - constexpr bsl::safe_umx NUM_NPT_ENTRIES{bsl::to_umx(512)}; - - /// @struct example::npt_t - /// +impl TlsT { /// - /// @brief Defines the layout of a page table (npt). + /// @brief creates a new TlsT /// - struct npt_t final - { - /// @brief stores the entires in the table - bsl::array entries; - }; + pub const fn new() -> Self { + Self {} + } } - -#pragma pack(pop) - -#endif diff --git a/example/default_rust/src/x64/amd/vs_t.rs b/example/default_rust/src/x64/amd/vs_t.rs new file mode 100644 index 00000000..e69379fb --- /dev/null +++ b/example/default_rust/src/x64/amd/vs_t.rs @@ -0,0 +1,242 @@ +/// @copyright +/// Copyright (C) 2020 Assured Information Security, Inc. +/// +/// @copyright +/// Permission is hereby granted, free of charge, to any person obtaining a copy +/// of this software and associated documentation files (the "Software"), to deal +/// in the Software without restriction, including without limitation the rights +/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +/// copies of the Software, and to permit persons to whom the Software is +/// furnished to do so, subject to the following conditions: +/// +/// @copyright +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// @copyright +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +/// SOFTWARE. + +#[derive(Debug, Copy, Clone)] +pub struct VsT { + /// @brief stores the ID associated with this VsT + m_id: bsl::SafeU16, + /// @brief stores whether or not this VsT is allocated. + m_allocated: crate::AllocatedStatusT, + /// @brief stores the ID of the VP this VsT is assigned to + m_assigned_vpid: bsl::SafeU16, + /// @brief stores the ID of the PP this VsT is assigned to + m_assigned_ppid: bsl::SafeU16, +} + +impl VsT { + /// + /// @brief creates a new VsT + /// + pub const fn new() -> Self { + Self { + m_id: bsl::SafeU16::new(0), + m_allocated: crate::AllocatedStatusT::Deallocated, + m_assigned_vpid: bsl::SafeU16::new(0), + m_assigned_ppid: bsl::SafeU16::new(0), + } + } + + /// + /// @brief Initializes this VsT + /// + /// + /// @param gs the gs_t to use + /// @param tls the tls_t to use + /// @param sys the bf_syscall_t to use + /// @param intrinsic the intrinsic_t to use + /// @param i the ID for this VsT + /// + pub fn initialize( + &mut self, + gs: &crate::GsT, + tls: &crate::TlsT, + sys: &syscall::BfSyscallT, + intrinsic: &crate::IntrinsicT, + i: bsl::SafeU16, + ) { + bsl::expects(self.id() == syscall::BF_INVALID_ID); + bsl::expects(self.m_allocated == crate::AllocatedStatusT::Deallocated); + + bsl::expects(i.is_valid_and_checked()); + bsl::expects(i != syscall::BF_INVALID_ID); + + bsl::discard(gs); + bsl::discard(tls); + bsl::discard(sys); + bsl::discard(intrinsic); + + self.m_id = !i; + } + + /// + /// @brief Release the VsT. + /// + /// + /// @param gs the gs_t to use + /// @param tls the tls_t to use + /// @param sys the bf_syscall_t to use + /// @param intrinsic the intrinsic_t to use + /// + pub fn release( + &mut self, + gs: &crate::GsT, + tls: &crate::TlsT, + sys: &syscall::BfSyscallT, + intrinsic: &crate::IntrinsicT, + ) { + self.deallocate(gs, tls, sys, intrinsic); + self.m_id = bsl::SafeU16::default(); + } + + /// + /// @brief Returns the ID of this VsT + /// + /// + /// @return Returns the ID of this VsT + /// + pub fn id(&self) -> bsl::SafeU16 { + bsl::ensures(self.m_id.is_valid_and_checked()); + return !self.m_id; + } + + /// + /// @brief Allocates the VsT and returns it's ID + /// + /// + /// @param gs the gs_t to use + /// @param tls the tls_t to use + /// @param sys the bf_syscall_t to use + /// @param intrinsic the intrinsic_t to use + /// @param vpid the ID of the VP to assign the VsT to + /// @param ppid the ID of the PP to assign the VsT to + /// @return Returns ID of this VsT + /// + pub fn allocate( + &mut self, + gs: &crate::GsT, + tls: &crate::TlsT, + sys: &mut syscall::BfSyscallT, + intrinsic: &crate::IntrinsicT, + vpid: bsl::SafeU16, + ppid: bsl::SafeU16, + ) -> bsl::SafeU16 { + bsl::expects(self.id() != syscall::BF_INVALID_ID); + bsl::expects(crate::AllocatedStatusT::Deallocated == self.m_allocated); + + bsl::expects(vpid.is_valid_and_checked()); + bsl::expects(vpid != syscall::BF_INVALID_ID); + bsl::expects(ppid.is_valid_and_checked()); + bsl::expects(ppid != syscall::BF_INVALID_ID); + + bsl::discard(gs); + bsl::discard(tls); + bsl::discard(intrinsic); + + let guest_asid_val = bsl::SafeU64::new(0x1); + let guest_asid_idx = syscall::BF_REG_T_GUEST_ASID; + bsl::expects(sys.bf_vs_op_write(self.id(), guest_asid_idx, guest_asid_val)); + + let intercept1_val = bsl::SafeU64::new(0x00040000); + let intercept1_idx = syscall::BF_REG_T_INTERCEPT_INSTRUCTION1; + bsl::expects(sys.bf_vs_op_write(self.id(), intercept1_idx, intercept1_val)); + + let intercept2_val = bsl::SafeU64::new(0x00000001); + let intercept2_idx = syscall::BF_REG_T_INTERCEPT_INSTRUCTION2; + bsl::expects(sys.bf_vs_op_write(self.id(), intercept2_idx, intercept2_val)); + + if syscall::BfSyscallT::is_vs_a_root_vs(self.id()) { + bsl::expects(sys.bf_vs_op_init_as_root(self.id())); + } else { + bsl::touch(); + } + + self.m_assigned_vpid = !vpid; + self.m_assigned_ppid = !ppid; + self.m_allocated = crate::AllocatedStatusT::Allocated; + + return self.id(); + } + + /// + /// @brief Deallocates the VsT + /// + /// + /// @param gs the gs_t to use + /// @param tls the tls_t to use + /// @param sys the bf_syscall_t to use + /// @param intrinsic the intrinsic_t to use + /// + pub fn deallocate( + &mut self, + gs: &crate::GsT, + tls: &crate::TlsT, + sys: &syscall::BfSyscallT, + intrinsic: &crate::IntrinsicT, + ) { + bsl::discard(gs); + bsl::discard(tls); + bsl::discard(sys); + bsl::discard(intrinsic); + + self.m_assigned_ppid = bsl::SafeU16::default(); + self.m_assigned_vpid = bsl::SafeU16::default(); + self.m_allocated = crate::AllocatedStatusT::Deallocated; + } + + /// + /// @brief Returns true if this VsT is allocated, false otherwise + /// + /// + /// @return Returns true if this VsT is allocated, false otherwise + /// + pub fn is_allocated(&self) -> bool { + return self.m_allocated == crate::AllocatedStatusT::Allocated; + } + + /// + /// @brief Returns true if this VsT is deallocated, false otherwise + /// + /// + /// @return Returns true if this VsT is deallocated, false otherwise + /// + pub fn is_deallocated(&self) -> bool { + return self.m_allocated == crate::AllocatedStatusT::Deallocated; + } + + /// + /// @brief Returns the ID of the VP this VsT is assigned to. If + /// this VsT is not assigned, syscall::BF_INVALID_ID is returned. + /// + /// + /// @return Returns the ID of the VP this VsT is assigned to. If + /// this VsT is not assigned, syscall::BF_INVALID_ID is returned. + /// + pub fn assigned_vp(&self) -> bsl::SafeU16 { + bsl::ensures(self.m_assigned_vpid.is_valid_and_checked()); + return !self.m_assigned_vpid; + } + + /// + /// @brief Returns the ID of the PP this VsT is assigned to. If + /// this VsT is not assigned, syscall::BF_INVALID_ID is returned. + /// + /// + /// @return Returns the ID of the PP this VsT is assigned to. If + /// this VsT is not assigned, syscall::BF_INVALID_ID is returned. + /// + pub fn assigned_pp(&self) -> bsl::SafeU16 { + bsl::ensures(self.m_assigned_ppid.is_valid_and_checked()); + return !self.m_assigned_ppid; + } +} diff --git a/example/default_rust/src/x64/dispatch_vmexit_cpuid.rs b/example/default_rust/src/x64/dispatch_vmexit_cpuid.rs new file mode 100644 index 00000000..dd7764f8 --- /dev/null +++ b/example/default_rust/src/x64/dispatch_vmexit_cpuid.rs @@ -0,0 +1,179 @@ +/// @copyright +/// Copyright (C) 2020 Assured Information Security, Inc. +/// +/// @copyright +/// Permission is hereby granted, free of charge, to any person obtaining a copy +/// of this software and associated documentation files (the "Software"), to deal +/// in the Software without restriction, including without limitation the rights +/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +/// copies of the Software, and to permit persons to whom the Software is +/// furnished to do so, subject to the following conditions: +/// +/// @copyright +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// @copyright +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +/// SOFTWARE. + +const CPUID_COMMAND_EAX: u32 = 0x400000FF; +const CPUID_COMMAND_ECX_STOP: u32 = 0xBF000000; +const CPUID_COMMAND_ECX_REPORT_ON: u32 = 0xBF000001; +const CPUID_COMMAND_ECX_REPORT_OFF: u32 = 0xBF000002; + +const CPUID_COMMAND_RAX_SUCCESS: u32 = 0x0; +const CPUID_COMMAND_RAX_FAILURE: u32 = 0x1; + +/// +/// @brief Handles the CPUID VMexit +/// +/// +/// @param gs the gs_t to use +/// @param tls the tls_t to use +/// @param sys the bf_syscall_t to use +/// @param intrinsic the intrinsic_t to use +/// @param vsid the ID of the VS that generated the VMExit +/// @return Returns bsl::errc_success on success, bsl::errc_failure +/// and friends otherwise +/// +pub fn dispatch_vmexit_cpuid( + gs: &crate::GsT, + tls: &crate::TlsT, + sys: &mut syscall::BfSyscallT, + intrinsic: &crate::IntrinsicT, + vsid: bsl::SafeU16, +) -> bsl::ErrcType { + let mut rax = syscall::BfSyscallT::bf_tls_rax(); + let mut rcx = syscall::BfSyscallT::bf_tls_rcx(); + + bsl::discard(gs); + bsl::discard(tls); + + // NOTE: + // - Before we execute CPUID, we need to check to see if we have + // received a CPUID command. If we have, we need to handle this + // CPUID differently. These are defined in the loader. + // + + if bsl::to_u32_unsafe(rax) == CPUID_COMMAND_EAX { + match bsl::to_u32_unsafe(rcx).get() { + CPUID_COMMAND_ECX_STOP => { + // NOTE: + // - If this is the first PP to stop (which is the + // last PP in the list as we stop in reverse order), + // print out how much memory was used by the + // hypervisor. This is optional of course. + // + + let last_online_ppid = + (syscall::BfSyscallT::bf_tls_online_pps() - bsl::SafeU16::magic_1()).checked(); + if syscall::BfSyscallT::bf_tls_ppid() == last_online_ppid { + print!("\n"); + syscall::bf_debug_op_dump_page_pool(); + print!("\n"); + } else { + bsl::touch(); + } + + // NOTE: + // - The following is another optional debug feature that + // will show a log of the most recent VMExits that have + // occurred. + // + + if bsl::debug_level_is_at_least_vv() { + print!("\n"); + syscall::bf_debug_op_dump_vmexit_log(syscall::BfSyscallT::bf_tls_ppid()); + } + + // NOTE: + // - Report that the root OS is no longer in a VM for + // this specific PP. Note that you can do whatever + // you want here, this is just the default behavior. + // To report success on promotion after promotion + // takes place would require that the loader reports + // success, which we do not do as we are not sure + // what the extension wants, so the message here + // should state that we are "about to", and not that + // it is "done", because it might fail. + // + + debug!( + "about to {}promote{} root OS on pp {}{:#06x}{}\n", + bsl::red, + bsl::rst, + bsl::cyn, + syscall::BfSyscallT::bf_tls_ppid(), + bsl::rst + ); + + // NOTE: + // - The promote ABI will load the microkernel by + // replacing the CPU's state withthe VP state + // associated with the provided VSID. If all + // goes well, bf_vs_op_promote will not return, + // and the system will continue executing with the + // hypervisor turned off. + // + + syscall::BfSyscallT::bf_tls_set_rax(bsl::to_u64(CPUID_COMMAND_RAX_SUCCESS)); + return sys.bf_vs_op_promote(vsid); + } + + CPUID_COMMAND_ECX_REPORT_ON => { + // NOTE: + // - Report that the root OS is now in a VM for this + // specific PP. + // + + debug!( + "root OS had been {}demoted{} to vm {}{:#06x}{} on pp {}{:#06x}{}\n", + bsl::red, + bsl::rst, + bsl::cyn, + syscall::BfSyscallT::bf_tls_vmid(), + bsl::rst, + bsl::cyn, + syscall::BfSyscallT::bf_tls_ppid(), + bsl::rst + ); + + syscall::BfSyscallT::bf_tls_set_rax(bsl::to_u64(CPUID_COMMAND_RAX_SUCCESS)); + return sys.bf_vs_op_advance_ip_and_run_current(); + } + + CPUID_COMMAND_ECX_REPORT_OFF => { + // NOTE: + // - There is nothing to do here as we report off + // right before promotion takes place. + // + + syscall::BfSyscallT::bf_tls_set_rax(bsl::to_u64(CPUID_COMMAND_RAX_SUCCESS)); + return sys.bf_vs_op_advance_ip_and_run_current(); + } + + _ => { + error!("unsupported cpuid command {:#018x}\n{}", rcx, bsl::here()); + } + } + + syscall::BfSyscallT::bf_tls_set_rax(bsl::to_u64(CPUID_COMMAND_RAX_FAILURE)); + return sys.bf_vs_op_advance_ip_and_run_current(); + } + + let mut rbx = syscall::BfSyscallT::bf_tls_rbx(); + let mut rdx = syscall::BfSyscallT::bf_tls_rdx(); + intrinsic.cpuid(&mut rax, &mut rbx, &mut rcx, &mut rdx); + + syscall::BfSyscallT::bf_tls_set_rax(rax); + syscall::BfSyscallT::bf_tls_set_rbx(rbx); + syscall::BfSyscallT::bf_tls_set_rcx(rcx); + syscall::BfSyscallT::bf_tls_set_rdx(rdx); + return sys.bf_vs_op_advance_ip_and_run_current(); +} diff --git a/example/default_rust/src/x64/intel/dispatch_vmexit.rs b/example/default_rust/src/x64/intel/dispatch_vmexit.rs new file mode 100644 index 00000000..9d52818b --- /dev/null +++ b/example/default_rust/src/x64/intel/dispatch_vmexit.rs @@ -0,0 +1,87 @@ +/// @copyright +/// Copyright (C) 2020 Assured Information Security, Inc. +/// +/// @copyright +/// Permission is hereby granted, free of charge, to any person obtaining a copy +/// of this software and associated documentation files (the "Software"), to deal +/// in the Software without restriction, including without limitation the rights +/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +/// copies of the Software, and to permit persons to whom the Software is +/// furnished to do so, subject to the following conditions: +/// +/// @copyright +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// @copyright +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +/// SOFTWARE. + +const EXIT_REASON_NMI: u64 = 0x0; +const EXIT_REASON_NMI_WINDOW: u64 = 0x8; +const EXIT_REASON_CPUID: u64 = 0xA; + +#[path = "dispatch_vmexit_nmi_window.rs"] +#[doc(hidden)] +pub mod dispatch_vmexit_nmi_window; +pub use dispatch_vmexit_nmi_window::*; + +#[path = "dispatch_vmexit_nmi.rs"] +#[doc(hidden)] +pub mod dispatch_vmexit_nmi; +pub use dispatch_vmexit_nmi::*; + +#[path = "../dispatch_vmexit_cpuid.rs"] +#[doc(hidden)] +pub mod dispatch_vmexit_cpuid; +pub use dispatch_vmexit_cpuid::*; + +/// +/// @brief Dispatches the VMExit. +/// +/// +/// @param gs the gs_t to use +/// @param tls the tls_t to use +/// @param sys the bf_syscall_t to use +/// @param intrinsic the intrinsic_t to use +/// @param vp_pool the vp_pool_t to use +/// @param vs_pool the vs_pool_t to use +/// @param vsid the ID of the VS that generated the VMExit +/// @param exit_reason the exit reason associated with the VMExit +/// @return Returns bsl::errc_success on success, bsl::errc_failure +/// and friends otherwise +/// +pub fn dispatch_vmexit( + gs: &crate::GsT, + tls: &crate::TlsT, + sys: &mut syscall::BfSyscallT, + intrinsic: &crate::IntrinsicT, + vp_pool: &crate::VpPoolT, + vs_pool: &crate::VsPoolT, + vsid: bsl::SafeU16, + exit_reason: bsl::SafeU64, +) -> bsl::ErrcType { + bsl::discard(vp_pool); + bsl::discard(vs_pool); + + match exit_reason.get() { + EXIT_REASON_NMI => return dispatch_vmexit_nmi(gs, tls, sys, vsid), + + EXIT_REASON_NMI_WINDOW => return dispatch_vmexit_nmi_window(gs, tls, sys, vsid), + + EXIT_REASON_CPUID => return dispatch_vmexit_cpuid(gs, tls, sys, intrinsic, vsid), + + _ => {} + } + + error!("unsupported vmexit: {:#018x}\n", exit_reason); + syscall::bf_debug_op_dump_vs(vsid); + print_v!("{}", bsl::here()); + + return bsl::errc_failure; +} diff --git a/example/default_rust/src/x64/intel/dispatch_vmexit_nmi.rs b/example/default_rust/src/x64/intel/dispatch_vmexit_nmi.rs new file mode 100644 index 00000000..b7c278e1 --- /dev/null +++ b/example/default_rust/src/x64/intel/dispatch_vmexit_nmi.rs @@ -0,0 +1,65 @@ +/// @copyright +/// Copyright (C) 2020 Assured Information Security, Inc. +/// +/// @copyright +/// Permission is hereby granted, free of charge, to any person obtaining a copy +/// of this software and associated documentation files (the "Software"), to deal +/// in the Software without restriction, including without limitation the rights +/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +/// copies of the Software, and to permit persons to whom the Software is +/// furnished to do so, subject to the following conditions: +/// +/// @copyright +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// @copyright +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +/// SOFTWARE. + +/// +/// @brief Handle NMIs. This is required by Intel. +/// +/// +/// @param gs the gs_t to use +/// @param tls the tls_t to use +/// @param sys the bf_syscall_t to use +/// @param vsid the ID of the VS that generated the VMExit +/// @return Returns bsl::errc_success on success, bsl::errc_failure +/// and friends otherwise +/// +pub fn dispatch_vmexit_nmi( + gs: &crate::GsT, + tls: &crate::TlsT, + sys: &mut syscall::BfSyscallT, + vsid: bsl::SafeU16, +) -> bsl::ErrcType { + let vmcs_set_nmi_window_exiting = bsl::SafeU64::new(0x400000); + let ctls_idx = syscall::BF_REG_T_PRIMARY_PROC_BASED_VM_EXECUTION_CTLS; + + bsl::discard(gs); + bsl::discard(tls); + + // NOTE: + // - If we caught an NMI, we need to inject it into the VM. To do + // this, all we do is enable the NMI window, which will tell us + // when we can safely inject the NMI. + // - Note that the microkernel will do the same thing. If an NMI + // fires while the hypevisor is running, it will enable the NMI + // window, which the extension will see as a VMExit, and must + // from there, inject the NMI into the appropriate VS. + // + + let mut val = sys.bf_vs_op_read(vsid, ctls_idx); + bsl::expects(val.is_valid_and_checked()); + + val |= vmcs_set_nmi_window_exiting; + bsl::expects(sys.bf_vs_op_write(vsid, ctls_idx, val)); + + return sys.bf_vs_op_run_current(); +} diff --git a/example/default_rust/src/x64/intel/dispatch_vmexit_nmi_window.rs b/example/default_rust/src/x64/intel/dispatch_vmexit_nmi_window.rs new file mode 100644 index 00000000..21faf735 --- /dev/null +++ b/example/default_rust/src/x64/intel/dispatch_vmexit_nmi_window.rs @@ -0,0 +1,75 @@ +/// @copyright +/// Copyright (C) 2020 Assured Information Security, Inc. +/// +/// @copyright +/// Permission is hereby granted, free of charge, to any person obtaining a copy +/// of this software and associated documentation files (the "Software"), to deal +/// in the Software without restriction, including without limitation the rights +/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +/// copies of the Software, and to permit persons to whom the Software is +/// furnished to do so, subject to the following conditions: +/// +/// @copyright +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// @copyright +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +/// SOFTWARE. + +/// +/// @brief Handle NMIs Windows +/// +/// +/// @param gs the gs_t to use +/// @param tls the tls_t to use +/// @param sys the bf_syscall_t to use +/// @param vsid the ID of the VS that generated the VMExit +/// @return Returns bsl::errc_success on success, bsl::errc_failure +/// and friends otherwise +/// +pub fn dispatch_vmexit_nmi_window( + gs: &crate::GsT, + tls: &crate::TlsT, + sys: &mut syscall::BfSyscallT, + vsid: bsl::SafeU16, +) -> bsl::ErrcType { + let nmi_info = bsl::SafeU64::new(0x80000202); + let vmcs_clear_nmi_window_exiting = bsl::SafeU64::new(0xFFBFFFFF); + let ctls_idx = syscall::BF_REG_T_PRIMARY_PROC_BASED_VM_EXECUTION_CTLS; + let info_idx = syscall::BF_REG_T_VMENTRY_INTERRUPT_INFORMATION_FIELD; + + bsl::discard(gs); + bsl::discard(tls); + + // NOTE: + // - If we see this exit, it is because an NMI fired. There are two + // situations where this could occur, either while the hypervisor + // is running, or the VS is running. In either case, we need to + // clear the NMI window and inject the NMI into the appropriate + // VS so that it can be handled. Note that Intel requires that + // we handle NMIs, and they actually happen a lot with Linux based + // on what hardware you are using (e.g., a laptop). + // + + let mut val = sys.bf_vs_op_read(vsid, ctls_idx); + bsl::expects(val.is_valid_and_checked()); + + val &= vmcs_clear_nmi_window_exiting; + bsl::expects(sys.bf_vs_op_write(vsid, ctls_idx, val)); + + // NOTE: + // - Inject an NMI. If the NMI window was enabled, it is because we + // need to inject a NMI. Note that the NMI window can be enabled + // both by this extension, as well as by the microkernel itself, + // so we are required to implement it on Intel. + // + + bsl::expects(sys.bf_vs_op_write(vsid, info_idx, nmi_info)); + return sys.bf_vs_op_run_current(); +} diff --git a/example/nested_paging/x64/amd/npdpt_t.hpp b/example/default_rust/src/x64/intel/gs_initialize.rs similarity index 62% rename from example/nested_paging/x64/amd/npdpt_t.hpp rename to example/default_rust/src/x64/intel/gs_initialize.rs index cbd1607c..21163aab 100644 --- a/example/nested_paging/x64/amd/npdpt_t.hpp +++ b/example/default_rust/src/x64/intel/gs_initialize.rs @@ -22,32 +22,28 @@ /// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE /// SOFTWARE. -#ifndef NPDPT_T_HPP -#define NPDPT_T_HPP +/// +/// @brief Initializes the Global Storage (GS). +/// +/// +/// @param gs the gs_t to use +/// @param sys the bf_syscall_t to use +/// @param intrinsic the intrinsic_t to use +/// @return Returns bsl::errc_success on success, bsl::errc_failure +/// and friends otherwise +/// +pub fn gs_initialize( + gs: &mut crate::GsT, + sys: &syscall::BfSyscallT, + intrinsic: &crate::IntrinsicT, +) -> bsl::ErrcType { + bsl::discard(intrinsic); -#include + gs.msr_bitmap = sys.bf_mem_op_alloc_page::(&mut gs.msr_bitmap_phys); + if core::ptr::null_mut() == gs.msr_bitmap { + print_v!("{}", bsl::here()); + return bsl::errc_failure; + } -#include -#include -#include - -#pragma pack(push, 1) - -namespace example -{ - /// @brief defined the expected size of the npdpt_t struct - constexpr bsl::safe_umx NUM_NPDPT_ENTRIES{bsl::to_umx(512)}; - - /// - /// @brief Defines the layout of a page-directory-pionter table (npdpt). - /// - struct npdpt_t final - { - /// @brief stores the entires in the table - bsl::array entries; - }; + return bsl::errc_success; } - -#pragma pack(pop) - -#endif diff --git a/example/nested_paging/x64/amd/npml4t_t.hpp b/example/default_rust/src/x64/intel/gs_t.rs similarity index 58% rename from example/nested_paging/x64/amd/npml4t_t.hpp rename to example/default_rust/src/x64/intel/gs_t.rs index 24f1d586..b545eece 100644 --- a/example/nested_paging/x64/amd/npml4t_t.hpp +++ b/example/default_rust/src/x64/intel/gs_t.rs @@ -22,34 +22,31 @@ /// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE /// SOFTWARE. -#ifndef NPML4T_T_HPP -#define NPML4T_T_HPP - -#include - -#include -#include -#include - -#pragma pack(push, 1) - -namespace example -{ - /// @brief defined the expected size of the npml4t_t struct - constexpr bsl::safe_umx NUM_NPML4T_ENTRIES{bsl::to_umx(512)}; - - /// @struct example::npml4t_t - /// - /// - /// @brief Defines the layout of a page-map level-4 table (pml4). - /// - struct npml4t_t final - { - /// @brief stores the entires in the table - bsl::array entries; - }; +/// +/// @brief Defines the extension's Global Storage (GS). +/// Extensions can use this to store global variables as needed. +/// The gs_t can also be used during unit testing to store testing +/// specific logic and data to ensure tests can support constexpr +/// style unit testing. Also note that this is stored in the arch +/// specific folders as it usually needs to store arch specific +/// resources. +/// +#[derive(Debug, Copy, Clone)] +pub struct GsT { + /// @brief stores the MSR bitmap used by this vs_t + pub msr_bitmap: *mut u8, + /// @brief stores the physical address of the MSR bitmap above + pub msr_bitmap_phys: bsl::SafeU64, } -#pragma pack(pop) - -#endif +impl GsT { + /// + /// @brief creates a new GsT + /// + pub const fn new() -> Self { + Self { + msr_bitmap: core::ptr::null_mut(), + msr_bitmap_phys: bsl::SafeU64::new(0), + } + } +} diff --git a/example/default_rust/src/x64/intel/tls_initialize.rs b/example/default_rust/src/x64/intel/tls_initialize.rs new file mode 100644 index 00000000..1803aa8c --- /dev/null +++ b/example/default_rust/src/x64/intel/tls_initialize.rs @@ -0,0 +1,45 @@ +/// @copyright +/// Copyright (C) 2020 Assured Information Security, Inc. +/// +/// @copyright +/// Permission is hereby granted, free of charge, to any person obtaining a copy +/// of this software and associated documentation files (the "Software"), to deal +/// in the Software without restriction, including without limitation the rights +/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +/// copies of the Software, and to permit persons to whom the Software is +/// furnished to do so, subject to the following conditions: +/// +/// @copyright +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// @copyright +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +/// SOFTWARE. + +/// +/// @brief Initializes the Thread Local Storage (TLS). +/// +/// +/// @param tls the tls_t to use +/// @param sys the bf_syscall_t to use +/// @param intrinsic the intrinsic_t to use +/// @return Returns bsl::errc_success on success, bsl::errc_failure +/// and friends otherwise +/// +pub fn tls_initialize( + tls: &crate::TlsT, + sys: &syscall::BfSyscallT, + intrinsic: &crate::IntrinsicT, +) -> bsl::ErrcType { + bsl::discard(tls); + bsl::discard(sys); + bsl::discard(intrinsic); + + return bsl::errc_success; +} diff --git a/example/default_rust/src/x64/intel/tls_t.rs b/example/default_rust/src/x64/intel/tls_t.rs new file mode 100644 index 00000000..396fd8e1 --- /dev/null +++ b/example/default_rust/src/x64/intel/tls_t.rs @@ -0,0 +1,53 @@ +/// @copyright +/// Copyright (C) 2020 Assured Information Security, Inc. +/// +/// @copyright +/// Permission is hereby granted, free of charge, to any person obtaining a copy +/// of this software and associated documentation files (the "Software"), to deal +/// in the Software without restriction, including without limitation the rights +/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +/// copies of the Software, and to permit persons to whom the Software is +/// furnished to do so, subject to the following conditions: +/// +/// @copyright +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// @copyright +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +/// SOFTWARE. + +/// +/// @brief Defines the extension's Thread Local Storage (TLS). +/// Extensions can use this to store data specific to a PP as needed. +/// The tls_t can also be used during unit testing to store testing +/// specific logic and data to ensure tests can support constexpr +/// style unit testing. Also note that this is stored in the arch +/// specific folders as it usually needs to store arch specific +/// resources. In this simple example, we leave this empty. +/// +/// +/// @note IMPORTANT: Extensions are limited to a single 4k page for the +/// TLS data. Technically, extensions are given 2 4k pages, but one of +/// the pages is dedicated to TLS data defined by the specification +/// and populated by the microkernel (e.g., the general purpose +/// registers and ID information). For this reason, if more than a +/// page is needed, the TLS block should store pointers to memory that +/// is allocated. +/// +#[derive(Debug, Default, Copy, Clone)] +pub struct TlsT {} + +impl TlsT { + /// + /// @brief creates a new TlsT + /// + pub const fn new() -> Self { + Self {} + } +} diff --git a/example/default_rust/src/x64/intel/vs_t.rs b/example/default_rust/src/x64/intel/vs_t.rs new file mode 100644 index 00000000..966cd368 --- /dev/null +++ b/example/default_rust/src/x64/intel/vs_t.rs @@ -0,0 +1,284 @@ +/// @copyright +/// Copyright (C) 2020 Assured Information Security, Inc. +/// +/// @copyright +/// Permission is hereby granted, free of charge, to any person obtaining a copy +/// of this software and associated documentation files (the "Software"), to deal +/// in the Software without restriction, including without limitation the rights +/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +/// copies of the Software, and to permit persons to whom the Software is +/// furnished to do so, subject to the following conditions: +/// +/// @copyright +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// @copyright +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +/// SOFTWARE. + +#[derive(Debug, Copy, Clone)] +pub struct VsT { + /// @brief stores the ID associated with this VsT + m_id: bsl::SafeU16, + /// @brief stores whether or not this VsT is allocated. + m_allocated: crate::AllocatedStatusT, + /// @brief stores the ID of the VP this VsT is assigned to + m_assigned_vpid: bsl::SafeU16, + /// @brief stores the ID of the PP this VsT is assigned to + m_assigned_ppid: bsl::SafeU16, +} + +impl VsT { + /// + /// @brief creates a new VsT + /// + pub const fn new() -> Self { + Self { + m_id: bsl::SafeU16::new(0), + m_allocated: crate::AllocatedStatusT::Deallocated, + m_assigned_vpid: bsl::SafeU16::new(0), + m_assigned_ppid: bsl::SafeU16::new(0), + } + } + + /// + /// @brief Initializes this VsT + /// + /// + /// @param gs the gs_t to use + /// @param tls the tls_t to use + /// @param sys the bf_syscall_t to use + /// @param intrinsic the intrinsic_t to use + /// @param i the ID for this VsT + /// + pub fn initialize( + &mut self, + gs: &crate::GsT, + tls: &crate::TlsT, + sys: &syscall::BfSyscallT, + intrinsic: &crate::IntrinsicT, + i: bsl::SafeU16, + ) { + bsl::expects(self.id() == syscall::BF_INVALID_ID); + bsl::expects(self.m_allocated == crate::AllocatedStatusT::Deallocated); + + bsl::expects(i.is_valid_and_checked()); + bsl::expects(i != syscall::BF_INVALID_ID); + + bsl::discard(gs); + bsl::discard(tls); + bsl::discard(sys); + bsl::discard(intrinsic); + + self.m_id = !i; + } + + /// + /// @brief Release the VsT. + /// + /// + /// @param gs the gs_t to use + /// @param tls the tls_t to use + /// @param sys the bf_syscall_t to use + /// @param intrinsic the intrinsic_t to use + /// + pub fn release( + &mut self, + gs: &crate::GsT, + tls: &crate::TlsT, + sys: &syscall::BfSyscallT, + intrinsic: &crate::IntrinsicT, + ) { + self.deallocate(gs, tls, sys, intrinsic); + self.m_id = bsl::SafeU16::default(); + } + + /// + /// @brief Returns the ID of this VsT + /// + /// + /// @return Returns the ID of this VsT + /// + pub fn id(&self) -> bsl::SafeU16 { + bsl::ensures(self.m_id.is_valid_and_checked()); + return !self.m_id; + } + + /// + /// @brief Allocates the VsT and returns it's ID + /// + /// + /// @param gs the gs_t to use + /// @param tls the tls_t to use + /// @param sys the bf_syscall_t to use + /// @param intrinsic the intrinsic_t to use + /// @param vpid the ID of the VP to assign the VsT to + /// @param ppid the ID of the PP to assign the VsT to + /// @return Returns ID of this VsT + /// + pub fn allocate( + &mut self, + gs: &crate::GsT, + tls: &crate::TlsT, + sys: &mut syscall::BfSyscallT, + intrinsic: &crate::IntrinsicT, + vpid: bsl::SafeU16, + ppid: bsl::SafeU16, + ) -> bsl::SafeU16 { + bsl::expects(self.id() != syscall::BF_INVALID_ID); + bsl::expects(crate::AllocatedStatusT::Deallocated == self.m_allocated); + + bsl::expects(vpid.is_valid_and_checked()); + bsl::expects(vpid != syscall::BF_INVALID_ID); + bsl::expects(ppid.is_valid_and_checked()); + bsl::expects(ppid != syscall::BF_INVALID_ID); + + bsl::discard(gs); + bsl::discard(tls); + bsl::discard(intrinsic); + + let vmcs_vpid_val = bsl::SafeU64::new(0x1); + let vmcs_vpid_idx = syscall::BF_REG_T_VIRTUAL_PROCESSOR_IDENTIFIER; + bsl::expects(sys.bf_vs_op_write(self.id(), vmcs_vpid_idx, vmcs_vpid_val)); + + let vmcs_link_ptr_val = bsl::SafeU64::new(0xFFFFFFFFFFFFFFFF); + let vmcs_link_ptr_idx = syscall::BF_REG_T_VMCS_LINK_POINTER; + bsl::expects(sys.bf_vs_op_write(self.id(), vmcs_link_ptr_idx, vmcs_link_ptr_val)); + + let pin_ctls = bsl::SafeU64::default(); + let mut proc_ctls = bsl::SafeU64::default(); + let exit_ctls = bsl::SafeU64::default(); + let mut entry_ctls = bsl::SafeU64::default(); + let mut proc2_ctls = bsl::SafeU64::default(); + + let enable_msr_bitmaps = bsl::SafeU64::new(0x10000000); + let enable_proc2_ctls = bsl::SafeU64::new(0x80000000); + + proc_ctls |= enable_msr_bitmaps; + proc_ctls |= enable_proc2_ctls; + + let enable_ia32e_mode = bsl::SafeU64::new(0x00000200); + + entry_ctls |= enable_ia32e_mode; + + let enable_vpid = bsl::SafeU64::new(0x00000020); + let enable_rdtscp = bsl::SafeU64::new(0x00000008); + let enable_invpcid = bsl::SafeU64::new(0x00001000); + let enable_xsave = bsl::SafeU64::new(0x00100000); + let enable_uwait = bsl::SafeU64::new(0x04000000); + + proc2_ctls |= enable_vpid; + proc2_ctls |= enable_rdtscp; + proc2_ctls |= enable_invpcid; + proc2_ctls |= enable_xsave; + proc2_ctls |= enable_uwait; + + let idx = syscall::BF_REG_T_PIN_BASED_VM_EXECUTION_CTLS; + bsl::expects(sys.bf_vs_op_write(self.id(), idx, pin_ctls)); + + let idx = syscall::BF_REG_T_PRIMARY_PROC_BASED_VM_EXECUTION_CTLS; + bsl::expects(sys.bf_vs_op_write(self.id(), idx, proc_ctls)); + + let idx = syscall::BF_REG_T_VMEXIT_CTLS; + bsl::expects(sys.bf_vs_op_write(self.id(), idx, exit_ctls)); + + let idx = syscall::BF_REG_T_VMENTRY_CTLS; + bsl::expects(sys.bf_vs_op_write(self.id(), idx, entry_ctls)); + + let idx = syscall::BF_REG_T_SECONDARY_PROC_BASED_VM_EXECUTION_CTLS; + bsl::expects(sys.bf_vs_op_write(self.id(), idx, proc2_ctls)); + + let idx = syscall::BF_REG_T_ADDRESS_OF_MSR_BITMAPS; + bsl::expects(sys.bf_vs_op_write(self.id(), idx, gs.msr_bitmap_phys)); + + if syscall::BfSyscallT::is_vs_a_root_vs(self.id()) { + bsl::expects(sys.bf_vs_op_init_as_root(self.id())); + } else { + bsl::touch(); + } + + self.m_assigned_vpid = !vpid; + self.m_assigned_ppid = !ppid; + self.m_allocated = crate::AllocatedStatusT::Allocated; + + return self.id(); + } + + /// + /// @brief Deallocates the VsT + /// + /// + /// @param gs the gs_t to use + /// @param tls the tls_t to use + /// @param sys the bf_syscall_t to use + /// @param intrinsic the intrinsic_t to use + /// + pub fn deallocate( + &mut self, + gs: &crate::GsT, + tls: &crate::TlsT, + sys: &syscall::BfSyscallT, + intrinsic: &crate::IntrinsicT, + ) { + bsl::discard(gs); + bsl::discard(tls); + bsl::discard(sys); + bsl::discard(intrinsic); + + self.m_assigned_ppid = bsl::SafeU16::default(); + self.m_assigned_vpid = bsl::SafeU16::default(); + self.m_allocated = crate::AllocatedStatusT::Deallocated; + } + + /// + /// @brief Returns true if this VsT is allocated, false otherwise + /// + /// + /// @return Returns true if this VsT is allocated, false otherwise + /// + pub fn is_allocated(&self) -> bool { + return self.m_allocated == crate::AllocatedStatusT::Allocated; + } + + /// + /// @brief Returns true if this VsT is deallocated, false otherwise + /// + /// + /// @return Returns true if this VsT is deallocated, false otherwise + /// + pub fn is_deallocated(&self) -> bool { + return self.m_allocated == crate::AllocatedStatusT::Deallocated; + } + + /// + /// @brief Returns the ID of the VP this VsT is assigned to. If + /// this VsT is not assigned, syscall::BF_INVALID_ID is returned. + /// + /// + /// @return Returns the ID of the VP this VsT is assigned to. If + /// this VsT is not assigned, syscall::BF_INVALID_ID is returned. + /// + pub fn assigned_vp(&self) -> bsl::SafeU16 { + bsl::ensures(self.m_assigned_vpid.is_valid_and_checked()); + return !self.m_assigned_vpid; + } + + /// + /// @brief Returns the ID of the PP this VsT is assigned to. If + /// this VsT is not assigned, syscall::BF_INVALID_ID is returned. + /// + /// + /// @return Returns the ID of the PP this VsT is assigned to. If + /// this VsT is not assigned, syscall::BF_INVALID_ID is returned. + /// + pub fn assigned_pp(&self) -> bsl::SafeU16 { + bsl::ensures(self.m_assigned_ppid.is_valid_and_checked()); + return !self.m_assigned_ppid; + } +} diff --git a/example/nested_paging/x64/intrinsic_cpuid.S b/example/default_rust/src/x64/intrinsic_cpuid_impl.S similarity index 81% rename from example/nested_paging/x64/intrinsic_cpuid.S rename to example/default_rust/src/x64/intrinsic_cpuid_impl.S index 71f80864..98e67426 100644 --- a/example/nested_paging/x64/intrinsic_cpuid.S +++ b/example/default_rust/src/x64/intrinsic_cpuid_impl.S @@ -27,26 +27,26 @@ .code64 .intel_syntax noprefix - .globl intrinsic_cpuid - .type intrinsic_cpuid, @function -intrinsic_cpuid: + .globl intrinsic_cpuid_impl + .type intrinsic_cpuid_impl, @function +intrinsic_cpuid_impl: push rbx mov r10, rdx mov r11, rcx - mov rax, [rdi] - mov rbx, [rsi] - mov rcx, [r10] - mov rdx, [r11] + mov eax, [rdi] + mov ebx, [rsi] + mov ecx, [r10] + mov edx, [r11] cpuid - mov [rdi], rax - mov [rsi], rbx - mov [r10], rcx - mov [r11], rdx + mov [rdi], eax + mov [rsi], ebx + mov [r10], ecx + mov [r11], edx pop rbx ret int 3 - .size intrinsic_cpuid, .-intrinsic_cpuid + .size intrinsic_cpuid_impl, .-intrinsic_cpuid_impl diff --git a/example/nested_paging/arm/common_arch_support.hpp b/example/default_rust/src/x64/intrinsic_cpuid_impl.rs similarity index 70% rename from example/nested_paging/arm/common_arch_support.hpp rename to example/default_rust/src/x64/intrinsic_cpuid_impl.rs index dd82eaea..ec551804 100644 --- a/example/nested_paging/arm/common_arch_support.hpp +++ b/example/default_rust/src/x64/intrinsic_cpuid_impl.rs @@ -22,7 +22,17 @@ /// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE /// SOFTWARE. -#ifndef COMMON_ARCH_SUPPORT_HPP -#define COMMON_ARCH_SUPPORT_HPP - -#endif +/// +/// @brief Executes the CPUID instruction given the provided EAX and ECX +/// and returns the results +/// +/// +/// @param gs ignored +/// @param rax the index used by CPUID, returns resulting rax +/// @param rbx returns resulting rbx +/// @param rcx the subindex used by CPUID, returns the resulting rcx +/// @param rdx returns resulting rdx +/// +extern "C" { + pub fn intrinsic_cpuid_impl(rax: *mut u64, rbx: *mut u64, rcx: *mut u64, rdx: *mut u64); +} diff --git a/example/nested_paging/x64/intrinsic_cpuid.hpp b/example/default_rust/src/x64/intrinsic_t.rs similarity index 69% rename from example/nested_paging/x64/intrinsic_cpuid.hpp rename to example/default_rust/src/x64/intrinsic_t.rs index 8b48fc35..d9da6490 100644 --- a/example/nested_paging/x64/intrinsic_cpuid.hpp +++ b/example/default_rust/src/x64/intrinsic_t.rs @@ -22,16 +22,25 @@ /// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE /// SOFTWARE. -#ifndef INTRINSIC_CPUID_HPP -#define INTRINSIC_CPUID_HPP +#[path = "intrinsic_cpuid_impl.rs"] +#[doc(hidden)] +pub mod intrinsic_cpuid_impl; +pub use intrinsic_cpuid_impl::*; -#include +#[derive(Debug, Copy, Clone)] +pub struct IntrinsicT {} -namespace example -{ +impl IntrinsicT { /// - /// @brief Executes the CPUID instruction given the provided EAX and ECX - /// and returns the results + /// @brief creates a new IntrinsicT + /// + pub const fn new() -> Self { + Self {} + } + + /// + /// @brief Executes the CPUID instruction given the provided + /// EAX and ECX and returns the results. /// /// /// @param rax the index used by CPUID, returns resulting rax @@ -39,11 +48,17 @@ namespace example /// @param rcx the subindex used by CPUID, returns the resulting rcx /// @param rdx returns resulting rdx /// - extern "C" void intrinsic_cpuid( - bsl::uint64 *const rax, - bsl::uint64 *const rbx, - bsl::uint64 *const rcx, - bsl::uint64 *const rdx) noexcept; -} + pub fn cpuid( + &self, + rax: &mut bsl::SafeU64, + rbx: &mut bsl::SafeU64, + rcx: &mut bsl::SafeU64, + rdx: &mut bsl::SafeU64, + ) { + bsl::discard(self); -#endif + unsafe { + intrinsic_cpuid_impl(rax.data(), rbx.data(), rcx.data(), rdx.data()); + } + } +} diff --git a/example/default_rust/tests/Cargo.toml b/example/default_rust/tests/Cargo.toml deleted file mode 100644 index 50c2fa70..00000000 --- a/example/default_rust/tests/Cargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[package] -name = "tests" -version = "0.1.0" -edition = "2018" - -[[bin]] -name = "tests" -path = "main.rs" diff --git a/example/default_rust/tests/main.rs b/example/default_rust/tests/main.rs deleted file mode 100644 index b49f1525..00000000 --- a/example/default_rust/tests/main.rs +++ /dev/null @@ -1,2 +0,0 @@ -#[path = "../src/println.rs"] -mod println; diff --git a/example/default_rust/tests/target/.rustc_info.json b/example/default_rust/tests/target/.rustc_info.json deleted file mode 100644 index e539b339..00000000 --- a/example/default_rust/tests/target/.rustc_info.json +++ /dev/null @@ -1 +0,0 @@ -{"rustc_fingerprint":16168608315693230404,"outputs":{"17598535894874457435":{"success":true,"status":"","code":0,"stdout":"rustc 1.54.0 (a178d0322 2021-07-26)\nbinary: rustc\ncommit-hash: a178d0322ce20e33eac124758e837cbd80a6f633\ncommit-date: 2021-07-26\nhost: x86_64-unknown-linux-gnu\nrelease: 1.54.0\nLLVM version: 12.0.1\n","stderr":""},"2797684049618456168":{"success":false,"status":"exit status: 1","code":1,"stdout":"","stderr":"error: `-Csplit-debuginfo` is unstable on this platform\n\n"},"931469667778813386":{"success":true,"status":"","code":0,"stdout":"___\nlib___.rlib\nlib___.so\nlib___.so\nlib___.a\nlib___.so\n/home/user/.rustup/toolchains/stable-x86_64-unknown-linux-gnu\ndebug_assertions\nproc_macro\ntarget_arch=\"x86_64\"\ntarget_endian=\"little\"\ntarget_env=\"gnu\"\ntarget_family=\"unix\"\ntarget_feature=\"fxsr\"\ntarget_feature=\"sse\"\ntarget_feature=\"sse2\"\ntarget_os=\"linux\"\ntarget_pointer_width=\"64\"\ntarget_vendor=\"unknown\"\nunix\n","stderr":""}},"successes":{}} \ No newline at end of file diff --git a/example/default_rust/tests/target/CACHEDIR.TAG b/example/default_rust/tests/target/CACHEDIR.TAG deleted file mode 100644 index 20d7c319..00000000 --- a/example/default_rust/tests/target/CACHEDIR.TAG +++ /dev/null @@ -1,3 +0,0 @@ -Signature: 8a477f597d28d172789f06886806bc55 -# This file is a cache directory tag created by cargo. -# For information about cache directory tags see https://bford.info/cachedir/ diff --git a/example/default_rust/tests/target/debug/.cargo-lock b/example/default_rust/tests/target/debug/.cargo-lock deleted file mode 100644 index e69de29b..00000000 diff --git a/example/default_rust/tests/target/debug/.fingerprint/tests-7c0c65c68d3b1808/dep-test-bin-tests b/example/default_rust/tests/target/debug/.fingerprint/tests-7c0c65c68d3b1808/dep-test-bin-tests deleted file mode 100644 index 99b2a769..00000000 Binary files a/example/default_rust/tests/target/debug/.fingerprint/tests-7c0c65c68d3b1808/dep-test-bin-tests and /dev/null differ diff --git a/example/default_rust/tests/target/debug/.fingerprint/tests-7c0c65c68d3b1808/invoked.timestamp b/example/default_rust/tests/target/debug/.fingerprint/tests-7c0c65c68d3b1808/invoked.timestamp deleted file mode 100644 index e00328da..00000000 --- a/example/default_rust/tests/target/debug/.fingerprint/tests-7c0c65c68d3b1808/invoked.timestamp +++ /dev/null @@ -1 +0,0 @@ -This file has an mtime of when this was started. \ No newline at end of file diff --git a/example/default_rust/tests/target/debug/.fingerprint/tests-7c0c65c68d3b1808/test-bin-tests b/example/default_rust/tests/target/debug/.fingerprint/tests-7c0c65c68d3b1808/test-bin-tests deleted file mode 100644 index a96084f4..00000000 --- a/example/default_rust/tests/target/debug/.fingerprint/tests-7c0c65c68d3b1808/test-bin-tests +++ /dev/null @@ -1 +0,0 @@ -60788f050c778f09 \ No newline at end of file diff --git a/example/default_rust/tests/target/debug/.fingerprint/tests-7c0c65c68d3b1808/test-bin-tests.json b/example/default_rust/tests/target/debug/.fingerprint/tests-7c0c65c68d3b1808/test-bin-tests.json deleted file mode 100644 index 154425d7..00000000 --- a/example/default_rust/tests/target/debug/.fingerprint/tests-7c0c65c68d3b1808/test-bin-tests.json +++ /dev/null @@ -1 +0,0 @@ -{"rustc":17807758859236181817,"features":"[]","target":8443017735982037405,"profile":14050059120794533848,"path":11302273381135081700,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/tests-7c0c65c68d3b1808/dep-test-bin-tests"}}],"rustflags":[],"metadata":7797948686568424061,"config":0,"compile_kind":0} \ No newline at end of file diff --git a/example/default_rust/tests/target/debug/deps/tests-7c0c65c68d3b1808 b/example/default_rust/tests/target/debug/deps/tests-7c0c65c68d3b1808 deleted file mode 100755 index c1daaff5..00000000 Binary files a/example/default_rust/tests/target/debug/deps/tests-7c0c65c68d3b1808 and /dev/null differ diff --git a/example/default_rust/tests/target/debug/incremental/tests-2x6wh4jy50g8g/s-g1o22ovy83-debazt-1gorwcmcqn3gf/dep-graph.bin b/example/default_rust/tests/target/debug/incremental/tests-2x6wh4jy50g8g/s-g1o22ovy83-debazt-1gorwcmcqn3gf/dep-graph.bin deleted file mode 100644 index 722a6502..00000000 Binary files a/example/default_rust/tests/target/debug/incremental/tests-2x6wh4jy50g8g/s-g1o22ovy83-debazt-1gorwcmcqn3gf/dep-graph.bin and /dev/null differ diff --git a/example/default_rust/tests/target/debug/incremental/tests-2x6wh4jy50g8g/s-g1o22ovy83-debazt-1gorwcmcqn3gf/query-cache.bin b/example/default_rust/tests/target/debug/incremental/tests-2x6wh4jy50g8g/s-g1o22ovy83-debazt-1gorwcmcqn3gf/query-cache.bin deleted file mode 100644 index e444d6c3..00000000 Binary files a/example/default_rust/tests/target/debug/incremental/tests-2x6wh4jy50g8g/s-g1o22ovy83-debazt-1gorwcmcqn3gf/query-cache.bin and /dev/null differ diff --git a/example/default_rust/tests/target/debug/incremental/tests-2x6wh4jy50g8g/s-g1o22ovy83-debazt-1gorwcmcqn3gf/work-products.bin b/example/default_rust/tests/target/debug/incremental/tests-2x6wh4jy50g8g/s-g1o22ovy83-debazt-1gorwcmcqn3gf/work-products.bin deleted file mode 100644 index 6bc0b05d..00000000 Binary files a/example/default_rust/tests/target/debug/incremental/tests-2x6wh4jy50g8g/s-g1o22ovy83-debazt-1gorwcmcqn3gf/work-products.bin and /dev/null differ diff --git a/example/default_rust/src/x86_64-unknown-none.json b/example/default_rust/x86_64-unknown-none.json similarity index 93% rename from example/default_rust/src/x86_64-unknown-none.json rename to example/default_rust/x86_64-unknown-none.json index eab996a0..155da631 100644 --- a/example/default_rust/src/x86_64-unknown-none.json +++ b/example/default_rust/x86_64-unknown-none.json @@ -8,7 +8,7 @@ "os": "none", "executables": true, "linker-flavor": "ld.lld", - "linker": "rust-lld", + "linker": "ld.lld", "panic-strategy": "abort", "features": "-mmx,-sse,+soft-float" } diff --git a/example/nested_paging/CMakeLists.txt b/example/nested_paging/CMakeLists.txt deleted file mode 100644 index e7bbeeb6..00000000 --- a/example/nested_paging/CMakeLists.txt +++ /dev/null @@ -1,160 +0,0 @@ -# -# Copyright (C) 2020 Assured Information Security, Inc. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - -add_executable(example_nested_paging) - -# ------------------------------------------------------------------------------ -# Includes -# ------------------------------------------------------------------------------ - -if(HYPERVISOR_TARGET_ARCH STREQUAL "AuthenticAMD" OR HYPERVISOR_TARGET_ARCH STREQUAL "GenuineIntel") - target_include_directories(example_nested_paging PRIVATE - x64 - ) - - if(HYPERVISOR_TARGET_ARCH STREQUAL "AuthenticAMD") - target_include_directories(example_nested_paging PRIVATE - x64/amd - ) - endif() - - if(HYPERVISOR_TARGET_ARCH STREQUAL "GenuineIntel") - target_include_directories(example_nested_paging PRIVATE - x64/intel - ) - endif() -endif() - -if(HYPERVISOR_TARGET_ARCH STREQUAL "aarch64") - target_include_directories(example_nested_paging PRIVATE - arm - ) - - if(HYPERVISOR_TARGET_ARCH STREQUAL "aarch64") - target_include_directories(example_nested_paging PRIVATE - arm/aarch64 - ) - endif() -endif() - -target_include_directories(example_nested_paging PRIVATE - . -) - -# ------------------------------------------------------------------------------ -# Headers -# ------------------------------------------------------------------------------ - -list(APPEND HEADERS - ${CMAKE_CURRENT_LIST_DIR}/page_pool_t.hpp -) - -if(HYPERVISOR_TARGET_ARCH STREQUAL "AuthenticAMD" OR HYPERVISOR_TARGET_ARCH STREQUAL "GenuineIntel") - list(APPEND HEADERS - ${CMAKE_CURRENT_LIST_DIR}/x64/common_arch_support.hpp - ${CMAKE_CURRENT_LIST_DIR}/x64/intrinsic_cpuid.hpp - ${CMAKE_CURRENT_LIST_DIR}/x64/map_page_flags.hpp - ${CMAKE_CURRENT_LIST_DIR}/x64/memory_type.hpp - ${CMAKE_CURRENT_LIST_DIR}/x64/mtrrs_t.hpp - ${CMAKE_CURRENT_LIST_DIR}/x64/range_t.hpp - ) - - if(HYPERVISOR_TARGET_ARCH STREQUAL "AuthenticAMD") - list(APPEND HEADERS - ${CMAKE_CURRENT_LIST_DIR}/x64/amd/arch_support.hpp - ${CMAKE_CURRENT_LIST_DIR}/x64/amd/nested_page_table_t.hpp - ${CMAKE_CURRENT_LIST_DIR}/x64/amd/npdpt_t.hpp - ${CMAKE_CURRENT_LIST_DIR}/x64/amd/npdpte_t.hpp - ${CMAKE_CURRENT_LIST_DIR}/x64/amd/npdt_t.hpp - ${CMAKE_CURRENT_LIST_DIR}/x64/amd/npdte_t.hpp - ${CMAKE_CURRENT_LIST_DIR}/x64/amd/npml4t_t.hpp - ${CMAKE_CURRENT_LIST_DIR}/x64/amd/npml4te_t.hpp - ${CMAKE_CURRENT_LIST_DIR}/x64/amd/npt_t.hpp - ${CMAKE_CURRENT_LIST_DIR}/x64/amd/npte_t.hpp - ) - endif() - - if(HYPERVISOR_TARGET_ARCH STREQUAL "GenuineIntel") - list(APPEND HEADERS - ${CMAKE_CURRENT_LIST_DIR}/x64/intel/arch_support.hpp - ${CMAKE_CURRENT_LIST_DIR}/x64/intel/epdpt_t.hpp - ${CMAKE_CURRENT_LIST_DIR}/x64/intel/epdpte_t.hpp - ${CMAKE_CURRENT_LIST_DIR}/x64/intel/epdt_t.hpp - ${CMAKE_CURRENT_LIST_DIR}/x64/intel/epdte_t.hpp - ${CMAKE_CURRENT_LIST_DIR}/x64/intel/epml4t_t.hpp - ${CMAKE_CURRENT_LIST_DIR}/x64/intel/epml4te_t.hpp - ${CMAKE_CURRENT_LIST_DIR}/x64/intel/ept_t.hpp - ${CMAKE_CURRENT_LIST_DIR}/x64/intel/epte_t.hpp - ${CMAKE_CURRENT_LIST_DIR}/x64/intel/extended_page_table_t.hpp - ) - endif() -endif() - -if(HYPERVISOR_TARGET_ARCH STREQUAL "aarch64") - list(APPEND HEADERS - ${CMAKE_CURRENT_LIST_DIR}/arm/common_arch_support.hpp - ) - - if(HYPERVISOR_TARGET_ARCH STREQUAL "aarch64") - list(APPEND HEADERS - ${CMAKE_CURRENT_LIST_DIR}/arm/aarch64/arch_support.hpp - ) - endif() -endif() - -# ------------------------------------------------------------------------------ -# Sources -# ------------------------------------------------------------------------------ - -target_sources(example_nested_paging PRIVATE - main.cpp -) - -set_property(SOURCE main.cpp APPEND PROPERTY OBJECT_DEPENDS ${HEADERS}) - -if(HYPERVISOR_TARGET_ARCH STREQUAL "AuthenticAMD" OR HYPERVISOR_TARGET_ARCH STREQUAL "GenuineIntel") - target_sources(example_nested_paging PRIVATE - x64/intrinsic_cpuid.S - ) - - set_property(SOURCE x64/intrinsic_cpuid.S APPEND PROPERTY OBJECT_DEPENDS ${HEADERS}) -endif() - -# ------------------------------------------------------------------------------ -# Libraries -# ------------------------------------------------------------------------------ - -target_link_libraries(example_nested_paging PRIVATE - runtime - bsl - loader - syscall -) - -# ------------------------------------------------------------------------------ -# Install -# ------------------------------------------------------------------------------ - -if(CMAKE_BUILD_TYPE STREQUAL RELEASE OR CMAKE_BUILD_TYPE STREQUAL MINSIZEREL) - add_custom_command(TARGET example_nested_paging POST_BUILD COMMAND ${CMAKE_STRIP} example_nested_paging) -endif() - -install(TARGETS example_nested_paging DESTINATION bin) diff --git a/example/nested_paging/arm/aarch64/arch_support.hpp b/example/nested_paging/arm/aarch64/arch_support.hpp deleted file mode 100644 index 5ba1b00a..00000000 --- a/example/nested_paging/arm/aarch64/arch_support.hpp +++ /dev/null @@ -1,77 +0,0 @@ -/// @copyright -/// Copyright (C) 2020 Assured Information Security, Inc. -/// -/// @copyright -/// Permission is hereby granted, free of charge, to any person obtaining a copy -/// of this software and associated documentation files (the "Software"), to deal -/// in the Software without restriction, including without limitation the rights -/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -/// copies of the Software, and to permit persons to whom the Software is -/// furnished to do so, subject to the following conditions: -/// -/// @copyright -/// The above copyright notice and this permission notice shall be included in -/// all copies or substantial portions of the Software. -/// -/// @copyright -/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -/// SOFTWARE. - -#ifndef ARCH_SUPPORT_HPP -#define ARCH_SUPPORT_HPP - -#include - -#include -#include -#include -#include -#include -#include - -namespace example -{ - /// - /// @brief Implements the architecture specific VMExit handler. - /// - /// - /// @param handle the handle to use - /// @param vsid the ID of the VS that generated the VMExit - /// @param exit_reason the exit reason associated with the VMExit - /// - constexpr void - vmexit( - syscall::bf_handle_t &handle, - bsl::safe_u16 const &vsid, - bsl::safe_u64 const &exit_reason) noexcept - { - bsl::discard(handle); - bsl::discard(vsid); - bsl::discard(exit_reason); - } - - /// - /// @brief Initializes a VS with architecture specific stuff. - /// - /// - /// @param handle the handle to use - /// @param vsid the VS being intialized - /// @return Returns bsl::errc_success on success and bsl::errc_failure - /// on failure. - /// - [[nodiscard]] constexpr auto - init_vs(syscall::bf_handle_t &handle, bsl::safe_u16 const &vsid) noexcept -> bsl::errc_type - { - bsl::discard(handle); - bsl::discard(vsid); - - return bsl::errc_success; - } -} - -#endif diff --git a/example/nested_paging/lock_guard.hpp b/example/nested_paging/lock_guard.hpp deleted file mode 100644 index bccf77f1..00000000 --- a/example/nested_paging/lock_guard.hpp +++ /dev/null @@ -1,108 +0,0 @@ -/// @copyright -/// Copyright (C) 2020 Assured Information Security, Inc. -/// -/// @copyright -/// Permission is hereby granted, free of charge, to any person obtaining a copy -/// of this software and associated documentation files (the "Software"), to deal -/// in the Software without restriction, including without limitation the rights -/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -/// copies of the Software, and to permit persons to whom the Software is -/// furnished to do so, subject to the following conditions: -/// -/// @copyright -/// The above copyright notice and this permission notice shall be included in -/// all copies or substantial portions of the Software. -/// -/// @copyright -/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -/// SOFTWARE. - -#ifndef LOCK_GUARD_HPP -#define LOCK_GUARD_HPP - -namespace example -{ - /// - /// @brief Implements a lock_guard. - /// - /// - /// @tparam T the type of mutex being locked - /// - template - class lock_guard final - { - /// @brief stores the lock that is being guarded - T &m_lock; - - public: - /// - /// @brief Creates a lock_guard, locking the provided - /// spinlock/mutex on construction. - /// - /// - /// @param lck the spinlock/mutex to guard - /// - explicit constexpr lock_guard(T &lck) noexcept // -- - : m_lock{lck} - { - m_lock.lock(); - } - - /// - /// @brief Do not allow temporaries. - /// - /// - /// @param lck the spinlock/mutex to guard - /// - constexpr lock_guard(T const &lck) noexcept = delete; - - /// - /// @brief Destructor - /// - constexpr ~lock_guard() noexcept - { - m_lock.unlock(); - } - - /// - /// @brief copy constructor - /// - /// - /// @param o the object being copied - /// - constexpr lock_guard(lock_guard const &o) noexcept = delete; - - /// - /// @brief move constructor - /// - /// - /// @param o the object being moved - /// - constexpr lock_guard(lock_guard &&o) noexcept = default; - - /// - /// @brief copy assignment - /// - /// - /// @param o the object being copied - /// @return a reference to *this - /// - [[maybe_unused]] auto operator=(lock_guard const &o) noexcept -> lock_guard & = delete; - - /// - /// @brief move assignment - /// - /// - /// @param o the object being moved - /// @return a reference to *this - /// - [[maybe_unused]] auto operator=(lock_guard &&o) noexcept -> lock_guard & = default; - }; -} - -#endif diff --git a/example/nested_paging/main.cpp b/example/nested_paging/main.cpp deleted file mode 100644 index d6f624bb..00000000 --- a/example/nested_paging/main.cpp +++ /dev/null @@ -1,267 +0,0 @@ -/// @copyright -/// Copyright (C) 2020 Assured Information Security, Inc. -/// -/// @copyright -/// Permission is hereby granted, free of charge, to any person obtaining a copy -/// of this software and associated documentation files (the "Software"), to deal -/// in the Software without restriction, including without limitation the rights -/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -/// copies of the Software, and to permit persons to whom the Software is -/// furnished to do so, subject to the following conditions: -/// -/// @copyright -/// The above copyright notice and this permission notice shall be included in -/// all copies or substantial portions of the Software. -/// -/// @copyright -/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -/// SOFTWARE. - -#include -#include - -#include -#include -#include -#include -#include - -namespace example -{ - /// @brief stores the handle the extension will use - constinit inline syscall::bf_handle_t g_handle{}; - - /// - /// @brief Implements the VMExit entry function. This is registered - /// by the main function to execute whenever a VMExit occurs. - /// - /// - /// @param vsid the ID of the VS that generated the VMExit - /// @param exit_reason the exit reason associated with the VMExit - /// - extern "C" void - vmexit_entry(bsl::uint16 const vsid, bsl::uint64 const exit_reason) noexcept - { - vmexit(g_handle, vsid, exit_reason); - - /// NOTE: - /// - This code is only reached if an error occurs. Executing this - /// syscall will tell the microkernel that the VMExit was not - /// handled, in which case it will enter a fast fail state. - /// - - bsl::print() << bsl::here(); - return syscall::bf_control_op_exit(); - } - - /// - /// @brief Implements the fast fail entry function. This is registered - /// by the main function to execute whenever a fast fail occurs. - /// - /// - /// @param fail_reason the exit reason associated with the fail - /// - extern "C" void - fail_entry(bsl::uint64 const fail_reason) noexcept - { - bsl::discard(fail_reason); - - /// NOTE: - /// - Tells the microkernel that we didn't handle the fast fail. - /// When this occurs, the microkernel will halt this PP. In most - /// cases, there are only two options here: - /// - Do the following, and report an error and halt. - /// - Return to a parent VS and continue execution from there, - /// which is typically only possible if you are implementing - /// more than one VS/VP per PP (e.g., when implementing guest - /// support or VSM support). - /// - /// - Another use case is integration testing. We can also use this - /// to generate faults that we can recover from to ensure the - /// fault system works properly during testing. - /// - - /// NOTE: - /// - To report success, i.e., you can continue, nothing to see here, - /// you need to execute a run API. If you are doing integration - /// testing, this would be bf_vs_op_advance_ip_and_run_current. - /// If you are cleaning up from a VM failure, you would typically - /// run bf_vs_op_run as you should know exactly what parameters - /// to give it. If you need to know what VM, VP and VS are - /// currently running, you can use the TLS functions. - /// - - bsl::print() << bsl::here(); - return syscall::bf_control_op_exit(); - } - - /// - /// @brief Implements the bootstrap entry function. The main function is - /// called on PP #0, and is only used to register the bootstrap entry - /// function and open a handle. From there, the rest of the bootstrap - /// process should occur from the bootstrap function, as this function - /// is executed once on each PP, giving you a chance to bootstrap each - /// PP as needed. - /// - /// - /// @param ppid the physical process to bootstrap - /// - extern "C" void - bootstrap_entry(bsl::uint16 const ppid) noexcept - { - bsl::errc_type ret{}; - - bsl::safe_u16 vpid{}; - bsl::safe_u16 vsid{}; - - /// NOTE: - /// - Create the root VP and root VS that we will start. - /// Since we are not implementing nested virtualization or VSM - /// support, the VPID and VSID are always identical. - /// - There is no need to create the root VM as this is created - /// for you. You only need to create VMs if you plan to add guest - /// VM support to your extension. - /// - - ret = syscall::bf_vp_op_create_vp(g_handle, syscall::BF_ROOT_VMID, ppid, vpid); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return syscall::bf_control_op_exit(); - } - - ret = syscall::bf_vs_op_create_vs(g_handle, vpid, ppid, vsid); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return syscall::bf_control_op_exit(); - } - - /// NOTE: - /// - Initialize the VS as a root VS. When the microkernel was - /// started, the loader saved the state of the root VP. This - /// syscall tells the microkernel to load the VS with this saved - /// state so that when we run the VP, it will contain the state - /// just before the microkernel was started. - /// - - ret = syscall::bf_vs_op_init_as_root(g_handle, vsid); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return syscall::bf_control_op_exit(); - } - - /// NOTE: - /// - Initialize architecture specific logic in the VS. - /// - - if (bsl::unlikely(!)) { - bsl::print() << bsl::here(); - return syscall::bf_control_op_exit(); - } - - /// NOTE: - /// - Run the newly created VP on behalf of the root VM using the - /// newly created and initialized VS. - /// - It should be noted that if bf_vs_op_run succeeds, it will - /// not return. Like the rest of the code in this example, we - /// return success for unit testing purposes. If this function - /// returns, it is actually an error. - /// - - bsl::discard(syscall::bf_vs_op_run(g_handle, syscall::BF_ROOT_VMID, vpid, vsid)); - - /// NOTE: - /// - The following is only called if an error occurs. Failure to - /// call this function leads to undefined behaviour (likely a - /// page fault). - /// - - bsl::print() << bsl::here(); - syscall::bf_control_op_exit(); - } - - /// - /// @brief Implements the main entry function for this example - /// - /// - /// @param version the version of the spec implemented by the - /// microkernel. This can be used to ensure the extension and the - /// microkernel speak the same ABI. - /// - extern "C" void - ext_main_entry(bsl::uint32 const version) noexcept - { - bsl::errc_type ret{}; - - /// NOTE: - /// - Check to see if the microkernel speaks the same version as we - /// do. Note that this is important. Years from now, the microkernel - /// might implement a completely different syscall interface. This - /// check ensures that if that happens, this code will not continue - /// as it might result in undefined behaviour. - /// - - if (bsl::unlikely(!syscall::bf_is_spec1_supported(version))) { - bsl::error() << "unsupported microkernel\n" << bsl::here(); - return syscall::bf_control_op_exit(); - } - - /// NOTE: - /// - Open a handle with the microkernel which will be used for the - /// remaining syscalls. - /// - - ret = syscall::bf_handle_op_open_handle(syscall::BF_SPEC_ID1_VAL, g_handle); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return syscall::bf_control_op_exit(); - } - - /// NOTE: - /// - Register the bootstrap entry function so that we can bootstrap - /// each PP - /// - - ret = syscall::bf_callback_op_register_bootstrap(g_handle, &bootstrap_entry); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return syscall::bf_control_op_exit(); - } - - /// NOTE: - /// - Register the vmexit entry function so that we can handle - /// VMExits - /// - - ret = syscall::bf_callback_op_register_vmexit(g_handle, &vmexit_entry); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return syscall::bf_control_op_exit(); - } - - /// NOTE: - /// - Register the vmexit entry function so that we can handle - /// fast fail events - /// - - ret = syscall::bf_callback_op_register_fail(g_handle, &fail_entry); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return syscall::bf_control_op_exit(); - } - - /// NOTE: - /// - Wait for callbacks. Note that this function does not return. - /// The next time the extension is executed, it will be the - /// bootstrap callback that was just previously registered, which - /// will be called on each PP that is online. Failure to call this - /// function leads to undefined behaviour (likely a page fault). - /// - - syscall::bf_control_op_wait(); - } -} diff --git a/example/nested_paging/page_pool_t.hpp b/example/nested_paging/page_pool_t.hpp deleted file mode 100644 index cfca14cc..00000000 --- a/example/nested_paging/page_pool_t.hpp +++ /dev/null @@ -1,227 +0,0 @@ -/// @copyright -/// Copyright (C) 2020 Assured Information Security, Inc. -/// -/// @copyright -/// Permission is hereby granted, free of charge, to any person obtaining a copy -/// of this software and associated documentation files (the "Software"), to deal -/// in the Software without restriction, including without limitation the rights -/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -/// copies of the Software, and to permit persons to whom the Software is -/// furnished to do so, subject to the following conditions: -/// -/// @copyright -/// The above copyright notice and this permission notice shall be included in -/// all copies or substantial portions of the Software. -/// -/// @copyright -/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -/// SOFTWARE. - -#ifndef PAGE_POOL_T_HPP -#define PAGE_POOL_T_HPP - -#include "lock_guard.hpp" -#include "spinlock.hpp" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace example -{ - /// - /// @brief The page pool is responsible for allocating and freeing - /// pages. The page pool exists in the extensions's direct map and so - /// the page pool can also return the physical address of any page - /// that it has allocated. For more information about how this page - /// pool works, see the page_pool_t in the kernel, as they are - /// very similar. - /// - /// One question you might ask if, why have a page_pool_t in the - /// extension in the first place? The reason is because some - /// microkernel implementations might not implement the free_page - /// ABI as it is optional, but the extension will still need to be - /// able to free memory and reuse it. For this reason, all allocations - /// are done using this class, instead of allocating memory manually. - /// Any time memory is freed, it is returned to the page pool to be - /// used again on the next allocation, and any time an allocation - /// occurs and there isn't enough memory, the extension asks the - /// kernel for another page. This way, the extension is only asking - /// for pages when it needs it, and it is able to reuse memory - /// when it is freed. - /// - class page_pool_t final - { - /// @brief stores the handle used to communicate with the kernel - syscall::bf_handle_t m_handle{}; - /// @brief stores the head of the page pool stack. - void *m_head{}; - /// @brief stores the total number of bytes in the page pool. - bsl::safe_umx m_size{}; - /// @brief safe guards operations on the pool. - mutable spinlock m_pool_lock{}; - - public: - /// - /// @brief Initializes the page pool - /// - /// - /// @param handle the handle used to communicate with the kernel - /// @return Returns bsl::errc_success on success, bsl::errc_failure - /// and friends otherwise - /// - [[nodiscard]] constexpr auto - initialize(syscall::bf_handle_t const &handle) noexcept -> bsl::errc_type - { - bsl::finally release_on_error{[this]() noexcept -> void { - this->release(); - }}; - - m_handle = handle; - - release_on_error.ignore(); - return bsl::errc_success; - } - - /// - /// @brief Release the page_pool_t - /// - constexpr void - release() noexcept - { - m_size = {}; - m_head = {}; - - m_handle = {}; - } - - /// - /// @brief Allocates a page from the page pool. - /// - /// - /// @tparam T the type of pointer to return - /// @return Returns a pointer to the newly allocated page - /// - template - [[nodiscard]] constexpr auto - allocate() noexcept -> T * - { - lock_guard lock{m_pool_lock}; - - if (bsl::unlikely(nullptr == m_head)) { - m_head = syscall::bf_mem_op_alloc_page(m_handle); - if (bsl::unlikely(nullptr == m_head)) { - bsl::print() << bsl::here(); - return nullptr; - } - - bsl::touch(); - } - else { - bsl::touch(); - } - - void *const ptr{m_head}; - m_head = *static_cast(m_head); - - bsl::builtin_memset(ptr, '\0', bsl::to_umx(HYPERVISOR_PAGE_SIZE).get()); - - if constexpr (!bsl::is_void::value) { - static_assert(bsl::is_standard_layout::value, "T must be a standard layout"); - bsl::construct_at(ptr); - } - - return static_cast(ptr); - } - - /// - /// @brief Returns a page previously allocated using the allocate - /// function to the page pool. - /// - /// - /// @param ptr the pointer to the page to deallocate - /// - constexpr void - deallocate(void *const ptr) noexcept - { - lock_guard lock{m_pool_lock}; - - if (bsl::unlikely(nullptr == ptr)) { - return; - } - - if (bsl::to_umx(ptr) < bsl::to_umx(HYPERVISOR_EXT_PAGE_POOL_ADDR)) { - bsl::error() << "invalid ptr" // -- - << ptr // -- - << bsl::endl // -- - << bsl::here(); - - return; - } - - *static_cast(ptr) = m_head; - m_head = ptr; - } - - /// - /// @brief Converts a virtual address to a physical address for - /// any page allocated by the page pool. If the provided ptr - /// was not allocated using the allocate function by the same - /// page pool, this results of this function are UB. It should - /// be noted that any virtual address may be used meaning the - /// provided address does not have to be page aligned, it simply - /// needs to be allocated using the same page pool. - /// - /// - /// @tparam T defines the type of virtual address being converted - /// @param virt the virtual address to convert - /// @return the resulting physical address - /// - template - [[nodiscard]] constexpr auto - virt_to_phys(T const *const virt) const noexcept -> bsl::safe_umx - { - static_assert(bsl::disjunction, bsl::is_standard_layout>::value); - return bsl::to_umx(virt) - bsl::to_umx(HYPERVISOR_EXT_PAGE_POOL_ADDR); - } - - /// - /// @brief Converts a physical address to a virtual address for - /// any page allocated by the page pool. If the provided address - /// was not allocated using the allocate function by the same - /// page pool, this results of this function are UB. It should - /// be noted that any physical address may be used meaning the - /// provided address does not have to be page aligned, it simply - /// needs to be allocated using the same page pool. - /// - /// - /// @tparam T defines the type of virtual address to convert to - /// @param phys the physical address to convert - /// @return the resulting virtual address - /// - template - [[nodiscard]] constexpr auto - phys_to_virt(bsl::safe_umx const &phys) const noexcept -> T * - { - static_assert(bsl::disjunction, bsl::is_standard_layout>::value); - return bsl::to_ptr(phys + bsl::to_umx(HYPERVISOR_EXT_PAGE_POOL_ADDR)); - } - }; -} - -#endif diff --git a/example/nested_paging/spinlock.hpp b/example/nested_paging/spinlock.hpp deleted file mode 100644 index a05d28d6..00000000 --- a/example/nested_paging/spinlock.hpp +++ /dev/null @@ -1,126 +0,0 @@ -/// @copyright -/// Copyright (C) 2020 Assured Information Security, Inc. -/// -/// @copyright -/// Permission is hereby granted, free of charge, to any person obtaining a copy -/// of this software and associated documentation files (the "Software"), to deal -/// in the Software without restriction, including without limitation the rights -/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -/// copies of the Software, and to permit persons to whom the Software is -/// furnished to do so, subject to the following conditions: -/// -/// @copyright -/// The above copyright notice and this permission notice shall be included in -/// all copies or substantial portions of the Software. -/// -/// @copyright -/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -/// SOFTWARE. - -#ifndef SPINLOCK_HPP -#define SPINLOCK_HPP - -#include - -#pragma clang diagnostic ignored "-Watomic-implicit-seq-cst" - -namespace example -{ - /// - /// @brief Implements a spinlock - /// - class spinlock final - { - /// @brief stores whether or not the lock is acquired - _Atomic bool m_flag; - - public: - /// - /// @brief Default constructor. - /// - // We cannot member initialize atomics so this is not possible - // NOLINTNEXTLINE(bsl-class-member-init) - constexpr spinlock() noexcept - { - // This is the only way to initialize this - // NOLINTNEXTLINE(bsl-implicit-conversions-forbidden) - m_flag = false; - } - - /// - /// @brief Destructor - /// - constexpr ~spinlock() noexcept = default; - - /// - /// @brief copy constructor - /// - /// - /// @param o the object being copied - /// - constexpr spinlock(spinlock const &o) noexcept = delete; - - /// - /// @brief move constructor - /// - /// - /// @param o the object being moved - /// - constexpr spinlock(spinlock &&o) noexcept = default; - - /// - /// @brief copy assignment - /// - /// - /// @param o the object being copied - /// @return a reference to *this - /// - [[maybe_unused]] auto operator=(spinlock const &o) noexcept -> spinlock & = delete; - - /// - /// @brief move assignment - /// - /// - /// @param o the object being moved - /// @return a reference to *this - /// - [[maybe_unused]] auto operator=(spinlock &&o) noexcept -> spinlock & = default; - - /// - /// @brief Locks the spinlock. This will not return until the - /// spinlock can be successfully acquired. - /// - constexpr void - lock() noexcept - { - if (bsl::is_constant_evaluated()) { - return; - } - - while (__c11_atomic_exchange(&m_flag, true, __ATOMIC_ACQUIRE)) { - while (__c11_atomic_load(&m_flag, __ATOMIC_RELAXED)) { - } - } - } - - /// - /// @brief Unlocks the spinlock. - /// - constexpr void - unlock() noexcept - { - if (bsl::is_constant_evaluated()) { - return; - } - - __c11_atomic_store(&m_flag, false, __ATOMIC_RELEASE); - } - }; -} - -#endif diff --git a/example/nested_paging/x64/amd/arch_support.hpp b/example/nested_paging/x64/amd/arch_support.hpp deleted file mode 100644 index 12845df8..00000000 --- a/example/nested_paging/x64/amd/arch_support.hpp +++ /dev/null @@ -1,283 +0,0 @@ -/// @copyright -/// Copyright (C) 2020 Assured Information Security, Inc. -/// -/// @copyright -/// Permission is hereby granted, free of charge, to any person obtaining a copy -/// of this software and associated documentation files (the "Software"), to deal -/// in the Software without restriction, including without limitation the rights -/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -/// copies of the Software, and to permit persons to whom the Software is -/// furnished to do so, subject to the following conditions: -/// -/// @copyright -/// The above copyright notice and this permission notice shall be included in -/// all copies or substantial portions of the Software. -/// -/// @copyright -/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -/// SOFTWARE. - -#ifndef ARCH_SUPPORT_HPP -#define ARCH_SUPPORT_HPP - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -namespace example -{ - /// @brief stores the page pool to use for page allocation - constinit inline page_pool_t g_page_pool{}; - /// @brief stores the nested page tables - constinit inline nested_page_table_t g_npt{}; - - /// - /// @brief Implements the architecture specific VMExit handler. - /// - /// - /// @param handle the handle to use - /// @param vsid the ID of the VS that generated the VMExit - /// @param exit_reason the exit reason associated with the VMExit - /// - constexpr void - vmexit( - syscall::bf_handle_t &handle, - bsl::safe_u16 const &vsid, - bsl::safe_u64 const &exit_reason) noexcept - { - bsl::errc_type ret{}; - constexpr bsl::safe_umx exit_reason_cpuid{bsl::to_umx(0x72U)}; - - /// NOTE: - /// - At a minimum, we need to handle CPUID on AMD. Note that the - /// "run" APIs all return an error code, but for the most part we - /// can ignore them. If the this function succeeds, it will not - /// return. If it fails, it will return, and the error code is - /// always UNKNOWN. We output the current line so that debugging - /// the issue is easier. - /// - - switch (exit_reason.get()) { - case exit_reason_cpuid.get(): { - ret = handle_vmexit_cpuid(handle, vsid); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return; - } - - bsl::discard(syscall::bf_vs_op_advance_ip_and_run_current(handle)); - bsl::print() << bsl::here(); - return; - } - - default: { - break; - } - } - - syscall::bf_debug_op_dump_vs(vsid); - - bsl::error() << "unknown exit_reason: " // -- - << bsl::hex(exit_reason) // -- - << bsl::endl // -- - << bsl::here(); // -- - } - - /// - /// @brief Initializes a VS with architecture specific stuff. - /// - /// - /// @param handle the handle to use - /// @param vsid the VS being intialized - /// @return Returns bsl::errc_success on success and bsl::errc_failure - /// on failure. - /// - [[nodiscard]] constexpr auto - init_vs(syscall::bf_handle_t &handle, bsl::safe_u16 const &vsid) noexcept -> bsl::errc_type - { - bsl::errc_type ret{}; - - bsl::safe_umx rax{}; - bsl::safe_umx rbx{}; - bsl::safe_umx rcx{}; - bsl::safe_umx rdx{}; - - /// NOTE: - /// - Set up ASID - /// - - constexpr bsl::safe_u64 guest_asid_idx{bsl::to_u64(0x0058U)}; - constexpr bsl::safe_u32 guest_asid_val{bsl::to_u32(0x1U)}; - - ret = syscall::bf_vs_op_write32(handle, vsid, guest_asid_idx, guest_asid_val); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return ret; - } - - /// NOTE: - /// - Set up intercept controls. On AMD, we need to intercept - /// VMRun, and CPUID if we plan to support reporting and stopping. - /// - - constexpr bsl::safe_u64 intercept_instruction1_idx{bsl::to_u64(0x000CU)}; - constexpr bsl::safe_u32 intercept_instruction1_val{bsl::to_u32(0x00040000U)}; - constexpr bsl::safe_u64 intercept_instruction2_idx{bsl::to_u64(0x0010U)}; - constexpr bsl::safe_u32 intercept_instruction2_val{bsl::to_u32(0x00000001U)}; - - ret = syscall::bf_vs_op_write32( - handle, vsid, intercept_instruction1_idx, intercept_instruction1_val); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return ret; - } - - ret = syscall::bf_vs_op_write32( - handle, vsid, intercept_instruction2_idx, intercept_instruction2_val); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return ret; - } - - /// NOTE: - /// - The first step in setting up nested paging is to determine - /// if we have support for it. We do this on each physical processor - /// we are being started on, but likely you could just do this - /// check on the first physical processor and be done. - /// - - constexpr bsl::safe_umx cpuid_svm_feature_identification{bsl::to_umx(0x8000000AU)}; - constexpr bsl::safe_umx cpuid_svm_feature_identification_np{bsl::to_umx(0x00000001U)}; - - rax = cpuid_svm_feature_identification; - rcx = {}; - intrinsic_cpuid(rax.data(), rbx.data(), rcx.data(), rdx.data()); - - if (bsl::unlikely((rdx & cpuid_svm_feature_identification_np).is_zero())) { - bsl::error() << "nested paging not supported\n" << bsl::here(); - return bsl::errc_failure; - } - - /// NOTE: - /// - The next step is to enable nested paging in the VMCB. - /// - - constexpr bsl::safe_u64 guest_ctls1_idx{bsl::to_u64(0x0090U)}; - constexpr bsl::safe_u64 guest_ctls1_val{bsl::to_u64(0x1U)}; - - ret = syscall::bf_vs_op_write64(handle, vsid, guest_ctls1_idx, guest_ctls1_val); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return ret; - } - - /// NOTE: - /// - Before we can set up the nested page tables, we need to set up - /// a page pool. This is needed because not all microkernels will - /// support the free_page() ABI. If we want to change the nested - /// page tables, or make new ones and then release them when we are - /// done, etc, we will need the ability to free a page so that we - /// can use it again. To do this we create our own page pool. - /// Whenever we allocate a page, if the page pool is empty, it will - /// as the microkernel for a page. When memory is freed, it puts - /// the freed page into our page pool so that we can use it the next - /// time an allocation occurs. - /// - Note that this approach is basically how malloc/free engines - /// work when you write your own application for Windows/Linux. - /// The allocation engine asks the kernel for memory (usually it - /// asks for heap memory, but that is not a requirement), and then - /// it provides this memory when you run malloc(). We are doing the - /// samething here, but with page granularity. - /// - It should also be noted that the microkernel does provide a - /// heap if you want to use it, but in this case we really do want - /// page allocation as you cannot do virtual address to physical - /// address conversions for memory that was allocated on the heap. - /// - - if (syscall::bf_tls_ppid(handle) == bsl::ZERO_U16) { - ret = g_page_pool.initialize(handle); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return ret; - } - - bsl::touch(); - } - else { - bsl::touch(); - } - - /// NOTE: - /// - The next step is to initialize and set up the nested page - /// tables. One issue with this is you need to know how much - /// physical memory to map in. You could determine how much - /// physical address space you will need, or you could use on-demand - /// paging. You could also fill the entire physical address space - /// (up to the MAX value provided by CPUID), but how much memory - /// you need to allocate for the page tables to make that work is - /// up to what granularity you use. In this example, we only - /// provide 2M granularity, so this approach is likely a bad idea. - /// - Also note that what we are creating here is what we call an - /// identify map. Basically, each guest physical address is mapped - /// to the same system physical address. This is needed (usually) - /// for the root OS. If you plan to create your own guest VMs, - /// you will need a different mapping scheme. - /// - By default, we map in 512 GB of memory. Again, this is likely - /// not safe, but is good enough for an example. - /// - - constexpr bsl::safe_u64 page_size_2m{bsl::to_umx(0x200000U)}; - constexpr bsl::safe_u64 max_physical_mem{bsl::to_umx(0x8000000000U)}; - - if (syscall::bf_tls_ppid(handle) == bsl::ZERO_U16) { - ret = g_npt.initialize(&g_page_pool); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return ret; - } - - for (bsl::safe_idx gpa{}; gpa < max_physical_mem; gpa += page_size_2m) { - ret = g_npt.map_2m_page(gpa, gpa, MAP_PAGE_RWE, MEMORY_TYPE_WB); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return ret; - } - - bsl::touch(); - } - } - else { - bsl::touch(); - } - - /// NOTE: - /// - Finally, we need to set N_CR3 in the VMCB so that the CPU - /// knows where to find our nested page tables. - /// - - constexpr bsl::safe_u64 guest_n_cr3_idx{bsl::to_u64(0x00B0U)}; - - ret = syscall::bf_vs_op_write64(handle, vsid, guest_n_cr3_idx, g_npt.phys()); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return ret; - } - - return ret; - } -} - -#endif diff --git a/example/nested_paging/x64/amd/nested_page_table_t.hpp b/example/nested_paging/x64/amd/nested_page_table_t.hpp deleted file mode 100644 index 6fb8c5d2..00000000 --- a/example/nested_paging/x64/amd/nested_page_table_t.hpp +++ /dev/null @@ -1,861 +0,0 @@ -/// @copyright -/// Copyright (C) 2020 Assured Information Security, Inc. -/// -/// @copyright -/// Permission is hereby granted, free of charge, to any person obtaining a copy -/// of this software and associated documentation files (the "Software"), to deal -/// in the Software without restriction, including without limitation the rights -/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -/// copies of the Software, and to permit persons to whom the Software is -/// furnished to do so, subject to the following conditions: -/// -/// @copyright -/// The above copyright notice and this permission notice shall be included in -/// all copies or substantial portions of the Software. -/// -/// @copyright -/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -/// SOFTWARE. - -#ifndef NESTED_PAGE_TABLE_T_HPP -#define NESTED_PAGE_TABLE_T_HPP - -#include "npdpt_t.hpp" -#include "npdpte_t.hpp" -#include "npdt_t.hpp" -#include "npdte_t.hpp" -#include "npml4t_t.hpp" -#include "npml4te_t.hpp" -#include "npt_t.hpp" -#include "npte_t.hpp" - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -namespace example -{ - /// - /// @brief Implements the nested pages tables used by the extension - /// for mapping guest physical memory. - /// - class nested_page_table_t final - { - /// @brief stores true if initialized() has been executed - bool m_initialized{}; - /// @brief stores a reference to the page pool to use - page_pool_t *m_page_pool{}; - /// @brief stores a pointer to the npml4t - npml4t_t *m_npml4t{}; - /// @brief stores the physical address of the npml4t - bsl::safe_umx m_npml4t_phys{bsl::safe_umx::failure()}; - /// @brief safe guards operations on the NPT. - mutable spinlock m_npt_lock{}; - - /// - /// @brief Returns the nested page-map level-4 (NPML4T) offset given - /// a guest physical address. - /// - /// - /// @param gpa the guest physical address to get the NPML4T offset from. - /// @return the NPML4T offset from the guest physical address - /// - [[nodiscard]] static constexpr auto - npml4to(bsl::safe_umx const &gpa) noexcept -> bsl::safe_umx - { - constexpr bsl::safe_umx mask{bsl::to_umx(0x1FF)}; - constexpr bsl::safe_umx shift{bsl::to_umx(39)}; - return (gpa >> shift) & mask; - } - - /// - /// @brief Adds a npdpt_t to the provided npml4te_t. - /// - /// - /// @param npml4te the npml4te_t to add a npdpt_t too - /// @return Returns bsl::errc_success on success, bsl::errc_failure - /// and friends otherwise - /// - [[nodiscard]] constexpr auto - add_npdpt(npml4te_t *const npml4te) noexcept -> bsl::errc_type - { - auto const *const table{m_page_pool->template allocate()}; - if (bsl::unlikely(nullptr == table)) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - auto const table_phys{m_page_pool->virt_to_phys(table)}; - if (bsl::unlikely(!table_phys)) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - npml4te->phys = (table_phys >> bsl::to_umx(HYPERVISOR_PAGE_SHIFT)).get(); - npml4te->p = bsl::ONE_UMAX.get(); - npml4te->rw = bsl::ONE_UMAX.get(); - npml4te->us = bsl::ONE_UMAX.get(); - - return bsl::errc_success; - } - - /// - /// @brief Adds a npdpt_t to the provided npml4te_t. - /// - /// - /// @param npml4te the npml4te_t to add a npdpt_t too - /// - constexpr void - remove_npdpt(npml4te_t *const npml4te) noexcept - { - for (auto const elem : get_npdpt(npml4te)->entries) { - if (elem.data->p != bsl::ZERO_UMAX) { - this->remove_npdt(elem.data); - } - else { - bsl::touch(); - } - } - - m_page_pool->deallocate(get_npdpt(npml4te)); - } - - /// - /// @brief Returns the npdpt_t associated with the provided - /// npml4te_t. - /// - /// - /// @param npml4te the npml4te_t to get the npdpt_t from - /// @return A pointer to the requested npdpt_t - /// - [[nodiscard]] constexpr auto - get_npdpt(npml4te_t *const npml4te) noexcept -> npdpt_t * - { - bsl::safe_umx entry_phys{npml4te->phys}; - entry_phys <<= bsl::to_umx(HYPERVISOR_PAGE_SHIFT); - - return m_page_pool->template phys_to_virt(entry_phys); - } - - /// - /// @brief Returns the npdpt_t associated with the provided - /// npml4te_t. - /// - /// - /// @param npml4te the npml4te_t to get the npdpt_t from - /// @return A pointer to the requested npdpt_t - /// - [[nodiscard]] constexpr auto - get_npdpt(npml4te_t const *const npml4te) const noexcept -> npdpt_t const * - { - bsl::safe_umx entry_phys{npml4te->phys}; - entry_phys <<= bsl::to_umx(HYPERVISOR_PAGE_SHIFT); - - return m_page_pool->template phys_to_virt(entry_phys); - } - - /// - /// @brief Returns the nested page-directory-pointer table (NPDPT) - /// offset given a guest physical address. - /// - /// - /// @param gpa the guest physical address to get the NPDPT offset from. - /// @return the NPDPT offset from the guest physical address - /// - [[nodiscard]] static constexpr auto - npdpto(bsl::safe_umx const &gpa) noexcept -> bsl::safe_umx - { - constexpr bsl::safe_umx mask{bsl::to_umx(0x1FF)}; - constexpr bsl::safe_umx shift{bsl::to_umx(30)}; - return (gpa >> shift) & mask; - } - - /// - /// @brief Adds a npdt_t to the provided npdpte_t. - /// - /// - /// @param npdpte the npdpte_t to add a npdt_t too - /// @return Returns bsl::errc_success on success, bsl::errc_failure - /// and friends otherwise - /// - [[nodiscard]] constexpr auto - add_npdt(npdpte_t *const npdpte) noexcept -> bsl::errc_type - { - auto const *const table{m_page_pool->template allocate()}; - if (bsl::unlikely(nullptr == table)) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - auto const table_phys{m_page_pool->virt_to_phys(table)}; - if (bsl::unlikely(!table_phys)) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - npdpte->phys = (table_phys >> bsl::to_umx(HYPERVISOR_PAGE_SHIFT)).get(); - npdpte->p = bsl::ONE_UMAX.get(); - npdpte->rw = bsl::ONE_UMAX.get(); - npdpte->us = bsl::ONE_UMAX.get(); - - return bsl::errc_success; - } - - /// - /// @brief Adds a npdt_t to the provided npdpte_t. - /// - /// - /// @param npdpte the npdpte_t to add a npdt_t too - /// - constexpr void - remove_npdt(npdpte_t *const npdpte) noexcept - { - for (auto const elem : get_npdt(npdpte)->entries) { - if (elem.data->p != bsl::ZERO_UMAX) { - this->remove_npt(elem.data); - } - else { - bsl::touch(); - } - } - - m_page_pool->deallocate(get_npdt(npdpte)); - } - - /// - /// @brief Returns the npdt_t associated with the provided - /// npdpte_t. - /// - /// - /// @param npdpte the npdpte_t to get the npdt_t from - /// @return A pointer to the requested npdt_t - /// - [[nodiscard]] constexpr auto - get_npdt(npdpte_t *const npdpte) noexcept -> npdt_t * - { - bsl::safe_umx entry_phys{npdpte->phys}; - entry_phys <<= bsl::to_umx(HYPERVISOR_PAGE_SHIFT); - - return m_page_pool->template phys_to_virt(entry_phys); - } - - /// - /// @brief Returns the npdt_t associated with the provided - /// npdpte_t. - /// - /// - /// @param npdpte the npdpte_t to get the npdt_t from - /// @return A pointer to the requested npdt_t - /// - [[nodiscard]] constexpr auto - get_npdt(npdpte_t const *const npdpte) const noexcept -> npdt_t const * - { - bsl::safe_umx entry_phys{npdpte->phys}; - entry_phys <<= bsl::to_umx(HYPERVISOR_PAGE_SHIFT); - - return m_page_pool->template phys_to_virt(entry_phys); - } - - /// - /// @brief Returns the nested page-directory table (NPDT) offset - /// given a guest physical address. - /// - /// - /// @param gpa the guest physical address to get the NPDT offset from. - /// @return the NPDT offset from the guest physical address. - /// - [[nodiscard]] static constexpr auto - npdto(bsl::safe_umx const &gpa) noexcept -> bsl::safe_umx - { - constexpr bsl::safe_umx mask{bsl::to_umx(0x1FF)}; - constexpr bsl::safe_umx shift{bsl::to_umx(21)}; - return (gpa >> shift) & mask; - } - - /// - /// @brief Adds a npt_t to the provided npdte_t. - /// - /// - /// @param npdte the npdte_t to add a npt_t too - /// @return Returns bsl::errc_success on success, bsl::errc_failure - /// and friends otherwise - /// - [[nodiscard]] constexpr auto - add_npt(npdte_t *const npdte) noexcept -> bsl::errc_type - { - auto const *const table{m_page_pool->template allocate()}; - if (bsl::unlikely(nullptr == table)) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - auto const table_phys{m_page_pool->virt_to_phys(table)}; - if (bsl::unlikely(!table_phys)) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - npdte->phys = (table_phys >> bsl::to_umx(HYPERVISOR_PAGE_SHIFT)).get(); - npdte->p = bsl::ONE_UMAX.get(); - npdte->rw = bsl::ONE_UMAX.get(); - npdte->us = bsl::ONE_UMAX.get(); - - return bsl::errc_success; - } - - /// - /// @brief Adds a npt_t to the provided npdte_t. - /// - /// - /// @param npdte the npdte_t to add a npt_t too - /// - constexpr void - remove_npt(npdte_t *const npdte) noexcept - { - m_page_pool->deallocate(get_npt(npdte)); - } - - /// - /// @brief Returns the npt_t associated with the provided - /// npdte_t. - /// - /// - /// @param npdte the npdte_t to get the npt_t from - /// @return A pointer to the requested npt_t - /// - [[nodiscard]] constexpr auto - get_npt(npdte_t *const npdte) noexcept -> npt_t * - { - bsl::safe_umx entry_phys{npdte->phys}; - entry_phys <<= bsl::to_umx(HYPERVISOR_PAGE_SHIFT); - - return m_page_pool->template phys_to_virt(entry_phys); - } - - /// - /// @brief Returns the npt_t associated with the provided - /// npdte_t. - /// - /// - /// @param npdte the npdte_t to get the npt_t from - /// @return A pointer to the requested npt_t - /// - [[nodiscard]] constexpr auto - get_npt(npdte_t const *const npdte) const noexcept -> npt_t const * - { - bsl::safe_umx entry_phys{npdte->phys}; - entry_phys <<= bsl::to_umx(HYPERVISOR_PAGE_SHIFT); - - return m_page_pool->template phys_to_virt(entry_phys); - } - - /// - /// @brief Returns the page-table (NPT) offset given a - /// guest physical address. - /// - /// - /// @param gpa the guest physical address to get the NPT offset from. - /// @return the NPT offset from the guest physical address - /// - [[nodiscard]] static constexpr auto - npto(bsl::safe_umx const &gpa) noexcept -> bsl::safe_umx - { - constexpr bsl::safe_umx mask{bsl::to_umx(0x1FF)}; - constexpr bsl::safe_umx shift{bsl::to_umx(12)}; - return (gpa >> shift) & mask; - } - - /// - /// @brief Returns true if the provided address is page aligned - /// - /// - /// @param addr the address to query - /// @return Returns true if the provided address is page aligned - /// - [[nodiscard]] static constexpr auto - is_page_aligned(bsl::safe_umx const &addr) noexcept -> bool - { - return (addr & (bsl::to_umx(HYPERVISOR_PAGE_SIZE) - bsl::ONE_UMAX)) == bsl::ZERO_UMAX; - } - - /// - /// @brief Releases the memory allocated in this root page table - /// - constexpr void - auto_release() noexcept - { - if (bsl::unlikely(nullptr == m_npml4t)) { - return; - } - - if (bsl::unlikely(nullptr == m_page_pool)) { - return; - } - - for (auto const elem : m_npml4t->entries) { - if (elem.data->p == bsl::ZERO_UMAX) { - continue; - } - - this->remove_npdpt(elem.data); - } - - m_page_pool->deallocate(m_npml4t); - m_npml4t = {}; - m_npml4t_phys = bsl::safe_umx::failure(); - } - - public: - /// - /// @brief Initializes this nested_page_table_t - /// - /// - /// @param page_pool the page pool to use - /// @return Returns bsl::errc_success on success, bsl::errc_failure - /// and friends otherwise - /// - [[nodiscard]] constexpr auto - initialize(page_pool_t *const page_pool) noexcept -> bsl::errc_type - { - if (bsl::unlikely(m_initialized)) { - bsl::error() << "nested_page_table_t already initialized\n" << bsl::here(); - return bsl::errc_failure; - } - - bsl::finally release_on_error{[this]() noexcept -> void { - this->release(); - }}; - - m_page_pool = page_pool; - if (bsl::unlikely(nullptr == page_pool)) { - bsl::error() << "invalid page_pool\n" << bsl::here(); - return bsl::errc_failure; - } - - m_npml4t = m_page_pool->template allocate(); - if (bsl::unlikely(nullptr == m_npml4t)) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - m_npml4t_phys = m_page_pool->virt_to_phys(m_npml4t); - if (bsl::unlikely(!m_npml4t_phys)) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - release_on_error.ignore(); - m_initialized = true; - - return bsl::errc_success; - } - - /// - /// @brief Releases the memory allocated in this nested page tables - /// - constexpr void - release() noexcept - { - this->auto_release(); - - m_page_pool = {}; - m_initialized = false; - } - - /// - /// @brief Returns the physical address of the PML4 - /// - /// - /// @return Returns the physical address of the PML4 - /// - [[nodiscard]] constexpr auto - phys() const noexcept -> bsl::safe_umx const & - { - return m_npml4t_phys; - } - - /// - /// @brief Maps a 4k page into the nested page tables being managed - /// by this class. - /// - /// - /// @param page_gpa the guest physical address to map the system - /// physical address to - /// @param page_spa the system physical address to map. - /// @param page_flags defines how memory should be mapped - /// @param page_type defines the memory type for the mapping - /// @return Returns bsl::errc_success on success, bsl::errc_failure - /// and friends otherwise - /// - [[nodiscard]] constexpr auto - map_4k_page( - bsl::safe_umx const &page_gpa, - bsl::safe_umx const &page_spa, - bsl::safe_umx const &page_flags, - bsl::safe_umx const &page_type) noexcept -> bsl::errc_type - { - lock_guard lock{m_npt_lock}; - - if (bsl::unlikely(!m_initialized)) { - bsl::error() << "nested_page_table_t not initialized\n" << bsl::here(); - return bsl::errc_failure; - } - - if (bsl::unlikely(!page_gpa)) { - bsl::error() << "guest physical address is invalid: " // -- - << bsl::hex(page_gpa) // -- - << bsl::endl // -- - << bsl::here(); // -- - - return bsl::errc_failure; - } - - if (bsl::unlikely(!this->is_page_aligned(page_gpa))) { - bsl::error() << "guest physical address is not page aligned: " // -- - << bsl::hex(page_gpa) // -- - << bsl::endl // -- - << bsl::here(); // -- - - return bsl::errc_failure; - } - - if (bsl::unlikely(!page_spa)) { - bsl::error() << "system physical address is invalid: " // -- - << bsl::hex(page_spa) // -- - << bsl::endl // -- - << bsl::here(); // -- - - return bsl::errc_failure; - } - - if (bsl::unlikely(!this->is_page_aligned(page_spa))) { - bsl::error() << "system physical address is not page aligned: " // -- - << bsl::hex(page_spa) // -- - << bsl::endl // -- - << bsl::here(); // -- - - return bsl::errc_failure; - } - - if (bsl::unlikely(!page_flags)) { - bsl::error() << "invalid flags: " // -- - << bsl::hex(page_flags) // -- - << bsl::endl // -- - << bsl::here(); // -- - - return bsl::errc_failure; - } - - if (bsl::unlikely(!page_type)) { - bsl::error() << "invalid flags: " // -- - << bsl::hex(page_type) // -- - << bsl::endl // -- - << bsl::here(); // -- - - return bsl::errc_failure; - } - - if (bsl::unlikely(page_type == MEMORY_TYPE_WC)) { - bsl::error() << "invalid flags: " // -- - << bsl::hex(page_flags) // -- - << bsl::endl // -- - << bsl::here(); // -- - - return bsl::errc_failure; - } - - if (bsl::unlikely(page_type == MEMORY_TYPE_WT)) { - bsl::error() << "invalid flags: " // -- - << bsl::hex(page_flags) // -- - << bsl::endl // -- - << bsl::here(); // -- - - return bsl::errc_failure; - } - - if (bsl::unlikely(page_type == MEMORY_TYPE_WP)) { - bsl::error() << "invalid flags: " // -- - << bsl::hex(page_flags) // -- - << bsl::endl // -- - << bsl::here(); // -- - - return bsl::errc_failure; - } - - auto *const npml4te{m_npml4t->entries.at_if(this->npml4to(page_gpa))}; - if (npml4te->p == bsl::ZERO_UMAX) { - if (bsl::unlikely(!this->add_npdpt(npml4te))) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - bsl::touch(); - } - else { - bsl::touch(); - } - - auto *const npdpt{this->get_npdpt(npml4te)}; - auto *const npdpte{npdpt->entries.at_if(this->npdpto(page_gpa))}; - if (npdpte->p == bsl::ZERO_UMAX) { - if (bsl::unlikely(!this->add_npdt(npdpte))) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - bsl::touch(); - } - else { - bsl::touch(); - } - - auto *const npdt{this->get_npdt(npdpte)}; - auto *const npdte{npdt->entries.at_if(this->npdto(page_gpa))}; - if (npdte->p == bsl::ZERO_UMAX) { - if (bsl::unlikely(!this->add_npt(npdte))) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - bsl::touch(); - } - else { - bsl::touch(); - } - - auto *const npt{this->get_npt(npdte)}; - auto *const npte{npt->entries.at_if(this->npto(page_gpa))}; - if (bsl::unlikely(npte->p != bsl::ZERO_UMAX)) { - bsl::error() << "guest physical address " // -- - << bsl::hex(page_gpa) // -- - << " already mapped" // -- - << bsl::endl // -- - << bsl::here(); // -- - - return bsl::errc_failure; - } - - npte->phys = (page_spa >> bsl::to_umx(HYPERVISOR_PAGE_SHIFT)).get(); - npte->p = bsl::ONE_UMAX.get(); - npte->us = bsl::ONE_UMAX.get(); - - if (!(page_flags & MAP_PAGE_WRITE).is_zero()) { - npte->rw = bsl::ONE_UMAX.get(); - } - else { - npte->rw = bsl::ZERO_UMAX.get(); - } - - if (!(page_flags & MAP_PAGE_EXECUTE).is_zero()) { - npte->nx = bsl::ZERO_UMAX.get(); - } - else { - npte->nx = bsl::ONE_UMAX.get(); - } - - if (page_type == MEMORY_TYPE_UC) { - npte->pwt = bsl::ONE_UMAX.get(); - npte->pcd = bsl::ONE_UMAX.get(); - } - else { - bsl::touch(); - } - - return bsl::errc_success; - } - - /// - /// @brief Maps a 2m page into the nested page tables being managed - /// by this class. - /// - /// - /// @param page_gpa the guest physical address to map the system - /// physical address to - /// @param page_spa the system physical address to map. - /// @param page_flags defines how memory should be mapped - /// @param page_type defines the memory type for the mapping - /// @return Returns bsl::errc_success on success, bsl::errc_failure - /// and friends otherwise - /// - [[nodiscard]] constexpr auto - map_2m_page( - bsl::safe_umx const &page_gpa, - bsl::safe_umx const &page_spa, - bsl::safe_umx const &page_flags, - bsl::safe_umx const &page_type) noexcept -> bsl::errc_type - { - lock_guard lock{m_npt_lock}; - - if (bsl::unlikely(!m_initialized)) { - bsl::error() << "nested_page_table_t not initialized\n" << bsl::here(); - return bsl::errc_failure; - } - - if (bsl::unlikely(!page_gpa)) { - bsl::error() << "guest physical address is invalid: " // -- - << bsl::hex(page_gpa) // -- - << bsl::endl // -- - << bsl::here(); // -- - - return bsl::errc_failure; - } - - if (bsl::unlikely(!this->is_page_aligned(page_gpa))) { - bsl::error() << "guest physical address is not page aligned: " // -- - << bsl::hex(page_gpa) // -- - << bsl::endl // -- - << bsl::here(); // -- - - return bsl::errc_failure; - } - - if (bsl::unlikely(!page_spa)) { - bsl::error() << "system physical address is invalid: " // -- - << bsl::hex(page_spa) // -- - << bsl::endl // -- - << bsl::here(); // -- - - return bsl::errc_failure; - } - - if (bsl::unlikely(!this->is_page_aligned(page_spa))) { - bsl::error() << "system physical address is not page aligned: " // -- - << bsl::hex(page_spa) // -- - << bsl::endl // -- - << bsl::here(); // -- - - return bsl::errc_failure; - } - - if (bsl::unlikely(!page_flags)) { - bsl::error() << "invalid flags: " // -- - << bsl::hex(page_flags) // -- - << bsl::endl // -- - << bsl::here(); // -- - - return bsl::errc_failure; - } - - if (bsl::unlikely(!page_type)) { - bsl::error() << "invalid flags: " // -- - << bsl::hex(page_type) // -- - << bsl::endl // -- - << bsl::here(); // -- - - return bsl::errc_failure; - } - - if (bsl::unlikely(page_type == MEMORY_TYPE_WC)) { - bsl::error() << "invalid flags: " // -- - << bsl::hex(page_flags) // -- - << bsl::endl // -- - << bsl::here(); // -- - - return bsl::errc_failure; - } - - if (bsl::unlikely(page_type == MEMORY_TYPE_WT)) { - bsl::error() << "invalid flags: " // -- - << bsl::hex(page_flags) // -- - << bsl::endl // -- - << bsl::here(); // -- - - return bsl::errc_failure; - } - - if (bsl::unlikely(page_type == MEMORY_TYPE_WP)) { - bsl::error() << "invalid flags: " // -- - << bsl::hex(page_flags) // -- - << bsl::endl // -- - << bsl::here(); // -- - - return bsl::errc_failure; - } - - auto *const npml4te{m_npml4t->entries.at_if(this->npml4to(page_gpa))}; - if (npml4te->p == bsl::ZERO_UMAX) { - if (bsl::unlikely(!this->add_npdpt(npml4te))) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - bsl::touch(); - } - else { - bsl::touch(); - } - - auto *const npdpt{this->get_npdpt(npml4te)}; - auto *const npdpte{npdpt->entries.at_if(this->npdpto(page_gpa))}; - if (npdpte->p == bsl::ZERO_UMAX) { - if (bsl::unlikely(!this->add_npdt(npdpte))) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - bsl::touch(); - } - else { - bsl::touch(); - } - - auto *const npdt{this->get_npdt(npdpte)}; - auto *const npdte{npdt->entries.at_if(this->npdto(page_gpa))}; - if (bsl::unlikely(npdte->p != bsl::ZERO_UMAX)) { - bsl::error() << "guest physical address " // -- - << bsl::hex(page_gpa) // -- - << " already mapped" // -- - << bsl::endl // -- - << bsl::here(); // -- - - return bsl::errc_failure; - } - - npdte->phys = (page_spa >> bsl::to_umx(HYPERVISOR_PAGE_SHIFT)).get(); - npdte->p = bsl::ONE_UMAX.get(); - npdte->us = bsl::ONE_UMAX.get(); - npdte->ps = bsl::ONE_UMAX.get(); - - if (!(page_flags & MAP_PAGE_WRITE).is_zero()) { - npdte->rw = bsl::ONE_UMAX.get(); - } - else { - npdte->rw = bsl::ZERO_UMAX.get(); - } - - if (!(page_flags & MAP_PAGE_EXECUTE).is_zero()) { - npdte->nx = bsl::ZERO_UMAX.get(); - } - else { - npdte->nx = bsl::ONE_UMAX.get(); - } - - if (page_type == MEMORY_TYPE_UC) { - npdte->pwt = bsl::ONE_UMAX.get(); - npdte->pcd = bsl::ONE_UMAX.get(); - } - else { - bsl::touch(); - } - - return bsl::errc_success; - } - }; -} - -#endif diff --git a/example/nested_paging/x64/amd/npdpte_t.hpp b/example/nested_paging/x64/amd/npdpte_t.hpp deleted file mode 100644 index 16e4c003..00000000 --- a/example/nested_paging/x64/amd/npdpte_t.hpp +++ /dev/null @@ -1,75 +0,0 @@ -/// @copyright -/// Copyright (C) 2020 Assured Information Security, Inc. -/// -/// @copyright -/// Permission is hereby granted, free of charge, to any person obtaining a copy -/// of this software and associated documentation files (the "Software"), to deal -/// in the Software without restriction, including without limitation the rights -/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -/// copies of the Software, and to permit persons to whom the Software is -/// furnished to do so, subject to the following conditions: -/// -/// @copyright -/// The above copyright notice and this permission notice shall be included in -/// all copies or substantial portions of the Software. -/// -/// @copyright -/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -/// SOFTWARE. - -#ifndef NPDPTE_T_HPP -#define NPDPTE_T_HPP - -#include -#include -#include - -#pragma pack(push, 1) - -namespace example -{ - /// @struct example::npdpte_t - /// - /// - /// @brief Defines the layout of a nested page-directory-pointer table - /// entry (NPDPTE). - /// - struct npdpte_t final - { - /// @brief defines the "present" field in the page - bsl::uint64 p : static_cast(1); - /// @brief defines the "read/write" field in the page - bsl::uint64 rw : static_cast(1); - /// @brief defines the "user/supervisor" field in the page - bsl::uint64 us : static_cast(1); - /// @brief defines the "page-level writethrough" field in the page - bsl::uint64 pwt : static_cast(1); - /// @brief defines the "page-level cache disable" field in the page - bsl::uint64 pcd : static_cast(1); - /// @brief defines the "accessed" field in the page - bsl::uint64 a : static_cast(1); - /// @brief defines the "dirty" field in the page (ignored) - bsl::uint64 d : static_cast(1); - /// @brief defines the "page size" field in the page (must be 0) - bsl::uint64 ps : static_cast(1); - /// @brief defines the "global" field in the page (must be 0) - bsl::uint64 g : static_cast(1); - /// @brief defines the "available to software" field in the page - bsl::uint64 available1 : static_cast(3); - /// @brief defines the "physical address" field in the page - bsl::uint64 phys : static_cast(40); - /// @brief defines the "available to software" field in the page - bsl::uint64 available2 : static_cast(11); - /// @brief defines the "no-execute" field in the page - bsl::uint64 nx : static_cast(1); - }; -} - -#pragma pack(pop) - -#endif diff --git a/example/nested_paging/x64/amd/npdte_t.hpp b/example/nested_paging/x64/amd/npdte_t.hpp deleted file mode 100644 index 6bd53a27..00000000 --- a/example/nested_paging/x64/amd/npdte_t.hpp +++ /dev/null @@ -1,75 +0,0 @@ -/// @copyright -/// Copyright (C) 2020 Assured Information Security, Inc. -/// -/// @copyright -/// Permission is hereby granted, free of charge, to any person obtaining a copy -/// of this software and associated documentation files (the "Software"), to deal -/// in the Software without restriction, including without limitation the rights -/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -/// copies of the Software, and to permit persons to whom the Software is -/// furnished to do so, subject to the following conditions: -/// -/// @copyright -/// The above copyright notice and this permission notice shall be included in -/// all copies or substantial portions of the Software. -/// -/// @copyright -/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -/// SOFTWARE. - -#ifndef NPDTE_T_HPP -#define NPDTE_T_HPP - -#include -#include -#include - -#pragma pack(push, 1) - -namespace example -{ - /// @struct example::npdte_t - /// - /// - /// @brief Defines the layout of a nested page-directory table entry - /// (NPDTE). - /// - struct npdte_t final - { - /// @brief defines the "present" field in the page - bsl::uint64 p : static_cast(1); - /// @brief defines the "read/write" field in the page - bsl::uint64 rw : static_cast(1); - /// @brief defines the "user/supervisor" field in the page - bsl::uint64 us : static_cast(1); - /// @brief defines the "page-level writethrough" field in the page - bsl::uint64 pwt : static_cast(1); - /// @brief defines the "page-level cache disable" field in the page - bsl::uint64 pcd : static_cast(1); - /// @brief defines the "accessed" field in the page - bsl::uint64 a : static_cast(1); - /// @brief defines the "dirty" field in the page (ignored) - bsl::uint64 d : static_cast(1); - /// @brief defines the "page size" field in the page (must be 0) - bsl::uint64 ps : static_cast(1); - /// @brief defines the "global" field in the page (must be 0) - bsl::uint64 g : static_cast(1); - /// @brief defines the "available to software" field in the page - bsl::uint64 available1 : static_cast(3); - /// @brief defines the "physical address" field in the page - bsl::uint64 phys : static_cast(40); - /// @brief defines the "available to software" field in the page - bsl::uint64 available2 : static_cast(11); - /// @brief defines the "no-execute" field in the page - bsl::uint64 nx : static_cast(1); - }; -} - -#pragma pack(pop) - -#endif diff --git a/example/nested_paging/x64/amd/npml4te_t.hpp b/example/nested_paging/x64/amd/npml4te_t.hpp deleted file mode 100644 index 2026666f..00000000 --- a/example/nested_paging/x64/amd/npml4te_t.hpp +++ /dev/null @@ -1,75 +0,0 @@ -/// @copyright -/// Copyright (C) 2020 Assured Information Security, Inc. -/// -/// @copyright -/// Permission is hereby granted, free of charge, to any person obtaining a copy -/// of this software and associated documentation files (the "Software"), to deal -/// in the Software without restriction, including without limitation the rights -/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -/// copies of the Software, and to permit persons to whom the Software is -/// furnished to do so, subject to the following conditions: -/// -/// @copyright -/// The above copyright notice and this permission notice shall be included in -/// all copies or substantial portions of the Software. -/// -/// @copyright -/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -/// SOFTWARE. - -#ifndef NPML4TE_T_HPP -#define NPML4TE_T_HPP - -#include -#include -#include - -#pragma pack(push, 1) - -namespace example -{ - /// @struct example::npml4te_t - /// - /// - /// @brief Defines the layout of a nested page-map level-4 table entry - /// (NPML4TE). - /// - struct npml4te_t final - { - /// @brief defines the "present" field in the page - bsl::uint64 p : static_cast(1); - /// @brief defines the "read/write" field in the page - bsl::uint64 rw : static_cast(1); - /// @brief defines the "user/supervisor" field in the page - bsl::uint64 us : static_cast(1); - /// @brief defines the "page-level writethrough" field in the page - bsl::uint64 pwt : static_cast(1); - /// @brief defines the "page-level cache disable" field in the page - bsl::uint64 pcd : static_cast(1); - /// @brief defines the "accessed" field in the page - bsl::uint64 a : static_cast(1); - /// @brief defines the "dirty" field in the page (ignored) - bsl::uint64 ignored : static_cast(1); - /// @brief defines the "page size" field in the page (must be 0) - bsl::uint64 mbz1 : static_cast(1); - /// @brief defines the "global" field in the page (must be 0) - bsl::uint64 mbz2 : static_cast(1); - /// @brief defines the "available to software" field in the page - bsl::uint64 available1 : static_cast(3); - /// @brief defines the "physical address" field in the page - bsl::uint64 phys : static_cast(40); - /// @brief defines the "available to software" field in the page - bsl::uint64 available2 : static_cast(11); - /// @brief defines the "no-execute" field in the page - bsl::uint64 nx : static_cast(1); - }; -} - -#pragma pack(pop) - -#endif diff --git a/example/nested_paging/x64/amd/npte_t.hpp b/example/nested_paging/x64/amd/npte_t.hpp deleted file mode 100644 index be3ab0d6..00000000 --- a/example/nested_paging/x64/amd/npte_t.hpp +++ /dev/null @@ -1,73 +0,0 @@ -/// @copyright -/// Copyright (C) 2020 Assured Information Security, Inc. -/// -/// @copyright -/// Permission is hereby granted, free of charge, to any person obtaining a copy -/// of this software and associated documentation files (the "Software"), to deal -/// in the Software without restriction, including without limitation the rights -/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -/// copies of the Software, and to permit persons to whom the Software is -/// furnished to do so, subject to the following conditions: -/// -/// @copyright -/// The above copyright notice and this permission notice shall be included in -/// all copies or substantial portions of the Software. -/// -/// @copyright -/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -/// SOFTWARE. - -#ifndef NPTE_T_HPP -#define NPTE_T_HPP - -#include -#include -#include - -#pragma pack(push, 1) - -namespace example -{ - /// @struct example::npte_t - /// - /// @brief Defines the layout of a nested page table entry (NPTE). - /// - struct npte_t final - { - /// @brief defines the "present" field in the page - bsl::uint64 p : static_cast(1); - /// @brief defines the "read/write" field in the page - bsl::uint64 rw : static_cast(1); - /// @brief defines the "user/supervisor" field in the page - bsl::uint64 us : static_cast(1); - /// @brief defines the "page-level writethrough" field in the page - bsl::uint64 pwt : static_cast(1); - /// @brief defines the "page-level cache disable" field in the page - bsl::uint64 pcd : static_cast(1); - /// @brief defines the "accessed" field in the page - bsl::uint64 a : static_cast(1); - /// @brief defines the "dirty" field in the page (ignored) - bsl::uint64 d : static_cast(1); - /// @brief defines the "page size" field in the page (must be 0) - bsl::uint64 ps : static_cast(1); - /// @brief defines the "global" field in the page (must be 0) - bsl::uint64 g : static_cast(1); - /// @brief defines the "available to software" field in the page - bsl::uint64 available1 : static_cast(3); - /// @brief defines the "physical address" field in the page - bsl::uint64 phys : static_cast(40); - /// @brief defines the "available to software" field in the page - bsl::uint64 available2 : static_cast(11); - /// @brief defines the "no-execute" field in the page - bsl::uint64 nx : static_cast(1); - }; -} - -#pragma pack(pop) - -#endif diff --git a/example/nested_paging/x64/common_arch_support.hpp b/example/nested_paging/x64/common_arch_support.hpp deleted file mode 100644 index 870fe818..00000000 --- a/example/nested_paging/x64/common_arch_support.hpp +++ /dev/null @@ -1,162 +0,0 @@ -/// @copyright -/// Copyright (C) 2020 Assured Information Security, Inc. -/// -/// @copyright -/// Permission is hereby granted, free of charge, to any person obtaining a copy -/// of this software and associated documentation files (the "Software"), to deal -/// in the Software without restriction, including without limitation the rights -/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -/// copies of the Software, and to permit persons to whom the Software is -/// furnished to do so, subject to the following conditions: -/// -/// @copyright -/// The above copyright notice and this permission notice shall be included in -/// all copies or substantial portions of the Software. -/// -/// @copyright -/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -/// SOFTWARE. - -#ifndef COMMON_ARCH_SUPPORT_HPP -#define COMMON_ARCH_SUPPORT_HPP - -#include "intrinsic_cpuid.hpp" - -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -namespace example -{ - /// - /// @brief Handle CPUID VMExits - /// - /// - /// @param handle the handle to use - /// @param vsid the ID of the VS that caused the VMExit - /// @return Returns bsl::errc_success on success and bsl::errc_failure - /// on failure. - /// - [[nodiscard]] inline auto - handle_vmexit_cpuid(syscall::bf_handle_t &handle, bsl::safe_u16 const &vsid) noexcept - -> bsl::errc_type - { - bsl::errc_type ret{}; - - bsl::safe_umx rax{syscall::bf_tls_rax(handle)}; - bsl::safe_umx rbx{syscall::bf_tls_rbx(handle)}; - bsl::safe_umx rcx{syscall::bf_tls_rcx(handle)}; - bsl::safe_umx rdx{syscall::bf_tls_rdx(handle)}; - - /// NOTE: - /// - Before we execute CPUID, we need to check to see if we have - /// received a CPUID command. If we have, we need to handle this - /// CPUID differently. - /// - - if (loader::CPUID_COMMAND_EAX == bsl::to_u32_unsafe(rax)) { - switch (bsl::to_u32_unsafe(rcx).get()) { - case loader::CPUID_COMMAND_ECX_STOP.get(): { - - /// NOTE: - /// - To support stopping the hypervisor, we need to - /// report success by setting RAX to 0, and advancing - /// the IP (as CPUID should not be executed again). - /// - From there, we can run the promote API, which will - /// take the current state associated with the provided - /// VS and promote it, effectively stopping the - /// hypervisor. - /// - - syscall::bf_tls_set_rax(handle, bsl::ZERO_UMAX); - - ret = syscall::bf_vs_op_advance_ip(handle, vsid); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return ret; - } - - ret = syscall::bf_vs_op_promote(handle, vsid); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return ret; - } - - // Unreachable - return bsl::errc_success; - } - - case loader::CPUID_COMMAND_ECX_REPORT_ON.get(): { - bsl::debug() << bsl::rst << "host os is" // -- - << bsl::grn << " now " // -- - << bsl::rst << "in a vm (nested_paging example)\n"; // -- - - if (vsid + bsl::ONE_U16 == syscall::bf_tls_online_pps(handle)) { - bsl::print() << bsl::endl; - syscall::bf_debug_op_dump_page_pool(); - bsl::print() << bsl::endl; - } - else { - bsl::touch(); - } - - return bsl::errc_success; - } - - case loader::CPUID_COMMAND_ECX_REPORT_OFF.get(): { - bsl::debug() << bsl::rst << "host os is" // -- - << bsl::red << " not " // -- - << bsl::rst << "in a vm\n"; // -- - - return bsl::errc_success; - } - - default: { - break; - } - } - } - else { - - /// NOTE: - /// - The call to bsl::touch is only needed if you plan to enforce - /// MC/DC testing. bsl::touch() does nothing (i.e., it is an - /// empty function), but it reserves a line in the source code - /// that coverage tools can use to ensure the else{} path was - /// taken during unit testing. Feel free to ignore this if you - /// have no plans to support MC/DC testing. - /// - - bsl::touch(); - } - - /// NOTE: - /// - If we go this far, this is a normal CPUID, which means we - /// simply need to emulate its execution by calling CPUID and - /// returning the results. - /// - - intrinsic_cpuid(rax.data(), rbx.data(), rcx.data(), rdx.data()); - - syscall::bf_tls_set_rax(handle, rax); - syscall::bf_tls_set_rbx(handle, rbx); - syscall::bf_tls_set_rcx(handle, rcx); - syscall::bf_tls_set_rdx(handle, rdx); - - return bsl::errc_success; - } -} - -#endif diff --git a/example/nested_paging/x64/intel/arch_support.hpp b/example/nested_paging/x64/intel/arch_support.hpp deleted file mode 100644 index 1c90917d..00000000 --- a/example/nested_paging/x64/intel/arch_support.hpp +++ /dev/null @@ -1,600 +0,0 @@ -/// @copyright -/// Copyright (C) 2020 Assured Information Security, Inc. -/// -/// @copyright -/// Permission is hereby granted, free of charge, to any person obtaining a copy -/// of this software and associated documentation files (the "Software"), to deal -/// in the Software without restriction, including without limitation the rights -/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -/// copies of the Software, and to permit persons to whom the Software is -/// furnished to do so, subject to the following conditions: -/// -/// @copyright -/// The above copyright notice and this permission notice shall be included in -/// all copies or substantial portions of the Software. -/// -/// @copyright -/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -/// SOFTWARE. - -#ifndef ARCH_SUPPORT_HPP -#define ARCH_SUPPORT_HPP - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -namespace example -{ - /// @brief stores the MSR bitmap used by this extension - constinit inline void *g_msr_bitmaps{}; - /// @brief stores the physical address of the MSR bitmap - constinit inline bsl::safe_umx g_msr_bitmaps_phys{}; - - /// @brief stores the page pool to use for page allocation - constinit inline page_pool_t g_page_pool{}; - /// @brief stores the mtrrs used to create EPT - constinit inline mtrrs_t g_mtrrs{}; - /// @brief stores the extended page tables - constinit inline extended_page_table_t g_ept{}; - - /// - /// @brief Handle NMIs. This is required by Intel. - /// - /// - /// @param handle the handle to use - /// @param vsid the ID of the VS that caused the VMExit - /// @return Returns bsl::errc_success on success and bsl::errc_failure - /// on failure. - /// - [[nodiscard]] constexpr auto - handle_vmexit_nmi(syscall::bf_handle_t &handle, bsl::safe_u16 const &vsid) noexcept - -> bsl::errc_type - { - /// NOTE: - /// - If we caught an NMI, we need to inject it into the VM. To do - /// this, all we do is enable the NMI window, which will tell us - /// when we can safely inject the NMI. - /// - Note that the microkernel will do the same thing. If an NMI - /// fires while the hypevisor is running, it will enable the NMI - /// window, which the extension will see as a VMExit, and must - /// from there, inject the NMI into the appropriate VS. - /// - - constexpr bsl::safe_umx vmcs_procbased_ctls_idx{bsl::to_umx(0x4002U)}; - constexpr bsl::safe_u32 vmcs_set_nmi_window_exiting{bsl::to_u32(0x400000U)}; - - bsl::errc_type ret{}; - bsl::safe_u32 val{}; - - ret = syscall::bf_vs_op_read32(handle, vsid, vmcs_procbased_ctls_idx, val); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return ret; - } - - val |= vmcs_set_nmi_window_exiting; - - ret = syscall::bf_vs_op_write32(handle, vsid, vmcs_procbased_ctls_idx, val); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return ret; - } - - return ret; - } - - /// - /// @brief Handle NMIs Windows - /// - /// - /// @param handle the handle to use - /// @param vsid the ID of the VS that caused the VMExit - /// @return Returns bsl::errc_success on success and bsl::errc_failure - /// on failure. - /// - [[nodiscard]] constexpr auto - handle_vmexit_nmi_window(syscall::bf_handle_t &handle, bsl::safe_u16 const &vsid) noexcept - -> bsl::errc_type - { - /// NOTE: - /// - If we see this exit, it is because an NMI fired. There are two - /// situations where this could occur, either while the hypervisor - /// is running, or the VS is running. In either case, we need to - /// clear the NMI window and inject the NMI into the appropriate - /// VS so that it can be handled. Note that Intel requires that - /// we handle NMIs, and they actually happen a lot with Linux based - /// on what hardware you are using (e.g., a laptop). - /// - - constexpr bsl::safe_umx vmcs_procbased_ctls_idx{bsl::to_umx(0x4002U)}; - constexpr bsl::safe_u32 vmcs_clear_nmi_window_exiting{bsl::to_u32(0xFFBFFFFFU)}; - - bsl::errc_type ret{}; - bsl::safe_u32 val{}; - - ret = syscall::bf_vs_op_read32(handle, vsid, vmcs_procbased_ctls_idx, val); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return ret; - } - - val &= vmcs_clear_nmi_window_exiting; - - ret = syscall::bf_vs_op_write32(handle, vsid, vmcs_procbased_ctls_idx, val); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return ret; - } - - /// NOTE: - /// - Inject an NMI. If the NMI window was enabled, it is because we - /// need to inject a NMI. Note that the NMI window can be enabled - /// both by this extension, as well as by the microkernel itself, - /// so we are required to implement it on Intel. - /// - - constexpr bsl::safe_umx vmcs_entry_interrupt_info_idx{bsl::to_umx(0x4016U)}; - constexpr bsl::safe_u32 vmcs_entry_interrupt_info_val{bsl::to_u32(0x80000202U)}; - - ret = syscall::bf_vs_op_write32( - handle, vsid, vmcs_entry_interrupt_info_idx, vmcs_entry_interrupt_info_val); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return ret; - } - - return ret; - } - - /// - /// @brief Implements the architecture specific VMExit handler. - /// - /// - /// @param handle the handle to use - /// @param vsid the ID of the VS that generated the VMExit - /// @param exit_reason the exit reason associated with the VMExit - /// - constexpr void - vmexit( - syscall::bf_handle_t &handle, - bsl::safe_u16 const &vsid, - bsl::safe_u64 const &exit_reason) noexcept - { - bsl::errc_type ret{}; - constexpr bsl::safe_umx exit_reason_nmi{bsl::to_umx(0x0)}; - constexpr bsl::safe_umx exit_reason_nmi_window{bsl::to_umx(0x8)}; - constexpr bsl::safe_umx exit_reason_cpuid{bsl::to_umx(0xA)}; - - /// NOTE: - /// - At a minimum, we need to handle CPUID and NMIs on Intel. Note - /// that the "run" APIs all return an error code, but for the most - /// part we can ignore them. If the this function succeeds, it will - /// not return. If it fails, it will return, and the error code is - /// always UNKNOWN. We output the current line so that debugging - /// the issue is easier. - /// - - switch (exit_reason.get()) { - case exit_reason_nmi.get(): { - ret = handle_vmexit_nmi(handle, vsid); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return; - } - - bsl::discard(syscall::bf_vs_op_run_current(handle)); - bsl::print() << bsl::here(); - return; - } - - case exit_reason_nmi_window.get(): { - ret = handle_vmexit_nmi_window(handle, vsid); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return; - } - - bsl::discard(syscall::bf_vs_op_run_current(handle)); - bsl::print() << bsl::here(); - return; - } - - case exit_reason_cpuid.get(): { - ret = handle_vmexit_cpuid(handle, vsid); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return; - } - - bsl::discard(syscall::bf_vs_op_advance_ip_and_run_current(handle)); - bsl::print() << bsl::here(); - return; - } - - default: { - break; - } - } - - syscall::bf_debug_op_dump_vs(vsid); - - bsl::error() << "unknown exit_reason: " // -- - << bsl::hex(exit_reason) // -- - << bsl::endl // -- - << bsl::here(); // -- - } - - /// - /// @brief Returns the controls as their masked versions using the - /// conversion rules defined in the Intel Manual for determining - /// which controls must be enabled, and which controls are not - /// allowed to be enabled. - /// - /// - /// @param val the control to mask - /// @return Returns the masked version of the control - /// - [[nodiscard]] constexpr auto - mask_enabled_and_disabled(bsl::safe_umx const &val) noexcept -> bsl::safe_u32 - { - constexpr bsl::safe_umx ctls_mask{bsl::to_umx(0x00000000FFFFFFFFU)}; - constexpr bsl::safe_umx ctls_shift{bsl::to_umx(32)}; - return bsl::to_u32_unsafe((val & ctls_mask) & (val >> ctls_shift)); - }; - - /// - /// @brief Initializes a VS with architecture specific stuff. - /// - /// - /// @param handle the handle to use - /// @param vsid the VS being intialized - /// @return Returns bsl::errc_success on success and bsl::errc_failure - /// on failure. - /// - [[nodiscard]] constexpr auto - init_vs(syscall::bf_handle_t &handle, bsl::safe_u16 const &vsid) noexcept -> bsl::errc_type - { - bsl::errc_type ret{}; - - /// NOTE: - /// - Set up VPID - /// - - constexpr bsl::safe_umx vmcs_vpid_idx{bsl::to_umx(0x0000U)}; - constexpr bsl::safe_u16 vmcs_vpid_val{bsl::to_u16(0x1)}; - - ret = syscall::bf_vs_op_write16(handle, vsid, vmcs_vpid_idx, vmcs_vpid_val); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return ret; - } - - /// NOTE: - /// - Set up the VMCS link pointer - /// - - constexpr bsl::safe_umx vmcs_link_ptr_idx{bsl::to_umx(0x2800U)}; - constexpr bsl::safe_umx vmcs_link_ptr_val{bsl::to_umx(0xFFFFFFFFFFFFFFFFU)}; - - ret = syscall::bf_vs_op_write64(handle, vsid, vmcs_link_ptr_idx, vmcs_link_ptr_val); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return ret; - } - - /// NOTE: - /// - Set up the VMCS pin based, proc based, exit and entry controls - /// - We turn on MSR bitmaps so that we do not trap on MSR reads and - /// writes. If you do not configure this, or you use the bitmap - /// to trap to specific MSR accesses, make sure you keep the VMCS - /// in sync with your MSR mods. Any MSR that is in the VMCS also - /// needs to be written to the VMCS, otherwise, VMEntry/VMExit will - /// replace any values you write. - /// - We also turn on secondary controls so that we can turn on VPID, - /// and turn on instructions that the OS is relying on, like - /// RDTSCP. Failure to do this will cause the invalid opcodes to - /// occur. - /// - The lambda below performs the MSR conversion of the CTLS - /// registers to determine the bits that must always be set to 1, - /// and the bits that must always be set to 0. This allows us to - /// turn on as much as possible, letting the MSRs decide what is - /// allowed and what is not. - /// - Also note that we do not attempt to detect support for the - /// secondary controls. This is because the loader ensures that - /// this support is present as it is a minimum requirement for the - /// project. - /// - - constexpr bsl::safe_umx vmcs_pinbased_ctls_idx{bsl::to_umx(0x4000U)}; - constexpr bsl::safe_umx vmcs_procbased_ctls_idx{bsl::to_umx(0x4002U)}; - constexpr bsl::safe_umx vmcs_exit_ctls_idx{bsl::to_umx(0x400CU)}; - constexpr bsl::safe_umx vmcs_entry_ctls_idx{bsl::to_umx(0x4012U)}; - constexpr bsl::safe_umx vmcs_procbased_ctls2_idx{bsl::to_umx(0x401EU)}; - - constexpr bsl::safe_u32 vmx_true_pinbased_ctls{bsl::to_u32(0x48DU)}; - constexpr bsl::safe_u32 vmx_true_procbased_ctls{bsl::to_u32(0x48EU)}; - constexpr bsl::safe_u32 vmx_true_exit_ctls{bsl::to_u32(0x48FU)}; - constexpr bsl::safe_u32 vmx_true_entry_ctls{bsl::to_u32(0x490U)}; - constexpr bsl::safe_u32 vmx_true_procbased_ctls2{bsl::to_u32(0x48BU)}; - - bsl::safe_umx ctls{}; - - /// NOTE: - /// - Configure the pin based controls - /// - - ret = syscall::bf_intrinsic_op_rdmsr(handle, vmx_true_pinbased_ctls, ctls); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return ret; - } - - ret = syscall::bf_vs_op_write32( - handle, vsid, vmcs_pinbased_ctls_idx, mask_enabled_and_disabled(ctls)); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return ret; - } - - /// NOTE: - /// - Configure the proc based controls - /// - - constexpr bsl::safe_umx enable_msr_bitmaps{bsl::to_umx(0x10000000U)}; - constexpr bsl::safe_umx enable_procbased_ctls2{bsl::to_umx(0x80000000U)}; - - ret = syscall::bf_intrinsic_op_rdmsr(handle, vmx_true_procbased_ctls, ctls); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return ret; - } - - ctls |= enable_msr_bitmaps; - ctls |= enable_procbased_ctls2; - - ret = syscall::bf_vs_op_write32( - handle, vsid, vmcs_procbased_ctls_idx, mask_enabled_and_disabled(ctls)); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return ret; - } - - /// NOTE: - /// - Configure the exit controls - /// - - ret = syscall::bf_intrinsic_op_rdmsr(handle, vmx_true_exit_ctls, ctls); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return ret; - } - - ret = syscall::bf_vs_op_write32( - handle, vsid, vmcs_exit_ctls_idx, mask_enabled_and_disabled(ctls)); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return ret; - } - - /// NOTE: - /// - Configure the entry controls - /// - - ret = syscall::bf_intrinsic_op_rdmsr(handle, vmx_true_entry_ctls, ctls); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return ret; - } - - ret = syscall::bf_vs_op_write32( - handle, vsid, vmcs_entry_ctls_idx, mask_enabled_and_disabled(ctls)); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return ret; - } - - /// NOTE: - /// - Configure the secondary proc controls. - /// - - constexpr bsl::safe_umx enable_vpid{bsl::to_umx(0x00000020U)}; - constexpr bsl::safe_umx enable_rdtscp{bsl::to_umx(0x00000008U)}; - constexpr bsl::safe_umx enable_invpcid{bsl::to_umx(0x00001000U)}; - constexpr bsl::safe_umx enable_xsave{bsl::to_umx(0x00100000U)}; - constexpr bsl::safe_umx enable_uwait{bsl::to_umx(0x04000000U)}; - constexpr bsl::safe_umx enable_ept{bsl::to_umx(0x00000002U)}; - - ret = syscall::bf_intrinsic_op_rdmsr(handle, vmx_true_procbased_ctls2, ctls); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return ret; - } - - ctls |= enable_vpid; - ctls |= enable_rdtscp; - ctls |= enable_invpcid; - ctls |= enable_xsave; - ctls |= enable_uwait; - ctls |= enable_ept; - - ret = syscall::bf_vs_op_write32( - handle, vsid, vmcs_procbased_ctls2_idx, mask_enabled_and_disabled(ctls)); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return ret; - } - - /// NOTE: - /// - Configure the MSR bitmaps. This ensures that we do not trap - /// on MSR reads and writes. Also note that in most applications, - /// you only need one of these, regardless of the total number of - /// CPUs you are running on. - /// - - constexpr bsl::safe_umx vmcs_msr_bitmaps{bsl::to_umx(0x2004U)}; - - if (nullptr == g_msr_bitmaps) { - ret = syscall::bf_mem_op_alloc_page(handle, g_msr_bitmaps, g_msr_bitmaps_phys); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return ret; - } - - bsl::touch(); - } - else { - bsl::touch(); - } - - ret = syscall::bf_vs_op_write64(handle, vsid, vmcs_msr_bitmaps, g_msr_bitmaps_phys); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return ret; - } - - /// NOTE: - /// - The first step in setting up EPT is to determine - /// if we have support for it. We do this on each physical processor - /// we are being started on, but likely you could just do this - /// check on the first physical processor and be done. - /// - To determine if we have support for EPT, we need to check to see - /// if attempting to enable EPT above worked. This can be done by - /// checking to see if EPT was actually enabled. - /// - - ret = syscall::bf_vs_op_read64(handle, vsid, vmcs_procbased_ctls2_idx, ctls); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return ret; - } - - if ((ctls & (~enable_ept)).is_zero()) { - bsl::error() << "EPT not supported\n" << bsl::here(); - return bsl::errc_failure; - } - - /// NOTE: - /// - Before we can set up the extended page tables, we need to set up - /// a page pool. This is needed because not all microkernels will - /// support the free_page() ABI. If we want to change the extended - /// page tables, or make new ones and then release them when we are - /// done, etc, we will need the ability to free a page so that we - /// can use it again. To do this we create our own page pool. - /// Whenever we allocate a page, if the page pool is empty, it will - /// as the microkernel for a page. When memory is freed, it puts - /// the freed page into our page pool so that we can use it the next - /// time an allocation occurs. - /// - Note that this approach is basically how malloc/free engines - /// work when you write your own application for Windows/Linux. - /// The allocation engine asks the kernel for memory (usually it - /// asks for heap memory, but that is not a requirement), and then - /// it provides this memory when you run malloc(). We are doing the - /// samething here, but with page granularity. - /// - It should also be noted that the microkernel does provide a - /// heap if you want to use it, but in this case we really do want - /// page allocation as you cannot do virtual address to physical - /// address conversions for memory that was allocated on the heap. - /// - - if (syscall::bf_tls_ppid(handle) == bsl::ZERO_U16) { - ret = g_page_pool.initialize(handle); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return ret; - } - - bsl::touch(); - } - else { - bsl::touch(); - } - - /// NOTE: - /// - The next step is to initialize and set up the nested page - /// tables. One issue with this is you need to know how much - /// physical memory to map in. You could determine how much - /// physical address space you will need, or you could use on-demand - /// paging. You could also fill the entire physical address space - /// (up to the MAX value provided by CPUID), but how much memory - /// you need to allocate for the page tables to make that work is - /// up to what granularity you use. In this example, we only - /// provide 2M granularity, so this approach is likely a bad idea. - /// - Also note that what we are creating here is what we call an - /// identify map. Basically, each guest physical address is mapped - /// to the same system physical address. This is needed (usually) - /// for the root OS. If you plan to create your own guest VMs, - /// you will need a different mapping scheme. - /// - By default, we map in 512 GB of memory. Again, this is likely - /// not safe, but is good enough for an example. If the MTRRs report - /// that there is less physical memory than 512GB, we use the value - /// returned by the MTRRs instead. - /// - - constexpr bsl::safe_u64 max_physical_mem{bsl::to_umx(0x8000000000U)}; - - if (syscall::bf_tls_ppid(handle) == bsl::ZERO_U16) { - ret = g_ept.initialize(&g_page_pool); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return ret; - } - - ret = g_mtrrs.parse(handle); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return ret; - } - - ret = g_mtrrs.identity_map_2m( - g_ept, bsl::ZERO_UMAX, g_mtrrs.max_phys().min(max_physical_mem), MAP_PAGE_RWE); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return ret; - } - - bsl::touch(); - } - else { - bsl::touch(); - } - - /// NOTE: - /// - Finally, we need to set EPTP in the VMCS so that the CPU - /// knows where to find our extended page tables. - /// - Similar to CR3, we also need to set some bits in the EPTP. - /// In this case we have told the CPU that it has 4 page levels - /// to walk and that the default memory type is WB. - /// - - constexpr bsl::safe_umx eptp_fields{bsl::to_umx(0x1EU)}; - constexpr bsl::safe_umx vmcs_ept_pointer{bsl::to_umx(0x201AU)}; - - bsl::safe_umx eptp{g_ept.phys() | eptp_fields}; - - ret = syscall::bf_vs_op_write64(handle, vsid, vmcs_ept_pointer, eptp); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return ret; - } - - return ret; - } -} - -#endif diff --git a/example/nested_paging/x64/intel/epdpt_t.hpp b/example/nested_paging/x64/intel/epdpt_t.hpp deleted file mode 100644 index b8dda873..00000000 --- a/example/nested_paging/x64/intel/epdpt_t.hpp +++ /dev/null @@ -1,55 +0,0 @@ -/// @copyright -/// Copyright (C) 2020 Assured Information Security, Inc. -/// -/// @copyright -/// Permission is hereby granted, free of charge, to any person obtaining a copy -/// of this software and associated documentation files (the "Software"), to deal -/// in the Software without restriction, including without limitation the rights -/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -/// copies of the Software, and to permit persons to whom the Software is -/// furnished to do so, subject to the following conditions: -/// -/// @copyright -/// The above copyright notice and this permission notice shall be included in -/// all copies or substantial portions of the Software. -/// -/// @copyright -/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -/// SOFTWARE. - -#ifndef EPDPT_T_HPP -#define EPDPT_T_HPP - -#include - -#include -#include -#include - -#pragma pack(push, 1) - -namespace example -{ - /// @brief defined the expected size of the epdpt_t struct - constexpr bsl::safe_umx NUM_EPDPT_ENTRIES{bsl::to_umx(512)}; - - /// @struct example::epdpt_t - /// - /// - /// @brief Defines the layout of a page-directory-pionter table (epdpt). - /// - struct epdpt_t final - { - /// @brief stores the entires in the table - bsl::array entries; - }; -} - -#pragma pack(pop) - -#endif diff --git a/example/nested_paging/x64/intel/epdpte_t.hpp b/example/nested_paging/x64/intel/epdpte_t.hpp deleted file mode 100644 index 78bd4b47..00000000 --- a/example/nested_paging/x64/intel/epdpte_t.hpp +++ /dev/null @@ -1,75 +0,0 @@ -/// @copyright -/// Copyright (C) 2020 Assured Information Security, Inc. -/// -/// @copyright -/// Permission is hereby granted, free of charge, to any person obtaining a copy -/// of this software and associated documentation files (the "Software"), to deal -/// in the Software without restriction, including without limitation the rights -/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -/// copies of the Software, and to permit persons to whom the Software is -/// furnished to do so, subject to the following conditions: -/// -/// @copyright -/// The above copyright notice and this permission notice shall be included in -/// all copies or substantial portions of the Software. -/// -/// @copyright -/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -/// SOFTWARE. - -#ifndef EPDPTE_T_HPP -#define EPDPTE_T_HPP - -#include -#include -#include - -#pragma pack(push, 1) - -namespace example -{ - /// @struct example::epdpte_t - /// - /// - /// @brief Defines the layout of a nested page-directory-pointer table - /// entry (EPDPTE). - /// - struct epdpte_t final - { - /// @brief defines the "read access" field in the page - bsl::uint64 r : static_cast(1); - /// @brief defines the "write access" field in the page - bsl::uint64 w : static_cast(1); - /// @brief defines the "execute access" field in the page - bsl::uint64 e : static_cast(1); - /// @brief defines the "memory type" field in the page - bsl::uint64 type : static_cast(3); - /// @brief defines the "ignore pat" field in the page - bsl::uint64 ignore_pat : static_cast(1); - /// @brief defines the "page size" field in the page - bsl::uint64 ps : static_cast(1); - /// @brief defines the "accessed" field in the page - bsl::uint64 a : static_cast(1); - /// @brief defines the "ignored" field in the page - bsl::uint64 d : static_cast(1); - /// @brief defines the "user execute access" field in the page - bsl::uint64 e_user : static_cast(1); - /// @brief defines the "ignored" field in the page - bsl::uint64 ignored1 : static_cast(1); - /// @brief defines the "physical address" field in the page - bsl::uint64 phys : static_cast(40); - /// @brief defines the "ignored" field in the page - bsl::uint64 ignored2 : static_cast(11); - /// @brief defines the "virtualization exception" field in the page - bsl::uint64 ve : static_cast(1); - }; -} - -#pragma pack(pop) - -#endif diff --git a/example/nested_paging/x64/intel/epdt_t.hpp b/example/nested_paging/x64/intel/epdt_t.hpp deleted file mode 100644 index 6b02924c..00000000 --- a/example/nested_paging/x64/intel/epdt_t.hpp +++ /dev/null @@ -1,55 +0,0 @@ -/// @copyright -/// Copyright (C) 2020 Assured Information Security, Inc. -/// -/// @copyright -/// Permission is hereby granted, free of charge, to any person obtaining a copy -/// of this software and associated documentation files (the "Software"), to deal -/// in the Software without restriction, including without limitation the rights -/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -/// copies of the Software, and to permit persons to whom the Software is -/// furnished to do so, subject to the following conditions: -/// -/// @copyright -/// The above copyright notice and this permission notice shall be included in -/// all copies or substantial portions of the Software. -/// -/// @copyright -/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -/// SOFTWARE. - -#ifndef EPDT_T_HPP -#define EPDT_T_HPP - -#include - -#include -#include -#include - -#pragma pack(push, 1) - -namespace example -{ - /// @brief defined the expected size of the epdt_t struct - constexpr bsl::safe_umx NUM_EPDT_ENTRIES{bsl::to_umx(512)}; - - /// @struct example::epdt_t - /// - /// - /// @brief Defines the layout of a page-directory table (epdt). - /// - struct epdt_t final - { - /// @brief stores the entires in the table - bsl::array entries; - }; -} - -#pragma pack(pop) - -#endif diff --git a/example/nested_paging/x64/intel/epdte_t.hpp b/example/nested_paging/x64/intel/epdte_t.hpp deleted file mode 100644 index 103878ca..00000000 --- a/example/nested_paging/x64/intel/epdte_t.hpp +++ /dev/null @@ -1,75 +0,0 @@ -/// @copyright -/// Copyright (C) 2020 Assured Information Security, Inc. -/// -/// @copyright -/// Permission is hereby granted, free of charge, to any person obtaining a copy -/// of this software and associated documentation files (the "Software"), to deal -/// in the Software without restriction, including without limitation the rights -/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -/// copies of the Software, and to permit persons to whom the Software is -/// furnished to do so, subject to the following conditions: -/// -/// @copyright -/// The above copyright notice and this permission notice shall be included in -/// all copies or substantial portions of the Software. -/// -/// @copyright -/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -/// SOFTWARE. - -#ifndef EPDTE_T_HPP -#define EPDTE_T_HPP - -#include -#include -#include - -#pragma pack(push, 1) - -namespace example -{ - /// @struct example::epdte_t - /// - /// - /// @brief Defines the layout of a nested page-directory table entry - /// (EPDTE). - /// - struct epdte_t final - { - /// @brief defines the "read access" field in the page - bsl::uint64 r : static_cast(1); - /// @brief defines the "write access" field in the page - bsl::uint64 w : static_cast(1); - /// @brief defines the "execute access" field in the page - bsl::uint64 e : static_cast(1); - /// @brief defines the "memory type" field in the page - bsl::uint64 type : static_cast(3); - /// @brief defines the "ignore pat" field in the page - bsl::uint64 ignore_pat : static_cast(1); - /// @brief defines the "page size" field in the page - bsl::uint64 ps : static_cast(1); - /// @brief defines the "accessed" field in the page - bsl::uint64 a : static_cast(1); - /// @brief defines the "ignored" field in the page - bsl::uint64 d : static_cast(1); - /// @brief defines the "user execute access" field in the page - bsl::uint64 e_user : static_cast(1); - /// @brief defines the "ignored" field in the page - bsl::uint64 ignored1 : static_cast(1); - /// @brief defines the "physical address" field in the page - bsl::uint64 phys : static_cast(40); - /// @brief defines the "ignored" field in the page - bsl::uint64 ignored2 : static_cast(11); - /// @brief defines the "virtualization exception" field in the page - bsl::uint64 ve : static_cast(1); - }; -} - -#pragma pack(pop) - -#endif diff --git a/example/nested_paging/x64/intel/epml4t_t.hpp b/example/nested_paging/x64/intel/epml4t_t.hpp deleted file mode 100644 index cca8ebbc..00000000 --- a/example/nested_paging/x64/intel/epml4t_t.hpp +++ /dev/null @@ -1,55 +0,0 @@ -/// @copyright -/// Copyright (C) 2020 Assured Information Security, Inc. -/// -/// @copyright -/// Permission is hereby granted, free of charge, to any person obtaining a copy -/// of this software and associated documentation files (the "Software"), to deal -/// in the Software without restriction, including without limitation the rights -/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -/// copies of the Software, and to permit persons to whom the Software is -/// furnished to do so, subject to the following conditions: -/// -/// @copyright -/// The above copyright notice and this permission notice shall be included in -/// all copies or substantial portions of the Software. -/// -/// @copyright -/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -/// SOFTWARE. - -#ifndef EPML4T_T_HPP -#define EPML4T_T_HPP - -#include - -#include -#include -#include - -#pragma pack(push, 1) - -namespace example -{ - /// @brief defined the expected size of the epml4t_t struct - constexpr bsl::safe_umx NUM_EPML4T_ENTRIES{bsl::to_umx(512)}; - - /// @struct example::epml4t_t - /// - /// - /// @brief Defines the layout of a page-map level-4 table (pml4). - /// - struct epml4t_t final - { - /// @brief stores the entires in the table - bsl::array entries; - }; -} - -#pragma pack(pop) - -#endif diff --git a/example/nested_paging/x64/intel/epml4te_t.hpp b/example/nested_paging/x64/intel/epml4te_t.hpp deleted file mode 100644 index fcc97624..00000000 --- a/example/nested_paging/x64/intel/epml4te_t.hpp +++ /dev/null @@ -1,69 +0,0 @@ -/// @copyright -/// Copyright (C) 2020 Assured Information Security, Inc. -/// -/// @copyright -/// Permission is hereby granted, free of charge, to any person obtaining a copy -/// of this software and associated documentation files (the "Software"), to deal -/// in the Software without restriction, including without limitation the rights -/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -/// copies of the Software, and to permit persons to whom the Software is -/// furnished to do so, subject to the following conditions: -/// -/// @copyright -/// The above copyright notice and this permission notice shall be included in -/// all copies or substantial portions of the Software. -/// -/// @copyright -/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -/// SOFTWARE. - -#ifndef EPML4TE_T_HPP -#define EPML4TE_T_HPP - -#include -#include -#include - -#pragma pack(push, 1) - -namespace example -{ - /// @struct example::epml4te_t - /// - /// - /// @brief Defines the layout of a nested page-map level-4 table entry - /// (EPML4TE). - /// - struct epml4te_t final - { - /// @brief defines the "read access" field in the page - bsl::uint64 r : static_cast(1); - /// @brief defines the "write access" field in the page - bsl::uint64 w : static_cast(1); - /// @brief defines the "execute access" field in the page - bsl::uint64 e : static_cast(1); - /// @brief defines the "must be zero" field in the page - bsl::uint64 mbz1 : static_cast(5); - /// @brief defines the "accessed" field in the page - bsl::uint64 a : static_cast(1); - /// @brief defines the "ignored" field in the page - bsl::uint64 ignored1 : static_cast(1); - /// @brief defines the "user execute access" field in the page - bsl::uint64 e_user : static_cast(1); - /// @brief defines the "ignored" field in the page - bsl::uint64 ignored2 : static_cast(1); - /// @brief defines the "physical address" field in the page - bsl::uint64 phys : static_cast(40); - /// @brief defines the "ignored" field in the page - bsl::uint64 ignored3 : static_cast(12); - }; -} - -#pragma pack(pop) - -#endif diff --git a/example/nested_paging/x64/intel/ept_t.hpp b/example/nested_paging/x64/intel/ept_t.hpp deleted file mode 100644 index 386c3ece..00000000 --- a/example/nested_paging/x64/intel/ept_t.hpp +++ /dev/null @@ -1,55 +0,0 @@ -/// @copyright -/// Copyright (C) 2020 Assured Information Security, Inc. -/// -/// @copyright -/// Permission is hereby granted, free of charge, to any person obtaining a copy -/// of this software and associated documentation files (the "Software"), to deal -/// in the Software without restriction, including without limitation the rights -/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -/// copies of the Software, and to permit persons to whom the Software is -/// furnished to do so, subject to the following conditions: -/// -/// @copyright -/// The above copyright notice and this permission notice shall be included in -/// all copies or substantial portions of the Software. -/// -/// @copyright -/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -/// SOFTWARE. - -#ifndef EPT_T_HPP -#define EPT_T_HPP - -#include - -#include -#include -#include - -#pragma pack(push, 1) - -namespace example -{ - /// @brief defined the expected size of the ept_t struct - constexpr bsl::safe_umx NUM_EPT_ENTRIES{bsl::to_umx(512)}; - - /// @struct example::ept_t - /// - /// - /// @brief Defines the layout of a page table (ept). - /// - struct ept_t final - { - /// @brief stores the entires in the table - bsl::array entries; - }; -} - -#pragma pack(pop) - -#endif diff --git a/example/nested_paging/x64/intel/epte_t.hpp b/example/nested_paging/x64/intel/epte_t.hpp deleted file mode 100644 index ba4fc3bc..00000000 --- a/example/nested_paging/x64/intel/epte_t.hpp +++ /dev/null @@ -1,77 +0,0 @@ -/// @copyright -/// Copyright (C) 2020 Assured Information Security, Inc. -/// -/// @copyright -/// Permission is hereby granted, free of charge, to any person obtaining a copy -/// of this software and associated documentation files (the "Software"), to deal -/// in the Software without restriction, including without limitation the rights -/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -/// copies of the Software, and to permit persons to whom the Software is -/// furnished to do so, subject to the following conditions: -/// -/// @copyright -/// The above copyright notice and this permission notice shall be included in -/// all copies or substantial portions of the Software. -/// -/// @copyright -/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -/// SOFTWARE. - -#ifndef EPTE_T_HPP -#define EPTE_T_HPP - -#include -#include -#include - -#pragma pack(push, 1) - -namespace example -{ - /// @struct example::epte_t - /// - /// @brief Defines the layout of a nested page table entry (EPTE). - /// - struct epte_t final - { - /// @brief defines the "read access" field in the page - bsl::uint64 r : static_cast(1); - /// @brief defines the "write access" field in the page - bsl::uint64 w : static_cast(1); - /// @brief defines the "execute access" field in the page - bsl::uint64 e : static_cast(1); - /// @brief defines the "memory type" field in the page - bsl::uint64 type : static_cast(3); - /// @brief defines the "ignore pat" field in the page - bsl::uint64 ignore_pat : static_cast(1); - /// @brief defines the "ignored" field in the page - bsl::uint64 ignored1 : static_cast(1); - /// @brief defines the "accessed" field in the page - bsl::uint64 a : static_cast(1); - /// @brief defines the "ignored" field in the page - bsl::uint64 d : static_cast(1); - /// @brief defines the "user execute access" field in the page - bsl::uint64 e_user : static_cast(1); - /// @brief defines the "ignored" field in the page - bsl::uint64 ignored2 : static_cast(1); - /// @brief defines the "physical address" field in the page - bsl::uint64 phys : static_cast(40); - /// @brief defines the "ignored" field in the page - bsl::uint64 ignored3 : static_cast(9); - /// @brief defines the "sub page write permissions" field in the page - bsl::uint64 sub : static_cast(1); - /// @brief defines the "ignored" field in the page - bsl::uint64 ignored4 : static_cast(1); - /// @brief defines the "virtualization exception" field in the page - bsl::uint64 ve : static_cast(1); - }; -} - -#pragma pack(pop) - -#endif diff --git a/example/nested_paging/x64/intel/extended_page_table_t.hpp b/example/nested_paging/x64/intel/extended_page_table_t.hpp deleted file mode 100644 index 09abaa58..00000000 --- a/example/nested_paging/x64/intel/extended_page_table_t.hpp +++ /dev/null @@ -1,791 +0,0 @@ -/// @copyright -/// Copyright (C) 2020 Assured Information Security, Inc. -/// -/// @copyright -/// Permission is hereby granted, free of charge, to any person obtaining a copy -/// of this software and associated documentation files (the "Software"), to deal -/// in the Software without restriction, including without limitation the rights -/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -/// copies of the Software, and to permit persons to whom the Software is -/// furnished to do so, subject to the following conditions: -/// -/// @copyright -/// The above copyright notice and this permission notice shall be included in -/// all copies or substantial portions of the Software. -/// -/// @copyright -/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -/// SOFTWARE. - -#ifndef EXTENDED_PAGE_TABLE_T_HPP -#define EXTENDED_PAGE_TABLE_T_HPP - -#include "epdpt_t.hpp" -#include "epdpte_t.hpp" -#include "epdt_t.hpp" -#include "epdte_t.hpp" -#include "epml4t_t.hpp" -#include "epml4te_t.hpp" -#include "ept_t.hpp" -#include "epte_t.hpp" - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -namespace example -{ - /// - /// @brief Implements the extended pages tables used by the extension - /// for mapping guest physical memory. - /// - class extended_page_table_t final - { - /// @brief stores true if initialized() has been executed - bool m_initialized{}; - /// @brief stores a reference to the page pool to use - page_pool_t *m_page_pool{}; - /// @brief stores a pointer to the epml4t - epml4t_t *m_epml4t{}; - /// @brief stores the physical address of the epml4t - bsl::safe_umx m_epml4t_phys{bsl::safe_umx::failure()}; - /// @brief safe guards operations on the NPT. - mutable spinlock m_ept_lock{}; - - /// - /// @brief Returns the extended page-map level-4 (NPML4T) offset given - /// a guest physical address. - /// - /// - /// @param gpa the guest physical address to get the NPML4T offset from. - /// @return the NPML4T offset from the guest physical address - /// - [[nodiscard]] static constexpr auto - epml4to(bsl::safe_umx const &gpa) noexcept -> bsl::safe_umx - { - constexpr bsl::safe_umx mask{bsl::to_umx(0x1FF)}; - constexpr bsl::safe_umx shift{bsl::to_umx(39)}; - return (gpa >> shift) & mask; - } - - /// - /// @brief Adds a epdpt_t to the provided epml4te_t. - /// - /// - /// @param epml4te the epml4te_t to add a epdpt_t too - /// @return Returns bsl::errc_success on success, bsl::errc_failure - /// and friends otherwise - /// - [[nodiscard]] constexpr auto - add_epdpt(epml4te_t *const epml4te) noexcept -> bsl::errc_type - { - auto const *const table{m_page_pool->template allocate()}; - if (bsl::unlikely(nullptr == table)) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - auto const table_phys{m_page_pool->virt_to_phys(table)}; - if (bsl::unlikely(!table_phys)) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - epml4te->phys = (table_phys >> bsl::to_umx(HYPERVISOR_PAGE_SHIFT)).get(); - epml4te->r = bsl::ONE_UMAX.get(); - epml4te->w = bsl::ONE_UMAX.get(); - epml4te->e = bsl::ONE_UMAX.get(); - - return bsl::errc_success; - } - - /// - /// @brief Adds a epdpt_t to the provided epml4te_t. - /// - /// - /// @param epml4te the epml4te_t to add a epdpt_t too - /// - constexpr void - remove_epdpt(epml4te_t *const epml4te) noexcept - { - for (auto const elem : get_epdpt(epml4te)->entries) { - if (elem.data->r != bsl::ZERO_UMAX) { - this->remove_epdt(elem.data); - } - else { - bsl::touch(); - } - } - - m_page_pool->deallocate(get_epdpt(epml4te)); - } - - /// - /// @brief Returns the epdpt_t associated with the provided - /// epml4te_t. - /// - /// - /// @param epml4te the epml4te_t to get the epdpt_t from - /// @return A pointer to the requested epdpt_t - /// - [[nodiscard]] constexpr auto - get_epdpt(epml4te_t *const epml4te) noexcept -> epdpt_t * - { - bsl::safe_umx entry_phys{epml4te->phys}; - entry_phys <<= bsl::to_umx(HYPERVISOR_PAGE_SHIFT); - - return m_page_pool->template phys_to_virt(entry_phys); - } - - /// - /// @brief Returns the epdpt_t associated with the provided - /// epml4te_t. - /// - /// - /// @param epml4te the epml4te_t to get the epdpt_t from - /// @return A pointer to the requested epdpt_t - /// - [[nodiscard]] constexpr auto - get_epdpt(epml4te_t const *const epml4te) const noexcept -> epdpt_t const * - { - bsl::safe_umx entry_phys{epml4te->phys}; - entry_phys <<= bsl::to_umx(HYPERVISOR_PAGE_SHIFT); - - return m_page_pool->template phys_to_virt(entry_phys); - } - - /// - /// @brief Returns the extended page-directory-pointer table (NPDPT) - /// offset given a guest physical address. - /// - /// - /// @param gpa the guest physical address to get the NPDPT offset from. - /// @return the NPDPT offset from the guest physical address - /// - [[nodiscard]] static constexpr auto - epdpto(bsl::safe_umx const &gpa) noexcept -> bsl::safe_umx - { - constexpr bsl::safe_umx mask{bsl::to_umx(0x1FF)}; - constexpr bsl::safe_umx shift{bsl::to_umx(30)}; - return (gpa >> shift) & mask; - } - - /// - /// @brief Adds a epdt_t to the provided epdpte_t. - /// - /// - /// @param epdpte the epdpte_t to add a epdt_t too - /// @return Returns bsl::errc_success on success, bsl::errc_failure - /// and friends otherwise - /// - [[nodiscard]] constexpr auto - add_epdt(epdpte_t *const epdpte) noexcept -> bsl::errc_type - { - auto const *const table{m_page_pool->template allocate()}; - if (bsl::unlikely(nullptr == table)) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - auto const table_phys{m_page_pool->virt_to_phys(table)}; - if (bsl::unlikely(!table_phys)) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - epdpte->phys = (table_phys >> bsl::to_umx(HYPERVISOR_PAGE_SHIFT)).get(); - epdpte->r = bsl::ONE_UMAX.get(); - epdpte->w = bsl::ONE_UMAX.get(); - epdpte->e = bsl::ONE_UMAX.get(); - - return bsl::errc_success; - } - - /// - /// @brief Adds a epdt_t to the provided epdpte_t. - /// - /// - /// @param epdpte the epdpte_t to add a epdt_t too - /// - constexpr void - remove_epdt(epdpte_t *const epdpte) noexcept - { - for (auto const elem : get_epdt(epdpte)->entries) { - if (elem.data->r != bsl::ZERO_UMAX) { - this->remove_ept(elem.data); - } - else { - bsl::touch(); - } - } - - m_page_pool->deallocate(get_epdt(epdpte)); - } - - /// - /// @brief Returns the epdt_t associated with the provided - /// epdpte_t. - /// - /// - /// @param epdpte the epdpte_t to get the epdt_t from - /// @return A pointer to the requested epdt_t - /// - [[nodiscard]] constexpr auto - get_epdt(epdpte_t *const epdpte) noexcept -> epdt_t * - { - bsl::safe_umx entry_phys{epdpte->phys}; - entry_phys <<= bsl::to_umx(HYPERVISOR_PAGE_SHIFT); - - return m_page_pool->template phys_to_virt(entry_phys); - } - - /// - /// @brief Returns the epdt_t associated with the provided - /// epdpte_t. - /// - /// - /// @param epdpte the epdpte_t to get the epdt_t from - /// @return A pointer to the requested epdt_t - /// - [[nodiscard]] constexpr auto - get_epdt(epdpte_t const *const epdpte) const noexcept -> epdt_t const * - { - bsl::safe_umx entry_phys{epdpte->phys}; - entry_phys <<= bsl::to_umx(HYPERVISOR_PAGE_SHIFT); - - return m_page_pool->template phys_to_virt(entry_phys); - } - - /// - /// @brief Returns the extended page-directory table (NPDT) offset - /// given a guest physical address. - /// - /// - /// @param gpa the guest physical address to get the NPDT offset from. - /// @return the NPDT offset from the guest physical address. - /// - [[nodiscard]] static constexpr auto - epdto(bsl::safe_umx const &gpa) noexcept -> bsl::safe_umx - { - constexpr bsl::safe_umx mask{bsl::to_umx(0x1FF)}; - constexpr bsl::safe_umx shift{bsl::to_umx(21)}; - return (gpa >> shift) & mask; - } - - /// - /// @brief Adds a ept_t to the provided epdte_t. - /// - /// - /// @param epdte the epdte_t to add a ept_t too - /// @return Returns bsl::errc_success on success, bsl::errc_failure - /// and friends otherwise - /// - [[nodiscard]] constexpr auto - add_ept(epdte_t *const epdte) noexcept -> bsl::errc_type - { - auto const *const table{m_page_pool->template allocate()}; - if (bsl::unlikely(nullptr == table)) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - auto const table_phys{m_page_pool->virt_to_phys(table)}; - if (bsl::unlikely(!table_phys)) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - epdte->phys = (table_phys >> bsl::to_umx(HYPERVISOR_PAGE_SHIFT)).get(); - epdte->r = bsl::ONE_UMAX.get(); - epdte->w = bsl::ONE_UMAX.get(); - epdte->e = bsl::ONE_UMAX.get(); - - return bsl::errc_success; - } - - /// - /// @brief Adds a ept_t to the provided epdte_t. - /// - /// - /// @param epdte the epdte_t to add a ept_t too - /// - constexpr void - remove_ept(epdte_t *const epdte) noexcept - { - m_page_pool->deallocate(get_ept(epdte)); - } - - /// - /// @brief Returns the ept_t associated with the provided - /// epdte_t. - /// - /// - /// @param epdte the epdte_t to get the ept_t from - /// @return A pointer to the requested ept_t - /// - [[nodiscard]] constexpr auto - get_ept(epdte_t *const epdte) noexcept -> ept_t * - { - bsl::safe_umx entry_phys{epdte->phys}; - entry_phys <<= bsl::to_umx(HYPERVISOR_PAGE_SHIFT); - - return m_page_pool->template phys_to_virt(entry_phys); - } - - /// - /// @brief Returns the ept_t associated with the provided - /// epdte_t. - /// - /// - /// @param epdte the epdte_t to get the ept_t from - /// @return A pointer to the requested ept_t - /// - [[nodiscard]] constexpr auto - get_ept(epdte_t const *const epdte) const noexcept -> ept_t const * - { - bsl::safe_umx entry_phys{epdte->phys}; - entry_phys <<= bsl::to_umx(HYPERVISOR_PAGE_SHIFT); - - return m_page_pool->template phys_to_virt(entry_phys); - } - - /// - /// @brief Returns the page-table (NPT) offset given a - /// guest physical address. - /// - /// - /// @param gpa the guest physical address to get the NPT offset from. - /// @return the NPT offset from the guest physical address - /// - [[nodiscard]] static constexpr auto - epto(bsl::safe_umx const &gpa) noexcept -> bsl::safe_umx - { - constexpr bsl::safe_umx mask{bsl::to_umx(0x1FF)}; - constexpr bsl::safe_umx shift{bsl::to_umx(12)}; - return (gpa >> shift) & mask; - } - - /// - /// @brief Returns true if the provided address is page aligned - /// - /// - /// @param addr the address to query - /// @return Returns true if the provided address is page aligned - /// - [[nodiscard]] static constexpr auto - is_page_aligned(bsl::safe_umx const &addr) noexcept -> bool - { - return (addr & (bsl::to_umx(HYPERVISOR_PAGE_SIZE) - bsl::ONE_UMAX)) == bsl::ZERO_UMAX; - } - - /// - /// @brief Releases the memory allocated in this root page table - /// - constexpr void - auto_release() noexcept - { - if (bsl::unlikely(nullptr == m_epml4t)) { - return; - } - - if (bsl::unlikely(nullptr == m_page_pool)) { - return; - } - - for (auto const elem : m_epml4t->entries) { - if (elem.data->r == bsl::ZERO_UMAX) { - continue; - } - - this->remove_epdpt(elem.data); - } - - m_page_pool->deallocate(m_epml4t); - m_epml4t = {}; - m_epml4t_phys = bsl::safe_umx::failure(); - } - - public: - /// - /// @brief Initializes this extended_page_table_t - /// - /// - /// @param page_pool the page pool to use - /// @return Returns bsl::errc_success on success, bsl::errc_failure - /// and friends otherwise - /// - [[nodiscard]] constexpr auto - initialize(page_pool_t *const page_pool) noexcept -> bsl::errc_type - { - if (bsl::unlikely(m_initialized)) { - bsl::error() << "extended_page_table_t already initialized\n" << bsl::here(); - return bsl::errc_failure; - } - - bsl::finally release_on_error{[this]() noexcept -> void { - this->release(); - }}; - - m_page_pool = page_pool; - if (bsl::unlikely(nullptr == page_pool)) { - bsl::error() << "invalid page_pool\n" << bsl::here(); - return bsl::errc_failure; - } - - m_epml4t = m_page_pool->template allocate(); - if (bsl::unlikely(nullptr == m_epml4t)) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - m_epml4t_phys = m_page_pool->virt_to_phys(m_epml4t); - if (bsl::unlikely(!m_epml4t_phys)) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - release_on_error.ignore(); - m_initialized = true; - - return bsl::errc_success; - } - - /// - /// @brief Releases the memory allocated in this extended page tables - /// - constexpr void - release() noexcept - { - this->auto_release(); - - m_page_pool = {}; - m_initialized = false; - } - - /// - /// @brief Returns the physical address of the PML4 - /// - /// - /// @return Returns the physical address of the PML4 - /// - [[nodiscard]] constexpr auto - phys() const noexcept -> bsl::safe_umx const & - { - return m_epml4t_phys; - } - - /// - /// @brief Maps a 4k page into the extended page tables being managed - /// by this class. - /// - /// - /// @param page_gpa the guest physical address to map the system - /// physical address to - /// @param page_spa the system physical address to map. - /// @param page_flags defines how memory should be mapped - /// @param page_type defines the memory type for the mapping - /// @return Returns bsl::errc_success on success, bsl::errc_failure - /// and friends otherwise - /// - [[nodiscard]] constexpr auto - map_4k_page( - bsl::safe_umx const &page_gpa, - bsl::safe_umx const &page_spa, - bsl::safe_umx const &page_flags, - bsl::safe_umx const &page_type) noexcept -> bsl::errc_type - { - lock_guard lock{m_ept_lock}; - - if (bsl::unlikely(!m_initialized)) { - bsl::error() << "extended_page_table_t not initialized\n" << bsl::here(); - return bsl::errc_failure; - } - - if (bsl::unlikely(!page_gpa)) { - bsl::error() << "guest physical address is invalid: " // -- - << bsl::hex(page_gpa) // -- - << bsl::endl // -- - << bsl::here(); // -- - - return bsl::errc_failure; - } - - if (bsl::unlikely(!this->is_page_aligned(page_gpa))) { - bsl::error() << "guest physical address is not page aligned: " // -- - << bsl::hex(page_gpa) // -- - << bsl::endl // -- - << bsl::here(); // -- - - return bsl::errc_failure; - } - - if (bsl::unlikely(!page_spa)) { - bsl::error() << "system physical address is invalid: " // -- - << bsl::hex(page_spa) // -- - << bsl::endl // -- - << bsl::here(); // -- - - return bsl::errc_failure; - } - - if (bsl::unlikely(!this->is_page_aligned(page_spa))) { - bsl::error() << "system physical address is not page aligned: " // -- - << bsl::hex(page_spa) // -- - << bsl::endl // -- - << bsl::here(); // -- - - return bsl::errc_failure; - } - - if (bsl::unlikely(!page_flags)) { - bsl::error() << "invalid flags: " // -- - << bsl::hex(page_flags) // -- - << bsl::endl // -- - << bsl::here(); // -- - - return bsl::errc_failure; - } - - if (bsl::unlikely(!page_type)) { - bsl::error() << "invalid type: " // -- - << bsl::hex(page_type) // -- - << bsl::endl // -- - << bsl::here(); // -- - - return bsl::errc_failure; - } - - auto *const epml4te{m_epml4t->entries.at_if(this->epml4to(page_gpa))}; - if (epml4te->r == bsl::ZERO_UMAX) { - if (bsl::unlikely(!this->add_epdpt(epml4te))) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - bsl::touch(); - } - else { - bsl::touch(); - } - - auto *const epdpt{this->get_epdpt(epml4te)}; - auto *const epdpte{epdpt->entries.at_if(this->epdpto(page_gpa))}; - if (epdpte->r == bsl::ZERO_UMAX) { - if (bsl::unlikely(!this->add_epdt(epdpte))) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - bsl::touch(); - } - else { - bsl::touch(); - } - - auto *const epdt{this->get_epdt(epdpte)}; - auto *const epdte{epdt->entries.at_if(this->epdto(page_gpa))}; - if (epdte->r == bsl::ZERO_UMAX) { - if (bsl::unlikely(!this->add_ept(epdte))) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - bsl::touch(); - } - else { - bsl::touch(); - } - - auto *const ept{this->get_ept(epdte)}; - auto *const epte{ept->entries.at_if(this->epto(page_gpa))}; - if (bsl::unlikely(epte->r != bsl::ZERO_UMAX)) { - bsl::error() << "guest physical address " // -- - << bsl::hex(page_gpa) // -- - << " already mapped" // -- - << bsl::endl // -- - << bsl::here(); // -- - - return bsl::errc_failure; - } - - epte->phys = (page_spa >> bsl::to_umx(HYPERVISOR_PAGE_SHIFT)).get(); - epte->r = bsl::ONE_UMAX.get(); - epte->type = page_type.get(); - - if (!(page_flags & MAP_PAGE_WRITE).is_zero()) { - epte->w = bsl::ONE_UMAX.get(); - } - else { - bsl::touch(); - } - - if (!(page_flags & MAP_PAGE_EXECUTE).is_zero()) { - epte->e = bsl::ONE_UMAX.get(); - } - else { - bsl::touch(); - } - - return bsl::errc_success; - } - - /// - /// @brief Maps a 2m page into the extended page tables being managed - /// by this class. - /// - /// - /// @param page_gpa the guest physical address to map the system - /// physical address to - /// @param page_spa the system physical address to map. - /// @param page_flags defines how memory should be mapped - /// @param page_type defines the memory type for the mapping - /// @return Returns bsl::errc_success on success, bsl::errc_failure - /// and friends otherwise - /// - [[nodiscard]] constexpr auto - map_2m_page( - bsl::safe_umx const &page_gpa, - bsl::safe_umx const &page_spa, - bsl::safe_umx const &page_flags, - bsl::safe_umx const &page_type) noexcept -> bsl::errc_type - { - lock_guard lock{m_ept_lock}; - - if (bsl::unlikely(!m_initialized)) { - bsl::error() << "extended_page_table_t not initialized\n" << bsl::here(); - return bsl::errc_failure; - } - - if (bsl::unlikely(!page_gpa)) { - bsl::error() << "guest physical address is invalid: " // -- - << bsl::hex(page_gpa) // -- - << bsl::endl // -- - << bsl::here(); // -- - - return bsl::errc_failure; - } - - if (bsl::unlikely(!this->is_page_aligned(page_gpa))) { - bsl::error() << "guest physical address is not page aligned: " // -- - << bsl::hex(page_gpa) // -- - << bsl::endl // -- - << bsl::here(); // -- - - return bsl::errc_failure; - } - - if (bsl::unlikely(!page_spa)) { - bsl::error() << "system physical address is invalid: " // -- - << bsl::hex(page_spa) // -- - << bsl::endl // -- - << bsl::here(); // -- - - return bsl::errc_failure; - } - - if (bsl::unlikely(!this->is_page_aligned(page_spa))) { - bsl::error() << "system physical address is not page aligned: " // -- - << bsl::hex(page_spa) // -- - << bsl::endl // -- - << bsl::here(); // -- - - return bsl::errc_failure; - } - - if (bsl::unlikely(!page_flags)) { - bsl::error() << "invalid flags: " // -- - << bsl::hex(page_flags) // -- - << bsl::endl // -- - << bsl::here(); // -- - - return bsl::errc_failure; - } - - if (bsl::unlikely(!page_type)) { - bsl::error() << "invalid type: " // -- - << bsl::hex(page_type) // -- - << bsl::endl // -- - << bsl::here(); // -- - - return bsl::errc_failure; - } - - auto *const epml4te{m_epml4t->entries.at_if(this->epml4to(page_gpa))}; - if (epml4te->r == bsl::ZERO_UMAX) { - if (bsl::unlikely(!this->add_epdpt(epml4te))) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - bsl::touch(); - } - else { - bsl::touch(); - } - - auto *const epdpt{this->get_epdpt(epml4te)}; - auto *const epdpte{epdpt->entries.at_if(this->epdpto(page_gpa))}; - if (epdpte->r == bsl::ZERO_UMAX) { - if (bsl::unlikely(!this->add_epdt(epdpte))) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - bsl::touch(); - } - else { - bsl::touch(); - } - - auto *const epdt{this->get_epdt(epdpte)}; - auto *const epdte{epdt->entries.at_if(this->epdto(page_gpa))}; - if (bsl::unlikely(epdte->r != bsl::ZERO_UMAX)) { - bsl::error() << "guest physical address " // -- - << bsl::hex(page_gpa) // -- - << " already mapped" // -- - << bsl::endl // -- - << bsl::here(); // -- - - return bsl::errc_failure; - } - - epdte->phys = (page_spa >> bsl::to_umx(HYPERVISOR_PAGE_SHIFT)).get(); - epdte->r = bsl::ONE_UMAX.get(); - epdte->type = page_type.get(); - epdte->ps = bsl::ONE_UMAX.get(); - - if (!(page_flags & MAP_PAGE_WRITE).is_zero()) { - epdte->w = bsl::ONE_UMAX.get(); - } - else { - bsl::touch(); - } - - if (!(page_flags & MAP_PAGE_EXECUTE).is_zero()) { - epdte->e = bsl::ONE_UMAX.get(); - } - else { - bsl::touch(); - } - - return bsl::errc_success; - } - }; -} - -#endif diff --git a/example/nested_paging/x64/map_page_flags.hpp b/example/nested_paging/x64/map_page_flags.hpp deleted file mode 100644 index c6c5606d..00000000 --- a/example/nested_paging/x64/map_page_flags.hpp +++ /dev/null @@ -1,48 +0,0 @@ -/// @copyright -/// Copyright (C) 2020 Assured Information Security, Inc. -/// -/// @copyright -/// Permission is hereby granted, free of charge, to any person obtaining a copy -/// of this software and associated documentation files (the "Software"), to deal -/// in the Software without restriction, including without limitation the rights -/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -/// copies of the Software, and to permit persons to whom the Software is -/// furnished to do so, subject to the following conditions: -/// -/// @copyright -/// The above copyright notice and this permission notice shall be included in -/// all copies or substantial portions of the Software. -/// -/// @copyright -/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -/// SOFTWARE. - -#ifndef MAP_PAGE_FLAGS_HPP -#define MAP_PAGE_FLAGS_HPP - -#include -#include - -namespace example -{ - /// @brief Map a page with read permmissions (has no effect) - constexpr bsl::safe_umx MAP_PAGE_READ{bsl::to_umx(0x0000000000000001U)}; - /// @brief Map a page with write permmissions - constexpr bsl::safe_umx MAP_PAGE_WRITE{bsl::to_umx(0x0000000000000002U)}; - /// @brief Map a page with execute permmissions - constexpr bsl::safe_umx MAP_PAGE_EXECUTE{bsl::to_umx(0x0000000000000004U)}; - - /// @brief Map a page with read/execute permmissions - constexpr bsl::safe_umx MAP_PAGE_RE{MAP_PAGE_READ | MAP_PAGE_EXECUTE}; - /// @brief Map a page with read/write permmissions - constexpr bsl::safe_umx MAP_PAGE_RW{MAP_PAGE_READ | MAP_PAGE_WRITE}; - /// @brief Map a page with read/write/execute permmissions - constexpr bsl::safe_umx MAP_PAGE_RWE{MAP_PAGE_READ | MAP_PAGE_WRITE | MAP_PAGE_EXECUTE}; -} - -#endif diff --git a/example/nested_paging/x64/memory_type.hpp b/example/nested_paging/x64/memory_type.hpp deleted file mode 100644 index e4d1c14a..00000000 --- a/example/nested_paging/x64/memory_type.hpp +++ /dev/null @@ -1,45 +0,0 @@ -/// @copyright -/// Copyright (C) 2020 Assured Information Security, Inc. -/// -/// @copyright -/// Permission is hereby granted, free of charge, to any person obtaining a copy -/// of this software and associated documentation files (the "Software"), to deal -/// in the Software without restriction, including without limitation the rights -/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -/// copies of the Software, and to permit persons to whom the Software is -/// furnished to do so, subject to the following conditions: -/// -/// @copyright -/// The above copyright notice and this permission notice shall be included in -/// all copies or substantial portions of the Software. -/// -/// @copyright -/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -/// SOFTWARE. - -#ifndef MEMORY_TYPE_HPP -#define MEMORY_TYPE_HPP - -#include -#include - -namespace example -{ - /// @brief defines the uncacheable memory type - constexpr bsl::safe_umx MEMORY_TYPE_UC{bsl::to_umx(0)}; - /// @brief defines the write-combine memory type - constexpr bsl::safe_umx MEMORY_TYPE_WC{bsl::to_umx(1)}; - /// @brief defines the write-through memory type - constexpr bsl::safe_umx MEMORY_TYPE_WT{bsl::to_umx(4)}; - /// @brief defines the write-protect memory type - constexpr bsl::safe_umx MEMORY_TYPE_WP{bsl::to_umx(5)}; - /// @brief defines the write-back memory type - constexpr bsl::safe_umx MEMORY_TYPE_WB{bsl::to_umx(6)}; -} - -#endif diff --git a/example/nested_paging/x64/mtrrs_t.hpp b/example/nested_paging/x64/mtrrs_t.hpp deleted file mode 100644 index 3a561240..00000000 --- a/example/nested_paging/x64/mtrrs_t.hpp +++ /dev/null @@ -1,1745 +0,0 @@ -/// @copyright -/// Copyright (C) 2020 Assured Information Security, Inc. -/// -/// @copyright -/// Permission is hereby granted, free of charge, to any person obtaining a copy -/// of this software and associated documentation files (the "Software"), to deal -/// in the Software without restriction, including without limitation the rights -/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -/// copies of the Software, and to permit persons to whom the Software is -/// furnished to do so, subject to the following conditions: -/// -/// @copyright -/// The above copyright notice and this permission notice shall be included in -/// all copies or substantial portions of the Software. -/// -/// @copyright -/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -/// SOFTWARE. - -#ifndef MTRRS_T_HPP -#define MTRRS_T_HPP - -#include "intrinsic_cpuid.hpp" -#include "memory_type.hpp" -#include "range_t.hpp" - -#include - -#include -#include -#include -#include -#include -#include -#include - -namespace example -{ - /// @brief defines the CPUID feature identifier bit for MTRR - constexpr bsl::safe_umx MAX_RANGES{bsl::to_umx(512)}; - - /// @brief defines the CPUID feature identifier index - constexpr bsl::safe_umx CPUID_FEATURE_IDENTIFIERS{bsl::to_umx(0x00000001U)}; - /// @brief defines the CPUID feature identifier bit for MTRR - constexpr bsl::safe_umx CPUID_FEATURE_IDENTIFIERS_MTRR{bsl::to_umx(0x00001000U)}; - - /// @brief defines the CPUID linear/physical address size index - constexpr bsl::safe_umx CPUID_LP_ADDRESS_SIZE{bsl::to_umx(0x80000008U)}; - /// @brief defines the CPUID linear/physical address size phys addr bits - constexpr bsl::safe_umx CPUID_LP_ADDRESS_SIZE_PHYS_ADDR_BITS{bsl::to_umx(0x000000FFU)}; - - /// @brief defines the MTRRcap MSR - constexpr bsl::safe_u32 MTRRCAP{bsl::to_u32(0x000000FEU)}; - /// @brief defines the MTRRcap MSR VCNT field - constexpr bsl::safe_umx MTRRCAP_VCNT{bsl::to_umx(0x00000000000000FFU)}; - /// @brief defines the MTRRcap MSR FIX field - constexpr bsl::safe_umx MTRRCAP_FIX{bsl::to_umx(0x0000000000000100U)}; - - /// @brief defines the MTRRdefType MSR - constexpr bsl::safe_u32 MTRRDEFTYPE{bsl::to_u32(0x000002FFU)}; - /// @brief defines the MTRRdefType MSR type field - constexpr bsl::safe_umx MTRRDEFTYPE_TYPE{bsl::to_umx(0x00000000000000FFU)}; - /// @brief defines the MTRRdefType MSR fixed range enable field - constexpr bsl::safe_umx MTRRDEFTYPE_FE{bsl::to_umx(0x0000000000000400U)}; - /// @brief defines the MTRRdefType MSR enable field - constexpr bsl::safe_umx MTRRDEFTYPE_E{bsl::to_umx(0x0000000000000800U)}; - - /// @brief defines the MTRRfix64K_00000 MSR - constexpr bsl::safe_u32 MTRRFIX64K_00000{bsl::to_u32(0x000000250U)}; - /// @brief defines the MTRRfix16K_80000 MSR - constexpr bsl::safe_u32 MTRRFIX16K_80000{bsl::to_u32(0x000000258U)}; - /// @brief defines the MTRRfix16K_A0000 MSR - constexpr bsl::safe_u32 MTRRFIX16K_A0000{bsl::to_u32(0x000000259U)}; - /// @brief defines the MTRRfix4K_C0000 MSR - constexpr bsl::safe_u32 MTRRFIX4K_C0000{bsl::to_u32(0x000000268U)}; - /// @brief defines the MTRRfix4K_C8000 MSR - constexpr bsl::safe_u32 MTRRFIX4K_C8000{bsl::to_u32(0x000000269U)}; - /// @brief defines the MTRRfix4K_D0000 MSR - constexpr bsl::safe_u32 MTRRFIX4K_D0000{bsl::to_u32(0x00000026AU)}; - /// @brief defines the MTRRfix4K_D8000 MSR - constexpr bsl::safe_u32 MTRRFIX4K_D8000{bsl::to_u32(0x00000026BU)}; - /// @brief defines the MTRRfix4K_E0000 MSR - constexpr bsl::safe_u32 MTRRFIX4K_E0000{bsl::to_u32(0x00000026CU)}; - /// @brief defines the MTRRfix4K_E8000 MSR - constexpr bsl::safe_u32 MTRRFIX4K_E8000{bsl::to_u32(0x00000026DU)}; - /// @brief defines the MTRRfix4K_F0000 MSR - constexpr bsl::safe_u32 MTRRFIX4K_F0000{bsl::to_u32(0x00000026EU)}; - /// @brief defines the MTRRfix4K_F8000 MSR - constexpr bsl::safe_u32 MTRRFIX4K_F8000{bsl::to_u32(0x00000026FU)}; - - /// @brief defines the memory type mask for fixed ranges - constexpr bsl::safe_umx MTRR_FIX_MASK{bsl::to_umx(0x00000000000000FFU)}; - /// @brief defines the memory type shift for fixed ranges - constexpr bsl::safe_umx MTRR_FIX_SHFT{bsl::to_umx(8)}; - /// @brief defines the total number of MTRRs per MSR for fixed ranges - constexpr bsl::safe_umx MTRR_FIX_MTRRS_PER_MSR{bsl::to_umx(8)}; - - /// @brief defines the address of MTRRFIX64K_00000 - constexpr bsl::safe_umx MTRRFIX64K_00000_ADDR{bsl::to_umx(0x0000000000000000U)}; - /// @brief defines the size of MTRRFIX64K_00000 - constexpr bsl::safe_umx MTRRFIX64K_00000_SIZE{bsl::to_umx(0x10000U)}; - /// @brief defines the address of MTRRFIX16K_80000 - constexpr bsl::safe_umx MTRRFIX16K_80000_ADDR{bsl::to_umx(0x0000000000080000U)}; - /// @brief defines the size of MTRRFIX16K_80000 - constexpr bsl::safe_umx MTRRFIX16K_80000_SIZE{bsl::to_umx(0x4000U)}; - /// @brief defines the address of MTRRFIX16K_A0000 - constexpr bsl::safe_umx MTRRFIX16K_A0000_ADDR{bsl::to_umx(0x00000000000A0000U)}; - /// @brief defines the size of MTRRFIX16K_A0000 - constexpr bsl::safe_umx MTRRFIX16K_A0000_SIZE{bsl::to_umx(0x4000U)}; - /// @brief defines the address of MTRRFIX4K_C0000 - constexpr bsl::safe_umx MTRRFIX4K_C0000_ADDR{bsl::to_umx(0x00000000000C0000U)}; - /// @brief defines the size of MTRRFIX4K_C0000 - constexpr bsl::safe_umx MTRRFIX4K_C0000_SIZE{bsl::to_umx(0x1000U)}; - /// @brief defines the address of MTRRFIX4K_C8000 - constexpr bsl::safe_umx MTRRFIX4K_C8000_ADDR{bsl::to_umx(0x00000000000C8000U)}; - /// @brief defines the size of MTRRFIX4K_C8000 - constexpr bsl::safe_umx MTRRFIX4K_C8000_SIZE{bsl::to_umx(0x1000U)}; - /// @brief defines the address of MTRRFIX4K_D0000 - constexpr bsl::safe_umx MTRRFIX4K_D0000_ADDR{bsl::to_umx(0x00000000000D0000U)}; - /// @brief defines the size of MTRRFIX4K_D0000 - constexpr bsl::safe_umx MTRRFIX4K_D0000_SIZE{bsl::to_umx(0x1000U)}; - /// @brief defines the address of MTRRFIX4K_D8000 - constexpr bsl::safe_umx MTRRFIX4K_D8000_ADDR{bsl::to_umx(0x00000000000D8000U)}; - /// @brief defines the size of MTRRFIX4K_D8000 - constexpr bsl::safe_umx MTRRFIX4K_D8000_SIZE{bsl::to_umx(0x1000U)}; - /// @brief defines the address of MTRRFIX4K_E0000 - constexpr bsl::safe_umx MTRRFIX4K_E0000_ADDR{bsl::to_umx(0x00000000000E0000U)}; - /// @brief defines the size of MTRRFIX4K_E0000 - constexpr bsl::safe_umx MTRRFIX4K_E0000_SIZE{bsl::to_umx(0x1000U)}; - /// @brief defines the address of MTRRFIX4K_E8000 - constexpr bsl::safe_umx MTRRFIX4K_E8000_ADDR{bsl::to_umx(0x00000000000E8000U)}; - /// @brief defines the size of MTRRFIX4K_E8000 - constexpr bsl::safe_umx MTRRFIX4K_E8000_SIZE{bsl::to_umx(0x1000U)}; - /// @brief defines the address of MTRRFIX4K_F0000 - constexpr bsl::safe_umx MTRRFIX4K_F0000_ADDR{bsl::to_umx(0x00000000000F0000U)}; - /// @brief defines the size of MTRRFIX4K_F0000 - constexpr bsl::safe_umx MTRRFIX4K_F0000_SIZE{bsl::to_umx(0x1000U)}; - /// @brief defines the address of MTRRFIX4K_F8000 - constexpr bsl::safe_umx MTRRFIX4K_F8000_ADDR{bsl::to_umx(0x00000000000F8000U)}; - /// @brief defines the size of MTRRFIX4K_F8000 - constexpr bsl::safe_umx MTRRFIX4K_F8000_SIZE{bsl::to_umx(0x1000U)}; - - /// @brief defines the MTRRphysBase MSR - constexpr bsl::safe_u32 MTRRPHYSBASE{bsl::to_u32(0x000000200U)}; - /// @brief defines the MTRRphysMask MSR - constexpr bsl::safe_u32 MTRRPHYSMASK{bsl::to_u32(0x000000201U)}; - - /// - /// @brief Implements the sort function that we use for a range_t - /// - /// - /// @param a the first element to compare - /// @param b the second element to compare - /// @return Returns true if a is less b, false otherwise - /// - [[nodiscard]] constexpr auto - range_t_sort_cmp(range_t const &a, range_t const &b) noexcept -> bool - { - if (!a.addr) { - return false; - } - - if (!b.addr) { - return true; - } - - return a.addr < b.addr; - }; - - /// - /// @brief Parses the MTRRs and provides a continuous, non-overlapping - /// view of the ranges as needed. - /// - class mtrrs_t final - { - /// @brief stores the ranges associated with this mtrrs_t - bsl::array m_ranges{}; - /// @brief stores the number of ranges in the list. - bsl::safe_umx m_ranges_count{}; - - /// - /// @brief Returns true if the provided address is 4k page aligned - /// - /// - /// @param addr the address to query - /// @return Returns true if the provided address is 4k page aligned - /// - [[nodiscard]] static constexpr auto - is_page_4k_aligned(bsl::safe_umx const &addr) noexcept -> bool - { - constexpr bsl::safe_u64 mask_4k{bsl::to_umx(0xFFFU)}; - return (addr & mask_4k) == bsl::ZERO_UMAX; - } - - /// - /// @brief Returns true if the provided address is 2m page aligned - /// - /// - /// @param addr the address to query - /// @return Returns true if the provided address is 2m page aligned - /// - [[nodiscard]] static constexpr auto - is_page_2m_aligned(bsl::safe_umx const &addr) noexcept -> bool - { - constexpr bsl::safe_u64 mask_2m{bsl::to_umx(0x1FFFFFU)}; - return (addr & mask_2m) == bsl::ZERO_UMAX; - } - /// - /// @brief Returns the combination of two memory type based on the - /// memory combining rules defined in the AMD/Intel manuals. - /// - /// - /// @param r1 the first range to combine - /// @param r2 the second range to combine - /// @return Returns the combination of two memory type based on the - /// memory combining rules defined in the AMD/Intel manuals. - /// - [[nodiscard]] static constexpr auto - combine(range_t const &r1, range_t const &r2) noexcept -> bsl::safe_umx - { - if (r1.dflt) { - return r2.type; - } - - if (r2.dflt) { - return r1.type; - } - - /// NOTE: - /// - "a. If the memory types are identical, then that memory type - /// is used." - /// - - if (r1.type == r2.type) { - return r1.type; - } - - /// NOTE: - /// - "b. If at least one of the memory types is UC, the UC memory - /// type is used." - /// - - if (r1.type == MEMORY_TYPE_UC) { - return MEMORY_TYPE_UC; - } - - if (r2.type == MEMORY_TYPE_UC) { - return MEMORY_TYPE_UC; - } - - /// NOTE: - /// - "c. If at least one of the memory types is WT, and the only - /// other memory type is WB, then the WT memory type is used" - /// - - if (r1.type == MEMORY_TYPE_WT) { - if (r2.type == MEMORY_TYPE_WB) { - return MEMORY_TYPE_WT; - } - - bsl::touch(); - } - else { - bsl::touch(); - } - - if (r2.type == MEMORY_TYPE_WT) { - if (r1.type == MEMORY_TYPE_WB) { - return MEMORY_TYPE_WT; - } - - bsl::touch(); - } - else { - bsl::touch(); - } - - /// NOTE: - /// - "d. If the combination of memory types is not listed Steps A - /// through C immediately above, then the memory type used is - /// undefined" - /// - - return MEMORY_TYPE_UC; - } - - /// - /// @brief Adds a range to the list. This version of the function - /// does not attempt to clean up the ranges in the list. It - /// simply adds the range to the list and moves on. - /// - /// - /// @param r the range to add - /// @return Returns bsl::errc_success on success and bsl::errc_failure - /// on failure. - /// - [[nodiscard]] constexpr auto - add_range(range_t const &r) noexcept -> bsl::errc_type - { - auto *const ptr{m_ranges.at_if(m_ranges_count)}; - if (bsl::unlikely(nullptr == ptr)) { - bsl::error() << "mtrrs_t full\n" << bsl::here(); - return bsl::errc_failure; - } - - *ptr = r; - ++m_ranges_count; - - return bsl::errc_success; - } - - /// - /// @brief Adds a range to the list. If the range that is being added - /// is a subset of any other range, or a range is a subset of the - /// range being added, the subsets are split. Any intersecting - /// ranges that are not subsets will cause this function to fail - /// as they are not supported by this algorithm. - /// - /// - /// @param addr the address of the range - /// @param size the size of the range - /// @param type the type of memory in the range - /// type for all of memory, false otherwise - /// @return Returns bsl::errc_success on success and bsl::errc_failure - /// on failure. - /// - [[nodiscard]] constexpr auto - add_range( - bsl::safe_umx const &addr, - bsl::safe_umx const &size, - bsl::safe_umx const &type) noexcept -> bsl::errc_type - { - bsl::errc_type ret{}; - range_t r1{addr, size, type, false}; - - if (bsl::unlikely(!this->is_page_4k_aligned(addr))) { - bsl::error() << "addr is not 4k page aligned: " // -- - << bsl::hex(addr) // -- - << bsl::endl // -- - << bsl::here(); // -- - - return bsl::errc_failure; - } - - if (bsl::unlikely(!this->is_page_4k_aligned(size))) { - bsl::error() << "size is not 4k page aligned: " // -- - << bsl::hex(size) // -- - << bsl::endl // -- - << bsl::here(); // -- - - return bsl::errc_failure; - } - - for (bsl::safe_idx i{}; i < m_ranges_count; ++i) { - auto *const r2{m_ranges.at_if(i)}; - - auto const r1_l{r1.addr}; - auto const r1_r{r1.addr + r1.size}; - auto const r2_l{r2->addr}; - auto const r2_r{r2->addr + r2->size}; - - /// NOTE: - /// - If the range has a size of 0, there is no range to add - /// and we can stop. This could either happen because we - /// were given a 0 sized range to start, or the range we - /// were overlaps multiple ranges, in which case we have to - /// slowly remove from the provided range until it is 0, and - /// this will stop the loop when it is done. - /// - - if (r1.size.is_zero()) { - break; - } - - /// NOTE: - /// - We need to scan the ranges until we find the first - /// range in the list that the provided range actually - /// intersects. For example: - /// - /// ---------------------------------------- - /// | | | +++++ | - /// | | | + 1 + 2 | - /// | | | +++++ | - /// ---------------------------------------- - /// - /// Until the left side of r1 is greater than or equal to - /// the left side of r2, we can keep scanning because r1 - /// and r2 do not intersect. Note that, you might be - /// thinking about, what if r1's right side overlaps into - /// r2. In this case, it would mean that r1's left side is - /// greater than or equal to the range to the left, which - /// means we have found a match. In other words, we only - /// have to pay attention to the left side, because if - /// the right side is an issue, the left side must also - /// be an issue with the adjacent range, which is really the - /// r2 we should be concerned with. - /// - /// - It should be noted that the above assumes that the - /// entire physical address range is represented by a range. - /// Meaning, there are not wholes. To ensure this, we the - /// first thing we do is fill the range list with the - /// default range that goes from 0 to MAX. From there, this - /// algorithm will perform it's work to add the range, and - /// then sort the list to ensure the list of ranges continues - /// to completely cover the entire physical address range. - /// - - if (!(r1_l < r2_r)) { - continue; - } - - /// NOTE: - /// - Ok, if we got this far, it means that we have found a - /// range that intersects. Now, we need to handle the - /// different types of scenarios that might occur. - /// - - if (r1_l == r2_l) { - - /// Case #1: - /// - In this case, r1's left side is the same as r2's left - /// side, meaning they are touching. When this happens, - /// we need to divide r2 into two ranges. - /// - /// -------------------- - /// | 2 | - /// |+++++ | - /// |+ 1 + | - /// |+++++ | - /// | | - /// -------------------- - /// - /// or - /// - /// -------------------- - /// | 2 | - /// |++++++++++++++++++++++ - /// |+ 1 + - /// |++++++++++++++++++++++ - /// | | - /// -------------------- - /// - - if (r1_r < r2_r) { - auto const new_r1_addr{r1.addr}; - auto const new_r1_size{r1.size}; - auto const new_r1_type{this->combine(r1, *r2)}; - bool const new_r1_dflt{false}; - - ret = this->add_range({new_r1_addr, new_r1_size, new_r1_type, new_r1_dflt}); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - auto const new_r2_addr{r1_r}; - auto const new_r2_size{r2_r - r1_r}; - auto const new_r2_type{r2->type}; - bool const new_r2_dflt{r2->dflt}; - - ret = this->add_range({new_r2_addr, new_r2_size, new_r2_type, new_r2_dflt}); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - r1.addr = bsl::ZERO_UMAX; - r1.size = bsl::ZERO_UMAX; - } - else { - auto const new_r1_addr{r1.addr}; - auto const new_r1_size{r2->size}; - auto const new_r1_type{this->combine(r1, *r2)}; - bool const new_r1_dflt{false}; - - ret = this->add_range({new_r1_addr, new_r1_size, new_r1_type, new_r1_dflt}); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - r1.addr = r2_r; - r1.size = r1_r - r2_r; - } - - r2->addr = bsl::safe_umx::failure(); - r2->size = bsl::safe_umx::failure(); - r2->type = bsl::safe_umx::failure(); - r2->dflt = false; - --m_ranges_count; - - bsl::sort(m_ranges, &range_t_sort_cmp); - } - else { - /// Case #2: - /// - In this case, r1 is inside r1, meaning their left - /// sides are not touching. This will force us to add - /// 2 or 3 ranges depending on the right side of r1. - /// - /// -------------------- - /// | 2 | - /// | +++++ | - /// | + 1 + | - /// | +++++ | - /// | | - /// -------------------- - /// - /// or - /// - /// -------------------- - /// | 2 | - /// | +++++++++++++++++++ - /// | + 1 + - /// | +++++++++++++++++++ - /// | | - /// -------------------- - /// - - if (r1_r < r2_r) { - auto const new_r1_addr{r2->addr}; - auto const new_r1_size{r1_l - r2_l}; - auto const new_r1_type{r2->type}; - bool const new_r1_dflt{r2->dflt}; - - ret = this->add_range({new_r1_addr, new_r1_size, new_r1_type, new_r1_dflt}); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - auto const new_r2_addr{r1.addr}; - auto const new_r2_size{r1.size}; - auto const new_r2_type{this->combine(r1, *r2)}; - bool const new_r2_dflt{false}; - - ret = this->add_range({new_r2_addr, new_r2_size, new_r2_type, new_r2_dflt}); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - auto const new_r3_addr{r1_r}; - auto const new_r3_size{r2_r - r1_r}; - auto const new_r3_type{r2->type}; - bool const new_r3_dflt{r2->dflt}; - - ret = this->add_range({new_r3_addr, new_r3_size, new_r3_type, new_r3_dflt}); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - r1.addr = bsl::ZERO_UMAX; - r1.size = bsl::ZERO_UMAX; - } - else { - auto const new_r1_addr{r2->addr}; - auto const new_r1_size{r1_l - r2_l}; - auto const new_r1_type{r2->type}; - bool const new_r1_dflt{r2->dflt}; - - ret = this->add_range({new_r1_addr, new_r1_size, new_r1_type, new_r1_dflt}); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - auto const new_r2_addr{r1.addr}; - auto const new_r2_size{r2_r - r1_l}; - auto const new_r2_type{this->combine(r1, *r2)}; - bool const new_r2_dflt{false}; - - ret = this->add_range({new_r2_addr, new_r2_size, new_r2_type, new_r2_dflt}); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - r1.addr = r2_r; - r1.size = r1_r - r2_r; - } - - r2->addr = bsl::safe_umx::failure(); - r2->size = bsl::safe_umx::failure(); - r2->type = bsl::safe_umx::failure(); - r2->dflt = false; - --m_ranges_count; - - bsl::sort(m_ranges, &range_t_sort_cmp); - } - } - - return bsl::errc_success; - } - - /// - /// @brief Once all of the ranges have been added, we can compress - /// the range list to reduce the overall size of the list. - /// Compression is simple. If two adjacent ranges have the same - /// type, we can combine them into a single range. Basically this - /// means we need to modify one range to be bigger and remove - /// the other range. Continue this process until we have scanned - /// the entire range list. - /// - /// - /// - constexpr void - compress_ranges() noexcept - { - bsl::safe_umx i{bsl::ONE_UMAX}; - - if (m_ranges.size() == bsl::ONE_UMAX) { - return; - } - - while (i < m_ranges_count) { - auto *const r1{m_ranges.at_if(i - bsl::ONE_UMAX)}; - auto *const r2{m_ranges.at_if(i)}; - - if (r1->type == r2->type) { - r1->size += r2->size; - - r2->addr = bsl::safe_umx::failure(); - r2->size = bsl::safe_umx::failure(); - r2->type = bsl::safe_umx::failure(); - r2->dflt = false; - --m_ranges_count; - - bsl::sort(m_ranges, &range_t_sort_cmp); - } - else { - ++i; - } - } - } - - /// - /// @brief Adds the 64k Fixed Range MTRRs starting at 0x00000. - /// - /// - /// @param handle the handle to use - /// @return Returns bsl::errc_success on success and bsl::errc_failure - /// on failure. - /// - [[nodiscard]] constexpr auto - add_mtrr_fix64k_00000(syscall::bf_handle_t &handle) noexcept -> bsl::errc_type - { - bsl::errc_type ret{}; - bsl::safe_umx mtrr{}; - bsl::safe_umx shft{}; - - ret = syscall::bf_intrinsic_op_rdmsr(handle, MTRRFIX64K_00000, mtrr); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - for (bsl::safe_idx i{}; i < MTRR_FIX_MTRRS_PER_MSR; ++i) { - auto const size{MTRRFIX64K_00000_SIZE}; - auto const addr{MTRRFIX64K_00000_ADDR + (size * i)}; - auto const mask{MTRR_FIX_MASK << shft}; - auto const type{(mtrr & mask) >> shft}; - - ret = this->add_range(addr, size, type); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - shft += MTRR_FIX_SHFT; - } - - return bsl::errc_success; - } - - /// - /// @brief Adds the 16k Fixed Range MTRRs starting at 0x80000. - /// - /// - /// @param handle the handle to use - /// @return Returns bsl::errc_success on success and bsl::errc_failure - /// on failure. - /// - [[nodiscard]] constexpr auto - add_mtrr_fix16k_80000(syscall::bf_handle_t &handle) noexcept -> bsl::errc_type - { - bsl::errc_type ret{}; - bsl::safe_umx mtrr{}; - bsl::safe_umx shft{}; - - ret = syscall::bf_intrinsic_op_rdmsr(handle, MTRRFIX16K_80000, mtrr); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - for (bsl::safe_idx i{}; i < MTRR_FIX_MTRRS_PER_MSR; ++i) { - auto const size{MTRRFIX16K_80000_SIZE}; - auto const addr{MTRRFIX16K_80000_ADDR + (size * i)}; - auto const mask{MTRR_FIX_MASK << shft}; - auto const type{(mtrr & mask) >> shft}; - - ret = this->add_range(addr, size, type); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - shft += MTRR_FIX_SHFT; - } - - return bsl::errc_success; - } - - /// - /// @brief Adds the 16k Fixed Range MTRRs starting at 0xA0000. - /// - /// - /// @param handle the handle to use - /// @return Returns bsl::errc_success on success and bsl::errc_failure - /// on failure. - /// - [[nodiscard]] constexpr auto - add_mtrr_fix16k_a0000(syscall::bf_handle_t &handle) noexcept -> bsl::errc_type - { - bsl::errc_type ret{}; - bsl::safe_umx mtrr{}; - bsl::safe_umx shft{}; - - ret = syscall::bf_intrinsic_op_rdmsr(handle, MTRRFIX16K_A0000, mtrr); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - for (bsl::safe_idx i{}; i < MTRR_FIX_MTRRS_PER_MSR; ++i) { - auto const size{MTRRFIX16K_A0000_SIZE}; - auto const addr{MTRRFIX16K_A0000_ADDR + (size * i)}; - auto const mask{MTRR_FIX_MASK << shft}; - auto const type{(mtrr & mask) >> shft}; - - ret = this->add_range(addr, size, type); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - shft += MTRR_FIX_SHFT; - } - - return bsl::errc_success; - } - - /// - /// @brief Adds the 4k Fixed Range MTRRs starting at 0xC0000. - /// - /// - /// @param handle the handle to use - /// @return Returns bsl::errc_success on success and bsl::errc_failure - /// on failure. - /// - [[nodiscard]] constexpr auto - add_mtrr_fix4k_c0000(syscall::bf_handle_t &handle) noexcept -> bsl::errc_type - { - bsl::errc_type ret{}; - bsl::safe_umx mtrr{}; - bsl::safe_umx shft{}; - - ret = syscall::bf_intrinsic_op_rdmsr(handle, MTRRFIX4K_C0000, mtrr); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - for (bsl::safe_idx i{}; i < MTRR_FIX_MTRRS_PER_MSR; ++i) { - auto const size{MTRRFIX4K_C0000_SIZE}; - auto const addr{MTRRFIX4K_C0000_ADDR + (size * i)}; - auto const mask{MTRR_FIX_MASK << shft}; - auto const type{(mtrr & mask) >> shft}; - - ret = this->add_range(addr, size, type); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - shft += MTRR_FIX_SHFT; - } - - return bsl::errc_success; - } - - /// - /// @brief Adds the 4k Fixed Range MTRRs starting at 0xC8000. - /// - /// - /// @param handle the handle to use - /// @return Returns bsl::errc_success on success and bsl::errc_failure - /// on failure. - /// - [[nodiscard]] constexpr auto - add_mtrr_fix4k_c8000(syscall::bf_handle_t &handle) noexcept -> bsl::errc_type - { - bsl::errc_type ret{}; - bsl::safe_umx mtrr{}; - bsl::safe_umx shft{}; - - ret = syscall::bf_intrinsic_op_rdmsr(handle, MTRRFIX4K_C8000, mtrr); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - for (bsl::safe_idx i{}; i < MTRR_FIX_MTRRS_PER_MSR; ++i) { - auto const size{MTRRFIX4K_C8000_SIZE}; - auto const addr{MTRRFIX4K_C8000_ADDR + (size * i)}; - auto const mask{MTRR_FIX_MASK << shft}; - auto const type{(mtrr & mask) >> shft}; - - ret = this->add_range(addr, size, type); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - shft += MTRR_FIX_SHFT; - } - - return bsl::errc_success; - } - - /// - /// @brief Adds the 4k Fixed Range MTRRs starting at 0xD0000. - /// - /// - /// @param handle the handle to use - /// @return Returns bsl::errc_success on success and bsl::errc_failure - /// on failure. - /// - [[nodiscard]] constexpr auto - add_mtrr_fix4k_d0000(syscall::bf_handle_t &handle) noexcept -> bsl::errc_type - { - bsl::errc_type ret{}; - bsl::safe_umx mtrr{}; - bsl::safe_umx shft{}; - - ret = syscall::bf_intrinsic_op_rdmsr(handle, MTRRFIX4K_D0000, mtrr); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - for (bsl::safe_idx i{}; i < MTRR_FIX_MTRRS_PER_MSR; ++i) { - auto const size{MTRRFIX4K_D0000_SIZE}; - auto const addr{MTRRFIX4K_D0000_ADDR + (size * i)}; - auto const mask{MTRR_FIX_MASK << shft}; - auto const type{(mtrr & mask) >> shft}; - - ret = this->add_range(addr, size, type); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - shft += MTRR_FIX_SHFT; - } - - return bsl::errc_success; - } - - /// - /// @brief Adds the 4k Fixed Range MTRRs starting at 0xD8000. - /// - /// - /// @param handle the handle to use - /// @return Returns bsl::errc_success on success and bsl::errc_failure - /// on failure. - /// - [[nodiscard]] constexpr auto - add_mtrr_fix4k_d8000(syscall::bf_handle_t &handle) noexcept -> bsl::errc_type - { - bsl::errc_type ret{}; - bsl::safe_umx mtrr{}; - bsl::safe_umx shft{}; - - ret = syscall::bf_intrinsic_op_rdmsr(handle, MTRRFIX4K_D8000, mtrr); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - for (bsl::safe_idx i{}; i < MTRR_FIX_MTRRS_PER_MSR; ++i) { - auto const size{MTRRFIX4K_D8000_SIZE}; - auto const addr{MTRRFIX4K_D8000_ADDR + (size * i)}; - auto const mask{MTRR_FIX_MASK << shft}; - auto const type{(mtrr & mask) >> shft}; - - ret = this->add_range(addr, size, type); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - shft += MTRR_FIX_SHFT; - } - - return bsl::errc_success; - } - - /// - /// @brief Adds the 4k Fixed Range MTRRs starting at 0xE0000. - /// - /// - /// @param handle the handle to use - /// @return Returns bsl::errc_success on success and bsl::errc_failure - /// on failure. - /// - [[nodiscard]] constexpr auto - add_mtrr_fix4k_e0000(syscall::bf_handle_t &handle) noexcept -> bsl::errc_type - { - bsl::errc_type ret{}; - bsl::safe_umx mtrr{}; - bsl::safe_umx shft{}; - - ret = syscall::bf_intrinsic_op_rdmsr(handle, MTRRFIX4K_E0000, mtrr); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - for (bsl::safe_idx i{}; i < MTRR_FIX_MTRRS_PER_MSR; ++i) { - auto const size{MTRRFIX4K_E0000_SIZE}; - auto const addr{MTRRFIX4K_E0000_ADDR + (size * i)}; - auto const mask{MTRR_FIX_MASK << shft}; - auto const type{(mtrr & mask) >> shft}; - - ret = this->add_range(addr, size, type); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - shft += MTRR_FIX_SHFT; - } - - return bsl::errc_success; - } - - /// - /// @brief Adds the 4k Fixed Range MTRRs starting at 0xE8000. - /// - /// - /// @param handle the handle to use - /// @return Returns bsl::errc_success on success and bsl::errc_failure - /// on failure. - /// - [[nodiscard]] constexpr auto - add_mtrr_fix4k_e8000(syscall::bf_handle_t &handle) noexcept -> bsl::errc_type - { - bsl::errc_type ret{}; - bsl::safe_umx mtrr{}; - bsl::safe_umx shft{}; - - ret = syscall::bf_intrinsic_op_rdmsr(handle, MTRRFIX4K_E8000, mtrr); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - for (bsl::safe_idx i{}; i < MTRR_FIX_MTRRS_PER_MSR; ++i) { - auto const size{MTRRFIX4K_E8000_SIZE}; - auto const addr{MTRRFIX4K_E8000_ADDR + (size * i)}; - auto const mask{MTRR_FIX_MASK << shft}; - auto const type{(mtrr & mask) >> shft}; - - ret = this->add_range(addr, size, type); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - shft += MTRR_FIX_SHFT; - } - - return bsl::errc_success; - } - - /// - /// @brief Adds the 4k Fixed Range MTRRs starting at 0xF0000. - /// - /// - /// @param handle the handle to use - /// @return Returns bsl::errc_success on success and bsl::errc_failure - /// on failure. - /// - [[nodiscard]] constexpr auto - add_mtrr_fix4k_f0000(syscall::bf_handle_t &handle) noexcept -> bsl::errc_type - { - bsl::errc_type ret{}; - bsl::safe_umx mtrr{}; - bsl::safe_umx shft{}; - - ret = syscall::bf_intrinsic_op_rdmsr(handle, MTRRFIX4K_F0000, mtrr); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - for (bsl::safe_idx i{}; i < MTRR_FIX_MTRRS_PER_MSR; ++i) { - auto const size{MTRRFIX4K_F0000_SIZE}; - auto const addr{MTRRFIX4K_F0000_ADDR + (size * i)}; - auto const mask{MTRR_FIX_MASK << shft}; - auto const type{(mtrr & mask) >> shft}; - - ret = this->add_range(addr, size, type); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - shft += MTRR_FIX_SHFT; - } - - return bsl::errc_success; - } - - /// - /// @brief Adds the 4k Fixed Range MTRRs starting at 0xF8000. - /// - /// - /// @param handle the handle to use - /// @return Returns bsl::errc_success on success and bsl::errc_failure - /// on failure. - /// - [[nodiscard]] constexpr auto - add_mtrr_fix4k_f8000(syscall::bf_handle_t &handle) noexcept -> bsl::errc_type - { - bsl::errc_type ret{}; - bsl::safe_umx mtrr{}; - bsl::safe_umx shft{}; - - ret = syscall::bf_intrinsic_op_rdmsr(handle, MTRRFIX4K_F8000, mtrr); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - for (bsl::safe_idx i{}; i < MTRR_FIX_MTRRS_PER_MSR; ++i) { - auto const size{MTRRFIX4K_F8000_SIZE}; - auto const addr{MTRRFIX4K_F8000_ADDR + (size * i)}; - auto const mask{MTRR_FIX_MASK << shft}; - auto const type{(mtrr & mask) >> shft}; - - ret = this->add_range(addr, size, type); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - shft += MTRR_FIX_SHFT; - } - - return bsl::errc_success; - } - - /// - /// @brief Returns the base address portion of physbase - /// - /// - /// @param physbase the physbase to convert - /// @return Returns the base address portion of physbase - /// - [[nodiscard]] static constexpr auto - physbase_to_addr(bsl::safe_umx const &physbase) noexcept -> bsl::safe_umx - { - constexpr bsl::safe_umx mask{bsl::to_umx(0xFFFFFFFFFFFFF000U)}; - return physbase & mask; - } - - /// - /// @brief Returns the size portion of physmask using the conversion - /// logic defined in the manual. - /// - /// - /// @param physmask the physmask to convert - /// @param pas the physical address size - /// @return Returns the size portion of physmask using the conversion - /// logic defined in the manual. - /// - [[nodiscard]] static constexpr auto - physmask_to_size( // -- - bsl::safe_umx const &physmask, // -- - bsl::safe_umx const &pas) noexcept -> bsl::safe_umx - { - constexpr bsl::safe_umx mask{bsl::to_umx(0xFFFFFFFFFFFFF000U)}; - return (~(physmask & mask) & ((bsl::ONE_UMAX << pas) - bsl::ONE_UMAX)) + bsl::ONE_UMAX; - } - - /// - /// @brief Returns the memory type portion of physbase - /// - /// - /// @param physbase the physbase to convert - /// @return Returns the memory type portion of physbase - /// - [[nodiscard]] static constexpr auto - physbase_to_type(bsl::safe_umx const &physbase) noexcept -> bsl::safe_umx - { - constexpr bsl::safe_umx mask{bsl::to_umx(0x00000000000000FFU)}; - return physbase & mask; - } - - /// - /// @brief Returns true if the valid bit is set in physmask, - /// false otherwise. - /// - /// - /// @param physmask the physmask to query - /// @return Returns true if the valid bit is set in physmask, - /// false otherwise. - /// - [[nodiscard]] static constexpr auto - physmask_to_valid(bsl::safe_umx const &physmask) noexcept -> bool - { - constexpr bsl::safe_umx mask{bsl::to_umx(0x0000000000000800U)}; - return (physmask & mask).is_pos(); - } - - /// - /// @brief Parses all of the variable range MTRRs and adds them - /// to the list. - /// - /// - /// @param handle the handle to use - /// @param vcnt the total number of supported variable range MTRRs - /// @param pas the physical address size - /// @return Returns bsl::errc_success on success and bsl::errc_failure - /// on failure. - /// - [[nodiscard]] constexpr auto - add_variable_range( - syscall::bf_handle_t &handle, - bsl::safe_u32 const &vcnt, - bsl::safe_umx const &pas) noexcept -> bsl::errc_type - { - bsl::errc_type ret{}; - bsl::safe_umx physbase{}; - bsl::safe_umx physmask{}; - - constexpr auto msrs_per_iteration{bsl::to_u32(2)}; - for (bsl::safe_idx i{}; i < (vcnt * msrs_per_iteration); i += msrs_per_iteration) { - auto mtrrphysbasen{MTRRPHYSBASE + i}; - auto mtrrphysmaskn{MTRRPHYSMASK + i}; - - ret = syscall::bf_intrinsic_op_rdmsr(handle, mtrrphysmaskn, physmask); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - if (!this->physmask_to_valid(physmask)) { - continue; - } - - ret = syscall::bf_intrinsic_op_rdmsr(handle, mtrrphysbasen, physbase); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - auto const addr{this->physbase_to_addr(physbase)}; - auto const size{this->physmask_to_size(physmask, pas)}; - auto const type{this->physbase_to_type(physbase)}; - - ret = this->add_range(addr, size, type); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - bsl::touch(); - } - - return bsl::errc_success; - } - - public: - /// - /// @brief Parses the MTRRs and stores the ranges in a continuous - /// non-overlapping form. This ensures that every single physical - /// address can be looked up by this class and provide the MTRR's - /// opinion as to what the memory's type is. - /// - /// - /// @param handle the handle to use - /// @return Returns bsl::errc_success on success and bsl::errc_failure - /// on failure. - /// - [[nodiscard]] constexpr auto - parse(syscall::bf_handle_t &handle) noexcept -> bsl::errc_type - { - bsl::errc_type ret{}; - - bsl::safe_umx rax{}; - bsl::safe_umx rbx{}; - bsl::safe_umx rcx{}; - bsl::safe_umx rdx{}; - - /// NOTE: - /// - Before we start, we need to ensure that the ranges are - /// cleared and an invalid state. This will ensure that during - /// the sorting process, ranges that are not used are ordered - /// last in the list. - /// - - for (auto &mut_range : m_ranges) { - mut_range = { - bsl::safe_umx::failure(), - bsl::safe_umx::failure(), - bsl::safe_umx::failure(), - false}; - } - - m_ranges_count = {}; - - /// NOTE: - /// - The first step is to get the total number of physical address - /// bits the hardware supports. This is needed to convert - /// the variable range registers. - /// - - rax = CPUID_LP_ADDRESS_SIZE; - rcx = {}; - intrinsic_cpuid(rax.data(), rbx.data(), rcx.data(), rdx.data()); - - auto const pas{rax & CPUID_LP_ADDRESS_SIZE_PHYS_ADDR_BITS}; - auto const pas_bytes{bsl::ONE_UMAX << pas}; - - /// NOTE: - /// - The next step is to make sure that MTRRs are supported. - /// If they aren't something really weird is going on, but in - /// general, that is ok as all we have to do is add a single - /// range that marks all of memory as WB. - /// - - rax = CPUID_FEATURE_IDENTIFIERS; - rcx = {}; - intrinsic_cpuid(rax.data(), rbx.data(), rcx.data(), rdx.data()); - - if ((rdx & CPUID_FEATURE_IDENTIFIERS_MTRR).is_zero()) { - ret = this->add_range({bsl::ZERO_UMAX, pas_bytes, MEMORY_TYPE_WB, false}); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - return bsl::errc_success; - } - - /// NOTE: - /// - The next step is to get the MTRR information from the MSRs. - /// We have to ask the kernel for this information. - /// - - bsl::safe_umx cap{}; - bsl::safe_umx deftype{}; - - ret = syscall::bf_intrinsic_op_rdmsr(handle, MTRRCAP, cap); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - ret = syscall::bf_intrinsic_op_rdmsr(handle, MTRRDEFTYPE, deftype); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - auto const cap_vcnt{bsl::to_u32(cap & MTRRCAP_VCNT)}; - auto const cap_fix{bsl::to_u32(cap & MTRRCAP_FIX)}; - - auto const deftype_type{deftype & MTRRDEFTYPE_TYPE}; - auto const deftype_fe{deftype & MTRRDEFTYPE_FE}; - auto const deftype_e{deftype & MTRRDEFTYPE_E}; - - /// NOTE: - /// - If the MTRRs are disabled, the default memory type is - /// uncacheable. - /// - - if (deftype_e.is_zero()) { - ret = this->add_range({bsl::ZERO_UMAX, pas_bytes, MEMORY_TYPE_UC, false}); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - return bsl::errc_success; - } - - /// NOTE: - /// - Next we need to add the default range to the list. This sets - /// all of memory to this memory type. All calls to add_range() - /// after this will split this default type up for each memory - /// type defined by BIOS. This ensures that when we are done, - /// every physical memory address has a type defined for it. - /// - It should be noted that the add_range() algorithm expects - /// that this initial range is added for it work properly. - /// - - ret = this->add_range({bsl::ZERO_UMAX, pas_bytes, deftype_type, true}); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - /// NOTE: - /// - Next, let's add the fixed range MTRRs. - /// - - if (cap_fix.is_pos()) { - if (deftype_fe.is_pos()) { - ret = this->add_mtrr_fix64k_00000(handle); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - ret = this->add_mtrr_fix16k_80000(handle); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - ret = this->add_mtrr_fix16k_a0000(handle); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - ret = this->add_mtrr_fix4k_c0000(handle); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - ret = this->add_mtrr_fix4k_c8000(handle); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - ret = this->add_mtrr_fix4k_d0000(handle); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - ret = this->add_mtrr_fix4k_d8000(handle); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - ret = this->add_mtrr_fix4k_e0000(handle); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - ret = this->add_mtrr_fix4k_e8000(handle); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - ret = this->add_mtrr_fix4k_f0000(handle); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - ret = this->add_mtrr_fix4k_f8000(handle); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - bsl::touch(); - } - else { - bsl::touch(); - } - } - else { - bsl::touch(); - } - - ret = this->add_variable_range(handle, cap_vcnt, pas); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - this->compress_ranges(); - - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return bsl::errc_failure; - } - - return bsl::errc_success; - } - - /// - /// @brief Creates an identity map in the provided map using the - /// memory types contained in the MTRRs. The resulting identity - /// map will mimic the MTRRs given the range provided - /// - /// - /// @tparam MAP_T the type of map to use - /// @param map the map to create the identity map in - /// @param gpa the starting guest physical address - /// @param size the number of bytes from the provided gpa to map - /// @param flags the read/write/execute flags to use - /// @return Returns bsl::errc_success on success and bsl::errc_failure - /// on failure. - /// - template - [[nodiscard]] constexpr auto - identity_map_4k( - MAP_T &map, - bsl::safe_umx const &gpa, - bsl::safe_umx const &size, - bsl::safe_umx const &flags) noexcept -> bsl::errc_type - { - constexpr bsl::safe_u64 page_size_4k{bsl::to_umx(0x001000U)}; - - bsl::errc_type ret{}; - bsl::safe_umx crsr{gpa}; - - if (bsl::unlikely(!gpa)) { - bsl::error() << "guest physical address is invalid: " // -- - << bsl::hex(gpa) // -- - << bsl::endl // -- - << bsl::here(); // -- - - return bsl::errc_failure; - } - - if (bsl::unlikely(!this->is_page_4k_aligned(gpa))) { - bsl::error() << "guest physical address is not 2m page aligned: " // -- - << bsl::hex(gpa) // -- - << bsl::endl // -- - << bsl::here(); // -- - - return bsl::errc_failure; - } - - if (bsl::unlikely(!size)) { - bsl::error() << "size is invalid: " // -- - << bsl::hex(size) // -- - << bsl::endl // -- - << bsl::here(); // -- - - return bsl::errc_failure; - } - - if (bsl::unlikely(!this->is_page_4k_aligned(size))) { - bsl::error() << "size is not 2m page aligned: " // -- - << bsl::hex(size) // -- - << bsl::endl // -- - << bsl::here(); // -- - - return bsl::errc_failure; - } - - for (bsl::safe_idx i{}; i < m_ranges_count; ++i) { - auto *const range{m_ranges.at_if(i)}; - - if (range->addr + range->size < crsr) { - continue; - } - - while (crsr < range->addr + range->size) { - - if (!(crsr < gpa + size)) { - return bsl::errc_success; - } - - ret = map.map_4k_page(crsr, crsr, flags, range->type); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return ret; - } - - crsr += page_size_4k; - } - } - - bsl::error() << "identity map is out of bounds" // -- - << bsl::endl // -- - << bsl::here(); // -- - - return bsl::errc_failure; - } - - /// - /// @brief Creates an identity map in the provided map using the - /// memory types contained in the MTRRs. The resulting identity - /// map will mimic the MTRRs given the range provided - /// - /// - /// @tparam MAP_T the type of map to use - /// @param map the map to create the identity map in - /// @param gpa the starting guest physical address - /// @param size the number of bytes from the provided gpa to map - /// @param flags the read/write/execute flags to use - /// @return Returns bsl::errc_success on success and bsl::errc_failure - /// on failure. - /// - template - [[nodiscard]] constexpr auto - identity_map_2m( - MAP_T &map, - bsl::safe_umx const &gpa, - bsl::safe_umx const &size, - bsl::safe_umx const &flags) noexcept -> bsl::errc_type - { - constexpr bsl::safe_u64 page_size_4k{bsl::to_umx(0x001000U)}; - constexpr bsl::safe_u64 page_size_2m{bsl::to_umx(0x200000U)}; - - bsl::errc_type ret{}; - bsl::safe_umx crsr{gpa}; - - if (bsl::unlikely(!gpa)) { - bsl::error() << "guest physical address is invalid: " // -- - << bsl::hex(gpa) // -- - << bsl::endl // -- - << bsl::here(); // -- - - return bsl::errc_failure; - } - - if (bsl::unlikely(!this->is_page_2m_aligned(gpa))) { - bsl::error() << "guest physical address is not 2m page aligned: " // -- - << bsl::hex(gpa) // -- - << bsl::endl // -- - << bsl::here(); // -- - - return bsl::errc_failure; - } - - if (bsl::unlikely(!size)) { - bsl::error() << "size is invalid: " // -- - << bsl::hex(size) // -- - << bsl::endl // -- - << bsl::here(); // -- - - return bsl::errc_failure; - } - - if (bsl::unlikely(!this->is_page_2m_aligned(size))) { - bsl::error() << "size is not 2m page aligned: " // -- - << bsl::hex(size) // -- - << bsl::endl // -- - << bsl::here(); // -- - - return bsl::errc_failure; - } - - for (bsl::safe_idx i{}; i < m_ranges_count; ++i) { - auto *const range{m_ranges.at_if(i)}; - - if (range->addr + range->size < crsr) { - continue; - } - - while (crsr < range->addr + range->size) { - - if (!(crsr < gpa + size)) { - return bsl::errc_success; - } - - if (this->is_page_2m_aligned(crsr)) { - if (!(crsr + page_size_2m > range->addr + range->size)) { - - ret = map.map_2m_page(crsr, crsr, flags, range->type); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return ret; - } - - crsr += page_size_2m; - continue; - } - - bsl::touch(); - } - else { - bsl::touch(); - } - - ret = map.map_4k_page(crsr, crsr, flags, range->type); - if (bsl::unlikely(!ret)) { - bsl::print() << bsl::here(); - return ret; - } - - crsr += page_size_4k; - } - } - - if (crsr == gpa + size) { - return bsl::errc_success; - } - - bsl::error() << "identity map is out of bounds" // -- - << bsl::endl // -- - << bsl::here(); // -- - - return bsl::errc_failure; - } - - /// - /// @brief Returns the max physical address in the MTRRs on success, - /// or bsl::safe_umx::failure() on failure. - /// - /// - /// @return Returns the max physical address in the MTRRs on success, - /// or bsl::safe_umx::failure() on failure. - /// - [[nodiscard]] constexpr auto - max_phys() noexcept -> bsl::safe_umx - { - if (m_ranges_count.is_zero()) { - bsl::error() << "mtrrs has not been parsed yet\n" << bsl::here(); - return bsl::safe_umx::failure(); - } - - auto const *const range{m_ranges.at_if(m_ranges_count - bsl::ONE_UMAX)}; - return range->addr + range->size; - } - - /// - /// @brief Outputs the contents of the MTRRs. - /// - constexpr void - dump() const noexcept - { - if constexpr (BSL_DEBUG_LEVEL == bsl::CRITICAL_ONLY) { - return; - } - - bsl::print() << bsl::mag << "mtrrs dump: "; - bsl::print() << bsl::rst << bsl::endl; - - /// Header - /// - - bsl::print() << bsl::ylw << "+------------------------------------------------+"; - bsl::print() << bsl::rst << bsl::endl; - - bsl::print() << bsl::ylw << "| "; - bsl::print() << bsl::cyn << bsl::fmt{"^19s", "start "}; - bsl::print() << bsl::ylw << "| "; - bsl::print() << bsl::cyn << bsl::fmt{"^19s", "end "}; - bsl::print() << bsl::ylw << "| "; - bsl::print() << bsl::cyn << bsl::fmt{"^5s", "type "}; - bsl::print() << bsl::ylw << "| "; - bsl::print() << bsl::rst << bsl::endl; - - bsl::print() << bsl::ylw << "+------------------------------------------------+"; - bsl::print() << bsl::rst << bsl::endl; - - /// MTRRs - /// - - for (bsl::safe_idx i{}; i < m_ranges_count; ++i) { - auto const *rowcolor{bsl::rst}; - auto const *const range{m_ranges.at_if(i)}; - - bsl::safe_umx const srt{range->addr}; - bsl::safe_umx const end{range->addr + range->size - bsl::ONE_UMAX}; - - if (MEMORY_TYPE_UC == range->type) { - rowcolor = bsl::blk; - } - else { - bsl::touch(); - } - - bsl::print() << bsl::ylw << "| "; - bsl::print() << rowcolor << bsl::hex(srt) << ' '; - bsl::print() << bsl::ylw << "| "; - bsl::print() << rowcolor << bsl::hex(end) << ' '; - bsl::print() << bsl::ylw << "| "; - - switch (range->type.get()) { - case MEMORY_TYPE_WC.get(): { - bsl::print() << rowcolor << bsl::fmt{"^5s", "wc"}; - break; - } - - case MEMORY_TYPE_WP.get(): { - bsl::print() << rowcolor << bsl::fmt{"^5s", "wp"}; - break; - } - - case MEMORY_TYPE_WT.get(): { - bsl::print() << rowcolor << bsl::fmt{"^5s", "wt"}; - break; - } - - case MEMORY_TYPE_WB.get(): { - bsl::print() << rowcolor << bsl::fmt{"^5s", "wb"}; - break; - } - - default: { - bsl::print() << rowcolor << bsl::fmt{"^5s", "uc"}; - break; - } - } - - bsl::print() << bsl::ylw << "| "; - bsl::print() << bsl::rst << bsl::endl; - } - - /// Footer - /// - - bsl::print() << bsl::ylw << "+------------------------------------------------+"; - bsl::print() << bsl::rst << bsl::endl; - } - }; -} - -#endif diff --git a/kernel/src/ext_t.hpp b/kernel/src/ext_t.hpp index dbbb816a..8f1412b6 100644 --- a/kernel/src/ext_t.hpp +++ b/kernel/src/ext_t.hpp @@ -686,6 +686,14 @@ namespace mk return bsl::errc_failure; } + if (bsl::safe_u64::magic_0() == phdr->p_filesz) { + return bsl::errc_success; + } + + if (bsl::safe_u64::magic_0() == phdr->p_memsz) { + return bsl::errc_success; + } + /// NOTE: /// - Since the validation code above ensures that the TLB block /// in the phdr is no larger than a page, dst_idx cannot diff --git a/kernel/src/x64/intel/intrinsic_vmrun.S b/kernel/src/x64/intel/intrinsic_vmrun.S index 68f3c170..0732eae3 100644 --- a/kernel/src/x64/intel/intrinsic_vmrun.S +++ b/kernel/src/x64/intel/intrinsic_vmrun.S @@ -148,12 +148,12 @@ nmis_complete: resume: vmresume - jmp intrinsic_vmexit + jmp intrinsic_vmexit_failure int 3 launch: vmlaunch - jmp intrinsic_vmexit + jmp intrinsic_vmexit_failure int 3 .size intrinsic_vmrun, .-intrinsic_vmrun @@ -296,4 +296,141 @@ intrinsic_vmexit: ret int 3 + + + .globl intrinsic_vmexit_failure + .type intrinsic_vmexit_failure, @function +intrinsic_vmexit_failure: + + push 0x40002 + popf + + /**************************************************************************/ + /* General Purpose Register State */ + /**************************************************************************/ + + mov fs:[0x870], r15 + mov fs:[0x868], r14 + mov fs:[0x860], r13 + mov fs:[0x858], r12 + mov fs:[0x850], r11 + mov fs:[0x848], r10 + mov fs:[0x840], r9 + mov fs:[0x838], r8 + mov fs:[0x830], rdi + mov fs:[0x828], rsi + mov fs:[0x820], rbp + mov fs:[0x818], rdx + mov fs:[0x810], rcx + mov fs:[0x808], rbx + mov fs:[0x800], rax + + pop r15 + + /**************************************************************************/ + /* Signal VMLaunch/VMResume Success */ + /**************************************************************************/ + + mov rax, 0x1 + mov [r15 + 0x000], rax + + /**************************************************************************/ + /* NMIs */ + /**************************************************************************/ + + mov rax, 0x1 + mov gs:[0x258], rax + + /**************************************************************************/ + /* MSRs */ + /**************************************************************************/ + + mov edi, 0xC0000102 + call intrinsic_rdmsr_unsafe + mov [r15 + 0x080], rax + mov rsi, [r15 + 0x0D0] + call intrinsic_wrmsr_unsafe + + mov edi, 0xC0000084 + call intrinsic_rdmsr_unsafe + mov [r15 + 0x078], rax + mov rsi, [r15 + 0x0C8] + call intrinsic_wrmsr_unsafe + + mov edi, 0xC0000083 + call intrinsic_rdmsr_unsafe + mov [r15 + 0x070], rax + mov rsi, [r15 + 0x0C0] + call intrinsic_wrmsr_unsafe + + mov edi, 0xC0000082 + call intrinsic_rdmsr_unsafe + mov [r15 + 0x068], rax + mov rsi, [r15 + 0x0B8] + call intrinsic_wrmsr_unsafe + + mov edi, 0xC0000081 + call intrinsic_rdmsr_unsafe + mov [r15 + 0x060], rax + mov rsi, [r15 + 0x0B0] + call intrinsic_wrmsr_unsafe + + /**************************************************************************/ + /* Missing Registers */ + /**************************************************************************/ + + xor ecx, ecx + xgetbv + mov [r15 + 0x088], eax + mov [r15 + 0x08C], edx + mov eax, [r15 + 0x0D8] + mov edx, [r15 + 0x0DC] + xsetbv + + xor rcx, rcx + + mov rax, dr6 + mov [r15 + 0x038], rax + mov dr6, rcx + + mov rax, dr3 + mov [r15 + 0x030], rax + mov dr3, rcx + + mov rax, dr2 + mov [r15 + 0x028], rax + mov dr2, rcx + + mov rax, dr1 + mov [r15 + 0x020], rax + mov dr1, rcx + + mov rax, dr0 + mov [r15 + 0x018], rax + mov dr0, rcx + + mov rax, cr8 + mov [r15 + 0x010], rax + mov cr8, rcx + + mov rax, cr2 + mov [r15 + 0x008], rax + mov cr2, rcx + + /**************************************************************************/ + /* Done */ + /**************************************************************************/ + + pop r15 + pop r14 + pop r13 + pop r12 + pop rbp + pop rbx + + mov rax, 0xFFFFFFFFFFFFFFFF + + ret + int 3 + .size intrinsic_vmrun, .-intrinsic_vmrun diff --git a/kernel/tests/src/ext_t/behavior.cpp b/kernel/tests/src/ext_t/behavior.cpp index e1dca5ba..3bf4bd5a 100644 --- a/kernel/tests/src/ext_t/behavior.cpp +++ b/kernel/tests/src/ext_t/behavior.cpp @@ -509,6 +509,60 @@ namespace mk }; }; + bsl::ut_scenario{"initialize tls file size is 0"} = [&]() noexcept { + bsl::ut_given{} = [&]() noexcept { + auto const elf_file_buf{get_elf_file_buf()}; + loader::ext_elf_file_t mut_file{}; + phdr_table_t mut_phdr_table{}; + ext_t mut_ext{}; + tls_t mut_tls{}; + page_pool_t mut_page_pool{}; + huge_pool_t mut_huge_pool{}; + root_page_table_t mut_rpt{}; + bsl::ut_when{} = [&]() noexcept { + mut_tls.online_pps = NUM_ONLINE_PPS.get(); + load_elf_file(mut_file, mut_phdr_table); + load_phdr_table(mut_phdr_table, elf_file_buf); + mut_phdr_table.at_if(PHDR_PT_TLS_IDX)->p_filesz = {}; + bsl::ut_then{} = [&]() noexcept { + bsl::ut_check( + mut_ext.initialize(mut_tls, mut_page_pool, {}, &mut_file, mut_rpt)); + }; + bsl::ut_cleanup{} = [&]() noexcept { + mut_ext.release(mut_tls, mut_page_pool, mut_huge_pool); + clr_elf_file_buf(elf_file_buf); + }; + }; + }; + }; + + bsl::ut_scenario{"initialize tls mem size is 0"} = [&]() noexcept { + bsl::ut_given{} = [&]() noexcept { + auto const elf_file_buf{get_elf_file_buf()}; + loader::ext_elf_file_t mut_file{}; + phdr_table_t mut_phdr_table{}; + ext_t mut_ext{}; + tls_t mut_tls{}; + page_pool_t mut_page_pool{}; + huge_pool_t mut_huge_pool{}; + root_page_table_t mut_rpt{}; + bsl::ut_when{} = [&]() noexcept { + mut_tls.online_pps = NUM_ONLINE_PPS.get(); + load_elf_file(mut_file, mut_phdr_table); + load_phdr_table(mut_phdr_table, elf_file_buf); + mut_phdr_table.at_if(PHDR_PT_TLS_IDX)->p_memsz = {}; + bsl::ut_then{} = [&]() noexcept { + bsl::ut_check( + mut_ext.initialize(mut_tls, mut_page_pool, {}, &mut_file, mut_rpt)); + }; + bsl::ut_cleanup{} = [&]() noexcept { + mut_ext.release(mut_tls, mut_page_pool, mut_huge_pool); + clr_elf_file_buf(elf_file_buf); + }; + }; + }; + }; + bsl::ut_scenario{"initialize allocate stack fails"} = [&]() noexcept { bsl::ut_given{} = [&]() noexcept { auto const elf_file_buf{get_elf_file_buf()}; diff --git a/lib/src/linux/basic_ioctl_t.hpp b/lib/src/linux/basic_ioctl_t.hpp index 13e4ccc0..e6b02f2e 100644 --- a/lib/src/linux/basic_ioctl_t.hpp +++ b/lib/src/linux/basic_ioctl_t.hpp @@ -71,7 +71,7 @@ namespace lib // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, hicpp-vararg) m_hndl = bsl::to_i32(open(name.data(), O_RDWR)); if (bsl::unlikely(IOCTL_INVALID_HNDL == m_hndl)) { - bsl::error() << "basic_ioctl_t open failed\n"; + bsl::error() << "ioctl open failed\n"; return; } diff --git a/lib/src/windows/basic_ioctl_t.hpp b/lib/src/windows/basic_ioctl_t.hpp index 4b56264b..f1005847 100644 --- a/lib/src/windows/basic_ioctl_t.hpp +++ b/lib/src/windows/basic_ioctl_t.hpp @@ -46,6 +46,8 @@ #include #include #include +#include +#include namespace lib { @@ -146,7 +148,7 @@ namespace lib nullptr); if (bsl::unlikely(nullptr == m_hndl)) { - bsl::error() << "basic_ioctl_t CreateFile failed\n"; + bsl::error() << "ioctl CreateFile failed\n"; return; } } @@ -280,8 +282,7 @@ namespace lib DWORD bytes{}; if (bsl::unlikely(nullptr == m_hndl)) { - bsl::error() - << "basic_ioctl_t failed because the handle to the driver is invalid\n"; + bsl::error() << "ioctl failed because the handle to the driver is invalid\n"; return bsl::safe_i64::magic_neg_1(); } @@ -316,8 +317,7 @@ namespace lib bsl::expects(nullptr != pmut_data); if (bsl::unlikely(nullptr == m_hndl)) { - bsl::error() - << "basic_ioctl_t failed because the handle to the driver is invalid\n"; + bsl::error() << "ioctl failed because the handle to the driver is invalid\n"; return bsl::safe_i64::magic_neg_1(); } @@ -358,8 +358,7 @@ namespace lib bsl::expects(nullptr != data); if (bsl::unlikely(nullptr == m_hndl)) { - bsl::error() - << "basic_ioctl_t failed because the handle to the driver is invalid\n"; + bsl::error() << "ioctl failed because the handle to the driver is invalid\n"; return bsl::safe_i64::magic_neg_1(); } @@ -399,8 +398,7 @@ namespace lib bsl::expects(data.is_valid_and_checked()); if (bsl::unlikely(nullptr == m_hndl)) { - bsl::error() - << "basic_ioctl_t failed because the handle to the driver is invalid\n"; + bsl::error() << "ioctl failed because the handle to the driver is invalid\n"; return bsl::safe_i64::magic_neg_1(); } @@ -438,8 +436,7 @@ namespace lib bsl::expects(nullptr != pmut_data); if (bsl::unlikely(nullptr == m_hndl)) { - bsl::error() - << "basic_ioctl_t failed because the handle to the driver is invalid\n"; + bsl::error() << "ioctl failed because the handle to the driver is invalid\n"; return bsl::safe_i64::magic_neg_1(); } diff --git a/loader/efi/src/entry.c b/loader/efi/src/entry.c index c448615d..5f2adf46 100644 --- a/loader/efi/src/entry.c +++ b/loader/efi/src/entry.c @@ -243,7 +243,7 @@ load_images_and_start(void) return status; } - status = read_file(volume_protocol, L"bareflank_extension0", &(start_args.ext_elf_files[0])); + status = read_file(volume_protocol, L"bareflank_extension", &(start_args.ext_elf_files[0])); if (EFI_ERROR(status)) { bferror_x64("open_extensions failed", status); return status; diff --git a/loader/src/start_vmm_per_cpu.c b/loader/src/start_vmm_per_cpu.c index d4171f94..7915b8df 100644 --- a/loader/src/start_vmm_per_cpu.c +++ b/loader/src/start_vmm_per_cpu.c @@ -213,7 +213,6 @@ start_vmm_per_cpu(uint32_t const cpu) NOEXCEPT platform_mark_gdt_readonly(); if (mut_ret) { - platform_dump_vmm(); bferror("demote failed"); goto demote_failed; } diff --git a/loader/src/x64/alloc_and_copy_mk_state.c b/loader/src/x64/alloc_and_copy_mk_state.c index 166f070f..4c9d094d 100644 --- a/loader/src/x64/alloc_and_copy_mk_state.c +++ b/loader/src/x64/alloc_and_copy_mk_state.c @@ -57,11 +57,6 @@ /** @brief defines the default value of CR4 */ #define DEFAULT_CR4 ((uint64_t)0x003400E0) -/** @brief defines the default value of CR0 bits that must be off */ -#define DEFAULT_CR0_OFF ((uint64_t)0xFFFFFFFFFFFFFFFF) -/** @brief defines the default value of CR4 bits that must be off */ -#define DEFAULT_CR4_OFF ((uint64_t)0xFFFFFFFFFFFFFFFF) - /** @brief defines the MSR_EFER MSR */ #define MSR_EFER ((uint32_t)0xC0000080) /** @brief defines the default value of EFER */ @@ -492,29 +487,32 @@ alloc_and_copy_mk_state( ESR_ATTRIB); // -- /**************************************************************************/ - /* Control Registers */ + /* CR0/CR4 */ /**************************************************************************/ - (*pmut_state)->cr0 = (intrinsic_scr0() | DEFAULT_CR0) & DEFAULT_CR0_OFF; - (*pmut_state)->cr3 = platform_virt_to_phys(rpt); - (*pmut_state)->cr4 = (intrinsic_scr4() | DEFAULT_CR4) & DEFAULT_CR4_OFF; + (*pmut_state)->cr0 = (intrinsic_scr0() | DEFAULT_CR0); + (*pmut_state)->cr4 = (intrinsic_scr4() | DEFAULT_CR4); + /**************************************************************************/ + /* CR3 */ + /**************************************************************************/ + + (*pmut_state)->cr3 = platform_virt_to_phys(rpt); if (((uint64_t)0) == (*pmut_state)->cr3) { bferror("platform_virt_to_phys failed"); goto platform_virt_to_phys_cr3_failed; } + /**************************************************************************/ + /* XCR0 */ + /**************************************************************************/ + mut_eax = CPUID_EXTENDED_STATE; mut_ecx = 0U; intrinsic_cpuid(&mut_eax, &mut_ebx, &mut_ecx, &mut_edx); (*pmut_state)->xcr0 = (((uint64_t)mut_edx) << ((uint64_t)32)) | ((uint64_t)mut_eax); - if (((uint64_t)0) == (*pmut_state)->xcr0) { - bferror("intrinsic_cpuid failed"); - goto intrinsic_cpuid_xcr0_failed; - } - /**************************************************************************/ /* MSRs */ /**************************************************************************/ @@ -526,7 +524,6 @@ alloc_and_copy_mk_state( return LOADER_SUCCESS; -intrinsic_cpuid_xcr0_failed: platform_virt_to_phys_cr3_failed: platform_alloc_idt_failed: platform_alloc_gdt_failed: diff --git a/loader/src/x64/amd/check_cpu_configuration.c b/loader/src/x64/amd/check_cpu_configuration.c index 7e7a765d..18829727 100644 --- a/loader/src/x64/amd/check_cpu_configuration.c +++ b/loader/src/x64/amd/check_cpu_configuration.c @@ -43,8 +43,8 @@ #define CPUID_LEAF_FEATURE ((uint32_t)0x1) /** @brief define the CPUID feature bit for XSAVE */ #define CPUID_FEATURE_ECX_XSAVE (((uint32_t)1) << ((uint32_t)26)) -/** @brief define the CPUID feature bit for OSXSAVE */ -#define CPUID_FEATURE_ECX_OSXSAVE (((uint32_t)1) << ((uint32_t)27)) +/** @brief define the CPUID feature bit for AVX */ +#define CPUID_FEATURE_ECX_AVX (((uint32_t)1) << ((uint32_t)28)) /** @brief defines the CPUID leaf for feature information */ #define CPUID_LEAF_EXT_FEATURE ((uint32_t)0x80000001) @@ -197,8 +197,8 @@ check_for_xsave(void) NOEXCEPT return LOADER_FAILURE; } - if ((ecx & CPUID_FEATURE_ECX_OSXSAVE) == 0U) { - bferror_x32("cpu does not support CR4.OSXSAVE", ecx); + if ((ecx & CPUID_FEATURE_ECX_AVX) == 0U) { + bferror_x32("cpu does not support AVX", ecx); return LOADER_FAILURE; } diff --git a/loader/src/x64/intel/check_cpu_configuration.c b/loader/src/x64/intel/check_cpu_configuration.c index 75914f15..3c360073 100644 --- a/loader/src/x64/intel/check_cpu_configuration.c +++ b/loader/src/x64/intel/check_cpu_configuration.c @@ -47,8 +47,8 @@ #define CPUID_FEATURE_ECX_VMX (((uint32_t)1) << ((uint32_t)5)) /** @brief define the CPUID feature bit for XSAVE */ #define CPUID_FEATURE_ECX_XSAVE (((uint32_t)1) << ((uint32_t)26)) -/** @brief define the CPUID feature bit for OSXSAVE */ -#define CPUID_FEATURE_ECX_OSXSAVE (((uint32_t)1) << ((uint32_t)27)) +/** @brief define the CPUID feature bit for AVX */ +#define CPUID_FEATURE_ECX_AVX (((uint32_t)1) << ((uint32_t)28)) /** @brief defines the MSR address for feature information */ #define MSR_FEATURE_CTRL ((uint32_t)0x3A) @@ -301,8 +301,8 @@ check_for_xsave(void) NOEXCEPT return LOADER_FAILURE; } - if ((ecx & CPUID_FEATURE_ECX_OSXSAVE) == 0U) { - bferror_x32("cpu does not support CR4.OSXSAVE", ecx); + if ((ecx & CPUID_FEATURE_ECX_AVX) == 0U) { + bferror_x32("cpu does not support AVX", ecx); return LOADER_FAILURE; } diff --git a/loader/tests/src/x64/test_alloc_and_copy_mk_state.cpp b/loader/tests/src/x64/test_alloc_and_copy_mk_state.cpp index 3e1e492a..f45d5a44 100644 --- a/loader/tests/src/x64/test_alloc_and_copy_mk_state.cpp +++ b/loader/tests/src/x64/test_alloc_and_copy_mk_state.cpp @@ -294,33 +294,6 @@ namespace loader }; }; - bsl::ut_scenario{"intrinsic_cpuid fails"} = [&]() noexcept { - bsl::ut_given{} = [&]() noexcept { - root_page_table_t const rpt{}; - elf_file_t mut_mk_elf_file{}; - span_t const mk_stack{}; - bsl::safe_u64 const mk_stack_virt{}; - state_save_t *pmut_mut_state{}; - bfelf_elf64_ehdr_t const ehdr{}; - bsl::ut_when{} = [&]() noexcept { - mut_mk_elf_file.addr = &ehdr; - helpers::g_mut_intrinsic_cpuid = -1; - bsl::ut_then{} = [&]() noexcept { - helpers::ut_fails(func( - &rpt, - &mut_mk_elf_file, - &mk_stack, - mk_stack_virt.get(), - &pmut_mut_state)); - }; - bsl::ut_cleanup{} = [&]() noexcept { - free_mk_state(&pmut_mut_state); - helpers::reset_x64(); - }; - }; - }; - }; - return helpers::fini(); } } diff --git a/loader/windows/src/platform.c b/loader/windows/src/platform.c index b6b7db0d..151b4940 100644 --- a/loader/windows/src/platform.c +++ b/loader/windows/src/platform.c @@ -56,7 +56,7 @@ void platform_expects(int const test) NOEXCEPT { - NT_ASSERT(!test); + NT_ASSERT(test); } /** @@ -73,7 +73,7 @@ platform_expects(int const test) NOEXCEPT void platform_ensures(int const test) NOEXCEPT { - NT_ASSERT(!test); + NT_ASSERT(test); } /** diff --git a/runtime/src/__stack_chk_fail.cpp b/runtime/src/__stack_chk_fail.cpp index f1ac7313..6fc4e189 100644 --- a/runtime/src/__stack_chk_fail.cpp +++ b/runtime/src/__stack_chk_fail.cpp @@ -26,6 +26,8 @@ #include +#pragma clang diagnostic ignored "-Wreserved-identifier" + namespace mk { /// diff --git a/syscall/CMakeLists.txt b/syscall/CMakeLists.txt index e2445dbd..a58d7a5a 100644 --- a/syscall/CMakeLists.txt +++ b/syscall/CMakeLists.txt @@ -19,8 +19,104 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -if(CMAKE_PROJECT_NAME STREQUAL "hypervisor_microkernel") - include(mk_lib.cmake) -else() - include(ext_lib_cpp.cmake) +if(NOT CMAKE_PROJECT_NAME STREQUAL "hypervisor") + if(CMAKE_PROJECT_NAME STREQUAL "hypervisor_microkernel") + include(mk_lib.cmake) + else() + include(ext_lib_cpp.cmake) + endif() +endif() + +if(CMAKE_PROJECT_NAME STREQUAL "hypervisor" AND NOT EXISTS ${CMAKE_BINARY_DIR}/rust/syscall_rust_files.txt) + + # -------------------------------------------------------------------------- + # Rebuild Flag + # -------------------------------------------------------------------------- + + file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/rust) + set(HYPERVISOR_CONSTANTS ${CMAKE_BINARY_DIR}/rust/syscall_rust_files.txt) + + file(WRITE ${HYPERVISOR_CONSTANTS} "touched\n") + + # -------------------------------------------------------------------------- + # Cargo.toml + # -------------------------------------------------------------------------- + + set(HYPERVISOR_CARGO_TOML ${CMAKE_SOURCE_DIR}/syscall/Cargo.toml) + + file(WRITE ${HYPERVISOR_CARGO_TOML} "[package]\n") + file(APPEND ${HYPERVISOR_CARGO_TOML} "name = \"syscall\"\n") + file(APPEND ${HYPERVISOR_CARGO_TOML} "version = \"0.1.0\"\n") + file(APPEND ${HYPERVISOR_CARGO_TOML} "edition = \"2018\"\n") + file(APPEND ${HYPERVISOR_CARGO_TOML} "\n") + file(APPEND ${HYPERVISOR_CARGO_TOML} "[lib]\n") + file(APPEND ${HYPERVISOR_CARGO_TOML} "path = \"lib.rs\"\n") + file(APPEND ${HYPERVISOR_CARGO_TOML} "\n") + file(APPEND ${HYPERVISOR_CARGO_TOML} "[features]\n") + + set(SYSCALL_DEFAULT_FEATURES "[\"custom_print_thread_id\"") + + if(HYPERVISOR_TARGET_ARCH STREQUAL "AuthenticAMD") + set(SYSCALL_DEFAULT_FEATURES "${SYSCALL_DEFAULT_FEATURES},\"AuthenticAMD\"") + endif() + + if(HYPERVISOR_TARGET_ARCH STREQUAL "GenuineIntel") + set(SYSCALL_DEFAULT_FEATURES "${SYSCALL_DEFAULT_FEATURES},\"GenuineIntel\"") + endif() + + if(NOT ENABLE_COLOR) + set(SYSCALL_DEFAULT_FEATURES "${SYSCALL_DEFAULT_FEATURES},\"disable_color\"") + endif() + + if(BSL_DEBUG_LEVEL STREQUAL "bsl::V") + set(SYSCALL_DEFAULT_FEATURES "${SYSCALL_DEFAULT_FEATURES},\"debug_level_v\"") + endif() + + if(BSL_DEBUG_LEVEL STREQUAL "bsl::VV") + set(SYSCALL_DEFAULT_FEATURES "${SYSCALL_DEFAULT_FEATURES},\"debug_level_v\",\"debug_level_vv\"") + endif() + + if(BSL_DEBUG_LEVEL STREQUAL "bsl::VVV") + set(SYSCALL_DEFAULT_FEATURES "${SYSCALL_DEFAULT_FEATURES},\"debug_level_v\",\"debug_level_vv\",\"debug_level_vvv\"") + endif() + + if(CMAKE_BUILD_TYPE STREQUAL RELEASE OR CMAKE_BUILD_TYPE STREQUAL MINSIZEREL) + set(SYSCALL_DEFAULT_FEATURES "${SYSCALL_DEFAULT_FEATURES},\"release_mode\"]") + else() + set(SYSCALL_DEFAULT_FEATURES "${SYSCALL_DEFAULT_FEATURES}]") + endif() + + file(APPEND ${HYPERVISOR_CARGO_TOML} "default = ${SYSCALL_DEFAULT_FEATURES}\n") + file(APPEND ${HYPERVISOR_CARGO_TOML} "debug_level_v = []\n") + file(APPEND ${HYPERVISOR_CARGO_TOML} "debug_level_vv = []\n") + file(APPEND ${HYPERVISOR_CARGO_TOML} "debug_level_vvv = []\n") + file(APPEND ${HYPERVISOR_CARGO_TOML} "disable_color = []\n") + file(APPEND ${HYPERVISOR_CARGO_TOML} "release_mode = []\n") + file(APPEND ${HYPERVISOR_CARGO_TOML} "AuthenticAMD = []\n") + file(APPEND ${HYPERVISOR_CARGO_TOML} "GenuineIntel = []\n") + file(APPEND ${HYPERVISOR_CARGO_TOML} "custom_print_thread_id = []\n") + file(APPEND ${HYPERVISOR_CARGO_TOML} "\n") + + file(APPEND ${HYPERVISOR_CARGO_TOML} "[dependencies]\n") + file(APPEND ${HYPERVISOR_CARGO_TOML} "bsl = { path = \"${bsl_SOURCE_DIR}\" }\n") + + # -------------------------------------------------------------------------- + # Constants + # -------------------------------------------------------------------------- + + set(HYPERVISOR_CONSTANTS ${CMAKE_SOURCE_DIR}/syscall/constants.rs) + + file(WRITE ${HYPERVISOR_CONSTANTS} "\n") + file(APPEND ${HYPERVISOR_CONSTANTS} "pub const HYPERVISOR_PAGE_SIZE:bsl::SafeU64 = bsl::SafeU64::new(${HYPERVISOR_PAGE_SIZE});\n") + file(APPEND ${HYPERVISOR_CONSTANTS} "pub const HYPERVISOR_PAGE_SHIFT:bsl::SafeU64 = bsl::SafeU64::new(${HYPERVISOR_PAGE_SHIFT});\n") + file(APPEND ${HYPERVISOR_CONSTANTS} "pub const HYPERVISOR_MAX_PPS:bsl::SafeUMx = bsl::SafeUMx::new(${HYPERVISOR_MAX_PPS});\n") + file(APPEND ${HYPERVISOR_CONSTANTS} "pub const HYPERVISOR_MAX_VMS:bsl::SafeUMx = bsl::SafeUMx::new(${HYPERVISOR_MAX_VMS});\n") + file(APPEND ${HYPERVISOR_CONSTANTS} "pub const HYPERVISOR_MAX_VPS:bsl::SafeUMx = bsl::SafeUMx::new(${HYPERVISOR_MAX_VPS});\n") + file(APPEND ${HYPERVISOR_CONSTANTS} "pub const HYPERVISOR_MAX_VSS:bsl::SafeUMx = bsl::SafeUMx::new(${HYPERVISOR_MAX_VSS});\n") + file(APPEND ${HYPERVISOR_CONSTANTS} "pub const HYPERVISOR_EXT_DIRECT_MAP_ADDR:bsl::SafeU64 = bsl::SafeU64::new(${HYPERVISOR_EXT_DIRECT_MAP_ADDR});\n") + file(APPEND ${HYPERVISOR_CONSTANTS} "pub const HYPERVISOR_EXT_DIRECT_MAP_SIZE:bsl::SafeU64 = bsl::SafeU64::new(${HYPERVISOR_EXT_DIRECT_MAP_SIZE});\n") + file(APPEND ${HYPERVISOR_CONSTANTS} "pub const HYPERVISOR_EXT_PAGE_POOL_ADDR:bsl::SafeU64 = bsl::SafeU64::new(${HYPERVISOR_EXT_PAGE_POOL_ADDR});\n") + file(APPEND ${HYPERVISOR_CONSTANTS} "pub const HYPERVISOR_EXT_PAGE_POOL_SIZE:bsl::SafeU64 = bsl::SafeU64::new(${HYPERVISOR_EXT_PAGE_POOL_SIZE});\n") + file(APPEND ${HYPERVISOR_CONSTANTS} "pub const HYPERVISOR_EXT_HUGE_POOL_ADDR:bsl::SafeU64 = bsl::SafeU64::new(${HYPERVISOR_EXT_HUGE_POOL_ADDR});\n") + file(APPEND ${HYPERVISOR_CONSTANTS} "pub const HYPERVISOR_EXT_HUGE_POOL_SIZE:bsl::SafeU64 = bsl::SafeU64::new(${HYPERVISOR_EXT_HUGE_POOL_SIZE});\n") endif() diff --git a/syscall/Cargo.toml b/syscall/Cargo.toml deleted file mode 100644 index 937c3b51..00000000 --- a/syscall/Cargo.toml +++ /dev/null @@ -1,4 +0,0 @@ -[package] -name = "syscall" -version = "0.1.0" -edition = "2018" diff --git a/syscall/include/bf_constants.hpp b/syscall/include/bf_constants.hpp index c432a6d6..e240d3ec 100644 --- a/syscall/include/bf_constants.hpp +++ b/syscall/include/bf_constants.hpp @@ -73,8 +73,6 @@ namespace syscall /// @brief Defines an invalid ID for an extension, VM, VP and VS constexpr auto BF_INVALID_ID{0xFFFF_u16}; - /// @brief Defines an ID for any extension, VM, VP and VS - constexpr auto BF_ANY_ID{0xFFFE_u16}; /// @brief Defines the bootstrap physical processor ID constexpr auto BF_BS_PPID{0x0_u16}; diff --git a/syscall/include/constants.rs b/syscall/include/bf_constants.rs similarity index 50% rename from syscall/include/constants.rs rename to syscall/include/bf_constants.rs index 7d300bcd..498ce1f4 100644 --- a/syscall/include/constants.rs +++ b/syscall/include/bf_constants.rs @@ -22,9 +22,9 @@ /// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE /// SOFTWARE. -// ------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- // Page Alignment -// ------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- /// /// @brief Returns true if the provided address is 4k page aligned, @@ -35,16 +35,16 @@ /// @return Returns true if the provided address is 4k page aligned, /// returns false otherwise. /// -pub fn bf_is_page_aligned(addr: u64) -> bool { - const MASK: u64 = cmake::HYPERVISOR_PAGE_SIZE - 1; - return (addr & MASK) == 0; +pub fn bf_is_page_aligned(addr: bsl::SafeU64) -> bool { + let mask: bsl::SafeU64 = crate::HYPERVISOR_PAGE_SIZE - 1; + return (addr & mask) == 0; } #[cfg(test)] mod test_bf_is_page_aligned { #[test] fn test_bf_is_page_aligned() { - let addr: u64 = 0x1234567890ABCDEF; + let addr: bsl::SafeU64 = bsl::SafeU64::new(0x1234567890ABCDEF); assert!(!super::bf_is_page_aligned(addr)); } } @@ -56,88 +56,88 @@ mod test_bf_is_page_aligned { /// @param addr the address to query /// @return Returns the page aligned version of the addr /// -pub fn bf_page_aligned(addr: u64) -> u64 { - return addr & !(cmake::HYPERVISOR_PAGE_SIZE - 1); +pub fn bf_page_aligned(addr: bsl::SafeU64) -> bsl::SafeU64 { + return addr & !(crate::HYPERVISOR_PAGE_SIZE - 1); } #[cfg(test)] mod test_bf_page_aligned { #[test] fn test_bf_page_aligned() { - let addr: u64 = 0x1234567890ABCDEF; - let expected: u64 = 0x1234567890ABC000; + let addr: bsl::SafeU64 = bsl::SafeU64::new(0x1234567890ABCDEF); + let expected: bsl::SafeU64 = bsl::SafeU64::new(0x1234567890ABC000); assert_eq!(super::bf_page_aligned(addr), expected); } } -// ------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- // Special IDs -// ------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- /// @brief Defines an invalid ID for an extension, VM, VP and VS -pub const BF_INVALID_ID: u16 = 0xFFFF; +pub const BF_INVALID_ID: bsl::SafeU16 = bsl::SafeU16::new(0xFFFF); /// @brief Defines the bootstrap physical processor ID -pub const BF_BS_PPID: u16 = 0x0; +pub const BF_BS_PPID: bsl::SafeU16 = bsl::SafeU16::new(0x0); /// @brief Defines the root virtual machine ID -pub const BF_ROOT_VMID: u16 = 0x0; +pub const BF_ROOT_VMID: bsl::SafeU16 = bsl::SafeU16::new(0x0); -// ------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- // Syscall Status Codes -// ------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- /// @brief Indicates the syscall returned successfully -pub const BF_STATUS_SUCCESS: u64 = 0x0000000000000000; +pub const BF_STATUS_SUCCESS: bsl::SafeU64 = bsl::SafeU64::new(0x0000000000000000); /// @brief Indicates an unknown error occurred -pub const BF_STATUS_FAILURE_UNKNOWN: u64 = 0xDEAD000000010001; +pub const BF_STATUS_FAILURE_UNKNOWN: bsl::SafeU64 = bsl::SafeU64::new(0xDEAD000000010001); /// @brief Indicates the syscall is unsupported -pub const BF_STATUS_FAILURE_INVALID_HANDLE: u64 = 0xDEAD000000020001; +pub const BF_STATUS_FAILURE_INVALID_HANDLE: bsl::SafeU64 = bsl::SafeU64::new(0xDEAD000000020001); /// @brief Indicates the provided handle is invalid -pub const BF_STATUS_FAILURE_UNSUPPORTED: u64 = 0xDEAD000000040001; +pub const BF_STATUS_FAILURE_UNSUPPORTED: bsl::SafeU64 = bsl::SafeU64::new(0xDEAD000000040001); /// @brief Indicates the policy engine denied the syscall -pub const BF_STATUS_INVALID_PERM_DENIED: u64 = 0xDEAD000000010002; +pub const BF_STATUS_INVALID_PERM_DENIED: bsl::SafeU64 = bsl::SafeU64::new(0xDEAD000000010002); /// @brief Indicates input reg0 is invalid -pub const BF_STATUS_INVALID_INPUT_REG0: u64 = 0xDEAD000000010003; +pub const BF_STATUS_INVALID_INPUT_REG0: bsl::SafeU64 = bsl::SafeU64::new(0xDEAD000000010003); /// @brief Indicates input reg1 is invalid -pub const BF_STATUS_INVALID_INPUT_REG1: u64 = 0xDEAD000000020003; +pub const BF_STATUS_INVALID_INPUT_REG1: bsl::SafeU64 = bsl::SafeU64::new(0xDEAD000000020003); /// @brief Indicates input reg2 is invalid -pub const BF_STATUS_INVALID_INPUT_REG2: u64 = 0xDEAD000000040003; +pub const BF_STATUS_INVALID_INPUT_REG2: bsl::SafeU64 = bsl::SafeU64::new(0xDEAD000000040003); /// @brief Indicates input reg3 is invalid -pub const BF_STATUS_INVALID_INPUT_REG3: u64 = 0xDEAD000000080003; +pub const BF_STATUS_INVALID_INPUT_REG3: bsl::SafeU64 = bsl::SafeU64::new(0xDEAD000000080003); /// @brief Indicates input reg4 is invalid -pub const BF_STATUS_INVALID_INPUT_REG4: u64 = 0xDEAD000000100003; +pub const BF_STATUS_INVALID_INPUT_REG4: bsl::SafeU64 = bsl::SafeU64::new(0xDEAD000000100003); /// @brief Indicates input reg5 is invalid -pub const BF_STATUS_INVALID_INPUT_REG5: u64 = 0xDEAD000000200003; +pub const BF_STATUS_INVALID_INPUT_REG5: bsl::SafeU64 = bsl::SafeU64::new(0xDEAD000000200003); /// @brief Indicates output reg0 is invalid -pub const BF_STATUS_INVALID_OUTPUT_REG0: u64 = 0xDEAD000000400003; +pub const BF_STATUS_INVALID_OUTPUT_REG0: bsl::SafeU64 = bsl::SafeU64::new(0xDEAD000000400003); /// @brief Indicates output reg1 is invalid -pub const BF_STATUS_INVALID_OUTPUT_REG1: u64 = 0xDEAD000000800003; +pub const BF_STATUS_INVALID_OUTPUT_REG1: bsl::SafeU64 = bsl::SafeU64::new(0xDEAD000000800003); /// @brief Indicates output reg2 is invalid -pub const BF_STATUS_INVALID_OUTPUT_REG2: u64 = 0xDEAD000001000003; +pub const BF_STATUS_INVALID_OUTPUT_REG2: bsl::SafeU64 = bsl::SafeU64::new(0xDEAD000001000003); /// @brief Indicates output reg3 is invalid -pub const BF_STATUS_INVALID_OUTPUT_REG3: u64 = 0xDEAD000002000003; +pub const BF_STATUS_INVALID_OUTPUT_REG3: bsl::SafeU64 = bsl::SafeU64::new(0xDEAD000002000003); /// @brief Indicates output reg4 is invalid -pub const BF_STATUS_INVALID_OUTPUT_REG4: u64 = 0xDEAD000004000003; +pub const BF_STATUS_INVALID_OUTPUT_REG4: bsl::SafeU64 = bsl::SafeU64::new(0xDEAD000004000003); /// @brief Indicates output reg5 is invalid -pub const BF_STATUS_INVALID_OUTPUT_REG5: u64 = 0xDEAD000008000003; +pub const BF_STATUS_INVALID_OUTPUT_REG5: bsl::SafeU64 = bsl::SafeU64::new(0xDEAD000008000003); -// ------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- // Syscall Inputs -// ------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- /// @brief Defines the BF_SYSCALL_SIG field for RAX -pub const BF_SYSCALL_SIG_VAL: u64 = 0x6642000000000000; +pub const BF_SYSCALL_SIG_VAL: bsl::SafeU64 = bsl::SafeU64::new(0x6642000000000000); /// @brief Defines a mask for BF_SYSCALL_SIG -pub const BF_SYSCALL_SIG_MASK: u64 = 0xFFFF000000000000; +pub const BF_SYSCALL_SIG_MASK: bsl::SafeU64 = bsl::SafeU64::new(0xFFFF000000000000); /// @brief Defines a mask for BF_SYSCALL_FLAGS -pub const BF_SYSCALL_FLAGS_MASK: u64 = 0x0000FFFF00000000; +pub const BF_SYSCALL_FLAGS_MASK: bsl::SafeU64 = bsl::SafeU64::new(0x0000FFFF00000000); /// @brief Defines a mask for BF_SYSCALL_OP -pub const BF_SYSCALL_OPCODE_MASK: u64 = 0xFFFF0000FFFF0000; +pub const BF_SYSCALL_OPCODE_MASK: bsl::SafeU64 = bsl::SafeU64::new(0xFFFF0000FFFF0000); /// @brief Defines a mask for BF_SYSCALL_OP (with no signature added) -pub const BF_SYSCALL_OPCODE_NOSIG_MASK: u64 = 0x00000000FFFF0000; +pub const BF_SYSCALL_OPCODE_NOSIG_MASK: bsl::SafeU64 = bsl::SafeU64::new(0x00000000FFFF0000); /// @brief Defines a mask for BF_SYSCALL_IDX -pub const BF_SYSCALL_INDEX_MASK: u64 = 0x000000000000FFFF; +pub const BF_SYSCALL_INDEX_MASK: bsl::SafeU64 = bsl::SafeU64::new(0x000000000000FFFF); /// /// @brief n/a @@ -146,7 +146,7 @@ pub const BF_SYSCALL_INDEX_MASK: u64 = 0x000000000000FFFF; /// @param rax n/a /// @return n/a /// -pub fn bf_syscall_sig(rax: u64) -> u64 { +pub fn bf_syscall_sig(rax: bsl::SafeU64) -> bsl::SafeU64 { return rax & BF_SYSCALL_SIG_MASK; } @@ -154,8 +154,8 @@ pub fn bf_syscall_sig(rax: u64) -> u64 { mod test_bf_syscall_sig { #[test] fn test_bf_syscall_sig() { - let syscall: u64 = 0x1234567890ABCDEF; - let expected: u64 = 0x1234000000000000; + let syscall: bsl::SafeU64 = bsl::SafeU64::new(0x1234567890ABCDEF); + let expected: bsl::SafeU64 = bsl::SafeU64::new(0x1234000000000000); assert_eq!(super::bf_syscall_sig(syscall), expected); } } @@ -167,7 +167,7 @@ mod test_bf_syscall_sig { /// @param rax n/a /// @return n/a /// -pub fn bf_syscall_flags(rax: u64) -> u64 { +pub fn bf_syscall_flags(rax: bsl::SafeU64) -> bsl::SafeU64 { return rax & BF_SYSCALL_FLAGS_MASK; } @@ -175,8 +175,8 @@ pub fn bf_syscall_flags(rax: u64) -> u64 { mod test_bf_syscall_flags { #[test] fn test_bf_syscall_flags() { - let syscall: u64 = 0x1234567890ABCDEF; - let expected: u64 = 0x0000567800000000; + let syscall: bsl::SafeU64 = bsl::SafeU64::new(0x1234567890ABCDEF); + let expected: bsl::SafeU64 = bsl::SafeU64::new(0x0000567800000000); assert_eq!(super::bf_syscall_flags(syscall), expected); } } @@ -188,7 +188,7 @@ mod test_bf_syscall_flags { /// @param rax n/a /// @return n/a /// -pub fn bf_syscall_opcode(rax: u64) -> u64 { +pub fn bf_syscall_opcode(rax: bsl::SafeU64) -> bsl::SafeU64 { return rax & BF_SYSCALL_OPCODE_MASK; } @@ -196,8 +196,8 @@ pub fn bf_syscall_opcode(rax: u64) -> u64 { mod test_bf_syscall_opcode { #[test] fn test_bf_syscall_opcode() { - let syscall: u64 = 0x1234567890ABCDEF; - let expected: u64 = 0x1234000090AB0000; + let syscall: bsl::SafeU64 = bsl::SafeU64::new(0x1234567890ABCDEF); + let expected: bsl::SafeU64 = bsl::SafeU64::new(0x1234000090AB0000); assert_eq!(super::bf_syscall_opcode(syscall), expected); } } @@ -209,7 +209,7 @@ mod test_bf_syscall_opcode { /// @param rax n/a /// @return n/a /// -pub fn bf_syscall_opcode_nosig(rax: u64) -> u64 { +pub fn bf_syscall_opcode_nosig(rax: bsl::SafeU64) -> bsl::SafeU64 { return rax & BF_SYSCALL_OPCODE_NOSIG_MASK; } @@ -217,8 +217,8 @@ pub fn bf_syscall_opcode_nosig(rax: u64) -> u64 { mod test_bf_syscall_opcode_nosig { #[test] fn test_bf_syscall_opcode_nosig() { - let syscall: u64 = 0x1234567890ABCDEF; - let expected: u64 = 0x0000000090AB0000; + let syscall: bsl::SafeU64 = bsl::SafeU64::new(0x1234567890ABCDEF); + let expected: bsl::SafeU64 = bsl::SafeU64::new(0x0000000090AB0000); assert_eq!(super::bf_syscall_opcode_nosig(syscall), expected); } } @@ -230,7 +230,7 @@ mod test_bf_syscall_opcode_nosig { /// @param rax n/a /// @return n/a /// -pub fn bf_syscall_index(rax: u64) -> u64 { +pub fn bf_syscall_index(rax: bsl::SafeU64) -> bsl::SafeU64 { return rax & BF_SYSCALL_INDEX_MASK; } @@ -238,27 +238,27 @@ pub fn bf_syscall_index(rax: u64) -> u64 { mod test_bf_syscall_index { #[test] fn test_bf_syscall_index() { - let syscall: u64 = 0x1234567890ABCDEF; - let expected: u64 = 0x000000000000CDEF; + let syscall: bsl::SafeU64 = bsl::SafeU64::new(0x1234567890ABCDEF); + let expected: bsl::SafeU64 = bsl::SafeU64::new(0x000000000000CDEF); assert_eq!(super::bf_syscall_index(syscall), expected); } } -// ------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- // Specification IDs -// ------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- /// @brief Defines the ID for version #1 of this spec -pub const BF_SPEC_ID1_VAL: u32 = 0x31236642; +pub const BF_SPEC_ID1_VAL: bsl::SafeU32 = bsl::SafeU32::new(0x31236642); /// @brief Defines the mask for checking support for version #1 of this spec -pub const BF_SPEC_ID1_MASK: u32 = 0x2; +pub const BF_SPEC_ID1_MASK: bsl::SafeU32 = bsl::SafeU32::new(0x2); /// @brief Defines all versions supported -pub const BF_ALL_SPECS_SUPPORTED_VAL: u32 = 0x2; +pub const BF_ALL_SPECS_SUPPORTED_VAL: bsl::SafeU32 = bsl::SafeU32::new(0x2); /// @brief Defines an invalid version -pub const BF_INVALID_VERSION: u32 = 0x80000000; +pub const BF_INVALID_VERSION: bsl::SafeU32 = bsl::SafeU32::new(0x80000000); /// /// @brief n/a @@ -267,7 +267,7 @@ pub const BF_INVALID_VERSION: u32 = 0x80000000; /// @param version n/a /// @return n/a /// -pub fn bf_is_spec1_supported(version: u32) -> bool { +pub fn bf_is_spec1_supported(version: bsl::SafeU32) -> bool { return (version & BF_SPEC_ID1_MASK) != 0; } @@ -275,241 +275,253 @@ pub fn bf_is_spec1_supported(version: u32) -> bool { mod test_bf_is_spec1_supported { #[test] fn test_bf_is_spec1_supported() { - let ver1: u32 = 0x2; - let ver2: u32 = 0x80000000; + let ver1: bsl::SafeU32 = 0x2; + let ver2: bsl::SafeU32 = 0x80000000; assert!(super::bf_is_spec1_supported(ver1)); assert!(!super::bf_is_spec1_supported(ver2)); } } -// ------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- // Syscall Opcodes - Control Support -// ------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- /// @brief Defines the syscall opcode for bf_control_op -pub const BF_CONTROL_OP_VAL: u64 = 0x6642000000000000; +pub const BF_CONTROL_OP_VAL: bsl::SafeU64 = bsl::SafeU64::new(0x6642000000000000); /// @brief Defines the syscall opcode for bf_control_op (nosig) -pub const BF_CONTROL_OP_NOSIG_VAL: u64 = 0x0000000000000000; +pub const BF_CONTROL_OP_NOSIG_VAL: bsl::SafeU64 = bsl::SafeU64::new(0x0000000000000000); -// ------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- // Syscall Opcodes - Handle Support -// ------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- /// @brief Defines the syscall opcode for bf_handle_op -pub const BF_HANDLE_OP_VAL: u64 = 0x6642000000010000; +pub const BF_HANDLE_OP_VAL: bsl::SafeU64 = bsl::SafeU64::new(0x6642000000010000); /// @brief Defines the syscall opcode for bf_handle_op (nosig) -pub const BF_HANDLE_OP_NOSIG_VAL: u64 = 0x0000000000010000; +pub const BF_HANDLE_OP_NOSIG_VAL: bsl::SafeU64 = bsl::SafeU64::new(0x0000000000010000); -// ------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- // Syscall Opcodes - Debug Support -// ------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- /// @brief Defines the syscall opcode for bf_debug_op -pub const BF_DEBUG_OP_VAL: u64 = 0x6642000000020000; +pub const BF_DEBUG_OP_VAL: bsl::SafeU64 = bsl::SafeU64::new(0x6642000000020000); /// @brief Defines the syscall opcode for bf_debug_op (nosig) -pub const BF_DEBUG_OP_NOSIG_VAL: u64 = 0x00000000000020000; +pub const BF_DEBUG_OP_NOSIG_VAL: bsl::SafeU64 = bsl::SafeU64::new(0x00000000000020000); -// ------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- // Syscall Opcodes - Callback Support -// ------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- /// @brief Defines the syscall opcode for bf_callback_op -pub const BF_CALLBACK_OP_VAL: u64 = 0x6642000000030000; +pub const BF_CALLBACK_OP_VAL: bsl::SafeU64 = bsl::SafeU64::new(0x6642000000030000); /// @brief Defines the syscall opcode for bf_callback_op (nosig) -pub const BF_CALLBACK_OP_NOSIG_VAL: u64 = 0x0000000000030000; +pub const BF_CALLBACK_OP_NOSIG_VAL: bsl::SafeU64 = bsl::SafeU64::new(0x0000000000030000); -// ------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- // Syscall Opcodes - VM Support -// ------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- /// @brief Defines the syscall opcode for bf_vm_op -pub const BF_VM_OP_VAL: u64 = 0x6642000000040000; +pub const BF_VM_OP_VAL: bsl::SafeU64 = bsl::SafeU64::new(0x6642000000040000); /// @brief Defines the syscall opcode for bf_vm_op (nosig) -pub const BF_VM_OP_NOSIG_VAL: u64 = 0x0000000000040000; +pub const BF_VM_OP_NOSIG_VAL: bsl::SafeU64 = bsl::SafeU64::new(0x0000000000040000); -// ------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- // Syscall Opcodes - VP Support -// ------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- /// @brief Defines the syscall opcode for bf_vp_op -pub const BF_VP_OP_VAL: u64 = 0x6642000000050000; +pub const BF_VP_OP_VAL: bsl::SafeU64 = bsl::SafeU64::new(0x6642000000050000); /// @brief Defines the syscall opcode for bf_vp_op (nosig) -pub const BF_VP_OP_NOSIG_VAL: u64 = 0x0000000000050000; +pub const BF_VP_OP_NOSIG_VAL: bsl::SafeU64 = bsl::SafeU64::new(0x0000000000050000); -// ------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- // Syscall Opcodes - VS Support -// ------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- /// @brief Defines the syscall opcode for bf_vs_op -pub const BF_VS_OP_VAL: u64 = 0x6642000000060000; +pub const BF_VS_OP_VAL: bsl::SafeU64 = bsl::SafeU64::new(0x6642000000060000); /// @brief Defines the syscall opcode for bf_vs_op (nosig) -pub const BF_VS_OP_NOSIG_VAL: u64 = 0x0000000000060000; +pub const BF_VS_OP_NOSIG_VAL: bsl::SafeU64 = bsl::SafeU64::new(0x0000000000060000); -// ------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- // Syscall Opcodes - Intrinsic Support -// ------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- /// @brief Defines the syscall opcode for bf_intrinsic_op -pub const BF_INTRINSIC_OP_VAL: u64 = 0x6642000000070000; +pub const BF_INTRINSIC_OP_VAL: bsl::SafeU64 = bsl::SafeU64::new(0x6642000000070000); /// @brief Defines the syscall opcode for bf_intrinsic_op (nosig) -pub const BF_INTRINSIC_OP_NOSIG_VAL: u64 = 0x0000000000070000; +pub const BF_INTRINSIC_OP_NOSIG_VAL: bsl::SafeU64 = bsl::SafeU64::new(0x0000000000070000); -// ------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- // Syscall Opcodes - Mem Support -// ------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- /// @brief Defines the syscall opcode for bf_mem_op -pub const BF_MEM_OP_VAL: u64 = 0x6642000000080000; +pub const BF_MEM_OP_VAL: bsl::SafeU64 = bsl::SafeU64::new(0x6642000000080000); /// @brief Defines the syscall opcode for bf_mem_op (nosig) -pub const BF_MEM_OP_NOSIG_VAL: u64 = 0x0000000000080000; +pub const BF_MEM_OP_NOSIG_VAL: bsl::SafeU64 = bsl::SafeU64::new(0x0000000000080000); -// ------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- // TLS Offsets -// ------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- /// @brief stores the offset for rax -pub const TLS_OFFSET_RAX: u64 = 0x800; +pub const TLS_OFFSET_RAX: bsl::SafeU64 = bsl::SafeU64::new(0x800); /// @brief stores the offset for rbx -pub const TLS_OFFSET_RBX: u64 = 0x808; +pub const TLS_OFFSET_RBX: bsl::SafeU64 = bsl::SafeU64::new(0x808); /// @brief stores the offset for rcx -pub const TLS_OFFSET_RCX: u64 = 0x810; +pub const TLS_OFFSET_RCX: bsl::SafeU64 = bsl::SafeU64::new(0x810); /// @brief stores the offset for rdx -pub const TLS_OFFSET_RDX: u64 = 0x818; +pub const TLS_OFFSET_RDX: bsl::SafeU64 = bsl::SafeU64::new(0x818); /// @brief stores the offset for rbp -pub const TLS_OFFSET_RBP: u64 = 0x820; +pub const TLS_OFFSET_RBP: bsl::SafeU64 = bsl::SafeU64::new(0x820); /// @brief stores the offset for rsi -pub const TLS_OFFSET_RSI: u64 = 0x828; +pub const TLS_OFFSET_RSI: bsl::SafeU64 = bsl::SafeU64::new(0x828); /// @brief stores the offset for rdi -pub const TLS_OFFSET_RDI: u64 = 0x830; +pub const TLS_OFFSET_RDI: bsl::SafeU64 = bsl::SafeU64::new(0x830); /// @brief stores the offset for r8 -pub const TLS_OFFSET_R8: u64 = 0x838; +pub const TLS_OFFSET_R8: bsl::SafeU64 = bsl::SafeU64::new(0x838); /// @brief stores the offset for r9 -pub const TLS_OFFSET_R9: u64 = 0x840; +pub const TLS_OFFSET_R9: bsl::SafeU64 = bsl::SafeU64::new(0x840); /// @brief stores the offset for r10 -pub const TLS_OFFSET_R10: u64 = 0x848; +pub const TLS_OFFSET_R10: bsl::SafeU64 = bsl::SafeU64::new(0x848); /// @brief stores the offset for r11 -pub const TLS_OFFSET_R11: u64 = 0x850; +pub const TLS_OFFSET_R11: bsl::SafeU64 = bsl::SafeU64::new(0x850); /// @brief stores the offset for r12 -pub const TLS_OFFSET_R12: u64 = 0x858; +pub const TLS_OFFSET_R12: bsl::SafeU64 = bsl::SafeU64::new(0x858); /// @brief stores the offset for r13 -pub const TLS_OFFSET_R13: u64 = 0x860; +pub const TLS_OFFSET_R13: bsl::SafeU64 = bsl::SafeU64::new(0x860); /// @brief stores the offset for r14 -pub const TLS_OFFSET_R14: u64 = 0x868; +pub const TLS_OFFSET_R14: bsl::SafeU64 = bsl::SafeU64::new(0x868); /// @brief stores the offset for r15 -pub const TLS_OFFSET_R15: u64 = 0x870; +pub const TLS_OFFSET_R15: bsl::SafeU64 = bsl::SafeU64::new(0x870); /// @brief stores the offset of the active extid -pub const TLS_OFFSET_ACTIVE_EXTID: u64 = 0xFF0; +pub const TLS_OFFSET_ACTIVE_EXTID: bsl::SafeU64 = bsl::SafeU64::new(0xFF0); /// @brief stores the offset of the active vmid -pub const TLS_OFFSET_ACTIVE_VMID: u64 = 0xFF2; +pub const TLS_OFFSET_ACTIVE_VMID: bsl::SafeU64 = bsl::SafeU64::new(0xFF2); /// @brief stores the offset of the active vpid -pub const TLS_OFFSET_ACTIVE_VPID: u64 = 0xFF4; +pub const TLS_OFFSET_ACTIVE_VPID: bsl::SafeU64 = bsl::SafeU64::new(0xFF4); /// @brief stores the offset of the active vsid -pub const TLS_OFFSET_ACTIVE_VSID: u64 = 0xFF6; +pub const TLS_OFFSET_ACTIVE_VSID: bsl::SafeU64 = bsl::SafeU64::new(0xFF6); /// @brief stores the offset of the active ppid -pub const TLS_OFFSET_ACTIVE_PPID: u64 = 0xFF8; +pub const TLS_OFFSET_ACTIVE_PPID: bsl::SafeU64 = bsl::SafeU64::new(0xFF8); /// @brief stores the number of PPs that are online -pub const TLS_OFFSET_ONLINE_PPS: u64 = 0xFFA; +pub const TLS_OFFSET_ONLINE_PPS: bsl::SafeU64 = bsl::SafeU64::new(0xFFA); -// ------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- // Hypercall Related Constants -// ------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- /// @brief Defines an invalid handle -pub const BF_INVALID_HANDLE: u64 = 0xFFFFFFFFFFFFFFFF; +pub const BF_INVALID_HANDLE: bsl::SafeU64 = bsl::SafeU64::new(0xFFFFFFFFFFFFFFFF); -// ------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- // Syscall Indexes -// ------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- /// @brief Defines the index for bf_control_op_exit -pub const BF_CONTROL_OP_EXIT_IDX_VAL: u64 = 0x0000000000000000; +pub const BF_CONTROL_OP_EXIT_IDX_VAL: bsl::SafeU64 = bsl::SafeU64::new(0x0000000000000000); /// @brief Defines the index for bf_control_op_wait -pub const BF_CONTROL_OP_WAIT_IDX_VAL: u64 = 0x0000000000000001; +pub const BF_CONTROL_OP_WAIT_IDX_VAL: bsl::SafeU64 = bsl::SafeU64::new(0x0000000000000001); +/// @brief Defines the index for bf_control_op_again +pub const BF_CONTROL_OP_AGAIN_IDX_VAL: bsl::SafeU64 = bsl::SafeU64::new(0x0000000000000002); /// @brief Defines the index for bf_handle_op_open_handle -pub const BF_HANDLE_OP_OPEN_HANDLE_IDX_VAL: u64 = 0x0000000000000000; +pub const BF_HANDLE_OP_OPEN_HANDLE_IDX_VAL: bsl::SafeU64 = bsl::SafeU64::new(0x0000000000000000); /// @brief Defines the index for bf_handle_op_close_handle -pub const BF_HANDLE_OP_CLOSE_HANDLE_IDX_VAL: u64 = 0x0000000000000001; +pub const BF_HANDLE_OP_CLOSE_HANDLE_IDX_VAL: bsl::SafeU64 = bsl::SafeU64::new(0x0000000000000001); /// @brief Defines the index for bf_debug_op_out -pub const BF_DEBUG_OP_OUT_IDX_VAL: u64 = 0x0000000000000000; +pub const BF_DEBUG_OP_OUT_IDX_VAL: bsl::SafeU64 = bsl::SafeU64::new(0x0000000000000000); /// @brief Defines the index for bf_debug_op_dump_vm -pub const BF_DEBUG_OP_DUMP_VM_IDX_VAL: u64 = 0x0000000000000001; +pub const BF_DEBUG_OP_DUMP_VM_IDX_VAL: bsl::SafeU64 = bsl::SafeU64::new(0x0000000000000001); /// @brief Defines the index for bf_debug_op_dump_vp -pub const BF_DEBUG_OP_DUMP_VP_IDX_VAL: u64 = 0x0000000000000002; +pub const BF_DEBUG_OP_DUMP_VP_IDX_VAL: bsl::SafeU64 = bsl::SafeU64::new(0x0000000000000002); /// @brief Defines the index for bf_debug_op_dump_vs -pub const BF_DEBUG_OP_DUMP_VS_IDX_VAL: u64 = 0x0000000000000003; +pub const BF_DEBUG_OP_DUMP_VS_IDX_VAL: bsl::SafeU64 = bsl::SafeU64::new(0x0000000000000003); /// @brief Defines the index for bf_debug_op_dump_vmexit_log -pub const BF_DEBUG_OP_DUMP_VMEXIT_LOG_IDX_VAL: u64 = 0x0000000000000004; +pub const BF_DEBUG_OP_DUMP_VMEXIT_LOG_IDX_VAL: bsl::SafeU64 = bsl::SafeU64::new(0x0000000000000004); /// @brief Defines the index for bf_debug_op_write_c -pub const BF_DEBUG_OP_WRITE_C_IDX_VAL: u64 = 0x0000000000000005; +pub const BF_DEBUG_OP_WRITE_C_IDX_VAL: bsl::SafeU64 = bsl::SafeU64::new(0x0000000000000005); /// @brief Defines the index for bf_debug_op_write_str -pub const BF_DEBUG_OP_WRITE_STR_IDX_VAL: u64 = 0x0000000000000006; +pub const BF_DEBUG_OP_WRITE_STR_IDX_VAL: bsl::SafeU64 = bsl::SafeU64::new(0x0000000000000006); /// @brief Defines the index for bf_debug_op_dump_ext -pub const BF_DEBUG_OP_DUMP_EXT_IDX_VAL: u64 = 0x0000000000000007; +pub const BF_DEBUG_OP_DUMP_EXT_IDX_VAL: bsl::SafeU64 = bsl::SafeU64::new(0x0000000000000007); /// @brief Defines the index for bf_debug_op_dump_page_pool -pub const BF_DEBUG_OP_DUMP_PAGE_POOL_IDX_VAL: u64 = 0x0000000000000008; +pub const BF_DEBUG_OP_DUMP_PAGE_POOL_IDX_VAL: bsl::SafeU64 = bsl::SafeU64::new(0x0000000000000008); /// @brief Defines the index for bf_debug_op_dump_huge_pool -pub const BF_DEBUG_OP_DUMP_HUGE_POOL_IDX_VAL: u64 = 0x0000000000000009; +pub const BF_DEBUG_OP_DUMP_HUGE_POOL_IDX_VAL: bsl::SafeU64 = bsl::SafeU64::new(0x0000000000000009); /// @brief Defines the index for bf_callback_op_register_bootstrap -pub const BF_CALLBACK_OP_REGISTER_BOOTSTRAP_IDX_VAL: u64 = 0x0000000000000000; +pub const BF_CALLBACK_OP_REGISTER_BOOTSTRAP_IDX_VAL: bsl::SafeU64 = + bsl::SafeU64::new(0x0000000000000000); /// @brief Defines the index for bf_callback_op_register_vmexit -pub const BF_CALLBACK_OP_REGISTER_VMEXIT_IDX_VAL: u64 = 0x0000000000000001; +pub const BF_CALLBACK_OP_REGISTER_VMEXIT_IDX_VAL: bsl::SafeU64 = + bsl::SafeU64::new(0x0000000000000001); /// @brief Defines the index for bf_callback_op_register_fail -pub const BF_CALLBACK_OP_REGISTER_FAIL_IDX_VAL: u64 = 0x0000000000000002; +pub const BF_CALLBACK_OP_REGISTER_FAIL_IDX_VAL: bsl::SafeU64 = + bsl::SafeU64::new(0x0000000000000002); /// @brief Defines the index for bf_vm_op_create_vm -pub const BF_VM_OP_CREATE_VM_IDX_VAL: u64 = 0x0000000000000000; +pub const BF_VM_OP_CREATE_VM_IDX_VAL: bsl::SafeU64 = bsl::SafeU64::new(0x0000000000000000); /// @brief Defines the index for bf_vm_op_destroy_vm -pub const BF_VM_OP_DESTROY_VM_IDX_VAL: u64 = 0x0000000000000001; +pub const BF_VM_OP_DESTROY_VM_IDX_VAL: bsl::SafeU64 = bsl::SafeU64::new(0x0000000000000001); /// @brief Defines the index for bf_vm_op_map_direct -pub const BF_VM_OP_MAP_DIRECT_IDX_VAL: u64 = 0x0000000000000002; +pub const BF_VM_OP_MAP_DIRECT_IDX_VAL: bsl::SafeU64 = bsl::SafeU64::new(0x0000000000000002); /// @brief Defines the index for bf_vm_op_unmap_direct -pub const BF_VM_OP_UNMAP_DIRECT_IDX_VAL: u64 = 0x0000000000000003; +pub const BF_VM_OP_UNMAP_DIRECT_IDX_VAL: bsl::SafeU64 = bsl::SafeU64::new(0x0000000000000003); /// @brief Defines the index for bf_vm_op_unmap_direct_broadcast -pub const BF_VM_OP_UNMAP_DIRECT_BROADCAST_IDX_VAL: u64 = 0x0000000000000004; +pub const BF_VM_OP_UNMAP_DIRECT_BROADCAST_IDX_VAL: bsl::SafeU64 = + bsl::SafeU64::new(0x0000000000000004); +/// @brief Defines the index for bf_vm_op_tlb_flush +pub const BF_VM_OP_TLB_FLUSH_IDX_VAL: bsl::SafeU64 = bsl::SafeU64::new(0x0000000000000005); /// @brief Defines the index for bf_vp_op_create_vp -pub const BF_VP_OP_CREATE_VP_IDX_VAL: u64 = 0x0000000000000000; +pub const BF_VP_OP_CREATE_VP_IDX_VAL: bsl::SafeU64 = bsl::SafeU64::new(0x0000000000000000); /// @brief Defines the index for bf_vp_op_destroy_vp -pub const BF_VP_OP_DESTROY_VP_IDX_VAL: u64 = 0x0000000000000001; +pub const BF_VP_OP_DESTROY_VP_IDX_VAL: bsl::SafeU64 = bsl::SafeU64::new(0x0000000000000001); /// @brief Defines the index for bf_vs_op_create_vs -pub const BF_VS_OP_CREATE_VS_IDX_VAL: u64 = 0x0000000000000000; +pub const BF_VS_OP_CREATE_VS_IDX_VAL: bsl::SafeU64 = bsl::SafeU64::new(0x0000000000000000); /// @brief Defines the index for bf_vs_op_destroy_vs -pub const BF_VS_OP_DESTROY_VS_IDX_VAL: u64 = 0x0000000000000001; +pub const BF_VS_OP_DESTROY_VS_IDX_VAL: bsl::SafeU64 = bsl::SafeU64::new(0x0000000000000001); /// @brief Defines the index for bf_vs_op_init_as_root -pub const BF_VS_OP_INIT_AS_ROOT_IDX_VAL: u64 = 0x0000000000000002; +pub const BF_VS_OP_INIT_AS_ROOT_IDX_VAL: bsl::SafeU64 = bsl::SafeU64::new(0x0000000000000002); /// @brief Defines the index for bf_vs_op_read_reg -pub const BF_VS_OP_READ_IDX_VAL: u64 = 0x0000000000000003; +pub const BF_VS_OP_READ_IDX_VAL: bsl::SafeU64 = bsl::SafeU64::new(0x0000000000000003); /// @brief Defines the index for bf_vs_op_write_reg -pub const BF_VS_OP_WRITE_IDX_VAL: u64 = 0x0000000000000004; +pub const BF_VS_OP_WRITE_IDX_VAL: bsl::SafeU64 = bsl::SafeU64::new(0x0000000000000004); /// @brief Defines the index for bf_vs_op_run -pub const BF_VS_OP_RUN_IDX_VAL: u64 = 0x0000000000000005; +pub const BF_VS_OP_RUN_IDX_VAL: bsl::SafeU64 = bsl::SafeU64::new(0x0000000000000005); /// @brief Defines the index for bf_vs_op_run_current -pub const BF_VS_OP_RUN_CURRENT_IDX_VAL: u64 = 0x0000000000000006; +pub const BF_VS_OP_RUN_CURRENT_IDX_VAL: bsl::SafeU64 = bsl::SafeU64::new(0x0000000000000006); /// @brief Defines the index for bf_vs_op_advance_ip_and_run -pub const BF_VS_OP_ADVANCE_IP_AND_RUN_IDX_VAL: u64 = 0x0000000000000007; +pub const BF_VS_OP_ADVANCE_IP_AND_RUN_IDX_VAL: bsl::SafeU64 = bsl::SafeU64::new(0x0000000000000007); /// @brief Defines the index for bf_vs_op_advance_ip_and_run_current -pub const BF_VS_OP_ADVANCE_IP_AND_RUN_CURRENT_IDX_VAL: u64 = 0x0000000000000008; +pub const BF_VS_OP_ADVANCE_IP_AND_RUN_CURRENT_IDX_VAL: bsl::SafeU64 = + bsl::SafeU64::new(0x0000000000000008); /// @brief Defines the index for bf_vs_op_promote -pub const BF_VS_OP_PROMOTE_IDX_VAL: u64 = 0x0000000000000009; +pub const BF_VS_OP_PROMOTE_IDX_VAL: bsl::SafeU64 = bsl::SafeU64::new(0x0000000000000009); /// @brief Defines the index for bf_vs_op_clear -pub const BF_VS_OP_CLEAR_IDX_VAL: u64 = 0x000000000000000A; +pub const BF_VS_OP_CLEAR_IDX_VAL: bsl::SafeU64 = bsl::SafeU64::new(0x000000000000000A); /// @brief Defines the index for bf_vs_op_migrate -pub const BF_VS_OP_MIGRATE_IDX_VAL: u64 = 0x000000000000000B; +pub const BF_VS_OP_MIGRATE_IDX_VAL: bsl::SafeU64 = bsl::SafeU64::new(0x000000000000000B); /// @brief Defines the index for bf_vs_op_set_active -pub const BF_VS_OP_SET_ACTIVE_IDX_VAL: u64 = 0x000000000000000C; +pub const BF_VS_OP_SET_ACTIVE_IDX_VAL: bsl::SafeU64 = bsl::SafeU64::new(0x000000000000000C); /// @brief Defines the index for bf_vs_op_advance_ip_and_set_active -pub const BF_VS_OP_ADVANCE_IP_AND_SET_ACTIVE_IDX_VAL: u64 = 0x000000000000000D; +pub const BF_VS_OP_ADVANCE_IP_AND_SET_ACTIVE_IDX_VAL: bsl::SafeU64 = + bsl::SafeU64::new(0x000000000000000D); +/// @brief Defines the index for bf_vs_op_tlb_flush +pub const BF_VS_OP_TLB_FLUSH_IDX_VAL: bsl::SafeU64 = bsl::SafeU64::new(0x000000000000000E); /// @brief Defines the index for bf_intrinsic_op_rdmsr -pub const BF_INTRINSIC_OP_RDMSR_IDX_VAL: u64 = 0x0000000000000000; +pub const BF_INTRINSIC_OP_RDMSR_IDX_VAL: bsl::SafeU64 = bsl::SafeU64::new(0x0000000000000000); /// @brief Defines the index for bf_intrinsic_op_wrmsr -pub const BF_INTRINSIC_OP_WRMSR_IDX_VAL: u64 = 0x0000000000000001; +pub const BF_INTRINSIC_OP_WRMSR_IDX_VAL: bsl::SafeU64 = bsl::SafeU64::new(0x0000000000000001); /// @brief Defines the index for bf_mem_op_alloc_page -pub const BF_MEM_OP_ALLOC_PAGE_IDX_VAL: u64 = 0x0000000000000000; +pub const BF_MEM_OP_ALLOC_PAGE_IDX_VAL: bsl::SafeU64 = bsl::SafeU64::new(0x0000000000000000); /// @brief Defines the index for bf_mem_op_alloc_huge -pub const BF_MEM_OP_ALLOC_HUGE_IDX_VAL: u64 = 0x0000000000000002; +pub const BF_MEM_OP_ALLOC_HUGE_IDX_VAL: bsl::SafeU64 = bsl::SafeU64::new(0x0000000000000002); diff --git a/syscall/include/types.rs b/syscall/include/bf_types.rs similarity index 97% rename from syscall/include/types.rs rename to syscall/include/bf_types.rs index 1c9151b3..ec675f21 100644 --- a/syscall/include/types.rs +++ b/syscall/include/bf_types.rs @@ -27,4 +27,4 @@ // ------------------------------------------------------------------------- /// @brief Defines the type used for returning status from a function -pub type BfStatusT = u64; +pub type BfStatusT = bsl::SafeU64; diff --git a/syscall/include/x64/amd/bf_reg_t.rs b/syscall/include/x64/amd/bf_reg_t.rs index 974c60c3..0533a807 100644 --- a/syscall/include/x64/amd/bf_reg_t.rs +++ b/syscall/include/x64/amd/bf_reg_t.rs @@ -22,231 +22,247 @@ /// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE /// SOFTWARE. +/// @brief defines an unsupported register +pub const BF_REG_T_UNSUPPORTED: u64 = 0; /// @brief defines the rbx register -const BF_REG_T_RBX:u64 = 1; +pub const BF_REG_T_RBX: u64 = 1; /// @brief defines the rcx register -const BF_REG_T_RCX:u64 = 2; +pub const BF_REG_T_RCX: u64 = 2; /// @brief defines the rdx register -const BF_REG_T_RDX:u64 = 3; +pub const BF_REG_T_RDX: u64 = 3; /// @brief defines the rbp register -const BF_REG_T_RBP:u64 = 4; +pub const BF_REG_T_RBP: u64 = 4; /// @brief defines the rsi register -const BF_REG_T_RSI:u64 = 5; +pub const BF_REG_T_RSI: u64 = 5; /// @brief defines the rdi register -const BF_REG_T_RDI:u64 = 6; +pub const BF_REG_T_RDI: u64 = 6; /// @brief defines the r8 register -const BF_REG_T_R8:u64 = 7; +pub const BF_REG_T_R8: u64 = 7; /// @brief defines the r9 register -const BF_REG_T_R9:u64 = 8; +pub const BF_REG_T_R9: u64 = 8; /// @brief defines the r10 register -const BF_REG_T_R10:u64 = 9; +pub const BF_REG_T_R10: u64 = 9; /// @brief defines the r11 register -const BF_REG_T_R11:u64 = 10; +pub const BF_REG_T_R11: u64 = 10; /// @brief defines the r12 register -const BF_REG_T_R12:u64 = 11; +pub const BF_REG_T_R12: u64 = 11; /// @brief defines the r13 register -const BF_REG_T_R13:u64 = 12; +pub const BF_REG_T_R13: u64 = 12; /// @brief defines the r14 register -const BF_REG_T_R14:u64 = 13; +pub const BF_REG_T_R14: u64 = 13; /// @brief defines the r15 register -const BF_REG_T_R15:u64 = 14; -/// @brief defines the intercept_cr_read register in the VMCB -const BF_REG_T_INTERCEPT_CR_READ:u64 = 15; -/// @brief defines the intercept_cr_write register in the VMCB -const BF_REG_T_INTERCEPT_CR_WRITE:u64 = 16; -/// @brief defines the intercept_dr_read register in the VMCB -const BF_REG_T_INTERCEPT_DR_READ:u64 = 17; -/// @brief defines the intercept_dr_write register in the VMCB -const BF_REG_T_INTERCEPT_DR_WRITE:u64 = 18; -/// @brief defines the intercept_exception register in the VMCB -const BF_REG_T_INTERCEPT_EXCEPTION:u64 = 19; -/// @brief defines the intercept_instruction1 register in the VMCB -const BF_REG_T_INTERCEPT_INSTRUCTION1:u64 = 20; -/// @brief defines the intercept_instruction2 register in the VMCB -const BF_REG_T_INTERCEPT_INSTRUCTION2:u64 = 21; -/// @brief defines the intercept_instruction3 register in the VMCB -const BF_REG_T_INTERCEPT_INSTRUCTION3:u64 = 22; -/// @brief defines the pause_filter_threshold register in the VMCB -const BF_REG_T_PAUSE_FILTER_THRESHOLD:u64 = 23; -/// @brief defines the pause_filter_count register in the VMCB -const BF_REG_T_PAUSE_FILTER_COUNT:u64 = 24; -/// @brief defines the iopm_base_pa register in the VMCB -const BF_REG_T_IOPM_BASE_PA:u64 = 25; -/// @brief defines the msrpm_base_pa register in the VMCB -const BF_REG_T_MSRPM_BASE_PA:u64 = 26; -/// @brief defines the tsc_offset register in the VMCB -const BF_REG_T_TSC_OFFSET:u64 = 27; -/// @brief defines the guest_asid register in the VMCB -const BF_REG_T_GUEST_ASID:u64 = 28; -/// @brief defines the tlb_control register in the VMCB -const BF_REG_T_TLB_CONTROL:u64 = 29; -/// @brief defines the virtual_interrupt_a register in the VMCB -const BF_REG_T_VIRTUAL_INTERRUPT_A:u64 = 30; -/// @brief defines the virtual_interrupt_b register in the VMCB -const BF_REG_T_VIRTUAL_INTERRUPT_B:u64 = 31; -/// @brief defines the exitcode register in the VMCB -const BF_REG_T_EXITCODE:u64 = 32; -/// @brief defines the exitinfo1 register in the VMCB -const BF_REG_T_EXITINFO1:u64 = 33; -/// @brief defines the exitinfo2 register in the VMCB -const BF_REG_T_EXITINFO2:u64 = 34; -/// @brief defines the exitininfo register in the VMCB -const BF_REG_T_EXITININFO:u64 = 35; -/// @brief defines the ctls1 register in the VMCB -const BF_REG_T_CTLS1:u64 = 36; -/// @brief defines the avic_apic_bar register in the VMCB -const BF_REG_T_AVIC_APIC_BAR:u64 = 37; -/// @brief defines the guest_pa_of_ghcb register in the VMCB -const BF_REG_T_GUEST_PA_OF_GHCB:u64 = 38; -/// @brief defines the eventinj register in the VMCB -const BF_REG_T_EVENTINJ:u64 = 39; -/// @brief defines the n_cr3 register in the VMCB -const BF_REG_T_N_CR3:u64 = 40; -/// @brief defines the ctls2 register in the VMCB -const BF_REG_T_CTLS2:u64 = 41; -/// @brief defines the vmcb_clean_bits register in the VMCB -const BF_REG_T_VMCB_CLEAN_BITS:u64 = 42; -/// @brief defines the nrip register in the VMCB -const BF_REG_T_NRIP:u64 = 43; -/// @brief defines the number_of_bytes_fetched register in the VMCB -const BF_REG_T_NUMBER_OF_BYTES_FETCHED:u64 = 44; -/// @brief defines the avic_apic_backing_page_ptr register in the VMCB -const BF_REG_T_AVIC_APIC_BACKING_PAGE_PTR:u64 = 45; -/// @brief defines the avic_logical_table_ptr register in the VMCB -const BF_REG_T_AVIC_LOGICAL_TABLE_PTR:u64 = 46; -/// @brief defines the avic_physical_table_ptr register in the VMCB -const BF_REG_T_AVIC_PHYSICAL_TABLE_PTR:u64 = 47; -/// @brief defines the vmsa_ptr register in the VMCB -const BF_REG_T_VMSA_PTR:u64 = 48; -/// @brief defines the es_selector register in the VMCB -const BF_REG_T_ES_SELECTOR:u64 = 49; -/// @brief defines the es_attrib register in the VMCB -const BF_REG_T_ES_ATTRIB:u64 = 50; -/// @brief defines the es_limit register in the VMCB -const BF_REG_T_ES_LIMIT:u64 = 51; -/// @brief defines the es_base register in the VMCB -const BF_REG_T_ES_BASE:u64 = 52; -/// @brief defines the cs_selector register in the VMCB -const BF_REG_T_CS_SELECTOR:u64 = 53; -/// @brief defines the cs_attrib register in the VMCB -const BF_REG_T_CS_ATTRIB:u64 = 54; -/// @brief defines the cs_limit register in the VMCB -const BF_REG_T_CS_LIMIT:u64 = 55; -/// @brief defines the cs_base register in the VMCB -const BF_REG_T_CS_BASE:u64 = 56; -/// @brief defines the ss_selector register in the VMCB -const BF_REG_T_SS_SELECTOR:u64 = 57; -/// @brief defines the ss_attrib register in the VMCB -const BF_REG_T_SS_ATTRIB:u64 = 58; -/// @brief defines the ss_limit register in the VMCB -const BF_REG_T_SS_LIMIT:u64 = 59; -/// @brief defines the ss_base register in the VMCB -const BF_REG_T_SS_BASE:u64 = 60; -/// @brief defines the ds_selector register in the VMCB -const BF_REG_T_DS_SELECTOR:u64 = 61; -/// @brief defines the ds_attrib register in the VMCB -const BF_REG_T_DS_ATTRIB:u64 = 62; -/// @brief defines the ds_limit register in the VMCB -const BF_REG_T_DS_LIMIT:u64 = 63; -/// @brief defines the ds_base register in the VMCB -const BF_REG_T_DS_BASE:u64 = 64; -/// @brief defines the fs_selector register in the VMCB -const BF_REG_T_FS_SELECTOR:u64 = 65; -/// @brief defines the fs_attrib register in the VMCB -const BF_REG_T_FS_ATTRIB:u64 = 66; -/// @brief defines the fs_limit register in the VMCB -const BF_REG_T_FS_LIMIT:u64 = 67; -/// @brief defines the fs_base register in the VMCB -const BF_REG_T_FS_BASE:u64 = 68; -/// @brief defines the gs_selector register in the VMCB -const BF_REG_T_GS_SELECTOR:u64 = 69; -/// @brief defines the gs_attrib register in the VMCB -const BF_REG_T_GS_ATTRIB:u64 = 70; -/// @brief defines the gs_limit register in the VMCB -const BF_REG_T_GS_LIMIT:u64 = 71; -/// @brief defines the gs_base register in the VMCB -const BF_REG_T_GS_BASE:u64 = 72; -/// @brief defines the gdtr_selector register in the VMCB -const BF_REG_T_GDTR_SELECTOR:u64 = 73; -/// @brief defines the gdtr_attrib register in the VMCB -const BF_REG_T_GDTR_ATTRIB:u64 = 74; -/// @brief defines the gdtr_limit register in the VMCB -const BF_REG_T_GDTR_LIMIT:u64 = 75; -/// @brief defines the gdtr_base register in the VMCB -const BF_REG_T_GDTR_BASE:u64 = 76; -/// @brief defines the ldtr_selector register in the VMCB -const BF_REG_T_LDTR_SELECTOR:u64 = 77; -/// @brief defines the ldtr_attrib register in the VMCB -const BF_REG_T_LDTR_ATTRIB:u64 = 78; -/// @brief defines the ldtr_limit register in the VMCB -const BF_REG_T_LDTR_LIMIT:u64 = 79; -/// @brief defines the ldtr_base register in the VMCB -const BF_REG_T_LDTR_BASE:u64 = 80; -/// @brief defines the idtr_selector register in the VMCB -const BF_REG_T_IDTR_SELECTOR:u64 = 81; -/// @brief defines the idtr_attrib register in the VMCB -const BF_REG_T_IDTR_ATTRIB:u64 = 82; -/// @brief defines the idtr_limit register in the VMCB -const BF_REG_T_IDTR_LIMIT:u64 = 83; -/// @brief defines the idtr_base register in the VMCB -const BF_REG_T_IDTR_BASE:u64 = 84; -/// @brief defines the tr_selector register in the VMCB -const BF_REG_T_TR_SELECTOR:u64 = 85; -/// @brief defines the tr_attrib register in the VMCB -const BF_REG_T_TR_ATTRIB:u64 = 86; -/// @brief defines the tr_limit register in the VMCB -const BF_REG_T_TR_LIMIT:u64 = 87; -/// @brief defines the tr_base register in the VMCB -const BF_REG_T_TR_BASE:u64 = 88; -/// @brief defines the cpl register in the VMCB -const BF_REG_T_CPL:u64 = 89; -/// @brief defines the efer register in the VMCB -const BF_REG_T_EFER:u64 = 90; -/// @brief defines the cr4 register in the VMCB -const BF_REG_T_CR4:u64 = 91; -/// @brief defines the cr3 register in the VMCB -const BF_REG_T_CR3:u64 = 92; -/// @brief defines the cr0 register in the VMCB -const BF_REG_T_CR0:u64 = 93; -/// @brief defines the dr7 register in the VMCB -const BF_REG_T_DR7:u64 = 94; -/// @brief defines the dr6 register in the VMCB -const BF_REG_T_DR6:u64 = 95; -/// @brief defines the rflags register in the VMCB -const BF_REG_T_RFLAGS:u64 = 96; -/// @brief defines the rip register in the VMCB -const BF_REG_T_RIP:u64 = 97; -/// @brief defines the rsp register in the VMCB -const BF_REG_T_RSP:u64 = 98; -/// @brief defines the rax register in the VMCB -const BF_REG_T_RAX:u64 = 99; -/// @brief defines the star register in the VMCB -const BF_REG_T_STAR:u64 = 100; -/// @brief defines the lstar register in the VMCB -const BF_REG_T_LSTAR:u64 = 101; -/// @brief defines the cstar register in the VMCB -const BF_REG_T_CSTAR:u64 = 102; -/// @brief defines the sfmask register in the VMCB -const BF_REG_T_SFMASK:u64 = 103; -/// @brief defines the kernel_gs_base register in the VMCB -const BF_REG_T_KERNEL_GS_BASE:u64 = 104; -/// @brief defines the sysenter_cs register in the VMCB -const BF_REG_T_SYSENTER_CS:u64 = 105; -/// @brief defines the sysenter_esp register in the VMCB -const BF_REG_T_SYSENTER_ESP:u64 = 106; -/// @brief defines the sysenter_eip register in the VMCB -const BF_REG_T_SYSENTER_EIP:u64 = 107; -/// @brief defines the cr2 register in the VMCB -const BF_REG_T_CR2:u64 = 108; -/// @brief defines the g_pat register in the VMCB -const BF_REG_T_G_PAT:u64 = 109; -/// @brief defines the dbgctl register in the VMCB -const BF_REG_T_DBGCTL:u64 = 110; -/// @brief defines the br_from register in the VMCB -const BF_REG_T_BR_FROM:u64 = 112; -/// @brief defines the br_to register in the VMCB -const BF_REG_T_BR_TO:u64 = 113; -/// @brief defines the lastexcpfrom register in the VMCB -const BF_REG_T_LASTEXCPFROM:u64 = 114; -/// @brief defines the lastexcpto register in the VMCB -const BF_REG_T_LASTEXCPTO:u64 = 115; +pub const BF_REG_T_R15: u64 = 14; +/// @brief defines the intercept_cr_read register +pub const BF_REG_T_INTERCEPT_CR_READ: u64 = 15; +/// @brief defines the intercept_cr_write register +pub const BF_REG_T_INTERCEPT_CR_WRITE: u64 = 16; +/// @brief defines the intercept_dr_read register +pub const BF_REG_T_INTERCEPT_DR_READ: u64 = 17; +/// @brief defines the intercept_dr_write register +pub const BF_REG_T_INTERCEPT_DR_WRITE: u64 = 18; +/// @brief defines the intercept_exception register +pub const BF_REG_T_INTERCEPT_EXCEPTION: u64 = 19; +/// @brief defines the intercept_instruction1 register +pub const BF_REG_T_INTERCEPT_INSTRUCTION1: u64 = 20; +/// @brief defines the intercept_instruction2 register +pub const BF_REG_T_INTERCEPT_INSTRUCTION2: u64 = 21; +/// @brief defines the intercept_instruction3 register +pub const BF_REG_T_INTERCEPT_INSTRUCTION3: u64 = 22; +/// @brief defines the pause_filter_threshold register +pub const BF_REG_T_PAUSE_FILTER_THRESHOLD: u64 = 23; +/// @brief defines the pause_filter_count register +pub const BF_REG_T_PAUSE_FILTER_COUNT: u64 = 24; +/// @brief defines the iopm_base_pa register +pub const BF_REG_T_IOPM_BASE_PA: u64 = 25; +/// @brief defines the msrpm_base_pa register +pub const BF_REG_T_MSRPM_BASE_PA: u64 = 26; +/// @brief defines the tsc_offset register +pub const BF_REG_T_TSC_OFFSET: u64 = 27; +/// @brief defines the guest_asid register +pub const BF_REG_T_GUEST_ASID: u64 = 28; +/// @brief defines the tlb_control register +pub const BF_REG_T_TLB_CONTROL: u64 = 29; +/// @brief defines the virtual_interrupt_a register +pub const BF_REG_T_VIRTUAL_INTERRUPT_A: u64 = 30; +/// @brief defines the virtual_interrupt_b register +pub const BF_REG_T_VIRTUAL_INTERRUPT_B: u64 = 31; +/// @brief defines the exitcode register +pub const BF_REG_T_EXITCODE: u64 = 32; +/// @brief defines the exitinfo1 register +pub const BF_REG_T_EXITINFO1: u64 = 33; +/// @brief defines the exitinfo2 register +pub const BF_REG_T_EXITINFO2: u64 = 34; +/// @brief defines the exitininfo register +pub const BF_REG_T_EXITININFO: u64 = 35; +/// @brief defines the ctls1 register +pub const BF_REG_T_CTLS1: u64 = 36; +/// @brief defines the avic_apic_bar register +pub const BF_REG_T_AVIC_APIC_BAR: u64 = 37; +/// @brief defines the guest_pa_of_ghcb register +pub const BF_REG_T_GUEST_PA_OF_GHCB: u64 = 38; +/// @brief defines the eventinj register +pub const BF_REG_T_EVENTINJ: u64 = 39; +/// @brief defines the n_cr3 register +pub const BF_REG_T_N_CR3: u64 = 40; +/// @brief defines the ctls2 register +pub const BF_REG_T_CTLS2: u64 = 41; +/// @brief defines the vmcb_clean_bits register +pub const BF_REG_T_VMCB_CLEAN_BITS: u64 = 42; +/// @brief defines the nrip register +pub const BF_REG_T_NRIP: u64 = 43; +/// @brief defines the number_of_bytes_fetched register +pub const BF_REG_T_NUMBER_OF_BYTES_FETCHED: u64 = 44; +/// @brief defines the avic_apic_backing_page_ptr register +pub const BF_REG_T_AVIC_APIC_BACKING_PAGE_PTR: u64 = 45; +/// @brief defines the avic_logical_table_ptr register +pub const BF_REG_T_AVIC_LOGICAL_TABLE_PTR: u64 = 46; +/// @brief defines the avic_physical_table_ptr register +pub const BF_REG_T_AVIC_PHYSICAL_TABLE_PTR: u64 = 47; +/// @brief defines the vmsa_ptr register +pub const BF_REG_T_VMSA_PTR: u64 = 48; +/// @brief defines the es_selector register +pub const BF_REG_T_ES_SELECTOR: u64 = 49; +/// @brief defines the es_attrib register +pub const BF_REG_T_ES_ATTRIB: u64 = 50; +/// @brief defines the es_limit register +pub const BF_REG_T_ES_LIMIT: u64 = 51; +/// @brief defines the es_base register +pub const BF_REG_T_ES_BASE: u64 = 52; +/// @brief defines the cs_selector register +pub const BF_REG_T_CS_SELECTOR: u64 = 53; +/// @brief defines the cs_attrib register +pub const BF_REG_T_CS_ATTRIB: u64 = 54; +/// @brief defines the cs_limit register +pub const BF_REG_T_CS_LIMIT: u64 = 55; +/// @brief defines the cs_base register +pub const BF_REG_T_CS_BASE: u64 = 56; +/// @brief defines the ss_selector register +pub const BF_REG_T_SS_SELECTOR: u64 = 57; +/// @brief defines the ss_attrib register +pub const BF_REG_T_SS_ATTRIB: u64 = 58; +/// @brief defines the ss_limit register +pub const BF_REG_T_SS_LIMIT: u64 = 59; +/// @brief defines the ss_base register +pub const BF_REG_T_SS_BASE: u64 = 60; +/// @brief defines the ds_selector register +pub const BF_REG_T_DS_SELECTOR: u64 = 61; +/// @brief defines the ds_attrib register +pub const BF_REG_T_DS_ATTRIB: u64 = 62; +/// @brief defines the ds_limit register +pub const BF_REG_T_DS_LIMIT: u64 = 63; +/// @brief defines the ds_base register +pub const BF_REG_T_DS_BASE: u64 = 64; +/// @brief defines the fs_selector register +pub const BF_REG_T_FS_SELECTOR: u64 = 65; +/// @brief defines the fs_attrib register +pub const BF_REG_T_FS_ATTRIB: u64 = 66; +/// @brief defines the fs_limit register +pub const BF_REG_T_FS_LIMIT: u64 = 67; +/// @brief defines the fs_base register +pub const BF_REG_T_FS_BASE: u64 = 68; +/// @brief defines the gs_selector register +pub const BF_REG_T_GS_SELECTOR: u64 = 69; +/// @brief defines the gs_attrib register +pub const BF_REG_T_GS_ATTRIB: u64 = 70; +/// @brief defines the gs_limit register +pub const BF_REG_T_GS_LIMIT: u64 = 71; +/// @brief defines the gs_base register +pub const BF_REG_T_GS_BASE: u64 = 72; +/// @brief defines the gdtr_selector register +pub const BF_REG_T_GDTR_SELECTOR: u64 = 73; +/// @brief defines the gdtr_attrib register +pub const BF_REG_T_GDTR_ATTRIB: u64 = 74; +/// @brief defines the gdtr_limit register +pub const BF_REG_T_GDTR_LIMIT: u64 = 75; +/// @brief defines the gdtr_base register +pub const BF_REG_T_GDTR_BASE: u64 = 76; +/// @brief defines the ldtr_selector register +pub const BF_REG_T_LDTR_SELECTOR: u64 = 77; +/// @brief defines the ldtr_attrib register +pub const BF_REG_T_LDTR_ATTRIB: u64 = 78; +/// @brief defines the ldtr_limit register +pub const BF_REG_T_LDTR_LIMIT: u64 = 79; +/// @brief defines the ldtr_base register +pub const BF_REG_T_LDTR_BASE: u64 = 80; +/// @brief defines the idtr_selector register +pub const BF_REG_T_IDTR_SELECTOR: u64 = 81; +/// @brief defines the idtr_attrib register +pub const BF_REG_T_IDTR_ATTRIB: u64 = 82; +/// @brief defines the idtr_limit register +pub const BF_REG_T_IDTR_LIMIT: u64 = 83; +/// @brief defines the idtr_base register +pub const BF_REG_T_IDTR_BASE: u64 = 84; +/// @brief defines the tr_selector register +pub const BF_REG_T_TR_SELECTOR: u64 = 85; +/// @brief defines the tr_attrib register +pub const BF_REG_T_TR_ATTRIB: u64 = 86; +/// @brief defines the tr_limit register +pub const BF_REG_T_TR_LIMIT: u64 = 87; +/// @brief defines the tr_base register +pub const BF_REG_T_TR_BASE: u64 = 88; +/// @brief defines the cpl register +pub const BF_REG_T_CPL: u64 = 89; +/// @brief defines the efer register +pub const BF_REG_T_EFER: u64 = 90; +/// @brief defines the cr4 register +pub const BF_REG_T_CR4: u64 = 91; +/// @brief defines the cr3 register +pub const BF_REG_T_CR3: u64 = 92; +/// @brief defines the cr0 register +pub const BF_REG_T_CR0: u64 = 93; +/// @brief defines the dr7 register +pub const BF_REG_T_DR7: u64 = 94; +/// @brief defines the dr6 register +pub const BF_REG_T_DR6: u64 = 95; +/// @brief defines the rflags register +pub const BF_REG_T_RFLAGS: u64 = 96; +/// @brief defines the rip register +pub const BF_REG_T_RIP: u64 = 97; +/// @brief defines the rsp register +pub const BF_REG_T_RSP: u64 = 98; +/// @brief defines the rax register +pub const BF_REG_T_RAX: u64 = 99; +/// @brief defines the star register +pub const BF_REG_T_STAR: u64 = 100; +/// @brief defines the lstar register +pub const BF_REG_T_LSTAR: u64 = 101; +/// @brief defines the cstar register +pub const BF_REG_T_CSTAR: u64 = 102; +/// @brief defines the fmask register +pub const BF_REG_T_FMASK: u64 = 103; +/// @brief defines the kernel_gs_base register +pub const BF_REG_T_KERNEL_GS_BASE: u64 = 104; +/// @brief defines the sysenter_cs register +pub const BF_REG_T_SYSENTER_CS: u64 = 105; +/// @brief defines the sysenter_esp register +pub const BF_REG_T_SYSENTER_ESP: u64 = 106; +/// @brief defines the sysenter_eip register +pub const BF_REG_T_SYSENTER_EIP: u64 = 107; +/// @brief defines the cr2 register +pub const BF_REG_T_CR2: u64 = 108; +/// @brief defines the pat register +pub const BF_REG_T_PAT: u64 = 109; +/// @brief defines the dbgctl register +pub const BF_REG_T_DBGCTL: u64 = 110; +/// @brief defines the br_from register +pub const BF_REG_T_BR_FROM: u64 = 111; +/// @brief defines the br_to register +pub const BF_REG_T_BR_TO: u64 = 112; +/// @brief defines the lastexcpfrom register +pub const BF_REG_T_LASTEXCPFROM: u64 = 113; +/// @brief defines the lastexcpto register +pub const BF_REG_T_LASTEXCPTO: u64 = 114; +/// @brief defines the cr8 register +pub const BF_REG_T_CR8: u64 = 115; +/// @brief defines the dr0 register +pub const BF_REG_T_DR0: u64 = 116; +/// @brief defines the dr1 register +pub const BF_REG_T_DR1: u64 = 117; +/// @brief defines the dr2 register +pub const BF_REG_T_DR2: u64 = 118; +/// @brief defines the dr3 register +pub const BF_REG_T_DR3: u64 = 119; +/// @brief defines the xcr0 register +pub const BF_REG_T_XCR0: u64 = 120; +/// @brief defines an invalid register +pub const BF_REG_T_INVALID: u64 = 121; diff --git a/syscall/include/x64/intel/bf_reg_t.rs b/syscall/include/x64/intel/bf_reg_t.rs index e7a8c7d2..819a99e6 100644 --- a/syscall/include/x64/intel/bf_reg_t.rs +++ b/syscall/include/x64/intel/bf_reg_t.rs @@ -22,315 +22,331 @@ /// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE /// SOFTWARE. +/// @brief defines an unsupported register +pub const BF_REG_T_UNSUPPORTED: u64 = 0; /// @brief defines the rax register -const BF_REG_T_RAX:u64 = 1; +pub const BF_REG_T_RAX: u64 = 1; /// @brief defines the rbx register -const BF_REG_T_RBX:u64 = 2; +pub const BF_REG_T_RBX: u64 = 2; /// @brief defines the rcx register -const BF_REG_T_RCX:u64 = 3; +pub const BF_REG_T_RCX: u64 = 3; /// @brief defines the rdx register -const BF_REG_T_RDX:u64 = 4; +pub const BF_REG_T_RDX: u64 = 4; /// @brief defines the rbp register -const BF_REG_T_RBP:u64 = 5; +pub const BF_REG_T_RBP: u64 = 5; /// @brief defines the rsi register -const BF_REG_T_RSI:u64 = 6; +pub const BF_REG_T_RSI: u64 = 6; /// @brief defines the rdi register -const BF_REG_T_RDI:u64 = 7; +pub const BF_REG_T_RDI: u64 = 7; /// @brief defines the r8 register -const BF_REG_T_R8:u64 = 8; +pub const BF_REG_T_R8: u64 = 8; /// @brief defines the r9 register -const BF_REG_T_R9:u64 = 9; +pub const BF_REG_T_R9: u64 = 9; /// @brief defines the r10 register -const BF_REG_T_R10:u64 = 10; +pub const BF_REG_T_R10: u64 = 10; /// @brief defines the r11 register -const BF_REG_T_R11:u64 = 11; +pub const BF_REG_T_R11: u64 = 11; /// @brief defines the r12 register -const BF_REG_T_R12:u64 = 12; +pub const BF_REG_T_R12: u64 = 12; /// @brief defines the r13 register -const BF_REG_T_R13:u64 = 13; +pub const BF_REG_T_R13: u64 = 13; /// @brief defines the r14 register -const BF_REG_T_R14:u64 = 14; +pub const BF_REG_T_R14: u64 = 14; /// @brief defines the r15 register -const BF_REG_T_R15:u64 = 15; -/// @brief defines the bf_reg_t_guest_cr2 register -const BF_REG_T_GUEST_CR2:u64 = 16; -/// @brief defines the bf_reg_t_guest_dr6 register -const BF_REG_T_GUEST_DR6:u64 = 17; -/// @brief defines the bf_reg_t_guest_star register -const BF_REG_T_GUEST_STAR:u64 = 18; -/// @brief defines the bf_reg_t_guest_lstar register -const BF_REG_T_GUEST_LSTAR:u64 = 19; -/// @brief defines the bf_reg_t_guest_cstar register -const BF_REG_T_GUEST_CSTAR:u64 = 20; -/// @brief defines the bf_reg_t_guest_fmask register -const BF_REG_T_GUEST_FMASK:u64 = 21; -/// @brief defines the bf_reg_t_guest_kernel_gs_base register -const BF_REG_T_GUEST_KERNEL_GS_BASE:u64 = 22; +pub const BF_REG_T_R15: u64 = 15; +/// @brief defines the cr2 register +pub const BF_REG_T_CR2: u64 = 16; +/// @brief defines the dr6 register +pub const BF_REG_T_DR6: u64 = 17; +/// @brief defines the star register +pub const BF_REG_T_STAR: u64 = 18; +/// @brief defines the lstar register +pub const BF_REG_T_LSTAR: u64 = 19; +/// @brief defines the cstar register +pub const BF_REG_T_CSTAR: u64 = 20; +/// @brief defines the fmask register +pub const BF_REG_T_FMASK: u64 = 21; +/// @brief defines the kernel_gs_base register +pub const BF_REG_T_KERNEL_GS_BASE: u64 = 22; /// @brief defines the virtual_processor_identifier register -const BF_REG_T_VIRTUAL_PROCESSOR_IDENTIFIER:u64 = 23; +pub const BF_REG_T_VIRTUAL_PROCESSOR_IDENTIFIER: u64 = 23; /// @brief defines the posted_interrupt_notification_vector register -const BF_REG_T_POSTED_INTERRUPT_NOTIFICATION_VECTOR:u64 = 24; +pub const BF_REG_T_POSTED_INTERRUPT_NOTIFICATION_VECTOR: u64 = 24; /// @brief defines the eptp_index register -const BF_REG_T_EPTP_INDEX:u64 = 25; +pub const BF_REG_T_EPTP_INDEX: u64 = 25; /// @brief defines the guest_es_selector register -const BF_REG_T_GUEST_ES_SELECTOR:u64 = 26; +pub const BF_REG_T_ES_SELECTOR: u64 = 26; /// @brief defines the guest_cs_selector register -const BF_REG_T_GUEST_CS_SELECTOR:u64 = 27; +pub const BF_REG_T_CS_SELECTOR: u64 = 27; /// @brief defines the guest_ss_selector register -const BF_REG_T_GUEST_SS_SELECTOR:u64 = 28; +pub const BF_REG_T_SS_SELECTOR: u64 = 28; /// @brief defines the guest_ds_selector register -const BF_REG_T_GUEST_DS_SELECTOR:u64 = 29; +pub const BF_REG_T_DS_SELECTOR: u64 = 29; /// @brief defines the guest_fs_selector register -const BF_REG_T_GUEST_FS_SELECTOR:u64 = 30; +pub const BF_REG_T_FS_SELECTOR: u64 = 30; /// @brief defines the guest_gs_selector register -const BF_REG_T_GUEST_GS_SELECTOR:u64 = 31; +pub const BF_REG_T_GS_SELECTOR: u64 = 31; /// @brief defines the guest_ldtr_selector register -const BF_REG_T_GUEST_LDTR_SELECTOR:u64 = 32; +pub const BF_REG_T_LDTR_SELECTOR: u64 = 32; /// @brief defines the guest_tr_selector register -const BF_REG_T_GUEST_TR_SELECTOR:u64 = 33; +pub const BF_REG_T_TR_SELECTOR: u64 = 33; /// @brief defines the guest_interrupt_status register -const BF_REG_T_GUEST_INTERRUPT_STATUS:u64 = 34; +pub const BF_REG_T_INTERRUPT_STATUS: u64 = 34; /// @brief defines the pml_index register -const BF_REG_T_PML_INDEX:u64 = 35; +pub const BF_REG_T_PML_INDEX: u64 = 35; /// @brief defines the address_of_io_bitmap_a register -const BF_REG_T_ADDRESS_OF_IO_BITMAP_A:u64 = 36; +pub const BF_REG_T_ADDRESS_OF_IO_BITMAP_A: u64 = 36; /// @brief defines the address_of_io_bitmap_b register -const BF_REG_T_ADDRESS_OF_IO_BITMAP_B:u64 = 37; +pub const BF_REG_T_ADDRESS_OF_IO_BITMAP_B: u64 = 37; /// @brief defines the address_of_msr_bitmaps register -const BF_REG_T_ADDRESS_OF_MSR_BITMAPS:u64 = 38; +pub const BF_REG_T_ADDRESS_OF_MSR_BITMAPS: u64 = 38; /// @brief defines the vmexit_msr_store_address register -const BF_REG_T_VMEXIT_MSR_STORE_ADDRESS:u64 = 39; +pub const BF_REG_T_VMEXIT_MSR_STORE_ADDRESS: u64 = 39; /// @brief defines the vmexit_msr_load_address register -const BF_REG_T_VMEXIT_MSR_LOAD_ADDRESS:u64 = 40; +pub const BF_REG_T_VMEXIT_MSR_LOAD_ADDRESS: u64 = 40; /// @brief defines the vmentry_msr_load_address register -const BF_REG_T_VMENTRY_MSR_LOAD_ADDRESS:u64 = 41; +pub const BF_REG_T_VMENTRY_MSR_LOAD_ADDRESS: u64 = 41; /// @brief defines the executive_vmcs_pointer register -const BF_REG_T_EXECUTIVE_VMCS_POINTER:u64 = 42; +pub const BF_REG_T_EXECUTIVE_VMCS_POINTER: u64 = 42; /// @brief defines the pml_address register -const BF_REG_T_PML_ADDRESS:u64 = 43; +pub const BF_REG_T_PML_ADDRESS: u64 = 43; /// @brief defines the tsc_offset register -const BF_REG_T_TSC_OFFSET:u64 = 44; +pub const BF_REG_T_TSC_OFFSET: u64 = 44; /// @brief defines the virtual_apic_address register -const BF_REG_T_VIRTUAL_APIC_ADDRESS:u64 = 45; +pub const BF_REG_T_VIRTUAL_APIC_ADDRESS: u64 = 45; /// @brief defines the apic_access_address register -const BF_REG_T_APIC_ACCESS_ADDRESS:u64 = 46; +pub const BF_REG_T_APIC_ACCESS_ADDRESS: u64 = 46; /// @brief defines the posted_interrupt_descriptor_address register -const BF_REG_T_POSTED_INTERRUPT_DESCRIPTOR_ADDRESS:u64 = 47; +pub const BF_REG_T_POSTED_INTERRUPT_DESCRIPTOR_ADDRESS: u64 = 47; /// @brief defines the vm_function_controls register -const BF_REG_T_VM_FUNCTION_CONTROLS:u64 = 48; +pub const BF_REG_T_VM_FUNCTION_CONTROLS: u64 = 48; /// @brief defines the ept_pointer register -const BF_REG_T_EPT_POINTER:u64 = 49; +pub const BF_REG_T_EPT_POINTER: u64 = 49; /// @brief defines the eoi_exit_bitmap0 register -const BF_REG_T_EOI_EXIT_BITMAP0:u64 = 50; +pub const BF_REG_T_EOI_EXIT_BITMAP0: u64 = 50; /// @brief defines the eoi_exit_bitmap1 register -const BF_REG_T_EOI_EXIT_BITMAP1:u64 = 51; +pub const BF_REG_T_EOI_EXIT_BITMAP1: u64 = 51; /// @brief defines the eoi_exit_bitmap2 register -const BF_REG_T_EOI_EXIT_BITMAP2:u64 = 52; +pub const BF_REG_T_EOI_EXIT_BITMAP2: u64 = 52; /// @brief defines the eoi_exit_bitmap3 register -const BF_REG_T_EOI_EXIT_BITMAP3:u64 = 53; +pub const BF_REG_T_EOI_EXIT_BITMAP3: u64 = 53; /// @brief defines the eptp_list_address register -const BF_REG_T_EPTP_LIST_ADDRESS:u64 = 54; +pub const BF_REG_T_EPTP_LIST_ADDRESS: u64 = 54; /// @brief defines the vmread_bitmap_address register -const BF_REG_T_VMREAD_BITMAP_ADDRESS:u64 = 55; +pub const BF_REG_T_VMREAD_BITMAP_ADDRESS: u64 = 55; /// @brief defines the vmwrite_bitmap_address register -const BF_REG_T_VMWRITE_BITMAP_ADDRESS:u64 = 56; +pub const BF_REG_T_VMWRITE_BITMAP_ADDRESS: u64 = 56; /// @brief defines the virt_exception_information_address register -const BF_REG_T_VIRT_EXCEPTION_INFORMATION_ADDRESS:u64 = 57; +pub const BF_REG_T_VIRT_EXCEPTION_INFORMATION_ADDRESS: u64 = 57; /// @brief defines the xss_exiting_bitmap register -const BF_REG_T_XSS_EXITING_BITMAP:u64 = 58; +pub const BF_REG_T_XSS_EXITING_BITMAP: u64 = 58; /// @brief defines the encls_exiting_bitmap register -const BF_REG_T_ENCLS_EXITING_BITMAP:u64 = 59; +pub const BF_REG_T_ENCLS_EXITING_BITMAP: u64 = 59; /// @brief defines the sub_page_permission_table_pointer register -const BF_REG_T_SUB_PAGE_PERMISSION_TABLE_POINTER:u64 = 60; -/// @brief defines the tls_multiplier register -const BF_REG_T_TLS_MULTIPLIER:u64 = 61; +pub const BF_REG_T_SUB_PAGE_PERMISSION_TABLE_POINTER: u64 = 60; +/// @brief defines the tsc_multiplier register +pub const BF_REG_T_TSC_MULTIPLIER: u64 = 61; /// @brief defines the guest_physical_address register -const BF_REG_T_GUEST_PHYSICAL_ADDRESS:u64 = 62; +pub const BF_REG_T_PHYSICAL_ADDRESS: u64 = 62; /// @brief defines the vmcs_link_pointer register -const BF_REG_T_VMCS_LINK_POINTER:u64 = 63; +pub const BF_REG_T_VMCS_LINK_POINTER: u64 = 63; /// @brief defines the guest_debugctl register -const BF_REG_T_GUEST_DEBUGCTL:u64 = 64; +pub const BF_REG_T_DEBUGCTL: u64 = 64; /// @brief defines the guest_pat register -const BF_REG_T_GUEST_PAT:u64 = 65; +pub const BF_REG_T_PAT: u64 = 65; /// @brief defines the guest_efer register -const BF_REG_T_GUEST_EFER:u64 = 66; +pub const BF_REG_T_EFER: u64 = 66; /// @brief defines the guest_perf_global_ctrl register -const BF_REG_T_GUEST_PERF_GLOBAL_CTRL:u64 = 67; +pub const BF_REG_T_PERF_GLOBAL_CTRL: u64 = 67; /// @brief defines the guest_pdpte0 register -const BF_REG_T_GUEST_PDPTE0:u64 = 68; +pub const BF_REG_T_PDPTE0: u64 = 68; /// @brief defines the guest_pdpte1 register -const BF_REG_T_GUEST_PDPTE1:u64 = 69; +pub const BF_REG_T_PDPTE1: u64 = 69; /// @brief defines the guest_pdpte2 register -const BF_REG_T_GUEST_PDPTE2:u64 = 70; +pub const BF_REG_T_PDPTE2: u64 = 70; /// @brief defines the guest_pdpte3 register -const BF_REG_T_GUEST_PDPTE3:u64 = 71; +pub const BF_REG_T_PDPTE3: u64 = 71; /// @brief defines the guest_bndcfgs register -const BF_REG_T_GUEST_BNDCFGS:u64 = 72; +pub const BF_REG_T_BNDCFGS: u64 = 72; /// @brief defines the guest_rtit_ctl register -const BF_REG_T_GUEST_RTIT_CTL:u64 = 73; +pub const BF_REG_T_RTIT_CTL: u64 = 73; /// @brief defines the pin_based_vm_execution_ctls register -const BF_REG_T_PIN_BASED_VM_EXECUTION_CTLS:u64 = 74; +pub const BF_REG_T_PIN_BASED_VM_EXECUTION_CTLS: u64 = 74; /// @brief defines the primary_proc_based_vm_execution_ctls register -const BF_REG_T_PRIMARY_PROC_BASED_VM_EXECUTION_CTLS:u64 = 75; +pub const BF_REG_T_PRIMARY_PROC_BASED_VM_EXECUTION_CTLS: u64 = 75; /// @brief defines the exception_bitmap register -const BF_REG_T_EXCEPTION_BITMAP:u64 = 76; +pub const BF_REG_T_EXCEPTION_BITMAP: u64 = 76; /// @brief defines the page_fault_error_code_mask register -const BF_REG_T_PAGE_FAULT_ERROR_CODE_MASK:u64 = 77; +pub const BF_REG_T_PAGE_FAULT_ERROR_CODE_MASK: u64 = 77; /// @brief defines the page_fault_error_code_match register -const BF_REG_T_PAGE_FAULT_ERROR_CODE_MATCH:u64 = 78; +pub const BF_REG_T_PAGE_FAULT_ERROR_CODE_MATCH: u64 = 78; /// @brief defines the cr3_target_count register -const BF_REG_T_CR3_TARGET_COUNT:u64 = 79; +pub const BF_REG_T_CR3_TARGET_COUNT: u64 = 79; /// @brief defines the vmexit_ctls register -const BF_REG_T_VMEXIT_CTLS:u64 = 80; +pub const BF_REG_T_VMEXIT_CTLS: u64 = 80; /// @brief defines the vmexit_msr_store_count register -const BF_REG_T_VMEXIT_MSR_STORE_COUNT:u64 = 81; +pub const BF_REG_T_VMEXIT_MSR_STORE_COUNT: u64 = 81; /// @brief defines the vmexit_msr_load_count register -const BF_REG_T_VMEXIT_MSR_LOAD_COUNT:u64 = 82; +pub const BF_REG_T_VMEXIT_MSR_LOAD_COUNT: u64 = 82; /// @brief defines the vmentry_ctls register -const BF_REG_T_VMENTRY_CTLS:u64 = 83; +pub const BF_REG_T_VMENTRY_CTLS: u64 = 83; /// @brief defines the vmentry_msr_load_count register -const BF_REG_T_VMENTRY_MSR_LOAD_COUNT:u64 = 84; +pub const BF_REG_T_VMENTRY_MSR_LOAD_COUNT: u64 = 84; /// @brief defines the vmentry_interrupt_information_field register -const BF_REG_T_VMENTRY_INTERRUPT_INFORMATION_FIELD:u64 = 85; +pub const BF_REG_T_VMENTRY_INTERRUPT_INFORMATION_FIELD: u64 = 85; /// @brief defines the vmentry_exception_error_code register -const BF_REG_T_VMENTRY_EXCEPTION_ERROR_CODE:u64 = 86; +pub const BF_REG_T_VMENTRY_EXCEPTION_ERROR_CODE: u64 = 86; /// @brief defines the vmentry_instruction_length register -const BF_REG_T_VMENTRY_INSTRUCTION_LENGTH:u64 = 87; +pub const BF_REG_T_VMENTRY_INSTRUCTION_LENGTH: u64 = 87; /// @brief defines the tpr_threshold register -const BF_REG_T_TPR_THRESHOLD:u64 = 88; +pub const BF_REG_T_TPR_THRESHOLD: u64 = 88; /// @brief defines the secondary_proc_based_vm_execution_ctls register -const BF_REG_T_SECONDARY_PROC_BASED_VM_EXECUTION_CTLS:u64 = 89; +pub const BF_REG_T_SECONDARY_PROC_BASED_VM_EXECUTION_CTLS: u64 = 89; /// @brief defines the ple_gap register -const BF_REG_T_PLE_GAP:u64 = 90; +pub const BF_REG_T_PLE_GAP: u64 = 90; /// @brief defines the ple_window register -const BF_REG_T_PLE_WINDOW:u64 = 91; +pub const BF_REG_T_PLE_WINDOW: u64 = 91; /// @brief defines the vm_instruction_error register -const BF_REG_T_VM_INSTRUCTION_ERROR:u64 = 92; +pub const BF_REG_T_VM_INSTRUCTION_ERROR: u64 = 92; /// @brief defines the exit_reason register -const BF_REG_T_EXIT_REASON:u64 = 93; +pub const BF_REG_T_EXIT_REASON: u64 = 93; /// @brief defines the vmexit_interruption_information register -const BF_REG_T_VMEXIT_INTERRUPTION_INFORMATION:u64 = 94; +pub const BF_REG_T_VMEXIT_INTERRUPTION_INFORMATION: u64 = 94; /// @brief defines the vmexit_interruption_error_code register -const BF_REG_T_VMEXIT_INTERRUPTION_ERROR_CODE:u64 = 95; +pub const BF_REG_T_VMEXIT_INTERRUPTION_ERROR_CODE: u64 = 95; /// @brief defines the idt_vectoring_information_field register -const BF_REG_T_IDT_VECTORING_INFORMATION_FIELD:u64 = 96; +pub const BF_REG_T_IDT_VECTORING_INFORMATION_FIELD: u64 = 96; /// @brief defines the idt_vectoring_error_code register -const BF_REG_T_IDT_VECTORING_ERROR_CODE:u64 = 97; +pub const BF_REG_T_IDT_VECTORING_ERROR_CODE: u64 = 97; /// @brief defines the vmexit_instruction_length register -const BF_REG_T_VMEXIT_INSTRUCTION_LENGTH:u64 = 98; +pub const BF_REG_T_VMEXIT_INSTRUCTION_LENGTH: u64 = 98; /// @brief defines the vmexit_instruction_information register -const BF_REG_T_VMEXIT_INSTRUCTION_INFORMATION:u64 = 99; +pub const BF_REG_T_VMEXIT_INSTRUCTION_INFORMATION: u64 = 99; /// @brief defines the guest_es_limit register -const BF_REG_T_GUEST_ES_LIMIT:u64 = 100; +pub const BF_REG_T_ES_LIMIT: u64 = 100; /// @brief defines the guest_cs_limit register -const BF_REG_T_GUEST_CS_LIMIT:u64 = 101; +pub const BF_REG_T_CS_LIMIT: u64 = 101; /// @brief defines the guest_ss_limit register -const BF_REG_T_GUEST_SS_LIMIT:u64 = 102; +pub const BF_REG_T_SS_LIMIT: u64 = 102; /// @brief defines the guest_ds_limit register -const BF_REG_T_GUEST_DS_LIMIT:u64 = 103; +pub const BF_REG_T_DS_LIMIT: u64 = 103; /// @brief defines the guest_fs_limit register -const BF_REG_T_GUEST_FS_LIMIT:u64 = 104; +pub const BF_REG_T_FS_LIMIT: u64 = 104; /// @brief defines the guest_gs_limit register -const BF_REG_T_GUEST_GS_LIMIT:u64 = 105; +pub const BF_REG_T_GS_LIMIT: u64 = 105; /// @brief defines the guest_ldtr_limit register -const BF_REG_T_GUEST_LDTR_LIMIT:u64 = 106; +pub const BF_REG_T_LDTR_LIMIT: u64 = 106; /// @brief defines the guest_tr_limit register -const BF_REG_T_GUEST_TR_LIMIT:u64 = 107; +pub const BF_REG_T_TR_LIMIT: u64 = 107; /// @brief defines the guest_gdtr_limit register -const BF_REG_T_GUEST_GDTR_LIMIT:u64 = 108; +pub const BF_REG_T_GDTR_LIMIT: u64 = 108; /// @brief defines the guest_idtr_limit register -const BF_REG_T_GUEST_IDTR_LIMIT:u64 = 109; -/// @brief defines the guest_es_access_rights register -const BF_REG_T_GUEST_ES_ACCESS_RIGHTS:u64 = 110; -/// @brief defines the guest_cs_access_rights register -const BF_REG_T_GUEST_CS_ACCESS_RIGHTS:u64 = 111; -/// @brief defines the guest_ss_access_rights register -const BF_REG_T_GUEST_SS_ACCESS_RIGHTS:u64 = 112; -/// @brief defines the guest_ds_access_rights register -const BF_REG_T_GUEST_DS_ACCESS_RIGHTS:u64 = 113; -/// @brief defines the guest_fs_access_rights register -const BF_REG_T_GUEST_FS_ACCESS_RIGHTS:u64 = 114; -/// @brief defines the guest_gs_access_rights register -const BF_REG_T_GUEST_GS_ACCESS_RIGHTS:u64 = 115; -/// @brief defines the guest_ldtr_access_rights register -const BF_REG_T_GUEST_LDTR_ACCESS_RIGHTS:u64 = 116; -/// @brief defines the guest_tr_access_rights register -const BF_REG_T_GUEST_TR_ACCESS_RIGHTS:u64 = 117; +pub const BF_REG_T_IDTR_LIMIT: u64 = 109; +/// @brief defines the guest_es_attrib register +pub const BF_REG_T_ES_ATTRIB: u64 = 110; +/// @brief defines the guest_cs_attrib register +pub const BF_REG_T_CS_ATTRIB: u64 = 111; +/// @brief defines the guest_ss_attrib register +pub const BF_REG_T_SS_ATTRIB: u64 = 112; +/// @brief defines the guest_ds_attrib register +pub const BF_REG_T_DS_ATTRIB: u64 = 113; +/// @brief defines the guest_fs_attrib register +pub const BF_REG_T_FS_ATTRIB: u64 = 114; +/// @brief defines the guest_gs_attrib register +pub const BF_REG_T_GS_ATTRIB: u64 = 115; +/// @brief defines the guest_ldtr_attrib register +pub const BF_REG_T_LDTR_ATTRIB: u64 = 116; +/// @brief defines the guest_tr_attrib register +pub const BF_REG_T_TR_ATTRIB: u64 = 117; /// @brief defines the guest_interruptibility_state register -const BF_REG_T_GUEST_INTERRUPTIBILITY_STATE:u64 = 118; +pub const BF_REG_T_INTERRUPTIBILITY_STATE: u64 = 118; /// @brief defines the guest_activity_state register -const BF_REG_T_GUEST_ACTIVITY_STATE:u64 = 119; +pub const BF_REG_T_ACTIVITY_STATE: u64 = 119; /// @brief defines the guest_smbase register -const BF_REG_T_GUEST_SMBASE:u64 = 120; +pub const BF_REG_T_SMBASE: u64 = 120; /// @brief defines the guest_sysenter_cs register -const BF_REG_T_GUEST_SYSENTER_CS:u64 = 121; +pub const BF_REG_T_SYSENTER_CS: u64 = 121; /// @brief defines the vmx_preemption_timer_value register -const BF_REG_T_VMX_PREEMPTION_TIMER_VALUE:u64 = 122; +pub const BF_REG_T_VMX_PREEMPTION_TIMER_VALUE: u64 = 122; /// @brief defines the cr0_guest_host_mask register -const BF_REG_T_CR0_GUEST_HOST_MASK:u64 = 123; +pub const BF_REG_T_CR0_GUEST_HOST_MASK: u64 = 123; /// @brief defines the cr4_guest_host_mask register -const BF_REG_T_CR4_GUEST_HOST_MASK:u64 = 124; +pub const BF_REG_T_CR4_GUEST_HOST_MASK: u64 = 124; /// @brief defines the cr0_read_shadow register -const BF_REG_T_CR0_READ_SHADOW:u64 = 125; +pub const BF_REG_T_CR0_READ_SHADOW: u64 = 125; /// @brief defines the cr4_read_shadow register -const BF_REG_T_CR4_READ_SHADOW:u64 = 126; +pub const BF_REG_T_CR4_READ_SHADOW: u64 = 126; /// @brief defines the cr3_target_value0 register -const BF_REG_T_CR3_TARGET_VALUE0:u64 = 127; +pub const BF_REG_T_CR3_TARGET_VALUE0: u64 = 127; /// @brief defines the cr3_target_value1 register -const BF_REG_T_CR3_TARGET_VALUE1:u64 = 128; +pub const BF_REG_T_CR3_TARGET_VALUE1: u64 = 128; /// @brief defines the cr3_target_value2 register -const BF_REG_T_CR3_TARGET_VALUE2:u64 = 129; +pub const BF_REG_T_CR3_TARGET_VALUE2: u64 = 129; /// @brief defines the cr3_target_value3 register -const BF_REG_T_CR3_TARGET_VALUE3:u64 = 130; +pub const BF_REG_T_CR3_TARGET_VALUE3: u64 = 130; /// @brief defines the exit_qualification register -const BF_REG_T_EXIT_QUALIFICATION:u64 = 131; +pub const BF_REG_T_EXIT_QUALIFICATION: u64 = 131; /// @brief defines the io_rcx register -const BF_REG_T_IO_RCX:u64 = 132; +pub const BF_REG_T_IO_RCX: u64 = 132; /// @brief defines the io_rsi register -const BF_REG_T_IO_RSI:u64 = 133; +pub const BF_REG_T_IO_RSI: u64 = 133; /// @brief defines the io_rdi register -const BF_REG_T_IO_RDI:u64 = 134; +pub const BF_REG_T_IO_RDI: u64 = 134; /// @brief defines the io_rip register -const BF_REG_T_IO_RIP:u64 = 135; +pub const BF_REG_T_IO_RIP: u64 = 135; /// @brief defines the guest_linear_address register -const BF_REG_T_GUEST_LINEAR_ADDRESS:u64 = 136; +pub const BF_REG_T_LINEAR_ADDRESS: u64 = 136; /// @brief defines the guest_cr0 register -const BF_REG_T_GUEST_CR0:u64 = 137; +pub const BF_REG_T_CR0: u64 = 137; /// @brief defines the guest_cr3 register -const BF_REG_T_GUEST_CR3:u64 = 138; +pub const BF_REG_T_CR3: u64 = 138; /// @brief defines the guest_cr4 register -const BF_REG_T_GUEST_CR4:u64 = 139; +pub const BF_REG_T_CR4: u64 = 139; /// @brief defines the guest_es_base register -const BF_REG_T_GUEST_ES_BASE:u64 = 140; +pub const BF_REG_T_ES_BASE: u64 = 140; /// @brief defines the guest_cs_base register -const BF_REG_T_GUEST_CS_BASE:u64 = 141; +pub const BF_REG_T_CS_BASE: u64 = 141; /// @brief defines the guest_ss_base register -const BF_REG_T_GUEST_SS_BASE:u64 = 142; +pub const BF_REG_T_SS_BASE: u64 = 142; /// @brief defines the guest_ds_base register -const BF_REG_T_GUEST_DS_BASE:u64 = 143; +pub const BF_REG_T_DS_BASE: u64 = 143; /// @brief defines the guest_fs_base register -const BF_REG_T_GUEST_FS_BASE:u64 = 144; +pub const BF_REG_T_FS_BASE: u64 = 144; /// @brief defines the guest_gs_base register -const BF_REG_T_GUEST_GS_BASE:u64 = 145; +pub const BF_REG_T_GS_BASE: u64 = 145; /// @brief defines the guest_ldtr_base register -const BF_REG_T_GUEST_LDTR_BASE:u64 = 146; +pub const BF_REG_T_LDTR_BASE: u64 = 146; /// @brief defines the guest_tr_base register -const BF_REG_T_GUEST_TR_BASE:u64 = 147; +pub const BF_REG_T_TR_BASE: u64 = 147; /// @brief defines the guest_gdtr_base register -const BF_REG_T_GUEST_GDTR_BASE:u64 = 148; +pub const BF_REG_T_GDTR_BASE: u64 = 148; /// @brief defines the guest_idtr_base register -const BF_REG_T_GUEST_IDTR_BASE:u64 = 149; +pub const BF_REG_T_IDTR_BASE: u64 = 149; /// @brief defines the guest_dr7 register -const BF_REG_T_GUEST_DR7:u64 = 150; +pub const BF_REG_T_DR7: u64 = 150; /// @brief defines the guest_rsp register -const BF_REG_T_GUEST_RSP:u64 = 151; +pub const BF_REG_T_RSP: u64 = 151; /// @brief defines the guest_rip register -const BF_REG_T_GUEST_RIP:u64 = 152; +pub const BF_REG_T_RIP: u64 = 152; /// @brief defines the guest_rflags register -const BF_REG_T_GUEST_RFLAGS:u64 = 153; +pub const BF_REG_T_RFLAGS: u64 = 153; /// @brief defines the guest_pending_debug_exceptions register -const BF_REG_T_GUEST_PENDING_DEBUG_EXCEPTIONS:u64 = 154; +pub const BF_REG_T_PENDING_DEBUG_EXCEPTIONS: u64 = 154; /// @brief defines the guest_sysenter_esp register -const BF_REG_T_GUEST_SYSENTER_ESP:u64 = 155; +pub const BF_REG_T_SYSENTER_ESP: u64 = 155; /// @brief defines the guest_sysenter_eip register -const BF_REG_T_GUEST_SYSENTER_EIP:u64 = 156; +pub const BF_REG_T_SYSENTER_EIP: u64 = 156; +/// @brief defines the cr8 register +pub const BF_REG_T_CR8: u64 = 157; +/// @brief defines the dr0 register +pub const BF_REG_T_DR0: u64 = 158; +/// @brief defines the dr1 register +pub const BF_REG_T_DR1: u64 = 159; +/// @brief defines the dr2 register +pub const BF_REG_T_DR2: u64 = 160; +/// @brief defines the dr3 register +pub const BF_REG_T_DR3: u64 = 161; +/// @brief defines the xcr0 register +pub const BF_REG_T_XCR0: u64 = 162; +/// @brief defines an invalid register +pub const BF_REG_T_INVALID: u64 = 163; diff --git a/syscall/lib.rs b/syscall/lib.rs index e93a8e22..0d8fdaba 100644 --- a/syscall/lib.rs +++ b/syscall/lib.rs @@ -21,3 +21,82 @@ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. + +#![no_std] + +#[macro_use] +extern crate bsl; + +#[path = "constants.rs"] +#[doc(hidden)] +pub mod constants; +pub use constants::*; + +#[path = "include/bf_types.rs"] +#[doc(hidden)] +pub mod bf_types; +pub use bf_types::*; + +#[path = "include/bf_constants.rs"] +#[doc(hidden)] +pub mod bf_constants; +pub use bf_constants::*; + +#[cfg(feature = "AuthenticAMD")] +#[path = "include/x64/amd/bf_reg_t.rs"] +#[doc(hidden)] +pub mod bf_reg_t; + +#[cfg(feature = "GenuineIntel")] +#[path = "include/x64/intel/bf_reg_t.rs"] +#[doc(hidden)] +pub mod bf_reg_t; + +pub use bf_reg_t::*; + +#[path = "src/bf_syscall_impl.rs"] +#[doc(hidden)] +pub mod bf_syscall_impl; +pub use bf_syscall_impl::*; + +macro_rules! print_thread_id { + ($($arg:tt)*) => { + unsafe { + print!( + " [{}{:04x}{}:{}{:04x}{}:{}{:04x}{}:{}{:04x}{}:{}{:04x}{}:{}US{}]", + bsl::cyn, + crate::bf_tls_extid_impl(), + bsl::rst, + bsl::cyn, + crate::bf_tls_vmid_impl(), + bsl::rst, + bsl::cyn, + crate::bf_tls_vpid_impl(), + bsl::rst, + bsl::cyn, + crate::bf_tls_vsid_impl(), + bsl::rst, + bsl::cyn, + crate::bf_tls_ppid_impl(), + bsl::rst, + bsl::blu, + bsl::rst + ); + } + }; +} + +#[path = "src/bf_control_ops.rs"] +#[doc(hidden)] +pub mod bf_control_ops; +pub use bf_control_ops::*; + +#[path = "src/bf_debug_ops.rs"] +#[doc(hidden)] +pub mod bf_debug_ops; +pub use bf_debug_ops::*; + +#[path = "src/bf_syscall_t.rs"] +#[doc(hidden)] +pub mod bf_syscall_t; +pub use bf_syscall_t::*; diff --git a/syscall/src/bf_control_ops.rs b/syscall/src/bf_control_ops.rs index 5a0b46ff..e90407d0 100644 --- a/syscall/src/bf_control_ops.rs +++ b/syscall/src/bf_control_ops.rs @@ -32,26 +32,6 @@ pub fn bf_control_op_exit() { } } -#[cfg(test)] -mod test_bf_control_op_exit { - static mut EXECUTED: bool = false; - - #[no_mangle] - fn bf_control_op_exit_impl() { - unsafe { - EXECUTED = true; - } - } - - #[test] - fn test_bf_control_op_exit() { - super::bf_control_op_exit(); - unsafe { - assert!(EXECUTED); - } - } -} - /// /// @brief This syscall tells the microkernel that the extension would /// like to wait for a callback. This is a blocking syscall that never @@ -64,22 +44,14 @@ pub fn bf_control_op_wait() { } } -#[cfg(test)] -mod test_bf_control_op_wait { - static mut EXECUTED: bool = false; - - #[no_mangle] - fn bf_control_op_wait_impl() { - unsafe { - EXECUTED = true; - } - } - - #[test] - fn test_bf_control_op_wait() { - super::bf_control_op_wait(); - unsafe { - assert!(EXECUTED); - } +/// +/// @brief This syscall tells the microkernel that the extension would +/// like to try again from a fast fail callback. This syscall is a +/// blocking syscall that never returns and should be used to return +/// from the fail_entry function. +/// +pub fn bf_control_op_again() { + unsafe { + crate::bf_syscall_impl::bf_control_op_again_impl(); } } diff --git a/syscall/src/bf_debug_ops.rs b/syscall/src/bf_debug_ops.rs index 9bb02fda..b8c5a71b 100644 --- a/syscall/src/bf_debug_ops.rs +++ b/syscall/src/bf_debug_ops.rs @@ -21,8 +21,6 @@ /// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, /// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE /// SOFTWARE. -use crate::types::BfCharT; -use crate::types::BfCstrT; /// /// @brief This syscall tells the microkernel to output reg0 and reg1 to @@ -33,32 +31,9 @@ use crate::types::BfCstrT; /// @param val1 The first value to output to the microkernel's console /// @param val2 The second value to output to the microkernel's console /// -pub fn bf_debug_op_out(val1: u64, val2: u64) { +pub fn bf_debug_op_out(val1: bsl::SafeU64, val2: bsl::SafeU64) { unsafe { - crate::bf_syscall_impl::bf_debug_op_out_impl(val1, val2); - } -} - -#[cfg(test)] -mod test_bf_debug_op_out { - static mut VAL1: u64 = 0; - static mut VAL2: u64 = 0; - - #[no_mangle] - fn bf_debug_op_out_impl(val1: u64, val2: u64) { - unsafe { - VAL1 = val1; - VAL2 = val2; - } - } - - #[test] - fn test_bf_debug_op_out() { - super::bf_debug_op_out(23, 42); - unsafe { - assert!(VAL1 == 23); - assert!(VAL2 == 42); - } + crate::bf_debug_op_out_impl(val1.get(), val2.get()); } } @@ -70,29 +45,9 @@ mod test_bf_debug_op_out { /// /// @param vmid The ID of the VM whose state is to be outputted /// -pub fn bf_debug_op_dump_vm(vmid: u16) { +pub fn bf_debug_op_dump_vm(vmid: bsl::SafeU16) { unsafe { - crate::bf_syscall_impl::bf_debug_op_dump_vm_impl(vmid); - } -} - -#[cfg(test)] -mod test_bf_debug_op_dump_vm { - static mut ID: u64 = 0; - - #[no_mangle] - fn bf_debug_op_dump_vm_impl(vmid: u64) { - unsafe { - ID = vmid; - } - } - - #[test] - fn test_bf_debug_op_dump_vm() { - super::bf_debug_op_dump_vm(42); - unsafe { - assert!(ID == 42); - } + crate::bf_debug_op_dump_vm_impl(vmid.get()); } } @@ -104,29 +59,9 @@ mod test_bf_debug_op_dump_vm { /// /// @param vpid The ID of the VP whose state is to be outputted /// -pub fn bf_debug_op_dump_vp(vpid: u16) { +pub fn bf_debug_op_dump_vp(vpid: bsl::SafeU16) { unsafe { - crate::bf_syscall_impl::bf_debug_op_dump_vp_impl(vpid); - } -} - -#[cfg(test)] -mod test_bf_debug_op_dump_vp { - static mut ID: u64 = 0; - - #[no_mangle] - fn bf_debug_op_dump_vp_impl(vpid: u64) { - unsafe { - ID = vpid; - } - } - - #[test] - fn test_bf_debug_op_dump_vp() { - super::bf_debug_op_dump_vp(42); - unsafe { - assert!(ID == 42); - } + crate::bf_debug_op_dump_vp_impl(vpid.get()); } } @@ -138,29 +73,9 @@ mod test_bf_debug_op_dump_vp { /// /// @param vsid The ID of the VS whose state is to be outputted /// -pub fn bf_debug_op_dump_vs(vsid: u16) { +pub fn bf_debug_op_dump_vs(vsid: bsl::SafeU16) { unsafe { - crate::bf_syscall_impl::bf_debug_op_dump_vs_impl(vsid); - } -} - -#[cfg(test)] -mod test_bf_debug_op_dump_vs { - static mut ID: u64 = 0; - - #[no_mangle] - fn bf_debug_op_dump_vs_impl(vsid: u64) { - unsafe { - ID = vsid; - } - } - - #[test] - fn test_bf_debug_op_dump_vs() { - super::bf_debug_op_dump_vs(42); - unsafe { - assert!(ID == 42); - } + crate::bf_debug_op_dump_vs_impl(vsid.get()); } } @@ -172,29 +87,9 @@ mod test_bf_debug_op_dump_vs { /// /// @param ppid The PPID of the PP to dump the log from /// -pub fn bf_debug_op_dump_vmexit_log(ppid: u16) { +pub fn bf_debug_op_dump_vmexit_log(ppid: bsl::SafeU16) { unsafe { - crate::bf_syscall_impl::bf_debug_op_dump_vmexit_log_impl(ppid); - } -} - -#[cfg(test)] -mod test_bf_debug_op_dump_vmexit_log { - static mut ID: u64 = 0; - - #[no_mangle] - fn bf_debug_op_dump_vmexit_log_impl(ppid: u64) { - unsafe { - ID = ppid; - } - } - - #[test] - fn test_bf_debug_op_dump_vmexit_log() { - super::bf_debug_op_dump_vmexit_log(42); - unsafe { - assert!(ID == 42); - } + crate::bf_debug_op_dump_vmexit_log_impl(ppid.get()); } } @@ -205,29 +100,9 @@ mod test_bf_debug_op_dump_vmexit_log { /// /// @param c The character to output /// -pub fn bf_debug_op_write_c(c: BfCharT) { +pub fn bf_debug_op_write_c(c: bsl::CharT) { unsafe { - crate::bf_syscall_impl::bf_debug_op_write_c_impl(c); - } -} - -#[cfg(test)] -mod test_bf_debug_op_write_c { - static mut C: super::BfCharT = 0; - - #[no_mangle] - fn bf_debug_op_write_c_impl(c: super::BfCharT) { - unsafe { - C = c; - } - } - - #[test] - fn test_bf_debug_op_write_c() { - super::bf_debug_op_write_c(42); - unsafe { - assert!(C == 42); - } + crate::bf_debug_op_write_c_impl(c); } } @@ -238,17 +113,12 @@ mod test_bf_debug_op_write_c { /// /// @param str The virtual address of a null terminated string to output /// -pub fn bf_debug_op_write_str(str: BfCstrT) { +pub fn bf_debug_op_write_str(str: bsl::CStrT, len: u64) { unsafe { - crate::bf_syscall_impl::bf_debug_op_write_str_impl(str); + crate::bf_debug_op_write_str_impl(str, len); } } -#[cfg(test)] -mod test_bf_debug_op_write_str { - // TODO -} - /// /// @brief This syscall tells the microkernel to output an extension's /// state to the console device the microkernel is currently using @@ -257,29 +127,9 @@ mod test_bf_debug_op_write_str { /// /// @param extid The EXTID of the extensions's state to output /// -pub fn bf_debug_op_dump_ext(extid: u16) { +pub fn bf_debug_op_dump_ext(extid: bsl::SafeU16) { unsafe { - crate::bf_syscall_impl::bf_debug_op_dump_ext_impl(extid); - } -} - -#[cfg(test)] -mod test_bf_debug_op_dump_ext { - static mut ID: u64 = 0; - - #[no_mangle] - fn bf_debug_op_dump_ext_impl(extid: u64) { - unsafe { - ID = extid; - } - } - - #[test] - fn test_bf_debug_op_dump_ext() { - super::bf_debug_op_dump_ext(42); - unsafe { - assert!(ID == 42); - } + crate::bf_debug_op_dump_ext_impl(extid.get()); } } @@ -290,27 +140,7 @@ mod test_bf_debug_op_dump_ext { /// pub fn bf_debug_op_dump_page_pool() { unsafe { - crate::bf_syscall_impl::bf_debug_op_dump_page_pool_impl(); - } -} - -#[cfg(test)] -mod test_bf_debug_op_dump_page_pool { - static mut EXECUTED: bool = false; - - #[no_mangle] - fn bf_debug_op_dump_page_pool_impl() { - unsafe { - EXECUTED = true; - } - } - - #[test] - fn test_bf_debug_op_dump_page_pool() { - super::bf_debug_op_dump_page_pool(); - unsafe { - assert!(EXECUTED); - } + crate::bf_debug_op_dump_page_pool_impl(); } } @@ -321,26 +151,6 @@ mod test_bf_debug_op_dump_page_pool { /// pub fn bf_debug_op_dump_huge_pool() { unsafe { - crate::bf_syscall_impl::bf_debug_op_dump_huge_pool_impl(); - } -} - -#[cfg(test)] -mod test_bf_debug_op_dump_huge_pool { - static mut EXECUTED: bool = false; - - #[no_mangle] - fn bf_debug_op_dump_huge_pool_impl() { - unsafe { - EXECUTED = true; - } - } - - #[test] - fn test_bf_debug_op_dump_huge_pool() { - super::bf_debug_op_dump_huge_pool(); - unsafe { - assert!(EXECUTED); - } + crate::bf_debug_op_dump_huge_pool_impl(); } } diff --git a/syscall/src/bf_syscall_impl.rs b/syscall/src/bf_syscall_impl.rs index 2bc9ef52..4e6e4d7e 100644 --- a/syscall/src/bf_syscall_impl.rs +++ b/syscall/src/bf_syscall_impl.rs @@ -1,4 +1,3 @@ -use crate::types::BfCharT; /// @copyright /// Copyright (C) 2020 Assured Information Security, Inc. /// @@ -22,15 +21,13 @@ use crate::types::BfCharT; /// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, /// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE /// SOFTWARE. -use crate::types::BfCptrT; -use crate::types::BfCstrT; + +// ------------------------------------------------------------------------- +// TLS ops +// ------------------------------------------------------------------------- extern "C" { - // ------------------------------------------------------------------------- - // TLS ops - // ------------------------------------------------------------------------- - /// /// @brief Implements the ABI for bf_tls_rax. /// @@ -333,6 +330,11 @@ extern "C" { /// pub fn bf_control_op_wait_impl(); + /// + /// @brief Implements the ABI for bf_control_op_again. + /// + pub fn bf_control_op_again_impl(); + // ------------------------------------------------------------------------- // bf_handle_ops // ------------------------------------------------------------------------- @@ -407,15 +409,20 @@ extern "C" { /// /// @param reg0_in n/a /// - pub fn bf_debug_op_write_c_impl(reg0_in: BfCharT); + pub fn bf_debug_op_write_c_impl(reg0_in: bsl::CharT); // NOLINT /// /// @brief Implements the ABI for bf_debug_op_write_str. /// /// /// @param reg0_in n/a + /// @param reg1_in n/a /// - pub fn bf_debug_op_write_str_impl(reg0_in: BfCstrT); + pub fn bf_debug_op_write_str_impl( + // NOLINT + reg0_in: bsl::CStrT, + reg1_in: u64, + ); // NOLINT /// /// @brief Implements the ABI for bf_debug_op_dump_ext. @@ -447,7 +454,7 @@ extern "C" { /// @param reg1_in n/a /// @return n/a /// - pub fn bf_callback_op_register_bootstrap_impl(reg0_in: u64, reg1_in: BfCptrT) -> u64; + pub fn bf_callback_op_register_bootstrap_impl(reg0_in: u64, reg1_in: bsl::CPtrT) -> u64; /// /// @brief Implements the ABI for bf_callback_op_register_vmexit. @@ -457,7 +464,7 @@ extern "C" { /// @param reg1_in n/a /// @return n/a /// - pub fn bf_callback_op_register_vmexit_impl(reg0_in: u64, reg1_in: BfCptrT) -> u64; + pub fn bf_callback_op_register_vmexit_impl(reg0_in: u64, reg1_in: bsl::CPtrT) -> u64; /// /// @brief Implements the ABI for bf_callback_op_register_fail. @@ -467,7 +474,7 @@ extern "C" { /// @param reg1_in n/a /// @return n/a /// - pub fn bf_callback_op_register_fail_impl(reg0_in: u64, reg1_in: BfCptrT) -> u64; + pub fn bf_callback_op_register_fail_impl(reg0_in: u64, reg1_in: bsl::CPtrT) -> u64; // ------------------------------------------------------------------------- // bf_vm_ops @@ -507,7 +514,7 @@ extern "C" { reg0_in: u64, reg1_in: u16, reg2_in: u64, - reg0_out: *mut BfCptrT, + reg0_out: *mut bsl::CPtrT, ) -> u64; /// @@ -519,7 +526,7 @@ extern "C" { /// @param reg2_in n/a /// @return n/a /// - pub fn bf_vm_op_unmap_direct_impl(reg0_in: u64, reg1_in: u16, reg2_in: u64) -> u64; + pub fn bf_vm_op_unmap_direct_impl(reg0_in: u64, reg1_in: u16, reg2_in: bsl::CPtrT) -> u64; /// /// @brief Implements the ABI for bf_vm_op_unmap_direct_broadcast. @@ -530,7 +537,21 @@ extern "C" { /// @param reg2_in n/a /// @return n/a /// - pub fn bf_vm_op_unmap_direct_broadcast_impl(reg0_in: u64, reg1_in: u16, reg2_in: u64) -> u64; + pub fn bf_vm_op_unmap_direct_broadcast_impl( + reg0_in: u64, + reg1_in: u16, + reg2_in: bsl::CPtrT, + ) -> u64; + + /// + /// @brief Implements the ABI for bf_vm_op_tlb_flush. + /// + /// + /// @param reg0_in n/a + /// @param reg1_in n/a + /// @return n/a + /// + pub fn bf_vm_op_tlb_flush_impl(reg0_in: u64, reg1_in: u16) -> u64; // ------------------------------------------------------------------------- // bf_vp_ops @@ -542,16 +563,10 @@ extern "C" { /// /// @param reg0_in n/a /// @param reg1_in n/a - /// @param reg2_in n/a /// @param reg0_out n/a /// @return n/a /// - pub fn bf_vp_op_create_vp_impl( - reg0_in: u64, - reg1_in: u16, - reg2_in: u16, - reg0_out: *mut u16, - ) -> u64; + pub fn bf_vp_op_create_vp_impl(reg0_in: u64, reg1_in: u16, reg0_out: *mut u16) -> u64; /// /// @brief Implements the ABI for bf_vp_op_destroy_vp. @@ -614,12 +629,7 @@ extern "C" { /// @param reg0_out n/a /// @return n/a /// - pub fn bf_vs_op_read_impl( - reg0_in: u64, - reg1_in: u16, - reg2_in: u64, - reg0_out: *const u64, - ) -> u64; + pub fn bf_vs_op_read_impl(reg0_in: u64, reg1_in: u16, reg2_in: u64, reg0_out: *mut u64) -> u64; /// /// @brief Implements the ABI for bf_vs_op_write. @@ -655,14 +665,21 @@ extern "C" { pub fn bf_vs_op_run_current_impl(reg0_in: u64) -> u64; /// - /// @brief Implements the ABI for bf_vs_op_advance_ip. + /// @brief Implements the ABI for bf_vs_op_advance_ip_and_run. /// /// /// @param reg0_in n/a /// @param reg1_in n/a + /// @param reg2_in n/a + /// @param reg3_in n/a /// @return n/a /// - pub fn bf_vs_op_advance_ip_impl(reg0_in: u64, reg1_in: u16) -> u64; + pub fn bf_vs_op_advance_ip_and_run_impl( + reg0_in: u64, + reg1_in: u16, + reg2_in: u16, + reg3_in: u16, + ) -> u64; /// /// @brief Implements the ABI for bf_vs_op_advance_ip_and_run_current. @@ -704,6 +721,46 @@ extern "C" { /// pub fn bf_vs_op_migrate_impl(reg0_in: u64, reg1_in: u16, reg2_in: u16) -> u64; + /// + /// @brief Implements the ABI for bf_vs_op_set_active. + /// + /// + /// @param reg0_in n/a + /// @param reg1_in n/a + /// @param reg2_in n/a + /// @param reg3_in n/a + /// @return n/a + /// + pub fn bf_vs_op_set_active_impl(reg0_in: u64, reg1_in: u16, reg2_in: u16, reg3_in: u16) -> u64; + + /// + /// @brief Implements the ABI for bf_vs_op_advance_ip_and_set_active. + /// + /// + /// @param reg0_in n/a + /// @param reg1_in n/a + /// @param reg2_in n/a + /// @param reg3_in n/a + /// @return n/a + /// + pub fn bf_vs_op_advance_ip_and_set_active_impl( + reg0_in: u64, + reg1_in: u16, + reg2_in: u16, + reg3_in: u16, + ) -> u64; + + /// + /// @brief Implements the ABI for bf_vs_op_tlb_flush. + /// + /// + /// @param reg0_in n/a + /// @param reg1_in n/a + /// @param reg2_in n/a + /// @return n/a + /// + pub fn bf_vs_op_tlb_flush_impl(reg0_in: u64, reg1_in: u16, reg2_in: u64) -> u64; + // ------------------------------------------------------------------------- // bf_intrinsic_ops // ------------------------------------------------------------------------- @@ -717,7 +774,7 @@ extern "C" { /// @param reg0_out n/a /// @return n/a /// - pub fn bf_intrinsic_op_rdmsr_impl(reg0_in: u64, reg1_in: u32, reg0_out: *const u64) -> u64; + pub fn bf_intrinsic_op_rdmsr_impl(reg0_in: u64, reg1_in: u32, reg0_out: *mut u64) -> u64; /// /// @brief Implements the ABI for bf_intrinsic_op_wrmsr. @@ -730,45 +787,6 @@ extern "C" { /// pub fn bf_intrinsic_op_wrmsr_impl(reg0_in: u64, reg1_in: u32, reg2_in: u64) -> u64; - /// - /// @brief Implements the ABI for bf_intrinsic_op_invlpga. - /// - /// - /// @param reg0_in n/a - /// @param reg1_in n/a - /// @param reg2_in n/a - /// @return n/a - /// - pub fn bf_intrinsic_op_invlpga_impl(reg0_in: u64, reg1_in: u64, reg2_in: u64) -> u64; - - /// - /// @brief Implements the ABI for bf_intrinsic_op_invept. - /// - /// - /// @param reg0_in n/a - /// @param reg1_in n/a - /// @param reg2_in n/a - /// @return n/a - /// - pub fn bf_intrinsic_op_invept_impl(reg0_in: u64, reg1_in: u64, reg2_in: u64) -> u64; - - /// - /// @brief Implements the ABI for bf_intrinsic_op_invvpid. - /// - /// - /// @param reg0_in n/a - /// @param reg1_in n/a - /// @param reg2_in n/a - /// @param reg3_in n/a - /// @return n/a - /// - pub fn bf_intrinsic_op_invvpid_impl( - reg0_in: u64, - reg1_in: u64, - reg2_in: u16, - reg3_in: u64, - ) -> u64; - // ------------------------------------------------------------------------- // bf_mem_ops // ------------------------------------------------------------------------- @@ -779,13 +797,13 @@ extern "C" { /// /// @param reg0_in n/a /// @param reg0_out n/a - /// @param reg1_out n/a + /// @param pmut_reg1_out n/a /// @return n/a /// pub fn bf_mem_op_alloc_page_impl( reg0_in: u64, - reg0_out: *mut BfCptrT, - reg1_out: *const u64, + reg0_out: *mut bsl::CPtrT, + pmut_reg1_out: *mut u64, ) -> u64; /// @@ -795,13 +813,14 @@ extern "C" { /// @param reg0_in n/a /// @param reg1_in n/a /// @param reg0_out n/a - /// @param reg1_out n/a + /// @param pmut_reg1_out n/a /// @return n/a /// pub fn bf_mem_op_alloc_huge_impl( reg0_in: u64, reg1_in: u64, - reg0_out: *mut BfCptrT, - reg1_out: *const u64, + reg0_out: *mut bsl::CPtrT, + pmut_reg1_out: *mut u64, ) -> u64; + } diff --git a/syscall/src/bf_syscall_t.hpp b/syscall/src/bf_syscall_t.hpp index 88e90d3a..b843f49c 100644 --- a/syscall/src/bf_syscall_t.hpp +++ b/syscall/src/bf_syscall_t.hpp @@ -1225,7 +1225,12 @@ namespace syscall } /// - /// @brief TODO + /// @brief Executes a VS given the ID of the VM, VP and VS to + /// execute. The VS must be assigned to the provided VP and the + /// provided VP must be assigned to the provided VM. The VP and VS + /// must not be executing on any other PP, and the VS must be + /// assigned to the PP this syscall is executed on. Upon success, + /// this syscall will not return. /// /// /// @param vmid The ID of the VM to run @@ -1289,7 +1294,12 @@ namespace syscall } /// - /// @brief TODO + /// @brief Advances the IP and executes a VS given the ID of the VM, + /// VP and VS to execute. The VS must be assigned to the provided + /// VP and the provided VP must be assigned to the provided VM. + /// The VP and VS must not be executing on any other PP, and the + /// VS must be assigned to the PP this syscall is executed on. + /// Upon success, this syscall will not return. /// /// /// @param vmid The ID of the VM to advance the IP for @@ -1329,7 +1339,9 @@ namespace syscall } /// - /// @brief TODO + /// @brief bf_vs_op_advance_ip_and_run_current tells the microkernel + /// to advance the IP of and execute the currently active VS, VP + /// and VM. /// /// /// @return Returns bsl::errc_success on success, bsl::errc_failure @@ -1418,7 +1430,8 @@ namespace syscall } /// - /// @brief TODO + /// @brief Migrates a VS to the provided PP. The VS must not be + /// active. /// /// /// @param vsid The ID of the VS to migrate diff --git a/syscall/src/bf_syscall_t.rs b/syscall/src/bf_syscall_t.rs index 1db7b45a..b583945e 100644 --- a/syscall/src/bf_syscall_t.rs +++ b/syscall/src/bf_syscall_t.rs @@ -22,101 +22,113 @@ /// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE /// SOFTWARE. -#[path = "../../include/rust/constants.rs"] -use crate::constants; -#[path = "../../include/rust/types.rs"] -use crate::types; - -use types::BfCharT; -use types::BfCptrT; -use types::BfCstrT; - -struct BfSyscallT { - m_hndl: u64, +#[derive(Debug, Default, Copy, Clone, PartialEq, PartialOrd)] +pub struct BfSyscallT { + m_hndl: bsl::SafeU64, } impl BfSyscallT { /// - /// @brief Initializes the BfSyscallT by verifying version - /// compatibility, opening a handle and registering the provided - /// callbacks. + /// @brief New constructor /// + pub const fn new() -> Self { + Self { + m_hndl: crate::BF_INVALID_HANDLE, + } + } + /// /// @param version the version provided to the extension by the /// microkernel. If this API does not support the ABI versions /// that the microkernel supports, this function will fail. - /// @param bootstrap_handler the bootstrap handler to register - /// @param vmexit_handler the vmexit handler to register - /// @param fail_handler the fail handler to register + /// @param pmut_bootstrap_handler the bootstrap handler to register + /// @param pmut_vmexit_handler the vmexit handler to register + /// @param pmut_fail_handler the fail handler to register /// @return Returns bsl::errc_success on success, bsl::errc_failure /// and friends otherwise /// pub fn initialize( &mut self, - version: u32, - bootstrap_handler: BfCptrT, - vmexit_handler: BfCptrT, - fail_handler: BfCptrT, + version: bsl::SafeU32, + pmut_bootstrap_handler: bsl::CPtrT, + pmut_vmexit_handler: bsl::CPtrT, + pmut_fail_handler: bsl::CPtrT, ) -> bsl::ErrcType { - let mut release_on_error = bsl::Finally::new(|| { - self.release(); - }); + let mut ret: u64; + bsl::expects(version.is_valid_and_checked()); + bsl::expects(version.is_pos()); + bsl::expects(core::ptr::null() != pmut_bootstrap_handler); + bsl::expects(core::ptr::null() != pmut_vmexit_handler); + bsl::expects(core::ptr::null() != pmut_fail_handler); - if !constants::bf_is_spec1_supported(version) { - // bsl::error() << "unsupported microkernel " // -- - // << bsl::hex(version) // -- - // << bsl::endl // -- - // << bsl::here(); - - // return bsl::errc_unsupported; + if !crate::bf_is_spec1_supported(version) { + error!("unsupported microkernel {:#018x}\n{}", version, bsl::here()); + return bsl::errc_unsupported; } - // mut_ret = bf_handle_op_open_handle_impl(BF_SPEC_ID1_VAL.get(), m_hndl.data()); - // if (mut_ret != BF_STATUS_SUCCESS)) { - // bsl::error() << "bf_handle_op_open_handle_impl failed with status " // -- - // << bsl::hex(mut_ret) // -- - // << bsl::endl // -- - // << bsl::here(); + unsafe { + ret = crate::bf_handle_op_open_handle_impl( + crate::BF_SPEC_ID1_VAL.get(), + self.m_hndl.data(), + ); + } + if crate::BF_STATUS_SUCCESS != ret { + error!( + "bf_handle_op_open_handle_impl failed with status {:#018x}\n{}", + ret, + bsl::here() + ); - // return bsl::errc_failure; - // } + return bsl::errc_failure; + } - // bsl::finally mut_release_on_error{[this]() -> void { - // this->release(); - // }}; + unsafe { + ret = crate::bf_callback_op_register_bootstrap_impl( + self.m_hndl.get(), + pmut_bootstrap_handler, + ); + } + if crate::BF_STATUS_SUCCESS != ret { + error!( + "bf_callback_op_register_bootstrap failed with status {:#018x}\n{}", + ret, + bsl::here() + ); - // mut_ret = bf_callback_op_register_bootstrap_impl(m_hndl.get(), bootstrap_handler); - // if (mut_ret != BF_STATUS_SUCCESS)) { - // bsl::error() << "bf_callback_op_register_bootstrap failed with status " // -- - // << bsl::hex(mut_ret) // -- - // << bsl::endl // -- - // << bsl::here(); + self.release(); + return bsl::errc_failure; + } - // return bsl::errc_failure; - // } + unsafe { + ret = + crate::bf_callback_op_register_vmexit_impl(self.m_hndl.get(), pmut_vmexit_handler); + } + if crate::BF_STATUS_SUCCESS != ret { + error!( + "bf_callback_op_register_vmexit failed with status {:#018x}\n{}", + ret, + bsl::here() + ); - // mut_ret = bf_callback_op_register_vmexit_impl(m_hndl.get(), vmexit_handler); - // if (mut_ret != BF_STATUS_SUCCESS)) { - // bsl::error() << "bf_callback_op_register_vmexit failed with status " // -- - // << bsl::hex(mut_ret) // -- - // << bsl::endl // -- - // << bsl::here(); + self.release(); + return bsl::errc_failure; + } - // return bsl::errc_failure; - // } + unsafe { + ret = crate::bf_callback_op_register_fail_impl(self.m_hndl.get(), pmut_fail_handler); + } + if crate::BF_STATUS_SUCCESS != ret { + error!( + "bf_callback_op_register_fail failed with status {:#018x}\n{}", + ret, + bsl::here() + ); - // mut_ret = bf_callback_op_register_fail_impl(m_hndl.get(), fail_handler); - // if (mut_ret != BF_STATUS_SUCCESS)) { - // bsl::error() << "bf_callback_op_register_fail failed with status " // -- - // << bsl::hex(mut_ret) // -- - // << bsl::endl // -- - // << bsl::here(); + self.release(); + return bsl::errc_failure; + } - // return bsl::errc_failure; - // } - - release_on_error.ignore(); - return true; + return bsl::errc_success; } /// @@ -124,1394 +136,1644 @@ impl BfSyscallT { /// pub fn release(&mut self) { unsafe { - crate::bf_syscall_impl::bf_handle_op_close_handle_impl(self.m_hndl); + crate::bf_handle_op_close_handle_impl(self.m_hndl.get()); } - self.m_hndl = 0; + self.m_hndl = bsl::SafeU64::magic_0(); } - // // --------------------------------------------------------------------- - // // TLS ops - // // --------------------------------------------------------------------- - - // /// - // /// @brief Returns the value of tls.rax - // /// - // /// - // /// @return Returns the value of tls.rax - // /// - // [[nodiscard]] static constexpr auto - // bf_tls_rax() -> bsl::safe_u64 - // { - // return bsl::to_u64(bf_tls_rax_impl()); - // } - - // /// - // /// @brief Sets the value of tls.rax - // /// - // /// - // /// @param val The value to set tls.rax to - // /// - // static constexpr void - // bf_tls_set_rax(bsl::safe_u64 const &val) - // { - // bsl::expects(val.is_valid_and_checked()); - // bf_tls_set_rax_impl(val.get()); - // } - - // /// - // /// @brief Returns the value of tls.rbx - // /// - // /// - // /// @return Returns the value of tls.rbx - // /// - // [[nodiscard]] static constexpr auto - // bf_tls_rbx() -> bsl::safe_u64 - // { - // return bsl::to_u64(bf_tls_rbx_impl()); - // } - - // /// - // /// @brief Sets the value of tls.rbx - // /// - // /// - // /// @param val The value to set tls.rbx to - // /// - // static constexpr void - // bf_tls_set_rbx(bsl::safe_u64 const &val) - // { - // bsl::expects(val.is_valid_and_checked()); - // bf_tls_set_rbx_impl(val.get()); - // } - - // /// - // /// @brief Returns the value of tls.rcx - // /// - // /// - // /// @return Returns the value of tls.rcx - // /// - // [[nodiscard]] static constexpr auto - // bf_tls_rcx() -> bsl::safe_u64 - // { - // return bsl::to_u64(bf_tls_rcx_impl()); - // } - - // /// - // /// @brief Sets the value of tls.rcx - // /// - // /// - // /// @param val The value to set tls.rcx to - // /// - // static constexpr void - // bf_tls_set_rcx(bsl::safe_u64 const &val) - // { - // bsl::expects(val.is_valid_and_checked()); - // bf_tls_set_rcx_impl(val.get()); - // } - - // /// - // /// @brief Returns the value of tls.rdx - // /// - // /// - // /// @return Returns the value of tls.rdx - // /// - // [[nodiscard]] static constexpr auto - // bf_tls_rdx() -> bsl::safe_u64 - // { - // return bsl::to_u64(bf_tls_rdx_impl()); - // } - - // /// - // /// @brief Sets the value of tls.rdx - // /// - // /// - // /// @param val The value to set tls.rdx to - // /// - // static constexpr void - // bf_tls_set_rdx(bsl::safe_u64 const &val) - // { - // bsl::expects(val.is_valid_and_checked()); - // bf_tls_set_rdx_impl(val.get()); - // } - - // /// - // /// @brief Returns the value of tls.rbp - // /// - // /// - // /// @return Returns the value of tls.rbp - // /// - // [[nodiscard]] static constexpr auto - // bf_tls_rbp() -> bsl::safe_u64 - // { - // return bsl::to_u64(bf_tls_rbp_impl()); - // } - - // /// - // /// @brief Sets the value of tls.rbp - // /// - // /// - // /// @param val The value to set tls.rbp to - // /// - // static constexpr void - // bf_tls_set_rbp(bsl::safe_u64 const &val) - // { - // bsl::expects(val.is_valid_and_checked()); - // bf_tls_set_rbp_impl(val.get()); - // } - - // /// - // /// @brief Returns the value of tls.rsi - // /// - // /// - // /// @return Returns the value of tls.rsi - // /// - // [[nodiscard]] static constexpr auto - // bf_tls_rsi() -> bsl::safe_u64 - // { - // return bsl::to_u64(bf_tls_rsi_impl()); - // } - - // /// - // /// @brief Sets the value of tls.rsi - // /// - // /// - // /// @param val The value to set tls.rsi to - // /// - // static constexpr void - // bf_tls_set_rsi(bsl::safe_u64 const &val) - // { - // bsl::expects(val.is_valid_and_checked()); - // bf_tls_set_rsi_impl(val.get()); - // } - - // /// - // /// @brief Returns the value of tls.rdi - // /// - // /// - // /// @return Returns the value of tls.rdi - // /// - // [[nodiscard]] static constexpr auto - // bf_tls_rdi() -> bsl::safe_u64 - // { - // return bsl::to_u64(bf_tls_rdi_impl()); - // } - - // /// - // /// @brief Sets the value of tls.rdi - // /// - // /// - // /// @param val The value to set tls.rdi to - // /// - // static constexpr void - // bf_tls_set_rdi(bsl::safe_u64 const &val) - // { - // bsl::expects(val.is_valid_and_checked()); - // bf_tls_set_rdi_impl(val.get()); - // } - - // /// - // /// @brief Returns the value of tls.r8 - // /// - // /// - // /// @return Returns the value of tls.r8 - // /// - // [[nodiscard]] static constexpr auto - // bf_tls_r8() -> bsl::safe_u64 - // { - // return bsl::to_u64(bf_tls_r8_impl()); - // } - - // /// - // /// @brief Sets the value of tls.r8 - // /// - // /// - // /// @param val The value to set tls.r8 to - // /// - // static constexpr void - // bf_tls_set_r8(bsl::safe_u64 const &val) - // { - // bsl::expects(val.is_valid_and_checked()); - // bf_tls_set_r8_impl(val.get()); - // } - - // /// - // /// @brief Returns the value of tls.r9 - // /// - // /// - // /// @return Returns the value of tls.r9 - // /// - // [[nodiscard]] static constexpr auto - // bf_tls_r9() -> bsl::safe_u64 - // { - // return bsl::to_u64(bf_tls_r9_impl()); - // } - - // /// - // /// @brief Sets the value of tls.r9 - // /// - // /// - // /// @param val The value to set tls.r9 to - // /// - // static constexpr void - // bf_tls_set_r9(bsl::safe_u64 const &val) - // { - // bsl::expects(val.is_valid_and_checked()); - // bf_tls_set_r9_impl(val.get()); - // } - - // /// - // /// @brief Returns the value of tls.r10 - // /// - // /// - // /// @return Returns the value of tls.r10 - // /// - // [[nodiscard]] static constexpr auto - // bf_tls_r10() -> bsl::safe_u64 - // { - // return bsl::to_u64(bf_tls_r10_impl()); - // } - - // /// - // /// @brief Sets the value of tls.r10 - // /// - // /// - // /// @param val The value to set tls.r10 to - // /// - // static constexpr void - // bf_tls_set_r10(bsl::safe_u64 const &val) - // { - // bsl::expects(val.is_valid_and_checked()); - // bf_tls_set_r10_impl(val.get()); - // } - - // /// - // /// @brief Returns the value of tls.r11 - // /// - // /// - // /// @return Returns the value of tls.r11 - // /// - // [[nodiscard]] static constexpr auto - // bf_tls_r11() -> bsl::safe_u64 - // { - // return bsl::to_u64(bf_tls_r11_impl()); - // } - - // /// - // /// @brief Sets the value of tls.r11 - // /// - // /// - // /// @param val The value to set tls.r11 to - // /// - // static constexpr void - // bf_tls_set_r11(bsl::safe_u64 const &val) - // { - // bsl::expects(val.is_valid_and_checked()); - // bf_tls_set_r11_impl(val.get()); - // } - - // /// - // /// @brief Returns the value of tls.r12 - // /// - // /// - // /// @return Returns the value of tls.r12 - // /// - // [[nodiscard]] static constexpr auto - // bf_tls_r12() -> bsl::safe_u64 - // { - // return bsl::to_u64(bf_tls_r12_impl()); - // } - - // /// - // /// @brief Sets the value of tls.r12 - // /// - // /// - // /// @param val The value to set tls.r12 to - // /// - // static constexpr void - // bf_tls_set_r12(bsl::safe_u64 const &val) - // { - // bsl::expects(val.is_valid_and_checked()); - // bf_tls_set_r12_impl(val.get()); - // } - - // /// - // /// @brief Returns the value of tls.r13 - // /// - // /// - // /// @return Returns the value of tls.r13 - // /// - // [[nodiscard]] static constexpr auto - // bf_tls_r13() -> bsl::safe_u64 - // { - // return bsl::to_u64(bf_tls_r13_impl()); - // } - - // /// - // /// @brief Sets the value of tls.r13 - // /// - // /// - // /// @param val The value to set tls.r13 to - // /// - // static constexpr void - // bf_tls_set_r13(bsl::safe_u64 const &val) - // { - // bsl::expects(val.is_valid_and_checked()); - // bf_tls_set_r13_impl(val.get()); - // } - - // /// - // /// @brief Returns the value of tls.r14 - // /// - // /// - // /// @return Returns the value of tls.r14 - // /// - // [[nodiscard]] static constexpr auto - // bf_tls_r14() -> bsl::safe_u64 - // { - // return bsl::to_u64(bf_tls_r14_impl()); - // } - - // /// - // /// @brief Sets the value of tls.r14 - // /// - // /// - // /// @param val The value to set tls.r14 to - // /// - // static constexpr void - // bf_tls_set_r14(bsl::safe_u64 const &val) - // { - // bsl::expects(val.is_valid_and_checked()); - // bf_tls_set_r14_impl(val.get()); - // } - - // /// - // /// @brief Returns the value of tls.r15 - // /// - // /// - // /// @return Returns the value of tls.r15 - // /// - // [[nodiscard]] static constexpr auto - // bf_tls_r15() -> bsl::safe_u64 - // { - // return bsl::to_u64(bf_tls_r15_impl()); - // } - - // /// - // /// @brief Sets the value of tls.r15 - // /// - // /// - // /// @param val The value to set tls.r15 to - // /// - // static constexpr void - // bf_tls_set_r15(bsl::safe_u64 const &val) - // { - // bsl::expects(val.is_valid_and_checked()); - // bf_tls_set_r15_impl(val.get()); - // } - - // /// - // /// @brief Returns the value of tls.extid - // /// - // /// - // /// @return Returns the value of tls.extid - // /// - // [[nodiscard]] static constexpr auto - // bf_tls_extid() -> bsl::safe_u16 - // { - // return bsl::to_u16(bf_tls_extid_impl()); - // } - - // /// - // /// @brief Returns the value of tls.vmid - // /// - // /// - // /// @return Returns the value of tls.vmid - // /// - // [[nodiscard]] static constexpr auto - // bf_tls_vmid() -> bsl::safe_u16 - // { - // return bsl::to_u16(bf_tls_vmid_impl()); - // } - - // /// - // /// @brief Returns the value of tls.vpid - // /// - // /// - // /// @return Returns the value of tls.vpid - // /// - // [[nodiscard]] static constexpr auto - // bf_tls_vpid() -> bsl::safe_u16 - // { - // return bsl::to_u16(bf_tls_vpid_impl()); - // } - - // /// - // /// @brief Returns the value of tls.vsid - // /// - // /// - // /// @return Returns the value of tls.vsid - // /// - // [[nodiscard]] static constexpr auto - // bf_tls_vsid() -> bsl::safe_u16 - // { - // return bsl::to_u16(bf_tls_vsid_impl()); - // } - - // /// - // /// @brief Returns the value of tls.ppid - // /// - // /// - // /// @return Returns the value of tls.ppid - // /// - // [[nodiscard]] static constexpr auto - // bf_tls_ppid() -> bsl::safe_u16 - // { - // return bsl::to_u16(bf_tls_ppid_impl()); - // } - - // /// - // /// @brief Returns the value of tls.online_pps - // /// - // /// - // /// @return Returns the value of tls.online_pps - // /// - // [[nodiscard]] static constexpr auto - // bf_tls_online_pps() -> bsl::safe_u16 - // { - // return bsl::to_u16(bf_tls_online_pps_impl()); - // } - - // // --------------------------------------------------------------------- - // // bf_vm_ops - // // --------------------------------------------------------------------- - - // /// - // /// @brief This syscall tells the microkernel to create a VM - // /// and return it's ID. - // /// - // /// - // /// @return Returns the resulting ID, or bsl::safe_u16::failure() - // /// on failure. - // /// - // - // bf_vm_op_create_vm() -> bsl::safe_u16 - // { - // bsl::safe_u16 mut_vmid{}; - - // bf_status_t const ret{bf_vm_op_create_vm_impl(m_hndl.get(), mut_vmid.data())}; - // if (ret != BF_STATUS_SUCCESS)) { - // bsl::error() << "bf_vm_op_create_vm failed with status " // -- - // << bsl::hex(ret) // -- - // << bsl::endl // -- - // << bsl::here(); - - // return bsl::safe_u16::failure(); - // } - - // return mut_vmid; - // } - - // /// - // /// @brief This syscall tells the microkernel to destroy a VM - // /// given an ID. - // /// - // /// - // /// @param vmid The ID of the VM to destroy - // /// @return Returns bsl::errc_success on success, bsl::errc_failure - // /// otherwise - // /// - // - // bf_vm_op_destroy_vm(bsl::safe_u16 const &vmid) -> bsl::errc_type - // { - // bsl::expects(vmid.is_valid_and_checked()); - // bsl::expects(vmid != BF_INVALID_ID); - // bsl::expects(bsl::to_umx(vmid) < HYPERVISOR_MAX_VMS); - - // bf_status_t const ret{bf_vm_op_destroy_vm_impl(m_hndl.get(), vmid.get())}; - // if (ret != BF_STATUS_SUCCESS)) { - // bsl::error() << "bf_vm_op_destroy_vm failed with status " // -- - // << bsl::hex(ret) // -- - // << bsl::endl // -- - // << bsl::here(); - - // return bsl::errc_failure; - // } - - // return bsl::errc_success; - // } - - // /// - // /// @brief This syscall tells the microkernel to map a physical - // /// address into the VM's direct map. This is the same as directly - // /// accessing the direct map with the difference being that - // /// software can provide a physical address and receive the - // /// precalculated virtual address. - // /// - // /// - // /// @param vmid The ID of the VM to map the physical address to - // /// @param phys The physical address to map - // /// @return Returns a pointer to the map on success, returns a - // /// nullptr on failure. - // /// - // template - // - // bf_vm_op_map_direct(bsl::safe_u16 const &vmid, bsl::safe_u64 const &phys) -> T * - // { - // bsl::expects(vmid.is_valid_and_checked()); - // bsl::expects(vmid != BF_INVALID_ID); - // bsl::expects(bsl::to_umx(vmid) < HYPERVISOR_MAX_VMS); - // bsl::expects(phys.is_valid_and_checked()); - // bsl::expects(phys.is_pos()); - // bsl::expects(phys < HYPERVISOR_EXT_DIRECT_MAP_SIZE); - // bsl::expects(bf_is_page_aligned(phys)); - - // static_assert(bsl::is_pod::value); - // static_assert(sizeof(T) <= HYPERVISOR_PAGE_SIZE); - - // void *mut_ptr{}; - - // bf_status_t const ret{ - // bf_vm_op_map_direct_impl(m_hndl.get(), vmid.get(), phys.get(), &mut_ptr)}; - // if (ret != BF_STATUS_SUCCESS)) { - // bsl::error() << "bf_vm_op_map_direct failed with status " // -- - // << bsl::hex(ret) // -- - // << bsl::endl // -- - // << bsl::here(); - - // return nullptr; - // } - - // return static_cast(mut_ptr); - // } - - // /// - // /// @brief This syscall tells the microkernel to unmap a previously - // /// mapped virtual address in the direct map. Unlike - // /// bf_vm_op_unmap_direct_broadcast, this syscall does not flush the - // /// TLB on any other PP, meaning this unmap is local to the PP the - // /// call is made on. Attempting to unmap a virtual address from the - // /// direct map that has been accessed on any other PP other than - // /// the PP this syscall is executed on will result in undefined - // /// behavior. This syscall is designed to support mapping and then - // /// immediately unmapping a physical address on a single PP during - // /// a single VMExit. It can also be used to map on a PP and then - // /// use unmap on the same PP during multiple VMExits, but special - // /// care must be taken to ensure no other PP can access the map, - // /// otherwise UB will occur. - // /// - // /// - // /// @param vmid The ID of the VM to unmap the virtual address from - // /// @param virt The virtual address to unmap - // /// @return Returns bsl::errc_success on success, bsl::errc_failure - // /// otherwise - // /// - // template - // - // bf_vm_op_unmap_direct(bsl::safe_u16 const &vmid, T *const virt) - // -> bsl::errc_type - // { - // constexpr auto min_addr{HYPERVISOR_EXT_DIRECT_MAP_ADDR}; - // constexpr auto max_addr{(min_addr + HYPERVISOR_EXT_DIRECT_MAP_SIZE).checked()}; - - // bsl::safe_u64 const virt{reinterpret_cast(virt)}; - - // bsl::expects(vmid.is_valid_and_checked()); - // bsl::expects(vmid != BF_INVALID_ID); - // bsl::expects(bsl::to_umx(vmid) < HYPERVISOR_MAX_VMS); - // bsl::expects(virt.is_valid_and_checked()); - // bsl::expects(virt.is_pos()); - // bsl::expects(virt > min_addr); - // bsl::expects(virt < max_addr); - // bsl::expects(bf_is_page_aligned(virt)); - - // static_assert(bsl::is_pod::value); - // static_assert(sizeof(T) <= HYPERVISOR_PAGE_SIZE); - - // bf_status_t const ret{bf_vm_op_unmap_direct_impl(m_hndl.get(), vmid.get(), virt.get())}; - // if (ret != BF_STATUS_SUCCESS)) { - // bsl::error() << "bf_vm_op_unmap_direct failed with status " // -- - // << bsl::hex(ret) // -- - // << bsl::endl // -- - // << bsl::here(); - - // return bsl::errc_failure; - // } - - // return bsl::errc_success; - // } - - // /// - // /// @brief This syscall tells the microkernel to unmap a previously - // /// mapped virtual address in the direct map. Unlike - // /// bf_vm_op_unmap_direct, this syscall performs a broadcast TLB flush - // /// which means it can be safely used on all direct mapped - // /// addresses. The downside of using this function is that it can - // /// be a lot slower than bf_vm_op_unmap_direct, especially on - // /// systems with a lot of PPs. - // /// - // /// - // /// @param vmid The ID of the VM to unmap the virtual address from - // /// @param virt The virtual address to unmap - // /// @return Returns bsl::errc_success on success, bsl::errc_failure - // /// otherwise - // /// - // template - // - // bf_vm_op_unmap_direct_broadcast(bsl::safe_u16 const &vmid, T *const virt) - // -> bsl::errc_type - // { - // constexpr auto min_addr{HYPERVISOR_EXT_DIRECT_MAP_ADDR}; - // constexpr auto max_addr{(min_addr + HYPERVISOR_EXT_DIRECT_MAP_SIZE).checked()}; - - // bsl::safe_u64 const virt{reinterpret_cast(virt)}; - - // bsl::expects(vmid.is_valid_and_checked()); - // bsl::expects(vmid != BF_INVALID_ID); - // bsl::expects(bsl::to_umx(vmid) < HYPERVISOR_MAX_VMS); - // bsl::expects(virt.is_valid_and_checked()); - // bsl::expects(virt.is_pos()); - // bsl::expects(virt > min_addr); - // bsl::expects(virt < max_addr); - // bsl::expects(bf_is_page_aligned(virt)); - - // static_assert(bsl::is_pod::value); - // static_assert(sizeof(T) <= HYPERVISOR_PAGE_SIZE); - - // bf_status_t const ret{ - // bf_vm_op_unmap_direct_broadcast_impl(m_hndl.get(), vmid.get(), virt.get())}; - // if (ret != BF_STATUS_SUCCESS)) { - // bsl::error() << "bf_vm_op_unmap_direct_broadcast_impl failed with status " // -- - // << bsl::hex(ret) // -- - // << bsl::endl // -- - // << bsl::here(); - - // return bsl::errc_failure; - // } - - // return bsl::errc_success; - // } - - // // --------------------------------------------------------------------- - // // bf_vp_ops - // // --------------------------------------------------------------------- - - // /// - // /// @brief This syscall tells the microkernel to create a VP given the - // /// IDs of the VM and PP the VP will be assigned to. Upon success, - // /// this syscall returns the ID of the newly created VP. - // /// - // /// - // /// @param vmid The ID of the VM to assign the newly created VP to - // /// @param ppid The ID of the PP to assign the newly created VP to - // /// @return Returns the resulting ID, or bsl::safe_u16::failure() - // /// on failure. - // /// - // /// - // - // bf_vp_op_create_vp(bsl::safe_u16 const &vmid, bsl::safe_u16 const &ppid) - // -> bsl::safe_u16 - // { - // bsl::expects(vmid.is_valid_and_checked()); - // bsl::expects(vmid != BF_INVALID_ID); - // bsl::expects(bsl::to_umx(vmid) < HYPERVISOR_MAX_VMS); - // bsl::expects(ppid.is_valid_and_checked()); - // bsl::expects(ppid != BF_INVALID_ID); - // bsl::expects(bsl::to_umx(ppid) < HYPERVISOR_MAX_PPS); - - // bsl::safe_u16 mut_vpid{}; - - // bf_status_t const ret{ - // bf_vp_op_create_vp_impl(m_hndl.get(), vmid.get(), ppid.get(), mut_vpid.data())}; - // if (ret != BF_STATUS_SUCCESS)) { - // bsl::error() << "bf_vp_op_create_vp failed with status " // -- - // << bsl::hex(ret) // -- - // << bsl::endl // -- - // << bsl::here(); - - // return bsl::safe_u16::failure(); - // } - - // return mut_vpid; - // } - - // /// - // /// @brief This syscall tells the microkernel to destroy a VP - // /// given an ID. - // /// - // /// - // /// @param vpid The ID of the VP to destroy - // /// @return Returns bsl::errc_success on success, bsl::errc_failure - // /// otherwise - // /// - // - // bf_vp_op_destroy_vp(bsl::safe_u16 const &vpid) -> bsl::errc_type - // { - // bsl::expects(vpid.is_valid_and_checked()); - // bsl::expects(vpid != BF_INVALID_ID); - // bsl::expects(bsl::to_umx(vpid) < HYPERVISOR_MAX_VPS); - - // bf_status_t const ret{bf_vp_op_destroy_vp_impl(m_hndl.get(), vpid.get())}; - // if (ret != BF_STATUS_SUCCESS)) { - // bsl::error() << "bf_vp_op_destroy_vp failed with status " // -- - // << bsl::hex(ret) // -- - // << bsl::endl // -- - // << bsl::here(); - - // return bsl::errc_failure; - // } - - // return bsl::errc_success; - // } - - // /// - // /// @brief This syscall tells the microkernel to migrate a VP from one PP - // /// to another PP. This function does not execute the VP (use - // /// bf_vs_op_run for that), but instead allows bf_vs_op_run to - // /// execute a VP on a PP that it was not originally assigned to. - // /// - // /// When a VP is migrated, all of the VSs that are assigned to the - // /// requested VP are also migrated to this new PP as well. From an - // /// AMD/Intel point of view, this clears the VMCS/VMCB for each VS - // /// assigned to the VP. On Intel, it also loads the newly cleared VS - // /// and sets the launched state to false, ensuring the next - // /// bf_vs_op_run will use VMLaunch instead of VMResume. - // /// - // /// It should be noted that the migration of a VS from one PP to - // /// another does not happen during the execution of this ABI. This - // /// ABI simply tells the microkernel that the requested VP may now - // /// execute on the requested PP. This will cause a mismatch between - // /// the assigned PP for a VP and the assigned PP for a VS. The - // /// microkernel will detect this mismatch when an extension attempts - // /// to execute bf_vs_op_run. When this occurs, the microkernel will - // /// ensure the VP is being run on the PP it was assigned to during - // /// migration, and then it will check to see if the PP of the VS - // /// matches. If it doesn't, it will then perform a migration of that - // /// VS at that time. This ensures that the microkernel is only - // /// migrations VSs when it needs to, and it ensures the VS is - // /// cleared an loaded (in the case of Intel) on the PP it will be - // /// executed on, which is a requirement for VMCS migration. An - // /// extension can determine which VSs have been migrated by looking - // /// at the assigned PP of a VS. If it doesn't match the VP it was - // /// assigned to, it has not been migrated. Finally, an extension is - // /// free to read/write to the VSs state, even if it has not been - // /// migrated. The only requirement for migration is execution (meaning - // /// VMRun/VMLaunch/VMResume). - // /// - // /// Any additional migration responsibilities, like TSC - // /// synchronization, must be performed by the extension. - // /// - // /// - // /// @param vpid The ID of the VP to migrate - // /// @param ppid The ID of the PP to assign the provided VP to - // /// @return Returns bsl::errc_success on success, bsl::errc_failure - // /// otherwise - // /// - // - // bf_vp_op_migrate(bsl::safe_u16 const &vpid, bsl::safe_u16 const &ppid) - // -> bsl::errc_type - // { - // bsl::expects(vpid.is_valid_and_checked()); - // bsl::expects(vpid != BF_INVALID_ID); - // bsl::expects(bsl::to_umx(vpid) < HYPERVISOR_MAX_VPS); - // bsl::expects(ppid.is_valid_and_checked()); - // bsl::expects(ppid != BF_INVALID_ID); - // bsl::expects(bsl::to_umx(ppid) < HYPERVISOR_MAX_PPS); - - // bf_status_t const ret{bf_vp_op_migrate_impl(m_hndl.get(), vpid.get(), ppid.get())}; - // if (ret != BF_STATUS_SUCCESS)) { - // bsl::error() << "bf_vp_op_migrate failed with status " // -- - // << bsl::hex(ret) // -- - // << bsl::endl // -- - // << bsl::here(); - - // return bsl::errc_failure; - // } - - // return bsl::errc_success; - // } - - // // --------------------------------------------------------------------- - // // bf_vs_ops - // // --------------------------------------------------------------------- - - // /// - // /// @brief This syscall tells the microkernel to create a VS - // /// and return it's ID. - // /// - // /// - // /// @param vpid The ID of the VP to assign the newly created VS to - // /// @param ppid The resulting VSID of the newly created VS - // /// @return Returns the resulting ID, or bsl::safe_u16::failure() - // /// on failure. - // /// - // /// - // - // bf_vs_op_create_vs(bsl::safe_u16 const &vpid, bsl::safe_u16 const &ppid) - // -> bsl::safe_u16 - // { - // bsl::expects(vpid.is_valid_and_checked()); - // bsl::expects(vpid != BF_INVALID_ID); - // bsl::expects(bsl::to_umx(vpid) < HYPERVISOR_MAX_VPS); - // bsl::expects(ppid.is_valid_and_checked()); - // bsl::expects(ppid != BF_INVALID_ID); - // bsl::expects(bsl::to_umx(ppid) < HYPERVISOR_MAX_PPS); - - // bsl::safe_u16 mut_vsid{}; - - // bf_status_t const ret{ - // bf_vs_op_create_vs_impl(m_hndl.get(), vpid.get(), ppid.get(), mut_vsid.data())}; - // if (ret != BF_STATUS_SUCCESS)) { - // bsl::error() << "bf_vs_op_create_vs failed with status " // -- - // << bsl::hex(ret) // -- - // << bsl::endl // -- - // << bsl::here(); - - // return bsl::safe_u16::failure(); - // } - - // return mut_vsid; - // } - - // /// - // /// @brief This syscall tells the microkernel to destroy a VS - // /// given an ID. - // /// - // /// - // /// @param vsid The ID of the VS to destroy - // /// @return Returns bsl::errc_success on success, bsl::errc_failure - // /// otherwise - // /// - // - // bf_vs_op_destroy_vs(bsl::safe_u16 const &vsid) -> bsl::errc_type - // { - // bsl::expects(vsid.is_valid_and_checked()); - // bsl::expects(vsid != BF_INVALID_ID); - // bsl::expects(bsl::to_umx(vsid) < HYPERVISOR_MAX_VSS); - - // bf_status_t const ret{bf_vs_op_destroy_vs_impl(m_hndl.get(), vsid.get())}; - // if (ret != BF_STATUS_SUCCESS)) { - // bsl::error() << "bf_vs_op_destroy_vs failed with status " // -- - // << bsl::hex(ret) // -- - // << bsl::endl // -- - // << bsl::here(); - - // return bsl::errc_failure; - // } - - // return bsl::errc_success; - // } - - // /// - // /// @brief This syscall tells the microkernel to initialize a VS using - // /// the root VP state provided by the loader using the current PPID. - // /// - // /// - // /// @param vsid The ID of the VS to initialize - // /// @return Returns bsl::errc_success on success, bsl::errc_failure - // /// otherwise - // /// - // - // bf_vs_op_init_as_root(bsl::safe_u16 const &vsid) -> bsl::errc_type - // { - // bsl::expects(vsid.is_valid_and_checked()); - // bsl::expects(vsid != BF_INVALID_ID); - // bsl::expects(bsl::to_umx(vsid) < HYPERVISOR_MAX_VSS); - - // bf_status_t const ret{bf_vs_op_init_as_root_impl(m_hndl.get(), vsid.get())}; - // if (ret != BF_STATUS_SUCCESS)) { - // bsl::error() << "bf_vs_op_init_as_root failed with status " // -- - // << bsl::hex(ret) // -- - // << bsl::endl // -- - // << bsl::here(); - - // return bsl::errc_failure; - // } - - // return bsl::errc_success; - // } - - // /// - // /// @brief Reads a CPU register from the VS given a bf_reg_t. Note - // /// that the bf_reg_t is architecture specific. - // /// - // /// - // /// @param vsid The ID of the VS to read from - // /// @param reg A bf_reg_t defining which register to read - // /// @return Returns the value read, or bsl::safe_u64::failure() - // /// on failure. - // /// - // - // bf_vs_op_read(bsl::safe_u16 const &vsid, bf_reg_t const reg) const -> bsl::safe_u64 - // { - // bsl::expects(vsid.is_valid_and_checked()); - // bsl::expects(vsid != BF_INVALID_ID); - // bsl::expects(bsl::to_umx(vsid) < HYPERVISOR_MAX_VSS); - // bsl::expects(reg < syscall::bf_reg_t::bf_reg_t_invalid); - // bsl::expects(reg != syscall::bf_reg_t::bf_reg_t_unsupported); - - // bsl::safe_u64 mut_val{}; - - // bf_status_t const ret{ - // bf_vs_op_read_impl(m_hndl.get(), vsid.get(), reg, mut_val.data())}; - // if (ret != BF_STATUS_SUCCESS)) { - // bsl::error() << "bf_vs_op_read failed with status " // -- - // << bsl::hex(ret) // -- - // << bsl::endl // -- - // << bsl::here(); - - // return bsl::safe_u64::failure(); - // } - - // return mut_val; - // } - - // /// - // /// @brief Writes to a CPU register in the VS given a bf_reg_t and the - // /// value to write. Note that the bf_reg_t is architecture specific. - // /// - // /// - // /// @param vsid The ID of the VS to write to - // /// @param reg A bf_reg_t defining which register to write to - // /// @param value The value to write to the requested register - // /// @return Returns bsl::errc_success on success, bsl::errc_failure - // /// otherwise - // /// - // - // bf_vs_op_write( - // bsl::safe_u16 const &vsid, bf_reg_t const reg, bsl::safe_u64 const &value) - // -> bsl::errc_type - // { - // bsl::expects(vsid.is_valid_and_checked()); - // bsl::expects(vsid != BF_INVALID_ID); - // bsl::expects(reg < syscall::bf_reg_t::bf_reg_t_invalid); - // bsl::expects(reg != syscall::bf_reg_t::bf_reg_t_unsupported); - // bsl::expects(bsl::to_umx(vsid) < HYPERVISOR_MAX_VSS); - // bsl::expects(value.is_valid_and_checked()); - - // bf_status_t const ret{bf_vs_op_write_impl(m_hndl.get(), vsid.get(), reg, value.get())}; - // if (ret != BF_STATUS_SUCCESS)) { - // bsl::error() << "bf_vs_op_write failed with status " // -- - // << bsl::hex(ret) // -- - // << bsl::endl // -- - // << bsl::here(); - - // return bsl::errc_failure; - // } - - // return bsl::errc_success; - // } - - // /// - // /// @brief bf_vs_op_run tells the microkernel to execute a given VS on - // /// behalf of a given VP and VM. This system call only returns if an - // /// error occurs. On success, this system call will physically execute - // /// the requested VM and VP using the requested VS, and the extension - // /// will only execute again on the next VMExit. - // /// - // /// Unless an extension needs to change the active VM, VP or VS, the - // /// extension should use bf_vs_op_run_current instead of - // /// bf_vs_op_run. bf_vs_op_run is slow as it must perform a series of - // /// checks to determine if it has any work to perform before execution - // /// of a VM can occur. - // /// - // /// Unlike bf_vs_op_run_current which is really just a return to - // /// microkernel execution, bf_vs_op_run must perform the following - // /// operations: - // /// - It first verifies that the provided VM, VP and VS are all - // /// created. Meaning, and extension must first use the create ABI - // /// to properly create a VM, VP and VS before it may be used. - // /// - Next, it must ensure VM, VP and VS assignment is correct. A - // /// newly created VP and VS are unassigned. Once bf_vs_op_run is - // /// executed, the VP is assigned to the provided VM and the VS is - // /// assigned to the provided VP. The VP and VS are also both - // /// assigned to the PP bf_vs_op_run is executed on. Once these - // /// assignments take place, an extension cannot change them, and any - // /// attempt to run a VP or VS on a VM, VP or PP they are not - // /// assigned to will fail. It is impossible to change the assigned of - // /// a VM or VP, but an extension can change the assignment of a VP - // /// and VSs PP by using the bf_vp_op_migrate function. - // /// - Next, bf_vs_op_run must determine if it needs to migrate a VS - // /// to the PP the VS is being executed on by bf_vs_op_run. For more - // /// information about how this works, please see bf_vp_op_migrate. - // /// - Finally, bf_vs_op_run must ensure the active VM, VP and VS are - // /// set to the VM, VP and VS provided to this ABI. Any changes in - // /// the active state could cause additional operations to take place. - // /// For example, the VS must transfer the TLS state of the general - // /// purpose registers to its internal cache so that the VS that is - // /// about to become active can use the TLS block instead. - // /// - // /// - // /// @param vmid The ID of the VM to run - // /// @param vpid The ID of the VP to run - // /// @param vsid The ID of the VS to run - // /// @return Returns bsl::errc_success on success, bsl::errc_failure - // /// otherwise - // /// - // - // bf_vs_op_run( - // bsl::safe_u16 const &vmid, - // bsl::safe_u16 const &vpid, - // bsl::safe_u16 const &vsid) -> bsl::errc_type - // { - // bsl::expects(vmid.is_valid_and_checked()); - // bsl::expects(vmid != BF_INVALID_ID); - // bsl::expects(bsl::to_umx(vmid) < HYPERVISOR_MAX_VMS); - // bsl::expects(vpid.is_valid_and_checked()); - // bsl::expects(vpid != BF_INVALID_ID); - // bsl::expects(bsl::to_umx(vpid) < HYPERVISOR_MAX_VPS); - // bsl::expects(vsid.is_valid_and_checked()); - // bsl::expects(vsid != BF_INVALID_ID); - // bsl::expects(bsl::to_umx(vsid) < HYPERVISOR_MAX_VSS); - - // bf_status_t const ret{ - // bf_vs_op_run_impl(m_hndl.get(), vmid.get(), vpid.get(), vsid.get())}; - // if (ret != BF_STATUS_SUCCESS)) { - // bsl::error() << "bf_vs_op_run failed with status " // -- - // << bsl::hex(ret) // -- - // << bsl::endl // -- - // << bsl::here(); - - // return bsl::errc_failure; - // } - - // return bsl::errc_success; - // } - - // /// - // /// @brief bf_vs_op_run_current tells the microkernel to execute the - // /// currently active VS, VP and VM. - // /// - // /// - // /// @return Returns bsl::errc_success on success, bsl::errc_failure - // /// otherwise - // /// - // - // bf_vs_op_run_current() -> bsl::errc_type - // { - // bf_status_t const ret{bf_vs_op_run_current_impl(m_hndl.get())}; - // if (ret != BF_STATUS_SUCCESS)) { - // bsl::error() << "bf_vs_op_run_current failed with status " // -- - // << bsl::hex(ret) // -- - // << bsl::endl // -- - // << bsl::here(); - - // return bsl::errc_failure; - // } - - // return bsl::errc_success; - // } - - // /// - // /// @brief This syscall tells the microkernel to advance the instruction - // /// pointer in the requested VS. - // /// - // /// - // /// @param vsid The ID of the VS advance the IP in - // /// @return Returns bsl::errc_success on success, bsl::errc_failure - // /// otherwise - // /// - // - // bf_vs_op_advance_ip(bsl::safe_u16 const &vsid) -> bsl::errc_type - // { - // bsl::expects(vsid.is_valid_and_checked()); - // bsl::expects(vsid != BF_INVALID_ID); - // bsl::expects(bsl::to_umx(vsid) < HYPERVISOR_MAX_VSS); - - // bf_status_t const ret{bf_vs_op_advance_ip_impl(m_hndl.get(), vsid.get())}; - // if (ret != BF_STATUS_SUCCESS)) { - // bsl::error() << "bf_vs_op_advance_ip failed with status " // -- - // << bsl::hex(ret) // -- - // << bsl::endl // -- - // << bsl::here(); - - // return bsl::errc_failure; - // } - - // return bsl::errc_success; - // } - - // /// - // /// @brief This syscall tells the microkernel to advance the instruction - // /// pointer in the currently active VS and run the currently active - // /// VS, VP and VM (i.e., this combines bf_vs_op_advance_ip and - // /// bf_vs_op_advance_ip). - // /// - // /// - // /// @return Returns bsl::errc_success on success, bsl::errc_failure - // /// otherwise - // /// - // - // bf_vs_op_advance_ip_and_run_current() -> bsl::errc_type - // { - // bf_status_t const ret{bf_vs_op_advance_ip_and_run_current_impl(m_hndl.get())}; - // if (ret != BF_STATUS_SUCCESS)) { - // bsl::error() << "bf_vs_op_advance_ip_and_run_current failed with status " // -- - // << bsl::hex(ret) // -- - // << bsl::endl // -- - // << bsl::here(); - - // return bsl::errc_failure; - // } - - // return bsl::errc_success; - // } - - // /// - // /// @brief This syscall tells the microkernel to promote the requested - // /// VS. This will stop the hypervisor complete on the physical - // /// processor that this syscall is executed on and replace it's state - // /// with the state in the VS. Note that this syscall only returns - // /// on error. - // /// - // /// - // /// @param vsid The ID of the VS to promote - // /// @return Returns bsl::errc_success on success, bsl::errc_failure - // /// otherwise - // /// - // - // bf_vs_op_promote(bsl::safe_u16 const &vsid) -> bsl::errc_type - // { - // bsl::expects(vsid.is_valid_and_checked()); - // bsl::expects(vsid != BF_INVALID_ID); - // bsl::expects(bsl::to_umx(vsid) < HYPERVISOR_MAX_VSS); - - // bf_status_t const ret{bf_vs_op_promote_impl(m_hndl.get(), vsid.get())}; - // if (ret != BF_STATUS_SUCCESS)) { - // bsl::error() << "bf_vs_op_promote failed with status " // -- - // << bsl::hex(ret) // -- - // << bsl::endl // -- - // << bsl::here(); - - // return bsl::errc_failure; - // } - - // return bsl::errc_success; - // } - - // /// - // /// @brief bf_vs_op_clear tells the microkernel to clear the VS's - // /// hardware cache, if one exists. How this is used depends entirely - // /// on the hardware and is associated with AMD's VMCB Clean Bits, - // /// and Intel's VMClear instruction. See the associated documentation - // /// for more details. On AMD, this ABI clears the entire VMCB. For more - // /// fine grained control, use the write ABIs to manually modify the - // /// VMCB. - // /// - // /// - // /// @param vsid The ID of the VS to clear - // /// @return Returns bsl::errc_success on success, bsl::errc_failure - // /// otherwise - // /// - // - // bf_vs_op_clear(bsl::safe_u16 const &vsid) -> bsl::errc_type - // { - // bsl::expects(vsid.is_valid_and_checked()); - // bsl::expects(vsid != BF_INVALID_ID); - // bsl::expects(bsl::to_umx(vsid) < HYPERVISOR_MAX_VSS); - - // bf_status_t const ret{bf_vs_op_clear_impl(m_hndl.get(), vsid.get())}; - // if (ret != BF_STATUS_SUCCESS)) { - // bsl::error() << "bf_vs_op_clear failed with status " // -- - // << bsl::hex(ret) // -- - // << bsl::endl // -- - // << bsl::here(); - - // return bsl::errc_failure; - // } - - // return bsl::errc_success; - // } - - // // --------------------------------------------------------------------- - // // bf_intrinsic_ops - // // --------------------------------------------------------------------- - - // /// - // /// @brief Reads an MSR directly from the CPU given the address of - // /// the MSR to read. Note that this is specific to Intel/AMD only. - // /// Also note that not all MSRs can be read, and which MSRs that - // /// can be read is up to the microkernel's internal policy as well - // /// as which architecture the hypervisor is running on. - // /// - // /// - // /// @param msr The address of the MSR to read - // /// @return Returns the value read, or bsl::safe_u64::failure() - // /// on failure. - // /// - // - // bf_intrinsic_op_rdmsr(bsl::safe_u32 const &msr) const -> bsl::safe_u64 - // { - // bsl::expects(msr.is_valid_and_checked()); - - // bsl::safe_u64 mut_val{}; - - // bf_status_t const ret{ - // bf_intrinsic_op_rdmsr_impl(m_hndl.get(), msr.get(), mut_val.data())}; - // if (ret != BF_STATUS_SUCCESS)) { - // bsl::error() << "bf_intrinsic_op_rdmsr failed with status " // -- - // << bsl::hex(ret) // -- - // << bsl::endl // -- - // << bsl::here(); - - // return bsl::safe_u64::failure(); - // } - - // return mut_val; - // } - - // /// - // /// @brief Writes to an MSR directly from the CPU given the address of - // /// the MSR to write as well as the value to write. Note that this is - // /// specific to Intel/AMD only. Also note that not all MSRs can be - // /// written to, and which MSRs that can be written to is up to the - // /// microkernel's internal policy as well as which architecture the - // /// hypervisor is running on. - // /// - // /// - // /// @param msr The address of the MSR to write to - // /// @param val The value to write to the requested MSR - // /// @return Returns bsl::errc_success on success, bsl::errc_failure - // /// otherwise - // /// - // - // bf_intrinsic_op_wrmsr(bsl::safe_u32 const &msr, bsl::safe_u64 const &val) - // -> bsl::errc_type - // { - // bsl::expects(msr.is_valid_and_checked()); - // bsl::expects(val.is_valid_and_checked()); - - // bf_status_t const ret{bf_intrinsic_op_wrmsr_impl(m_hndl.get(), msr.get(), val.get())}; - // if (ret != BF_STATUS_SUCCESS)) { - // bsl::error() << "bf_intrinsic_op_wrmsr failed with status " // -- - // << bsl::hex(ret) // -- - // << bsl::endl // -- - // << bsl::here(); - - // return bsl::errc_failure; - // } - - // return bsl::errc_success; - // } - - // // --------------------------------------------------------------------- - // // bf_mem_ops - // // --------------------------------------------------------------------- - - // /// - // /// @brief bf_mem_op_alloc_page allocates a page, and maps this page - // /// into the direct map of the VM. - // /// - // /// - // /// @param mut_phys The physical address of the resulting page - // /// @return Returns a pointer to the newly allocated memory on success, - // /// or a nullptr on failure. - // /// - // - // bf_mem_op_alloc_page(bsl::safe_u64 &mut_phys) -> void * - // { - // bsl::expects(mut_phys.is_valid_and_checked()); - // void *mut_ptr{}; - - // bf_status_t const ret{ - // bf_mem_op_alloc_page_impl(m_hndl.get(), &mut_ptr, mut_phys.data())}; - // if (ret != BF_STATUS_SUCCESS)) { - // bsl::error() << "bf_mem_op_alloc_page failed with status " // -- - // << bsl::hex(ret) // -- - // << bsl::endl // -- - // << bsl::here(); - - // return nullptr; - // } - - // return mut_ptr; - // } - - // /// - // /// @brief bf_mem_op_alloc_page allocates a page, and maps this page - // /// into the direct map of the VM. - // /// - // /// - // /// @return Returns a pointer to the newly allocated memory on success, - // /// or a nullptr on failure. - // /// - // - // bf_mem_op_alloc_page() -> void * - // { - // bsl::safe_u64 mut_ignored{}; - // return this->bf_mem_op_alloc_page(mut_ignored); - // } - - // /// - // /// @brief bf_mem_op_alloc_huge allocates a physically contiguous block - // /// of memory. When allocating a page, the extension should keep in - // /// mind the following: - // /// - The total memory available to allocate from this pool is - // /// extremely limited. This should only be used when absolutely - // /// needed, and extensions should not expect more than 1 MB (might - // /// be less) of total memory available. - // /// - Memory allocated from the huge pool might be allocated using - // /// different schemes. For example, the microkernel might allocate - // /// in increments of a page, or it might use a buddy allocator that - // /// would allocate in multiples of 2. If the allocation size - // /// doesn't match the algorithm, internal fragmentation could - // /// occur, further limiting the total number of allocations this - // /// pool can support. - // /// - // /// - // /// @param size The total number of bytes to allocate - // /// @param mut_phys The physical address of the resulting memory - // /// @return Returns a pointer to the newly allocated memory on success, - // /// or a nullptr on failure. - // /// - // - // bf_mem_op_alloc_huge(bsl::safe_u64 const &size, bsl::safe_u64 &mut_phys) -> void * - // { - // bsl::expects(size.is_valid_and_checked()); - // bsl::expects(size.is_pos()); - // bsl::expects(bf_is_page_aligned(size)); - // bsl::expects(mut_phys.is_valid_and_checked()); - - // void *mut_ptr{}; - - // bf_status_t const ret{bf_mem_op_alloc_huge_impl( - // m_hndl.get(), size.get(), &mut_ptr, mut_phys.data())}; - // if (ret != BF_STATUS_SUCCESS)) { - // bsl::error() << "bf_mem_op_alloc_huge failed with status " // -- - // << bsl::hex(ret) // -- - // << bsl::endl // -- - // << bsl::here(); - - // return nullptr; - // } - - // return mut_ptr; - // } - - // /// - // /// @brief bf_mem_op_alloc_huge allocates a physically contiguous block - // /// of memory. When allocating a page, the extension should keep in - // /// mind the following: - // /// - The total memory available to allocate from this pool is - // /// extremely limited. This should only be used when absolutely - // /// needed, and extensions should not expect more than 1 MB (might - // /// be less) of total memory available. - // /// - Memory allocated from the huge pool might be allocated using - // /// different schemes. For example, the microkernel might allocate - // /// in increments of a page, or it might use a buddy allocator that - // /// would allocate in multiples of 2. If the allocation size - // /// doesn't match the algorithm, internal fragmentation could - // /// occur, further limiting the total number of allocations this - // /// pool can support. - // /// - // /// - // /// @param size The total number of bytes to allocate - // /// @return Returns a pointer to the newly allocated memory on success, - // /// or a nullptr on failure. - // /// - // - // bf_mem_op_alloc_huge(bsl::safe_u64 const &size) -> void * - // { - // bsl::safe_u64 mut_ignored{}; - // return this->bf_mem_op_alloc_huge(size, mut_ignored); - // } + /// + /// @brief Returns the handle that is used for syscalls. If this + /// class has not been initialized, a default (likely 0) handle + /// is returned. + /// + /// + /// @return Returns the handle that is used for syscalls. If this + /// class has not been initialized, a default (likely 0) handle + /// is returned. + /// + pub fn handle(&self) -> bsl::SafeU64 { + return self.m_hndl; + } + + // --------------------------------------------------------------------- + // TLS ops + // --------------------------------------------------------------------- + + /// + /// @brief Returns the value of tls.rax + /// + /// + /// @return Returns the value of tls.rax + /// + pub fn bf_tls_rax() -> bsl::SafeU64 { + unsafe { + return bsl::to_u64(crate::bf_tls_rax_impl()); + } + } + + /// + /// @brief Sets the value of tls.rax + /// + /// + /// @param val The value to set tls.rax to + /// + pub fn bf_tls_set_rax(val: bsl::SafeU64) { + bsl::expects(val.is_valid_and_checked()); + unsafe { + crate::bf_tls_set_rax_impl(val.get()); + } + } + + /// + /// @brief Returns the value of tls.rbx + /// + /// + /// @return Returns the value of tls.rbx + /// + pub fn bf_tls_rbx() -> bsl::SafeU64 { + unsafe { + return bsl::to_u64(crate::bf_tls_rbx_impl()); + } + } + + /// + /// @brief Sets the value of tls.rbx + /// + /// + /// @param val The value to set tls.rbx to + /// + pub fn bf_tls_set_rbx(val: bsl::SafeU64) { + bsl::expects(val.is_valid_and_checked()); + unsafe { + crate::bf_tls_set_rbx_impl(val.get()); + } + } + + /// + /// @brief Returns the value of tls.rcx + /// + /// + /// @return Returns the value of tls.rcx + /// + pub fn bf_tls_rcx() -> bsl::SafeU64 { + unsafe { + return bsl::to_u64(crate::bf_tls_rcx_impl()); + } + } + + /// + /// @brief Sets the value of tls.rcx + /// + /// + /// @param val The value to set tls.rcx to + /// + pub fn bf_tls_set_rcx(val: bsl::SafeU64) { + bsl::expects(val.is_valid_and_checked()); + unsafe { + crate::bf_tls_set_rcx_impl(val.get()); + } + } + + /// + /// @brief Returns the value of tls.rdx + /// + /// + /// @return Returns the value of tls.rdx + /// + pub fn bf_tls_rdx() -> bsl::SafeU64 { + unsafe { + return bsl::to_u64(crate::bf_tls_rdx_impl()); + } + } + + /// + /// @brief Sets the value of tls.rdx + /// + /// + /// @param val The value to set tls.rdx to + /// + pub fn bf_tls_set_rdx(val: bsl::SafeU64) { + bsl::expects(val.is_valid_and_checked()); + unsafe { + crate::bf_tls_set_rdx_impl(val.get()); + } + } + + /// + /// @brief Returns the value of tls.rbp + /// + /// + /// @return Returns the value of tls.rbp + /// + pub fn bf_tls_rbp() -> bsl::SafeU64 { + unsafe { + return bsl::to_u64(crate::bf_tls_rbp_impl()); + } + } + + /// + /// @brief Sets the value of tls.rbp + /// + /// + /// @param val The value to set tls.rbp to + /// + pub fn bf_tls_set_rbp(val: bsl::SafeU64) { + bsl::expects(val.is_valid_and_checked()); + unsafe { + crate::bf_tls_set_rbp_impl(val.get()); + } + } + + /// + /// @brief Returns the value of tls.rsi + /// + /// + /// @return Returns the value of tls.rsi + /// + pub fn bf_tls_rsi() -> bsl::SafeU64 { + unsafe { + return bsl::to_u64(crate::bf_tls_rsi_impl()); + } + } + + /// + /// @brief Sets the value of tls.rsi + /// + /// + /// @param val The value to set tls.rsi to + /// + pub fn bf_tls_set_rsi(val: bsl::SafeU64) { + bsl::expects(val.is_valid_and_checked()); + unsafe { + crate::bf_tls_set_rsi_impl(val.get()); + } + } + + /// + /// @brief Returns the value of tls.rdi + /// + /// + /// @return Returns the value of tls.rdi + /// + pub fn bf_tls_rdi() -> bsl::SafeU64 { + unsafe { + return bsl::to_u64(crate::bf_tls_rdi_impl()); + } + } + + /// + /// @brief Sets the value of tls.rdi + /// + /// + /// @param val The value to set tls.rdi to + /// + pub fn bf_tls_set_rdi(val: bsl::SafeU64) { + bsl::expects(val.is_valid_and_checked()); + unsafe { + crate::bf_tls_set_rdi_impl(val.get()); + } + } + + /// + /// @brief Returns the value of tls.r8 + /// + /// + /// @return Returns the value of tls.r8 + /// + pub fn bf_tls_r8() -> bsl::SafeU64 { + unsafe { + return bsl::to_u64(crate::bf_tls_r8_impl()); + } + } + + /// + /// @brief Sets the value of tls.r8 + /// + /// + /// @param val The value to set tls.r8 to + /// + pub fn bf_tls_set_r8(val: bsl::SafeU64) { + bsl::expects(val.is_valid_and_checked()); + unsafe { + crate::bf_tls_set_r8_impl(val.get()); + } + } + + /// + /// @brief Returns the value of tls.r9 + /// + /// + /// @return Returns the value of tls.r9 + /// + pub fn bf_tls_r9() -> bsl::SafeU64 { + unsafe { + return bsl::to_u64(crate::bf_tls_r9_impl()); + } + } + + /// + /// @brief Sets the value of tls.r9 + /// + /// + /// @param val The value to set tls.r9 to + /// + pub fn bf_tls_set_r9(val: bsl::SafeU64) { + bsl::expects(val.is_valid_and_checked()); + unsafe { + crate::bf_tls_set_r9_impl(val.get()); + } + } + + /// + /// @brief Returns the value of tls.r10 + /// + /// + /// @return Returns the value of tls.r10 + /// + pub fn bf_tls_r10() -> bsl::SafeU64 { + unsafe { + return bsl::to_u64(crate::bf_tls_r10_impl()); + } + } + + /// + /// @brief Sets the value of tls.r10 + /// + /// + /// @param val The value to set tls.r10 to + /// + pub fn bf_tls_set_r10(val: bsl::SafeU64) { + bsl::expects(val.is_valid_and_checked()); + unsafe { + crate::bf_tls_set_r10_impl(val.get()); + } + } + + /// + /// @brief Returns the value of tls.r11 + /// + /// + /// @return Returns the value of tls.r11 + /// + pub fn bf_tls_r11() -> bsl::SafeU64 { + unsafe { + return bsl::to_u64(crate::bf_tls_r11_impl()); + } + } + + /// + /// @brief Sets the value of tls.r11 + /// + /// + /// @param val The value to set tls.r11 to + /// + pub fn bf_tls_set_r11(val: bsl::SafeU64) { + bsl::expects(val.is_valid_and_checked()); + unsafe { + crate::bf_tls_set_r11_impl(val.get()); + } + } + + /// + /// @brief Returns the value of tls.r12 + /// + /// + /// @return Returns the value of tls.r12 + /// + pub fn bf_tls_r12() -> bsl::SafeU64 { + unsafe { + return bsl::to_u64(crate::bf_tls_r12_impl()); + } + } + + /// + /// @brief Sets the value of tls.r12 + /// + /// + /// @param val The value to set tls.r12 to + /// + pub fn bf_tls_set_r12(val: bsl::SafeU64) { + bsl::expects(val.is_valid_and_checked()); + unsafe { + crate::bf_tls_set_r12_impl(val.get()); + } + } + + /// + /// @brief Returns the value of tls.r13 + /// + /// + /// @return Returns the value of tls.r13 + /// + pub fn bf_tls_r13() -> bsl::SafeU64 { + unsafe { + return bsl::to_u64(crate::bf_tls_r13_impl()); + } + } + + /// + /// @brief Sets the value of tls.r13 + /// + /// + /// @param val The value to set tls.r13 to + /// + pub fn bf_tls_set_r13(val: bsl::SafeU64) { + bsl::expects(val.is_valid_and_checked()); + unsafe { + crate::bf_tls_set_r13_impl(val.get()); + } + } + + /// + /// @brief Returns the value of tls.r14 + /// + /// + /// @return Returns the value of tls.r14 + /// + pub fn bf_tls_r14() -> bsl::SafeU64 { + unsafe { + return bsl::to_u64(crate::bf_tls_r14_impl()); + } + } + + /// + /// @brief Sets the value of tls.r14 + /// + /// + /// @param val The value to set tls.r14 to + /// + pub fn bf_tls_set_r14(val: bsl::SafeU64) { + bsl::expects(val.is_valid_and_checked()); + unsafe { + crate::bf_tls_set_r14_impl(val.get()); + } + } + + /// + /// @brief Returns the value of tls.r15 + /// + /// + /// @return Returns the value of tls.r15 + /// + pub fn bf_tls_r15() -> bsl::SafeU64 { + unsafe { + return bsl::to_u64(crate::bf_tls_r15_impl()); + } + } + + /// + /// @brief Sets the value of tls.r15 + /// + /// + /// @param val The value to set tls.r15 to + /// + pub fn bf_tls_set_r15(val: bsl::SafeU64) { + bsl::expects(val.is_valid_and_checked()); + unsafe { + crate::bf_tls_set_r15_impl(val.get()); + } + } + + /// + /// @brief Returns the value of tls.extid + /// + /// + /// @return Returns the value of tls.extid + /// + pub fn bf_tls_extid() -> bsl::SafeU16 { + unsafe { + return bsl::to_u16(crate::bf_tls_extid_impl()); + } + } + + /// + /// @brief Returns the value of tls.vmid + /// + /// + /// @return Returns the value of tls.vmid + /// + pub fn bf_tls_vmid() -> bsl::SafeU16 { + unsafe { + return bsl::to_u16(crate::bf_tls_vmid_impl()); + } + } + + /// + /// @brief Returns the value of tls.vpid + /// + /// + /// @return Returns the value of tls.vpid + /// + pub fn bf_tls_vpid() -> bsl::SafeU16 { + unsafe { + return bsl::to_u16(crate::bf_tls_vpid_impl()); + } + } + + /// + /// @brief Returns the value of tls.vsid + /// + /// + /// @return Returns the value of tls.vsid + /// + pub fn bf_tls_vsid() -> bsl::SafeU16 { + unsafe { + return bsl::to_u16(crate::bf_tls_vsid_impl()); + } + } + + /// + /// @brief Returns the value of tls.ppid + /// + /// + /// @return Returns the value of tls.ppid + /// + pub fn bf_tls_ppid() -> bsl::SafeU16 { + unsafe { + return bsl::to_u16(crate::bf_tls_ppid_impl()); + } + } + + /// + /// @brief Returns the value of tls.online_pps + /// + /// + /// @return Returns the value of tls.online_pps + /// + pub fn bf_tls_online_pps() -> bsl::SafeU16 { + unsafe { + return bsl::to_u16(crate::bf_tls_online_pps_impl()); + } + } + + /// + /// @brief Returns true if the active VM is the + /// root VM. Returns false otherwise. + /// + /// + /// @return Returns true if the active VM is the + /// root VM. Returns false otherwise. + /// + pub fn is_the_active_vm_the_root_vm() -> bool { + unsafe { + return crate::BF_ROOT_VMID == crate::bf_tls_vmid_impl(); + } + } + + /// + /// @brief Returns true if the provided VMID is the + /// ID of the root VM. Returns false otherwise. + /// + /// + /// @param vmid the ID of the VM to query + /// @return Returns true if the provided VMID is the + /// ID of the root VM. Returns false otherwise. + /// + pub fn is_vm_the_root_vm(vmid: bsl::SafeU16) -> bool { + return vmid == crate::BF_ROOT_VMID; + } + + /// + /// @brief Returns true if the provided VPID is the + /// ID of a root VP. Returns false otherwise. This + /// is the same as vpid == sys.bf_tls_ppid(). + /// + /// + /// @param vpid the ID of the VP to query + /// @return Returns true if the provided VPID is the + /// ID of a root VP. Returns false otherwise. This + /// is the same as vpid == sys.bf_tls_ppid(). + /// + pub fn is_vp_a_root_vp(vpid: bsl::SafeU16) -> bool { + unsafe { + return vpid < crate::bf_tls_online_pps_impl(); + } + } + + /// + /// @brief Returns true if the provided VSID is the + /// ID of a root VS. Returns false otherwise. This + /// is the same as vsid == sys.bf_tls_ppid(). + /// + /// + /// @param vsid the ID of the VS to query + /// @return Returns true if the provided VSID is the + /// ID of a root VS. Returns false otherwise. This + /// is the same as vsid == sys.bf_tls_ppid(). + /// + pub fn is_vs_a_root_vs(vsid: bsl::SafeU16) -> bool { + unsafe { + return vsid < crate::bf_tls_online_pps_impl(); + } + } + + // --------------------------------------------------------------------- + // bf_vm_ops + // --------------------------------------------------------------------- + + /// + /// @brief This syscall tells the microkernel to create a VM + /// and return it's ID. + /// + /// + /// @return Returns the resulting ID, or bsl::SafeU16::failure() + /// on failure. + /// + pub fn bf_vm_op_create_vm(&self) -> bsl::SafeU16 { + let ret: u64; + let mut vmid: bsl::SafeU16 = bsl::SafeU16::default(); + + unsafe { + ret = crate::bf_vm_op_create_vm_impl(self.m_hndl.get(), vmid.data()); + } + if crate::BF_STATUS_SUCCESS != ret { + error!( + "bf_vm_op_create_vm failed with status {:#018x}\n{}", + ret, + bsl::here() + ); + + return bsl::SafeU16::failure(); + } + + if crate::BF_INVALID_ID == vmid { + error!( + "the vmid {:#06x} returned by bf_vm_op_create_vm is invalid\n{}", + vmid, + bsl::here() + ); + + return bsl::SafeU16::failure(); + } + + if crate::HYPERVISOR_MAX_VMS <= bsl::to_umx(vmid) { + error!( + "the vmid {:#06x} returned by bf_vm_op_create_vm is out of range\n{}", + vmid, + bsl::here() + ); + + return bsl::SafeU16::failure(); + } + + return vmid; + } + + /// + /// @brief This syscall tells the microkernel to destroy a VM + /// given an ID. + /// + /// + /// @param vmid The ID of the VM to destroy + /// @return Returns bsl::errc_success on success, bsl::errc_failure + /// otherwise + /// + pub fn bf_vm_op_destroy_vm(&self, vmid: bsl::SafeU16) -> bsl::ErrcType { + let ret: u64; + + bsl::expects(vmid.is_valid_and_checked()); + bsl::expects(crate::BF_INVALID_ID != vmid); + bsl::expects(crate::HYPERVISOR_MAX_VMS > bsl::to_umx(vmid)); + + unsafe { + ret = crate::bf_vm_op_destroy_vm_impl(self.m_hndl.get(), vmid.get()); + } + if crate::BF_STATUS_SUCCESS != ret { + error!( + "bf_vm_op_destroy_vm failed with status {:#018x}\n{}", + ret, + bsl::here() + ); + + return bsl::errc_failure; + } + + return bsl::errc_success; + } + + /// + /// @brief This syscall tells the microkernel to map a physical + /// address into the VM's direct map. This is the same as directly + /// accessing the direct map with the difference being that + /// software can provide a physical address and receive the + /// precalculated virtual address. + /// + /// + /// @tparam T the type of pointer to return. Must be a POD type and + /// the size of a page. + /// @param vmid The ID of the VM to map the physical address to + /// @param phys The physical address to map + /// @return Returns a pointer to the map on success, returns a + /// nullptr on failure. + /// + pub fn bf_vm_op_map_direct(&self, vmid: bsl::SafeU16, phys: bsl::SafeU64) -> *mut T { + let ret: u64; + let mut ptr: bsl::CPtrT = core::ptr::null_mut(); + + bsl::expects(vmid.is_valid_and_checked()); + bsl::expects(crate::BF_INVALID_ID != vmid); + bsl::expects(crate::HYPERVISOR_MAX_VMS > bsl::to_umx(vmid)); + bsl::expects(phys.is_valid_and_checked()); + bsl::expects(phys.is_pos()); + bsl::expects(crate::HYPERVISOR_EXT_DIRECT_MAP_SIZE > phys); + bsl::expects(crate::bf_is_page_aligned(phys)); + + unsafe { + ret = crate::bf_vm_op_map_direct_impl( + self.m_hndl.get(), + vmid.get(), + phys.get(), + &mut ptr, + ); + } + if crate::BF_STATUS_SUCCESS != ret { + error!( + "bf_vm_op_destroy_vm failed with status {:#018x}\n{}", + ret, + bsl::here() + ); + + return core::ptr::null_mut(); + } + + return ptr as *mut T; + } + + /// + /// @brief This syscall tells the microkernel to unmap a previously + /// mapped virtual address in the direct map. Unlike + /// bf_vm_op_unmap_direct_broadcast, this syscall does not flush the + /// TLB on any other PP, meaning this unmap is local to the PP the + /// call is made on. Attempting to unmap a virtual address from the + /// direct map that has been accessed on any other PP other than + /// the PP this syscall is executed on will result in undefined + /// behavior. This syscall is designed to support mapping and then + /// immediately unmapping a physical address on a single PP during + /// a single VMExit. It can also be used to map on a PP and then + /// use unmap on the same PP during multiple VMExits, but special + /// care must be taken to ensure no other PP can access the map, + /// otherwise UB will occur. + /// + /// + /// @param vmid The ID of the VM to unmap the virtual address from + /// @param ptr The virtual address to unmap + /// @return Returns bsl::errc_success on success, bsl::errc_failure + /// otherwise + /// + pub fn bf_vm_op_unmap_direct(&self, vmid: bsl::SafeU16, ptr: bsl::CPtrT) -> bsl::ErrcType { + let ret: u64; + + bsl::expects(vmid.is_valid_and_checked()); + bsl::expects(crate::BF_INVALID_ID != vmid); + bsl::expects(crate::HYPERVISOR_MAX_VMS > bsl::to_umx(vmid)); + + unsafe { + ret = crate::bf_vm_op_unmap_direct_impl(self.m_hndl.get(), vmid.get(), ptr); + } + if crate::BF_STATUS_SUCCESS != ret { + error!( + "bf_vm_op_unmap_direct failed with status {:#018x}\n{}", + ret, + bsl::here() + ); + + return bsl::errc_failure; + } + + return bsl::errc_success; + } + + /// + /// @brief This syscall tells the microkernel to unmap a previously + /// mapped virtual address in the direct map. Unlike + /// bf_vm_op_unmap_direct, this syscall performs a broadcast TLB flush + /// which means it can be safely used on all direct mapped + /// addresses. The downside of using this function is that it can + /// be a lot slower than bf_vm_op_unmap_direct, especially on + /// systems with a lot of PPs. + /// + /// + /// @param vmid The ID of the VM to unmap the virtual address from + /// @param ptr The virtual address to unmap + /// @return Returns bsl::errc_success on success, bsl::errc_failure + /// otherwise + /// + pub fn bf_vm_op_unmap_direct_broadcast( + &self, + vmid: bsl::SafeU16, + ptr: bsl::CPtrT, + ) -> bsl::ErrcType { + let ret: u64; + + bsl::expects(vmid.is_valid_and_checked()); + bsl::expects(crate::BF_INVALID_ID != vmid); + bsl::expects(crate::HYPERVISOR_MAX_VMS > bsl::to_umx(vmid)); + + unsafe { + ret = crate::bf_vm_op_unmap_direct_broadcast_impl(self.m_hndl.get(), vmid.get(), ptr); + } + if crate::BF_STATUS_SUCCESS != ret { + error!( + "bf_vm_op_unmap_direct_broadcast failed with status {:#018x}\n{}", + ret, + bsl::here() + ); + + return bsl::errc_failure; + } + + return bsl::errc_success; + } + + /// + /// @brief Given the ID of a VM, invalidates a TLB entry for a given + /// GLA on the PP that this is executed on. + /// + /// + /// @param vmid The ID of the VM to invalidate + /// @return Returns bsl::errc_success on success, bsl::errc_failure + /// otherwise + /// + pub fn bf_vm_op_tlb_flush(&self, vmid: bsl::SafeU16) -> bsl::ErrcType { + let ret: u64; + + bsl::expects(vmid.is_valid_and_checked()); + bsl::expects(crate::BF_INVALID_ID != vmid); + bsl::expects(crate::HYPERVISOR_MAX_VMS > bsl::to_umx(vmid)); + + unsafe { + ret = crate::bf_vm_op_tlb_flush_impl(self.m_hndl.get(), vmid.get()); + } + if crate::BF_STATUS_SUCCESS != ret { + error!( + "bf_vm_op_tlb_flush failed with status {:#018x}\n{}", + ret, + bsl::here() + ); + + return bsl::errc_failure; + } + + return bsl::errc_success; + } + + // --------------------------------------------------------------------- + // bf_vp_ops + // --------------------------------------------------------------------- + + /// + /// @brief This syscall tells the microkernel to create a VP given the + /// IDs of the VM and PP the VP will be assigned to. Upon success, + /// this syscall returns the ID of the newly created VP. + /// + /// + /// @param vmid The ID of the VM to assign the newly created VP to + /// @return Returns the resulting ID, or bsl::SafeU16::failure() + /// on failure. + /// + /// + pub fn bf_vp_op_create_vp(&self, vmid: bsl::SafeU16) -> bsl::SafeU16 { + let ret: u64; + let mut vpid: bsl::SafeU16 = bsl::SafeU16::default(); + + bsl::expects(vmid.is_valid_and_checked()); + bsl::expects(crate::BF_INVALID_ID != vmid); + bsl::expects(crate::HYPERVISOR_MAX_VPS > bsl::to_umx(vmid)); + + unsafe { + ret = crate::bf_vp_op_create_vp_impl(self.m_hndl.get(), vmid.get(), vpid.data()); + } + if crate::BF_STATUS_SUCCESS != ret { + error!( + "bf_vp_op_create_vp failed with status {:#018x}\n{}", + ret, + bsl::here() + ); + + return bsl::SafeU16::failure(); + } + + if crate::BF_INVALID_ID == vpid { + error!( + "the vpid {:#06x} returned by bf_vp_op_create_vp is invalid\n{}", + vpid, + bsl::here() + ); + + return bsl::SafeU16::failure(); + } + + if crate::HYPERVISOR_MAX_VPS <= bsl::to_umx(vpid) { + error!( + "the vpid {:#06x} returned by bf_vp_op_create_vp is out of range\n{}", + vpid, + bsl::here() + ); + + return bsl::SafeU16::failure(); + } + + return vpid; + } + + /// + /// @brief This syscall tells the microkernel to destroy a VP + /// given an ID. + /// + /// + /// @param vpid The ID of the VP to destroy + /// @return Returns bsl::errc_success on success, bsl::errc_failure + /// otherwise + /// + pub fn bf_vp_op_destroy_vp(&self, vpid: bsl::SafeU16) -> bsl::ErrcType { + let ret: u64; + + bsl::expects(vpid.is_valid_and_checked()); + bsl::expects(crate::BF_INVALID_ID != vpid); + bsl::expects(crate::HYPERVISOR_MAX_VPS > bsl::to_umx(vpid)); + + unsafe { + ret = crate::bf_vp_op_destroy_vp_impl(self.m_hndl.get(), vpid.get()); + } + if crate::BF_STATUS_SUCCESS != ret { + error!( + "bf_vp_op_destroy_vp failed with status {:#018x}\n{}", + ret, + bsl::here() + ); + + return bsl::errc_failure; + } + + return bsl::errc_success; + } + + // --------------------------------------------------------------------- + // bf_vs_ops + // --------------------------------------------------------------------- + + /// + /// @brief This syscall tells the microkernel to create a VS + /// and return it's ID. + /// + /// + /// @param vpid The ID of the VP to assign the newly created VS to + /// @param ppid The resulting VSID of the newly created VS + /// @return Returns the resulting ID, or bsl::SafeU16::failure() + /// on failure. + /// + /// + pub fn bf_vs_op_create_vs(&self, vpid: bsl::SafeU16, ppid: bsl::SafeU16) -> bsl::SafeU16 { + let ret: u64; + let mut vsid: bsl::SafeU16 = bsl::SafeU16::default(); + + bsl::expects(vpid.is_valid_and_checked()); + bsl::expects(crate::BF_INVALID_ID != vpid); + bsl::expects(crate::HYPERVISOR_MAX_VPS > bsl::to_umx(vpid)); + bsl::expects(ppid.is_valid_and_checked()); + bsl::expects(crate::BF_INVALID_ID != ppid); + bsl::expects(crate::HYPERVISOR_MAX_VPS > bsl::to_umx(ppid)); + + unsafe { + ret = crate::bf_vs_op_create_vs_impl( + self.m_hndl.get(), + vpid.get(), + ppid.get(), + vsid.data(), + ); + } + if crate::BF_STATUS_SUCCESS != ret { + error!( + "bf_vs_op_create_vs failed with status {:#018x}\n{}", + ret, + bsl::here() + ); + + return bsl::SafeU16::failure(); + } + + if crate::BF_INVALID_ID == vsid { + error!( + "the vsid {:#06x} returned by bf_vs_op_create_vs is invalid\n{}", + vsid, + bsl::here() + ); + + return bsl::SafeU16::failure(); + } + + if crate::HYPERVISOR_MAX_VSS <= bsl::to_umx(vsid) { + error!( + "the vsid {:#06x} returned by bf_vs_op_create_vs is out of range\n{}", + vsid, + bsl::here() + ); + + return bsl::SafeU16::failure(); + } + + return vsid; + } + + /// + /// @brief This syscall tells the microkernel to destroy a VS + /// given an ID. + /// + /// + /// @param vsid The ID of the VS to destroy + /// @return Returns bsl::errc_success on success, bsl::errc_failure + /// otherwise + /// + pub fn bf_vs_op_destroy_vs(&self, vsid: bsl::SafeU16) -> bsl::ErrcType { + let ret: u64; + + bsl::expects(vsid.is_valid_and_checked()); + bsl::expects(crate::BF_INVALID_ID != vsid); + bsl::expects(crate::HYPERVISOR_MAX_VPS > bsl::to_umx(vsid)); + + unsafe { + ret = crate::bf_vs_op_destroy_vs_impl(self.m_hndl.get(), vsid.get()); + } + if crate::BF_STATUS_SUCCESS != ret { + error!( + "bf_vs_op_destroy_vs failed with status {:#018x}\n{}", + ret, + bsl::here() + ); + + return bsl::errc_failure; + } + + return bsl::errc_success; + } + + /// + /// @brief This syscall tells the microkernel to initialize a VS using + /// the root VP state provided by the loader using the current PPID. + /// + /// + /// @param vsid The ID of the VS to initialize + /// @return Returns bsl::errc_success on success, bsl::errc_failure + /// otherwise + /// + pub fn bf_vs_op_init_as_root(&self, vsid: bsl::SafeU16) -> bsl::ErrcType { + let ret: u64; + + bsl::expects(vsid.is_valid_and_checked()); + bsl::expects(crate::BF_INVALID_ID != vsid); + bsl::expects(crate::HYPERVISOR_MAX_VPS > bsl::to_umx(vsid)); + + unsafe { + ret = crate::bf_vs_op_init_as_root_impl(self.m_hndl.get(), vsid.get()); + } + if crate::BF_STATUS_SUCCESS != ret { + error!( + "bf_vs_op_init_as_root failed with status {:#018x}\n{}", + ret, + bsl::here() + ); + + return bsl::errc_failure; + } + + return bsl::errc_success; + } + + /// + /// @brief Reads a CPU register from the VS given a bf_reg_t. Note + /// that the bf_reg_t is architecture specific. + /// + /// + /// @param vsid The ID of the VS to read from + /// @param reg A bf_reg_t defining which register to read + /// @return Returns the value read, or bsl::SafeU64::failure() + /// on failure. + /// + pub fn bf_vs_op_read(&self, vsid: bsl::SafeU16, reg: u64) -> bsl::SafeU64 { + let ret: u64; + let mut val: bsl::SafeU64 = bsl::SafeU64::default(); + + bsl::expects(vsid.is_valid_and_checked()); + bsl::expects(crate::BF_INVALID_ID != vsid); + bsl::expects(crate::HYPERVISOR_MAX_VPS > bsl::to_umx(vsid)); + bsl::expects(crate::BF_REG_T_INVALID > reg); + bsl::expects(crate::BF_REG_T_UNSUPPORTED != reg); + + unsafe { + ret = crate::bf_vs_op_read_impl(self.m_hndl.get(), vsid.get(), reg, val.data()); + } + if crate::BF_STATUS_SUCCESS != ret { + error!( + "bf_vs_op_read failed with status {:#018x}\n{}", + ret, + bsl::here() + ); + + return bsl::SafeU64::failure(); + } + + return val; + } + + /// + /// @brief Writes to a CPU register in the VS given a bf_reg_t and the + /// value to write. Note that the bf_reg_t is architecture specific. + /// + /// + /// @param vsid The ID of the VS to write to + /// @param reg A bf_reg_t defining which register to write to + /// @param value The value to write to the requested register + /// @return Returns bsl::errc_success on success, bsl::errc_failure + /// otherwise + /// + pub fn bf_vs_op_write(&self, vsid: bsl::SafeU16, reg: u64, val: bsl::SafeU64) -> bsl::ErrcType { + let ret: u64; + + bsl::expects(vsid.is_valid_and_checked()); + bsl::expects(crate::BF_INVALID_ID != vsid); + bsl::expects(crate::HYPERVISOR_MAX_VPS > bsl::to_umx(vsid)); + bsl::expects(crate::BF_REG_T_INVALID > reg); + bsl::expects(crate::BF_REG_T_UNSUPPORTED != reg); + bsl::expects(val.is_valid_and_checked()); + + unsafe { + ret = crate::bf_vs_op_write_impl(self.m_hndl.get(), vsid.get(), reg, val.get()); + } + if crate::BF_STATUS_SUCCESS != ret { + error!( + "bf_vs_op_write failed with status {:#018x}\n{}", + ret, + bsl::here() + ); + + return bsl::errc_failure; + } + + return bsl::errc_success; + } + + /// + /// @brief Executes a VS given the ID of the VM, VP and VS to execute. + /// The VS must be assigned to the provided VP and the provided VP must + /// be assigned to the provided VM. The VP and VS must not be executing + /// on any other PP, and the VS must be assigned to the PP this syscall + /// is executed on. Upon success, this syscall will not return. + /// + /// + /// @param vmid The ID of the VM to run + /// @param vpid The ID of the VP to run + /// @param vsid The ID of the VS to run + /// @return Returns bsl::errc_success on success, bsl::errc_failure + /// otherwise + /// + pub fn bf_vs_op_run( + &self, + vmid: bsl::SafeU16, + vpid: bsl::SafeU16, + vsid: bsl::SafeU16, + ) -> bsl::ErrcType { + let ret: u64; + + bsl::expects(vmid.is_valid_and_checked()); + bsl::expects(crate::BF_INVALID_ID != vmid); + bsl::expects(crate::HYPERVISOR_MAX_VPS > bsl::to_umx(vmid)); + bsl::expects(vpid.is_valid_and_checked()); + bsl::expects(crate::BF_INVALID_ID != vpid); + bsl::expects(crate::HYPERVISOR_MAX_VPS > bsl::to_umx(vpid)); + bsl::expects(vsid.is_valid_and_checked()); + bsl::expects(crate::BF_INVALID_ID != vsid); + bsl::expects(crate::HYPERVISOR_MAX_VPS > bsl::to_umx(vsid)); + + unsafe { + ret = crate::bf_vs_op_run_impl(self.m_hndl.get(), vmid.get(), vpid.get(), vsid.get()); + } + if crate::BF_STATUS_SUCCESS != ret { + error!( + "bf_vs_op_run failed with status {:#018x}\n{}", + ret, + bsl::here() + ); + + return bsl::errc_failure; + } + + return bsl::errc_success; + } + + /// + /// @brief bf_vs_op_run_current tells the microkernel to execute the + /// currently active VS, VP and VM. + /// + /// + /// @return Returns bsl::errc_success on success, bsl::errc_failure + /// otherwise + /// + pub fn bf_vs_op_run_current(&self) -> bsl::ErrcType { + let ret: u64; + + unsafe { + ret = crate::bf_vs_op_run_current_impl(self.m_hndl.get()); + } + if crate::BF_STATUS_SUCCESS != ret { + error!( + "bf_vs_op_run_current failed with status {:#018x}\n{}", + ret, + bsl::here() + ); + + return bsl::errc_failure; + } + + return bsl::errc_success; + } + + /// + /// @brief Advances the IP and executes a VS given the ID of the VM, VP + /// and VS to execute. The VS must be assigned to the provided VP and + /// the provided VP must be assigned to the provided VM. The VP and VS + /// must not be executing on any other PP, and the VS must be assigned + /// to the PP this syscall is executed on. Upon success, this syscall + /// will not return. + /// + /// + /// @param vmid The ID of the VM to advance the IP for + /// @param vpid The ID of the VP to advance the IP for + /// @param vsid The ID of the VS to advance the IP for + /// @return Returns bsl::errc_success on success, bsl::errc_failure + /// otherwise + /// + pub fn bf_vs_op_advance_ip_and_run( + &self, + vmid: bsl::SafeU16, + vpid: bsl::SafeU16, + vsid: bsl::SafeU16, + ) -> bsl::ErrcType { + let ret: u64; + + bsl::expects(vmid.is_valid_and_checked()); + bsl::expects(crate::BF_INVALID_ID != vmid); + bsl::expects(crate::HYPERVISOR_MAX_VPS > bsl::to_umx(vmid)); + bsl::expects(vpid.is_valid_and_checked()); + bsl::expects(crate::BF_INVALID_ID != vpid); + bsl::expects(crate::HYPERVISOR_MAX_VPS > bsl::to_umx(vpid)); + bsl::expects(vsid.is_valid_and_checked()); + bsl::expects(crate::BF_INVALID_ID != vsid); + bsl::expects(crate::HYPERVISOR_MAX_VPS > bsl::to_umx(vsid)); + + unsafe { + ret = crate::bf_vs_op_advance_ip_and_run_impl( + self.m_hndl.get(), + vmid.get(), + vpid.get(), + vsid.get(), + ); + } + if crate::BF_STATUS_SUCCESS != ret { + error!( + "bf_vs_op_advance_ip_and_run failed with status {:#018x}\n{}", + ret, + bsl::here() + ); + + return bsl::errc_failure; + } + + return bsl::errc_success; + } + + /// + /// @brief bf_vs_op_advance_ip_and_run_current tells the microkernel to + /// advance the IP of and execute the currently active VS, VP and VM. + /// + /// + /// @return Returns bsl::errc_success on success, bsl::errc_failure + /// otherwise + /// + pub fn bf_vs_op_advance_ip_and_run_current(&self) -> bsl::ErrcType { + let ret: u64; + + unsafe { + ret = crate::bf_vs_op_advance_ip_and_run_current_impl(self.m_hndl.get()); + } + if crate::BF_STATUS_SUCCESS != ret { + error!( + "bf_vs_op_advance_ip_and_run_current failed with status {:#018x}\n{}", + ret, + bsl::here() + ); + + return bsl::errc_failure; + } + + return bsl::errc_success; + } + + /// + /// @brief This syscall tells the microkernel to promote the requested + /// VS. This will stop the hypervisor complete on the physical + /// processor that this syscall is executed on and replace it's state + /// with the state in the VS. Note that this syscall only returns + /// on error. + /// + /// + /// @param vsid The ID of the VS to promote + /// @return Returns bsl::errc_success on success, bsl::errc_failure + /// otherwise + /// + pub fn bf_vs_op_promote(&self, vsid: bsl::SafeU16) -> bsl::ErrcType { + let ret: u64; + + bsl::expects(vsid.is_valid_and_checked()); + bsl::expects(crate::BF_INVALID_ID != vsid); + bsl::expects(crate::HYPERVISOR_MAX_VPS > bsl::to_umx(vsid)); + + unsafe { + ret = crate::bf_vs_op_promote_impl(self.m_hndl.get(), vsid.get()); + } + if crate::BF_STATUS_SUCCESS != ret { + error!( + "bf_vs_op_promote failed with status {:#018x}\n{}", + ret, + bsl::here() + ); + + return bsl::errc_failure; + } + + return bsl::errc_success; + } + + /// + /// @brief bf_vs_op_clear tells the microkernel to clear the VS's + /// hardware cache, if one exists. How this is used depends entirely + /// on the hardware and is associated with AMD's VMCB Clean Bits, + /// and Intel's VMClear instruction. See the associated documentation + /// for more details. On AMD, this ABI clears the entire VMCB. For more + /// fine grained control, use the write ABIs to manually modify the + /// VMCB. + /// + /// + /// @param vsid The ID of the VS to clear + /// @return Returns bsl::errc_success on success, bsl::errc_failure + /// otherwise + /// + pub fn bf_vs_op_clear(&self, vsid: bsl::SafeU16) -> bsl::ErrcType { + let ret: u64; + + bsl::expects(vsid.is_valid_and_checked()); + bsl::expects(crate::BF_INVALID_ID != vsid); + bsl::expects(crate::HYPERVISOR_MAX_VPS > bsl::to_umx(vsid)); + + unsafe { + ret = crate::bf_vs_op_clear_impl(self.m_hndl.get(), vsid.get()); + } + if crate::BF_STATUS_SUCCESS != ret { + error!( + "bf_vs_op_clear failed with status {:#018x}\n{}", + ret, + bsl::here() + ); + + return bsl::errc_failure; + } + + return bsl::errc_success; + } + + /// + /// @brief Migrates a VS to the provided PP. The VS must not be active. + /// + /// + /// @param vsid The ID of the VS to migrate + /// @param ppid The ID of the PP to migrate the VS to + /// @return Returns bsl::errc_success on success, bsl::errc_failure + /// otherwise + /// + pub fn bf_vs_op_migrate(&self, vsid: bsl::SafeU16, ppid: bsl::SafeU16) -> bsl::ErrcType { + let ret: u64; + + bsl::expects(vsid.is_valid_and_checked()); + bsl::expects(crate::BF_INVALID_ID != vsid); + bsl::expects(crate::HYPERVISOR_MAX_VPS > bsl::to_umx(vsid)); + bsl::expects(ppid.is_valid_and_checked()); + bsl::expects(crate::BF_INVALID_ID != ppid); + bsl::expects(crate::HYPERVISOR_MAX_VPS > bsl::to_umx(ppid)); + + unsafe { + ret = crate::bf_vs_op_migrate_impl(self.m_hndl.get(), vsid.get(), ppid.get()); + } + if crate::BF_STATUS_SUCCESS != ret { + error!( + "bf_vs_op_migrate failed with status {:#018x}\n{}", + ret, + bsl::here() + ); + + return bsl::errc_failure; + } + + return bsl::errc_success; + } + + /// + /// @brief TODO + /// + /// + /// @param vmid The ID of the VM to run + /// @param vpid The ID of the VP to run + /// @param vsid The ID of the VS to run + /// @return Returns bsl::errc_success on success, bsl::errc_failure + /// otherwise + /// + pub fn bf_vs_op_set_active( + &self, + vmid: bsl::SafeU16, + vpid: bsl::SafeU16, + vsid: bsl::SafeU16, + ) -> bsl::ErrcType { + let ret: u64; + + bsl::expects(vmid.is_valid_and_checked()); + bsl::expects(crate::BF_INVALID_ID != vmid); + bsl::expects(crate::HYPERVISOR_MAX_VPS > bsl::to_umx(vmid)); + bsl::expects(vpid.is_valid_and_checked()); + bsl::expects(crate::BF_INVALID_ID != vpid); + bsl::expects(crate::HYPERVISOR_MAX_VPS > bsl::to_umx(vpid)); + bsl::expects(vsid.is_valid_and_checked()); + bsl::expects(crate::BF_INVALID_ID != vsid); + bsl::expects(crate::HYPERVISOR_MAX_VPS > bsl::to_umx(vsid)); + + unsafe { + ret = crate::bf_vs_op_set_active_impl( + self.m_hndl.get(), + vmid.get(), + vpid.get(), + vsid.get(), + ); + } + if crate::BF_STATUS_SUCCESS != ret { + error!( + "bf_vs_op_set_active failed with status {:#018x}\n{}", + ret, + bsl::here() + ); + + return bsl::errc_failure; + } + + return bsl::errc_success; + } + + /// + /// @brief TODO + /// + /// + /// @param vmid The ID of the VM to run + /// @param vpid The ID of the VP to run + /// @param vsid The ID of the VS to run + /// @return Returns bsl::errc_success on success, bsl::errc_failure + /// otherwise + /// + pub fn bf_vs_op_advance_ip_and_set_active( + &self, + vmid: bsl::SafeU16, + vpid: bsl::SafeU16, + vsid: bsl::SafeU16, + ) -> bsl::ErrcType { + let ret: u64; + + bsl::expects(vmid.is_valid_and_checked()); + bsl::expects(crate::BF_INVALID_ID != vmid); + bsl::expects(crate::HYPERVISOR_MAX_VPS > bsl::to_umx(vmid)); + bsl::expects(vpid.is_valid_and_checked()); + bsl::expects(crate::BF_INVALID_ID != vpid); + bsl::expects(crate::HYPERVISOR_MAX_VPS > bsl::to_umx(vpid)); + bsl::expects(vsid.is_valid_and_checked()); + bsl::expects(crate::BF_INVALID_ID != vsid); + bsl::expects(crate::HYPERVISOR_MAX_VPS > bsl::to_umx(vsid)); + + unsafe { + ret = crate::bf_vs_op_advance_ip_and_set_active_impl( + self.m_hndl.get(), + vmid.get(), + vpid.get(), + vsid.get(), + ); + } + if crate::BF_STATUS_SUCCESS != ret { + error!( + "bf_vs_op_advance_ip_and_set_active failed with status {:#018x}\n{}", + ret, + bsl::here() + ); + + return bsl::errc_failure; + } + + return bsl::errc_success; + } + + /// + /// @brief Given the ID of a VS, invalidates a TLB entry for a given + /// GLA on the PP that this is executed on. + /// + /// + /// @param vsid The ID of the VS to invalidate + /// @param gla The GLA to invalidate + /// @return Returns bsl::errc_success on success, bsl::errc_failure + /// otherwise + /// + pub fn bf_vs_op_tlb_flush(&self, vsid: bsl::SafeU16, gla: bsl::SafeU64) -> bsl::ErrcType { + let ret: u64; + + bsl::expects(vsid.is_valid_and_checked()); + bsl::expects(crate::BF_INVALID_ID != vsid); + bsl::expects(crate::HYPERVISOR_MAX_VPS > bsl::to_umx(vsid)); + bsl::expects(gla.is_valid_and_checked()); + bsl::expects(gla.is_pos()); + bsl::expects(crate::bf_is_page_aligned(gla)); + + unsafe { + ret = crate::bf_vs_op_tlb_flush_impl(self.m_hndl.get(), vsid.get(), gla.get()); + } + if crate::BF_STATUS_SUCCESS != ret { + error!( + "bf_vs_op_tlb_flush failed with status {:#018x}\n{}", + ret, + bsl::here() + ); + + return bsl::errc_failure; + } + + return bsl::errc_success; + } + + // --------------------------------------------------------------------- + // bf_intrinsic_ops + // --------------------------------------------------------------------- + + /// + /// @brief Reads an MSR directly from the CPU given the address of + /// the MSR to read. Note that this is specific to Intel/AMD only. + /// Also note that not all MSRs can be read, and which MSRs that + /// can be read is up to the microkernel's internal policy as well + /// as which architecture the hypervisor is running on. + /// + /// + /// @param msr The address of the MSR to read + /// @return Returns the value read, or bsl::SafeU64::failure() + /// on failure. + /// + pub fn bf_intrinsic_op_rdmsr(&self, msr: bsl::SafeU32) -> bsl::SafeU64 { + let ret: u64; + let mut val: bsl::SafeU64 = bsl::SafeU64::default(); + + bsl::expects(msr.is_valid_and_checked()); + bsl::expects(msr.is_pos()); + + unsafe { + ret = crate::bf_intrinsic_op_rdmsr_impl(self.m_hndl.get(), msr.get(), val.data()); + } + if crate::BF_STATUS_SUCCESS != ret { + error!( + "bf_intrinsic_op_rdmsr failed with status {:#018x}\n{}", + ret, + bsl::here() + ); + + return bsl::SafeU64::failure(); + } + + return val; + } + + /// + /// @brief Writes to an MSR directly from the CPU given the address of + /// the MSR to write as well as the value to write. Note that this is + /// specific to Intel/AMD only. Also note that not all MSRs can be + /// written to, and which MSRs that can be written to is up to the + /// microkernel's internal policy as well as which architecture the + /// hypervisor is running on. + /// + /// + /// @param msr The address of the MSR to write to + /// @param val The value to write to the requested MSR + /// @return Returns bsl::errc_success on success, bsl::errc_failure + /// otherwise + /// + pub fn bf_intrinsic_op_wrmsr(&self, msr: bsl::SafeU32, val: bsl::SafeU64) -> bsl::ErrcType { + let ret: u64; + + bsl::expects(msr.is_valid_and_checked()); + bsl::expects(msr.is_pos()); + bsl::expects(val.is_valid_and_checked()); + + unsafe { + ret = crate::bf_intrinsic_op_wrmsr_impl(self.m_hndl.get(), msr.get(), val.get()); + } + if crate::BF_STATUS_SUCCESS != ret { + error!( + "bf_intrinsic_op_wrmsr failed with status {:#018x}\n{}", + ret, + bsl::here() + ); + + return bsl::errc_failure; + } + + return bsl::errc_success; + } + + // --------------------------------------------------------------------- + // bf_mem_ops + // --------------------------------------------------------------------- + + /// + /// @brief bf_mem_op_alloc_page allocates a page, and maps this page + /// into the direct map of the VM. + /// + /// + /// @tparam T the type of pointer to return. Must be a POD type and + /// the size of a page. + /// @param mut_phys The physical address of the resulting page + /// @return Returns a pointer to the newly allocated memory on success, + /// or a nullptr on failure. + /// + pub fn bf_mem_op_alloc_page(&self, phys: &mut bsl::SafeU64) -> *mut T { + let ret: u64; + let mut ptr: bsl::CPtrT = core::ptr::null_mut(); + + bsl::expects(phys.is_valid_and_checked()); + + unsafe { + ret = crate::bf_mem_op_alloc_page_impl(self.m_hndl.get(), &mut ptr, phys.data()); + } + if crate::BF_STATUS_SUCCESS != ret { + error!( + "bf_mem_op_alloc_page failed with status {:#018x}\n{}", + ret, + bsl::here() + ); + + return core::ptr::null_mut(); + } + + return ptr as *mut T; + } + + /// + /// @brief bf_mem_op_alloc_huge allocates a physically contiguous block + /// of memory. When allocating a page, the extension should keep in + /// mind the following: + /// - The total memory available to allocate from this pool is + /// extremely limited. This should only be used when absolutely + /// needed, and extensions should not expect more than 1 MB (might + /// be less) of total memory available. + /// - Memory allocated from the huge pool might be allocated using + /// different schemes. For example, the microkernel might allocate + /// in increments of a page, or it might use a buddy allocator that + /// would allocate in multiples of 2. If the allocation size + /// doesn't match the algorithm, internal fragmentation could + /// occur, further limiting the total number of allocations this + /// pool can support. + /// + /// + /// @tparam T the type of pointer to return. Must be a POD type and + /// the size of a page. + /// @param size The total number of bytes to allocate + /// @param mut_phys The physical address of the resulting memory + /// @return Returns a pointer to the newly allocated memory on success, + /// or a nullptr on failure. + /// + pub fn bf_mem_op_alloc_huge(&self, size: bsl::SafeU64, phys: &mut bsl::SafeU64) -> *mut T { + let ret: u64; + let mut ptr: bsl::CPtrT = core::ptr::null_mut(); + + bsl::expects(size.is_valid_and_checked()); + bsl::expects(size.is_pos()); + bsl::expects(crate::bf_is_page_aligned(size)); + bsl::expects(phys.is_valid_and_checked()); + + unsafe { + ret = crate::bf_mem_op_alloc_huge_impl( + self.m_hndl.get(), + size.get(), + &mut ptr, + phys.data(), + ); + } + if crate::BF_STATUS_SUCCESS != ret { + error!( + "bf_mem_op_alloc_huge failed with status {:#018x}\n{}", + ret, + bsl::here() + ); + + return core::ptr::null_mut(); + } + + return ptr as *mut T; + } }