Adds an example extension written in Rust and fixes a number of bugs

This patch:
- Adds a complete extension written in Rust, with all of the build
  system logic to support Rust development as well.
- Fixes an issues on Intel systems where the MSR bitmaps were not
  set up properly.
- Fixes a number of issues with UEFI.
- Fixes a number of issues with Windows, including a BSOD issue
  with narrow contracts.
This commit is contained in:
Rian Quinn 2021-10-18 10:12:46 -06:00
parent 44e6f4f19f
commit 91886c75d9
118 changed files with 6021 additions and 9252 deletions

8
.gitignore vendored
View file

@ -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/

View file

@ -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)

View file

@ -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**: <https://github.com/Bareflank/hypervisor/tree/master/docs>
- **Specification**: <https://github.com/Bareflank/hypervisor/blob/master/docs/Microkernel%20Syscall%20Specification.md>
- **Examples**: <https://github.com/Bareflank/hypervisor/tree/master/example>
- **Integration Tests**: <https://github.com/Bareflank/hypervisor/tree/master/kernel/integration>
If you have any questions, bugs, or feature requests, please feel free to ask on any of the following:
- **Slack**: <https://bareflank.herokuapp.com/>

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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" }

View file

@ -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" }

View file

@ -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}

View file

@ -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

View file

@ -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)

View file

@ -1,4 +0,0 @@
/* ---- AUTO GENERATED ---- */
pub const HYPERVISOR_PAGE_SIZE:u64 = 0x1000;

View file

@ -1,7 +0,0 @@
[package]
name = "cmake"
version = "0.1.0"
edition = "2018"
[lib]
path = "lib.rs"

View file

@ -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)

View file

@ -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

View file

@ -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
)

View file

@ -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
)

View file

@ -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()

View file

@ -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.

View file

@ -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.

View file

@ -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
)

View file

@ -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();
}
/// <!-- description -->

View file

@ -40,21 +40,6 @@
namespace example
{
/// <!-- description -->
/// @brief Returns the masked version of the VMCS control fields
///
/// <!-- inputs/outputs -->
/// @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();
};
/// <!-- description -->
/// @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();
}
/// <!-- description -->

View file

@ -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()

View file

@ -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;
/// <!-- description -->
/// @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,
}

View file

@ -1,8 +0,0 @@
[package]
name = "rust"
version = "0.1.0"
edition = "2018"
[lib]
path = "lib.rs"
crate-type = ["staticlib"]

View file

@ -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.
/// <!-- description -->
/// @brief Dispatches the bootstrap process as needed. Note that
/// the bootstrap callback is only called when starting the
/// hypervisor on root VPs.
///
/// <!-- inputs/outputs -->
/// @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);
}

View file

@ -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.
/// <!-- description -->
/// @brief Dispatches the fail as needed, or returns an error so
/// that the microkernel can halt the PP.
///
/// <!-- inputs/outputs -->
/// @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;
}

View file

@ -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 {}
}

View file

@ -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);
}
}

View file

@ -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 {
/// <!-- description -->
/// @brief Returns the VpT associated with the provided vpid.
///
/// <!-- inputs/outputs -->
/// @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()];
}
/// <!-- description -->
/// @brief Returns the VpT associated with the provided vpid.
///
/// <!-- inputs/outputs -->
/// @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()];
}
/// <!-- description -->
/// @brief creates a new VpPoolT
///
pub const fn new() -> Self {
Self {
m_pool: [crate::VpT::new(); *syscall::HYPERVISOR_MAX_VPS.get_unsafe()],
}
}
/// <!-- description -->
/// @brief Initializes this vp_pool_t
///
/// <!-- inputs/outputs -->
/// @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));
}
}
/// <!-- description -->
/// @brief Release the vp_pool_t.
///
/// <!-- inputs/outputs -->
/// @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);
}
}
/// <!-- description -->
/// @brief Allocates a VP and returns it's ID
///
/// <!-- inputs/outputs -->
/// @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);
}
/// <!-- description -->
/// @brief Deallocates the requested VpT
///
/// <!-- inputs/outputs -->
/// @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();
}
}
/// <!-- description -->
/// @brief Returns true if the requested VpT is allocated,
/// false otherwise
///
/// <!-- inputs/outputs -->
/// @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();
}
/// <!-- description -->
/// @brief Returns true if the requested VpT is deallocated,
/// false otherwise
///
/// <!-- inputs/outputs -->
/// @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();
}
/// <!-- description -->
/// @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.
///
/// <!-- inputs/outputs -->
/// @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();
}
}

View file

@ -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 {
/// <!-- description -->
/// @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),
}
}
/// <!-- description -->
/// @brief Initializes this dVpT
///
/// <!-- inputs/outputs -->
/// @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;
}
/// <!-- description -->
/// @brief Release the dVpT.
///
/// <!-- inputs/outputs -->
/// @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();
}
/// <!-- description -->
/// @brief Returns the ID of this dVpT
///
/// <!-- inputs/outputs -->
/// @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;
}
/// <!-- description -->
/// @brief Allocates the dVpT and returns it's ID
///
/// <!-- inputs/outputs -->
/// @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();
}
/// <!-- description -->
/// @brief Deallocates the dVpT
///
/// <!-- inputs/outputs -->
/// @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;
}
/// <!-- description -->
/// @brief Returns true if this dVpT is allocated, false otherwise
///
/// <!-- inputs/outputs -->
/// @return Returns true if this dVpT is allocated, false otherwise
///
pub fn is_allocated(&self) -> bool {
return self.m_allocated == crate::AllocatedStatusT::Allocated;
}
/// <!-- description -->
/// @brief Returns true if this dVpT is deallocated, false otherwise
///
/// <!-- inputs/outputs -->
/// @return Returns true if this dVpT is deallocated, false otherwise
///
pub fn is_deallocated(&self) -> bool {
return self.m_allocated == crate::AllocatedStatusT::Deallocated;
}
/// <!-- description -->
/// @brief Returns the ID of the VM this dVpT is assigned to. If
/// this dVpT is not assigned, syscall::BF_INVALID_ID is returned.
///
/// <!-- inputs/outputs -->
/// @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;
}
}

View file

@ -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 {
/// <!-- description -->
/// @brief Returns the VsT associated with the provided vsid.
///
/// <!-- inputs/outputs -->
/// @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()];
}
/// <!-- description -->
/// @brief Returns the VsT associated with the provided vsid.
///
/// <!-- inputs/outputs -->
/// @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()];
}
/// <!-- description -->
/// @brief creates a new VsPoolT
///
pub const fn new() -> Self {
Self {
m_pool: [crate::VsT::new(); *syscall::HYPERVISOR_MAX_VSS.get_unsafe()],
}
}
/// <!-- description -->
/// @brief Initializes this vp_pool_t
///
/// <!-- inputs/outputs -->
/// @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));
}
}
/// <!-- description -->
/// @brief Release the vp_pool_t.
///
/// <!-- inputs/outputs -->
/// @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);
}
}
/// <!-- description -->
/// @brief Allocates a VP and returns it's ID
///
/// <!-- inputs/outputs -->
/// @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);
}
/// <!-- description -->
/// @brief Deallocates the requested VsT
///
/// <!-- inputs/outputs -->
/// @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();
}
}
/// <!-- description -->
/// @brief Returns true if the requested VsT is allocated,
/// false otherwise
///
/// <!-- inputs/outputs -->
/// @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();
}
/// <!-- description -->
/// @brief Returns true if the requested VsT is deallocated,
/// false otherwise
///
/// <!-- inputs/outputs -->
/// @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();
}
/// <!-- description -->
/// @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.
///
/// <!-- inputs/outputs -->
/// @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();
}
/// <!-- description -->
/// @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.
///
/// <!-- inputs/outputs -->
/// @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();
}
}

View file

@ -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::*;
/// <!-- description -->
/// @brief Dispatches the VMExit.
///
/// <!-- inputs/outputs -->
/// @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;
}

View file

@ -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
/// <!-- description -->
/// @brief Initializes the Global Storage (GS).
///
/// <!-- inputs/outputs -->
/// @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 <bsl/cstdint.hpp>
namespace example
{
/// <!-- description -->
/// @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

View file

@ -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
/// <!-- description -->
/// @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 <npdte_t.hpp>
#include <bsl/array.hpp>
#include <bsl/convert.hpp>
#include <bsl/safe_integral.hpp>
#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 {
/// <!-- description -->
/// @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<npdte_t, NUM_NPDT_ENTRIES.get()> entries;
};
pub const fn new() -> Self {
Self {}
}
}
#pragma pack(pop)
#endif

View file

@ -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.
/// <!-- description -->
/// @brief Initializes the Thread Local Storage (TLS).
///
/// <!-- inputs/outputs -->
/// @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;
}

View file

@ -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
/// <!-- description -->
/// @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.
///
/// <!-- notes -->
/// @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 <npte_t.hpp>
#include <bsl/array.hpp>
#include <bsl/convert.hpp>
#include <bsl/safe_integral.hpp>
#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 {
/// <!-- description -->
/// @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<npte_t, NUM_NPT_ENTRIES.get()> entries;
};
pub const fn new() -> Self {
Self {}
}
}
#pragma pack(pop)
#endif

View file

@ -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 {
/// <!-- description -->
/// @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),
}
}
/// <!-- description -->
/// @brief Initializes this VsT
///
/// <!-- inputs/outputs -->
/// @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;
}
/// <!-- description -->
/// @brief Release the VsT.
///
/// <!-- inputs/outputs -->
/// @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();
}
/// <!-- description -->
/// @brief Returns the ID of this VsT
///
/// <!-- inputs/outputs -->
/// @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;
}
/// <!-- description -->
/// @brief Allocates the VsT and returns it's ID
///
/// <!-- inputs/outputs -->
/// @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();
}
/// <!-- description -->
/// @brief Deallocates the VsT
///
/// <!-- inputs/outputs -->
/// @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;
}
/// <!-- description -->
/// @brief Returns true if this VsT is allocated, false otherwise
///
/// <!-- inputs/outputs -->
/// @return Returns true if this VsT is allocated, false otherwise
///
pub fn is_allocated(&self) -> bool {
return self.m_allocated == crate::AllocatedStatusT::Allocated;
}
/// <!-- description -->
/// @brief Returns true if this VsT is deallocated, false otherwise
///
/// <!-- inputs/outputs -->
/// @return Returns true if this VsT is deallocated, false otherwise
///
pub fn is_deallocated(&self) -> bool {
return self.m_allocated == crate::AllocatedStatusT::Deallocated;
}
/// <!-- description -->
/// @brief Returns the ID of the VP this VsT is assigned to. If
/// this VsT is not assigned, syscall::BF_INVALID_ID is returned.
///
/// <!-- inputs/outputs -->
/// @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;
}
/// <!-- description -->
/// @brief Returns the ID of the PP this VsT is assigned to. If
/// this VsT is not assigned, syscall::BF_INVALID_ID is returned.
///
/// <!-- inputs/outputs -->
/// @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;
}
}

View file

@ -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;
/// <!-- description -->
/// @brief Handles the CPUID VMexit
///
/// <!-- inputs/outputs -->
/// @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();
}

View file

@ -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::*;
/// <!-- description -->
/// @brief Dispatches the VMExit.
///
/// <!-- inputs/outputs -->
/// @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;
}

View file

@ -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.
/// <!-- description -->
/// @brief Handle NMIs. This is required by Intel.
///
/// <!-- inputs/outputs -->
/// @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();
}

View file

@ -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.
/// <!-- description -->
/// @brief Handle NMIs Windows
///
/// <!-- inputs/outputs -->
/// @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();
}

View file

@ -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
/// <!-- description -->
/// @brief Initializes the Global Storage (GS).
///
/// <!-- inputs/outputs -->
/// @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 <npdpte_t.hpp>
gs.msr_bitmap = sys.bf_mem_op_alloc_page::<u8>(&mut gs.msr_bitmap_phys);
if core::ptr::null_mut() == gs.msr_bitmap {
print_v!("{}", bsl::here());
return bsl::errc_failure;
}
#include <bsl/array.hpp>
#include <bsl/convert.hpp>
#include <bsl/safe_integral.hpp>
#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)};
/// <!-- description -->
/// @brief Defines the layout of a page-directory-pionter table (npdpt).
///
struct npdpt_t final
{
/// @brief stores the entires in the table
bsl::array<npdpte_t, NUM_NPDPT_ENTRIES.get()> entries;
};
return bsl::errc_success;
}
#pragma pack(pop)
#endif

View file

@ -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 <npml4te_t.hpp>
#include <bsl/array.hpp>
#include <bsl/convert.hpp>
#include <bsl/safe_integral.hpp>
#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
///
/// <!-- description -->
/// @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<npml4te_t, NUM_NPML4T_ENTRIES.get()> entries;
};
/// <!-- description -->
/// @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 {
/// <!-- description -->
/// @brief creates a new GsT
///
pub const fn new() -> Self {
Self {
msr_bitmap: core::ptr::null_mut(),
msr_bitmap_phys: bsl::SafeU64::new(0),
}
}
}

View file

@ -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.
/// <!-- description -->
/// @brief Initializes the Thread Local Storage (TLS).
///
/// <!-- inputs/outputs -->
/// @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;
}

View file

@ -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.
/// <!-- description -->
/// @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.
///
/// <!-- notes -->
/// @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 {
/// <!-- description -->
/// @brief creates a new TlsT
///
pub const fn new() -> Self {
Self {}
}
}

View file

@ -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 {
/// <!-- description -->
/// @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),
}
}
/// <!-- description -->
/// @brief Initializes this VsT
///
/// <!-- inputs/outputs -->
/// @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;
}
/// <!-- description -->
/// @brief Release the VsT.
///
/// <!-- inputs/outputs -->
/// @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();
}
/// <!-- description -->
/// @brief Returns the ID of this VsT
///
/// <!-- inputs/outputs -->
/// @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;
}
/// <!-- description -->
/// @brief Allocates the VsT and returns it's ID
///
/// <!-- inputs/outputs -->
/// @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();
}
/// <!-- description -->
/// @brief Deallocates the VsT
///
/// <!-- inputs/outputs -->
/// @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;
}
/// <!-- description -->
/// @brief Returns true if this VsT is allocated, false otherwise
///
/// <!-- inputs/outputs -->
/// @return Returns true if this VsT is allocated, false otherwise
///
pub fn is_allocated(&self) -> bool {
return self.m_allocated == crate::AllocatedStatusT::Allocated;
}
/// <!-- description -->
/// @brief Returns true if this VsT is deallocated, false otherwise
///
/// <!-- inputs/outputs -->
/// @return Returns true if this VsT is deallocated, false otherwise
///
pub fn is_deallocated(&self) -> bool {
return self.m_allocated == crate::AllocatedStatusT::Deallocated;
}
/// <!-- description -->
/// @brief Returns the ID of the VP this VsT is assigned to. If
/// this VsT is not assigned, syscall::BF_INVALID_ID is returned.
///
/// <!-- inputs/outputs -->
/// @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;
}
/// <!-- description -->
/// @brief Returns the ID of the PP this VsT is assigned to. If
/// this VsT is not assigned, syscall::BF_INVALID_ID is returned.
///
/// <!-- inputs/outputs -->
/// @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;
}
}

View file

@ -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

View file

@ -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
/// <!-- description -->
/// @brief Executes the CPUID instruction given the provided EAX and ECX
/// and returns the results
///
/// <!-- inputs/outputs -->
/// @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);
}

View file

@ -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 <bsl/cstdint.hpp>
#[derive(Debug, Copy, Clone)]
pub struct IntrinsicT {}
namespace example
{
impl IntrinsicT {
/// <!-- description -->
/// @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 {}
}
/// <!-- description -->
/// @brief Executes the CPUID instruction given the provided
/// EAX and ECX and returns the results.
///
/// <!-- inputs/outputs -->
/// @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());
}
}
}

View file

@ -1,8 +0,0 @@
[package]
name = "tests"
version = "0.1.0"
edition = "2018"
[[bin]]
name = "tests"
path = "main.rs"

View file

@ -1,2 +0,0 @@
#[path = "../src/println.rs"]
mod println;

View file

@ -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":{}}

View file

@ -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/

View file

@ -1 +0,0 @@
This file has an mtime of when this was started.

View file

@ -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}

View file

@ -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"
}

View file

@ -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)

View file

@ -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 <mk_interface.hpp>
#include <bsl/convert.hpp>
#include <bsl/debug.hpp>
#include <bsl/discard.hpp>
#include <bsl/errc_type.hpp>
#include <bsl/safe_integral.hpp>
#include <bsl/unlikely.hpp>
namespace example
{
/// <!-- description -->
/// @brief Implements the architecture specific VMExit handler.
///
/// <!-- inputs/outputs -->
/// @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);
}
/// <!-- description -->
/// @brief Initializes a VS with architecture specific stuff.
///
/// <!-- inputs/outputs -->
/// @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

View file

@ -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
{
/// <!-- description -->
/// @brief Implements a lock_guard.
///
/// <!-- template parameters -->
/// @tparam T the type of mutex being locked
///
template<typename T>
class lock_guard final
{
/// @brief stores the lock that is being guarded
T &m_lock;
public:
/// <!-- description -->
/// @brief Creates a lock_guard, locking the provided
/// spinlock/mutex on construction.
///
/// <!-- inputs/outputs -->
/// @param lck the spinlock/mutex to guard
///
explicit constexpr lock_guard(T &lck) noexcept // --
: m_lock{lck}
{
m_lock.lock();
}
/// <!-- description -->
/// @brief Do not allow temporaries.
///
/// <!-- inputs/outputs -->
/// @param lck the spinlock/mutex to guard
///
constexpr lock_guard(T const &lck) noexcept = delete;
/// <!-- description -->
/// @brief Destructor
///
constexpr ~lock_guard() noexcept
{
m_lock.unlock();
}
/// <!-- description -->
/// @brief copy constructor
///
/// <!-- inputs/outputs -->
/// @param o the object being copied
///
constexpr lock_guard(lock_guard const &o) noexcept = delete;
/// <!-- description -->
/// @brief move constructor
///
/// <!-- inputs/outputs -->
/// @param o the object being moved
///
constexpr lock_guard(lock_guard &&o) noexcept = default;
/// <!-- description -->
/// @brief copy assignment
///
/// <!-- inputs/outputs -->
/// @param o the object being copied
/// @return a reference to *this
///
[[maybe_unused]] auto operator=(lock_guard const &o) noexcept -> lock_guard & = delete;
/// <!-- description -->
/// @brief move assignment
///
/// <!-- inputs/outputs -->
/// @param o the object being moved
/// @return a reference to *this
///
[[maybe_unused]] auto operator=(lock_guard &&o) noexcept -> lock_guard & = default;
};
}
#endif

View file

@ -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 <arch_support.hpp>
#include <mk_interface.hpp>
#include <bsl/debug.hpp>
#include <bsl/discard.hpp>
#include <bsl/exit_code.hpp>
#include <bsl/safe_integral.hpp>
#include <bsl/unlikely.hpp>
namespace example
{
/// @brief stores the handle the extension will use
constinit inline syscall::bf_handle_t g_handle{};
/// <!-- description -->
/// @brief Implements the VMExit entry function. This is registered
/// by the main function to execute whenever a VMExit occurs.
///
/// <!-- inputs/outputs -->
/// @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::V>() << bsl::here();
return syscall::bf_control_op_exit();
}
/// <!-- description -->
/// @brief Implements the fast fail entry function. This is registered
/// by the main function to execute whenever a fast fail occurs.
///
/// <!-- inputs/outputs -->
/// @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::V>() << bsl::here();
return syscall::bf_control_op_exit();
}
/// <!-- description -->
/// @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.
///
/// <!-- inputs/outputs -->
/// @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::V>() << 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::V>() << 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::V>() << bsl::here();
return syscall::bf_control_op_exit();
}
/// NOTE:
/// - Initialize architecture specific logic in the VS.
///
if (bsl::unlikely(!)) {
bsl::print<bsl::V>() << 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::V>() << bsl::here();
syscall::bf_control_op_exit();
}
/// <!-- description -->
/// @brief Implements the main entry function for this example
///
/// <!-- inputs/outputs -->
/// @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::V>() << 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::V>() << 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::V>() << 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::V>() << 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();
}
}

View file

@ -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 <bsl/construct_at.hpp>
#include <bsl/convert.hpp>
#include <bsl/cstring.hpp>
#include <bsl/debug.hpp>
#include <bsl/disjunction.hpp>
#include <bsl/errc_type.hpp>
#include <bsl/finally.hpp>
#include <bsl/is_standard_layout.hpp>
#include <bsl/is_void.hpp>
#include <bsl/safe_integral.hpp>
#include <bsl/span.hpp>
#include <bsl/touch.hpp>
#include <bsl/unlikely.hpp>
namespace example
{
/// <!-- description -->
/// @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:
/// <!-- description -->
/// @brief Initializes the page pool
///
/// <!-- inputs/outputs -->
/// @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;
}
/// <!-- description -->
/// @brief Release the page_pool_t
///
constexpr void
release() noexcept
{
m_size = {};
m_head = {};
m_handle = {};
}
/// <!-- description -->
/// @brief Allocates a page from the page pool.
///
/// <!-- inputs/outputs -->
/// @tparam T the type of pointer to return
/// @return Returns a pointer to the newly allocated page
///
template<typename T>
[[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::V>() << bsl::here();
return nullptr;
}
bsl::touch();
}
else {
bsl::touch();
}
void *const ptr{m_head};
m_head = *static_cast<void **>(m_head);
bsl::builtin_memset(ptr, '\0', bsl::to_umx(HYPERVISOR_PAGE_SIZE).get());
if constexpr (!bsl::is_void<T>::value) {
static_assert(bsl::is_standard_layout<T>::value, "T must be a standard layout");
bsl::construct_at<T>(ptr);
}
return static_cast<T *>(ptr);
}
/// <!-- description -->
/// @brief Returns a page previously allocated using the allocate
/// function to the page pool.
///
/// <!-- inputs/outputs -->
/// @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<void **>(ptr) = m_head;
m_head = ptr;
}
/// <!-- description -->
/// @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.
///
/// <!-- inputs/outputs -->
/// @tparam T defines the type of virtual address being converted
/// @param virt the virtual address to convert
/// @return the resulting physical address
///
template<typename T>
[[nodiscard]] constexpr auto
virt_to_phys(T const *const virt) const noexcept -> bsl::safe_umx
{
static_assert(bsl::disjunction<bsl::is_void<T>, bsl::is_standard_layout<T>>::value);
return bsl::to_umx(virt) - bsl::to_umx(HYPERVISOR_EXT_PAGE_POOL_ADDR);
}
/// <!-- description -->
/// @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.
///
/// <!-- inputs/outputs -->
/// @tparam T defines the type of virtual address to convert to
/// @param phys the physical address to convert
/// @return the resulting virtual address
///
template<typename T>
[[nodiscard]] constexpr auto
phys_to_virt(bsl::safe_umx const &phys) const noexcept -> T *
{
static_assert(bsl::disjunction<bsl::is_void<T>, bsl::is_standard_layout<T>>::value);
return bsl::to_ptr<T *>(phys + bsl::to_umx(HYPERVISOR_EXT_PAGE_POOL_ADDR));
}
};
}
#endif

View file

@ -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 <bsl/is_constant_evaluated.hpp>
#pragma clang diagnostic ignored "-Watomic-implicit-seq-cst"
namespace example
{
/// <!-- description -->
/// @brief Implements a spinlock
///
class spinlock final
{
/// @brief stores whether or not the lock is acquired
_Atomic bool m_flag;
public:
/// <!-- description -->
/// @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;
}
/// <!-- description -->
/// @brief Destructor
///
constexpr ~spinlock() noexcept = default;
/// <!-- description -->
/// @brief copy constructor
///
/// <!-- inputs/outputs -->
/// @param o the object being copied
///
constexpr spinlock(spinlock const &o) noexcept = delete;
/// <!-- description -->
/// @brief move constructor
///
/// <!-- inputs/outputs -->
/// @param o the object being moved
///
constexpr spinlock(spinlock &&o) noexcept = default;
/// <!-- description -->
/// @brief copy assignment
///
/// <!-- inputs/outputs -->
/// @param o the object being copied
/// @return a reference to *this
///
[[maybe_unused]] auto operator=(spinlock const &o) noexcept -> spinlock & = delete;
/// <!-- description -->
/// @brief move assignment
///
/// <!-- inputs/outputs -->
/// @param o the object being moved
/// @return a reference to *this
///
[[maybe_unused]] auto operator=(spinlock &&o) noexcept -> spinlock & = default;
/// <!-- description -->
/// @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)) {
}
}
}
/// <!-- description -->
/// @brief Unlocks the spinlock.
///
constexpr void
unlock() noexcept
{
if (bsl::is_constant_evaluated()) {
return;
}
__c11_atomic_store(&m_flag, false, __ATOMIC_RELEASE);
}
};
}
#endif

View file

@ -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 <common_arch_support.hpp>
#include <mk_interface.hpp>
#include <nested_page_table_t.hpp>
#include <page_pool_t.hpp>
#include <bsl/convert.hpp>
#include <bsl/debug.hpp>
#include <bsl/discard.hpp>
#include <bsl/errc_type.hpp>
#include <bsl/safe_integral.hpp>
#include <bsl/unlikely.hpp>
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{};
/// <!-- description -->
/// @brief Implements the architecture specific VMExit handler.
///
/// <!-- inputs/outputs -->
/// @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::V>() << bsl::here();
return;
}
bsl::discard(syscall::bf_vs_op_advance_ip_and_run_current(handle));
bsl::print<bsl::V>() << 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(); // --
}
/// <!-- description -->
/// @brief Initializes a VS with architecture specific stuff.
///
/// <!-- inputs/outputs -->
/// @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::V>() << 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::V>() << 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::V>() << 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::V>() << 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::V>() << 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::V>() << 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::V>() << 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::V>() << bsl::here();
return ret;
}
return ret;
}
}
#endif

View file

@ -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 <lock_guard.hpp>
#include <map_page_flags.hpp>
#include <memory_type.hpp>
#include <page_pool_t.hpp>
#include <spinlock.hpp>
#include <bsl/convert.hpp>
#include <bsl/debug.hpp>
#include <bsl/errc_type.hpp>
#include <bsl/finally.hpp>
#include <bsl/safe_integral.hpp>
#include <bsl/touch.hpp>
#include <bsl/unlikely.hpp>
namespace example
{
/// <!-- description -->
/// @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{};
/// <!-- description -->
/// @brief Returns the nested page-map level-4 (NPML4T) offset given
/// a guest physical address.
///
/// <!-- inputs/outputs -->
/// @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;
}
/// <!-- description -->
/// @brief Adds a npdpt_t to the provided npml4te_t.
///
/// <!-- inputs/outputs -->
/// @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<void>()};
if (bsl::unlikely(nullptr == table)) {
bsl::print<bsl::V>() << 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::V>() << 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;
}
/// <!-- description -->
/// @brief Adds a npdpt_t to the provided npml4te_t.
///
/// <!-- inputs/outputs -->
/// @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));
}
/// <!-- description -->
/// @brief Returns the npdpt_t associated with the provided
/// npml4te_t.
///
/// <!-- inputs/outputs -->
/// @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<npdpt_t>(entry_phys);
}
/// <!-- description -->
/// @brief Returns the npdpt_t associated with the provided
/// npml4te_t.
///
/// <!-- inputs/outputs -->
/// @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<npdpt_t const>(entry_phys);
}
/// <!-- description -->
/// @brief Returns the nested page-directory-pointer table (NPDPT)
/// offset given a guest physical address.
///
/// <!-- inputs/outputs -->
/// @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;
}
/// <!-- description -->
/// @brief Adds a npdt_t to the provided npdpte_t.
///
/// <!-- inputs/outputs -->
/// @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<void>()};
if (bsl::unlikely(nullptr == table)) {
bsl::print<bsl::V>() << 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::V>() << 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;
}
/// <!-- description -->
/// @brief Adds a npdt_t to the provided npdpte_t.
///
/// <!-- inputs/outputs -->
/// @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));
}
/// <!-- description -->
/// @brief Returns the npdt_t associated with the provided
/// npdpte_t.
///
/// <!-- inputs/outputs -->
/// @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<npdt_t>(entry_phys);
}
/// <!-- description -->
/// @brief Returns the npdt_t associated with the provided
/// npdpte_t.
///
/// <!-- inputs/outputs -->
/// @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<npdt_t const>(entry_phys);
}
/// <!-- description -->
/// @brief Returns the nested page-directory table (NPDT) offset
/// given a guest physical address.
///
/// <!-- inputs/outputs -->
/// @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;
}
/// <!-- description -->
/// @brief Adds a npt_t to the provided npdte_t.
///
/// <!-- inputs/outputs -->
/// @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<void>()};
if (bsl::unlikely(nullptr == table)) {
bsl::print<bsl::V>() << 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::V>() << 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;
}
/// <!-- description -->
/// @brief Adds a npt_t to the provided npdte_t.
///
/// <!-- inputs/outputs -->
/// @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));
}
/// <!-- description -->
/// @brief Returns the npt_t associated with the provided
/// npdte_t.
///
/// <!-- inputs/outputs -->
/// @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<npt_t>(entry_phys);
}
/// <!-- description -->
/// @brief Returns the npt_t associated with the provided
/// npdte_t.
///
/// <!-- inputs/outputs -->
/// @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<npt_t const>(entry_phys);
}
/// <!-- description -->
/// @brief Returns the page-table (NPT) offset given a
/// guest physical address.
///
/// <!-- inputs/outputs -->
/// @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;
}
/// <!-- description -->
/// @brief Returns true if the provided address is page aligned
///
/// <!-- inputs/outputs -->
/// @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;
}
/// <!-- description -->
/// @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:
/// <!-- description -->
/// @brief Initializes this nested_page_table_t
///
/// <!-- inputs/outputs -->
/// @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<npml4t_t>();
if (bsl::unlikely(nullptr == m_npml4t)) {
bsl::print<bsl::V>() << 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::V>() << bsl::here();
return bsl::errc_failure;
}
release_on_error.ignore();
m_initialized = true;
return bsl::errc_success;
}
/// <!-- description -->
/// @brief Releases the memory allocated in this nested page tables
///
constexpr void
release() noexcept
{
this->auto_release();
m_page_pool = {};
m_initialized = false;
}
/// <!-- description -->
/// @brief Returns the physical address of the PML4
///
/// <!-- inputs/outputs -->
/// @return Returns the physical address of the PML4
///
[[nodiscard]] constexpr auto
phys() const noexcept -> bsl::safe_umx const &
{
return m_npml4t_phys;
}
/// <!-- description -->
/// @brief Maps a 4k page into the nested page tables being managed
/// by this class.
///
/// <!-- inputs/outputs -->
/// @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::V>() << 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::V>() << 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::V>() << 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;
}
/// <!-- description -->
/// @brief Maps a 2m page into the nested page tables being managed
/// by this class.
///
/// <!-- inputs/outputs -->
/// @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::V>() << 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::V>() << 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

View file

@ -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 <bsl/convert.hpp>
#include <bsl/cstdint.hpp>
#include <bsl/safe_integral.hpp>
#pragma pack(push, 1)
namespace example
{
/// @struct example::npdpte_t
///
/// <!-- description -->
/// @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<bsl::uint64>(1);
/// @brief defines the "read/write" field in the page
bsl::uint64 rw : static_cast<bsl::uint64>(1);
/// @brief defines the "user/supervisor" field in the page
bsl::uint64 us : static_cast<bsl::uint64>(1);
/// @brief defines the "page-level writethrough" field in the page
bsl::uint64 pwt : static_cast<bsl::uint64>(1);
/// @brief defines the "page-level cache disable" field in the page
bsl::uint64 pcd : static_cast<bsl::uint64>(1);
/// @brief defines the "accessed" field in the page
bsl::uint64 a : static_cast<bsl::uint64>(1);
/// @brief defines the "dirty" field in the page (ignored)
bsl::uint64 d : static_cast<bsl::uint64>(1);
/// @brief defines the "page size" field in the page (must be 0)
bsl::uint64 ps : static_cast<bsl::uint64>(1);
/// @brief defines the "global" field in the page (must be 0)
bsl::uint64 g : static_cast<bsl::uint64>(1);
/// @brief defines the "available to software" field in the page
bsl::uint64 available1 : static_cast<bsl::uint64>(3);
/// @brief defines the "physical address" field in the page
bsl::uint64 phys : static_cast<bsl::uint64>(40);
/// @brief defines the "available to software" field in the page
bsl::uint64 available2 : static_cast<bsl::uint64>(11);
/// @brief defines the "no-execute" field in the page
bsl::uint64 nx : static_cast<bsl::uint64>(1);
};
}
#pragma pack(pop)
#endif

View file

@ -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 <bsl/convert.hpp>
#include <bsl/cstdint.hpp>
#include <bsl/safe_integral.hpp>
#pragma pack(push, 1)
namespace example
{
/// @struct example::npdte_t
///
/// <!-- description -->
/// @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<bsl::uint64>(1);
/// @brief defines the "read/write" field in the page
bsl::uint64 rw : static_cast<bsl::uint64>(1);
/// @brief defines the "user/supervisor" field in the page
bsl::uint64 us : static_cast<bsl::uint64>(1);
/// @brief defines the "page-level writethrough" field in the page
bsl::uint64 pwt : static_cast<bsl::uint64>(1);
/// @brief defines the "page-level cache disable" field in the page
bsl::uint64 pcd : static_cast<bsl::uint64>(1);
/// @brief defines the "accessed" field in the page
bsl::uint64 a : static_cast<bsl::uint64>(1);
/// @brief defines the "dirty" field in the page (ignored)
bsl::uint64 d : static_cast<bsl::uint64>(1);
/// @brief defines the "page size" field in the page (must be 0)
bsl::uint64 ps : static_cast<bsl::uint64>(1);
/// @brief defines the "global" field in the page (must be 0)
bsl::uint64 g : static_cast<bsl::uint64>(1);
/// @brief defines the "available to software" field in the page
bsl::uint64 available1 : static_cast<bsl::uint64>(3);
/// @brief defines the "physical address" field in the page
bsl::uint64 phys : static_cast<bsl::uint64>(40);
/// @brief defines the "available to software" field in the page
bsl::uint64 available2 : static_cast<bsl::uint64>(11);
/// @brief defines the "no-execute" field in the page
bsl::uint64 nx : static_cast<bsl::uint64>(1);
};
}
#pragma pack(pop)
#endif

View file

@ -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 <bsl/convert.hpp>
#include <bsl/cstdint.hpp>
#include <bsl/safe_integral.hpp>
#pragma pack(push, 1)
namespace example
{
/// @struct example::npml4te_t
///
/// <!-- description -->
/// @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<bsl::uint64>(1);
/// @brief defines the "read/write" field in the page
bsl::uint64 rw : static_cast<bsl::uint64>(1);
/// @brief defines the "user/supervisor" field in the page
bsl::uint64 us : static_cast<bsl::uint64>(1);
/// @brief defines the "page-level writethrough" field in the page
bsl::uint64 pwt : static_cast<bsl::uint64>(1);
/// @brief defines the "page-level cache disable" field in the page
bsl::uint64 pcd : static_cast<bsl::uint64>(1);
/// @brief defines the "accessed" field in the page
bsl::uint64 a : static_cast<bsl::uint64>(1);
/// @brief defines the "dirty" field in the page (ignored)
bsl::uint64 ignored : static_cast<bsl::uint64>(1);
/// @brief defines the "page size" field in the page (must be 0)
bsl::uint64 mbz1 : static_cast<bsl::uint64>(1);
/// @brief defines the "global" field in the page (must be 0)
bsl::uint64 mbz2 : static_cast<bsl::uint64>(1);
/// @brief defines the "available to software" field in the page
bsl::uint64 available1 : static_cast<bsl::uint64>(3);
/// @brief defines the "physical address" field in the page
bsl::uint64 phys : static_cast<bsl::uint64>(40);
/// @brief defines the "available to software" field in the page
bsl::uint64 available2 : static_cast<bsl::uint64>(11);
/// @brief defines the "no-execute" field in the page
bsl::uint64 nx : static_cast<bsl::uint64>(1);
};
}
#pragma pack(pop)
#endif

View file

@ -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 <bsl/convert.hpp>
#include <bsl/cstdint.hpp>
#include <bsl/safe_integral.hpp>
#pragma pack(push, 1)
namespace example
{
/// @struct example::npte_t
/// <!-- description -->
/// @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<bsl::uint64>(1);
/// @brief defines the "read/write" field in the page
bsl::uint64 rw : static_cast<bsl::uint64>(1);
/// @brief defines the "user/supervisor" field in the page
bsl::uint64 us : static_cast<bsl::uint64>(1);
/// @brief defines the "page-level writethrough" field in the page
bsl::uint64 pwt : static_cast<bsl::uint64>(1);
/// @brief defines the "page-level cache disable" field in the page
bsl::uint64 pcd : static_cast<bsl::uint64>(1);
/// @brief defines the "accessed" field in the page
bsl::uint64 a : static_cast<bsl::uint64>(1);
/// @brief defines the "dirty" field in the page (ignored)
bsl::uint64 d : static_cast<bsl::uint64>(1);
/// @brief defines the "page size" field in the page (must be 0)
bsl::uint64 ps : static_cast<bsl::uint64>(1);
/// @brief defines the "global" field in the page (must be 0)
bsl::uint64 g : static_cast<bsl::uint64>(1);
/// @brief defines the "available to software" field in the page
bsl::uint64 available1 : static_cast<bsl::uint64>(3);
/// @brief defines the "physical address" field in the page
bsl::uint64 phys : static_cast<bsl::uint64>(40);
/// @brief defines the "available to software" field in the page
bsl::uint64 available2 : static_cast<bsl::uint64>(11);
/// @brief defines the "no-execute" field in the page
bsl::uint64 nx : static_cast<bsl::uint64>(1);
};
}
#pragma pack(pop)
#endif

View file

@ -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 <cpuid_commands.hpp>
#include <mk_interface.hpp>
#include <bsl/convert.hpp>
#include <bsl/cstdint.hpp>
#include <bsl/debug.hpp>
#include <bsl/errc_type.hpp>
#include <bsl/safe_integral.hpp>
#include <bsl/touch.hpp>
#include <bsl/unlikely.hpp>
namespace example
{
/// <!-- description -->
/// @brief Handle CPUID VMExits
///
/// <!-- inputs/outputs -->
/// @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::V>() << bsl::here();
return ret;
}
ret = syscall::bf_vs_op_promote(handle, vsid);
if (bsl::unlikely(!ret)) {
bsl::print<bsl::V>() << 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

View file

@ -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 <common_arch_support.hpp>
#include <extended_page_table_t.hpp>
#include <map_page_flags.hpp>
#include <mk_interface.hpp>
#include <mtrrs_t.hpp>
#include <page_pool_t.hpp>
#include <bsl/convert.hpp>
#include <bsl/debug.hpp>
#include <bsl/discard.hpp>
#include <bsl/errc_type.hpp>
#include <bsl/safe_integral.hpp>
#include <bsl/unlikely.hpp>
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{};
/// <!-- description -->
/// @brief Handle NMIs. This is required by Intel.
///
/// <!-- inputs/outputs -->
/// @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::V>() << 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::V>() << bsl::here();
return ret;
}
return ret;
}
/// <!-- description -->
/// @brief Handle NMIs Windows
///
/// <!-- inputs/outputs -->
/// @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::V>() << 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::V>() << 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::V>() << bsl::here();
return ret;
}
return ret;
}
/// <!-- description -->
/// @brief Implements the architecture specific VMExit handler.
///
/// <!-- inputs/outputs -->
/// @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::V>() << bsl::here();
return;
}
bsl::discard(syscall::bf_vs_op_run_current(handle));
bsl::print<bsl::V>() << bsl::here();
return;
}
case exit_reason_nmi_window.get(): {
ret = handle_vmexit_nmi_window(handle, vsid);
if (bsl::unlikely(!ret)) {
bsl::print<bsl::V>() << bsl::here();
return;
}
bsl::discard(syscall::bf_vs_op_run_current(handle));
bsl::print<bsl::V>() << bsl::here();
return;
}
case exit_reason_cpuid.get(): {
ret = handle_vmexit_cpuid(handle, vsid);
if (bsl::unlikely(!ret)) {
bsl::print<bsl::V>() << bsl::here();
return;
}
bsl::discard(syscall::bf_vs_op_advance_ip_and_run_current(handle));
bsl::print<bsl::V>() << 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(); // --
}
/// <!-- description -->
/// @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.
///
/// <!-- inputs/outputs -->
/// @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));
};
/// <!-- description -->
/// @brief Initializes a VS with architecture specific stuff.
///
/// <!-- inputs/outputs -->
/// @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::V>() << 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::V>() << 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::V>() << 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::V>() << 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::V>() << 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::V>() << 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::V>() << 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::V>() << 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::V>() << 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::V>() << 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::V>() << 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::V>() << 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::V>() << 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::V>() << 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::V>() << 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::V>() << 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::V>() << bsl::here();
return ret;
}
ret = g_mtrrs.parse(handle);
if (bsl::unlikely(!ret)) {
bsl::print<bsl::V>() << 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::V>() << 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::V>() << bsl::here();
return ret;
}
return ret;
}
}
#endif

View file

@ -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 <epdpte_t.hpp>
#include <bsl/array.hpp>
#include <bsl/convert.hpp>
#include <bsl/safe_integral.hpp>
#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
///
/// <!-- description -->
/// @brief Defines the layout of a page-directory-pionter table (epdpt).
///
struct epdpt_t final
{
/// @brief stores the entires in the table
bsl::array<epdpte_t, NUM_EPDPT_ENTRIES.get()> entries;
};
}
#pragma pack(pop)
#endif

View file

@ -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 <bsl/convert.hpp>
#include <bsl/cstdint.hpp>
#include <bsl/safe_integral.hpp>
#pragma pack(push, 1)
namespace example
{
/// @struct example::epdpte_t
///
/// <!-- description -->
/// @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<bsl::uint64>(1);
/// @brief defines the "write access" field in the page
bsl::uint64 w : static_cast<bsl::uint64>(1);
/// @brief defines the "execute access" field in the page
bsl::uint64 e : static_cast<bsl::uint64>(1);
/// @brief defines the "memory type" field in the page
bsl::uint64 type : static_cast<bsl::uint64>(3);
/// @brief defines the "ignore pat" field in the page
bsl::uint64 ignore_pat : static_cast<bsl::uint64>(1);
/// @brief defines the "page size" field in the page
bsl::uint64 ps : static_cast<bsl::uint64>(1);
/// @brief defines the "accessed" field in the page
bsl::uint64 a : static_cast<bsl::uint64>(1);
/// @brief defines the "ignored" field in the page
bsl::uint64 d : static_cast<bsl::uint64>(1);
/// @brief defines the "user execute access" field in the page
bsl::uint64 e_user : static_cast<bsl::uint64>(1);
/// @brief defines the "ignored" field in the page
bsl::uint64 ignored1 : static_cast<bsl::uint64>(1);
/// @brief defines the "physical address" field in the page
bsl::uint64 phys : static_cast<bsl::uint64>(40);
/// @brief defines the "ignored" field in the page
bsl::uint64 ignored2 : static_cast<bsl::uint64>(11);
/// @brief defines the "virtualization exception" field in the page
bsl::uint64 ve : static_cast<bsl::uint64>(1);
};
}
#pragma pack(pop)
#endif

View file

@ -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 <epdte_t.hpp>
#include <bsl/array.hpp>
#include <bsl/convert.hpp>
#include <bsl/safe_integral.hpp>
#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
///
/// <!-- description -->
/// @brief Defines the layout of a page-directory table (epdt).
///
struct epdt_t final
{
/// @brief stores the entires in the table
bsl::array<epdte_t, NUM_EPDT_ENTRIES.get()> entries;
};
}
#pragma pack(pop)
#endif

View file

@ -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 <bsl/convert.hpp>
#include <bsl/cstdint.hpp>
#include <bsl/safe_integral.hpp>
#pragma pack(push, 1)
namespace example
{
/// @struct example::epdte_t
///
/// <!-- description -->
/// @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<bsl::uint64>(1);
/// @brief defines the "write access" field in the page
bsl::uint64 w : static_cast<bsl::uint64>(1);
/// @brief defines the "execute access" field in the page
bsl::uint64 e : static_cast<bsl::uint64>(1);
/// @brief defines the "memory type" field in the page
bsl::uint64 type : static_cast<bsl::uint64>(3);
/// @brief defines the "ignore pat" field in the page
bsl::uint64 ignore_pat : static_cast<bsl::uint64>(1);
/// @brief defines the "page size" field in the page
bsl::uint64 ps : static_cast<bsl::uint64>(1);
/// @brief defines the "accessed" field in the page
bsl::uint64 a : static_cast<bsl::uint64>(1);
/// @brief defines the "ignored" field in the page
bsl::uint64 d : static_cast<bsl::uint64>(1);
/// @brief defines the "user execute access" field in the page
bsl::uint64 e_user : static_cast<bsl::uint64>(1);
/// @brief defines the "ignored" field in the page
bsl::uint64 ignored1 : static_cast<bsl::uint64>(1);
/// @brief defines the "physical address" field in the page
bsl::uint64 phys : static_cast<bsl::uint64>(40);
/// @brief defines the "ignored" field in the page
bsl::uint64 ignored2 : static_cast<bsl::uint64>(11);
/// @brief defines the "virtualization exception" field in the page
bsl::uint64 ve : static_cast<bsl::uint64>(1);
};
}
#pragma pack(pop)
#endif

View file

@ -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 <epml4te_t.hpp>
#include <bsl/array.hpp>
#include <bsl/convert.hpp>
#include <bsl/safe_integral.hpp>
#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
///
/// <!-- description -->
/// @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<epml4te_t, NUM_EPML4T_ENTRIES.get()> entries;
};
}
#pragma pack(pop)
#endif

View file

@ -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 <bsl/convert.hpp>
#include <bsl/cstdint.hpp>
#include <bsl/safe_integral.hpp>
#pragma pack(push, 1)
namespace example
{
/// @struct example::epml4te_t
///
/// <!-- description -->
/// @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<bsl::uint64>(1);
/// @brief defines the "write access" field in the page
bsl::uint64 w : static_cast<bsl::uint64>(1);
/// @brief defines the "execute access" field in the page
bsl::uint64 e : static_cast<bsl::uint64>(1);
/// @brief defines the "must be zero" field in the page
bsl::uint64 mbz1 : static_cast<bsl::uint64>(5);
/// @brief defines the "accessed" field in the page
bsl::uint64 a : static_cast<bsl::uint64>(1);
/// @brief defines the "ignored" field in the page
bsl::uint64 ignored1 : static_cast<bsl::uint64>(1);
/// @brief defines the "user execute access" field in the page
bsl::uint64 e_user : static_cast<bsl::uint64>(1);
/// @brief defines the "ignored" field in the page
bsl::uint64 ignored2 : static_cast<bsl::uint64>(1);
/// @brief defines the "physical address" field in the page
bsl::uint64 phys : static_cast<bsl::uint64>(40);
/// @brief defines the "ignored" field in the page
bsl::uint64 ignored3 : static_cast<bsl::uint64>(12);
};
}
#pragma pack(pop)
#endif

View file

@ -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 <epte_t.hpp>
#include <bsl/array.hpp>
#include <bsl/convert.hpp>
#include <bsl/safe_integral.hpp>
#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
///
/// <!-- description -->
/// @brief Defines the layout of a page table (ept).
///
struct ept_t final
{
/// @brief stores the entires in the table
bsl::array<epte_t, NUM_EPT_ENTRIES.get()> entries;
};
}
#pragma pack(pop)
#endif

View file

@ -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 <bsl/convert.hpp>
#include <bsl/cstdint.hpp>
#include <bsl/safe_integral.hpp>
#pragma pack(push, 1)
namespace example
{
/// @struct example::epte_t
/// <!-- description -->
/// @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<bsl::uint64>(1);
/// @brief defines the "write access" field in the page
bsl::uint64 w : static_cast<bsl::uint64>(1);
/// @brief defines the "execute access" field in the page
bsl::uint64 e : static_cast<bsl::uint64>(1);
/// @brief defines the "memory type" field in the page
bsl::uint64 type : static_cast<bsl::uint64>(3);
/// @brief defines the "ignore pat" field in the page
bsl::uint64 ignore_pat : static_cast<bsl::uint64>(1);
/// @brief defines the "ignored" field in the page
bsl::uint64 ignored1 : static_cast<bsl::uint64>(1);
/// @brief defines the "accessed" field in the page
bsl::uint64 a : static_cast<bsl::uint64>(1);
/// @brief defines the "ignored" field in the page
bsl::uint64 d : static_cast<bsl::uint64>(1);
/// @brief defines the "user execute access" field in the page
bsl::uint64 e_user : static_cast<bsl::uint64>(1);
/// @brief defines the "ignored" field in the page
bsl::uint64 ignored2 : static_cast<bsl::uint64>(1);
/// @brief defines the "physical address" field in the page
bsl::uint64 phys : static_cast<bsl::uint64>(40);
/// @brief defines the "ignored" field in the page
bsl::uint64 ignored3 : static_cast<bsl::uint64>(9);
/// @brief defines the "sub page write permissions" field in the page
bsl::uint64 sub : static_cast<bsl::uint64>(1);
/// @brief defines the "ignored" field in the page
bsl::uint64 ignored4 : static_cast<bsl::uint64>(1);
/// @brief defines the "virtualization exception" field in the page
bsl::uint64 ve : static_cast<bsl::uint64>(1);
};
}
#pragma pack(pop)
#endif

View file

@ -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 <lock_guard.hpp>
#include <map_page_flags.hpp>
#include <memory_type.hpp>
#include <page_pool_t.hpp>
#include <spinlock.hpp>
#include <bsl/convert.hpp>
#include <bsl/debug.hpp>
#include <bsl/errc_type.hpp>
#include <bsl/finally.hpp>
#include <bsl/safe_integral.hpp>
#include <bsl/touch.hpp>
#include <bsl/unlikely.hpp>
namespace example
{
/// <!-- description -->
/// @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{};
/// <!-- description -->
/// @brief Returns the extended page-map level-4 (NPML4T) offset given
/// a guest physical address.
///
/// <!-- ieputs/outputs -->
/// @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;
}
/// <!-- description -->
/// @brief Adds a epdpt_t to the provided epml4te_t.
///
/// <!-- ieputs/outputs -->
/// @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<void>()};
if (bsl::unlikely(nullptr == table)) {
bsl::print<bsl::V>() << 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::V>() << 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;
}
/// <!-- description -->
/// @brief Adds a epdpt_t to the provided epml4te_t.
///
/// <!-- ieputs/outputs -->
/// @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));
}
/// <!-- description -->
/// @brief Returns the epdpt_t associated with the provided
/// epml4te_t.
///
/// <!-- ieputs/outputs -->
/// @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<epdpt_t>(entry_phys);
}
/// <!-- description -->
/// @brief Returns the epdpt_t associated with the provided
/// epml4te_t.
///
/// <!-- ieputs/outputs -->
/// @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<epdpt_t const>(entry_phys);
}
/// <!-- description -->
/// @brief Returns the extended page-directory-pointer table (NPDPT)
/// offset given a guest physical address.
///
/// <!-- ieputs/outputs -->
/// @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;
}
/// <!-- description -->
/// @brief Adds a epdt_t to the provided epdpte_t.
///
/// <!-- ieputs/outputs -->
/// @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<void>()};
if (bsl::unlikely(nullptr == table)) {
bsl::print<bsl::V>() << 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::V>() << 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;
}
/// <!-- description -->
/// @brief Adds a epdt_t to the provided epdpte_t.
///
/// <!-- ieputs/outputs -->
/// @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));
}
/// <!-- description -->
/// @brief Returns the epdt_t associated with the provided
/// epdpte_t.
///
/// <!-- ieputs/outputs -->
/// @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<epdt_t>(entry_phys);
}
/// <!-- description -->
/// @brief Returns the epdt_t associated with the provided
/// epdpte_t.
///
/// <!-- ieputs/outputs -->
/// @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<epdt_t const>(entry_phys);
}
/// <!-- description -->
/// @brief Returns the extended page-directory table (NPDT) offset
/// given a guest physical address.
///
/// <!-- ieputs/outputs -->
/// @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;
}
/// <!-- description -->
/// @brief Adds a ept_t to the provided epdte_t.
///
/// <!-- ieputs/outputs -->
/// @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<void>()};
if (bsl::unlikely(nullptr == table)) {
bsl::print<bsl::V>() << 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::V>() << 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;
}
/// <!-- description -->
/// @brief Adds a ept_t to the provided epdte_t.
///
/// <!-- ieputs/outputs -->
/// @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));
}
/// <!-- description -->
/// @brief Returns the ept_t associated with the provided
/// epdte_t.
///
/// <!-- ieputs/outputs -->
/// @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<ept_t>(entry_phys);
}
/// <!-- description -->
/// @brief Returns the ept_t associated with the provided
/// epdte_t.
///
/// <!-- ieputs/outputs -->
/// @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<ept_t const>(entry_phys);
}
/// <!-- description -->
/// @brief Returns the page-table (NPT) offset given a
/// guest physical address.
///
/// <!-- ieputs/outputs -->
/// @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;
}
/// <!-- description -->
/// @brief Returns true if the provided address is page aligned
///
/// <!-- ieputs/outputs -->
/// @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;
}
/// <!-- description -->
/// @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:
/// <!-- description -->
/// @brief Initializes this extended_page_table_t
///
/// <!-- ieputs/outputs -->
/// @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<epml4t_t>();
if (bsl::unlikely(nullptr == m_epml4t)) {
bsl::print<bsl::V>() << 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::V>() << bsl::here();
return bsl::errc_failure;
}
release_on_error.ignore();
m_initialized = true;
return bsl::errc_success;
}
/// <!-- description -->
/// @brief Releases the memory allocated in this extended page tables
///
constexpr void
release() noexcept
{
this->auto_release();
m_page_pool = {};
m_initialized = false;
}
/// <!-- description -->
/// @brief Returns the physical address of the PML4
///
/// <!-- ieputs/outputs -->
/// @return Returns the physical address of the PML4
///
[[nodiscard]] constexpr auto
phys() const noexcept -> bsl::safe_umx const &
{
return m_epml4t_phys;
}
/// <!-- description -->
/// @brief Maps a 4k page into the extended page tables being managed
/// by this class.
///
/// <!-- ieputs/outputs -->
/// @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::V>() << 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::V>() << 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::V>() << 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;
}
/// <!-- description -->
/// @brief Maps a 2m page into the extended page tables being managed
/// by this class.
///
/// <!-- ieputs/outputs -->
/// @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::V>() << 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::V>() << 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

View file

@ -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 <bsl/convert.hpp>
#include <bsl/safe_integral.hpp>
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

View file

@ -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 <bsl/convert.hpp>
#include <bsl/safe_integral.hpp>
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

File diff suppressed because it is too large Load diff

View file

@ -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

View file

@ -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

View file

@ -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()};

View file

@ -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;
}

View file

@ -46,6 +46,8 @@
#include <bsl/safe_integral.hpp>
#include <bsl/swap.hpp>
#include <bsl/unlikely.hpp>
#include <bsl/convert.hpp>
#include <bsl/finally.hpp>
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();
}

View file

@ -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;

View file

@ -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;
}

View file

@ -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:

Some files were not shown because too many files have changed in this diff Show more