Unit/Integration Test and ARM support changes

This patch contains a massive number of changes that are the
result of finally adding unit/integration tests and ARM
support. ARM support moved a number of files that were duplicates
while the unit and integration tests identified a massive number
of structural issues. The cost of waiting so long to finally
add tests.
This commit is contained in:
Rian Quinn 2021-03-25 11:25:06 -06:00
parent d8876dd605
commit f5f39193e5
1536 changed files with 125188 additions and 15970 deletions

View file

@ -22,7 +22,10 @@
Checks:
'
-*,
bsl-*
bsl-*,
-bsl-template-generic-param,
-bsl-literals-user-defined,
-bsl-unused-return-value,
bugprone-*,
-bugprone-branch-clone,
cert-*,

View file

@ -813,7 +813,7 @@ WARN_LOGFILE =
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
# NOTE: If this tag is empty the current directory is searched.
INPUT = kernel loader runtime syscall vmmctl
INPUT = example kernel loader runtime syscall vmmctl
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
@ -913,7 +913,7 @@ EXCLUDE_SYMLINKS = NO
# Note that the wildcards are matched against the file with absolute path, so to
# exclude all test directories for example use the pattern */test/*
EXCLUDE_PATTERNS = */backup/* \
EXCLUDE_PATTERNS = */test/* \
*/cmake/* \
*/docs/* \

View file

@ -63,7 +63,7 @@ jobs:
sudo tar -xzvf hypervisor/utils/linux/llvm-bareflank.tar.gz -C /usr/lib/
export PATH="/usr/lib/llvm-bareflank/bin:$PATH"
mkdir build && cd build
cmake -GNinja -DCMAKE_CXX_COMPILER="clang++" -DCMAKE_BUILD_TYPE=CLANG_TIDY -DBUILD_EXAMPLES=ON -DBUILD_TESTS=ON ../hypervisor
cmake -GNinja -DCMAKE_CXX_COMPILER="clang++" -DCMAKE_BUILD_TYPE=CLANG_TIDY -DBUILD_EXAMPLES=ON -DBUILD_TESTS=ON -DBSL_DEBUG_LEVEL=bsl::VVV ../hypervisor
ninja
shell: bash
@ -81,7 +81,7 @@ jobs:
- name: Validate ASAN
run: |
mkdir build && cd build
cmake -GNinja -DCMAKE_CXX_COMPILER="clang++" -DCMAKE_BUILD_TYPE=ASAN -DBUILD_EXAMPLES=ON -DBUILD_TESTS=ON ../hypervisor
cmake -GNinja -DCMAKE_CXX_COMPILER="clang++" -DCMAKE_BUILD_TYPE=ASAN -DBUILD_EXAMPLES=ON -DBUILD_TESTS=ON -DBSL_DEBUG_LEVEL=bsl::VVV ../hypervisor
ninja
ninja unittest
shell: bash
@ -100,7 +100,7 @@ jobs:
- name: Validate UBSAN
run: |
mkdir build && cd build
cmake -GNinja -DCMAKE_CXX_COMPILER="clang++" -DCMAKE_BUILD_TYPE=UBSAN -DBUILD_EXAMPLES=ON -DBUILD_TESTS=ON ../hypervisor
cmake -GNinja -DCMAKE_CXX_COMPILER="clang++" -DCMAKE_BUILD_TYPE=UBSAN -DBUILD_EXAMPLES=ON -DBUILD_TESTS=ON -DBSL_DEBUG_LEVEL=bsl::VVV ../hypervisor
ninja
ninja unittest
shell: bash
@ -137,34 +137,35 @@ jobs:
- name: Validate Debug Build
run: |
mkdir build && cd build
cmake -GNinja -DCMAKE_CXX_COMPILER="clang++" -DCMAKE_BUILD_TYPE=DEBUG -DBUILD_EXAMPLES=ON -DBUILD_TESTS=ON ../hypervisor
cmake -GNinja -DCMAKE_CXX_COMPILER="clang++" -DCMAKE_BUILD_TYPE=DEBUG -DBUILD_EXAMPLES=ON -DBUILD_TESTS=ON -DBSL_DEBUG_LEVEL=bsl::VVV ../hypervisor
ninja
ninja unittest
shell: bash
# Codecov:
# runs-on: ubuntu-20.04
# steps:
# - uses: actions/checkout@v2
# with:
# path: hypervisor
# - name: Setup
# run: |
# sudo apt-get update
# sudo apt-get install -y clang lld cmake ninja-build
# wget https://github.com/mozilla/grcov/releases/download/v0.5.9/grcov-linux-x86_64.tar.bz2
# tar xvf grcov-linux-x86_64.tar.bz2
# sudo mv grcov /usr/bin/
# shell: bash
# - name: Gather Codecov Info
# run: |
# mkdir build && cd build
# cmake -GNinja -DCMAKE_CXX_COMPILER="clang++" -DCMAKE_BUILD_TYPE=CODECOV -DBUILD_TESTS=ON ../hypervisor
# ninja
# ninja codecov-info
# shell: bash
# - name: Upload Codecov Info
# run: |
# cd build
# ninja codecov-upload-ci
# shell: bash
Codecov:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2
with:
path: hypervisor
- name: Setup
run: |
sudo apt-get update
sudo apt-get install -y clang cmake ninja-build llvm
wget https://github.com/mozilla/grcov/releases/download/v0.8.0/grcov-linux-x86_64.tar.bz2
tar xvf grcov-linux-x86_64.tar.bz2
sudo mv grcov /usr/bin/
sudo rm /usr/bin/gcov
sudo ln -s /usr/bin/llvm-cov-10 /usr/bin/gcov
shell: bash
- name: Gather Codecov Info
run: |
mkdir build && cd build
cmake -GNinja -DCMAKE_CXX_COMPILER="clang++" -DCMAKE_BUILD_TYPE=CODECOV -DBUILD_TESTS=ON -DBSL_DEBUG_LEVEL=bsl::VVV ../hypervisor
ninja
shell: bash
- name: Upload Codecov Info
run: |
cd build
ninja codecov-upload-ci
shell: bash

2
.gitignore vendored
View file

@ -57,6 +57,8 @@
build/
site/
doxygen_output/
grcov/
genhtml/
# Linux Loader
loader/**/*.symvers

View file

@ -20,26 +20,37 @@
# SOFTWARE.
cmake_minimum_required(VERSION 3.13)
project(hypervisor CXX)
project(hypervisor C CXX ASM)
include(${CMAKE_CURRENT_LIST_DIR}/cmake/init_build.cmake)
if(HYPERVISOR_BUILD_LOADER)
add_subdirectory(loader)
endif()
if(NOT CMAKE_BUILD_TYPE STREQUAL CODECOV)
if(HYPERVISOR_BUILD_LOADER)
add_subdirectory(loader)
endif()
if(HYPERVISOR_BUILD_VMMCTL)
add_subdirectory(vmmctl)
endif()
if(HYPERVISOR_BUILD_VMMCTL)
add_subdirectory(vmmctl)
endif()
if(HYPERVISOR_BUILD_MICROKERNEL)
hypervisor_add_mk_cross_compile(cmake/mk_cross_compile)
endif()
if(HYPERVISOR_BUILD_MICROKERNEL)
hypervisor_add_mk_cross_compile(cmake/mk_cross_compile)
endif()
if(HYPERVISOR_BUILD_EXAMPLES OR DEFINED HYPERVISOR_EXTENSIONS_DIR)
hypervisor_add_ext_cross_compile(cmake/ext_cross_compile)
if(BUILD_TESTS AND NOT HYPERVISOR_BUILD_TESTS_OVERRIDE)
include(kernel/integration/integration_targets.cmake)
endif()
endif()
if(HYPERVISOR_BUILD_EFI)
hypervisor_add_efi_cross_compile(cmake/efi_cross_compile)
if(NOT CMAKE_BUILD_TYPE STREQUAL RELEASE AND NOT CMAKE_BUILD_TYPE STREQUAL MINSIZEREL)
if(BUILD_TESTS AND NOT HYPERVISOR_BUILD_TESTS_OVERRIDE)
add_subdirectory(example/default/test)
add_subdirectory(kernel/test)
# add_subdirectory(loader/test)
add_subdirectory(runtime/test)
add_subdirectory(syscall/test)
add_subdirectory(vmmctl/test)
endif()
endif()

116
README.md
View file

@ -1,20 +1,30 @@
![Bareflank](https://github.com/Bareflank/hypervisor/raw/master/.github/images/hypervisor_logo.png)
## Description
**Warning:** The master branch is under heavy development as we work to complete Bareflank 3.0. For now, you might want to consider one of our offical releases until Bareflank 3.0 is complete .
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), led by Assured Information Security, Inc. (AIS), that provides the tools needed to rapidly prototype and create your own hypervisor.
Most people think that hypervisors are meant to virtualize servers and provide a means to run Windows on a Mac, but there is a whole field of research where hypervisors are used without guest virtual machines. Since a hypervisor is capable of controlling the host OS running underneath it (so-called "ring -1"), host-only hypervisors support introspection, reverse engineering, anti-virus, containerization, diversity, and even architectural research like [MoRE](https://github.com/ainfosec/MoRE). All of these use cases start the same way, by spending months standing up the hypervisor itself before you can start working on your actual project. Existing open source hypervisors are burdened with legacy support, only support a single operating system or contain unnecessary complexity that make them painful to work with when conducting hypervisor research.
Instead, Bareflank uses a layered, modular approach, that lets you pick just how much complexity you need in your project:
- [BSL](https://github.com/Bareflank/bsl): provides a header-only, AUTOSAR compliant implementation of a subset of the C++ Standard Library, used to implement Bareflank's C++ components ensuring Bareflank and projects built using Bareflank can support critical systems applications like Automotive.
- [LLVM](https://github.com/Bareflank/llvm-project): provides our custom implementation of the LLVM Clang compiler and associated tools including additional static analysis checks in Clang Tidy 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 (e.g., Windows and Linux), ABI (e.g., SysV and MS64) and programming language (e.g., C, C++ and Python).
- [hypervisor](https://github.com/Bareflank/hypervisor): provides the base SDK including the loader, the Bareflank microkernel and support applications. If all you need is host-only hypervisor support, this is the project to start with.
- [MicroV](https://github.com/Bareflank/microv): provides support for guest VMs, allowing the user to create and execute additional virtual machines. If you need guest VM support, this is the project to start with.
To support Bareflank's ecosystem, the hypervisor SDK is licensed under MIT, specifically enabling users of the project to both contribute back to the project, but also create proprietary, closed source products that use the Bareflank SDK as their foundation. Feel free to use Bareflank to create your commercial products. All we ask is that if you find a bug or add a feature to the SDK that you consider contributing your changes back to the project.
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
compliant implementation of a subset of the C++ Standard Library, used to
implement Bareflank's C++ components ensuring Bareflank and projects built
using Bareflank can support critical systems applications.
- [LLVM](https://github.com/Bareflank/llvm-project): provides our custom
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.
- [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
scaffolding for creating your own hypervisor. If you are in education or
performing research and do not want to deal with the complexity of a fully
functional hypervisor, this repo would be your starting point. By itself, the
code in this repo only implements enough virtualization to start/stop a
hypervisor.
- [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.
## **Quick start**
![GitHub release (latest by date)](https://img.shields.io/github/v/release/bareflank/hypervisor?color=brightgreen)
@ -56,6 +66,41 @@ the following videos at [CppCon](https://www.youtube.com/user/CppCon) below:
[![CppCon 2017](https://i.imgur.com/nBFD6uA.png)](https://www.youtube.com/watch?v=KdJhQuycD78)
[![CppCon 2016](https://i.imgur.com/fwmlOiJ.png)](https://www.youtube.com/watch?v=uQSQy-7lveQ)
## **Important Tips**
Before attempting to use Bareflank, please review the following tips as they can make a huge difference in your initial experience:
- Make sure you are running on a system with a serial port. Which serial port
Bareflank uses can be configured by setting HYPERVISOR_SERIAL_PORT on x86
or HYPERVISOR_SERIAL_PORTH and HYPERVISOR_SERIAL_PORTL on ARMv8. Cables like
[these](https://www.amazon.com/USB-Serial-Adapter-Modem-9-pin/dp/B008634VJY/ref=sr_1_1_sspa?crid=P21N96MOCMDS&dchild=1&keywords=usb+null+modem+cable&qid=1622226200&sprefix=usb+null+mo%2Caps%2C201&sr=8-1-spons&psc=1&spLa=ZW5jcnlwdGVkUXVhbGlmaWVyPUEzNzBLRUcxVzRNOE8zJmVuY3J5cHRlZElkPUEwMTA1Nzg4U0IyM1RPU0NTRjROJmVuY3J5cHRlZEFkSWQ9QTA3OTM4MjVFMzlNSEQ3T1E2MEwmd2lkZ2V0TmFtZT1zcF9hdGYmYWN0aW9uPWNsaWNrUmVkaXJlY3QmZG9Ob3RMb2dDbGljaz10cnVl)
work great. Bareflank uses the following settings (115200 baud rate, 8 data
bits, no parity bits, one stop bit).
- Using PCI serial addon cards will not work with UEFI. These cards need to be
initialized by the OS, logic that Bareflank does not currently contain.
If you are using Bareflank directly from Windows/Linux, these cards will work
fine, but from UEFI, you need a serial port provided on the motherboard.
- The serial output might contain a lot of ANSI color codes if you are using
a terminal that doesn't support ANSI color. To remove these, configure CMake
with -DENABLE_COLOR=OFF.
- Windows Subsystem For Linux v2 is not supported. When this is turned on,
Windows runs under HyperV, which currently does not support nested
virtualization. Furthermore, if you have ever enabled the WSL2, you must
turn HyperV off using `bcdedit /set hypervisorlaunchtype off` as HyperV will
continue to run even if you are no longer using the WSL2.
- When running under Windows, driver issues can be seen by using
[DbgView](https://docs.microsoft.com/en-us/sysinternals/downloads/debugview).
This tool must be run with Admin rights, and you need to turn on kernel
output. Once this is working, you will see error messages coming from the
Windows driver if needed.
- Nested virtualization (i.e., attempting to run Bareflank inside a VM) is
not officially supported, but does work if you know what you are doing.
Specifically, a headless version of Linux 20.04 or higher in VMWare works
with the proper configuration. VirtualBox does not work due to a lack of
supported features and KVM may or may not work (your milage may vary). In
general, you should be using real hardware.
- If you need to compile Bareflank on older versions of Linux, it is possible,
but you will need to update the build tools manually including LLVM 10+ and
CMake 3.13+.
## **Build Requirements**
Currently, the Bareflank hypervisor only supports the Clang/LLVM 10+ compiler. This, however, ensures that the hypervisor can be natively compiled on Windows including support for cross-compiling. Support for other C++20 compilers can be added if needed, just let us know if that is something you need.
@ -208,13 +253,52 @@ The `HYPERVISOR_EXTENSIONS` variable tells CMake what the name of the resulting
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/cpp/mk_interface.hpp](https://github.com/Bareflank/hypervisor/blob/master/syscall/include/cpp/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://bareflank.github.io/hypervisor/>
- **Documentation**: <https://github.com/Bareflank/hypervisor/tree/master/docs>
- **Examples**: <https://github.com/Bareflank/hypervisor/tree/master/example>
- **Unit Tests**: <https://github.com/Bareflank/hypervisor/tree/master/test>
If you have any questions, bugs, or feature requests, please feel free to ask on any of the following:
- **Slack**: <https://bareflank.herokuapp.com/>
@ -244,6 +328,8 @@ If this is the case, disable the default serial device using the following:
reg add "HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Serial" /f /v "start" /t REG_DWORD /d "4"
```
See "Important Tips" above for additional details on how to use serial devices.
## License
The Bareflank Hypervisor is licensed under the MIT License.

View file

@ -21,13 +21,32 @@
include(${bsl_SOURCE_DIR}/cmake/function/bf_add_config.cmake)
option(HYPERVISOR_BUILD_LOADER "Turns on/off building the loader" ON)
option(HYPERVISOR_BUILD_VMMCTL "Turns on/off building the vmmctl" ON)
option(HYPERVISOR_BUILD_MICROKERNEL "Turns on/off building the microkernel" ON)
option(HYPERVISOR_BUILD_EXAMPLES "Turns on/off building the examples" ON)
option(HYPERVISOR_BUILD_EFI "Turns on/off building the EFI loader" OFF)
if(NOT CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64")
bf_add_config(
CONFIG_NAME HYPERVISOR_DEFAULT_BUILD_VMMCTL
CONFIG_TYPE BOOL
DEFAULT_VAL ON
DESCRIPTION "Define the default value for HYPERVISOR_BUILD_VMMCTL"
SKIP_VALIDATION
)
else()
bf_add_config(
CONFIG_NAME HYPERVISOR_DEFAULT_BUILD_EFI
CONFIG_TYPE BOOL
DEFAULT_VAL ON
DESCRIPTION "Define the default value for HYPERVISOR_BUILD_EFI"
SKIP_VALIDATION
)
if (NOT DEFINED HYPERVISOR_TARGET_ARCH)
set(HYPERVISOR_TARGET_ARCH ${CMAKE_SYSTEM_PROCESSOR})
endif()
option(HYPERVISOR_BUILD_LOADER "Turns on/off building the loader" ON)
option(HYPERVISOR_BUILD_VMMCTL "Turns on/off building the vmmctl" ${HYPERVISOR_DEFAULT_BUILD_VMMCTL})
option(HYPERVISOR_BUILD_MICROKERNEL "Turns on/off building the microkernel" ON)
option(HYPERVISOR_BUILD_EFI "Turns on/off building the EFI loader" ${HYPERVISOR_DEFAULT_BUILD_EFI})
if(NOT DEFINED HYPERVISOR_TARGET_ARCH)
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
execute_process(
COMMAND ${CMAKE_CURRENT_LIST_DIR}/../../utils/linux/get_target_arch
@ -47,7 +66,7 @@ else()
set(HYPERVISOR_DEFAULT_TARGET_ARCH ${HYPERVISOR_TARGET_ARCH})
endif()
if (NOT DEFINED HYPERVISOR_CXX_LINKER)
if(NOT DEFINED HYPERVISOR_CXX_LINKER)
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
set(HYPERVISOR_DEFAULT_CXX_LINKER "ld.lld")
elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows")
@ -59,7 +78,7 @@ else()
set(HYPERVISOR_DEFAULT_CXX_LINKER ${HYPERVISOR_CXX_LINKER})
endif()
if (NOT DEFINED HYPERVISOR_EFI_LINKER)
if(NOT DEFINED HYPERVISOR_EFI_LINKER)
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
set(HYPERVISOR_DEFAULT_EFI_LINKER "lld-link")
elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows")
@ -71,7 +90,7 @@ else()
set(HYPERVISOR_DEFAULT_EFI_LINKER ${HYPERVISOR_EFI_LINKER})
endif()
if (NOT DEFINED HYPERVISOR_EFI_FS0)
if(NOT DEFINED HYPERVISOR_EFI_FS0)
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
set(HYPERVISOR_DEFAULT_EFI_FS0 "/boot/efi/")
elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows")
@ -94,7 +113,7 @@ bf_add_config(
bf_add_config(
CONFIG_NAME HYPERVISOR_EXTENSIONS_DIR
CONFIG_TYPE STRING
DEFAULT_VAL "${CMAKE_SOURCE_DIR}/example"
DEFAULT_VAL "${CMAKE_SOURCE_DIR}/example/default"
DESCRIPTION "Defines the extension to use"
SKIP_VALIDATION
)
@ -104,7 +123,7 @@ bf_add_config(
CONFIG_TYPE STRING
DEFAULT_VAL ${HYPERVISOR_DEFAULT_TARGET_ARCH}
DESCRIPTION "The target architecture for the build"
OPTIONS AuthenticAMD GenuineIntel
OPTIONS AuthenticAMD GenuineIntel aarch64
)
bf_add_config(
@ -112,7 +131,7 @@ bf_add_config(
CONFIG_TYPE STRING
DEFAULT_VAL ${HYPERVISOR_DEFAULT_CXX_LINKER}
DESCRIPTION "Define the linker to use for cross-compiling"
SKIP_VALIDATION
OPTIONS ld.lld
)
bf_add_config(
@ -120,7 +139,7 @@ bf_add_config(
CONFIG_TYPE STRING
DEFAULT_VAL ${HYPERVISOR_DEFAULT_EFI_LINKER}
DESCRIPTION "Define the linker to use for linking EFI applications"
SKIP_VALIDATION
OPTIONS lld-link
)
bf_add_config(
@ -134,24 +153,58 @@ bf_add_config(
bf_add_config(
CONFIG_NAME HYPERVISOR_PAGE_SIZE
CONFIG_TYPE STRING
DEFAULT_VAL "BSL_PAGE_SIZE"
DESCRIPTION "Defines the hypervisor's page size"
SKIP_VALIDATION
DEFAULT_VAL ${BSL_PAGE_SIZE}
DESCRIPTION "Defines the hypervisor's page size in bytes"
OPTIONS 0x1000
)
bf_add_config(
CONFIG_NAME HYPERVISOR_PAGE_SHIFT
CONFIG_TYPE STRING
DEFAULT_VAL "12"
DESCRIPTION "Defines the hypervisor's page size (as a shift)"
DESCRIPTION "Defines the hypervisor's page size in bytes (as a shift)"
OPTIONS 12
)
if(HYPERVISOR_TARGET_ARCH STREQUAL "AuthenticAMD" OR HYPERVISOR_TARGET_ARCH STREQUAL "GenuineIntel")
bf_add_config(
CONFIG_NAME HYPERVISOR_SERIAL_PORT
CONFIG_TYPE STRING
DEFAULT_VAL "0x03F8"
DESCRIPTION "Defines the hypervisor's serial port"
SKIP_VALIDATION
)
else()
bf_add_config(
CONFIG_NAME HYPERVISOR_SERIAL_PORTH
CONFIG_TYPE STRING
DEFAULT_VAL "0xFE20"
DESCRIPTION "Defines the upper 16 bits of the hypervisor's UART0 base address (defaults to RPi4)"
SKIP_VALIDATION
)
bf_add_config(
CONFIG_NAME HYPERVISOR_SERIAL_PORTL
CONFIG_TYPE STRING
DEFAULT_VAL "0x1000"
DESCRIPTION "Defines the lower 16 bits of the hypervisor's UART0 base address (defaults to RPi4)"
SKIP_VALIDATION
)
endif()
bf_add_config(
CONFIG_NAME HYPERVISOR_DEBUG_RING_SIZE
CONFIG_TYPE STRING
DEFAULT_VAL "0x1FFF0"
DESCRIPTION "Defines the hypervisor's debug ring size in bytes"
SKIP_VALIDATION
)
bf_add_config(
CONFIG_NAME HYPERVISOR_SERIAL_PORT
CONFIG_NAME HYPERVISOR_VMEXIT_LOG_SIZE
CONFIG_TYPE STRING
DEFAULT_VAL "0x03F8"
DESCRIPTION "Defines the hypervisor's serial port"
DEFAULT_VAL "5"
DESCRIPTION "Defines the hypervisor's vmexit log size in # of entries"
SKIP_VALIDATION
)
@ -160,7 +213,7 @@ bf_add_config(
CONFIG_TYPE STRING
DEFAULT_VAL "0x800000"
DESCRIPTION "Defines the hypervisor's max ELF file size supported"
SKIP_VALIDATION
OPTIONS 0x800000
)
bf_add_config(
@ -203,44 +256,28 @@ bf_add_config(
SKIP_VALIDATION
)
bf_add_config(
CONFIG_NAME HYPERVISOR_MAX_VPS_PER_VM
CONFIG_TYPE STRING
DEFAULT_VAL "HYPERVISOR_MAX_PPS"
DESCRIPTION "Defines the hypervisor's max number of virtual processors per VM supported"
SKIP_VALIDATION
)
bf_add_config(
CONFIG_NAME HYPERVISOR_MAX_VPSS_PER_VP
CONFIG_TYPE STRING
DEFAULT_VAL "2"
DESCRIPTION "Defines the hypervisor's max number of virtual processor states per VP supported"
SKIP_VALIDATION
)
bf_add_config(
CONFIG_NAME HYPERVISOR_MAX_VPSS
CONFIG_TYPE STRING
DEFAULT_VAL "HYPERVISOR_MAX_VPS * HYPERVISOR_MAX_VPSS_PER_VP"
DEFAULT_VAL ${HYPERVISOR_MAX_VPS}
DESCRIPTION "Defines the hypervisor's max number of virtual processor states"
SKIP_VALIDATION
)
bf_add_config(
CONFIG_NAME HYPERVISOR_DEBUG_RING_SIZE
CONFIG_NAME HYPERVISOR_MK_DIRECT_MAP_ADDR
CONFIG_TYPE STRING
DEFAULT_VAL "0x7FF0"
DESCRIPTION "Defines the hypervisor's debug ring size"
SKIP_VALIDATION
DEFAULT_VAL "0x0000400000000000"
DESCRIPTION "Defines an microkernel's default direct map address"
OPTIONS 0x0000400000000000
)
bf_add_config(
CONFIG_NAME HYPERVISOR_DIRECT_MAP_ADDR
CONFIG_NAME HYPERVISOR_MK_DIRECT_MAP_SIZE
CONFIG_TYPE STRING
DEFAULT_VAL "0x0000400000000000"
DESCRIPTION "Defines an hypervisor's default direct map address"
SKIP_VALIDATION
DEFAULT_VAL "0x0000200000000000"
DESCRIPTION "Defines an microkernel's default direct map size in bytes"
OPTIONS 0x0000200000000000
)
bf_add_config(
@ -248,7 +285,7 @@ bf_add_config(
CONFIG_TYPE STRING
DEFAULT_VAL "0x0000008000000000"
DESCRIPTION "Defines the microkernel's default stack address"
SKIP_VALIDATION
OPTIONS 0x0000008000000000
)
bf_add_config(
@ -264,31 +301,63 @@ bf_add_config(
CONFIG_TYPE STRING
DEFAULT_VAL "0x0000028000000000"
DESCRIPTION "Defines the microkernel's default code address"
SKIP_VALIDATION
OPTIONS 0x0000028000000000
)
bf_add_config(
CONFIG_NAME HYPERVISOR_MK_CODE_SIZE
CONFIG_TYPE STRING
DEFAULT_VAL "HYPERVISOR_MAX_ELF_FILE_SIZE"
DESCRIPTION "Defines the microkernel's default code max size"
DEFAULT_VAL ${HYPERVISOR_MAX_ELF_FILE_SIZE}
DESCRIPTION "Defines the microkernel's default code max size in bytes"
OPTIONS ${HYPERVISOR_MAX_ELF_FILE_SIZE}
)
bf_add_config(
CONFIG_NAME HYPERVISOR_MK_PAGE_POOL_ADDR
CONFIG_TYPE STRING
DEFAULT_VAL ${HYPERVISOR_MK_DIRECT_MAP_ADDR}
DESCRIPTION "Defines the hypervisor's default page pool address"
OPTIONS ${HYPERVISOR_MK_DIRECT_MAP_ADDR}
)
bf_add_config(
CONFIG_NAME HYPERVISOR_MK_PAGE_POOL_SIZE
CONFIG_TYPE STRING
DEFAULT_VAL "0x8000000"
DESCRIPTION "Defines the hypervisor's default page pool size in bytes"
SKIP_VALIDATION
)
bf_add_config(
CONFIG_NAME HYPERVISOR_MK_MAP_ADDR
CONFIG_NAME HYPERVISOR_MK_HUGE_POOL_ADDR
CONFIG_TYPE STRING
DEFAULT_VAL "0x0000038000000000"
DESCRIPTION "Defines the microkernel's default map address"
DEFAULT_VAL ${HYPERVISOR_MK_DIRECT_MAP_ADDR}
DESCRIPTION "Defines the microkernel's default huge pool address"
OPTIONS ${HYPERVISOR_MK_DIRECT_MAP_ADDR}
)
bf_add_config(
CONFIG_NAME HYPERVISOR_MK_HUGE_POOL_SIZE
CONFIG_TYPE STRING
DEFAULT_VAL "0x10000"
DESCRIPTION "Defines the microkernel's default huge pool size in bytes"
SKIP_VALIDATION
)
bf_add_config(
CONFIG_NAME HYPERVISOR_MK_MAP_SIZE
CONFIG_NAME HYPERVISOR_EXT_DIRECT_MAP_ADDR
CONFIG_TYPE STRING
DEFAULT_VAL "0x1000000000"
DESCRIPTION "Defines the microkernel's default map max size"
SKIP_VALIDATION
DEFAULT_VAL "0x0000600000000000"
DESCRIPTION "Defines an extension's default direct map address"
OPTIONS 0x0000600000000000
)
bf_add_config(
CONFIG_NAME HYPERVISOR_EXT_DIRECT_MAP_SIZE
CONFIG_TYPE STRING
DEFAULT_VAL "0x0000200000000000"
DESCRIPTION "Defines an extension's default direct map size in bytes"
OPTIONS 0x0000200000000000
)
bf_add_config(
@ -296,7 +365,7 @@ bf_add_config(
CONFIG_TYPE STRING
DEFAULT_VAL "0x0000308000000000"
DESCRIPTION "Defines an extension's default stack address"
SKIP_VALIDATION
OPTIONS 0x0000308000000000
)
bf_add_config(
@ -312,15 +381,15 @@ bf_add_config(
CONFIG_TYPE STRING
DEFAULT_VAL "0x0000328000000000"
DESCRIPTION "Defines an extension's default code address"
SKIP_VALIDATION
OPTIONS 0x0000328000000000
)
bf_add_config(
CONFIG_NAME HYPERVISOR_EXT_CODE_SIZE
CONFIG_TYPE STRING
DEFAULT_VAL "HYPERVISOR_MAX_ELF_FILE_SIZE"
DESCRIPTION "Defines an extension's default code max size"
SKIP_VALIDATION
DEFAULT_VAL ${HYPERVISOR_MAX_ELF_FILE_SIZE}
DESCRIPTION "Defines an extension's default code max size in bytes"
OPTIONS ${HYPERVISOR_MAX_ELF_FILE_SIZE}
)
bf_add_config(
@ -328,61 +397,61 @@ bf_add_config(
CONFIG_TYPE STRING
DEFAULT_VAL "0x0000338000000000"
DESCRIPTION "Defines an extension's default TLS address"
SKIP_VALIDATION
OPTIONS 0x0000338000000000
)
bf_add_config(
CONFIG_NAME HYPERVISOR_EXT_TLS_SIZE
CONFIG_TYPE STRING
DEFAULT_VAL "0x2000"
DESCRIPTION "Defines an extension's default TLS size"
SKIP_VALIDATION
DESCRIPTION "Defines an extension's default TLS size in bytes (not modifiable)"
OPTIONS 0x2000
)
bf_add_config(
CONFIG_NAME HYPERVISOR_EXT_PAGE_POOL_ADDR
CONFIG_TYPE STRING
DEFAULT_VAL "0x0000358000000000"
DEFAULT_VAL ${HYPERVISOR_EXT_DIRECT_MAP_ADDR}
DESCRIPTION "Defines an extension's default page pool address"
SKIP_VALIDATION
OPTIONS ${HYPERVISOR_EXT_DIRECT_MAP_ADDR}
)
bf_add_config(
CONFIG_NAME HYPERVISOR_EXT_PAGE_POOL_SIZE
CONFIG_TYPE STRING
DEFAULT_VAL "0x1000000000"
DESCRIPTION "Defines an extension's default page pool max size"
SKIP_VALIDATION
DEFAULT_VAL ${HYPERVISOR_MK_PAGE_POOL_SIZE}
DESCRIPTION "Defines an extension's default page pool max size in bytes"
OPTIONS ${HYPERVISOR_MK_PAGE_POOL_SIZE}
)
bf_add_config(
CONFIG_NAME HYPERVISOR_EXT_HUGE_POOL_ADDR
CONFIG_TYPE STRING
DEFAULT_VAL ${HYPERVISOR_EXT_DIRECT_MAP_ADDR}
DESCRIPTION "Defines an extension's default huge pool address"
OPTIONS ${HYPERVISOR_EXT_DIRECT_MAP_ADDR}
)
bf_add_config(
CONFIG_NAME HYPERVISOR_EXT_HUGE_POOL_SIZE
CONFIG_TYPE STRING
DEFAULT_VAL ${HYPERVISOR_MK_HUGE_POOL_SIZE}
DESCRIPTION "Defines an extension's default huge pool max size in bytes"
OPTIONS ${HYPERVISOR_MK_HUGE_POOL_SIZE}
)
bf_add_config(
CONFIG_NAME HYPERVISOR_EXT_HEAP_POOL_ADDR
CONFIG_TYPE STRING
DEFAULT_VAL "0x0000368000000000"
DESCRIPTION "Defines an extension's default heap pool address"
SKIP_VALIDATION
DEFAULT_VAL "0x0000348000000000"
DESCRIPTION "Defines an extension's default heap pool address in bytes"
OPTIONS 0x0000348000000000
)
bf_add_config(
CONFIG_NAME HYPERVISOR_EXT_HEAP_POOL_SIZE
CONFIG_TYPE STRING
DEFAULT_VAL "0x1000000000"
DEFAULT_VAL ${HYPERVISOR_MK_PAGE_POOL_SIZE}
DESCRIPTION "Defines an extension's default heap pool max size"
SKIP_VALIDATION
)
bf_add_config(
CONFIG_NAME HYPERVISOR_HUGE_POOL_SIZE
CONFIG_TYPE STRING
DEFAULT_VAL "0x10000"
DESCRIPTION "Defines the hypervisor's default huge pool size in bytes"
SKIP_VALIDATION
)
bf_add_config(
CONFIG_NAME HYPERVISOR_PAGE_POOL_SIZE
CONFIG_TYPE STRING
DEFAULT_VAL "0x2000000"
DESCRIPTION "Defines the hypervisor's default page pool size in bytes"
SKIP_VALIDATION
OPTIONS ${HYPERVISOR_MK_PAGE_POOL_SIZE}
)

View file

@ -22,7 +22,7 @@
FetchContent_Declare(
bsl
GIT_REPOSITORY https://github.com/bareflank/bsl.git
GIT_TAG 92dff4d9e701b7ae18c9dbdfe579d9f6f2decbb2
GIT_TAG 5c3c948d44a0cdeb2477b42c1493d88e3268c40d
)
FetchContent_GetProperties(bsl)

View file

@ -27,7 +27,23 @@ include(${CMAKE_CURRENT_LIST_DIR}/../init_cross_compile_build.cmake)
add_subdirectory(../../loader loader)
add_subdirectory(../../runtime runtime)
add_subdirectory(../../syscall syscall)
add_subdirectory(../../kernel/integration integration)
if (DEFINED HYPERVISOR_EXTENSIONS_DIR OR NOT HYPERVISOR_BUILD_EXAMPLES_OVERRIDE)
if(DEFINED HYPERVISOR_EXTENSIONS_DIR)
add_subdirectory(${HYPERVISOR_EXTENSIONS_DIR} extension)
endif()
# get_filename_component(HYPERVISOR_EXTENSIONS_REALPATH
# "${HYPERVISOR_EXTENSIONS_DIR}" REALPATH BASE_DIR "${CMAKE_CURRENT_LIST_DIR}")
# get_filename_component(HYPERVISOR_DEFAULT_REALPATH
# "../../example/default" REALPATH BASE_DIR "${CMAKE_CURRENT_LIST_DIR}")
# get_filename_component(HYPERVISOR_NESTED_PAGING_REALPATH
# "../../example/nested_paging" REALPATH BASE_DIR "${CMAKE_CURRENT_LIST_DIR}")
# if(NOT HYPERVISOR_DEFAULT_REALPATH STREQUAL "${HYPERVISOR_EXTENSIONS_REALPATH}")
# add_subdirectory(../../example/default example_default)
# endif()
# if(NOT HYPERVISOR_NESTED_PAGING_REALPATH STREQUAL "${HYPERVISOR_EXTENSIONS_REALPATH}")
# add_subdirectory(../../example/nested_paging example_nested_paging)
# endif()

View file

@ -47,6 +47,17 @@ macro(hypervisor_add_cmake_args)
-DBSL_PAGE_SIZE=${BSL_PAGE_SIZE}
)
if(HYPERVISOR_TARGET_ARCH STREQUAL "AuthenticAMD" OR HYPERVISOR_TARGET_ARCH STREQUAL "GenuineIntel")
list(APPEND CMAKE_ARGS
-DHYPERVISOR_SERIAL_PORT=${HYPERVISOR_SERIAL_PORT}
)
else()
list(APPEND CMAKE_ARGS
-DHYPERVISOR_SERIAL_PORTH=${HYPERVISOR_SERIAL_PORTH}
-DHYPERVISOR_SERIAL_PORTL=${HYPERVISOR_SERIAL_PORTL}
)
endif()
list(APPEND CMAKE_ARGS
-DHYPERVISOR_EXTENSIONS=${HYPERVISOR_EXTENSIONS}
-DHYPERVISOR_EXTENSIONS_DIR=${HYPERVISOR_EXTENSIONS_DIR}
@ -56,24 +67,27 @@ macro(hypervisor_add_cmake_args)
-DHYPERVISOR_EFI_FS0=${HYPERVISOR_EFI_FS0}
-DHYPERVISOR_PAGE_SIZE=${HYPERVISOR_PAGE_SIZE}
-DHYPERVISOR_PAGE_SHIFT=${HYPERVISOR_PAGE_SHIFT}
-DHYPERVISOR_SERIAL_PORT=${HYPERVISOR_SERIAL_PORT}
-DHYPERVISOR_DEBUG_RING_SIZE=${HYPERVISOR_DEBUG_RING_SIZE}
-DHYPERVISOR_VMEXIT_LOG_SIZE=${HYPERVISOR_VMEXIT_LOG_SIZE}
-DHYPERVISOR_MAX_ELF_FILE_SIZE=${HYPERVISOR_MAX_ELF_FILE_SIZE}
-DHYPERVISOR_MAX_SEGMENTS=${HYPERVISOR_MAX_SEGMENTS}
-DHYPERVISOR_MAX_EXTENSIONS=${HYPERVISOR_MAX_EXTENSIONS}
-DHYPERVISOR_MAX_VMS=${HYPERVISOR_MAX_VMS}
-DHYPERVISOR_MAX_PPS=${HYPERVISOR_MAX_PPS}
-DHYPERVISOR_MAX_VPS=${HYPERVISOR_MAX_VPS}
-DHYPERVISOR_MAX_VPS_PER_VM=${HYPERVISOR_MAX_VPS_PER_VM}
-DHYPERVISOR_MAX_VPSS_PER_VP=${HYPERVISOR_MAX_VPSS_PER_VP}
-DHYPERVISOR_MAX_VPSS=${HYPERVISOR_MAX_VPSS}
-DHYPERVISOR_DEBUG_RING_SIZE=${HYPERVISOR_DEBUG_RING_SIZE}
-DHYPERVISOR_DIRECT_MAP_ADDR=${HYPERVISOR_DIRECT_MAP_ADDR}
-DHYPERVISOR_MK_DIRECT_MAP_ADDR=${HYPERVISOR_MK_DIRECT_MAP_ADDR}
-DHYPERVISOR_MK_DIRECT_MAP_SIZE=${HYPERVISOR_MK_DIRECT_MAP_SIZE}
-DHYPERVISOR_MK_STACK_ADDR=${HYPERVISOR_MK_STACK_ADDR}
-DHYPERVISOR_MK_STACK_SIZE=${HYPERVISOR_MK_STACK_SIZE}
-DHYPERVISOR_MK_CODE_ADDR=${HYPERVISOR_MK_CODE_ADDR}
-DHYPERVISOR_MK_CODE_SIZE=${HYPERVISOR_MK_CODE_SIZE}
-DHYPERVISOR_MK_MAP_ADDR=${HYPERVISOR_MK_MAP_ADDR}
-DHYPERVISOR_MK_MAP_SIZE=${HYPERVISOR_MK_MAP_SIZE}
-DHYPERVISOR_MK_PAGE_POOL_ADDR=${HYPERVISOR_MK_PAGE_POOL_ADDR}
-DHYPERVISOR_MK_PAGE_POOL_SIZE=${HYPERVISOR_MK_PAGE_POOL_SIZE}
-DHYPERVISOR_MK_HUGE_POOL_ADDR=${HYPERVISOR_MK_HUGE_POOL_ADDR}
-DHYPERVISOR_MK_HUGE_POOL_SIZE=${HYPERVISOR_MK_HUGE_POOL_SIZE}
-DHYPERVISOR_EXT_DIRECT_MAP_ADDR=${HYPERVISOR_EXT_DIRECT_MAP_ADDR}
-DHYPERVISOR_EXT_DIRECT_MAP_SIZE=${HYPERVISOR_EXT_DIRECT_MAP_SIZE}
-DHYPERVISOR_EXT_STACK_ADDR=${HYPERVISOR_EXT_STACK_ADDR}
-DHYPERVISOR_EXT_STACK_SIZE=${HYPERVISOR_EXT_STACK_SIZE}
-DHYPERVISOR_EXT_CODE_ADDR=${HYPERVISOR_EXT_CODE_ADDR}
@ -82,9 +96,9 @@ macro(hypervisor_add_cmake_args)
-DHYPERVISOR_EXT_TLS_SIZE=${HYPERVISOR_EXT_TLS_SIZE}
-DHYPERVISOR_EXT_PAGE_POOL_ADDR=${HYPERVISOR_EXT_PAGE_POOL_ADDR}
-DHYPERVISOR_EXT_PAGE_POOL_SIZE=${HYPERVISOR_EXT_PAGE_POOL_SIZE}
-DHYPERVISOR_EXT_HUGE_POOL_ADDR=${HYPERVISOR_EXT_HUGE_POOL_ADDR}
-DHYPERVISOR_EXT_HUGE_POOL_SIZE=${HYPERVISOR_EXT_HUGE_POOL_SIZE}
-DHYPERVISOR_EXT_HEAP_POOL_ADDR=${HYPERVISOR_EXT_HEAP_POOL_ADDR}
-DHYPERVISOR_EXT_HEAP_POOL_SIZE=${HYPERVISOR_EXT_HEAP_POOL_SIZE}
-DHYPERVISOR_HUGE_POOL_SIZE=${HYPERVISOR_HUGE_POOL_SIZE}
-DHYPERVISOR_PAGE_POOL_SIZE=${HYPERVISOR_PAGE_POOL_SIZE}
)
endmacro(hypervisor_add_cmake_args)

View file

@ -38,9 +38,11 @@ function(hypervisor_add_efi_cross_compile SOURCE_DIR)
endif()
if(HYPERVISOR_TARGET_ARCH STREQUAL "GenuineIntel")
set(CMAKE_TOOLCHAIN_FILE ${CMAKE_CURRENT_LIST_DIR}/cmake/toolchain/x64/efi.cmake)
set(CMAKE_TOOLCHAIN_FILE ${CMAKE_CURRENT_LIST_DIR}/../cmake/toolchain/x64/efi.cmake)
elseif(HYPERVISOR_TARGET_ARCH STREQUAL "AuthenticAMD")
set(CMAKE_TOOLCHAIN_FILE ${CMAKE_CURRENT_LIST_DIR}/cmake/toolchain/x64/efi.cmake)
set(CMAKE_TOOLCHAIN_FILE ${CMAKE_CURRENT_LIST_DIR}/../cmake/toolchain/x64/efi.cmake)
elseif(HYPERVISOR_TARGET_ARCH STREQUAL "aarch64")
set(CMAKE_TOOLCHAIN_FILE ${CMAKE_CURRENT_LIST_DIR}/../cmake/toolchain/aarch64/efi.cmake)
else()
message(FATAL_ERROR "Unsupported HYPERVISOR_TARGET_ARCH: ${HYPERVISOR_TARGET_ARCH}")
endif()

View file

@ -41,6 +41,8 @@ function(hypervisor_add_ext_cross_compile SOURCE_DIR)
set(CMAKE_TOOLCHAIN_FILE ${CMAKE_CURRENT_LIST_DIR}/cmake/toolchain/x64/ext.cmake)
elseif(HYPERVISOR_TARGET_ARCH STREQUAL "AuthenticAMD")
set(CMAKE_TOOLCHAIN_FILE ${CMAKE_CURRENT_LIST_DIR}/cmake/toolchain/x64/ext.cmake)
elseif(HYPERVISOR_TARGET_ARCH STREQUAL "aarch64")
set(CMAKE_TOOLCHAIN_FILE ${CMAKE_CURRENT_LIST_DIR}/cmake/toolchain/aarch64/ext.cmake)
else()
message(FATAL_ERROR "Unsupported HYPERVISOR_TARGET_ARCH: ${HYPERVISOR_TARGET_ARCH}")
endif()

View file

@ -90,18 +90,6 @@ macro(hypervisor_add_info)
)
endif()
if(HYPERVISOR_BUILD_EXAMPLES)
add_custom_command(TARGET info
COMMAND ${CMAKE_COMMAND} -E echo "${BF_COLOR_YLW} HYPERVISOR_BUILD_EXAMPLES ${BF_COLOR_GRN}enabled${BF_COLOR_RST}"
VERBATIM
)
else()
add_custom_command(TARGET info
COMMAND ${CMAKE_COMMAND} -E echo "${BF_COLOR_YLW} HYPERVISOR_BUILD_EXAMPLES ${BF_COLOR_RED}disabled${BF_COLOR_RST}"
VERBATIM
)
endif()
if(HYPERVISOR_BUILD_EFI)
add_custom_command(TARGET info
COMMAND ${CMAKE_COMMAND} -E echo "${BF_COLOR_YLW} HYPERVISOR_BUILD_EFI ${BF_COLOR_GRN}enabled${BF_COLOR_RST}"
@ -144,8 +132,29 @@ macro(hypervisor_add_info)
VERBATIM
)
if(HYPERVISOR_TARGET_ARCH STREQUAL "AuthenticAMD" OR HYPERVISOR_TARGET_ARCH STREQUAL "GenuineIntel")
add_custom_command(TARGET info
COMMAND ${CMAKE_COMMAND} -E echo "${BF_COLOR_YLW} HYPERVISOR_SERIAL_PORT ${BF_COLOR_CYN}${HYPERVISOR_SERIAL_PORT}${BF_COLOR_RST}"
VERBATIM
)
else()
add_custom_command(TARGET info
COMMAND ${CMAKE_COMMAND} -E echo "${BF_COLOR_YLW} HYPERVISOR_SERIAL_PORTH ${BF_COLOR_CYN}${HYPERVISOR_SERIAL_PORTH}${BF_COLOR_RST}"
VERBATIM
)
add_custom_command(TARGET info
COMMAND ${CMAKE_COMMAND} -E echo "${BF_COLOR_YLW} HYPERVISOR_SERIAL_PORTL ${BF_COLOR_CYN}${HYPERVISOR_SERIAL_PORTL}${BF_COLOR_RST}"
VERBATIM
)
endif()
add_custom_command(TARGET info
COMMAND ${CMAKE_COMMAND} -E echo "${BF_COLOR_YLW} HYPERVISOR_SERIAL_PORT ${BF_COLOR_CYN}${HYPERVISOR_SERIAL_PORT}${BF_COLOR_RST}"
COMMAND ${CMAKE_COMMAND} -E echo "${BF_COLOR_YLW} HYPERVISOR_DEBUG_RING_SIZE ${BF_COLOR_CYN}${HYPERVISOR_DEBUG_RING_SIZE}${BF_COLOR_RST}"
VERBATIM
)
add_custom_command(TARGET info
COMMAND ${CMAKE_COMMAND} -E echo "${BF_COLOR_YLW} HYPERVISOR_VMEXIT_LOG_SIZE ${BF_COLOR_CYN}${HYPERVISOR_VMEXIT_LOG_SIZE}${BF_COLOR_RST}"
VERBATIM
)
@ -179,28 +188,18 @@ macro(hypervisor_add_info)
VERBATIM
)
add_custom_command(TARGET info
COMMAND ${CMAKE_COMMAND} -E echo "${BF_COLOR_YLW} HYPERVISOR_MAX_VPS_PER_VM ${BF_COLOR_CYN}${HYPERVISOR_MAX_VPS_PER_VM}${BF_COLOR_RST}"
VERBATIM
)
add_custom_command(TARGET info
COMMAND ${CMAKE_COMMAND} -E echo "${BF_COLOR_YLW} HYPERVISOR_MAX_VPSS_PER_VP ${BF_COLOR_CYN}${HYPERVISOR_MAX_VPSS_PER_VP}${BF_COLOR_RST}"
VERBATIM
)
add_custom_command(TARGET info
COMMAND ${CMAKE_COMMAND} -E echo "${BF_COLOR_YLW} HYPERVISOR_MAX_VPSS ${BF_COLOR_CYN}${HYPERVISOR_MAX_VPSS}${BF_COLOR_RST}"
VERBATIM
)
add_custom_command(TARGET info
COMMAND ${CMAKE_COMMAND} -E echo "${BF_COLOR_YLW} HYPERVISOR_DEBUG_RING_SIZE ${BF_COLOR_CYN}${HYPERVISOR_DEBUG_RING_SIZE}${BF_COLOR_RST}"
COMMAND ${CMAKE_COMMAND} -E echo "${BF_COLOR_YLW} HYPERVISOR_MK_DIRECT_MAP_ADDR ${BF_COLOR_CYN}${HYPERVISOR_MK_DIRECT_MAP_ADDR}${BF_COLOR_RST}"
VERBATIM
)
add_custom_command(TARGET info
COMMAND ${CMAKE_COMMAND} -E echo "${BF_COLOR_YLW} HYPERVISOR_DIRECT_MAP_ADDR ${BF_COLOR_CYN}${HYPERVISOR_DIRECT_MAP_ADDR}${BF_COLOR_RST}"
COMMAND ${CMAKE_COMMAND} -E echo "${BF_COLOR_YLW} HYPERVISOR_MK_DIRECT_MAP_SIZE ${BF_COLOR_CYN}${HYPERVISOR_MK_DIRECT_MAP_SIZE}${BF_COLOR_RST}"
VERBATIM
)
@ -225,12 +224,32 @@ macro(hypervisor_add_info)
)
add_custom_command(TARGET info
COMMAND ${CMAKE_COMMAND} -E echo "${BF_COLOR_YLW} HYPERVISOR_MK_MAP_ADDR ${BF_COLOR_CYN}${HYPERVISOR_MK_MAP_ADDR}${BF_COLOR_RST}"
COMMAND ${CMAKE_COMMAND} -E echo "${BF_COLOR_YLW} HYPERVISOR_MK_PAGE_POOL_ADDR ${BF_COLOR_CYN}${HYPERVISOR_MK_PAGE_POOL_ADDR}${BF_COLOR_RST}"
VERBATIM
)
add_custom_command(TARGET info
COMMAND ${CMAKE_COMMAND} -E echo "${BF_COLOR_YLW} HYPERVISOR_MK_MAP_SIZE ${BF_COLOR_CYN}${HYPERVISOR_MK_MAP_SIZE}${BF_COLOR_RST}"
COMMAND ${CMAKE_COMMAND} -E echo "${BF_COLOR_YLW} HYPERVISOR_MK_PAGE_POOL_SIZE ${BF_COLOR_CYN}${HYPERVISOR_MK_PAGE_POOL_SIZE}${BF_COLOR_RST}"
VERBATIM
)
add_custom_command(TARGET info
COMMAND ${CMAKE_COMMAND} -E echo "${BF_COLOR_YLW} HYPERVISOR_MK_HUGE_POOL_ADDR ${BF_COLOR_CYN}${HYPERVISOR_MK_HUGE_POOL_ADDR}${BF_COLOR_RST}"
VERBATIM
)
add_custom_command(TARGET info
COMMAND ${CMAKE_COMMAND} -E echo "${BF_COLOR_YLW} HYPERVISOR_MK_HUGE_POOL_SIZE ${BF_COLOR_CYN}${HYPERVISOR_MK_HUGE_POOL_SIZE}${BF_COLOR_RST}"
VERBATIM
)
add_custom_command(TARGET info
COMMAND ${CMAKE_COMMAND} -E echo "${BF_COLOR_YLW} HYPERVISOR_EXT_DIRECT_MAP_ADDR ${BF_COLOR_CYN}${HYPERVISOR_EXT_DIRECT_MAP_ADDR}${BF_COLOR_RST}"
VERBATIM
)
add_custom_command(TARGET info
COMMAND ${CMAKE_COMMAND} -E echo "${BF_COLOR_YLW} HYPERVISOR_EXT_DIRECT_MAP_SIZE ${BF_COLOR_CYN}${HYPERVISOR_EXT_DIRECT_MAP_SIZE}${BF_COLOR_RST}"
VERBATIM
)
@ -274,6 +293,16 @@ macro(hypervisor_add_info)
VERBATIM
)
add_custom_command(TARGET info
COMMAND ${CMAKE_COMMAND} -E echo "${BF_COLOR_YLW} HYPERVISOR_EXT_HUGE_POOL_ADDR ${BF_COLOR_CYN}${HYPERVISOR_EXT_HUGE_POOL_ADDR}${BF_COLOR_RST}"
VERBATIM
)
add_custom_command(TARGET info
COMMAND ${CMAKE_COMMAND} -E echo "${BF_COLOR_YLW} HYPERVISOR_EXT_HUGE_POOL_SIZE ${BF_COLOR_CYN}${HYPERVISOR_EXT_HUGE_POOL_SIZE}${BF_COLOR_RST}"
VERBATIM
)
add_custom_command(TARGET info
COMMAND ${CMAKE_COMMAND} -E echo "${BF_COLOR_YLW} HYPERVISOR_EXT_HEAP_POOL_ADDR ${BF_COLOR_CYN}${HYPERVISOR_EXT_HEAP_POOL_ADDR}${BF_COLOR_RST}"
VERBATIM
@ -284,16 +313,6 @@ macro(hypervisor_add_info)
VERBATIM
)
add_custom_command(TARGET info
COMMAND ${CMAKE_COMMAND} -E echo "${BF_COLOR_YLW} HYPERVISOR_HUGE_POOL_SIZE ${BF_COLOR_CYN}${HYPERVISOR_HUGE_POOL_SIZE}${BF_COLOR_RST}"
VERBATIM
)
add_custom_command(TARGET info
COMMAND ${CMAKE_COMMAND} -E echo "${BF_COLOR_YLW} HYPERVISOR_PAGE_POOL_SIZE ${BF_COLOR_CYN}${HYPERVISOR_PAGE_POOL_SIZE}${BF_COLOR_RST}"
VERBATIM
)
add_custom_command(TARGET info
COMMAND ${CMAKE_COMMAND} -E echo " "
VERBATIM

View file

@ -0,0 +1,69 @@
#
# 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's An Integration Test Target
#
macro(hypervisor_add_integration NAME HEADERS)
add_executable(integration_${NAME})
target_include_directories(integration_${NAME} PRIVATE
support
)
if(HYPERVISOR_TARGET_ARCH STREQUAL "AuthenticAMD")
target_include_directories(integration_${NAME} PRIVATE
support/x64
support/x64/amd
)
endif()
if(HYPERVISOR_TARGET_ARCH STREQUAL "GenuineIntel")
target_include_directories(integration_${NAME} PRIVATE
support/x64
support/x64/intel
)
endif()
if(HYPERVISOR_TARGET_ARCH STREQUAL "aarch64")
target_include_directories(integration_${NAME} PRIVATE
support/arm/aarch64
)
endif()
target_sources(integration_${NAME} PRIVATE
${NAME}.cpp
)
set_property(SOURCE ${NAME} APPEND PROPERTY OBJECT_DEPENDS ${${HEADERS}})
target_link_libraries(integration_${NAME} PRIVATE
runtime
bsl
loader
syscall
)
if(CMAKE_BUILD_TYPE STREQUAL RELEASE OR CMAKE_BUILD_TYPE STREQUAL MINSIZEREL)
add_custom_command(TARGET integration_${NAME} POST_BUILD COMMAND ${CMAKE_STRIP} integration_${NAME})
endif()
install(TARGETS integration_${NAME} DESTINATION bin)
endmacro(hypervisor_add_integration)

View file

@ -0,0 +1,59 @@
#
# 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(integration)
# Add's An Integration Test Target
#
macro(hypervisor_add_integration_target NAME)
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
add_custom_target(integration_${NAME}
COMMAND sync
COMMAND sudo vmmctl/vmmctl start ${CMAKE_BINARY_DIR}/mk_cross_compile/bin/kernel ${CMAKE_BINARY_DIR}/ext_cross_compile/bin/integration_${NAME} | true
COMMAND sudo vmmctl/vmmctl dump
VERBATIM
)
add_custom_target(${NAME}
COMMAND sync
COMMAND sudo vmmctl/vmmctl start ${CMAKE_BINARY_DIR}/mk_cross_compile/bin/kernel ${CMAKE_BINARY_DIR}/ext_cross_compile/bin/integration_${NAME} | true
COMMAND sudo vmmctl/vmmctl dump
VERBATIM
)
elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows")
add_custom_target(integration_${NAME}
COMMAND vmmctl/vmmctl start ${CMAKE_BINARY_DIR}/mk_cross_compile/bin/kernel ${CMAKE_BINARY_DIR}/ext_cross_compile/bin/integration_${NAME} | true
COMMAND vmmctl/vmmctl dump
VERBATIM
)
add_custom_target(${NAME}
COMMAND vmmctl/vmmctl start ${CMAKE_BINARY_DIR}/mk_cross_compile/bin/kernel ${CMAKE_BINARY_DIR}/ext_cross_compile/bin/integration_${NAME} | true
COMMAND vmmctl/vmmctl dump
VERBATIM
)
else()
message(FATAL_ERROR "Unsupported CMAKE_SYSTEM_NAME: ${CMAKE_SYSTEM_NAME}")
endif()
add_custom_command(TARGET integration
COMMAND ${CMAKE_COMMAND} --build . --target integration_${NAME}
VERBATIM
)
endmacro(hypervisor_add_integration_target)

View file

@ -41,6 +41,8 @@ function(hypervisor_add_mk_cross_compile SOURCE_DIR)
set(CMAKE_TOOLCHAIN_FILE ${CMAKE_CURRENT_LIST_DIR}/cmake/toolchain/x64/mk.cmake)
elseif(HYPERVISOR_TARGET_ARCH STREQUAL "AuthenticAMD")
set(CMAKE_TOOLCHAIN_FILE ${CMAKE_CURRENT_LIST_DIR}/cmake/toolchain/x64/mk.cmake)
elseif(HYPERVISOR_TARGET_ARCH STREQUAL "aarch64")
set(CMAKE_TOOLCHAIN_FILE ${CMAKE_CURRENT_LIST_DIR}/cmake/toolchain/aarch64/mk.cmake)
else()
message(FATAL_ERROR "Unsupported HYPERVISOR_TARGET_ARCH: ${HYPERVISOR_TARGET_ARCH}")
endif()

View file

@ -0,0 +1,29 @@
#
# 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.
# Adds a source file to a target, and ensures that dependencies are being
# tracked to deal with a bug with Ninja on Windows where changes to header
# files are not tracked properly.
#
macro(hypervisor_target_source NAME SOURCE_FILE)
target_sources(${NAME} PRIVATE ${SOURCE_FILE})
set_property(SOURCE ${SOURCE_FILE} APPEND PROPERTY OBJECT_DEPENDS ${ARGN})
endmacro(hypervisor_target_source)

View file

@ -28,7 +28,15 @@ include(${bsl_SOURCE_DIR}/cmake/build_types.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/silence.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/write_constants.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/write_toolchain_x64_ext_ld.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/write_toolchain_x64_mk_ld.cmake)
if(HYPERVISOR_TARGET_ARCH STREQUAL "AuthenticAMD" OR HYPERVISOR_TARGET_ARCH STREQUAL "GenuineIntel")
include(${CMAKE_CURRENT_LIST_DIR}/write_toolchain_x64_ext_ld.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/write_toolchain_x64_mk_ld.cmake)
endif()
if(HYPERVISOR_TARGET_ARCH STREQUAL "aarch64")
include(${CMAKE_CURRENT_LIST_DIR}/write_toolchain_aarch64_ext_ld.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/write_toolchain_aarch64_mk_ld.cmake)
endif()
include(${CMAKE_CURRENT_LIST_DIR}/interface/hypervisor.cmake)

View file

@ -21,37 +21,51 @@
add_library(hypervisor INTERFACE)
if(HYPERVISOR_TARGET_ARCH STREQUAL "AuthenticAMD" OR HYPERVISOR_TARGET_ARCH STREQUAL "GenuineIntel")
target_compile_definitions(hypervisor INTERFACE
HYPERVISOR_SERIAL_PORT=${HYPERVISOR_SERIAL_PORT}
)
else()
target_compile_definitions(hypervisor INTERFACE
HYPERVISOR_SERIAL_PORTH=${HYPERVISOR_SERIAL_PORTH}
HYPERVISOR_SERIAL_PORTL=${HYPERVISOR_SERIAL_PORTL}
)
endif()
target_compile_definitions(hypervisor INTERFACE
HYPERVISOR_PAGE_SIZE=${HYPERVISOR_PAGE_SIZE}
HYPERVISOR_PAGE_SHIFT=${HYPERVISOR_PAGE_SHIFT}
HYPERVISOR_SERIAL_PORT=${HYPERVISOR_SERIAL_PORT}
HYPERVISOR_MAX_ELF_FILE_SIZE=${HYPERVISOR_MAX_ELF_FILE_SIZE}
HYPERVISOR_MAX_SEGMENTS=${HYPERVISOR_MAX_SEGMENTS}
HYPERVISOR_MAX_EXTENSIONS=${HYPERVISOR_MAX_EXTENSIONS}
HYPERVISOR_MAX_VMS=${HYPERVISOR_MAX_VMS}
HYPERVISOR_MAX_PPS=${HYPERVISOR_MAX_PPS}
HYPERVISOR_MAX_VPS=${HYPERVISOR_MAX_VPS}
HYPERVISOR_MAX_VPS_PER_VM=${HYPERVISOR_MAX_VPS_PER_VM}
HYPERVISOR_MAX_VPSS_PER_VP=${HYPERVISOR_MAX_VPSS_PER_VP}
HYPERVISOR_MAX_VPSS=${HYPERVISOR_MAX_VPSS}
HYPERVISOR_DEBUG_RING_SIZE=${HYPERVISOR_DEBUG_RING_SIZE}
HYPERVISOR_DIRECT_MAP_ADDR=${HYPERVISOR_DIRECT_MAP_ADDR}
HYPERVISOR_MK_STACK_ADDR=${HYPERVISOR_MK_STACK_ADDR}
HYPERVISOR_MK_STACK_SIZE=${HYPERVISOR_MK_STACK_SIZE}
HYPERVISOR_MK_CODE_ADDR=${HYPERVISOR_MK_CODE_ADDR}
HYPERVISOR_MK_CODE_SIZE=${HYPERVISOR_MK_CODE_SIZE}
HYPERVISOR_MK_MAP_ADDR=${HYPERVISOR_MK_MAP_ADDR}
HYPERVISOR_MK_MAP_SIZE=${HYPERVISOR_MK_MAP_SIZE}
HYPERVISOR_EXT_STACK_ADDR=${HYPERVISOR_EXT_STACK_ADDR}
HYPERVISOR_EXT_STACK_SIZE=${HYPERVISOR_EXT_STACK_SIZE}
HYPERVISOR_EXT_CODE_ADDR=${HYPERVISOR_EXT_CODE_ADDR}
HYPERVISOR_EXT_CODE_SIZE=${HYPERVISOR_EXT_CODE_SIZE}
HYPERVISOR_EXT_TLS_ADDR=${HYPERVISOR_EXT_TLS_ADDR}
HYPERVISOR_EXT_TLS_SIZE=${HYPERVISOR_EXT_TLS_SIZE}
HYPERVISOR_EXT_PAGE_POOL_ADDR=${HYPERVISOR_EXT_PAGE_POOL_ADDR}
HYPERVISOR_EXT_PAGE_POOL_SIZE=${HYPERVISOR_EXT_PAGE_POOL_SIZE}
HYPERVISOR_EXT_HEAP_POOL_ADDR=${HYPERVISOR_EXT_HEAP_POOL_ADDR}
HYPERVISOR_EXT_HEAP_POOL_SIZE=${HYPERVISOR_EXT_HEAP_POOL_SIZE}
HYPERVISOR_HUGE_POOL_SIZE=${HYPERVISOR_HUGE_POOL_SIZE}
HYPERVISOR_PAGE_POOL_SIZE=${HYPERVISOR_PAGE_POOL_SIZE}
HYPERVISOR_PAGE_SIZE=${HYPERVISOR_PAGE_SIZE}_umax
HYPERVISOR_PAGE_SHIFT=${HYPERVISOR_PAGE_SHIFT}_umax
HYPERVISOR_DEBUG_RING_SIZE=${HYPERVISOR_DEBUG_RING_SIZE}_umax
HYPERVISOR_VMEXIT_LOG_SIZE=${HYPERVISOR_VMEXIT_LOG_SIZE}_umax
HYPERVISOR_MAX_ELF_FILE_SIZE=${HYPERVISOR_MAX_ELF_FILE_SIZE}_umax
HYPERVISOR_MAX_SEGMENTS=${HYPERVISOR_MAX_SEGMENTS}_umax
HYPERVISOR_MAX_EXTENSIONS=${HYPERVISOR_MAX_EXTENSIONS}_umax
HYPERVISOR_MAX_VMS=${HYPERVISOR_MAX_VMS}_umax
HYPERVISOR_MAX_PPS=${HYPERVISOR_MAX_PPS}_umax
HYPERVISOR_MAX_VPS=${HYPERVISOR_MAX_VPS}_umax
HYPERVISOR_MAX_VPSS=${HYPERVISOR_MAX_VPSS}_umax
HYPERVISOR_MK_DIRECT_MAP_ADDR=${HYPERVISOR_MK_DIRECT_MAP_ADDR}_umax
HYPERVISOR_MK_DIRECT_MAP_SIZE=${HYPERVISOR_MK_DIRECT_MAP_SIZE}_umax
HYPERVISOR_MK_STACK_ADDR=${HYPERVISOR_MK_STACK_ADDR}_umax
HYPERVISOR_MK_STACK_SIZE=${HYPERVISOR_MK_STACK_SIZE}_umax
HYPERVISOR_MK_CODE_ADDR=${HYPERVISOR_MK_CODE_ADDR}_umax
HYPERVISOR_MK_CODE_SIZE=${HYPERVISOR_MK_CODE_SIZE}_umax
HYPERVISOR_MK_PAGE_POOL_ADDR=${HYPERVISOR_MK_PAGE_POOL_ADDR}_umax
HYPERVISOR_MK_PAGE_POOL_SIZE=${HYPERVISOR_MK_PAGE_POOL_SIZE}_umax
HYPERVISOR_MK_HUGE_POOL_ADDR=${HYPERVISOR_MK_HUGE_POOL_ADDR}_umax
HYPERVISOR_MK_HUGE_POOL_SIZE=${HYPERVISOR_MK_HUGE_POOL_SIZE}_umax
HYPERVISOR_EXT_DIRECT_MAP_ADDR=${HYPERVISOR_EXT_DIRECT_MAP_ADDR}_umax
HYPERVISOR_EXT_DIRECT_MAP_SIZE=${HYPERVISOR_EXT_DIRECT_MAP_SIZE}_umax
HYPERVISOR_EXT_STACK_ADDR=${HYPERVISOR_EXT_STACK_ADDR}_umax
HYPERVISOR_EXT_STACK_SIZE=${HYPERVISOR_EXT_STACK_SIZE}_umax
HYPERVISOR_EXT_CODE_ADDR=${HYPERVISOR_EXT_CODE_ADDR}_umax
HYPERVISOR_EXT_CODE_SIZE=${HYPERVISOR_EXT_CODE_SIZE}_umax
HYPERVISOR_EXT_TLS_ADDR=${HYPERVISOR_EXT_TLS_ADDR}_umax
HYPERVISOR_EXT_TLS_SIZE=${HYPERVISOR_EXT_TLS_SIZE}_umax
HYPERVISOR_EXT_PAGE_POOL_ADDR=${HYPERVISOR_EXT_PAGE_POOL_ADDR}_umax
HYPERVISOR_EXT_PAGE_POOL_SIZE=${HYPERVISOR_EXT_PAGE_POOL_SIZE}_umax
HYPERVISOR_EXT_HUGE_POOL_ADDR=${HYPERVISOR_EXT_HUGE_POOL_ADDR}_umax
HYPERVISOR_EXT_HUGE_POOL_SIZE=${HYPERVISOR_EXT_HUGE_POOL_SIZE}_umax
HYPERVISOR_EXT_HEAP_POOL_ADDR=${HYPERVISOR_EXT_HEAP_POOL_ADDR}_umax
HYPERVISOR_EXT_HEAP_POOL_SIZE=${HYPERVISOR_EXT_HEAP_POOL_SIZE}_umax
)

View file

@ -48,24 +48,35 @@ hypervisor_silence(HYPERVISOR_EFI_LINKER)
hypervisor_silence(HYPERVISOR_EFI_FS0)
hypervisor_silence(HYPERVISOR_PAGE_SIZE)
hypervisor_silence(HYPERVISOR_PAGE_SHIFT)
hypervisor_silence(HYPERVISOR_SERIAL_PORT)
if(HYPERVISOR_TARGET_ARCH STREQUAL "AuthenticAMD" OR HYPERVISOR_TARGET_ARCH STREQUAL "GenuineIntel")
hypervisor_silence(HYPERVISOR_SERIAL_PORT)
else()
hypervisor_silence(HYPERVISOR_SERIAL_PORTH)
hypervisor_silence(HYPERVISOR_SERIAL_PORTL)
endif()
hypervisor_silence(HYPERVISOR_DEBUG_RING_SIZE)
hypervisor_silence(HYPERVISOR_VMEXIT_LOG_SIZE)
hypervisor_silence(HYPERVISOR_MAX_ELF_FILE_SIZE)
hypervisor_silence(HYPERVISOR_MAX_SEGMENTS)
hypervisor_silence(HYPERVISOR_MAX_EXTENSIONS)
hypervisor_silence(HYPERVISOR_MAX_VMS)
hypervisor_silence(HYPERVISOR_MAX_PPS)
hypervisor_silence(HYPERVISOR_MAX_VPS)
hypervisor_silence(HYPERVISOR_MAX_VPS_PER_VM)
hypervisor_silence(HYPERVISOR_MAX_VPSS_PER_VP)
hypervisor_silence(HYPERVISOR_MAX_VPSS)
hypervisor_silence(HYPERVISOR_DEBUG_RING_SIZE)
hypervisor_silence(HYPERVISOR_DIRECT_MAP_ADDR)
hypervisor_silence(HYPERVISOR_MK_DIRECT_MAP_ADDR)
hypervisor_silence(HYPERVISOR_MK_DIRECT_MAP_SIZE)
hypervisor_silence(HYPERVISOR_MK_STACK_ADDR)
hypervisor_silence(HYPERVISOR_MK_STACK_SIZE)
hypervisor_silence(HYPERVISOR_MK_CODE_ADDR)
hypervisor_silence(HYPERVISOR_MK_CODE_SIZE)
hypervisor_silence(HYPERVISOR_MK_MAP_ADDR)
hypervisor_silence(HYPERVISOR_MK_MAP_SIZE)
hypervisor_silence(HYPERVISOR_MK_PAGE_POOL_ADDR)
hypervisor_silence(HYPERVISOR_MK_PAGE_POOL_SIZE)
hypervisor_silence(HYPERVISOR_MK_HUGE_POOL_ADDR)
hypervisor_silence(HYPERVISOR_MK_HUGE_POOL_SIZE)
hypervisor_silence(HYPERVISOR_EXT_DIRECT_MAP_ADDR)
hypervisor_silence(HYPERVISOR_EXT_DIRECT_MAP_SIZE)
hypervisor_silence(HYPERVISOR_EXT_STACK_ADDR)
hypervisor_silence(HYPERVISOR_EXT_STACK_SIZE)
hypervisor_silence(HYPERVISOR_EXT_CODE_ADDR)
@ -74,7 +85,7 @@ hypervisor_silence(HYPERVISOR_EXT_TLS_ADDR)
hypervisor_silence(HYPERVISOR_EXT_TLS_SIZE)
hypervisor_silence(HYPERVISOR_EXT_PAGE_POOL_ADDR)
hypervisor_silence(HYPERVISOR_EXT_PAGE_POOL_SIZE)
hypervisor_silence(HYPERVISOR_EXT_HUGE_POOL_ADDR)
hypervisor_silence(HYPERVISOR_EXT_HUGE_POOL_SIZE)
hypervisor_silence(HYPERVISOR_EXT_HEAP_POOL_ADDR)
hypervisor_silence(HYPERVISOR_EXT_HEAP_POOL_SIZE)
hypervisor_silence(HYPERVISOR_HUGE_POOL_SIZE)
hypervisor_silence(HYPERVISOR_PAGE_POOL_SIZE)

View file

@ -19,7 +19,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
if(HYPERVISOR_BUILD_VMMCTL)
if(HYPERVISOR_BUILD_VMMCTL AND NOT HYPERVISOR_TARGET_ARCH STREQUAL "aarch64")
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
add_custom_target(dump
COMMAND sudo vmmctl/vmmctl dump

View file

@ -19,7 +19,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
if(HYPERVISOR_BUILD_LOADER)
if(HYPERVISOR_BUILD_LOADER AND NOT HYPERVISOR_TARGET_ARCH STREQUAL "aarch64")
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
add_custom_target(loader_build
COMMAND ${CMAKE_COMMAND} -E chdir ${CMAKE_CURRENT_LIST_DIR}/../../loader/linux make CMAKE_BINARY_DIR='${CMAKE_BINARY_DIR}'

View file

@ -19,7 +19,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
if(HYPERVISOR_BUILD_LOADER)
if(HYPERVISOR_BUILD_LOADER AND NOT HYPERVISOR_TARGET_ARCH STREQUAL "aarch64")
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
add_custom_target(loader_clean
COMMAND ${CMAKE_COMMAND} --build . --target loader_unload

View file

@ -19,7 +19,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
if(HYPERVISOR_BUILD_LOADER)
if(HYPERVISOR_BUILD_LOADER AND NOT HYPERVISOR_TARGET_ARCH STREQUAL "aarch64")
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
add_custom_target(loader_load
COMMAND ${CMAKE_COMMAND} --build . --target loader_build

View file

@ -19,7 +19,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
if(HYPERVISOR_BUILD_LOADER)
if(HYPERVISOR_BUILD_LOADER AND NOT HYPERVISOR_TARGET_ARCH STREQUAL "aarch64")
add_custom_target(loader_quick
COMMAND ${CMAKE_COMMAND} --build . --target loader_clean
COMMAND ${CMAKE_COMMAND} --build . --target loader_load

View file

@ -19,7 +19,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
if(HYPERVISOR_BUILD_LOADER)
if(HYPERVISOR_BUILD_LOADER AND NOT HYPERVISOR_TARGET_ARCH STREQUAL "aarch64")
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
add_custom_target(loader_unload
COMMAND sync

View file

@ -19,7 +19,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
if(HYPERVISOR_BUILD_VMMCTL)
if(HYPERVISOR_BUILD_VMMCTL AND NOT HYPERVISOR_TARGET_ARCH STREQUAL "aarch64")
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
add_custom_target(start
COMMAND sync

View file

@ -19,7 +19,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
if(HYPERVISOR_BUILD_VMMCTL)
if(HYPERVISOR_BUILD_VMMCTL AND NOT HYPERVISOR_TARGET_ARCH STREQUAL "aarch64")
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
add_custom_target(stop
COMMAND sync

View file

@ -0,0 +1,69 @@
#
# 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.
set(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_C_COMPILER_WORKS 1)
string(CONCAT HYPERVISOR_EFI_C_FLAGS
"--target=aarch64-unknown-windows "
"-ffreestanding "
"-fshort-wchar "
"-mno-implicit-float "
)
string(CONCAT HYPERVISOR_EFI_LINK_FLAGS
"--target=aarch64-unknown-windows "
"-nostdlib "
"-Wl,-entry:efi_main "
"-Wl,-subsystem:efi_application "
"-fuse-ld=${HYPERVISOR_EFI_LINKER}"
)
set(CMAKE_ASM_COMPILE_OBJECT
"<CMAKE_C_COMPILER> ${HYPERVISOR_EFI_C_FLAGS} <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT> -c <SOURCE>")
set(CMAKE_C_COMPILE_OBJECT
"<CMAKE_C_COMPILER> ${HYPERVISOR_EFI_C_FLAGS} <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT> -c <SOURCE>")
set(CMAKE_C_LINK_EXECUTABLE
"<CMAKE_C_COMPILER> ${HYPERVISOR_EFI_LINK_FLAGS} <CMAKE_C_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>"
)
################################################################################
# Hack For Windows
################################################################################
# For some reason, CMake on Windows is adding extra stuff to the compiler
# includes and flags. The following fixes this issue by telling CMake not
# to configure the compiler. We need to add C++20 to the command above
# to make this work.
# https://gitlab.kitware.com/cmake/cmake/-/issues/21789
set(__COMPILER_CLANG 1)
macro(__compiler_clang lang)
endmacro()
macro(__compiler_clang_C_standards lang)
endmacro()
macro(__compiler_check_default_language_standard lang)
endmacro()

View file

@ -0,0 +1,76 @@
#
# 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.
set(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_CXX_COMPILER_WORKS 1)
string(CONCAT HYPERVISOR_EXT_CXX_FLAGS
"--target=aarch64-elf "
"-ffreestanding "
"-mno-implicit-float "
"-mcmodel=large "
"-std=c++20 "
)
if(CMAKE_BUILD_TYPE STREQUAL RELEASE OR CMAKE_BUILD_TYPE STREQUAL MINSIZEREL)
string(CONCAT HYPERVISOR_EXT_CXX_FLAGS
${HYPERVISOR_EXT_CXX_FLAGS}
"-flto "
)
endif()
string(CONCAT HYPERVISOR_EXT_LINK_FLAGS
"-static "
"-nostdlib "
"-z noexecstack "
"-T ${CMAKE_BINARY_DIR}/toolchain/arm/aarch64/ext.ld "
)
set(CMAKE_ASM_COMPILE_OBJECT
"<CMAKE_CXX_COMPILER> ${HYPERVISOR_EXT_CXX_FLAGS} <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT> -c <SOURCE>")
set(CMAKE_CXX_COMPILE_OBJECT
"<CMAKE_CXX_COMPILER> ${HYPERVISOR_EXT_CXX_FLAGS} <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT> -c <SOURCE>")
set(CMAKE_CXX_LINK_EXECUTABLE
"${HYPERVISOR_CXX_LINKER} ${HYPERVISOR_EXT_LINK_FLAGS} <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>"
)
################################################################################
# Hack For Windows
################################################################################
# For some reason, CMake on Windows is adding extra stuff to the compiler
# includes and flags. The following fixes this issue by telling CMake not
# to configure the compiler. We need to add C++20 to the command above
# to make this work.
# https://gitlab.kitware.com/cmake/cmake/-/issues/21789
set(__COMPILER_CLANG 1)
macro(__compiler_clang lang)
endmacro()
macro(__compiler_clang_cxx_standards lang)
endmacro()
macro(__compiler_check_default_language_standard lang)
endmacro()

View file

@ -0,0 +1,76 @@
#
# 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.
set(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_CXX_COMPILER_WORKS 1)
string(CONCAT HYPERVISOR_MK_CXX_FLAGS
"--target=aarch64-elf "
"-ffreestanding "
"-mno-implicit-float "
"-mcmodel=large "
"-std=c++20 "
)
if(CMAKE_BUILD_TYPE STREQUAL RELEASE OR CMAKE_BUILD_TYPE STREQUAL MINSIZEREL)
string(CONCAT HYPERVISOR_MK_CXX_FLAGS
${HYPERVISOR_MK_CXX_FLAGS}
"-flto "
)
endif()
string(CONCAT HYPERVISOR_MK_LINK_FLAGS
"-static "
"-nostdlib "
"-z noexecstack "
"-T ${CMAKE_BINARY_DIR}/toolchain/arm/aarch64/mk.ld "
)
set(CMAKE_ASM_COMPILE_OBJECT
"<CMAKE_CXX_COMPILER> ${HYPERVISOR_MK_CXX_FLAGS} <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT> -c <SOURCE>")
set(CMAKE_CXX_COMPILE_OBJECT
"<CMAKE_CXX_COMPILER> ${HYPERVISOR_MK_CXX_FLAGS} <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT> -c <SOURCE>")
set(CMAKE_CXX_LINK_EXECUTABLE
"${HYPERVISOR_CXX_LINKER} ${HYPERVISOR_MK_LINK_FLAGS} <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>"
)
################################################################################
# Hack For Windows
################################################################################
# For some reason, CMake on Windows is adding extra stuff to the compiler
# includes and flags. The following fixes this issue by telling CMake not
# to configure the compiler. We need to add C++20 to the command above
# to make this work.
# https://gitlab.kitware.com/cmake/cmake/-/issues/21789
set(__COMPILER_CLANG 1)
macro(__compiler_clang lang)
endmacro()
macro(__compiler_clang_cxx_standards lang)
endmacro()
macro(__compiler_check_default_language_standard lang)
endmacro()

View file

@ -40,6 +40,13 @@ string(CONCAT HYPERVISOR_EXT_CXX_FLAGS
"-std=c++20 "
)
if(CMAKE_BUILD_TYPE STREQUAL RELEASE OR CMAKE_BUILD_TYPE STREQUAL MINSIZEREL)
string(CONCAT HYPERVISOR_EXT_CXX_FLAGS
${HYPERVISOR_EXT_CXX_FLAGS}
"-flto "
)
endif()
string(CONCAT HYPERVISOR_EXT_LINK_FLAGS
"-static "
"-nostdlib "

View file

@ -40,6 +40,13 @@ string(CONCAT HYPERVISOR_MK_CXX_FLAGS
"-std=c++20 "
)
if(CMAKE_BUILD_TYPE STREQUAL RELEASE OR CMAKE_BUILD_TYPE STREQUAL MINSIZEREL)
string(CONCAT HYPERVISOR_MK_CXX_FLAGS
${HYPERVISOR_MK_CXX_FLAGS}
"-flto "
)
endif()
string(CONCAT HYPERVISOR_MK_LINK_FLAGS
"-static "
"-nostdlib "

View file

@ -19,11 +19,69 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
if(HYPERVISOR_TARGET_ARCH STREQUAL "aarch64")
if(HYPERVISOR_BUILD_VMMCTL)
message(FATAL_ERROR "HYPERVISOR_BUILD_VMMCTL is not supported on ARM")
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()
# TODO:
# - Validate the rest of the configuration
#
if(NOT EXISTS "${HYPERVISOR_EXTENSIONS_DIR}")
message(FATAL_ERROR "HYPERVISOR_EXTENSIONS_DIR does not exist: ${HYPERVISOR_EXTENSIONS_DIR}")
endif()
if(NOT EXISTS "${HYPERVISOR_EXTENSIONS_DIR}/CMakeLists.txt")
message(FATAL_ERROR "HYPERVISOR_EXTENSIONS_DIR does not contain a CMakeLists.txt")
endif()
if(HYPERVISOR_DEBUG_RING_SIZE LESS 0x1000)
message(FATAL_ERROR "HYPERVISOR_DEBUG_RING_SIZE must be at least a page")
endif()
if(HYPERVISOR_VMEXIT_LOG_SIZE LESS 1)
message(FATAL_ERROR "HYPERVISOR_VMEXIT_LOG_SIZE must be at least 1")
endif()
if(HYPERVISOR_MAX_SEGMENTS LESS 2)
message(FATAL_ERROR "HYPERVISOR_MAX_SEGMENTS must be at least 2")
endif()
if(HYPERVISOR_MAX_EXTENSIONS LESS 1)
message(FATAL_ERROR "HYPERVISOR_MAX_EXTENSIONS must be at least 1")
endif()
if(HYPERVISOR_MAX_VMS LESS 1)
message(FATAL_ERROR "HYPERVISOR_MAX_VMS must be at least 1")
endif()
if(HYPERVISOR_MAX_PPS LESS 1)
message(FATAL_ERROR "HYPERVISOR_MAX_PPS must be at least 1")
endif()
if(HYPERVISOR_MAX_VPS LESS HYPERVISOR_MAX_PPS)
message(FATAL_ERROR "HYPERVISOR_MAX_VPS the same or greater as HYPERVISOR_MAX_PPS")
endif()
if(HYPERVISOR_MAX_VPSS LESS HYPERVISOR_MAX_VPS)
message(FATAL_ERROR "HYPERVISOR_MAX_VPSS the same or greater as HYPERVISOR_MAX_VPS")
endif()
if(HYPERVISOR_MK_STACK_SIZE LESS 0x1000)
message(FATAL_ERROR "HYPERVISOR_MK_STACK_SIZE must be at least a page")
endif()
if(HYPERVISOR_MK_PAGE_POOL_SIZE LESS 0x1000)
message(FATAL_ERROR "HYPERVISOR_MK_PAGE_POOL_SIZE must be at least a page")
endif()
if(HYPERVISOR_MK_HUGE_POOL_SIZE LESS 0x1000)
message(FATAL_ERROR "HYPERVISOR_MK_HUGE_POOL_SIZE must be at least a page")
endif()
if(HYPERVISOR_EXT_STACK_SIZE LESS 0x1000)
message(FATAL_ERROR "HYPERVISOR_EXT_STACK_SIZE must be at least a page")
endif()

View file

@ -30,6 +30,14 @@ if (NOT EXISTS ${CMAKE_BINARY_DIR}/include/constants.h)
file(APPEND ${HYPERVISOR_CONSTANTS} "#define CONSTANTS_H\n")
file(APPEND ${HYPERVISOR_CONSTANTS} "\n")
if(HYPERVISOR_TARGET_ARCH STREQUAL "AuthenticAMD" OR HYPERVISOR_TARGET_ARCH STREQUAL "GenuineIntel")
file(APPEND ${HYPERVISOR_CONSTANTS} "#define HYPERVISOR_SERIAL_PORT ${HYPERVISOR_SERIAL_PORT}\n")
else()
file(APPEND ${HYPERVISOR_CONSTANTS} "#define HYPERVISOR_SERIAL_PORTH ${HYPERVISOR_SERIAL_PORTH}\n")
file(APPEND ${HYPERVISOR_CONSTANTS} "#define HYPERVISOR_SERIAL_PORTL ${HYPERVISOR_SERIAL_PORTL}\n")
endif()
file(APPEND ${HYPERVISOR_CONSTANTS} "#ifndef ASSEMBLY\n")
file(APPEND ${HYPERVISOR_CONSTANTS} "#include <stdint.h>\n")
file(APPEND ${HYPERVISOR_CONSTANTS} "\n")
@ -37,24 +45,27 @@ if (NOT EXISTS ${CMAKE_BINARY_DIR}/include/constants.h)
file(APPEND ${HYPERVISOR_CONSTANTS} "#define BSL_PAGE_SIZE ((uint64_t)(${BSL_PAGE_SIZE}))\n")
file(APPEND ${HYPERVISOR_CONSTANTS} "#define HYPERVISOR_PAGE_SIZE ((uint64_t)(${HYPERVISOR_PAGE_SIZE}))\n")
file(APPEND ${HYPERVISOR_CONSTANTS} "#define HYPERVISOR_PAGE_SHIFT ((uint64_t)(${HYPERVISOR_PAGE_SHIFT}))\n")
file(APPEND ${HYPERVISOR_CONSTANTS} "#define HYPERVISOR_SERIAL_PORT ((uint16_t)(${HYPERVISOR_SERIAL_PORT}))\n")
file(APPEND ${HYPERVISOR_CONSTANTS} "#define HYPERVISOR_DEBUG_RING_SIZE ((uint64_t)(${HYPERVISOR_DEBUG_RING_SIZE}))\n")
file(APPEND ${HYPERVISOR_CONSTANTS} "#define HYPERVISOR_VMEXIT_LOG_SIZE ((uint64_t)(${HYPERVISOR_VMEXIT_LOG_SIZE}))\n")
file(APPEND ${HYPERVISOR_CONSTANTS} "#define HYPERVISOR_MAX_ELF_FILE_SIZE ((uint64_t)(${HYPERVISOR_MAX_ELF_FILE_SIZE}))\n")
file(APPEND ${HYPERVISOR_CONSTANTS} "#define HYPERVISOR_MAX_SEGMENTS ((uint64_t)(${HYPERVISOR_MAX_SEGMENTS}))\n")
file(APPEND ${HYPERVISOR_CONSTANTS} "#define HYPERVISOR_MAX_EXTENSIONS ((uint64_t)(${HYPERVISOR_MAX_EXTENSIONS}))\n")
file(APPEND ${HYPERVISOR_CONSTANTS} "#define HYPERVISOR_MAX_VMS ((uint64_t)(${HYPERVISOR_MAX_VMS}))\n")
file(APPEND ${HYPERVISOR_CONSTANTS} "#define HYPERVISOR_MAX_PPS ((uint64_t)(${HYPERVISOR_MAX_PPS}))\n")
file(APPEND ${HYPERVISOR_CONSTANTS} "#define HYPERVISOR_MAX_VPS ((uint64_t)(${HYPERVISOR_MAX_VPS}))\n")
file(APPEND ${HYPERVISOR_CONSTANTS} "#define HYPERVISOR_MAX_VPS_PER_VM ((uint64_t)(${HYPERVISOR_MAX_VPS_PER_VM}))\n")
file(APPEND ${HYPERVISOR_CONSTANTS} "#define HYPERVISOR_MAX_VPSS_PER_VP ((uint64_t)(${HYPERVISOR_MAX_VPSS_PER_VP}))\n")
file(APPEND ${HYPERVISOR_CONSTANTS} "#define HYPERVISOR_MAX_VPSS ((uint64_t)(${HYPERVISOR_MAX_VPSS}))\n")
file(APPEND ${HYPERVISOR_CONSTANTS} "#define HYPERVISOR_DEBUG_RING_SIZE ((uint64_t)(${HYPERVISOR_DEBUG_RING_SIZE}))\n")
file(APPEND ${HYPERVISOR_CONSTANTS} "#define HYPERVISOR_DIRECT_MAP_ADDR ((uint64_t)(${HYPERVISOR_DIRECT_MAP_ADDR}))\n")
file(APPEND ${HYPERVISOR_CONSTANTS} "#define HYPERVISOR_MK_DIRECT_MAP_ADDR ((uint64_t)(${HYPERVISOR_MK_DIRECT_MAP_ADDR}))\n")
file(APPEND ${HYPERVISOR_CONSTANTS} "#define HYPERVISOR_MK_DIRECT_MAP_SIZE ((uint64_t)(${HYPERVISOR_MK_DIRECT_MAP_SIZE}))\n")
file(APPEND ${HYPERVISOR_CONSTANTS} "#define HYPERVISOR_MK_STACK_ADDR ((uint64_t)(${HYPERVISOR_MK_STACK_ADDR}))\n")
file(APPEND ${HYPERVISOR_CONSTANTS} "#define HYPERVISOR_MK_STACK_SIZE ((uint64_t)(${HYPERVISOR_MK_STACK_SIZE}))\n")
file(APPEND ${HYPERVISOR_CONSTANTS} "#define HYPERVISOR_MK_CODE_ADDR ((uint64_t)(${HYPERVISOR_MK_CODE_ADDR}))\n")
file(APPEND ${HYPERVISOR_CONSTANTS} "#define HYPERVISOR_MK_CODE_SIZE ((uint64_t)(${HYPERVISOR_MK_CODE_SIZE}))\n")
file(APPEND ${HYPERVISOR_CONSTANTS} "#define HYPERVISOR_MK_MAP_ADDR ((uint64_t)(${HYPERVISOR_MK_MAP_ADDR}))\n")
file(APPEND ${HYPERVISOR_CONSTANTS} "#define HYPERVISOR_MK_MAP_SIZE ((uint64_t)(${HYPERVISOR_MK_MAP_SIZE}))\n")
file(APPEND ${HYPERVISOR_CONSTANTS} "#define HYPERVISOR_MK_PAGE_POOL_ADDR ((uint64_t)(${HYPERVISOR_MK_PAGE_POOL_ADDR}))\n")
file(APPEND ${HYPERVISOR_CONSTANTS} "#define HYPERVISOR_MK_PAGE_POOL_SIZE ((uint64_t)(${HYPERVISOR_MK_PAGE_POOL_SIZE}))\n")
file(APPEND ${HYPERVISOR_CONSTANTS} "#define HYPERVISOR_MK_HUGE_POOL_ADDR ((uint64_t)(${HYPERVISOR_MK_HUGE_POOL_ADDR}))\n")
file(APPEND ${HYPERVISOR_CONSTANTS} "#define HYPERVISOR_MK_HUGE_POOL_SIZE ((uint64_t)(${HYPERVISOR_MK_HUGE_POOL_SIZE}))\n")
file(APPEND ${HYPERVISOR_CONSTANTS} "#define HYPERVISOR_EXT_DIRECT_MAP_ADDR ((uint64_t)(${HYPERVISOR_EXT_DIRECT_MAP_ADDR}))\n")
file(APPEND ${HYPERVISOR_CONSTANTS} "#define HYPERVISOR_EXT_DIRECT_MAP_SIZE ((uint64_t)(${HYPERVISOR_EXT_DIRECT_MAP_SIZE}))\n")
file(APPEND ${HYPERVISOR_CONSTANTS} "#define HYPERVISOR_EXT_STACK_ADDR ((uint64_t)(${HYPERVISOR_EXT_STACK_ADDR}))\n")
file(APPEND ${HYPERVISOR_CONSTANTS} "#define HYPERVISOR_EXT_STACK_SIZE ((uint64_t)(${HYPERVISOR_EXT_STACK_SIZE}))\n")
file(APPEND ${HYPERVISOR_CONSTANTS} "#define HYPERVISOR_EXT_CODE_ADDR ((uint64_t)(${HYPERVISOR_EXT_CODE_ADDR}))\n")
@ -63,11 +74,23 @@ if (NOT EXISTS ${CMAKE_BINARY_DIR}/include/constants.h)
file(APPEND ${HYPERVISOR_CONSTANTS} "#define HYPERVISOR_EXT_TLS_SIZE ((uint64_t)(${HYPERVISOR_EXT_TLS_SIZE}))\n")
file(APPEND ${HYPERVISOR_CONSTANTS} "#define HYPERVISOR_EXT_PAGE_POOL_ADDR ((uint64_t)(${HYPERVISOR_EXT_PAGE_POOL_ADDR}))\n")
file(APPEND ${HYPERVISOR_CONSTANTS} "#define HYPERVISOR_EXT_PAGE_POOL_SIZE ((uint64_t)(${HYPERVISOR_EXT_PAGE_POOL_SIZE}))\n")
file(APPEND ${HYPERVISOR_CONSTANTS} "#define HYPERVISOR_EXT_HUGE_POOL_ADDR ((uint64_t)(${HYPERVISOR_EXT_HUGE_POOL_ADDR}))\n")
file(APPEND ${HYPERVISOR_CONSTANTS} "#define HYPERVISOR_EXT_HUGE_POOL_SIZE ((uint64_t)(${HYPERVISOR_EXT_HUGE_POOL_SIZE}))\n")
file(APPEND ${HYPERVISOR_CONSTANTS} "#define HYPERVISOR_EXT_HEAP_POOL_ADDR ((uint64_t)(${HYPERVISOR_EXT_HEAP_POOL_ADDR}))\n")
file(APPEND ${HYPERVISOR_CONSTANTS} "#define HYPERVISOR_EXT_HEAP_POOL_SIZE ((uint64_t)(${HYPERVISOR_EXT_HEAP_POOL_SIZE}))\n")
file(APPEND ${HYPERVISOR_CONSTANTS} "#define HYPERVISOR_HUGE_POOL_SIZE ((uint64_t)(${HYPERVISOR_HUGE_POOL_SIZE}))\n")
file(APPEND ${HYPERVISOR_CONSTANTS} "#define HYPERVISOR_PAGE_POOL_SIZE ((uint64_t)(${HYPERVISOR_PAGE_POOL_SIZE}))\n")
file(APPEND ${HYPERVISOR_CONSTANTS} "\n")
file(APPEND ${HYPERVISOR_CONSTANTS} "#endif\n")
file(APPEND ${HYPERVISOR_CONSTANTS} "#endif\n")
endif()
if (NOT EXISTS ${CMAKE_BINARY_DIR}/include/constants_masm.h)
file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/include)
set(HYPERVISOR_CONSTANTS ${CMAKE_BINARY_DIR}/include/constants_masm.h)
file(WRITE ${HYPERVISOR_CONSTANTS} "; ---- AUTO GENERATED ---- \n")
file(APPEND ${HYPERVISOR_CONSTANTS} "\n")
string(REPLACE "0x" "" HYPERVISOR_SERIAL_PORT_MASM "${HYPERVISOR_SERIAL_PORT}")
file(APPEND ${HYPERVISOR_CONSTANTS} "HYPERVISOR_SERIAL_PORT EQU ${HYPERVISOR_SERIAL_PORT_MASM}h\n")
endif()

View file

@ -0,0 +1,41 @@
#
# 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.
if (NOT EXISTS ${CMAKE_BINARY_DIR}/toolchain/arm/aarch64/ext.ld)
file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/toolchain)
file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/toolchain/arm)
file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/toolchain/arm/aarch64)
set(HYPERVISOR_TOOLCHAIN_X64_MK_LD ${CMAKE_BINARY_DIR}/toolchain/arm/aarch64/ext.ld)
file(WRITE ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} "/* ---- AUTO GENERATED ---- */\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} "\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} "ENTRY(_start)\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} "\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} "SECTIONS {\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} " . = ${HYPERVISOR_EXT_CODE_ADDR};\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} " .text : ALIGN(0x1000) { *(.text .text.*); }\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} " .rodata : ALIGN(0x1000) { *(.rodata .rodata.*); }\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} " .data : ALIGN(0x1000) { *(.data .data.*); }\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} " .bss : ALIGN(0x1000) { *(.bss .bss.*); }\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} "}\n")
endif()

View file

@ -0,0 +1,41 @@
#
# 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.
if (NOT EXISTS ${CMAKE_BINARY_DIR}/toolchain/arm/aarch64/mk.ld)
file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/toolchain)
file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/toolchain/arm)
file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/toolchain/arm/aarch64)
set(HYPERVISOR_TOOLCHAIN_X64_MK_LD ${CMAKE_BINARY_DIR}/toolchain/arm/aarch64/mk.ld)
file(WRITE ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} "/* ---- AUTO GENERATED ---- */\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} "\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} "ENTRY(mk_main_entry)\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} "\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} "SECTIONS {\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} " . = ${HYPERVISOR_MK_CODE_ADDR};\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} " .text : ALIGN(0x1000) { *(.text .text.*); }\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} " .rodata : ALIGN(0x1000) { *(.rodata .rodata.*); }\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} " .data : ALIGN(0x1000) { *(.data .data.*); }\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} " .bss : ALIGN(0x1000) { *(.bss .bss.*); }\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} "}\n")
endif()

View file

@ -28,45 +28,13 @@ if (NOT EXISTS ${CMAKE_BINARY_DIR}/toolchain/x64/ext.ld)
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} "\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} "ENTRY(_start)\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} "OUTPUT_FORMAT(elf64-x86-64)\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} "\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} "SECTIONS {\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} " . = ${HYPERVISOR_EXT_CODE_ADDR};\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} " .text : ALIGN(${BSL_PAGE_SIZE}) {\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} " *(.text)\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} " }\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} " .init : ALIGN(${BSL_PAGE_SIZE}) {\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} " *(.init)\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} " }\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} " .init_array : ALIGN(${BSL_PAGE_SIZE}) {\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} " *(.init_array)\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} " }\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} " .fini : ALIGN(${BSL_PAGE_SIZE}) {\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} " *(.fini)\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} " }\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} " .fini_array : ALIGN(${BSL_PAGE_SIZE}) {\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} " *(.fini_array)\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} " }\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} " .rodata : ALIGN(${BSL_PAGE_SIZE}) {\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} " *(.rodata)\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} " }\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} " .data : ALIGN(${BSL_PAGE_SIZE}) {\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} " *(.data)\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} " }\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} " .bss : ALIGN(${BSL_PAGE_SIZE}) {\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} " *(.bss)\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} " }\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} " .text : ALIGN(0x1000) { *(.text .text.*); }\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} " .rodata : ALIGN(0x1000) { *(.rodata .rodata.*); }\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} " .data : ALIGN(0x1000) { *(.data .data.*); }\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} " .bss : ALIGN(0x1000) { *(.bss .bss.*); }\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} "}\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} "\n")
endif()

View file

@ -28,45 +28,13 @@ if (NOT EXISTS ${CMAKE_BINARY_DIR}/toolchain/x64/mk.ld)
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} "\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} "ENTRY(mk_main_entry)\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} "OUTPUT_FORMAT(elf64-x86-64)\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} "\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} "SECTIONS {\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} " . = ${HYPERVISOR_MK_CODE_ADDR};\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} " .text : ALIGN(${BSL_PAGE_SIZE}) {\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} " *(.text)\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} " }\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} " .init : ALIGN(${BSL_PAGE_SIZE}) {\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} " *(.init)\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} " }\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} " .init_array : ALIGN(${BSL_PAGE_SIZE}) {\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} " *(.init_array)\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} " }\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} " .fini : ALIGN(${BSL_PAGE_SIZE}) {\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} " *(.fini)\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} " }\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} " .fini_array : ALIGN(${BSL_PAGE_SIZE}) {\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} " *(.fini_array)\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} " }\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} " .rodata : ALIGN(${BSL_PAGE_SIZE}) {\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} " *(.rodata)\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} " }\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} " .data : ALIGN(${BSL_PAGE_SIZE}) {\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} " *(.data)\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} " }\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} " .bss : ALIGN(${BSL_PAGE_SIZE}) {\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} " *(.bss)\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} " }\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} " .text : ALIGN(0x1000) { *(.text .text.*); }\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} " .rodata : ALIGN(0x1000) { *(.rodata .rodata.*); }\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} " .data : ALIGN(0x1000) { *(.data .data.*); }\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} " .bss : ALIGN(0x1000) { *(.bss .bss.*); }\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} "}\n")
file(APPEND ${HYPERVISOR_TOOLCHAIN_X64_MK_LD} "\n")
endif()

36
docs/Failure Analysis.md Normal file
View file

@ -0,0 +1,36 @@
## Table of Contents <!-- omit in toc -->
# 1. Introduction
This document defines how failures are handled by the microkernel and what the expected results are.
# 2. Starting
TBD
# 3. Stopping
TBD
# 4. Syscalls
When a syscall is executed it is possible that the microkernel could generate a hardware exception and fail to execute the syscall. If this occurs, the microkernel is designed to return back to the extension with an error code stating that the call to the microkernel failed.
If a syscall returns BF_STATUS_FAILURE_UNKNOWN, it should be assumed that either an unexpected error has occurred, or a hardware exception has occurred. In either case, the following are the expectations that an extension can make about any given syscall:
# 4.1 Resource Creation
Any syscall that creates a resource like bf_vm_op_create_vm, bf_vm_op_create_vp and bf_vm_op_create_vps will leave the internal state of the microkernel the way it was prior to an error. This includes if a hardware exception occurs while attempting to execute the syscall (excluding exceptions like a Machine Check which are unrecoverable by design). It is up to the extension to determine how to proceed. For example, if the extension is implementing guest support and a creation fails for whatever reason, the extension may choose to stop everything, or it may choose to continue the execution of any existing virtual machines and simply fail to create a new one.
# 4.2 Resource Destruction
Resource destruction is way more complicated than resource creation. When we create a resource we are simply taking a clean, unused resource and assigning it so the hardest part about creation is resource starvation. Destruction on the other hand has the following conditions that we need to handle:
- Attempting to destroy resources that were never created or cannot be created. For example, if you attempt to destroy a resource that you never created in the first place, destroying a resource that is above the max allowed, or is invalid.
- Attempting to destroy a resource that is still in use.
In both cases, we need to ensure the microkernel can continue execution without getting into a corrupt state. Any attempt to destroy a resource that was never created or cannot be created will just output an error and move on as there is no state to reverse. If an extension attempts to destroy a resource that is still in use, the extension would be creating a use-after-free bug. Most kernels would just allow the userspace application to crash, become corrupt, etc, but since this is a hypervisor, we need to try to survive this case. To handle this, the microkernel will mark the resource as a "Zombie".
A zombie resource is any resource that is still in use that an extension tried to destroy. When this happens, the microkernel will not allow the resource to be used. What this means is that any attempt to make a syscall using the ID of a zombied resource will fail. To understand why, think about free() with a memory address that is still in use. Once an extension makes the decision to free a resource, it should never, ever try to use it. The microkernel's job is not to magically allow a freed resource to still be usable, but instead to ensure that it doesn't crash while an extension is in this state.
A zombie resource cannot be recovered. For example, if an extension tries to destroy a resource that is still in use, and then realizes it should ensure all other resources are removed first and no longer in use, it cannot then turn around and destroy the zombie resource to get it back. Once a resource is destroyed, it is destroyed. The zombie status is used by the microkernel to say that the resource has been leaked, don't touch it because we don't know how to proceed safely with it. Again, a the zombie status is not about magically providing a means for the extension to do really bad things. It is about providing a means to prevent the hypervisor from crashing which is what would normally happen if a use-after-free bug occurs.

69
docs/IPI Design Doc.md Normal file
View file

@ -0,0 +1,69 @@
# IPI Design Doc
The microkernel needs a way to IPI itself. For example, if an extension decides free a previously allocated page, the microkernel needs to flush the TLB on all cores to ensure the unmap process doesn't result in a use after free bug.
The problem is, the microkernel is not actually in charge of how virtualization is implemented. Userspace extensions are responsible for this action. This limits what the microkernel is able to use for performing an IPI.
## Options
The following documents the options available to the microkernel WRT to how it implements its own IPI mechanism.
### External Interrupts
The microkernel could IPI an external interrupt. This is the safest way to IPI another core. The problem is, the hypervisor doesn't own external interrupts in the type 1 case (it does in the type 2 case like KVM for example). In the type 1 case, the root OS (sometimes called the root partition or Dom0) owns all of the external interrupt vectors. If the hypervisor wants to use one of these vectors, it would either need to ask the OS for a vector, or it would need to steal a vector.
Asking for a vector has a lot of issues. It means that we must trust the root OS to never use this vector itself. It also doesn't help much while the root OS is booting because we would need a way to ask UEFI to give us a vector, and then from there hope this vector is not used by the OS until we have an opportunity to ask for the vector. This problem is easy to solve with a Linux root OS as we can simply hardcode (which is done today) a vector that we can use. On Windows, or some other random OS that we might want to support, this is a problem.
Stealing the vector is also problematic because we would need to ensure that no external devices are given the vector we decide to steal. With an IOMMU, we could remap a vector that we steal, but this would require that the microkernel is capable of setting up the IOMMU on its own, which again, the userspace extension should be doing, not the microkernel. This also doesn't help us on systems that either do not have an IOMMU, or devices that are not on the PCI bus that are still capable of firing an external interrupt like the APIC and HPET. In other words, this approach would require an enormous amount of emulation in the microkernel which it is not supposed to be doing.
### NMIs
We could use an NMI. On Intel, we cannot mask NMIs, and as a result, we are forced the handle them safely already. What this means is, if an NMI fires while the microkernel is running, it records this and turns on the NMI window, which extensions are required to implement on Intel. One AMD, NMIs are blocked using the global interrupt flag, meaning if an NMI were to fire, it is delivered to the guest on the next VMRun.
The biggest issue with using the NMI method is trying to determine if the NMI came from the hypervisor. NMIs are owned by the root OS. If more than one NMI fires, the second NMI is ignored. On Linux, this is a problem as NMIs fire all the time, which means that the chances of two NMIs colliding is possible. If this occurs while the hypervisor is in the process of handling an IPI, it would result in the NMI the OS is expecting to be dropped. Since NMIs are used by Linux to handle power management, this event would be a real problem.
### SMIs
Another option is to IPI an SMI. The problem with this approach is that on Intel, there is no way to trap SMIs. In fact, on Intel, if an SMI occurs, SMM is executed below the hypervisor. We can trap on SMIs on AMD, but an SMI using an IPI would be considered an external SMI, and on AMD, even after the trap, the SMI is held pending, so once you return back to the guest VM, the SMI will be delivered to the guest with no way to prevent this.
### INIT
Unlike all of the other interrupts discussed above, INIT is actually owned by the hypervisor. Meaning, unlike the other interrupts, the ability to reset a CPU is up to the hypervisor, and the hypervisor can decide how INIT is implemented. Rarely would a hypervisor actually wish to deliver an INIT to the guest VM and instead it would normally emulate INIT itself.
Both Intel and AMD support the ability to trap INIT. On Intel, INIT is trapped as it's own VMExit. From there, it is up to the hypervisor to emulate INIT. On AMD, you can let the guest handle INIT, or you can trap INIT. If you trap INIT, the INIT flag is held pending even after the exit. What this means is that once you enable the global interrupt flag, the CPU would be reset. To prevent this, you need to enable R_INIT in the VM_CR MSR. This tells the CPU to deliver the INIT to the CPU as an SX exception. If the SX exception is intercepted as well, it will result in a VMExit and the hypervisor can emulate INIT from there the same way it would for Intel.
The problem is when SX is delivered to the hypervisor while it is running, and this is really where the nightmare begins. The global interrupt flag doesn't block SX, so like an NMI on Intel, we have to handle it. There are two ways in which we could implement the SX handler:
- If we use an IST, we would end up with the microkernel state becoming corrupt if more than one INIT lands on the CPU in a short period of time. In other words, unless you want to roll the dice, using the IST is not an option.
- If we don't use an IST, it means that whatever stack the CPU is currently using will be used to handle SX. From the hypervisor point of view, this means the stack given to the microkernel, or the stack given to a userspace extension. Since the microkernel doesn't do much, most of the time will be spent in userspace, which means that we are likely to see a userspace stack more often than not.
If we take option #2, it means that we have to allow SX to write to the userspace stack. How this is done depends on two different scenarios:
- If SMAP is disabled, the userspace stack would be used without an issue. So long as there is enough stack space (including space for more than one SX exception), we are good. The biggest issue with this approach is anything the microkernel puts on the stack will be leaked to userspace. Bareflank implements the hypervisor in userspace to provide a clean way to support extensions, but one great side effect is we can design the system such that we do not need to trust userspace. Although this is not our primary goal, it is something we would like to achieve in time. What this means is we either need to trust userspace, or we need to ensure we don't use the stack when handling SX.
- If SMAP is enabled, an SX would immediately result in a Double Fault. Specifically, when the CPU would attempt to use the userspace stack, it would generate a page fault due to Ring 0 trying to use Ring 3 memory. The double fault handler however uses the IST, which means that any additional SX would not have a kernel stack to use instead of a userspace stack. What this means is that when SMAP is enabled, the CPU will never be allowed to use the userspace stack, and instead would have to execute from the double fault handler. With a carefully crafted double fault handler this may be possible.
## Intel Approach
## AMD Approach
Currently SMAP is disabled in the microkernel to ensure support on devices that do not support SMAP. This is done in two ways:
- On AMD, the loader disables SMAP in CR4.
- On Intel, this is not as simple as Intel requires certain CR4 bits to be enabled while VT-x is in use. It just so happens that on some CPUs, SMAP must be enabled in both the host and the guest state for VMLaunch to succeed (for example, some Atom processors do this). To mitigate this issue, the microkernel also ensures that whenever the microkernel is executing, the AC bit is set. This allows SMAP to technically be enabled, but not enforced.
With SMAP disabled, it means that we can use the userspace stack for the SX handler. There are two issues with this that we need to mitigate:
- We would need to trust userspace because kernel specific secrets would be stored on the userspace stack.
- We would need a pretty large userspace stack. Specifically, the stack would have to be large enough to handle normal userspace stuff, plus several SX handler workloads if they happen to pile on.
To mitigate these two issues, this approach will keep the SX handler as simple as possible. Specifically, it would do the following:
- inc gs:[sx_pending]
- if gs:[sx_lock] not set, jump to RIP in VMRun handler
- iret
The code above doesn't use the userspace stack at all. It is also quick, so the chances of SX happening more than once are small, but even if it did, there is no issue here. The only stack modifications using the code above are for the IRET instruction itself. Specifically, when the SX exception fired, microcode will place RIP, RSP, RFLAGS and CS/SS onto the stack. The amount of memory used is so small, it introduces very little risk of the stack running out of space, so issue #2 is addressed above. All we have left to worry about is issue #1. Since we were running in userspace, everything pushed to the stack is userspace specific information, so nothing is leaked.
Well.... that is not actually true. If two SX exceptions fire before we have an opportunity to execute even a single instruction, the kernel's RIP of the SX handler would be leaked. If we implement KASLR, this would provide userspace with a means to detect the location of the kernel. Do we care... no, and here is why:
- Due to how SWAPGS and NMIs do not play nice, we currently leak GS, so if we are ok with leaking GS for now, we should be ok with leaking RIP of the SX handler as well.
- Need be, we can move the SX handler around independent of where KASLR would have put the microkernel, meaning knowing where the SX handler is wouldn't mean you will know where the rest of the microkernel is.
Ok, so now that we have a way to handle SX, we still need a way to handle the state that SX is setting. Specifically, there are two things in the TLS block that SX is working with
- tls.sx_pending, like the tls.nmi_pending is used to signal that the SX handler has executed. Unlike tls.nmi_pending, tls.sx_pending is a counter so that we can determine if more than one SX handler has executed.
- tls.sx_lock is used to determine if we need to jump or not in the VMRun logic. Specifically, when this bit is set, the SX handler is only allowed to increment tls.sx_pending. When this bit is not set, it will jump to a different return path of the VMRun handler designed to return from VMRun with an INIT intercept exit. We need this bit to ensure that once we have checked to see if an SX handler was fired that if we get an SX exception between the check and when we actually call VMRun that we don't actually call VMRun and instead continue to process exits. Without this, if an SX exception were to fire between when we checked tls.sx_pending and when we execute VMRun, could result in an IPI that would not be serviced until the next VMExit. Since Bareflank is designed to support hypervisors that result in a VMExit infrequently, this could be a real issue, especially if a core is waiting for all of the other cores to sync up as that could produce deadlock. We also have to deal with the case of when VMRun returns with a real exit and when tls.sx_lock has not been set yet. If this occurs, as soon as the SX exception fires, we would end up with an exception because likely the TLS block has not even been loaded yet.

View file

@ -5,17 +5,18 @@
- [1.2. Document Revision](#12-document-revision)
- [1.3. Glossary](#13-glossary)
- [1.4. Scalar Types](#14-scalar-types)
- [1.5. Memory Address Types](#15-memory-address-types)
- [1.6. ID Types](#16-id-types)
- [1.7. Constants, Structures, Enumerations, and Bit Fields](#17-constants-structures-enumerations-and-bit-fields)
- [1.7.1. Null](#171-null)
- [1.7.2. Handle Type](#172-handle-type)
- [1.7.3. Register Type](#173-register-type)
- [1.7.4. Exit Type](#174-exit-type)
- [1.7.5. Bootstrap Callback Handler Type](#175-bootstrap-callback-handler-type)
- [1.7.6. VMExit Callback Handler Type](#176-vmexit-callback-handler-type)
- [1.7.7. Fast Fail Callback Handler Type](#177-fast-fail-callback-handler-type)
- [1.8. Endianness](#18-endianness)
- [1.5. ID Types](#15-id-types)
- [1.6. Constants, Structures, Enumerations, and Bit Fields](#16-constants-structures-enumerations-and-bit-fields)
- [1.6.1. Null](#161-null)
- [1.6.2. Handle Type](#162-handle-type)
- [1.6.3. Register Type](#163-register-type)
- [1.6.4. Exit Type](#164-exit-type)
- [1.6.5. Bootstrap Callback Handler Type](#165-bootstrap-callback-handler-type)
- [1.6.6. VMExit Callback Handler Type](#166-vmexit-callback-handler-type)
- [1.6.7. Fast Fail Callback Handler Type](#167-fast-fail-callback-handler-type)
- [1.7. Invalid ID](#17-invalid-id)
- [1.8. Host PAT (Intel/AMD Only)](#18-host-pat-intelamd-only)
- [1.9. Endianness](#19-endianness)
- [2. Syscall Interface](#2-syscall-interface)
- [2.1. Legal Syscall Environments](#21-legal-syscall-environments)
- [2.2. Syscall Status Codes](#22-syscall-status-codes)
@ -40,6 +41,7 @@
- [2.6.1. TLS Offsets](#261-tls-offsets)
- [2.7. Control Syscalls](#27-control-syscalls)
- [2.7.1. bf_control_op_exit, OP=0x0, IDX=0x0](#271-bf_control_op_exit-op0x0-idx0x0)
- [2.10.1. bf_control_op_wait, OP=0x0, IDX=0x1](#2101-bf_control_op_wait-op0x0-idx0x1)
- [2.8. Handle Syscalls](#28-handle-syscalls)
- [2.8.1. bf_handle_op_open_handle, OP=0x1, IDX=0x0](#281-bf_handle_op_open_handle-op0x1-idx0x0)
- [2.8.2. bf_handle_op_close_handle, OP=0x1, IDX=0x1](#282-bf_handle_op_close_handle-op0x1-idx0x1)
@ -51,8 +53,10 @@
- [2.9.5. bf_debug_op_dump_vmexit_log, OP=0x2, IDX=0x4](#295-bf_debug_op_dump_vmexit_log-op0x2-idx0x4)
- [2.9.6. bf_debug_op_write_c, OP=0x2, IDX=0x5](#296-bf_debug_op_write_c-op0x2-idx0x5)
- [2.9.7. bf_debug_op_write_str, OP=0x2, IDX=0x6](#297-bf_debug_op_write_str-op0x2-idx0x6)
- [2.9.8. bf_debug_op_dump_ext, OP=0x2, IDX=0x7](#298-bf_debug_op_dump_ext-op0x2-idx0x7)
- [2.9.9. bf_debug_op_dump_page_pool, OP=0x2, IDX=0x8](#299-bf_debug_op_dump_page_pool-op0x2-idx0x8)
- [2.9.10. bf_debug_op_dump_huge_pool, OP=0x2, IDX=0x9](#2910-bf_debug_op_dump_huge_pool-op0x2-idx0x9)
- [2.10. Callback Syscalls](#210-callback-syscalls)
- [2.10.1. bf_callback_op_wait, OP=0x3, IDX=0x0](#2101-bf_callback_op_wait-op0x3-idx0x0)
- [2.10.2. bf_callback_op_register_bootstrap, OP=0x3, IDX=0x2](#2102-bf_callback_op_register_bootstrap-op0x3-idx0x2)
- [2.10.3. bf_callback_op_register_vmexit, OP=0x3, IDX=0x3](#2103-bf_callback_op_register_vmexit-op0x3-idx0x3)
- [2.10.4. bf_callback_op_register_fail, OP=0x3, IDX=0x4](#2104-bf_callback_op_register_fail-op0x3-idx0x4)
@ -64,6 +68,7 @@
- [2.12.1. Virtual Processor ID (VPID)](#2121-virtual-processor-id-vpid)
- [2.12.2. bf_vp_op_create_vp, OP=0x5, IDX=0x0](#2122-bf_vp_op_create_vp-op0x5-idx0x0)
- [2.12.3. bf_vp_op_destroy_vp, OP=0x5, IDX=0x1](#2123-bf_vp_op_destroy_vp-op0x5-idx0x1)
- [2.12.3. bf_vp_op_migrate, OP=0x5, IDX=0x2](#2123-bf_vp_op_migrate-op0x5-idx0x2)
- [2.12.4. Virtual Processor State Syscalls](#2124-virtual-processor-state-syscalls)
- [2.12.5. Virtual Processor State ID (VPSID)](#2125-virtual-processor-state-id-vpsid)
- [2.12.6. bf_vps_op_create_vps, OP=0x6, IDX=0x0](#2126-bf_vps_op_create_vps-op0x6-idx0x0)
@ -84,17 +89,19 @@
- [2.12.21. bf_vps_op_advance_ip, OP=0x5, IDX=0xF](#21221-bf_vps_op_advance_ip-op0x5-idx0xf)
- [2.12.22. bf_vps_op_advance_ip_and_run_current, OP=0x5, IDX=0x10](#21222-bf_vps_op_advance_ip_and_run_current-op0x5-idx0x10)
- [2.12.23. bf_vps_op_promote, OP=0x5, IDX=0x11](#21223-bf_vps_op_promote-op0x5-idx0x11)
- [2.12.24. bf_vps_op_clear_vps, OP=0x5, IDX=0x11](#21224-bf_vps_op_clear_vps-op0x5-idx0x11)
- [2.13. Intrinsic Syscalls](#213-intrinsic-syscalls)
- [2.13.1. bf_intrinsic_op_read_msr, OP=0x7, IDX=0x0](#2131-bf_intrinsic_op_read_msr-op0x7-idx0x0)
- [2.13.2. bf_intrinsic_op_write_msr, OP=0x7, IDX=0x1](#2132-bf_intrinsic_op_write_msr-op0x7-idx0x1)
- [2.13.1. bf_intrinsic_op_rdmsr, OP=0x7, IDX=0x0](#2131-bf_intrinsic_op_rdmsr-op0x7-idx0x0)
- [2.13.2. bf_intrinsic_op_wrmsr, OP=0x7, IDX=0x1](#2132-bf_intrinsic_op_wrmsr-op0x7-idx0x1)
- [2.13.3. bf_intrinsic_op_invlpga, OP=0x7, IDX=0x2](#2133-bf_intrinsic_op_invlpga-op0x7-idx0x2)
- [2.13.4. bf_intrinsic_op_invept, OP=0x7, IDX=0x3](#2134-bf_intrinsic_op_invept-op0x7-idx0x3)
- [2.13.5. bf_intrinsic_op_invvpid, OP=0x7, IDX=0x4](#2135-bf_intrinsic_op_invvpid-op0x7-idx0x4)
- [2.14. Mem Syscalls](#214-mem-syscalls)
- [2.14.1. bf_mem_op_alloc_page, OP=0x7, IDX=0x0](#2141-bf_mem_op_alloc_page-op0x7-idx0x0)
- [2.14.2. bf_mem_op_free_page, OP=0x7, IDX=0x1](#2142-bf_mem_op_free_page-op0x7-idx0x1)
- [2.14.3. bf_mem_op_alloc_huge, OP=0x7, IDX=0x2](#2143-bf_mem_op_alloc_huge-op0x7-idx0x2)
- [2.14.4. bf_mem_op_free_huge, OP=0x7, IDX=0x3](#2144-bf_mem_op_free_huge-op0x7-idx0x3)
- [2.14.5. bf_mem_op_alloc_heap, OP=0x7, IDX=0x4](#2145-bf_mem_op_alloc_heap-op0x7-idx0x4)
- [2.14.6. bf_mem_op_free_heap, OP=0x7, IDX=0x5](#2146-bf_mem_op_free_heap-op0x7-idx0x5)
- [2.14.7. bf_mem_op_virt_to_phys, OP=0x7, IDX=0x6](#2147-bf_mem_op_virt_to_phys-op0x7-idx0x6)
# 1. Introduction
@ -145,17 +152,10 @@ This specification is specific to 64bit Intel and AMD processors conforming to t
| bf_uint16_t | uint16_t | Defines an unsigned 16bit integer |
| bf_uint32_t | uint32_t | Defines an unsigned 32bit integer |
| bf_uint64_t | uint64_t | Defines an unsigned 64bit integer |
| bf_ptr_t | void const * | Defines a raw pointer type |
| bf_ptr_t | void * | Defines a raw pointer type |
| bf_cptr_t | void const * | Defines a raw const pointer type |
## 1.5. Memory Address Types
| Name | Type |
| :--- | :--- |
| System Physical Address (SPA) | bf_uint64_t |
| Guest Physical Address (GPA) | bf_uint64_t |
| Guest Virtual Address (GVA) | bf_uint64_t |
## 1.6. ID Types
## 1.5. ID Types
| Name | Type |
| :--- | :--- |
@ -164,16 +164,16 @@ This specification is specific to 64bit Intel and AMD processors conforming to t
| Virtual Processor State ID (VPSID) | bf_uint64_t |
| Physical Processor ID (PPID) | bf_uint64_t |
## 1.7. Constants, Structures, Enumerations, and Bit Fields
## 1.6. Constants, Structures, Enumerations, and Bit Fields
### 1.7.1. Null
### 1.6.1. Null
**const, void *: BF_NULL**
| Value | Description |
| :---- | :---------- |
| 0 | Defines the value of a null pointer |
### 1.7.2. Handle Type
### 1.6.2. Handle Type
The bf_handle_t structure is an opaque structure containing the handle used by most of the syscalls in this specification. The opaque structure is used internally by the C wrapper interface and should not be accessed directly. The C wrapper is allowed to redefine the internal layout of this structure at any time (e.g., the C wrapper might provide an alternative layout for unit testing).
@ -182,7 +182,7 @@ The bf_handle_t structure is an opaque structure containing the handle used by m
| :--- | :--- | :----- | :--- | :---------- |
| hndl | bf_uint64_t | 0x0 | 8 bytes | The handle returned by bf_handle_op_open_handle |
### 1.7.3. Register Type
### 1.6.3. Register Type
Defines which register a syscall is requesting.
@ -263,7 +263,7 @@ Defines which register a syscall is requesting.
| bf_reg_t_ia32_pat | 71 | defines ia32_pat register |
| bf_reg_t_ia32_debugctl | 72 | defines ia32_debugctl register |
### 1.7.4. Exit Type
### 1.6.4. Exit Type
Defines the exit type used by bf_control_op_exit
@ -273,25 +273,53 @@ Defines the exit type used by bf_control_op_exit
| bf_exit_status_t_success | 0 | Exit with a success code |
| bf_exit_status_t_failure | 1 | Exit with a failure code |
### 1.7.5. Bootstrap Callback Handler Type
### 1.6.5. Bootstrap Callback Handler Type
Defines the signature of the bootstrap callback handler
**typedef, void(*bf_callback_handler_bootstrap_t)(bf_uint16_t)**
### 1.7.6. VMExit Callback Handler Type
### 1.6.6. VMExit Callback Handler Type
Defines the signature of the VM exit callback handler
**typedef, void(*bf_callback_handler_vmexit_t)(bsl::bf_uint16_t, bf_uint64_t)**
### 1.7.7. Fast Fail Callback Handler Type
### 1.6.7. Fast Fail Callback Handler Type
Defines the signature of the fast fail callback handler
**typedef, void(*bf_callback_handler_fail_t)()**
**typedef, void(*bf_callback_handler_fail_t)(bf_status_t)**
## 1.8. Endianness
## 1.7. Invalid ID
The following defines an invalid ID which can be used for all ID types.
**const, bf_uint16_t: BF_INVALID_ID**
| Value | Description |
| :---- | :---------- |
| 0xFFFF | Defines an invalid ID for an extension, VM, VP and VPS |
**const, bf_uint16_t: BF_BS_PPID**
| Value | Description |
| :---- | :---------- |
| 0x0 | Defines the bootstrap physical processor ID |
**const, bf_uint16_t: BF_ROOT_VMID**
| Value | Description |
| :---- | :---------- |
| 0x0 | Defines the root virtual machine ID |
## 1.8. Host PAT (Intel/AMD Only)
The host PAT has the following layout. Indexes marked as XX are reserved for future use.
**const, bf_uint64_t: BF_HOST_PAT**
| Value | Description |
| :---- | :---------- |
| 0xXXXXXXXX00XXXX06 | Defines the host PAT value |
## 1.9. Endianness
This document only applies to 64bit Intel and AMD systems conforming to the amd64 architecture. As such, this document conforms to little-endian.
@ -315,21 +343,6 @@ Every syscall returns a bf_status_t to indicate the success or failure of a sysc
BF_STATUS_VALUE defines success or which type of error occurred. BF_STATUS_FLAGS provides additional information about why the error occurred. BF_STATUS_FLAGS is optional and used solely for diagnostics. As such, the microkernel may or may not provide it.
**const, bf_uint64_t: BF_STATUS_SIG_MASK**
| Value | Description |
| :---- | :---------- |
| 0xFFFF000000000000 | Defines a mask for BF_STATUS_SIG |
**const, bf_uint32_t: BF_STATUS_FLAGS_MASK**
| Value | Description |
| :---- | :---------- |
| 0x0000FFFFFFFF0000 | Defines a mask for BF_STATUS_FLAGS |
**const, bf_uint32_t: BF_STATUS_VALUE_MASK**
| Value | Description |
| :---- | :---------- |
| 0x000000000000FFFF | Defines a mask for BF_STATUS_VALUE |
### 2.2.1. BF_STATUS_SUCCESS, VALUE=0
**const, bf_status_t: BF_STATUS_SUCCESS**
@ -625,12 +638,39 @@ The following defines the specification IDs used when opening a handle. These pr
The microkernel defines a "thread" the same way both Intel and AMD define a thread (i.e., a logical core). For example, some Intel CPUs have 4 cores and 8 threads when hyper-threading is enabled, or 4 cores and 4 threads when hyper-threading is disabled. Each logical core is given one "thread" and that thread always executes on that logical core. The microkernel defines these logical cores as physical processors (i.e., PP).
Although there is only one thread per PP, a thread's ID changes based on the active extension, VM and VP. If a thread's ID changes, it's TLS block does not, meaning an extension is given one TLS block per PP, regardless of which VM or VP is active.
The layout of the TLS block provided to each extension uses a scheme similar to the ELF TLS specification, but with some modifications. Unlike the ELF TLS specification, each TLS block is limited to two pages. The lower half of the page is dedicated to "thread_local" storage. The upper half is defined by this specification, and provides access to registers shared between the microkernel and the extension to improve performance. For example, access to a VM's general purpose registers is available from the TLS block. Each TLS register defined by this specific is an offset into the upper half of the TLS block (which can be located using the fs segment register on Intel/AMD).
In addition, the layout of the TLS block uses a scheme similar to the ELF TLS specification, but with some modifications. Unlike the ELF TLS specification, each TLS block is limited to two pages. The lower half of the page is dedicated to "thread_local" storage. The upper half is defined by this specification, and provides access to registers shared between the microkernel and the extension to improve performance. For example, access to a VM's general purpose registers is available from the TLS block.
**IMPORTANT:**
The general purpose registers are always accessible to an extension to read and write, but it is up to the extension to ensure the correct VPS state is being modified. Accesses to the TLS block modifies the active VPS only. For example, while an extension is executing its bootstrap handler, there is no active VPS, in which case any reads/writes to the general purpose registers from the TLS block will be lost. When an extension is executing from a VMExit handler, reads/writes to the general purpose registers from the TLS block are made to the VPS that generated the VMExit. If an extension then creates a VPS, the only way to modify the general purpose registers for the newly created VPS is through the read_reg/write_reg ABIs. Attempting to use the TLS block will modify the registers for the active VPS, not the newly created VPS. The only way to set a VPS to "active" is to use the run ABI, which on success does not return, meaning the extension has to wait for a VMExit before the newly create VPS's general purpose registers can be accessed from the TLS block.
Although this seems overly complicated, this optimization works well for the majority of the VMExits an extension will have to handle, especially the VMExits that execute frequently as most of the time an extension will only be modifying the general purpose registers for the active VPS.
### 2.6.1. TLS Offsets
TBD
**consts, void *: bf_uint64_t**
| Name | Value | Description |
| :--- | :---- | :---------- |
| TLS_OFFSET_RAX | 0x800U | stores the offset for rax |
| TLS_OFFSET_RBX | 0x808U | stores the offset for rbx |
| TLS_OFFSET_RCX | 0x810U | stores the offset for rcx |
| TLS_OFFSET_RDX | 0x818U | stores the offset for rdx |
| TLS_OFFSET_RBP | 0x820U | stores the offset for rbp |
| TLS_OFFSET_RSI | 0x828U | stores the offset for rsi |
| TLS_OFFSET_RDI | 0x830U | stores the offset for rdi |
| TLS_OFFSET_R8 | 0x838U | stores the offset for r8 |
| TLS_OFFSET_R9 | 0x840U | stores the offset for r9 |
| TLS_OFFSET_R10 | 0x848U | stores the offset for r10 |
| TLS_OFFSET_R11 | 0x850U | stores the offset for r11 |
| TLS_OFFSET_R12 | 0x858U | stores the offset for r12 |
| TLS_OFFSET_R13 | 0x860U | stores the offset for r13 |
| TLS_OFFSET_R14 | 0x868U | stores the offset for r14 |
| TLS_OFFSET_R15 | 0x870U | stores the offset for r15 |
| TLS_OFFSET_ACTIVE_EXTID | 0xFF0U | stores the offset of the active extid |
| TLS_OFFSET_ACTIVE_VMID | 0xFF2U | stores the offset of the active vmid |
| TLS_OFFSET_ACTIVE_VPID | 0xFF4U | stores the offset of the active vpid |
| TLS_OFFSET_ACTIVE_VPSID | 0xFF6U | stores the offset of the active vpsid |
| TLS_OFFSET_ACTIVE_PPID | 0xFF8U | stores the offset of the active ppid |
| TLS_OFFSET_ONLINE_PPS | 0xFFAU | stores the number of PPs that are online |
## 2.7. Control Syscalls
@ -643,6 +683,15 @@ This syscall tells the microkernel to stop the execution of an extension, provid
| :---- | :---------- |
| 0x0000000000000000 | Defines the syscall index for bf_control_op_exit |
### 2.10.1. bf_control_op_wait, OP=0x0, IDX=0x1
This syscall tells the microkernel that the extension would like to wait for a callback. This syscall is a blocking syscall that never returns and should be used to return from the _start function.
**const, bf_uint64_t: BF_CONTROL_OP_WAIT_IDX_VAL**
| Value | Description |
| :---- | :---------- |
| 0x0000000000000001 | Defines the syscall index for bf_control_op_wait |
## 2.8. Handle Syscalls
### 2.8.1. bf_handle_op_open_handle, OP=0x1, IDX=0x0
@ -685,9 +734,6 @@ This syscall closes a previously opened handle.
This syscall tells the microkernel to output RDI and RSI to the console device the microkernel is currently using for debugging.
**WARNING:**
In production builds of Bareflank, this syscall is not present.
**Input:**
| Register Name | Bits | Description |
| :------------ | :--- | :---------- |
@ -703,9 +749,6 @@ In production builds of Bareflank, this syscall is not present.
This syscall tells the microkernel to output a VM's state to the console device the microkernel is currently using for debugging.
**WARNING:**
In production builds of Bareflank, this syscall is not present.
**Input:**
| Register Name | Bits | Description |
| :------------ | :--- | :---------- |
@ -720,9 +763,6 @@ In production builds of Bareflank, this syscall is not present.
This syscall tells the microkernel to output a VP's state to the console device the microkernel is currently using for debugging.
**WARNING:**
In production builds of Bareflank, this syscall is not present.
**Input:**
| Register Name | Bits | Description |
| :------------ | :--- | :---------- |
@ -737,9 +777,6 @@ In production builds of Bareflank, this syscall is not present.
This syscall tells the microkernel to output a VPS's state to the console device the microkernel is currently using for debugging.
**WARNING:**
In production builds of Bareflank, this syscall is not present.
**Input:**
| Register Name | Bits | Description |
| :------------ | :--- | :---------- |
@ -752,15 +789,12 @@ In production builds of Bareflank, this syscall is not present.
### 2.9.5. bf_debug_op_dump_vmexit_log, OP=0x2, IDX=0x4
This syscall tells the microkernel to output the VMExit log. The VMExit log is a chronological log of the "X" number of exits that have occurred. The total number of "X" logs is implementation-defined and not under the control of software.
**WARNING:**
In production builds of Bareflank, this syscall is not present.
This syscall tells the microkernel to output the VMExit log. The VMExit log is a chronological log of the "X" number of exits that have occurred on a specific physical processor.
**Input:**
| Register Name | Bits | Description |
| :------------ | :--- | :---------- |
| REG0 | 63:0 | The VPID of the VP to dump the log from |
| REG0 | 63:0 | The PPID of the PP to dump the log from |
**const, bf_uint64_t: BF_DEBUG_OP_DUMP_VMEXIT_LOG_IDX_VAL**
| Value | Description |
@ -796,16 +830,39 @@ This syscall tells the microkernel to output a provided string to the microkerne
| :---- | :---------- |
| 0x0000000000000006 | Defines the syscall index for bf_debug_op_write_str |
## 2.10. Callback Syscalls
### 2.9.8. bf_debug_op_dump_ext, OP=0x2, IDX=0x7
### 2.10.1. bf_callback_op_wait, OP=0x3, IDX=0x0
This syscall tells the microkernel to output an extension's state to the console device the microkernel is currently using for debugging.
This syscall tells the microkernel that the extension would like to wait for a callback. This syscall is a blocking syscall that never returns and should be used to return from the _start function.
**Input:**
| Register Name | Bits | Description |
| :------------ | :--- | :---------- |
| REG0 | 63:0 | The EXTID of the extensions's state to output |
**const, bf_uint64_t: BF_CALLBACK_OP_WAIT_IDX_VAL**
**const, bf_uint64_t: BF_DEBUG_OP_DUMP_EXT_IDX_VAL**
| Value | Description |
| :---- | :---------- |
| 0x0000000000000000 | Defines the syscall index for bf_callback_op_wait |
| 0x0000000000000007 | Defines the syscall index for bf_debug_op_dump_ext |
### 2.9.9. bf_debug_op_dump_page_pool, OP=0x2, IDX=0x8
This syscall tells the microkernel to output the page pool's stats to the console device the microkernel is currently using for debugging.
**const, bf_uint64_t: BF_DEBUG_OP_DUMP_PAGE_POOL_IDX_VAL**
| Value | Description |
| :---- | :---------- |
| 0x0000000000000008 | Defines the syscall index for bf_debug_op_dump_page_pool |
### 2.9.10. bf_debug_op_dump_huge_pool, OP=0x2, IDX=0x9
This syscall tells the microkernel to output the huge pool's stats to the console device the microkernel is currently using for debugging.
**const, bf_uint64_t: BF_DEBUG_OP_DUMP_HUGE_POOL_IDX_VAL**
| Value | Description |
| :---- | :---------- |
| 0x0000000000000009 | Defines the syscall index for bf_debug_op_dump_huge_pool |
## 2.10. Callback Syscalls
### 2.10.2. bf_callback_op_register_bootstrap, OP=0x3, IDX=0x2
@ -856,6 +913,8 @@ This syscall tells the microkernel that the extension would like to receive call
A Virtual Machine or VM virtually represents a physical computer. Although the microkernel has an internal representation of a VM, it doesn't understand what a VM is outside of resource management, and it is up to the extension to define what a VM is and how it should operate.
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.11.1. Virtual Machine ID (VMID)
The Virtual Machine ID (VMID) is a 16bit number that uniquely identifies a VM.
@ -898,7 +957,9 @@ This syscall tells the microkernel to destroy a VM given an ID.
## 2.12. Virtual Processor Syscalls
TODO
A Virtual Processor or VP virtually represents a logical core. 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.
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.12.1. Virtual Processor ID (VPID)
@ -906,12 +967,16 @@ The Virtual Processor ID (VPID) is a 16bit number that uniquely identifies a VP.
### 2.12.2. bf_vp_op_create_vp, OP=0x5, IDX=0x0
This syscall tells the microkernel to create a VP and return its ID.
This syscall tells the microkernel to create a VP given the IDs of the VM and PP the VP will be assigned to. Upon success, this syscall returns the ID of the newly created VP.
**Input:**
| Register Name | Bits | Description |
| :------------ | :--- | :---------- |
| REG0 | 63:0 | Set to the result of bf_handle_op_open_handle |
| REG1 | 15:0 | The ID of the VM to assign the newly created VP to |
| REG1 | 63:16 | REVI |
| REG2 | 15:0 | The ID of the PP to assign the newly created VP to |
| REG2 | 63:16 | REVI |
**Output:**
| Register Name | Bits | Description |
@ -940,9 +1005,35 @@ This syscall tells the microkernel to destroy a VP given an ID.
| :---- | :---------- |
| 0x0000000000000001 | Defines the syscall index for bf_vp_op_destroy_vp |
### 2.12.3. bf_vp_op_migrate, OP=0x5, IDX=0x2
This syscall tells the microkernel to migrate a VP from one PP to another PP. This function does not execute the VP (use bf_vps_op_run for that), but instead allows bf_vps_op_run to execute a VP on a PP that it was not originally assigned to.
When a VP is migrated, all of the VPSs that are assigned to the requested VP are also migrated to this new PP as well. From an AMD/Intel point of view, this clears the VMCS/VMCB for each VPS assigned to the VP. On Intel, it also loads the newly cleared VPS and sets the launched state to false, ensuring the next bf_vps_op_run will use VMLaunch instead of VMResume.
It should be noted that the migration of a VPS from one PP to another does not happen during the execution of this ABI. This ABI simply tells the microkernel that the requested VP may now execute on the requested PP. This will cause a mismatch between the assigned PP for a VP and the assigned PP for a VPS. The microkernel will detect this mismatch when an extension attempts to execute bf_vps_op_run. When this occurs, the microkernel will ensure the VP is being run on the PP it was assigned to during migration, and then it will check to see if the PP of the VPS matches. If it doesn't, it will then perform a migration of that VPS at that time. This ensures that the microkernel is only migrations VPSs when it needs to, and it ensures the VPS is cleared an loaded (in the case of Intel) on the PP it will be executed on, which is a requirement for VMCS migration. An extension can determine which VPSs have been migrated by looking at the assigned PP of a VPS. If it doesn't match the VP it was assigned to, it has not been migrated. Finally, an extension is free to read/write to the VPSs state, even if it has not been migrated. The only requirement for migration is execution (meaning VMRun/VMLaunch/VMResume).
Any additional migration responsibilities, like TSC synchronization, must be performed by the extension.
**Input:**
| Register Name | Bits | Description |
| :------------ | :--- | :---------- |
| REG0 | 63:0 | Set to the result of bf_handle_op_open_handle |
| REG1 | 15:0 | The VPID of the VP to migrate |
| REG1 | 63:16 | REVI |
| REG2 | 15:0 | The ID of the PP to assign the provided VP to |
| REG2 | 63:16 | REVI |
**const, bf_uint64_t: BF_VP_OP_MIGRATE_IDX_VAL**
| Value | Description |
| :---- | :---------- |
| 0x0000000000000002 | Defines the syscall index for bf_vp_op_migrate |
### 2.12.4. Virtual Processor State Syscalls
TODO
A Virtual Processor State or VPS encapsulates the state associated with a virtual process. For example, on Intel this would be the VMCS, the registers that must be saved that the VMCS does not manage, and the general purpose registers.
Once a VPS is run, it is assigned to the VP it was run on, and cannot be run on any other VP for the remainder of it's lifetime. Since a VP is also assigned to a specific PP (physical processor), so is the VPS. When a VP is migrated, all VPSs assigned to that VP are also migrated.
### 2.12.5. Virtual Processor State ID (VPSID)
@ -950,12 +1041,16 @@ The Virtual Processor State ID (VPSID) is a 16bit number that uniquely identifie
### 2.12.6. bf_vps_op_create_vps, OP=0x6, IDX=0x0
This syscall tells the microkernel to create a VPS and return its ID.
This syscall tells the microkernel to create a VPS given the IDs of the VP and PP the VPS will be assigned to. Upon success, this syscall returns the ID of the newly created VPS.
**Input:**
| Register Name | Bits | Description |
| :------------ | :--- | :---------- |
| REG0 | 63:0 | Set to the result of bf_handle_op_open_handle |
| REG1 | 15:0 | The ID of the VP to assign the newly created VPS to |
| REG1 | 63:16 | REVI |
| REG2 | 15:0 | The ID of the PP to assign the newly created VPS to |
| REG2 | 63:16 | REVI |
**Output:**
| Register Name | Bits | Description |
@ -1002,7 +1097,7 @@ This syscall tells the microkernel to initialize a VPS using the root VP state p
### 2.12.9. bf_vps_op_read8, OP=0x6, IDX=0x3
bf_vps_op_read8 reads an 8bit field from the VPS and returns the value. The "index" is architecture-specific. For Intel, Appendix B, "Field Encoding in VMCS," defines the index (or encoding). For AMD, Appendix B, "Layout of VMCB," defines the index (or offset).
Reads an 8bit field from the VPS and returns the value. The "index" is architecture-specific. For Intel, Appendix B, "Field Encoding in VMCS," defines the index (or encoding). For AMD, Appendix B, "Layout of VMCB," defines the index (or offset).
**Input:**
| Register Name | Bits | Description |
@ -1025,7 +1120,7 @@ bf_vps_op_read8 reads an 8bit field from the VPS and returns the value. The "ind
### 2.12.10. bf_vps_op_read16, OP=0x6, IDX=0x4
bf_vps_op_read16 reads a 16bit field from the VPS and returns the value. The "index" is architecture-specific. For Intel, Appendix B, "Field Encoding in VMCS," defines the index (or encoding). For AMD, Appendix B, "Layout of VMCB," defines the index (or offset).
Reads a 16bit field from the VPS and returns the value. The "index" is architecture-specific. For Intel, Appendix B, "Field Encoding in VMCS," defines the index (or encoding). For AMD, Appendix B, "Layout of VMCB," defines the index (or offset).
**Input:**
| Register Name | Bits | Description |
@ -1048,7 +1143,7 @@ bf_vps_op_read16 reads a 16bit field from the VPS and returns the value. The "in
### 2.12.11. bf_vps_op_read32, OP=0x6, IDX=0x5
bf_vps_op_read32 reads a 32bit field from the VPS and returns the value. The "index" is architecture-specific. For Intel, Appendix B, "Field Encoding in VMCS," defines the index (or encoding). For AMD, Appendix B, "Layout of VMCB," defines the index (or offset).
Reads a 32bit field from the VPS and returns the value. The "index" is architecture-specific. For Intel, Appendix B, "Field Encoding in VMCS," defines the index (or encoding). For AMD, Appendix B, "Layout of VMCB," defines the index (or offset).
**Input:**
| Register Name | Bits | Description |
@ -1071,7 +1166,7 @@ bf_vps_op_read32 reads a 32bit field from the VPS and returns the value. The "in
### 2.12.12. bf_vps_op_read64, OP=0x6, IDX=0x6
bf_vps_op_read64 reads a 64bit field from the VPS and returns the value. The "index" is architecture-specific. For Intel, Appendix B, "Field Encoding in VMCS," defines the index (or encoding). For AMD, Appendix B, "Layout of VMCB," defines the index (or offset).
Reads a 64bit field from the VPS and returns the value. The "index" is architecture-specific. For Intel, Appendix B, "Field Encoding in VMCS," defines the index (or encoding). For AMD, Appendix B, "Layout of VMCB," defines the index (or offset).
**Input:**
| Register Name | Bits | Description |
@ -1093,7 +1188,7 @@ bf_vps_op_read64 reads a 64bit field from the VPS and returns the value. The "in
### 2.12.13. bf_vps_op_write8, OP=0x6, IDX=0x7
bf_vps_op_write8 writes to an 8bit field in the VPS. The "index" is architecture-specific. For Intel, Appendix B, "Field Encoding in VMCS," defines the index (or encoding). For AMD, Appendix B, "Layout of VMCB," defines the index (or offset).
Writes to an 8bit field in the VPS. The "index" is architecture-specific. For Intel, Appendix B, "Field Encoding in VMCS," defines the index (or encoding). For AMD, Appendix B, "Layout of VMCB," defines the index (or offset).
**Input:**
| Register Name | Bits | Description |
@ -1112,7 +1207,7 @@ bf_vps_op_write8 writes to an 8bit field in the VPS. The "index" is architecture
### 2.12.14. bf_vps_op_write16, OP=0x6, IDX=0x8
bf_vps_op_write16 writes to a 16bit field in the VPS. The "index" is architecture-specific. For Intel, Appendix B, "Field Encoding in VMCS," defines the index (or encoding). For AMD, Appendix B, "Layout of VMCB," defines the index (or offset).
Writes to a 16bit field in the VPS. The "index" is architecture-specific. For Intel, Appendix B, "Field Encoding in VMCS," defines the index (or encoding). For AMD, Appendix B, "Layout of VMCB," defines the index (or offset).
**Input:**
| Register Name | Bits | Description |
@ -1131,7 +1226,7 @@ bf_vps_op_write16 writes to a 16bit field in the VPS. The "index" is architectur
### 2.12.15. bf_vps_op_write32, OP=0x6, IDX=0x9
bf_vps_op_write32 writes to a 32bit field in the VPS. The "index" is architecture-specific. For Intel, Appendix B, "Field Encoding in VMCS," defines the index (or encoding). For AMD, Appendix B, "Layout of VMCB," defines the index (or offset).
Writes to a 32bit field in the VPS. The "index" is architecture-specific. For Intel, Appendix B, "Field Encoding in VMCS," defines the index (or encoding). For AMD, Appendix B, "Layout of VMCB," defines the index (or offset).
**Input:**
| Register Name | Bits | Description |
@ -1150,7 +1245,7 @@ bf_vps_op_write32 writes to a 32bit field in the VPS. The "index" is architectur
### 2.12.16. bf_vps_op_write64, OP=0x6, IDX=0xA
bf_vps_op_write64 writes to a 64bit field in the VPS. The "index" is architecture-specific. For Intel, Appendix B, "Field Encoding in VMCS," defines the index (or encoding). For AMD, Appendix B, "Layout of VMCB," defines the index (or offset).
Writes to a 64bit field in the VPS. The "index" is architecture-specific. For Intel, Appendix B, "Field Encoding in VMCS," defines the index (or encoding). For AMD, Appendix B, "Layout of VMCB," defines the index (or offset).
**Input:**
| Register Name | Bits | Description |
@ -1208,17 +1303,25 @@ Writes to a CPU register in the VPS given a bf_reg_t and the value to write. Not
### 2.12.19. bf_vps_op_run, OP=0x5, IDX=0xD
bf_vps_op_run tells the microkernel to execute a given VPS on behalf of a given VP and VM. This system call only returns if an error occurs. On success, this system call will physically execute the requested VP using the requested VPS, and the extension will only execute again on the next VMExit.
bf_vps_op_run tells the microkernel to execute a given VPS on behalf of a given VP and VM. This system call only returns if an error occurs. On success, this system call will physically execute the requested VM and VP using the requested VPS, and the extension will only execute again on the next VMExit.
Unless an extension needs to change the active VM, VP or VPS, the extension should use bf_vps_op_run_current instead of bf_vps_op_run. bf_vps_op_run is slow as it must perform a series of checks to determine if it has any work to perform before execution of a VM can occur.
Unlike bf_vps_op_run_current which is really just a return to microkernel execution, bf_vps_op_run must perform the following operations:
- It first verifies that the provided VM, VP and VPS are all created. Meaning, and extension must first use the create ABI to properly create a VM, VP and VPS before it may be used.
- Next, it must ensure VM, VP and VPS assignment is correct. A newly created VP and VPS are unassigned. Once bf_vps_op_run is executed, the VP is assigned to the provided VM and the VPS is assigned to the provided VP. The VP and VPS are also both assigned to the PP bf_vps_op_run is executed on. Once these assignments take place, an extension cannot change them, and any attempt to run a VP or VPS on a VM, VP or PP they are not assigned to will fail. It is impossible to change the assigned of a VM or VP, but an extension can change the assignment of a VP and VPSs PP by using the bf_vp_op_migrate function.
- Next, bf_vps_op_run must determine if it needs to migrate a VPS to the PP the VPS is being executed on by bf_vps_op_run. For more information about how this works, please see bf_vp_op_migrate.
- Finally, bf_vps_op_run must ensure the active VM, VP and VPS are set to the VM, VP and VPS provided to this ABI. Any changes in the active state could cause additional operations to take place. For example, the VPS must transfer the TLS state of the general purpose registers to its internal cache so that the VPS that is about to become active can use the TLS block instead.
**Input:**
| Register Name | Bits | Description |
| :------------ | :--- | :---------- |
| REG0 | 63:0 | Set to the result of bf_handle_op_open_handle |
| REG1 | 15:0 | The VPSID of the VPS to run |
| REG1 | 15:0 | The VMID of the VM to run |
| REG1 | 63:16 | REVI |
| REG2 | 15:0 | The VPID of the VP to run |
| REG2 | 63:16 | REVI |
| REG3 | 15:0 | The VMID of the VM to run |
| REG3 | 15:0 | The VPSID of the VPS to run |
| REG3 | 63:16 | REVI |
**const, bf_uint64_t: BF_VPS_OP_RUN_IDX_VAL**
@ -1258,14 +1361,12 @@ This syscall tells the microkernel to advance the instruction pointer in the req
### 2.12.22. bf_vps_op_advance_ip_and_run_current, OP=0x5, IDX=0x10
This syscall tells the microkernel to advance the instruction pointer in the requested VPS and run the currently active VPS, VP and VM (i.e., this combines bf_vps_op_advance_ip and bf_vps_op_advance_ip).
This syscall tells the microkernel to advance the instruction pointer in the currently active VPS and run the currently active VPS, VP and VM (i.e., this combines bf_vps_op_advance_ip and bf_vps_op_advance_ip).
**Input:**
| Register Name | Bits | Description |
| :------------ | :--- | :---------- |
| REG0 | 63:0 | Set to the result of bf_handle_op_open_handle |
| REG1 | 15:0 | The VPSID of the VPS advance the IP in |
| REG1 | 63:16 | REVI |
**const, bf_uint64_t: BF_VPS_OP_ADVANCE_IP_IDX_VAL**
| Value | Description |
@ -1288,11 +1389,27 @@ bf_vps_op_promote tells the microkernel to promote the requested VPS. bf_vps_op_
| :---- | :---------- |
| 0x0000000000000011 | Defines the syscall index for bf_vps_op_promote |
### 2.12.24. bf_vps_op_clear_vps, OP=0x5, IDX=0x11
bf_vps_op_clear_vps tells the microkernel to clear the VPS'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.
**Input:**
| Register Name | Bits | Description |
| :------------ | :--- | :---------- |
| REG0 | 63:0 | Set to the result of bf_handle_op_open_handle |
| REG1 | 15:0 | The VPSID of the VPS to clear |
| REG1 | 63:16 | REVI |
**const, bf_uint64_t: BF_VPS_OP_CLEAR_IDX_VAL**
| Value | Description |
| :---- | :---------- |
| 0x0000000000000012 | Defines the syscall index for bf_vps_op_clear_vps |
## 2.13. Intrinsic Syscalls
### 2.13.1. bf_intrinsic_op_read_msr, OP=0x7, IDX=0x0
### 2.13.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.
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.
**Input:**
| Register Name | Bits | Description |
@ -1306,14 +1423,14 @@ Reads an MSR directly from the CPU given the address of the MSR to read. Note th
| :------------ | :--- | :---------- |
| REG0 | 63:0 | The resulting value |
**const, bf_uint64_t: BF_INTRINSIC_OP_READ_MSR_IDX_VAL**
**const, bf_uint64_t: BF_INTRINSIC_OP_RDMSR_IDX_VAL**
| Value | Description |
| :---- | :---------- |
| 0x0000000000000000 | Defines the syscall index for bf_intrinsic_op_read_msr |
| 0x0000000000000000 | Defines the syscall index for bf_intrinsic_op_rdmsr |
### 2.13.2. bf_intrinsic_op_write_msr, OP=0x7, IDX=0x1
### 2.13.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.
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.
**Input:**
| Register Name | Bits | Description |
@ -1323,10 +1440,60 @@ Writes to an MSR directly from the CPU given the address of the MSR to write and
| REG1 | 63:32 | REVI |
| REG2 | 63:0 | The value to write to the requested MSR |
**const, bf_uint64_t: BF_INTRINSIC_OP_WRITE_MSR_IDX_VAL**
**const, bf_uint64_t: BF_INTRINSIC_OP_WRMSR_IDX_VAL**
| Value | Description |
| :---- | :---------- |
| 0x0000000000000001 | Defines the syscall index for bf_intrinsic_op_write_msr |
| 0x0000000000000001 | Defines the syscall index for bf_intrinsic_op_wrmsr |
### 2.13.3. bf_intrinsic_op_invlpga, OP=0x7, IDX=0x2
Invalidates the TLB mapping for a given virtual page and a given ASID. Note that this is specific to AMD only.
**Input:**
| Register Name | Bits | Description |
| :------------ | :--- | :---------- |
| REG0 | 63:0 | Set to the result of bf_handle_op_open_handle |
| REG1 | 63:0 | The address to invalidate |
| REG2 | 63:0 | The ASID to invalidate |
**const, bf_uint64_t: BF_INTRINSIC_OP_INVLPGA_IDX_VAL**
| Value | Description |
| :---- | :---------- |
| 0x0000000000000002 | Defines the syscall index for bf_intrinsic_op_invlpga |
### 2.13.4. bf_intrinsic_op_invept, OP=0x7, IDX=0x3
Invalidates mappings in the translation lookaside buffers (TLBs) and paging-structure caches that were derived from extended page tables (EPT). Note that this is specific to Intel only.
**Input:**
| Register Name | Bits | Description |
| :------------ | :--- | :---------- |
| REG0 | 63:0 | Set to the result of bf_handle_op_open_handle |
| REG1 | 63:0 | The EPTP to invalidate |
| REG2 | 63:0 | The INVEPT type (see the Intel SDM for details) |
**const, bf_uint64_t: BF_INTRINSIC_OP_INVEPT_IDX_VAL**
| Value | Description |
| :---- | :---------- |
| 0x0000000000000003 | Defines the syscall index for bf_intrinsic_op_invept |
### 2.13.5. bf_intrinsic_op_invvpid, OP=0x7, IDX=0x4
Invalidates mappings in the translation lookaside buffers (TLBs) and paging-structure caches based on virtual-processor identifier (VPID). Note that this is specific to Intel only.
**Input:**
| Register Name | Bits | Description |
| :------------ | :--- | :---------- |
| REG0 | 63:0 | Set to the result of bf_handle_op_open_handle |
| REG1 | 63:0 | The address to invalidate |
| REG2 | 15:0 | The VPID to invalidate |
| REG2 | 63:16 | REVI |
| REG3 | 63:0 | The INVVPID type (see the Intel SDM for details) |
**const, bf_uint64_t: BF_INTRINSIC_OP_INVVPID_IDX_VAL**
| Value | Description |
| :---- | :---------- |
| 0x0000000000000004 | Defines the syscall index for bf_intrinsic_op_invvpid |
## 2.14. Mem Syscalls
@ -1337,26 +1504,20 @@ Each extension has access to several different memory pools:
- TLS (used for thread-local storage)
- The direct map
The page pool provides a means to allocate a page. Allocated pages are **not** mapped into the microkernel, and therefore are safe for storing secrets if needed (at least as safe as it is going to get). Page allocation (and freeing) is a slow process as several different page walks are involved.
The page pool provides a means to allocate a page.
The huge pool provides a method for allocating physically contiguous memory. This pool is small and platform-dependent (as in less than a megabyte total).
It should be noted that some microkernels may choose not to implement bf_mem_op_free_huge which is optional.
The heap pool provides memory that can only be grown or shrunk, meaning the memory must always remain contiguous. An extension is free to use heap memory or the page pool. Both unmap any allocated pages from the microkernel, and both are slow. The only difference between these two pools is the page pool can only allocate a single page at a time and may or may not be fragmented (depends on the implementation). The heap pool can allocate memory of any size (must be a multiple of a page) and never fragments. Freeing memory is also different. An extension can free any page from the page pool (although the virtual address associated with the page may remain allocated, meaning the memory is reusable, but the virtual address is not, leading to potential exhaustion of the virtual memory space). The heap pool can only be grown or shrunk, meaning the free operation reduces the heap pool's size.
The heap pool provides memory that can only be grown, meaning the memory must always remain virtually contiguous. An extension is free to use heap memory or the page pool. The only difference between these two pools is the page pool can only allocate a single page at a time and may or may not be fragmented (depends on the implementation). The heap pool can allocate memory of any size (must be a multiple of a page) and never fragments.
Allocations must all occur during the bootstrap phase of the extension. Once an extension has executed bf_vps_op_run, allocations are no longer allowed.
Thread-Local Storage (TLS) memory (typically allocated using `thread_local`) provides per-physical processor storage. The amount of TLS available to an extension is 1 page per physical processor.
Thread-Local Storage (TLS) memory (typically allocated using `thread_local`) provides per-thread storage. The amount of TLS available to an extension depends on the configuration of the hypervisor.
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 0x0000400000000000. An extension can access any physical address by simply adding 0x0000400000000000 to the physical address and dereferencing the resulting value. Note that not all extensions can access the direct map (depends on the microkernel's security policy), and not all physical addresses are accessible. For example, any physical address mapped into the microkernel or another extension cannot be mapped (meaning a physical address can only be mapped once by the entire hypervisor). The microkernel also provides a per-VM direct map to provide additional mitigations for transient execution attacks. This feature is seamless to an extension, meaning, so long as an extension has the right to map a physical address, any attempt to access a legal, physical address will successfully map.
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.14.1. bf_mem_op_alloc_page, OP=0x7, IDX=0x0
bf_mem_op_alloc_page allocates a page. When allocating a page, the extension should keep in mind the following:
- The microkernel removes the page from its address space, which requires a page walk, which means that this operation is slow.
- Virtual address to physical address conversions require a page walk, so they are slow.
- The microkernel does not support physical address to virtual address conversions.
- Whether or not bf_mem_op_free_page frees the allocated virtual address is implementation-specific and not known to the extension, which could lead to the virtual address space's exhaustion.
- The execution of bf_mem_op_free_page is also slow, as a page walk is also needed.
bf_mem_op_alloc_page allocates a page, and maps this page into the direct map of the VM.
**Input:**
| Register Name | Bits | Description |
@ -1376,7 +1537,7 @@ bf_mem_op_alloc_page allocates a page. When allocating a page, the extension sho
### 2.14.2. bf_mem_op_free_page, OP=0x7, IDX=0x1
Frees a page previously allocated by bf_mem_op_alloc_page. For more information, please see bf_mem_op_alloc_page.
Frees a page previously allocated by bf_mem_op_alloc_page. This operation is optional and not all microkernels may implement it.
**Input:**
| Register Name | Bits | Description |
@ -1396,36 +1557,67 @@ Frees a page previously allocated by bf_mem_op_alloc_page. For more information,
### 2.14.3. bf_mem_op_alloc_huge, OP=0x7, IDX=0x2
TBD
### 2.14.4. bf_mem_op_free_huge, OP=0x7, IDX=0x3
TBD
### 2.14.5. bf_mem_op_alloc_heap, OP=0x7, IDX=0x4
TBD
### 2.14.6. bf_mem_op_free_heap, OP=0x7, IDX=0x5
TBD
### 2.14.7. bf_mem_op_virt_to_phys, OP=0x7, IDX=0x6
bf_mem_op_virt_to_phys converts a provided virtual address to a physical address for any virtual address allocated using bf_mem_op_alloc_page, bf_mem_op_alloc_huge, bf_mem_op_alloc_heap or mapped using the direct map.
bf_mem_op_alloc_huge allocates a physically contiguous block of memory. When allocating a page, the extension should keep in mind the following:
- The total memory available to allocate from this pool is extremely limited. This should only be used when absolutely needed, and extensions should not expect more than 1 MB (might be less) of total memory available.
- Memory allocated from the huge pool might be allocated using different schemes. For example, the microkernel might allocate in increments of a page, or it might use a buddy allocator that would allocate in multiples of 2. If the allocation size doesn't match the algorithm, internal fragmentation could occur, further limiting the total number of allocations this pool can support.
**Input:**
| Register Name | Bits | Description |
| :------------ | :--- | :---------- |
| REG0 | 63:0 | Set to the result of bf_handle_op_open_handle |
| REG1 | 63:0 | The virtual address of the page to convert |
| REG1 | 63:0 | The total number of bytes to allocate |
**Output:**
| Register Name | Bits | Description |
| :------------ | :--- | :---------- |
| REG0 | 63:0 | The physical address of the provided virtual address |
| REG0 | 63:0 | The virtual address of the resulting memory |
| REG1 | 63:0 | The physical address of the resulting memory |
**const, bf_uint64_t: BF_MEM_OP_VIRT_TO_PHYS_IDX_VAL**
**const, bf_uint64_t: BF_MEM_OP_ALLOC_HUGE_IDX_VAL**
| Value | Description |
| :---- | :---------- |
| 0x0000000000000006 | Defines the syscall index for bf_mem_op_virt_to_phys |
| 0x0000000000000002 | Defines the syscall index for bf_mem_op_alloc_huge |
### 2.14.4. bf_mem_op_free_huge, OP=0x7, IDX=0x3
Frees memory previously allocated by bf_mem_op_alloc_huge. This operation is optional and not all microkernels may implement it.
**Input:**
| Register Name | Bits | Description |
| :------------ | :--- | :---------- |
| REG0 | 63:0 | Set to the result of bf_handle_op_open_handle |
| REG1 | 63:0 | The virtual address of the memory to free |
**Output:**
| Register Name | Bits | Description |
| :------------ | :--- | :---------- |
**const, bf_uint64_t: BF_MEM_OP_FREE_HUGE_IDX_VAL**
| Value | Description |
| :---- | :---------- |
| 0x0000000000000003 | Defines the syscall index for bf_mem_op_free_huge |
### 2.14.5. bf_mem_op_alloc_heap, OP=0x7, IDX=0x4
bf_mem_op_alloc_heap allocates heap memory. When allocating heap memory, the extension should keep in mind the following:
- This ABI is designed to work similar to sbrk() to support malloc/free implementations common with existing open source libraries.
- Calling this ABI with with a size of 0 will return the current heap location.
- Calling this ABI with a size (in bytes) will result in return the previous heap location. The current heap location will be set to the previous location, plus the provide size, rounded to the nearest page size.
- The heap is not mapped into the direct map, so virtual to physical (and vice versa) translations are not possible.
- There is no ability to free heap memory
**Input:**
| Register Name | Bits | Description |
| :------------ | :--- | :---------- |
| REG0 | 63:0 | Set to the result of bf_handle_op_open_handle |
| REG1 | 63:0 | The number of bytes to increase the heap by |
**Output:**
| Register Name | Bits | Description |
| :------------ | :--- | :---------- |
| REG0 | 63:0 | The virtual address of the previous heap location |
**const, bf_uint64_t: BF_MEM_OP_ALLOC_HEAP_IDX_VAL**
| Value | Description |
| :---- | :---------- |
| 0x0000000000000004 | Defines the syscall index for bf_mem_op_alloc_heap |

27
docs/Optimizations.md Normal file
View file

@ -0,0 +1,27 @@
## Table of Contents <!-- omit in toc -->
# 1. Introduction
This document describes some of the reasoning behind certain optimization, or the lack there of.
# 2. VM, VP and VPS Pools
The VM, VP and VPS pools used to use a combination of an array and a linked list. THe ID given to each resource is the resource's position in the array. This allows any API to access the resource using it's ID, which is fast and simple. Allocations, however, used a linked list. Basically, each resource stored a "next" pointer which the pools could use to turn the array into a linked list. This provided a means to allocate using O(1). In otherwords, all operations for each resource, including accesses, allocations and deallocations were all O(1) which is fast.
This was changed to remove the linked list portion for a couple of reasons. To start, the next pointer adds memory usage. This memory usage is small, so by itself is not enough to remove the linked list. The main reason for removing the linked list is stability. Even if Bareflank is configured to have access to the max of 32767 resources for a VM, VP and VPS, O(N) in this case is not unreasonable. There are other operations that must take place other than just allocations that are O(N). For example, the microkernel must ensure that when a VM is destroyed, it is not active on any PPs, and that no VPs are assigned to it. All of these operations are all O(N), or we would need additional linked lists to reduce the overall time required to perform these checks. Each linked list not only adds additional memory requirements, but most importantly, it adds additional complexity to the microkernel.
For example, suppose in the process of performing a deallocation, a null dereference occurs in the microkernel. If this happens, the microkernel needs to mark the resource as a zombie as it was not properly deallocated. Now lets say the microkernel needs to allocate a new resource. If the zombie resource is the head (which it will eventually become), the microkernel would fail as it would have allocated a zombie resource. This means that in addition to the added complexity of the linked lists, the microkernel needs added logic for handling when it attempts to allocate a resource that is a zombie. It also needs added logic for handling when the linked list is not properly linked. There are many more examples of these types of issues. Each linked list adds a lot of extra logic that must be compiled into the code (which also adds to the size of the microkernel), unit tested, etc.
For these reasons, we simply loop through the arrays when attempting to do allocations. The move from O(1) to O(N) does mean that as N increases, allocations will take longer, but in the grand scheme of things, the reduction in overall complexity is worth it, as there are far fewer edge cases that must be considered, and a lot less state that must be properly handled in the event of unexpected errors.
# 3. Release and MinSizeRel Modes
The difference between bsl::unlikely and bsl::unlikely_assert (and the bsl::likely and bsl::finally equivalents) is that in Release and MinSizeRel mode, calls to these functions are optimized out, meaning they will not be executed.
There are a number of debugging checks that code must have to ensure mods to the hypervisor do not break certain assumptions that during runtime will never actually occur. For example, when creating a VP, an extension must provide the VMID that the VP will be assigned to. The ABI specification states that the microkernel will ignore the upper bits of the field that do not contribute to a 16bit ID. What this means is that the ID will never overflow, in which case the error flag in the ID's safe integral will never trigger. The code for allocating a VP however cannot assume this and so it must check for an invalid VMID even through at runtime, this check will never trigger.
To overcome this, the bsl::unlikely and friends have assert versions of them that are compiled out in a Release and MinSizeRel mode. This optimization provides a massive reduction in the overall size of the microkernel and extensions that use the BSL as most of the error checks that are in the code are there for developers while they are making changes and not for runtime specific errors. Furthermore, this optimization not only removes the check (including the branch), but is also likely removes a bunch of string information that likely adds more to the overall size of the microkernel and extensions than the code itself.
These assert versions should not be used to validate correctness. Using the same example above, the microkernel needs to verify that the VMID is a valid VMID. Specifically, it needs to be allocated. If we use the assert version of bsl::unlikely, this check will not be included in a Release or MinSizeRel mode. Extensions that are well tested should never trigger this issue in a Release or MinSizeRel build, but the microkernel cannot assume this as this check is part of the ABI and must be enforced at all times. For this reason, use the assert versions of bsl::unlikely and friends only when the check cannot trigger at runtime assuming the microkernel has been properly tested, and never use the assert versions for validating correctness of the ABI, or some other configuration (including hardware) option that could change.
The assert versions should also not be used when passing an error code onto the callee of a function. Instead, the debugging statement should be programmed to use bsl::V or higher, meaning these extra debug statements will be compiled out, but the branch will remain. So in other words, bsl::unlikely_assert and friends would only ever be paired with a bsl::error() and not a bsl::print().

66
docs/Security.md Normal file
View file

@ -0,0 +1,66 @@
## Table of Contents <!-- omit in toc -->
# 1. Introduction
This document defines all of the security features that have been added to the design of the Bareflank Microkernel.
# 2. Features
TBD
# 3. Remaining Todos
The following documents all of the security related features that the microkernel still has to implement.
## 3.1. Meltdown
The microkernel currently doesn't protect against Meltdown. This is a problem because one of the goals of being able to support multiple user-space applications is so that we can create a vTPM app that stores vTPM secrets. This would dramatically improve the overall security of a vTPM as it would ensure that only that user-space application and possibly the microkernel can see the secrets in the vTPM, something other hypervisors will struggle with. If other user-space applications can use Meltdown to access these secrets, we have a problem.
There are basically two different ways to prevent this. We could either unmap all of the memory from the microkernel that we hand out to the user-space application, or we could set up a different CR3 between the kernel and the user-space application.
There are several issues with the first approach. First, the process of unmapping is slow, and causes issues with shootdowns, something the microkernel cannot really do as it has no way to IPI itself. The other issue is the microkernel doesn't have the ability to walk it's own page tables. It can only walk the page tables that are allocated for user-space. As a result, it cannot unmap. To solve this, we need to modify the loader to direct map all microkernel memory, including the memory used to store the microkernel's page tables. Since this is recursive, there are issues with running out of stack space in the kernel. In general, although this approach would be extremely effective, and generally faster during normal runtime operations, it is not a great solution and would add a lot of extra complexity.
The second option would be to provide a different CR3 for the microkernel. We already have this CR3, it is the m_system_rpt. We simply need to remove the microkernel aliases from the other RPTs that the extensions use, and then load the m_system_rpt whenever an extension is done executing, which includes the execute() function, the syscall dispatch logic, and the ESR logic (basically anywhere user-space can enter/exit the microkernel from). The problem with this approach is everything is currently marked as global inside the kernel to reduce the overhead of constantly swapping CR3. The global flag would have to be turned off (done in the loader), and we would need something like PCID to prevent the implementation from being insanely slow.
Adding a PCID requirement would severally limit which CPUs this code supports, especially on AMD which added this feature in Zen 3.
For now, we leave this security hole unpatched, but once we attempt to implement a vTPM, this issue should be resolved, and we will either have to implement option #1, or implement option #2 and deal with the massive performance hit systems will take that do not have PCID support.
## 3.2. Transient Execution Attacks
We need to complete any remaining patches for transient execution attacks. Current we have implemented retpoline, and the user-space direct map implementation should mitigate L1TF style attacks. Attacks like MDS are best handled by disabling HyperThreading or purchasing hardware that is not vulnerable to this style of attack. Besides Meltdown which is described above, we might have some others that still need to be completed.
## 3.3. Extension Physical Memory Mapping
We currently do not prevent user-space from mapping in any physical address. This means that a user-space application can map in memory from the microkernel or some other user-space application.
This is obviously an issue, and the solution is not simple. The microkernel has no idea what physical addresses are that it controls as it is given random physical memory from the loader.
There are basically three options to solve this issue. The first option is to walk the page tables of all extensions and the microkernel to see if the physical page that a user-space application is trying to map is owned by the hypervisor. If it is, it should never be mapped by the user-space application. The second approach is to only enable this security feature for the hypervisor when UEFI is used to load the hypervisor. In this case, the loader could be modified to allocate one giant block of memory for everything and then pull from this block of memory as it needs it. The address and size of this block of memory could then be given to the microkernel, and it could determine if a map is valid or not using a simple comparison. The third option is to store a list that contains all of the physical addresses that the hypervisor was provided by the loader. This is essentially how the older version of Bareflank works. This would require some sort of data structure to store this memory, and obviously would use a fair amount of memory itself just to store the physical address list, but would work for any loader. The downside to this approach is determining if a physical address is in the list would likely require the data structure to be a hash table, which we would have to implement from scratch.
Since the Windows/Linux loaders are only intended for developers, the second approach should work great and solve this problem in a way that is both fast, and simple. The only trick is ensuring that the loader pulls all of it's allocations from a single, contiguous block. For example, it could use the page pool argument in the start_vmm to determine the total number of pages that are allowed to be used by the entire hypervisor, and then all allocations come from that specific page pool. Any memory left is given to the microkernel as it's page pool. This would not only ensure a simple means to implement this feature, but it would also provide a nice way to reason about how much memory the hypervisor is using as the page pool would account for all memory allocated, including by the loader which it currently doesn't.
For now, this security issue is left unpatched.
## 3.4. KALSR
We currently do not implement KASLR like we did in the previous version of the hypervisor. To implement this, all addresses should have some random entropy added to them.
Specifically, all of the hypervisor constants are still needed, but we need to simply add some entropy to these values to ensure they are not fixed. The only constants that do not need entropy are the direct map constants as these are based on the size of 4-level paging and must remain fixed.
The other requirement that will be needed to make this work is ensuring that the microkernel and all of it's extensions are compiled as static PIE binaries. We still want "static" compilation because adding support for dynamic libraries would cause issues not only with the overall complexity, but also with retpoline as the PLT that is needed would have to run through an out-of-line retpoline which is not good for performance.
Like the old code, the ELF loader should always perform all relocations when the ELF is loaded (meaning lazy loading should not be implemented). In general, this security feature should be relatively easy to implement since we have already done it once before. The hardest part will be finding a way to generate random numbers.
## 3.5. Hardware Security Features
There are some additional kernel level security features that both Intel and AMD continue to implement that we have not yet implemented. We really should do a complete analysis of all of these features and make sure they are turned on when they can be.
It should be noted that some of them might be due to how the loader works. If any of the bits in CR0/CR4 are turned on, it is likely that the microkernel will inherit these features (which could also cause issues with support for future CPUs). Others like clearing the L1 cache that use MSRs need a full review and implementation where it makes sense.
One exception to this is SMAP. Right now, even if the loader attempts to enable SMAP (which it likely will), we set the RFLAGS to set SMAP disabled at all times. This is done by making sure that FMASK doesn't clear AC, that AC is set in the dispatch and ESR entry points, and that when calling into an extension using call_ext, that AC is disabled as unaligned memory accesses are performed all the time by the compiler which we don't really have control of. This was done to simplify the microkernel's assembly logic, but at some point this will need to be enabled, and we will have to have some way of determining if and when the SMAP instructions should be used depending on what hardware the system is on. Another option would be to simply set RFLAGs manually without using these new instructions. This would allow SMAP to be used on all hardware (as AC is not used in the microkernel, so changing it has no effect). Option #2 is likely the better solution as even the Linux kernel has struggled with this issue since userspace memory access has to occur in areas where performing a feature check is non-trial.
Finally, non of these features are turned on in the UEFI loader, and they should be. Basically, once we know what all of the security features are, and how to turn them on, we need to add this logic to the UEFI loader so that it can ensure the system is as secure as possible.
## 3.6 Support For Multiple Extensions
The microkernel already has a bunch of logic for handling more than one extension, but the main feature missing is IPC ABIs and the ability for one extension to signal another (which is the method for getting more than one extension to execute since we don't have a scheduler). Once multiple extensions are supported, downstream projects like MicroV can break their logic into different extensions which provides several security benefits. There is more details about how this would work in the ext_t.hpp file.
One detail that MicroV will need to pay attention to once it has more than one extension is how much memory the PV and emulation extensions are using. Ideally, these extensions (which has a communication path to a VM and are thus the first line of defense), should limit how much memory it maps in to as little as possible. They should also be prevented from executing syscalls as much as possible (see below). Again, if these extensions that communicate directly with the VM are ever compromised, or used as a path for transient execution attacks, keeping their access to data and syscalls to a minimum might result in the attack failing overall.
## 3.7 Syscall Policy
Once multiple extensions are supported, a syscall policy should be implemented to determine which extensions should be allowed to execute specific syscalls. This could then be used to prevent an emulation or PV extension (basically any extension that talks to a VM) from being able to perform certain actions that could further improve security.

28
docs/Testing.md Normal file
View file

@ -0,0 +1,28 @@
## Table of Contents <!-- omit in toc -->
# 1. Introduction
This document defines the testing methodology for Bareflank, and some notes
when writing tests.
# 2. Unit Tests
## 2.1 "constexpr"
As much of the code as possible is written as a constexpr. This means that the majority of the code can be compiled and executed at compile time from a static assert. This allows us to execute the unit tests while the code is being compiled, which ensures two things:
- When code is modified, the compiler not only checks for the correctness of the code, but also the correctness of the logic itself, making it far more difficult to make mistakes.
- Undefined behavior is mostly impossible as UB is not allowed in constexpr functions. We also use UBSAN to check for this, but in general, this check is not needed as the use of constexpr performs a much better and more reliable check than attempting to verify this at runtime using UBSAN.
Some of the code (e.g., the assembly logic) cannot be compiled as a constexpr. In these cases we usually provide a mock that is a constexpr, or we check to see if we are executing at compile-time and if we are, we return early, allowing the function to act as a constexpr at compile-time, avoiding the logic that is not constexpr friendly. For this reason, unit tests are always executed at both compile-time and run-time. All of the non-constexpr logic is tested at runtime to ensure that it is also tested.
## 2.2 Branch Tests
The unit tests come complete with 100% branch coverage in addition to function and line coverage. Bareflank's version of the Clang Tidy static analysis engine does not allow the use of boolean operators, and if statements are required to be in a specific form to ensure that line coverage should be the same as the branch coverage. When this does not end up being the case is when templates are used. Specifically, each template argument to a function or class creates a new copy of this function or class, and duplicates all of the branches. This means that all of the unit tests need to test every branch for every template type it is provided in the test. Since the test reports are merged across all tests, it is extremely important that template arguments are managed across all of the unit tests. Just providing a new implementation of an object that is passed to a function or class that takes a template is usually a bad idea is it will add requirements for other tests with a cascade style effect. Branch coverage is required to ensure compliance with ASIL/D so it is important that this is done properly. What this means is that the unit tests should have a single mock type, and that type should be capable of supporting all tests that are needed. In some cases, additional seams in the code are needed to support this.
## 2.3 Std C++
The BSL is fully compatible with the standard C++ library, so feel free to use standard C++ in a unit test if needed. Ideally, this is kept to a minimum to support systems that do not have access to a standard C++ library (especially on some RTOS operating systems). In these cases, the unit tests for these systems can be ignored, so keeping the use of the standard C++ library to a minimum is ideal, but when absolutely needed, it is supported.
# 3. Integration Tests
All of the ABIs that Bareflank supports have a complete set of integration tests to ensure they operate as expected at runtime. This ensures that all of the assembly code is also tested and works as expected. Note that the use of these integration tests on a specific system can be used to perform system level testing as well, meaning the integration tests can also be used to ensure that all of the code is working on each system tests. The examples also provide an additional level of system level testing as they exercise specific features on the system.

View file

@ -19,69 +19,173 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
# ------------------------------------------------------------------------------
# Notes
# ------------------------------------------------------------------------------
# - Extensions must be compiled with the extension toolchain. Bareflank's
# build systems already has support for configuring where your extension
# might be located. Please see the readme for more details.
#
# - If you set up the build system properly, HYPERVISOR_TARGET_ARCH and
# CMAKE_BUILD_TYPE will already be set for you, as well as most of the
# other HYPERVISOR_ variables that the microkernel can use.
#
# - The goal of each example is to prevent the need for any macros that the
# microkernel's build system already provides which is why some macros
# are duplicated here.
#
# ------------------------------------------------------------------------------
# Executable
# ------------------------------------------------------------------------------
add_executable(example_default)
# NOTE:
# - Include your headers and include directories
#
if(HYPERVISOR_TARGET_ARCH STREQUAL "AuthenticAMD" OR HYPERVISOR_TARGET_ARCH STREQUAL "GenuineIntel")
target_include_directories(example_default PRIVATE
x64
)
list(APPEND HEADERS
${CMAKE_CURRENT_LIST_DIR}/x64/common_arch_support.hpp
)
endif()
if(HYPERVISOR_TARGET_ARCH STREQUAL "AuthenticAMD")
target_include_directories(example_default PRIVATE
x64/amd
)
list(APPEND HEADERS
${CMAKE_CURRENT_LIST_DIR}/x64/amd/arch_support.hpp
)
elseif(HYPERVISOR_TARGET_ARCH STREQUAL "GenuineIntel")
target_include_directories(example_default PRIVATE
x64/intel
)
list(APPEND HEADERS
${CMAKE_CURRENT_LIST_DIR}/x64/intel/arch_support.hpp
)
else()
message(FATAL_ERROR "Unsupported HYPERVISOR_TARGET_ARCH: ${HYPERVISOR_TARGET_ARCH}")
endif()
# ------------------------------------------------------------------------------
# Macros
# ------------------------------------------------------------------------------
# NOTE:
# - Include your source files and dependencies
# - We use this macro to add source files to an executable because Ninja on
# Windows will not recompile without the dependencies being stated explicitly
# simpilar to how Visual Studio works. This simplifies the process.
#
target_sources(example_default PRIVATE
main.cpp
macro(example_target_source NAME SOURCE_FILE)
target_sources(${NAME} PRIVATE ${SOURCE_FILE})
set_property(SOURCE ${SOURCE_FILE} APPEND PROPERTY OBJECT_DEPENDS ${ARGN})
endmacro(example_target_source)
# ------------------------------------------------------------------------------
# Includes
# ------------------------------------------------------------------------------
# NOTE:
# - Add each include folder as needed. This is what allows us to handle
# each architecture. Common code simply calls into code that has the same
# name across all architectures, and the build system handles making sure
# the right code is compiled in. This prevents the need for any compile time
# macros in the code.
#
target_include_directories(example_default PRIVATE
include
src
)
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_default PRIVATE
x64/intrinsic_cpuid.S
target_include_directories(example_default PRIVATE
include/x64
src/x64
)
if(HYPERVISOR_TARGET_ARCH STREQUAL "AuthenticAMD")
target_include_directories(example_default PRIVATE
include/x64/amd
src/x64/amd
)
endif()
if(HYPERVISOR_TARGET_ARCH STREQUAL "GenuineIntel")
target_include_directories(example_default PRIVATE
include/x64/intel
src/x64/intel
)
endif()
endif()
if(HYPERVISOR_TARGET_ARCH STREQUAL "aarch64")
target_include_directories(example_default PRIVATE
include/arm/aarch64
src/arm/aarch64
)
endif()
if(HYPERVISOR_TARGET_ARCH STREQUAL "AuthenticAMD")
# target_sources(example_default PRIVATE
# )
elseif(HYPERVISOR_TARGET_ARCH STREQUAL "GenuineIntel")
# target_sources(example_default PRIVATE
# )
else()
message(FATAL_ERROR "Unsupported HYPERVISOR_TARGET_ARCH: ${HYPERVISOR_TARGET_ARCH}")
endif()
# ------------------------------------------------------------------------------
# Headers
# ------------------------------------------------------------------------------
# NOTE:
# - Include your libraries. Note that if you use our runtime libary,
# you must include it first, otherwise your extension will try to use
# files from the BSL that the runtime library is meant to replace.
# - We need to explicitly declare each header due to Windows dependency
# issues with header files.
#
list(APPEND HEADERS
${CMAKE_CURRENT_LIST_DIR}/include/dummy_t.hpp
${CMAKE_CURRENT_LIST_DIR}/src/bootstrap_t.hpp
${CMAKE_CURRENT_LIST_DIR}/src/fail_t.hpp
${CMAKE_CURRENT_LIST_DIR}/src/vp_pool_t.hpp
${CMAKE_CURRENT_LIST_DIR}/src/vp_t.hpp
${CMAKE_CURRENT_LIST_DIR}/src/vps_pool_t.hpp
)
if(HYPERVISOR_TARGET_ARCH STREQUAL "AuthenticAMD" OR HYPERVISOR_TARGET_ARCH STREQUAL "GenuineIntel")
list(APPEND HEADERS
${CMAKE_CURRENT_LIST_DIR}/src/x64/intrinsic_cpuid_impl.hpp
)
if(HYPERVISOR_TARGET_ARCH STREQUAL "AuthenticAMD")
list(APPEND HEADERS
${CMAKE_CURRENT_LIST_DIR}/include/x64/amd/arch_dummy_t.hpp
${CMAKE_CURRENT_LIST_DIR}/src/x64/amd/gs_t.hpp
${CMAKE_CURRENT_LIST_DIR}/src/x64/amd/tls_t.hpp
${CMAKE_CURRENT_LIST_DIR}/src/x64/amd/intrinsic_t.hpp
${CMAKE_CURRENT_LIST_DIR}/src/x64/amd/vmexit_t.hpp
${CMAKE_CURRENT_LIST_DIR}/src/x64/amd/vps_t.hpp
)
endif()
if(HYPERVISOR_TARGET_ARCH STREQUAL "GenuineIntel")
list(APPEND HEADERS
${CMAKE_CURRENT_LIST_DIR}/include/x64/intel/arch_dummy_t.hpp
${CMAKE_CURRENT_LIST_DIR}/src/x64/intel/gs_t.hpp
${CMAKE_CURRENT_LIST_DIR}/src/x64/intel/tls_t.hpp
${CMAKE_CURRENT_LIST_DIR}/src/x64/intel/intrinsic_t.hpp
${CMAKE_CURRENT_LIST_DIR}/src/x64/intel/vmexit_t.hpp
${CMAKE_CURRENT_LIST_DIR}/src/x64/intel/vps_t.hpp
)
endif()
endif()
if(HYPERVISOR_TARGET_ARCH STREQUAL "aarch64")
list(APPEND HEADERS
${CMAKE_CURRENT_LIST_DIR}/include/arm/aarch64/arch_dummy_t.hpp
${CMAKE_CURRENT_LIST_DIR}/src/arm/aarch64/gs_t.hpp
${CMAKE_CURRENT_LIST_DIR}/src/arm/aarch64/tls_t.hpp
${CMAKE_CURRENT_LIST_DIR}/src/arm/aarch64/intrinsic_t.hpp
${CMAKE_CURRENT_LIST_DIR}/src/arm/aarch64/vmexit_t.hpp
${CMAKE_CURRENT_LIST_DIR}/src/arm/aarch64/vps_t.hpp
)
endif()
# ------------------------------------------------------------------------------
# Sources
# ------------------------------------------------------------------------------
# NOTE:
# - Add the sources to the executable. See the note above about why we
# use the macro for doing this.
#
example_target_source(example_default src/main.cpp ${HEADERS})
if(HYPERVISOR_TARGET_ARCH STREQUAL "AuthenticAMD" OR HYPERVISOR_TARGET_ARCH STREQUAL "GenuineIntel")
example_target_source(example_default src/x64/intrinsic_cpuid_impl.S ${HEADERS})
endif()
# ------------------------------------------------------------------------------
# Libraries
# ------------------------------------------------------------------------------
# NOTE:
# - The only library that is probably needed here is the loader. If you are
# using C, you do not need the BSL, and you can provide your own syscall and
# runtime libraries if you want. We provide our own versions to make things
# easy, but if you prefer to implement your extension another way, you
# can do so. The microkernel's ABI is the only piece of code that the project
# is aiming to keep stable, so if it changes, you can continue to use an
# old implementation, or write your own.
#
target_link_libraries(example_default PRIVATE
@ -91,8 +195,25 @@ target_link_libraries(example_default PRIVATE
syscall
)
# ------------------------------------------------------------------------------
# Install
# ------------------------------------------------------------------------------
# NOTE:
# - Install your extension somewhere.
# - If this is a release or minsizerel build, we strip just to make the
# finaly executable as small as possible. Note that this is entirely
# optional and can be removed if you wish.
#
if(CMAKE_BUILD_TYPE STREQUAL RELEASE OR CMAKE_BUILD_TYPE STREQUAL MINSIZEREL)
add_custom_command(TARGET example_default POST_BUILD COMMAND ${CMAKE_STRIP} example_default)
endif()
# NOTE:
# - You can install wherever you want. We install into the bin folder,
# which the build system can find for starting/stopping the hypervisor.
# If you provide your own tools, you can install to wherever is easier
# for you.
#
install(TARGETS example_default DESTINATION bin)

View file

@ -0,0 +1,47 @@
/// @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_DUMMY_T_HPP
#define ARCH_DUMMY_T_HPP
#include <bsl/safe_integral.hpp>
namespace example
{
/// @class example::arch_dummy_t
///
/// <!-- description -->
/// @brief The only thing that should go in the include folder are
/// type defintions like this one that are not mocked in the unit
/// tests as the include folder is included in the unit tests. All
/// other code should be placed in the src folder.
///
struct arch_dummy_t final
{
/// @brief dummy data for example purposes only.
bsl::safe_uintmax dummy;
};
}
#endif

View file

@ -0,0 +1,47 @@
/// @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 DUMMY_T_HPP
#define DUMMY_T_HPP
#include <bsl/safe_integral.hpp>
namespace example
{
/// @class example::dummy_t
///
/// <!-- description -->
/// @brief The only thing that should go in the include folder are
/// type defintions like this one that are not mocked in the unit
/// tests as the include folder is included in the unit tests. All
/// other code should be placed in the src folder.
///
struct dummy_t final
{
/// @brief dummy data for example purposes only.
bsl::safe_uintmax dummy;
};
}
#endif

View file

@ -0,0 +1,47 @@
/// @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_DUMMY_T_HPP
#define ARCH_DUMMY_T_HPP
#include <bsl/safe_integral.hpp>
namespace example
{
/// @class example::arch_dummy_t
///
/// <!-- description -->
/// @brief The only thing that should go in the include folder are
/// type defintions like this one that are not mocked in the unit
/// tests as the include folder is included in the unit tests. All
/// other code should be placed in the src folder.
///
struct arch_dummy_t final
{
/// @brief dummy data for example purposes only.
bsl::safe_uintmax dummy;
};
}
#endif

View file

@ -0,0 +1,47 @@
/// @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_DUMMY_T_HPP
#define ARCH_DUMMY_T_HPP
#include <bsl/safe_integral.hpp>
namespace example
{
/// @class example::arch_dummy_t
///
/// <!-- description -->
/// @brief The only thing that should go in the include folder are
/// type defintions like this one that are not mocked in the unit
/// tests as the include folder is included in the unit tests. All
/// other code should be placed in the src folder.
///
struct arch_dummy_t final
{
/// @brief dummy data for example purposes only.
bsl::safe_uintmax dummy;
};
}
#endif

View file

@ -0,0 +1,42 @@
/// @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 MOCKS_GS_T_HPP
#define MOCKS_GS_T_HPP
#include <bsl/errc_type.hpp>
namespace example
{
/// @class example::gs_t
///
/// <!-- description -->
/// @brief Defines the extension's mocked version of gs_t, used for
/// unit testing.
///
struct gs_t final
{};
}
#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.
#ifndef MOCKS_TLS_T_HPP
#define MOCKS_TLS_T_HPP
#include <errc_types.hpp>
namespace example
{
/// @class example::tls_t
///
/// <!-- description -->
/// @brief Defines the extension's mocked version of tls_t, used for
/// unit testing.
///
struct tls_t final
{
/// @brief stores the return value for a test
bsl::errc_type test_ret;
};
}
#endif

View file

@ -0,0 +1,182 @@
/// @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 MOCKS_BOOTSTRAP_T_HPP
#define MOCKS_BOOTSTRAP_T_HPP
#include <bf_syscall_t.hpp>
#include <gs_t.hpp>
#include <intrinsic_t.hpp>
#include <tls_t.hpp>
#include <vp_pool_t.hpp>
#include <vps_pool_t.hpp>
#include <bsl/discard.hpp>
#include <bsl/errc_type.hpp>
#include <bsl/safe_integral.hpp>
namespace example
{
/// @class example::bootstrap_t
///
/// <!-- description -->
/// @brief Defines the extension's bootstrap handler used for unit
/// testing
///
class bootstrap_t final
{
/// @brief stores the return value for initialize
bsl::errc_type m_initialize{};
/// @brief stores the return value for dispatch
bsl::errc_type m_dispatch{};
public:
/// <!-- description -->
/// @brief Initializes this bootstrap_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
/// @param vp_pool the vp_pool_t to use
/// @param vps_pool the vps_pool_t to use
/// @return Returns bsl::errc_success on success, bsl::errc_failure
/// and friends otherwise
///
[[nodiscard]] constexpr auto
initialize(
gs_t &gs,
tls_t &tls,
syscall::bf_syscall_t &sys,
intrinsic_t &intrinsic,
vp_pool_t &vp_pool,
vps_pool_t &vps_pool) noexcept -> bsl::errc_type
{
bsl::discard(gs);
bsl::discard(tls);
bsl::discard(sys);
bsl::discard(intrinsic);
bsl::discard(vp_pool);
bsl::discard(vps_pool);
return m_initialize;
}
/// <!-- description -->
/// @brief Sets the return value of initialize.
/// (unit testing only)
///
/// <!-- inputs/outputs -->
/// @param errc the bsl::errc_type to return when executing
/// initialize
///
constexpr void
set_initialize(bsl::errc_type const &errc) noexcept
{
m_initialize = errc;
}
/// <!-- description -->
/// @brief Release the bootstrap_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
/// @param vp_pool the vp_pool_t to use
/// @param vps_pool the vps_pool_t to use
///
static constexpr void
release(
gs_t &gs,
tls_t &tls,
syscall::bf_syscall_t &sys,
intrinsic_t &intrinsic,
vp_pool_t &vp_pool,
vps_pool_t &vps_pool) noexcept
{
bsl::discard(gs);
bsl::discard(tls);
bsl::discard(sys);
bsl::discard(intrinsic);
bsl::discard(vp_pool);
bsl::discard(vps_pool);
}
/// <!-- 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 vps_pool the vps_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
///
[[nodiscard]] constexpr auto
dispatch(
gs_t &gs,
tls_t &tls,
syscall::bf_syscall_t &sys,
intrinsic_t &intrinsic,
vp_pool_t &vp_pool,
vps_pool_t &vps_pool,
bsl::safe_uint16 const &ppid) noexcept -> bsl::errc_type
{
bsl::discard(gs);
bsl::discard(tls);
bsl::discard(sys);
bsl::discard(intrinsic);
bsl::discard(vp_pool);
bsl::discard(vps_pool);
bsl::discard(ppid);
return m_dispatch;
}
/// <!-- description -->
/// @brief Sets the return value of dispatch.
/// (unit testing only)
///
/// <!-- inputs/outputs -->
/// @param errc the bsl::errc_type to return when executing
/// dispatch
///
constexpr void
set_dispatch(bsl::errc_type const &errc) noexcept
{
m_dispatch = errc;
}
};
}
#endif

View file

@ -0,0 +1,183 @@
/// @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 MOCKS_FAIL_T_HPP
#define MOCKS_FAIL_T_HPP
#include <bf_syscall_t.hpp>
#include <gs_t.hpp>
#include <intrinsic_t.hpp>
#include <tls_t.hpp>
#include <vp_pool_t.hpp>
#include <vps_pool_t.hpp>
#include <bsl/discard.hpp>
#include <bsl/errc_type.hpp>
#include <bsl/safe_integral.hpp>
namespace example
{
/// @class example::fail_t
///
/// <!-- description -->
/// @brief Defines the extension's fail handler used for unit testing
///
class fail_t final
{
/// @brief stores the return value for initialize
bsl::errc_type m_initialize{};
/// @brief stores the return value for dispatch
bsl::errc_type m_dispatch{};
public:
/// <!-- description -->
/// @brief Initializes this fail_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
/// @param vp_pool the vp_pool_t to use
/// @param vps_pool the vps_pool_t to use
/// @return Returns bsl::errc_success on success, bsl::errc_failure
/// and friends otherwise
///
[[nodiscard]] constexpr auto
initialize(
gs_t &gs,
tls_t &tls,
syscall::bf_syscall_t &sys,
intrinsic_t &intrinsic,
vp_pool_t &vp_pool,
vps_pool_t &vps_pool) noexcept -> bsl::errc_type
{
bsl::discard(gs);
bsl::discard(tls);
bsl::discard(sys);
bsl::discard(intrinsic);
bsl::discard(vp_pool);
bsl::discard(vps_pool);
return m_initialize;
}
/// <!-- description -->
/// @brief Sets the return value of initialize.
/// (unit testing only)
///
/// <!-- inputs/outputs -->
/// @param errc the bsl::errc_type to return when executing
/// initialize
///
constexpr void
set_initialize(bsl::errc_type const &errc) noexcept
{
m_initialize = errc;
}
/// <!-- description -->
/// @brief Release the fail_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
/// @param vp_pool the vp_pool_t to use
/// @param vps_pool the vps_pool_t to use
///
static constexpr void
release(
gs_t &gs,
tls_t &tls,
syscall::bf_syscall_t &sys,
intrinsic_t &intrinsic,
vp_pool_t &vp_pool,
vps_pool_t &vps_pool) noexcept
{
bsl::discard(gs);
bsl::discard(tls);
bsl::discard(sys);
bsl::discard(intrinsic);
bsl::discard(vp_pool);
bsl::discard(vps_pool);
}
/// <!-- 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 vps_pool the vps_pool_t to use
/// @param vpsid the ID of the VPS that generated the fail
/// @param fail_reason the exit reason associated with the fail
/// @return Returns bsl::errc_success on success, bsl::errc_failure
/// and friends otherwise
///
[[nodiscard]] constexpr auto
dispatch(
gs_t &gs,
tls_t &tls,
syscall::bf_syscall_t &sys,
intrinsic_t &intrinsic,
vp_pool_t &vp_pool,
vps_pool_t &vps_pool,
bsl::safe_uint16 const &vpsid,
bsl::safe_uint64 const &fail_reason) noexcept -> bsl::errc_type
{
bsl::discard(gs);
bsl::discard(tls);
bsl::discard(sys);
bsl::discard(intrinsic);
bsl::discard(vp_pool);
bsl::discard(vps_pool);
bsl::discard(vpsid);
bsl::discard(fail_reason);
return m_dispatch;
}
/// <!-- description -->
/// @brief Sets the return value of dispatch.
/// (unit testing only)
///
/// <!-- inputs/outputs -->
/// @param errc the bsl::errc_type to return when executing
/// dispatch
///
constexpr void
set_dispatch(bsl::errc_type const &errc) noexcept
{
m_dispatch = errc;
}
};
}
#endif

View file

@ -0,0 +1,41 @@
/// @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 MOCKS_GS_T_HPP
#define MOCKS_GS_T_HPP
namespace example
{
/// @class example::gs_t
///
/// <!-- description -->
/// @brief Defines the extension's mocked version of gs_t, used for
/// unit testing. Specifically, this version only contains portions
/// that are common for all architectures.
///
struct gs_t final
{};
}
#endif

View file

@ -0,0 +1,97 @@
/// @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 MOCKS_INTRINSIC_HPP
#define MOCKS_INTRINSIC_HPP
#include <gs_t.hpp>
#include <tls_t.hpp>
#include <bsl/discard.hpp>
#include <bsl/errc_type.hpp>
namespace example
{
/// @class example::intrinsic_t
///
/// <!-- description -->
/// @brief Provides raw access to intrinsics used for unit testing.
/// Specifically, this version only contains portions that are common
/// for all architectures.
///
class intrinsic_t final
{
/// @brief stores the return value for initialize
bsl::errc_type m_initialize{};
public:
/// <!-- description -->
/// @brief Initializes this intrinsic_t.
///
/// <!-- inputs/outputs -->
/// @param gs the gs_t to use
/// @param tls the tls_t to use
/// @return Returns bsl::errc_success on success, bsl::errc_failure
/// and friends otherwise
///
[[nodiscard]] constexpr auto
initialize(gs_t &gs, tls_t &tls) noexcept -> bsl::errc_type
{
bsl::discard(gs);
bsl::discard(tls);
return m_initialize;
}
/// <!-- description -->
/// @brief Sets the return value of initialize.
/// (unit testing only)
///
/// <!-- inputs/outputs -->
/// @param errc the bsl::errc_type to return when executing
/// initialize
///
constexpr void
set_initialize(bsl::errc_type const &errc) noexcept
{
m_initialize = errc;
}
/// <!-- description -->
/// @brief Release the intrinsic_t.
///
/// <!-- inputs/outputs -->
/// @param gs the gs_t to use
/// @param tls the tls_t to use
///
static constexpr void
release(gs_t &gs, tls_t &tls) noexcept
{
bsl::discard(gs);
bsl::discard(tls);
}
};
}
#endif

View file

@ -0,0 +1,46 @@
/// @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 MOCKS_TLS_T_HPP
#define MOCKS_TLS_T_HPP
#include <bsl/errc_type.hpp>
namespace example
{
/// @class example::tls_t
///
/// <!-- description -->
/// @brief Defines the extension's mocked version of tls_t, used for
/// unit testing. Specifically, this version only contains portions
/// that are common for all architectures.
///
struct tls_t final
{
/// @brief tells certain mocks when to fail
bsl::errc_type test_ret;
};
}
#endif

View file

@ -0,0 +1,183 @@
/// @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 MOCKS_VMEXIT_T_HPP
#define MOCKS_VMEXIT_T_HPP
#include <bf_syscall_t.hpp>
#include <gs_t.hpp>
#include <intrinsic_t.hpp>
#include <tls_t.hpp>
#include <vp_pool_t.hpp>
#include <vps_pool_t.hpp>
#include <bsl/debug.hpp>
#include <bsl/discard.hpp>
#include <bsl/errc_type.hpp>
#include <bsl/safe_integral.hpp>
namespace example
{
/// @class example::vmexit_t
///
/// <!-- description -->
/// @brief Defines the extension's VMExit handler
///
class vmexit_t final
{
/// @brief stores the return value for initialize
bsl::errc_type m_initialize{};
/// @brief stores the return value for dispatch
bsl::errc_type m_dispatch{};
public:
/// <!-- description -->
/// @brief Initializes this vmexit_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
/// @param vp_pool the vp_pool_t to use
/// @param vps_pool the vps_pool_t to use
/// @return Returns bsl::errc_success on success, bsl::errc_failure
/// and friends otherwise
///
[[nodiscard]] constexpr auto
initialize(
gs_t &gs,
tls_t &tls,
syscall::bf_syscall_t &sys,
intrinsic_t &intrinsic,
vp_pool_t &vp_pool,
vps_pool_t &vps_pool) noexcept -> bsl::errc_type
{
bsl::discard(gs);
bsl::discard(tls);
bsl::discard(sys);
bsl::discard(intrinsic);
bsl::discard(vp_pool);
bsl::discard(vps_pool);
return m_initialize;
}
/// <!-- description -->
/// @brief Sets the return value of initialize.
/// (unit testing only)
///
/// <!-- inputs/outputs -->
/// @param errc the bsl::errc_type to return when executing
/// initialize
///
constexpr void
set_initialize(bsl::errc_type const &errc) noexcept
{
m_initialize = errc;
}
/// <!-- description -->
/// @brief Release the vmexit_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
/// @param vp_pool the vp_pool_t to use
/// @param vps_pool the vps_pool_t to use
///
static constexpr void
release(
gs_t &gs,
tls_t &tls,
syscall::bf_syscall_t &sys,
intrinsic_t &intrinsic,
vp_pool_t &vp_pool,
vps_pool_t &vps_pool) noexcept
{
bsl::discard(gs);
bsl::discard(tls);
bsl::discard(sys);
bsl::discard(intrinsic);
bsl::discard(vp_pool);
bsl::discard(vps_pool);
}
/// <!-- 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 vps_pool the vps_pool_t to use
/// @param vpsid the ID of the VPS 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
///
[[nodiscard]] constexpr auto
dispatch(
gs_t &gs,
tls_t &tls,
syscall::bf_syscall_t &sys,
intrinsic_t &intrinsic,
vp_pool_t &vp_pool,
vps_pool_t &vps_pool,
bsl::safe_uint16 const &vpsid,
bsl::safe_uint64 const &exit_reason) noexcept -> bsl::errc_type
{
bsl::discard(gs);
bsl::discard(tls);
bsl::discard(sys);
bsl::discard(intrinsic);
bsl::discard(vp_pool);
bsl::discard(vps_pool);
bsl::discard(vpsid);
bsl::discard(exit_reason);
return m_dispatch;
}
/// <!-- description -->
/// @brief Sets the return value of dispatch.
/// (unit testing only)
///
/// <!-- inputs/outputs -->
/// @param errc the bsl::errc_type to return when executing
/// dispatch
///
constexpr void
set_dispatch(bsl::errc_type const &errc) noexcept
{
m_dispatch = errc;
}
};
}
#endif

View file

@ -0,0 +1,156 @@
/// @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 MOCKS_VP_POOL_T_HPP
#define MOCKS_VP_POOL_T_HPP
#include <bf_syscall_t.hpp>
#include <gs_t.hpp>
#include <intrinsic_t.hpp>
#include <tls_t.hpp>
#include <bsl/discard.hpp>
#include <bsl/errc_type.hpp>
#include <bsl/safe_integral.hpp>
namespace example
{
/// @class example::vp_pool_t
///
/// <!-- description -->
/// @brief Defines the extension's VP pool
///
class vp_pool_t final
{
/// @brief stores the return value for initialize
bsl::errc_type m_initialize{};
/// @brief stores the return value for allocate
bsl::safe_uint16 m_allocate{};
public:
/// <!-- 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
/// @return Returns bsl::errc_success on success, bsl::errc_failure
/// and friends otherwise
///
[[nodiscard]] constexpr auto
initialize(
gs_t &gs, tls_t &tls, syscall::bf_syscall_t &sys, intrinsic_t &intrinsic) noexcept
-> bsl::errc_type
{
bsl::discard(gs);
bsl::discard(tls);
bsl::discard(sys);
bsl::discard(intrinsic);
return m_initialize;
}
/// <!-- description -->
/// @brief Sets the return value of initialize.
/// (unit testing only)
///
/// <!-- inputs/outputs -->
/// @param errc the bsl::errc_type to return when executing
/// initialize
///
constexpr void
set_initialize(bsl::errc_type const &errc) noexcept
{
m_initialize = errc;
}
/// <!-- 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
///
static constexpr void
release(gs_t &gs, tls_t &tls, syscall::bf_syscall_t &sys, intrinsic_t &intrinsic) noexcept
{
bsl::discard(gs);
bsl::discard(tls);
bsl::discard(sys);
bsl::discard(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
/// @param ppid the ID of the PP to assign the newly created VP to
/// @return Returns the ID of the newly created VP on
/// success, or bsl::safe_uint16::failure() on failure.
///
[[nodiscard]] constexpr auto
allocate(
gs_t &gs,
tls_t &tls,
syscall::bf_syscall_t &sys,
intrinsic_t &intrinsic,
bsl::safe_uint16 const &vmid,
bsl::safe_uint16 const &ppid) noexcept -> bsl::safe_uint16
{
bsl::discard(gs);
bsl::discard(tls);
bsl::discard(sys);
bsl::discard(intrinsic);
bsl::discard(vmid);
bsl::discard(ppid);
return m_allocate;
}
/// <!-- description -->
/// @brief Sets the return value of allocate.
/// (unit testing only)
///
/// <!-- inputs/outputs -->
/// @param val the bsl::safe_uint16 to return when executing
/// allocate
///
constexpr void
set_allocate(bsl::safe_uint16 const &val) noexcept
{
m_allocate = val;
}
};
}
#endif

View file

@ -0,0 +1,126 @@
/// @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 MOCKS_VP_T_HPP
#define MOCKS_VP_T_HPP
#include <bf_syscall_t.hpp>
#include <gs_t.hpp>
#include <intrinsic_t.hpp>
#include <tls_t.hpp>
#include <bsl/discard.hpp>
#include <bsl/errc_type.hpp>
#include <bsl/safe_integral.hpp>
namespace example
{
/// @class example::vp_t
///
/// <!-- description -->
/// @brief Defines the extension's notion of a VP for unit testing.
///
class vp_t final
{
public:
/// <!-- description -->
/// @brief Initializes this vp_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
/// @param i the ID for this vp_t
/// @return Returns bsl::errc_success on success, bsl::errc_failure
/// and friends otherwise
///
[[nodiscard]] static constexpr auto
initialize(
gs_t &gs,
tls_t &tls,
syscall::bf_syscall_t &sys,
intrinsic_t &intrinsic,
bsl::safe_uint16 const &i) noexcept -> bsl::errc_type
{
bsl::discard(gs);
bsl::discard(sys);
bsl::discard(intrinsic);
bsl::discard(i);
return tls.test_ret;
}
/// <!-- description -->
/// @brief Release the vp_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
///
static constexpr void
release(gs_t &gs, tls_t &tls, syscall::bf_syscall_t &sys, intrinsic_t &intrinsic) noexcept
{
bsl::discard(gs);
bsl::discard(tls);
bsl::discard(sys);
bsl::discard(intrinsic);
}
/// <!-- description -->
/// @brief Allocates a vp_t 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 vp_t to
/// @param ppid the ID of the PP to assign the vp_t to
/// @return Returns bsl::errc_success on success, bsl::errc_failure
/// and friends otherwise
///
[[nodiscard]] static constexpr auto
allocate(
gs_t &gs,
tls_t &tls,
syscall::bf_syscall_t &sys,
intrinsic_t &intrinsic,
bsl::safe_uint16 const &vmid,
bsl::safe_uint16 const &ppid) noexcept -> bsl::errc_type
{
bsl::discard(gs);
bsl::discard(sys);
bsl::discard(intrinsic);
bsl::discard(vmid);
bsl::discard(ppid);
return tls.test_ret;
}
};
}
#endif

View file

@ -0,0 +1,156 @@
/// @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 MOCKS_VPS_POOL_T_HPP
#define MOCKS_VPS_POOL_T_HPP
#include <bf_syscall_t.hpp>
#include <gs_t.hpp>
#include <intrinsic_t.hpp>
#include <tls_t.hpp>
#include <bsl/discard.hpp>
#include <bsl/errc_type.hpp>
#include <bsl/safe_integral.hpp>
namespace example
{
/// @class example::vps_pool_t
///
/// <!-- description -->
/// @brief Defines the extension's VPS pool
///
class vps_pool_t final
{
/// @brief stores the return value for initialize
bsl::errc_type m_initialize{};
/// @brief stores the return value for allocate
bsl::safe_uint16 m_allocate{};
public:
/// <!-- description -->
/// @brief Initializes this vps_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
/// @return Returns bsl::errc_success on success, bsl::errc_failure
/// and friends otherwise
///
[[nodiscard]] constexpr auto
initialize(
gs_t &gs, tls_t &tls, syscall::bf_syscall_t &sys, intrinsic_t &intrinsic) noexcept
-> bsl::errc_type
{
bsl::discard(gs);
bsl::discard(tls);
bsl::discard(sys);
bsl::discard(intrinsic);
return m_initialize;
}
/// <!-- description -->
/// @brief Sets the return value of initialize.
/// (unit testing only)
///
/// <!-- inputs/outputs -->
/// @param errc the bsl::errc_type to return when executing
/// initialize
///
constexpr void
set_initialize(bsl::errc_type const &errc) noexcept
{
m_initialize = errc;
}
/// <!-- description -->
/// @brief Release the vps_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
///
static constexpr void
release(gs_t &gs, tls_t &tls, syscall::bf_syscall_t &sys, intrinsic_t &intrinsic) noexcept
{
bsl::discard(gs);
bsl::discard(tls);
bsl::discard(sys);
bsl::discard(intrinsic);
}
/// <!-- description -->
/// @brief Allocates a VPS 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 VPS to
/// @param ppid the ID of the PP to assign the newly created VPS to
/// @return Returns the ID of the newly created VPS on
/// success, or bsl::safe_uint16::failure() on failure.
///
[[nodiscard]] constexpr auto
allocate(
gs_t &gs,
tls_t &tls,
syscall::bf_syscall_t &sys,
intrinsic_t &intrinsic,
bsl::safe_uint16 const &vpid,
bsl::safe_uint16 const &ppid) noexcept -> bsl::safe_uint16
{
bsl::discard(gs);
bsl::discard(tls);
bsl::discard(sys);
bsl::discard(intrinsic);
bsl::discard(vpid);
bsl::discard(ppid);
return m_allocate;
}
/// <!-- description -->
/// @brief Sets the return value of allocate.
/// (unit testing only)
///
/// <!-- inputs/outputs -->
/// @param val the bsl::safe_uint16 to return when executing
/// allocate
///
constexpr void
set_allocate(bsl::safe_uint16 const &val) noexcept
{
m_allocate = val;
}
};
}
#endif

View file

@ -0,0 +1,126 @@
/// @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 MOCKS_VPS_T_HPP
#define MOCKS_VPS_T_HPP
#include <bf_syscall_t.hpp>
#include <gs_t.hpp>
#include <intrinsic_t.hpp>
#include <tls_t.hpp>
#include <bsl/discard.hpp>
#include <bsl/errc_type.hpp>
#include <bsl/safe_integral.hpp>
namespace example
{
/// @class example::vps_t
///
/// <!-- description -->
/// @brief Defines the extension's notion of a VPS for unit testing.
///
class vps_t final
{
public:
/// <!-- description -->
/// @brief Initializes this vps_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
/// @param i the ID for this vps_t
/// @return Returns bsl::errc_success on success, bsl::errc_failure
/// and friends otherwise
///
[[nodiscard]] static constexpr auto
initialize(
gs_t &gs,
tls_t &tls,
syscall::bf_syscall_t &sys,
intrinsic_t &intrinsic,
bsl::safe_uint16 const &i) noexcept -> bsl::errc_type
{
bsl::discard(gs);
bsl::discard(sys);
bsl::discard(intrinsic);
bsl::discard(i);
return tls.test_ret;
}
/// <!-- description -->
/// @brief Release the vps_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
///
static constexpr void
release(gs_t &gs, tls_t &tls, syscall::bf_syscall_t &sys, intrinsic_t &intrinsic) noexcept
{
bsl::discard(gs);
bsl::discard(tls);
bsl::discard(sys);
bsl::discard(intrinsic);
}
/// <!-- description -->
/// @brief Allocates a vps_t 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 vps_t to
/// @param ppid the ID of the PP to assign the vps_t to
/// @return Returns bsl::errc_success on success, bsl::errc_failure
/// and friends otherwise
///
[[nodiscard]] static constexpr auto
allocate(
gs_t &gs,
tls_t &tls,
syscall::bf_syscall_t &sys,
intrinsic_t &intrinsic,
bsl::safe_uint16 const &vpid,
bsl::safe_uint16 const &ppid) noexcept -> bsl::errc_type
{
bsl::discard(gs);
bsl::discard(sys);
bsl::discard(intrinsic);
bsl::discard(vpid);
bsl::discard(ppid);
return tls.test_ret;
}
};
}
#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.
#ifndef MOCKS_GS_T_HPP
#define MOCKS_GS_T_HPP
#include <bsl/safe_integral.hpp>
namespace example
{
/// @class example::gs_t
///
/// <!-- description -->
/// @brief Defines the extension's mocked version of gs_t, used for
/// unit testing. Specifically, this version is architecture specific.
///
struct gs_t final
{
/// @brief stores the cpuid value to return from intrinsic_cpuid_impl
bsl::safe_uint64 cpuid_val{};
};
}
#endif

View file

@ -0,0 +1,161 @@
/// @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 MOCKS_INTRINSIC_HPP
#define MOCKS_INTRINSIC_HPP
#include <gs_t.hpp>
#include <tls_t.hpp>
#include <bsl/convert.hpp>
#include <bsl/discard.hpp>
#include <bsl/errc_type.hpp>
#include <bsl/safe_integral.hpp>
namespace example
{
/// @class example::intrinsic_t
///
/// <!-- description -->
/// @brief Provides raw access to intrinsics used for unit testing.
/// Specifically, this version is architecture specific.
///
class intrinsic_t final
{
/// @brief stores the return value for initialize
bsl::errc_type m_initialize{};
/// @brief stores the return value for eax with cpuid
bsl::safe_uint32 m_eax{};
/// @brief stores the return value for ebx with cpuid
bsl::safe_uint32 m_ebx{};
/// @brief stores the return value for ecx with cpuid
bsl::safe_uint32 m_ecx{};
/// @brief stores the return value for edx with cpuid
bsl::safe_uint32 m_edx{};
public:
/// <!-- description -->
/// @brief Initializes this intrinsic_t.
///
/// <!-- inputs/outputs -->
/// @param gs the gs_t to use
/// @param tls the tls_t to use
/// @return Returns bsl::errc_success on success, bsl::errc_failure
/// and friends otherwise
///
[[nodiscard]] constexpr auto
initialize(gs_t &gs, tls_t &tls) noexcept -> bsl::errc_type
{
bsl::discard(gs);
bsl::discard(tls);
return m_initialize;
}
/// <!-- description -->
/// @brief Sets the return value of initialize.
/// (unit testing only)
///
/// <!-- inputs/outputs -->
/// @param errc the bsl::errc_type to return when executing
/// initialize
///
constexpr void
set_initialize(bsl::errc_type const &errc) noexcept
{
m_initialize = errc;
}
/// <!-- description -->
/// @brief Release the intrinsic_t.
///
/// <!-- inputs/outputs -->
/// @param gs the gs_t to use
/// @param tls the tls_t to use
///
static constexpr void
release(gs_t &gs, tls_t &tls) noexcept
{
bsl::discard(gs);
bsl::discard(tls);
}
/// <!-- description -->
/// @brief Executes the CPUID instruction given the provided
/// EAX and ECX and returns the results.
///
/// <!-- inputs/outputs -->
/// @param gs the gs_t to use
/// @param tls the tls_t to use
/// @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
///
constexpr void
cpuid(
gs_t &gs,
tls_t &tls,
bsl::safe_uint64 &rax,
bsl::safe_uint64 &rbx,
bsl::safe_uint64 &rcx,
bsl::safe_uint64 &rdx) noexcept
{
bsl::discard(gs);
bsl::discard(tls);
constexpr auto mask{0xFFFFFFFF00000000_u64};
rax = ((rax & mask) | bsl::to_u64(m_eax));
rbx = ((rbx & mask) | bsl::to_u64(m_ebx));
rcx = ((rcx & mask) | bsl::to_u64(m_ecx));
rdx = ((rdx & mask) | bsl::to_u64(m_edx));
}
/// <!-- description -->
/// @brief Sets the return value of cpuid.
/// (unit testing only)
///
/// <!-- inputs/outputs -->
/// @param eax the value to return from cpuid for eax
/// @param ebx the value to return from cpuid for ebx
/// @param ecx the value to return from cpuid for ecx
/// @param edx the value to return from cpuid for edx
///
constexpr void
set_cpuid(
bsl::safe_uint32 const &eax,
bsl::safe_uint32 const &ebx,
bsl::safe_uint32 const &ecx,
bsl::safe_uint32 const &edx) noexcept
{
m_eax = eax;
m_ebx = ebx;
m_ecx = ecx;
m_edx = edx;
}
};
}
#endif

View file

@ -0,0 +1,46 @@
/// @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 MOCKS_TLS_T_HPP
#define MOCKS_TLS_T_HPP
#include <bsl/errc_type.hpp>
namespace example
{
/// @class example::tls_t
///
/// <!-- description -->
/// @brief Defines the extension's mocked version of tls_t, used for
/// unit testing. Specifically, this version only contains portions
/// that are common for all architectures.
///
struct tls_t final
{
/// @brief tells certain mocks when to fail
bsl::errc_type test_ret;
};
}
#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.
#ifndef MOCKS_GS_T_HPP
#define MOCKS_GS_T_HPP
#include <bsl/safe_integral.hpp>
namespace example
{
/// @class example::gs_t
///
/// <!-- description -->
/// @brief Defines the extension's mocked version of gs_t, used for
/// unit testing. Specifically, this version is architecture specific.
///
struct gs_t final
{
/// @brief stores the cpuid value to return from intrinsic_cpuid_impl
bsl::safe_uint64 cpuid_val{};
};
}
#endif

View file

@ -0,0 +1,49 @@
/// @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 MOCKS_GS_T_HPP
#define MOCKS_GS_T_HPP
#include <bsl/safe_integral.hpp>
namespace example
{
/// @class example::gs_t
///
/// <!-- description -->
/// @brief Defines the extension's mocked version of gs_t, used for
/// unit testing. Specifically, this version is architecture specific.
///
struct gs_t final
{
/// @brief stores the cpuid value to return from intrinsic_cpuid_impl
bsl::safe_uint64 cpuid_val{};
/// @brief stores the MSR bitmap used by this vps_t
void *msr_bitmap{};
/// @brief stores the physical address of the MSR bitmap above
bsl::safe_uintmax msr_bitmap_phys{};
};
}
#endif

View file

@ -0,0 +1,161 @@
/// @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 MOCKS_INTRINSIC_HPP
#define MOCKS_INTRINSIC_HPP
#include <gs_t.hpp>
#include <tls_t.hpp>
#include <bsl/convert.hpp>
#include <bsl/discard.hpp>
#include <bsl/errc_type.hpp>
#include <bsl/safe_integral.hpp>
namespace example
{
/// @class example::intrinsic_t
///
/// <!-- description -->
/// @brief Provides raw access to intrinsics used for unit testing.
/// Specifically, this version is architecture specific.
///
class intrinsic_t final
{
/// @brief stores the return value for initialize
bsl::errc_type m_initialize{};
/// @brief stores the return value for eax with cpuid
bsl::safe_uint32 m_eax{};
/// @brief stores the return value for ebx with cpuid
bsl::safe_uint32 m_ebx{};
/// @brief stores the return value for ecx with cpuid
bsl::safe_uint32 m_ecx{};
/// @brief stores the return value for edx with cpuid
bsl::safe_uint32 m_edx{};
public:
/// <!-- description -->
/// @brief Initializes this intrinsic_t.
///
/// <!-- inputs/outputs -->
/// @param gs the gs_t to use
/// @param tls the tls_t to use
/// @return Returns bsl::errc_success on success, bsl::errc_failure
/// and friends otherwise
///
[[nodiscard]] constexpr auto
initialize(gs_t &gs, tls_t &tls) noexcept -> bsl::errc_type
{
bsl::discard(gs);
bsl::discard(tls);
return m_initialize;
}
/// <!-- description -->
/// @brief Sets the return value of initialize.
/// (unit testing only)
///
/// <!-- inputs/outputs -->
/// @param errc the bsl::errc_type to return when executing
/// initialize
///
constexpr void
set_initialize(bsl::errc_type const &errc) noexcept
{
m_initialize = errc;
}
/// <!-- description -->
/// @brief Release the intrinsic_t.
///
/// <!-- inputs/outputs -->
/// @param gs the gs_t to use
/// @param tls the tls_t to use
///
static constexpr void
release(gs_t &gs, tls_t &tls) noexcept
{
bsl::discard(gs);
bsl::discard(tls);
}
/// <!-- description -->
/// @brief Executes the CPUID instruction given the provided
/// EAX and ECX and returns the results.
///
/// <!-- inputs/outputs -->
/// @param gs the gs_t to use
/// @param tls the tls_t to use
/// @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
///
constexpr void
cpuid(
gs_t &gs,
tls_t &tls,
bsl::safe_uint64 &rax,
bsl::safe_uint64 &rbx,
bsl::safe_uint64 &rcx,
bsl::safe_uint64 &rdx) noexcept
{
bsl::discard(gs);
bsl::discard(tls);
constexpr auto mask{0xFFFFFFFF00000000_u64};
rax = ((rax & mask) | bsl::to_u64(m_eax));
rbx = ((rbx & mask) | bsl::to_u64(m_ebx));
rcx = ((rcx & mask) | bsl::to_u64(m_ecx));
rdx = ((rdx & mask) | bsl::to_u64(m_edx));
}
/// <!-- description -->
/// @brief Sets the return value of cpuid.
/// (unit testing only)
///
/// <!-- inputs/outputs -->
/// @param eax the value to return from cpuid for eax
/// @param ebx the value to return from cpuid for ebx
/// @param ecx the value to return from cpuid for ecx
/// @param edx the value to return from cpuid for edx
///
constexpr void
set_cpuid(
bsl::safe_uint32 const &eax,
bsl::safe_uint32 const &ebx,
bsl::safe_uint32 const &ecx,
bsl::safe_uint32 const &edx) noexcept
{
m_eax = eax;
m_ebx = ebx;
m_ecx = ecx;
m_edx = edx;
}
};
}
#endif

View file

@ -0,0 +1,46 @@
/// @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 MOCKS_TLS_T_HPP
#define MOCKS_TLS_T_HPP
#include <bsl/errc_type.hpp>
namespace example
{
/// @class example::tls_t
///
/// <!-- description -->
/// @brief Defines the extension's mocked version of tls_t, used for
/// unit testing. Specifically, this version only contains portions
/// that are common for all architectures.
///
struct tls_t final
{
/// @brief tells certain mocks when to fail
bsl::errc_type test_ret;
};
}
#endif

View file

@ -0,0 +1,89 @@
/// @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 MOCKS_INTRINSIC_IMPL_PROTOTYPES_HPP
#define MOCKS_INTRINSIC_IMPL_PROTOTYPES_HPP
#include <gs_t.hpp>
#include <bsl/cstdint.hpp>
#include <bsl/debug.hpp>
#include <bsl/discard.hpp>
#include <bsl/safe_integral.hpp>
#include <bsl/unlikely_assert.hpp>
namespace example
{
/// <!-- description -->
/// @brief Executes the CPUID instruction given the provided EAX and ECX
/// and returns the results
///
/// <!-- inputs/outputs -->
/// @param gs a pointer to the global storage to use
/// @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" constexpr void
intrinsic_cpuid_impl(
gs_t *const gs,
bsl::uint64 *const rax,
bsl::uint64 *const rbx,
bsl::uint64 *const rcx,
bsl::uint64 *const rdx) noexcept
{
if (bsl::unlikely_assert(nullptr == gs)) {
bsl::alert() << "gs is null\n" << bsl::here();
return;
}
if (bsl::unlikely_assert(nullptr == rax)) {
bsl::alert() << "rax is null\n" << bsl::here();
return;
}
if (bsl::unlikely_assert(nullptr == rbx)) {
bsl::alert() << "rbx is null\n" << bsl::here();
return;
}
if (bsl::unlikely_assert(nullptr == rcx)) {
bsl::alert() << "rcx is null\n" << bsl::here();
return;
}
if (bsl::unlikely_assert(nullptr == rdx)) {
bsl::alert() << "rdx is null\n" << bsl::here();
return;
}
*rax = gs->cpuid_val.get();
*rbx = gs->cpuid_val.get();
*rcx = gs->cpuid_val.get();
*rdx = gs->cpuid_val.get();
}
}
#endif

View file

@ -0,0 +1,46 @@
/// @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 MOCKS_TLS_T_HPP
#define MOCKS_TLS_T_HPP
#include <bsl/errc_type.hpp>
namespace example
{
/// @class example::tls_t
///
/// <!-- description -->
/// @brief Defines the extension's mocked version of tls_t, used for
/// unit testing. Specifically, this version only contains portions
/// that are common for all architectures.
///
struct tls_t final
{
/// @brief tells certain mocks when to fail
bsl::errc_type test_ret;
};
}
#endif

View file

@ -0,0 +1,50 @@
/// @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 GS_T_HPP
#define GS_T_HPP
#include <bsl/safe_integral.hpp>
namespace example
{
/// @class example::gs_t
///
/// <!-- 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.
///
struct gs_t final
{
/// @brief dummy data for example purposes only.
bsl::safe_uintmax dummy;
};
}
#endif

View file

@ -0,0 +1,91 @@
/// @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 INTRINSIC_HPP
#define INTRINSIC_HPP
#include <gs_t.hpp>
#include <tls_t.hpp>
#include <bsl/discard.hpp>
#include <bsl/errc_type.hpp>
#include <bsl/safe_integral.hpp>
namespace example
{
/// @class example::intrinsic_t
///
/// <!-- description -->
/// @brief Provides raw access to intrinsics. Instead of using global
/// functions, the intrinsics class provides a means for the rest of
/// the extension to mock the intrinsics when needed during testing.
///
class intrinsic_t final
{
public:
/// <!-- description -->
/// @brief Initializes this intrinsic_t.
///
/// <!-- inputs/outputs -->
/// @param gs the gs_t to use
/// @param tls the tls_t to use
/// @return Returns bsl::errc_success on success, bsl::errc_failure
/// and friends otherwise
///
[[nodiscard]] static constexpr auto
initialize(gs_t &gs, tls_t &tls) noexcept -> bsl::errc_type
{
bsl::discard(gs);
bsl::discard(tls);
/// NOTE:
/// - Add initialization code here if needed. Otherwise, this
/// function can be removed if it is not needed.
///
return bsl::errc_success;
}
/// <!-- description -->
/// @brief Release the intrinsic_t.
///
/// <!-- inputs/outputs -->
/// @param gs the gs_t to use
/// @param tls the tls_t to use
///
static constexpr void
release(gs_t &gs, tls_t &tls) noexcept
{
bsl::discard(gs);
bsl::discard(tls);
/// NOTE:
/// - Release functions are usually only needed in the event of
/// an error, or during unit testing.
///
}
};
}
#endif

View file

@ -0,0 +1,66 @@
/// @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 TLS_T_HPP
#define TLS_T_HPP
#include <bsl/convert.hpp>
#include <bsl/safe_integral.hpp>
namespace example
{
/// @class example::tls_t
///
/// <!-- 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.
///
struct tls_t final
{
/// @brief dummy data for example purposes only.
bsl::safe_uintmax dummy;
};
/// @brief defines the max size supported for the TLS block
constexpr auto MAX_TLS_SIZE{HYPERVISOR_PAGE_SIZE};
/// @brief ensure that the tls_t does not exceed the max supported size
static_assert(!(sizeof(tls_t) > MAX_TLS_SIZE));
}
#endif

View file

@ -0,0 +1,177 @@
/// @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 VMEXIT_T_HPP
#define VMEXIT_T_HPP
#include <bf_syscall_t.hpp>
#include <gs_t.hpp>
#include <intrinsic_t.hpp>
#include <tls_t.hpp>
#include <vp_pool_t.hpp>
#include <vps_pool_t.hpp>
#include <bsl/debug.hpp>
#include <bsl/discard.hpp>
#include <bsl/errc_type.hpp>
#include <bsl/safe_integral.hpp>
#include <bsl/unlikely_assert.hpp>
namespace example
{
/// @class example::vmexit_t
///
/// <!-- description -->
/// @brief Defines the extension's VMExit handler
///
class vmexit_t final
{
public:
/// <!-- description -->
/// @brief Initializes this vmexit_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
/// @param vp_pool the vp_pool_t to use
/// @param vps_pool the vps_pool_t to use
/// @return Returns bsl::errc_success on success, bsl::errc_failure
/// and friends otherwise
///
[[nodiscard]] static constexpr auto
initialize(
gs_t &gs,
tls_t &tls,
syscall::bf_syscall_t &sys,
intrinsic_t &intrinsic,
vp_pool_t &vp_pool,
vps_pool_t &vps_pool) noexcept -> bsl::errc_type
{
bsl::discard(gs);
bsl::discard(tls);
bsl::discard(sys);
bsl::discard(intrinsic);
bsl::discard(vp_pool);
bsl::discard(vps_pool);
/// NOTE:
/// - Add initialization code here if needed. Otherwise, this
/// function can be removed if it is not needed.
///
return bsl::errc_success;
}
/// <!-- description -->
/// @brief Release the vmexit_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
/// @param vp_pool the vp_pool_t to use
/// @param vps_pool the vps_pool_t to use
///
static constexpr void
release(
gs_t &gs,
tls_t &tls,
syscall::bf_syscall_t &sys,
intrinsic_t &intrinsic,
vp_pool_t &vp_pool,
vps_pool_t &vps_pool) noexcept
{
bsl::discard(gs);
bsl::discard(tls);
bsl::discard(sys);
bsl::discard(intrinsic);
bsl::discard(vp_pool);
bsl::discard(vps_pool);
/// NOTE:
/// - Release functions are usually only needed in the event of
/// an error, or during unit testing.
///
}
/// <!-- 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 vps_pool the vps_pool_t to use
/// @param vpsid the ID of the VPS 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
///
[[nodiscard]] static constexpr auto
dispatch(
gs_t &gs,
tls_t &tls,
syscall::bf_syscall_t &sys,
intrinsic_t &intrinsic,
vp_pool_t &vp_pool,
vps_pool_t &vps_pool,
bsl::safe_uint16 const &vpsid,
bsl::safe_uint64 const &exit_reason) noexcept -> bsl::errc_type
{
/// NOTE:
/// - Define the different VMExits that this dispatcher will
/// support. At a minimum, we need to handle CPUID on AMD.
///
/// NOTE:
/// - Dispatch and handle each VMExit.
///
switch (exit_reason.get()) {
default: {
break;
}
}
/// NOTE:
/// - If we got this far, it means that we were given a VMExit
/// that we do not handle.
///
bsl::error() << "unsupported vmexit " // --
<< bsl::hex(exit_reason) // --
<< bsl::endl // --
<< bsl::here(); // --
return bsl::errc_failure;
}
};
}
#endif

View file

@ -0,0 +1,308 @@
/// @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 VPS_T_HPP
#define VPS_T_HPP
#include <bf_constants.hpp>
#include <bf_syscall_t.hpp>
#include <gs_t.hpp>
#include <intrinsic_t.hpp>
#include <tls_t.hpp>
#include <bsl/discard.hpp>
#include <bsl/errc_type.hpp>
#include <bsl/safe_integral.hpp>
#include <bsl/touch.hpp>
#include <bsl/unlikely_assert.hpp>
namespace example
{
/// @class example::vps_t
///
/// <!-- description -->
/// @brief Defines the extension's notion of a VPS
///
class vps_t final
{
/// @brief stores the ID associated with this vps_t
bsl::safe_uint16 m_id{bsl::safe_uint16::failure()};
/// @brief stores the ID of the VP this vps_t is assigned to
bsl::safe_uint16 m_assigned_vpid{syscall::BF_INVALID_ID};
/// @brief stores the ID of the PP this vps_t is assigned to
bsl::safe_uint16 m_assigned_ppid{syscall::BF_INVALID_ID};
public:
/// <!-- description -->
/// @brief Initializes this vps_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
/// @param i the ID for this vps_t
/// @return Returns bsl::errc_success on success, bsl::errc_failure
/// and friends otherwise
///
[[nodiscard]] constexpr auto
initialize(
gs_t &gs,
tls_t &tls,
syscall::bf_syscall_t &sys,
intrinsic_t &intrinsic,
bsl::safe_uint16 const &i) noexcept -> bsl::errc_type
{
bsl::discard(gs);
bsl::discard(tls);
bsl::discard(sys);
bsl::discard(intrinsic);
/// NOTE:
/// - The following is a pedantic check to make sure we have
/// not already initialized ourselves. In larger extensions,
/// this is useful as it helps to weed out hard to find bugs.
/// In a small example like this, it is completely overkill,
/// but is added for completeness.
///
if (bsl::unlikely_assert(m_id)) {
bsl::error() << "vps_t already initialized\n" << bsl::here();
return bsl::errc_precondition;
}
/// NOTE:
/// - The following are some pedantic checks on the input. In
/// larger extensions, this is useful as it helps to weed
/// out hard to find bugs. In a small example like this, it
/// is completely overkill, but is added for completeness.
/// - We check to to make sure that we were given a valid ID,
/// meaning the safe integral is not storing an error, and we
/// also check to make sure the ID itself is not the reserved
/// syscall::BF_INVALID_ID as that is also not allowed.
///
if (bsl::unlikely_assert(!i)) {
bsl::error() << "invalid id\n" << bsl::here();
return bsl::errc_invalid_argument;
}
if (bsl::unlikely_assert(syscall::BF_INVALID_ID == i)) {
bsl::error() << "id " // --
<< bsl::hex(i) // --
<< " is invalid and cannot be used for initialization" // --
<< bsl::endl // --
<< bsl::here(); // --
return bsl::errc_invalid_argument;
}
/// NOTE:
/// - Finally, store the ID assigned to this vps_t and report
/// success.
///
m_id = i;
return bsl::errc_success;
}
/// <!-- description -->
/// @brief Release the vps_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
///
constexpr void
release(gs_t &gs, tls_t &tls, syscall::bf_syscall_t &sys, intrinsic_t &intrinsic) noexcept
{
bsl::discard(gs);
bsl::discard(tls);
bsl::discard(sys);
bsl::discard(intrinsic);
/// NOTE:
/// - Release functions are usually only needed in the event of
/// an error, or during unit testing.
///
m_assigned_ppid = syscall::BF_INVALID_ID;
m_assigned_vpid = syscall::BF_INVALID_ID;
m_id = bsl::safe_uint16::failure();
}
/// <!-- description -->
/// @brief Allocates a vps_t 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 vps_t to
/// @param ppid the ID of the PP to assign the vps_t to
/// @return Returns bsl::errc_success on success, bsl::errc_failure
/// and friends otherwise
///
[[nodiscard]] constexpr auto
allocate(
gs_t &gs,
tls_t &tls,
syscall::bf_syscall_t &sys,
intrinsic_t &intrinsic,
bsl::safe_uint16 const &vpid,
bsl::safe_uint16 const &ppid) noexcept -> bsl::errc_type
{
bsl::discard(gs);
bsl::discard(tls);
bsl::discard(intrinsic);
bsl::errc_type ret{};
/// NOTE:
/// - The following is a pedantic check to make sure we have
/// been initialized by the vp_pool_t. In larger extensions,
/// this is useful as it helps to weed out hard to find bugs.
/// In a small example like this, it is completely overkill,
/// but is added for completeness.
///
if (bsl::unlikely_assert(!m_id)) {
bsl::error() << "vps_t not initialized\n" << bsl::here();
return bsl::errc_precondition;
}
/// NOTE:
/// - The following is a pedantic check to make sure we have
/// not already allocated this vps_t. In larger extensions,
/// this is useful as it helps to weed out hard to find bugs.
/// In a small example like this, it is completely overkill,
/// but is added for completeness.
///
if (bsl::unlikely_assert(syscall::BF_INVALID_ID != m_assigned_ppid)) {
bsl::error() << "vp " // --
<< bsl::hex(m_id) // --
<< " is already allocated and cannot be created" // --
<< bsl::endl // --
<< bsl::here(); // --
return bsl::errc_precondition;
}
/// NOTE:
/// - The following are some pedantic checks on the input. In
/// larger extensions, this is useful as it helps to weed
/// out hard to find bugs. In a small example like this, it
/// is completely overkill, but is added for completeness.
/// - We check to to make sure that we were given a valid ID,
/// meaning the safe integral is not storing an error, and we
/// also check to make sure the ID itself is not the reserved
/// syscall::BF_INVALID_ID as that is also not allowed.
///
if (bsl::unlikely_assert(!vpid)) {
bsl::error() << "invalid vpid\n" << bsl::here();
return bsl::errc_invalid_argument;
}
if (bsl::unlikely_assert(syscall::BF_INVALID_ID == vpid)) {
bsl::error() << "vm " // --
<< bsl::hex(vpid) // --
<< " is invalid and a vp cannot be assigned to it" // --
<< bsl::endl // --
<< bsl::here(); // --
return bsl::errc_invalid_argument;
}
if (bsl::unlikely_assert(!ppid)) {
bsl::error() << "invalid ppid\n" << bsl::here();
return bsl::errc_invalid_argument;
}
if (bsl::unlikely_assert(syscall::BF_INVALID_ID == ppid)) {
bsl::error() << "pp " // --
<< bsl::hex(ppid) // --
<< " is invalid and a vp cannot be assigned to it" // --
<< bsl::endl // --
<< bsl::here(); // --
return bsl::errc_invalid_argument;
}
/// NOTE:
/// - Initialize the VPS as a root VPS. When the microkernel was
/// started, the loader saved the state of the root VP. This
/// syscall tells the microkernel to load the VPS with this saved
/// state so that when we run the VP, it will contain the state
/// just before the microkernel was started.
/// - In other words, this is what allows the microkernel to return
/// back to the loader once the hypervisor is running.
/// - You only want to run this on root VPs. VPs that are being
/// created for guest VPs should not use this, as it would give
/// the guest VP the state associated with the root VP. Also
/// note that once the root VP has executed, this ABI is no
/// longer useful as the state stored in the microkernel would be
/// out-dated. For root VPs, that ID of the PP should always be
/// the same as the IP of the VP, so we added this check for
/// completeness just in case cut/paste is used here.
///
if (ppid == m_id) {
ret = sys.bf_vps_op_init_as_root(m_id);
if (bsl::unlikely_assert(!ret)) {
bsl::print<bsl::V>() << bsl::here();
return ret;
}
bsl::touch();
}
else {
/// NOTE:
/// - The call to bsl::touch is only needed if you plan to
/// enforce MC/DC unit testing. Feel free to remove this if
/// you have no plans to support MC/DC unit testing.
///
bsl::touch();
}
/// NOTE:
/// - Finally, store the IDs of the VP and PP that this vps_t is
/// assigned to and reprot success.
///
m_assigned_vpid = vpid;
m_assigned_ppid = ppid;
return bsl::errc_success;
}
};
}
#endif

View file

@ -0,0 +1,193 @@
/// @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 BOOTSTRAP_T_HPP
#define BOOTSTRAP_T_HPP
#include <bf_constants.hpp>
#include <bf_syscall_t.hpp>
#include <gs_t.hpp>
#include <intrinsic_t.hpp>
#include <tls_t.hpp>
#include <vp_pool_t.hpp>
#include <vps_pool_t.hpp>
#include <bsl/debug.hpp>
#include <bsl/discard.hpp>
#include <bsl/errc_type.hpp>
#include <bsl/safe_integral.hpp>
#include <bsl/unlikely_assert.hpp>
namespace example
{
/// @class example::bootstrap_t
///
/// <!-- description -->
/// @brief Defines the extension's bootstrap handler
///
class bootstrap_t final
{
public:
/// <!-- description -->
/// @brief Initializes this bootstrap_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
/// @param vp_pool the vp_pool_t to use
/// @param vps_pool the vps_pool_t to use
/// @return Returns bsl::errc_success on success, bsl::errc_failure
/// and friends otherwise
///
[[nodiscard]] static constexpr auto
initialize(
gs_t &gs,
tls_t &tls,
syscall::bf_syscall_t &sys,
intrinsic_t &intrinsic,
vp_pool_t &vp_pool,
vps_pool_t &vps_pool) noexcept -> bsl::errc_type
{
bsl::discard(gs);
bsl::discard(tls);
bsl::discard(sys);
bsl::discard(intrinsic);
bsl::discard(vp_pool);
bsl::discard(vps_pool);
/// NOTE:
/// - Add initialization code here if needed. Otherwise, this
/// function can be removed if it is not needed.
///
return bsl::errc_success;
}
/// <!-- description -->
/// @brief Release the bootstrap_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
/// @param vp_pool the vp_pool_t to use
/// @param vps_pool the vps_pool_t to use
///
static constexpr void
release(
gs_t &gs,
tls_t &tls,
syscall::bf_syscall_t &sys,
intrinsic_t &intrinsic,
vp_pool_t &vp_pool,
vps_pool_t &vps_pool) noexcept
{
bsl::discard(gs);
bsl::discard(tls);
bsl::discard(sys);
bsl::discard(intrinsic);
bsl::discard(vp_pool);
bsl::discard(vps_pool);
/// NOTE:
/// - Release functions are usually only needed in the event of
/// an error, or during unit testing.
///
}
/// <!-- 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 vps_pool the vps_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
///
[[nodiscard]] static constexpr auto
dispatch(
gs_t &gs,
tls_t &tls,
syscall::bf_syscall_t &sys,
intrinsic_t &intrinsic,
vp_pool_t &vp_pool,
vps_pool_t &vps_pool,
bsl::safe_uint16 const &ppid) noexcept -> bsl::errc_type
{
/// NOTE:
/// - In order to execcute bf_vps_op_run, which is what executes
/// the hypervisor, we must have a VM, VP and VPS.
/// - 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.
///
auto const 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 VPS
/// per VP (e.g., if you are implementing HyperV's VSM, or nested
/// virtualization support). Otherwise, you will always have one
/// VPS for each VP, and they will appear as the same thing.
/// - The VPS is what stores the state associated with the VPS. It
/// is the thing that does most of the work, including storing
/// the VMCS/VMCB and other CPU register state that is needed.
///
auto const vpid{vp_pool.allocate(gs, tls, sys, intrinsic, vmid, ppid)};
if (bsl::unlikely_assert(!vpid)) {
bsl::print<bsl::V>() << bsl::here();
return bsl::errc_failure;
}
auto const vpsid{vps_pool.allocate(gs, tls, sys, intrinsic, vpid, ppid)};
if (bsl::unlikely_assert(!vpsid)) {
bsl::print<bsl::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 VPS. Note that this version of
/// the run function should only be used when starting the
/// hypervisor, or switching the VM, VP or VPS as it is slow.
///
return sys.bf_vps_op_run(vmid, vpid, vpsid);
}
};
}
#endif

View file

@ -0,0 +1,175 @@
/// @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 FAIL_T_HPP
#define FAIL_T_HPP
#include <bf_syscall_t.hpp>
#include <gs_t.hpp>
#include <intrinsic_t.hpp>
#include <tls_t.hpp>
#include <vp_pool_t.hpp>
#include <vps_pool_t.hpp>
#include <bsl/discard.hpp>
#include <bsl/errc_type.hpp>
#include <bsl/safe_integral.hpp>
namespace example
{
/// @class example::fail_t
///
/// <!-- description -->
/// @brief Defines the extension's fail handler
///
class fail_t final
{
public:
/// <!-- description -->
/// @brief Initializes this fail_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
/// @param vp_pool the vp_pool_t to use
/// @param vps_pool the vps_pool_t to use
/// @return Returns bsl::errc_success on success, bsl::errc_failure
/// and friends otherwise
///
[[nodiscard]] static constexpr auto
initialize(
gs_t &gs,
tls_t &tls,
syscall::bf_syscall_t &sys,
intrinsic_t &intrinsic,
vp_pool_t &vp_pool,
vps_pool_t &vps_pool) noexcept -> bsl::errc_type
{
bsl::discard(gs);
bsl::discard(tls);
bsl::discard(sys);
bsl::discard(intrinsic);
bsl::discard(vp_pool);
bsl::discard(vps_pool);
/// NOTE:
/// - Add initialization code here if needed. Otherwise, this
/// function can be removed if it is not needed.
///
return bsl::errc_success;
}
/// <!-- description -->
/// @brief Release the fail_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
/// @param vp_pool the vp_pool_t to use
/// @param vps_pool the vps_pool_t to use
///
static constexpr void
release(
gs_t &gs,
tls_t &tls,
syscall::bf_syscall_t &sys,
intrinsic_t &intrinsic,
vp_pool_t &vp_pool,
vps_pool_t &vps_pool) noexcept
{
bsl::discard(gs);
bsl::discard(tls);
bsl::discard(sys);
bsl::discard(intrinsic);
bsl::discard(vp_pool);
bsl::discard(vps_pool);
/// NOTE:
/// - Release functions are usually only needed in the event of
/// an error, or during unit testing.
///
}
/// <!-- 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 vps_pool the vps_pool_t to use
/// @param vpsid the ID of the VPS that generated the fail
/// @param fail_reason the exit reason associated with the fail
/// @return Returns bsl::errc_success on success, bsl::errc_failure
/// and friends otherwise
///
[[nodiscard]] static constexpr auto
dispatch(
gs_t &gs,
tls_t &tls,
syscall::bf_syscall_t &sys,
intrinsic_t &intrinsic,
vp_pool_t &vp_pool,
vps_pool_t &vps_pool,
bsl::safe_uint16 const &vpsid,
bsl::safe_uint64 const &fail_reason) noexcept -> bsl::errc_type
{
bsl::discard(gs);
bsl::discard(tls);
bsl::discard(sys);
bsl::discard(intrinsic);
bsl::discard(vp_pool);
bsl::discard(vps_pool);
bsl::discard(vpsid);
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 for how to handle a fail:
/// - Do the following, and report an error and halt.
/// - Return to a parent VPS and continue execution from there,
/// which is typically only possible if you are implementing
/// more than one VP/VPS 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.
///
return bsl::errc_failure;
}
};
}
#endif

View file

@ -0,0 +1,341 @@
/// @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 <bf_control_ops.hpp>
#include <bf_syscall_t.hpp>
#include <bootstrap_t.hpp>
#include <fail_t.hpp>
#include <gs_t.hpp>
#include <intrinsic_t.hpp>
#include <tls_t.hpp>
#include <vmexit_t.hpp>
#include <vp_pool_t.hpp>
#include <vps_pool_t.hpp>
#include <bsl/convert.hpp>
#include <bsl/debug.hpp>
#include <bsl/unlikely_assert.hpp>
namespace example
{
/// NOTE:
/// - This is where we store all of our global and thread local variables.
/// All of the variables are marked as static to ensure they are not
/// visable to the rest of the code.
/// - All global and thread local variables must be passed around from
/// function to function as needed. This ensures that constexpr unit
/// tests work properly as the rest of the code never relies on global
/// variables. In addition, it dramatically simplifies unit testing, so
/// enforcing this coding style, although annoying for the function
/// signatures, makes working with the rest of the code a lot easier.
/// - We use constinit here, which works around a specific AUTOSAR rule
/// that does not allow global constructors/destructors. By using
/// constinit, we are sure that runtime global constructors are not used.
/// Bareflank does not attempt to run any init/fini sections of the
/// ELF binary, so if you use accidentally forget constinit, the code
/// will likely not execute and fail as a reminder. Instead, use the
/// initialization/release pattern that this example provides.
/// - From a unit testing point of view, each of these will have dummy
/// versions that are used for testing. When the code is compiled, each
/// source file and head file is compiled in isolation, meaning they are
/// not given include folder access to all of the code. This means that
/// each of these must be mocked, and the unit tests are given include
/// access to the mocks. This prevents the need for templates, and
/// instead, all mock injection is done using the build system, greatly
/// simplifying both the code and branch analysis during unit tests as
/// the removal of templates also removes issues with branches being
/// counted for each instantiaion of a template type.
/// - Finally, some of these are not really needed for this simple example,
/// but we added them for completness so that it is easier to get
/// started with your own extension as more complicated code will likely
/// need most of these if not all.
///
/// @brief stores the bf_syscall_t that this code will use
constinit syscall::bf_syscall_t g_sys{};
/// @brief stores the intrinsic_t that this code will use
constinit intrinsic_t g_intrinsic{};
/// @brief stores the pool of VPs that we will use
constinit vp_pool_t g_vp_pool{};
/// @brief stores the pool of VPSs that we will use
constinit vps_pool_t g_vps_pool{};
/// @brief stores the bootstrap_t that this code will use
constinit bootstrap_t g_bootstrap{};
/// @brief stores the fail_t that this code will use
constinit fail_t g_fail{};
/// @brief stores the vmexit_t that this code will use
constinit vmexit_t g_vmexit{};
/// @brief stores the Global Storage for this extension
constinit gs_t g_gs{};
/// @brief stores the Thread Local Storage for this extension on this PP
thread_local tls_t g_tls{};
/// <!-- description -->
/// @brief Implements the bootstrap entry function. This function is
/// called on each PP while the hypervisor is being bootstrapped.
///
/// <!-- inputs/outputs -->
/// @param ppid the physical process to bootstrap
///
extern "C" void
bootstrap_entry(syscall::bf_uint16_t::value_type const ppid) noexcept
{
bsl::errc_type ret{};
/// 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.
///
ret = g_bootstrap.dispatch( // --
g_gs, // --
g_tls, // --
g_sys, // --
g_intrinsic, // --
g_vp_pool, // --
g_vps_pool, // --
ppid);
if (bsl::unlikely_assert(!ret)) {
bsl::print<bsl::V>() << bsl::here();
return syscall::bf_control_op_exit();
}
/// 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.
///
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 vpsid the ID of the VPS that generated the fail
/// @param fail_reason the exit reason associated with the fail
///
extern "C" void
fail_entry(
syscall::bf_uint16_t::value_type const vpsid,
syscall::bf_status_t::value_type const fail_reason) noexcept
{
bsl::errc_type ret{};
/// 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.
///
ret = g_fail.dispatch( // --
g_gs, // --
g_tls, // --
g_sys, // --
g_intrinsic, // --
g_vp_pool, // --
g_vps_pool, // --
vpsid, // --
fail_reason);
if (bsl::unlikely_assert(!ret)) {
bsl::print<bsl::V>() << bsl::here();
return syscall::bf_control_op_exit();
}
/// 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.
///
return syscall::bf_control_op_exit();
}
/// <!-- description -->
/// @brief Implements the VMExit entry function. This is registered
/// by the main function to execute whenever a VMExit occurs.
///
/// <!-- inputs/outputs -->
/// @param vpsid the ID of the VPS that generated the VMExit
/// @param exit_reason the exit reason associated with the VMExit
///
extern "C" void
vmexit_entry(
syscall::bf_uint16_t::value_type const vpsid,
syscall::bf_uint64_t::value_type const exit_reason) noexcept
{
bsl::errc_type ret{};
/// NOTE:
/// - Call into the vmexit 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.
///
ret = g_vmexit.dispatch( // --
g_gs, // --
g_tls, // --
g_sys, // --
g_intrinsic, // --
g_vp_pool, // --
g_vps_pool, // --
vpsid, // --
exit_reason);
if (bsl::unlikely_assert(!ret)) {
bsl::print<bsl::V>() << bsl::here();
return syscall::bf_control_op_exit();
}
/// 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.
///
return 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:
/// - Initialize the bf_syscall_t. This will validate the ABI version,
/// open a handle to the microkernel and register the required
/// callbacks. If this fails, we call bf_control_op_exit, which is
/// similar to exit() from POSIX, except that the return value is
/// always the same.
///
ret = g_sys.initialize(version, &bootstrap_entry, &vmexit_entry, &fail_entry);
if (bsl::unlikely_assert(!ret)) {
bsl::print<bsl::V>() << bsl::here();
return syscall::bf_control_op_exit();
}
/// NOTE:
/// - Initialize the g_intrinsic. This can be used to add any init
/// logic that might be needed, otherwise it can be removed.
///
ret = g_intrinsic.initialize(g_gs, g_tls);
if (bsl::unlikely_assert(!ret)) {
bsl::print<bsl::V>() << bsl::here();
return syscall::bf_control_op_exit();
}
/// NOTE:
/// - Initialize the vp_pool_t. This will give all of our vp_t's
/// their IDs so that they can be allocated.
///
ret = g_vp_pool.initialize(g_gs, g_tls, g_sys, g_intrinsic);
if (bsl::unlikely_assert(!ret)) {
bsl::print<bsl::V>() << bsl::here();
return syscall::bf_control_op_exit();
}
/// NOTE:
/// - Initialize the vps_pool_t. This will give all of our vps_t's
/// their IDs so that they can be allocated.
///
ret = g_vps_pool.initialize(g_gs, g_tls, g_sys, g_intrinsic);
if (bsl::unlikely_assert(!ret)) {
bsl::print<bsl::V>() << bsl::here();
return syscall::bf_control_op_exit();
}
/// NOTE:
/// - Initialize the g_bootstrap. This can be used to add any init
/// logic that might be needed, otherwise it can be removed.
///
ret = g_bootstrap.initialize(g_gs, g_tls, g_sys, g_intrinsic, g_vp_pool, g_vps_pool);
if (bsl::unlikely_assert(!ret)) {
bsl::print<bsl::V>() << bsl::here();
return syscall::bf_control_op_exit();
}
/// NOTE:
/// - Initialize the g_fail. This can be used to add any init
/// logic that might be needed, otherwise it can be removed.
///
ret = g_fail.initialize(g_gs, g_tls, g_sys, g_intrinsic, g_vp_pool, g_vps_pool);
if (bsl::unlikely_assert(!ret)) {
bsl::print<bsl::V>() << bsl::here();
return syscall::bf_control_op_exit();
}
/// NOTE:
/// - Initialize the g_vmexit. This can be used to add any init
/// logic that might be needed, otherwise it can be removed.
///
ret = g_vmexit.initialize(g_gs, g_tls, g_sys, g_intrinsic, g_vp_pool, g_vps_pool);
if (bsl::unlikely_assert(!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).
/// - This is similar to the wait() function from POSIX after having
/// just started some processes, with the difference being that
/// this will never return, so there is no need to pass in status
/// as there is nothing to process after this call.
///
return syscall::bf_control_op_wait();
}
}

View file

@ -0,0 +1,228 @@
/// @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 VP_POOL_T_HPP
#define VP_POOL_T_HPP
#include <bf_syscall_t.hpp>
#include <gs_t.hpp>
#include <intrinsic_t.hpp>
#include <tls_t.hpp>
#include <vp_t.hpp>
#include <bsl/array.hpp>
#include <bsl/debug.hpp>
#include <bsl/discard.hpp>
#include <bsl/errc_type.hpp>
#include <bsl/finally.hpp>
#include <bsl/finally_assert.hpp>
#include <bsl/safe_integral.hpp>
#include <bsl/unlikely.hpp>
#include <bsl/unlikely_assert.hpp>
namespace example
{
/// @class example::vp_pool_t
///
/// <!-- description -->
/// @brief Defines the extension's VP pool
///
class vp_pool_t final
{
/// @brief stores the pool of VPs
bsl::array<vp_t, HYPERVISOR_MAX_VPS.get()> m_pool{};
public:
/// <!-- 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
/// @return Returns bsl::errc_success on success, bsl::errc_failure
/// and friends otherwise
///
[[nodiscard]] constexpr auto
initialize(
gs_t &gs, tls_t &tls, syscall::bf_syscall_t &sys, intrinsic_t &intrinsic) noexcept
-> bsl::errc_type
{
/// NOTE:
/// - The following is used in the event of an error. Basically,
/// whatever is in the bsl::finally will execute once the
/// function is returned from unless we explicitly call the
/// ignore() function, which we do at the end when all is good.
///
bsl::finally_assert release_on_error{
[this, &gs, &tls, &sys, &intrinsic]() noexcept -> void {
this->release(gs, tls, sys, intrinsic);
}};
/// NOTE:
/// - Initialize all of the VPs. This basically gives each one it's
/// ID. We could spare some execution time if we wanted and only
/// initialize VPs equal to the online PPs (there is an ABI to
/// get that), as we are only going to have one VP per PP, so the
/// two totals are the same, but for now, this is just easier,
/// and it allows us to create more if needed.
///
bsl::errc_type ret{};
for (bsl::safe_uintmax i{}; i < m_pool.size(); ++i) {
ret = m_pool.at_if(i)->initialize(gs, tls, sys, intrinsic, bsl::to_u16(i));
if (bsl::unlikely_assert(!ret)) {
bsl::print<bsl::V>() << bsl::here();
return ret;
}
/// NOTE:
/// - The call to bsl::touch is only needed if you plan to
/// enforce MC/DC unit testing. Feel free to remove this if
/// you have no plans to support MC/DC unit testing.
///
bsl::touch();
}
release_on_error.ignore();
return bsl::errc_success;
}
/// <!-- 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
///
constexpr void
release(gs_t &gs, tls_t &tls, syscall::bf_syscall_t &sys, intrinsic_t &intrinsic) noexcept
{
/// NOTE:
/// - Release functions are usually only needed in the event of
/// an error, or during unit testing.
///
for (bsl::safe_uintmax i{}; i < m_pool.size(); ++i) {
m_pool.at_if(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
/// @param ppid the ID of the PP to assign the newly created VP to
/// @return Returns the ID of the newly created VP on
/// success, or bsl::safe_uint16::failure() on failure.
///
[[nodiscard]] constexpr auto
allocate(
gs_t &gs,
tls_t &tls,
syscall::bf_syscall_t &sys,
intrinsic_t &intrinsic,
bsl::safe_uint16 const &vmid,
bsl::safe_uint16 const &ppid) noexcept -> bsl::safe_uint16
{
bsl::errc_type ret{};
bsl::safe_uint16 vpid{};
/// NOTE:
/// - Ask the microkernel to create a VP and return the ID of the
/// newly created VP. We do not check in this function if the
/// provided vmid or ppid are valid as this is done by the
/// bf_vp_op_create_vp. We only need to check these types of
/// inputs at the point of use, and not when we are just passing
/// them to another function.
///
vpid = sys.bf_vp_op_create_vp(vmid, ppid);
if (bsl::unlikely_assert(!vpid)) {
bsl::print<bsl::V>() << bsl::here();
return bsl::safe_uint16::failure();
}
/// NOTE:
/// - The following is used in the event of an error. Basically,
/// whatever is in the bsl::finally will execute once the
/// function is returned from unless we explicitly call the
/// ignore() function, which we do at the end when all is good.
///
bsl::finally destroy_vp_on_error{[&sys, &vpid]() noexcept -> void {
bsl::discard(sys.bf_vp_op_destroy_vp(vpid));
}};
/// NOTE:
/// - We need to check to make sure that the provided ID fits
/// inside of our pool. Even with microkernel that use the same
/// ABI, this would possibly be an issue if the extension and
/// the microkernel did not use the same max limits.
///
auto *const vp{m_pool.at_if(bsl::to_umax(vpid))};
if (bsl::unlikely(nullptr == vp)) {
bsl::error() << "vpid " // --
<< bsl::hex(vpid) // --
<< " provided by the microkernel is invalid" // --
<< " or greater than or equal to the HYPERVISOR_MAX_VPS " // --
<< bsl::hex(HYPERVISOR_MAX_VPS) // --
<< bsl::endl // --
<< bsl::here(); // --
return bsl::safe_uint16::failure();
}
/// NOTE:
/// - Finally, we need to allocate the VP in our pool. This will
/// simply tell the VP which VM and PP it is assigned to. We
/// can use this in more complicated extensions, and it also
/// serves to make sure that we have not allocated the same VP
/// more than once.
///
ret = vp->allocate(gs, tls, sys, intrinsic, vmid, ppid);
if (bsl::unlikely_assert(!ret)) {
bsl::print<bsl::V>() << bsl::here();
return bsl::safe_uint16::failure();
}
destroy_vp_on_error.ignore();
return vpid;
}
};
}
#endif

View file

@ -0,0 +1,268 @@
/// @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 VP_T_HPP
#define VP_T_HPP
#include <bf_constants.hpp>
#include <bf_syscall_t.hpp>
#include <gs_t.hpp>
#include <intrinsic_t.hpp>
#include <tls_t.hpp>
#include <bsl/discard.hpp>
#include <bsl/errc_type.hpp>
#include <bsl/safe_integral.hpp>
#include <bsl/unlikely_assert.hpp>
namespace example
{
/// @class example::vp_t
///
/// <!-- description -->
/// @brief Defines the extension's notion of a VP
///
class vp_t final
{
/// @brief stores the ID associated with this vp_t
bsl::safe_uint16 m_id{bsl::safe_uint16::failure()};
/// @brief stores the ID of the VM this vp_t is assigned to
bsl::safe_uint16 m_assigned_vmid{syscall::BF_INVALID_ID};
/// @brief stores the ID of the PP this vp_t is assigned to
bsl::safe_uint16 m_assigned_ppid{syscall::BF_INVALID_ID};
public:
/// <!-- description -->
/// @brief Initializes this vp_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
/// @param i the ID for this vp_t
/// @return Returns bsl::errc_success on success, bsl::errc_failure
/// and friends otherwise
///
[[nodiscard]] constexpr auto
initialize(
gs_t &gs,
tls_t &tls,
syscall::bf_syscall_t &sys,
intrinsic_t &intrinsic,
bsl::safe_uint16 const &i) noexcept -> bsl::errc_type
{
bsl::discard(gs);
bsl::discard(tls);
bsl::discard(sys);
bsl::discard(intrinsic);
/// NOTE:
/// - The following is a pedantic check to make sure we have
/// not already initialized ourselves. In larger extensions,
/// this is useful as it helps to weed out hard to find bugs.
/// In a small example like this, it is completely overkill,
/// but is added for completeness.
///
if (bsl::unlikely_assert(m_id)) {
bsl::error() << "vp_t already initialized\n" << bsl::here();
return bsl::errc_precondition;
}
/// NOTE:
/// - The following are some pedantic checks on the input. In
/// larger extensions, this is useful as it helps to weed
/// out hard to find bugs. In a small example like this, it
/// is completely overkill, but is added for completeness.
/// - We check to to make sure that we were given a valid ID,
/// meaning the safe integral is not storing an error, and we
/// also check to make sure the ID itself is not the reserved
/// syscall::BF_INVALID_ID as that is also not allowed.
///
if (bsl::unlikely_assert(!i)) {
bsl::error() << "invalid id\n" << bsl::here();
return bsl::errc_invalid_argument;
}
if (bsl::unlikely_assert(syscall::BF_INVALID_ID == i)) {
bsl::error() << "id " // --
<< bsl::hex(i) // --
<< " is invalid and cannot be used for initialization" // --
<< bsl::endl // --
<< bsl::here(); // --
return bsl::errc_invalid_argument;
}
/// NOTE:
/// - Finally, store the ID assigned to this vp_t and report
/// success.
///
m_id = i;
return bsl::errc_success;
}
/// <!-- description -->
/// @brief Release the vp_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
///
constexpr void
release(gs_t &gs, tls_t &tls, syscall::bf_syscall_t &sys, intrinsic_t &intrinsic) noexcept
{
bsl::discard(gs);
bsl::discard(tls);
bsl::discard(sys);
bsl::discard(intrinsic);
/// NOTE:
/// - Release functions are usually only needed in the event of
/// an error, or during unit testing.
///
m_assigned_ppid = syscall::BF_INVALID_ID;
m_assigned_vmid = syscall::BF_INVALID_ID;
m_id = bsl::safe_uint16::failure();
}
/// <!-- description -->
/// @brief Allocates a vp_t 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 vp_t to
/// @param ppid the ID of the PP to assign the vp_t to
/// @return Returns bsl::errc_success on success, bsl::errc_failure
/// and friends otherwise
///
[[nodiscard]] constexpr auto
allocate(
gs_t &gs,
tls_t &tls,
syscall::bf_syscall_t &sys,
intrinsic_t &intrinsic,
bsl::safe_uint16 const &vmid,
bsl::safe_uint16 const &ppid) noexcept -> bsl::errc_type
{
bsl::discard(gs);
bsl::discard(tls);
bsl::discard(sys);
bsl::discard(intrinsic);
/// NOTE:
/// - The following is a pedantic check to make sure we have
/// been initialized by the vp_pool_t. In larger extensions,
/// this is useful as it helps to weed out hard to find bugs.
/// In a small example like this, it is completely overkill,
/// but is added for completeness.
///
if (bsl::unlikely_assert(!m_id)) {
bsl::error() << "vp_t not initialized\n" << bsl::here();
return bsl::errc_precondition;
}
/// NOTE:
/// - The following is a pedantic check to make sure we have
/// not already allocated this vp_t. In larger extensions,
/// this is useful as it helps to weed out hard to find bugs.
/// In a small example like this, it is completely overkill,
/// but is added for completeness.
///
if (bsl::unlikely_assert(syscall::BF_INVALID_ID != m_assigned_ppid)) {
bsl::error() << "vp " // --
<< bsl::hex(m_id) // --
<< " is already allocated and cannot be created" // --
<< bsl::endl // --
<< bsl::here(); // --
return bsl::errc_precondition;
}
/// NOTE:
/// - The following are some pedantic checks on the input. In
/// larger extensions, this is useful as it helps to weed
/// out hard to find bugs. In a small example like this, it
/// is completely overkill, but is added for completeness.
/// - We check to to make sure that we were given a valid ID,
/// meaning the safe integral is not storing an error, and we
/// also check to make sure the ID itself is not the reserved
/// syscall::BF_INVALID_ID as that is also not allowed.
///
if (bsl::unlikely_assert(!vmid)) {
bsl::error() << "invalid vmid\n" << bsl::here();
return bsl::errc_invalid_argument;
}
if (bsl::unlikely_assert(syscall::BF_INVALID_ID == vmid)) {
bsl::error() << "vm " // --
<< bsl::hex(vmid) // --
<< " is invalid and a vp cannot be assigned to it" // --
<< bsl::endl // --
<< bsl::here(); // --
return bsl::errc_invalid_argument;
}
if (bsl::unlikely_assert(!ppid)) {
bsl::error() << "invalid ppid\n" << bsl::here();
return bsl::errc_invalid_argument;
}
if (bsl::unlikely_assert(syscall::BF_INVALID_ID == ppid)) {
bsl::error() << "pp " // --
<< bsl::hex(ppid) // --
<< " is invalid and a vp cannot be assigned to it" // --
<< bsl::endl // --
<< bsl::here(); // --
return bsl::errc_invalid_argument;
}
/// NOTE:
/// - Finally, store the IDs of the VM and PP that this vp_t is
/// assigned to and reprot success.
///
m_assigned_vmid = vmid;
m_assigned_ppid = ppid;
return bsl::errc_success;
}
};
}
#endif

View file

@ -0,0 +1,228 @@
/// @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 VPS_POOL_T_HPP
#define VPS_POOL_T_HPP
#include <bf_syscall_t.hpp>
#include <gs_t.hpp>
#include <intrinsic_t.hpp>
#include <tls_t.hpp>
#include <vps_t.hpp>
#include <bsl/array.hpp>
#include <bsl/debug.hpp>
#include <bsl/discard.hpp>
#include <bsl/errc_type.hpp>
#include <bsl/finally.hpp>
#include <bsl/finally_assert.hpp>
#include <bsl/safe_integral.hpp>
#include <bsl/unlikely.hpp>
#include <bsl/unlikely_assert.hpp>
namespace example
{
/// @class example::vps_pool_t
///
/// <!-- description -->
/// @brief Defines the extension's VPS pool
///
class vps_pool_t final
{
/// @brief stores the pool of VPSs
bsl::array<vps_t, HYPERVISOR_MAX_VPSS.get()> m_pool{};
public:
/// <!-- description -->
/// @brief Initializes this vps_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
/// @return Returns bsl::errc_success on success, bsl::errc_failure
/// and friends otherwise
///
[[nodiscard]] constexpr auto
initialize(
gs_t &gs, tls_t &tls, syscall::bf_syscall_t &sys, intrinsic_t &intrinsic) noexcept
-> bsl::errc_type
{
/// NOTE:
/// - The following is used in the event of an error. Basically,
/// whatever is in the bsl::finally will execute once the
/// function is returned from unless we explicitly call the
/// ignore() function, which we do at the end when all is good.
///
bsl::finally_assert release_on_error{
[this, &gs, &tls, &sys, &intrinsic]() noexcept -> void {
this->release(gs, tls, sys, intrinsic);
}};
/// NOTE:
/// - Initialize all of the VPSs. This basically gives each one it's
/// ID. We could spare some execution time if we wanted and only
/// initialize VPSs equal to the online PPs (there is an ABI to
/// get that), as we are only going to have one VPS per PP, so the
/// two totals are the same, but for now, this is just easier,
/// and it allows us to create more if needed.
///
bsl::errc_type ret{};
for (bsl::safe_uintmax i{}; i < m_pool.size(); ++i) {
ret = m_pool.at_if(i)->initialize(gs, tls, sys, intrinsic, bsl::to_u16(i));
if (bsl::unlikely_assert(!ret)) {
bsl::print<bsl::V>() << bsl::here();
return ret;
}
/// NOTE:
/// - The call to bsl::touch is only needed if you plan to
/// enforce MC/DC unit testing. Feel free to remove this if
/// you have no plans to support MC/DC unit testing.
///
bsl::touch();
}
release_on_error.ignore();
return bsl::errc_success;
}
/// <!-- description -->
/// @brief Release the vps_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
///
constexpr void
release(gs_t &gs, tls_t &tls, syscall::bf_syscall_t &sys, intrinsic_t &intrinsic) noexcept
{
/// NOTE:
/// - Release functions are usually only needed in the event of
/// an error, or during unit testing.
///
for (bsl::safe_uintmax i{}; i < m_pool.size(); ++i) {
m_pool.at_if(i)->release(gs, tls, sys, intrinsic);
}
}
/// <!-- description -->
/// @brief Allocates a VPS 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 VPS to
/// @param ppid the ID of the PP to assign the newly created VPS to
/// @return Returns the ID of the newly created VPS on
/// success, or bsl::safe_uint16::failure() on failure.
///
[[nodiscard]] constexpr auto
allocate(
gs_t &gs,
tls_t &tls,
syscall::bf_syscall_t &sys,
intrinsic_t &intrinsic,
bsl::safe_uint16 const &vpid,
bsl::safe_uint16 const &ppid) noexcept -> bsl::safe_uint16
{
bsl::errc_type ret{};
bsl::safe_uint16 vpsid{};
/// NOTE:
/// - Ask the microkernel to create a VPS and return the ID of the
/// newly created VPS. We do not check in this function if the
/// provided vmid or ppid are valid as this is done by the
/// bf_vp_op_create_vp. We only need to check these types of
/// inputs at the point of use, and not when we are just passing
/// them to another function.
///
vpsid = sys.bf_vps_op_create_vps(vpid, ppid);
if (bsl::unlikely_assert(!vpsid)) {
bsl::print<bsl::V>() << bsl::here();
return bsl::safe_uint16::failure();
}
/// NOTE:
/// - The following is used in the event of an error. Basically,
/// whatever is in the bsl::finally will execute once the
/// function is returned from unless we explicitly call the
/// ignore() function, which we do at the end when all is good.
///
bsl::finally destroy_vps_on_error{[&sys, &vpsid]() noexcept -> void {
bsl::discard(sys.bf_vps_op_destroy_vps(vpsid));
}};
/// NOTE:
/// - We need to check to make sure that the provided ID fits
/// inside of our pool. Even with microkernel that use the same
/// ABI, this would possibly be an issue if the extension and
/// the microkernel did not use the same max limits.
///
auto *const vps{m_pool.at_if(bsl::to_umax(vpsid))};
if (bsl::unlikely(nullptr == vps)) {
bsl::error() << "vpsid " // --
<< bsl::hex(vpsid) // --
<< " provided by the microkernel is invalid" // --
<< " or greater than or equal to the HYPERVISOR_MAX_VPSS " // --
<< bsl::hex(HYPERVISOR_MAX_VPSS) // --
<< bsl::endl // --
<< bsl::here(); // --
return bsl::safe_uint16::failure();
}
/// NOTE:
/// - Finally, we need to allocate the VPS in our pool. This will
/// simply tell the VPS which VP and PP it is assigned to. We
/// can use this in more complicated extensions, and it also
/// serves to make sure that we have not allocated the same VPS
/// more than once.
///
ret = vps->allocate(gs, tls, sys, intrinsic, vpid, ppid);
if (bsl::unlikely_assert(!ret)) {
bsl::print<bsl::V>() << bsl::here();
return bsl::safe_uint16::failure();
}
destroy_vps_on_error.ignore();
return vpsid;
}
};
}
#endif

View file

@ -0,0 +1,50 @@
/// @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 GS_T_HPP
#define GS_T_HPP
#include <bsl/safe_integral.hpp>
namespace example
{
/// @class example::gs_t
///
/// <!-- 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.
///
struct gs_t final
{
/// @brief dummy data for example purposes only.
bsl::safe_uintmax dummy;
};
}
#endif

View file

@ -0,0 +1,117 @@
/// @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 INTRINSIC_HPP
#define INTRINSIC_HPP
#include <gs_t.hpp>
#include <intrinsic_cpuid_impl.hpp>
#include <tls_t.hpp>
#include <bsl/discard.hpp>
#include <bsl/errc_type.hpp>
#include <bsl/safe_integral.hpp>
namespace example
{
/// @class example::intrinsic_t
///
/// <!-- description -->
/// @brief Provides raw access to intrinsics. Instead of using global
/// functions, the intrinsics class provides a means for the rest of
/// the extension to mock the intrinsics when needed during testing.
///
class intrinsic_t final
{
public:
/// <!-- description -->
/// @brief Initializes this intrinsic_t.
///
/// <!-- inputs/outputs -->
/// @param gs the gs_t to use
/// @param tls the tls_t to use
/// @return Returns bsl::errc_success on success, bsl::errc_failure
/// and friends otherwise
///
[[nodiscard]] static constexpr auto
initialize(gs_t &gs, tls_t &tls) noexcept -> bsl::errc_type
{
bsl::discard(gs);
bsl::discard(tls);
/// NOTE:
/// - Add initialization code here if needed. Otherwise, this
/// function can be removed if it is not needed.
///
return bsl::errc_success;
}
/// <!-- description -->
/// @brief Release the intrinsic_t.
///
/// <!-- inputs/outputs -->
/// @param gs the gs_t to use
/// @param tls the tls_t to use
///
static constexpr void
release(gs_t &gs, tls_t &tls) noexcept
{
bsl::discard(gs);
bsl::discard(tls);
/// NOTE:
/// - Release functions are usually only needed in the event of
/// an error, or during unit testing.
///
}
/// <!-- description -->
/// @brief Executes the CPUID instruction given the provided
/// EAX and ECX and returns the results.
///
/// <!-- inputs/outputs -->
/// @param gs the gs_t to use
/// @param tls the tls_t to use
/// @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
///
static constexpr void
cpuid(
gs_t &gs,
tls_t &tls,
bsl::safe_uint64 &rax,
bsl::safe_uint64 &rbx,
bsl::safe_uint64 &rcx,
bsl::safe_uint64 &rdx) noexcept
{
bsl::discard(tls);
intrinsic_cpuid_impl(&gs, rax.data(), rbx.data(), rcx.data(), rdx.data());
}
};
}
#endif

View file

@ -0,0 +1,66 @@
/// @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 TLS_T_HPP
#define TLS_T_HPP
#include <bsl/convert.hpp>
#include <bsl/safe_integral.hpp>
namespace example
{
/// @class example::tls_t
///
/// <!-- 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.
///
struct tls_t final
{
/// @brief dummy data for example purposes only.
bsl::safe_uintmax dummy;
};
/// @brief defines the max size supported for the TLS block
constexpr auto MAX_TLS_SIZE{HYPERVISOR_PAGE_SIZE};
/// @brief ensure that the tls_t does not exceed the max supported size
static_assert(!(sizeof(tls_t) > MAX_TLS_SIZE));
}
#endif

View file

@ -0,0 +1,401 @@
/// @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 VMEXIT_T_HPP
#define VMEXIT_T_HPP
#include <bf_debug_ops.hpp>
#include <bf_syscall_t.hpp>
#include <cpuid_commands.hpp>
#include <gs_t.hpp>
#include <intrinsic_t.hpp>
#include <tls_t.hpp>
#include <vp_pool_t.hpp>
#include <vps_pool_t.hpp>
#include <bsl/debug.hpp>
#include <bsl/discard.hpp>
#include <bsl/errc_type.hpp>
#include <bsl/safe_integral.hpp>
#include <bsl/unlikely_assert.hpp>
namespace example
{
/// @class example::vmexit_t
///
/// <!-- description -->
/// @brief Defines the extension's VMExit handler
///
class vmexit_t final
{
public:
/// <!-- description -->
/// @brief Initializes this vmexit_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
/// @param vp_pool the vp_pool_t to use
/// @param vps_pool the vps_pool_t to use
/// @return Returns bsl::errc_success on success, bsl::errc_failure
/// and friends otherwise
///
[[nodiscard]] static constexpr auto
initialize(
gs_t &gs,
tls_t &tls,
syscall::bf_syscall_t &sys,
intrinsic_t &intrinsic,
vp_pool_t &vp_pool,
vps_pool_t &vps_pool) noexcept -> bsl::errc_type
{
bsl::discard(gs);
bsl::discard(tls);
bsl::discard(sys);
bsl::discard(intrinsic);
bsl::discard(vp_pool);
bsl::discard(vps_pool);
/// NOTE:
/// - Add initialization code here if needed. Otherwise, this
/// function can be removed if it is not needed.
///
return bsl::errc_success;
}
/// <!-- description -->
/// @brief Release the vmexit_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
/// @param vp_pool the vp_pool_t to use
/// @param vps_pool the vps_pool_t to use
///
static constexpr void
release(
gs_t &gs,
tls_t &tls,
syscall::bf_syscall_t &sys,
intrinsic_t &intrinsic,
vp_pool_t &vp_pool,
vps_pool_t &vps_pool) noexcept
{
bsl::discard(gs);
bsl::discard(tls);
bsl::discard(sys);
bsl::discard(intrinsic);
bsl::discard(vp_pool);
bsl::discard(vps_pool);
/// NOTE:
/// - Release functions are usually only needed in the event of
/// an error, or during unit testing.
///
}
/// <!-- 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 vp_pool the vp_pool_t to use
/// @param vps_pool the vps_pool_t to use
/// @param vpsid the ID of the VPS that generated the VMExit
/// @return Returns bsl::errc_success on success, bsl::errc_failure
/// and friends otherwise
///
[[nodiscard]] static constexpr auto
handle_cpuid(
gs_t &gs,
tls_t &tls,
syscall::bf_syscall_t &sys,
intrinsic_t &intrinsic,
vp_pool_t &vp_pool,
vps_pool_t &vps_pool,
bsl::safe_uint16 const &vpsid) noexcept -> bsl::errc_type
{
bsl::discard(vp_pool);
bsl::discard(vps_pool);
bsl::errc_type ret{};
/// NOTE:
/// - The first thing that we need to do is get the current values
/// of RAX, RBX, RCX and RDX. We use the full 64bit versions to
/// ensure that we leave the upper half of these values intact,
/// otherwise we would not be emulating the execution of CPUID
/// correctly.
///
auto rax{sys.bf_tls_rax()};
auto rbx{sys.bf_tls_rbx()};
auto rcx{sys.bf_tls_rcx()};
auto rdx{sys.bf_tls_rdx()};
/// 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:
/// - 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 a debugging feature that can
/// be disabled, but it helps to track if memory is
/// being over used.
///
if (sys.bf_tls_ppid() == (sys.bf_tls_online_pps() - 1_u16)) {
bsl::print() << bsl::endl;
syscall::bf_debug_op_dump_page_pool();
bsl::print() << bsl::endl;
}
else {
bsl::touch();
}
/// NOTE:
/// - If the debug level is set to something higher
/// than bsl::V, we can print out a VMExit log. How
/// many entries we print is configurable, and you
/// can control which PP you want to output if you
/// only care about a specific PP. Note that this log
/// will show VMExits for the whole PP, meaning you
/// will see the order in which different VM's are
/// making VMExits. The VMExit log doesn't attempt
/// to decode anything, so that is up to you.
///
if constexpr (BSL_DEBUG_LEVEL > bsl::V) {
bsl::print() << bsl::endl;
syscall::bf_debug_op_dump_vmexit_log(sys.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.
///
bsl::debug() << bsl::rst << "about to" // --
<< bsl::red << " promote " // --
<< bsl::rst << "root OS on pp " // --
<< bsl::cyn << bsl::hex(sys.bf_tls_ppid()) // --
<< bsl::rst << bsl::endl; // --
/// NOTE:
/// - Report success
///
sys.bf_tls_set_rax(loader::CPUID_COMMAND_RAX_SUCCESS);
/// NOTE:
/// - Before we can stop, we need to advance RIP.
/// Normally, all of the other commands will advance
/// and return to the VM at the end of this switch
/// statement, but in this case, promote will not
/// exit before then so we need to advance now.
///
ret = sys.bf_vps_op_advance_ip(vpsid);
if (bsl::unlikely_assert(!ret)) {
bsl::print<bsl::V>() << bsl::here();
return ret;
}
/// NOTE:
/// - The promote ABI will load the microkernel by
/// replacing the CPU's state withthe VP state
/// associated with the provided VPSID. If all
/// goes well, bf_vps_op_promote will not return,
/// and the system will continue executing with the
/// hypervisor turned off.
///
return sys.bf_vps_op_promote(vpsid);
}
case loader::CPUID_COMMAND_ECX_REPORT_ON.get(): {
/// NOTE:
/// - Report that the root OS is now in a VM for this
/// specific PP. Note that you can do whatever you
/// want here, this is just the default behavior.
///
bsl::debug() << bsl::rst << "root OS had been" // --
<< bsl::grn << " demoted " // --
<< bsl::rst << "to vm " // --
<< bsl::cyn << bsl::hex(sys.bf_tls_vmid()) // --
<< bsl::rst << " on pp " // --
<< bsl::cyn << bsl::hex(sys.bf_tls_ppid()) // --
<< bsl::rst << bsl::endl; // --
break;
}
case loader::CPUID_COMMAND_ECX_REPORT_OFF.get(): {
/// NOTE:
/// - There is nothing to do here as we report off
/// right before promotion takes place. Extensions
/// can use this as a means to perform actions if
/// needed right before the loader sends the stop
/// command. Just note that this command does not
/// report success/failure.
///
break;
}
default: {
bsl::error() << "unsupported cpuid command " // --
<< bsl::hex(rcx) // --
<< bsl::endl // --
<< bsl::here(); // --
break;
}
}
/// NOTE:
/// - Complete this command by advancing RIP and running
/// the currently loaded VM, VP and VPS.
///
return sys.bf_vps_op_advance_ip_and_run_current();
}
/// NOTE:
/// - If we got 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(gs, tls, rax, rbx, rcx, rdx);
/// NOTE:
/// - Write the results of CPUID to the VP's registers. Note that
/// the above CPUID intrinsic takes in the full 64bit registers
/// but only touches the lower half of each register, which makes
/// sure that we are emulating CPUID properly.
///
sys.bf_tls_set_rax(rax);
sys.bf_tls_set_rbx(rbx);
sys.bf_tls_set_rcx(rcx);
sys.bf_tls_set_rdx(rdx);
/// NOTE:
/// - Complete the emulation of CPUID by advancing RIP and running
/// the currently loaded VM, VP and VPS.
///
return sys.bf_vps_op_advance_ip_and_run_current();
}
/// <!-- 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 vps_pool the vps_pool_t to use
/// @param vpsid the ID of the VPS 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
///
[[nodiscard]] static constexpr auto
dispatch(
gs_t &gs,
tls_t &tls,
syscall::bf_syscall_t &sys,
intrinsic_t &intrinsic,
vp_pool_t &vp_pool,
vps_pool_t &vps_pool,
bsl::safe_uint16 const &vpsid,
bsl::safe_uint64 const &exit_reason) noexcept -> bsl::errc_type
{
/// NOTE:
/// - Define the different VMExits that this dispatcher will
/// support. At a minimum, we need to handle CPUID on AMD.
///
constexpr auto exit_reason_cpuid{0x72_u64};
/// NOTE:
/// - Dispatch and handle each VMExit.
///
switch (exit_reason.get()) {
case exit_reason_cpuid.get(): {
return handle_cpuid(gs, tls, sys, intrinsic, vp_pool, vps_pool, vpsid);
}
default: {
break;
}
}
/// NOTE:
/// - If we got this far, it means that we were given a VMExit
/// that we do not handle.
///
bsl::error() << "unsupported vmexit " // --
<< bsl::hex(exit_reason) // --
<< bsl::endl // --
<< bsl::here(); // --
return bsl::errc_failure;
}
};
}
#endif

View file

@ -0,0 +1,347 @@
/// @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 VPS_T_HPP
#define VPS_T_HPP
#include <bf_constants.hpp>
#include <bf_syscall_t.hpp>
#include <gs_t.hpp>
#include <intrinsic_t.hpp>
#include <tls_t.hpp>
#include <bsl/discard.hpp>
#include <bsl/errc_type.hpp>
#include <bsl/safe_integral.hpp>
#include <bsl/touch.hpp>
#include <bsl/unlikely_assert.hpp>
namespace example
{
/// @class example::vps_t
///
/// <!-- description -->
/// @brief Defines the extension's notion of a VPS
///
class vps_t final
{
/// @brief stores the ID associated with this vps_t
bsl::safe_uint16 m_id{bsl::safe_uint16::failure()};
/// @brief stores the ID of the VP this vps_t is assigned to
bsl::safe_uint16 m_assigned_vpid{syscall::BF_INVALID_ID};
/// @brief stores the ID of the PP this vps_t is assigned to
bsl::safe_uint16 m_assigned_ppid{syscall::BF_INVALID_ID};
public:
/// <!-- description -->
/// @brief Initializes this vps_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
/// @param i the ID for this vps_t
/// @return Returns bsl::errc_success on success, bsl::errc_failure
/// and friends otherwise
///
[[nodiscard]] constexpr auto
initialize(
gs_t &gs,
tls_t &tls,
syscall::bf_syscall_t &sys,
intrinsic_t &intrinsic,
bsl::safe_uint16 const &i) noexcept -> bsl::errc_type
{
bsl::discard(gs);
bsl::discard(tls);
bsl::discard(sys);
bsl::discard(intrinsic);
/// NOTE:
/// - The following is a pedantic check to make sure we have
/// not already initialized ourselves. In larger extensions,
/// this is useful as it helps to weed out hard to find bugs.
/// In a small example like this, it is completely overkill,
/// but is added for completeness.
///
if (bsl::unlikely_assert(m_id)) {
bsl::error() << "vps_t already initialized\n" << bsl::here();
return bsl::errc_precondition;
}
/// NOTE:
/// - The following are some pedantic checks on the input. In
/// larger extensions, this is useful as it helps to weed
/// out hard to find bugs. In a small example like this, it
/// is completely overkill, but is added for completeness.
/// - We check to to make sure that we were given a valid ID,
/// meaning the safe integral is not storing an error, and we
/// also check to make sure the ID itself is not the reserved
/// syscall::BF_INVALID_ID as that is also not allowed.
///
if (bsl::unlikely_assert(!i)) {
bsl::error() << "invalid id\n" << bsl::here();
return bsl::errc_invalid_argument;
}
if (bsl::unlikely_assert(syscall::BF_INVALID_ID == i)) {
bsl::error() << "id " // --
<< bsl::hex(i) // --
<< " is invalid and cannot be used for initialization" // --
<< bsl::endl // --
<< bsl::here(); // --
return bsl::errc_invalid_argument;
}
/// NOTE:
/// - Finally, store the ID assigned to this vps_t and report
/// success.
///
m_id = i;
return bsl::errc_success;
}
/// <!-- description -->
/// @brief Release the vps_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
///
constexpr void
release(gs_t &gs, tls_t &tls, syscall::bf_syscall_t &sys, intrinsic_t &intrinsic) noexcept
{
bsl::discard(gs);
bsl::discard(tls);
bsl::discard(sys);
bsl::discard(intrinsic);
/// NOTE:
/// - Release functions are usually only needed in the event of
/// an error, or during unit testing.
///
m_assigned_ppid = syscall::BF_INVALID_ID;
m_assigned_vpid = syscall::BF_INVALID_ID;
m_id = bsl::safe_uint16::failure();
}
/// <!-- description -->
/// @brief Allocates a vps_t 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 vps_t to
/// @param ppid the ID of the PP to assign the vps_t to
/// @return Returns bsl::errc_success on success, bsl::errc_failure
/// and friends otherwise
///
[[nodiscard]] constexpr auto
allocate(
gs_t &gs,
tls_t &tls,
syscall::bf_syscall_t &sys,
intrinsic_t &intrinsic,
bsl::safe_uint16 const &vpid,
bsl::safe_uint16 const &ppid) noexcept -> bsl::errc_type
{
bsl::discard(gs);
bsl::discard(tls);
bsl::discard(intrinsic);
bsl::errc_type ret{};
/// NOTE:
/// - The following is a pedantic check to make sure we have
/// been initialized by the vp_pool_t. In larger extensions,
/// this is useful as it helps to weed out hard to find bugs.
/// In a small example like this, it is completely overkill,
/// but is added for completeness.
///
if (bsl::unlikely_assert(!m_id)) {
bsl::error() << "vps_t not initialized\n" << bsl::here();
return bsl::errc_precondition;
}
/// NOTE:
/// - The following is a pedantic check to make sure we have
/// not already allocated this vps_t. In larger extensions,
/// this is useful as it helps to weed out hard to find bugs.
/// In a small example like this, it is completely overkill,
/// but is added for completeness.
///
if (bsl::unlikely_assert(syscall::BF_INVALID_ID != m_assigned_ppid)) {
bsl::error() << "vp " // --
<< bsl::hex(m_id) // --
<< " is already allocated and cannot be created" // --
<< bsl::endl // --
<< bsl::here(); // --
return bsl::errc_precondition;
}
/// NOTE:
/// - The following are some pedantic checks on the input. In
/// larger extensions, this is useful as it helps to weed
/// out hard to find bugs. In a small example like this, it
/// is completely overkill, but is added for completeness.
/// - We check to to make sure that we were given a valid ID,
/// meaning the safe integral is not storing an error, and we
/// also check to make sure the ID itself is not the reserved
/// syscall::BF_INVALID_ID as that is also not allowed.
///
if (bsl::unlikely_assert(!vpid)) {
bsl::error() << "invalid vpid\n" << bsl::here();
return bsl::errc_invalid_argument;
}
if (bsl::unlikely_assert(syscall::BF_INVALID_ID == vpid)) {
bsl::error() << "vm " // --
<< bsl::hex(vpid) // --
<< " is invalid and a vp cannot be assigned to it" // --
<< bsl::endl // --
<< bsl::here(); // --
return bsl::errc_invalid_argument;
}
if (bsl::unlikely_assert(!ppid)) {
bsl::error() << "invalid ppid\n" << bsl::here();
return bsl::errc_invalid_argument;
}
if (bsl::unlikely_assert(syscall::BF_INVALID_ID == ppid)) {
bsl::error() << "pp " // --
<< bsl::hex(ppid) // --
<< " is invalid and a vp cannot be assigned to it" // --
<< bsl::endl // --
<< bsl::here(); // --
return bsl::errc_invalid_argument;
}
/// NOTE:
/// - Initialize the VPS as a root VPS. When the microkernel was
/// started, the loader saved the state of the root VP. This
/// syscall tells the microkernel to load the VPS with this saved
/// state so that when we run the VP, it will contain the state
/// just before the microkernel was started.
/// - In other words, this is what allows the microkernel to return
/// back to the loader once the hypervisor is running.
/// - You only want to run this on root VPs. VPs that are being
/// created for guest VPs should not use this, as it would give
/// the guest VP the state associated with the root VP. Also
/// note that once the root VP has executed, this ABI is no
/// longer useful as the state stored in the microkernel would be
/// out-dated. For root VPs, that ID of the PP should always be
/// the same as the IP of the VP, so we added this check for
/// completeness just in case cut/paste is used here.
///
if (ppid == m_id) {
ret = sys.bf_vps_op_init_as_root(m_id);
if (bsl::unlikely_assert(!ret)) {
bsl::print<bsl::V>() << bsl::here();
return ret;
}
bsl::touch();
}
else {
/// NOTE:
/// - The call to bsl::touch is only needed if you plan to
/// enforce MC/DC unit testing. Feel free to remove this if
/// you have no plans to support MC/DC unit testing.
///
bsl::touch();
}
/// NOTE:
/// - Set up ASID. For this simple example, we will use "1", but
/// in most cases you will want to use something based on the
/// VMID that this VPS is assigned to (which is based on which
/// VP the VPS is assigned to, as VPs are assigned to VMs and
/// VPSs are assigned to VPs).
///
constexpr auto guest_asid_idx{0x0058_u64};
constexpr auto guest_asid_val{0x1_u32};
ret = sys.bf_vps_op_write32(m_id, guest_asid_idx, guest_asid_val);
if (bsl::unlikely_assert(!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 auto intercept_instr1_idx{0x000C_u64};
constexpr auto intercept_instr1_val{0x00040000_u32};
constexpr auto intercept_instr2_idx{0x0010_u64};
constexpr auto intercept_instr2_val{0x00000001_u32};
ret = sys.bf_vps_op_write32(m_id, intercept_instr1_idx, intercept_instr1_val);
if (bsl::unlikely_assert(!ret)) {
bsl::print<bsl::V>() << bsl::here();
return ret;
}
ret = sys.bf_vps_op_write32(m_id, intercept_instr2_idx, intercept_instr2_val);
if (bsl::unlikely_assert(!ret)) {
bsl::print<bsl::V>() << bsl::here();
return ret;
}
/// NOTE:
/// - Finally, store the IDs of the VP and PP that this vps_t is
/// assigned to and reprot success.
///
m_assigned_vpid = vpid;
m_assigned_ppid = ppid;
return bsl::errc_success;
}
};
}
#endif

View file

@ -0,0 +1,52 @@
/// @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 GS_T_HPP
#define GS_T_HPP
#include <bsl/safe_integral.hpp>
namespace example
{
/// @class example::gs_t
///
/// <!-- 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.
///
struct gs_t final
{
/// @brief stores the MSR bitmap used by this vps_t
void *msr_bitmap{};
/// @brief stores the physical address of the MSR bitmap above
bsl::safe_uintmax msr_bitmap_phys{};
};
}
#endif

View file

@ -0,0 +1,117 @@
/// @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 INTRINSIC_HPP
#define INTRINSIC_HPP
#include <gs_t.hpp>
#include <intrinsic_cpuid_impl.hpp>
#include <tls_t.hpp>
#include <bsl/discard.hpp>
#include <bsl/errc_type.hpp>
#include <bsl/safe_integral.hpp>
namespace example
{
/// @class example::intrinsic_t
///
/// <!-- description -->
/// @brief Provides raw access to intrinsics. Instead of using global
/// functions, the intrinsics class provides a means for the rest of
/// the extension to mock the intrinsics when needed during testing.
///
class intrinsic_t final
{
public:
/// <!-- description -->
/// @brief Initializes this intrinsic_t.
///
/// <!-- inputs/outputs -->
/// @param gs the gs_t to use
/// @param tls the tls_t to use
/// @return Returns bsl::errc_success on success, bsl::errc_failure
/// and friends otherwise
///
[[nodiscard]] static constexpr auto
initialize(gs_t &gs, tls_t &tls) noexcept -> bsl::errc_type
{
bsl::discard(gs);
bsl::discard(tls);
/// NOTE:
/// - Add initialization code here if needed. Otherwise, this
/// function can be removed if it is not needed.
///
return bsl::errc_success;
}
/// <!-- description -->
/// @brief Release the intrinsic_t.
///
/// <!-- inputs/outputs -->
/// @param gs the gs_t to use
/// @param tls the tls_t to use
///
static constexpr void
release(gs_t &gs, tls_t &tls) noexcept
{
bsl::discard(gs);
bsl::discard(tls);
/// NOTE:
/// - Release functions are usually only needed in the event of
/// an error, or during unit testing.
///
}
/// <!-- description -->
/// @brief Executes the CPUID instruction given the provided
/// EAX and ECX and returns the results.
///
/// <!-- inputs/outputs -->
/// @param gs the gs_t to use
/// @param tls the tls_t to use
/// @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
///
static constexpr void
cpuid(
gs_t &gs,
tls_t &tls,
bsl::safe_uint64 &rax,
bsl::safe_uint64 &rbx,
bsl::safe_uint64 &rcx,
bsl::safe_uint64 &rdx) noexcept
{
bsl::discard(tls);
intrinsic_cpuid_impl(&gs, rax.data(), rbx.data(), rcx.data(), rdx.data());
}
};
}
#endif

View file

@ -0,0 +1,66 @@
/// @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 TLS_T_HPP
#define TLS_T_HPP
#include <bsl/convert.hpp>
#include <bsl/safe_integral.hpp>
namespace example
{
/// @class example::tls_t
///
/// <!-- 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.
///
struct tls_t final
{
/// @brief dummy data for example purposes only.
bsl::safe_uintmax dummy;
};
/// @brief defines the max size supported for the TLS block
constexpr auto MAX_TLS_SIZE{HYPERVISOR_PAGE_SIZE};
/// @brief ensure that the tls_t does not exceed the max supported size
static_assert(!(sizeof(tls_t) > MAX_TLS_SIZE));
}
#endif

View file

@ -0,0 +1,570 @@
/// @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 VMEXIT_T_HPP
#define VMEXIT_T_HPP
#include <bf_debug_ops.hpp>
#include <bf_syscall_t.hpp>
#include <cpuid_commands.hpp>
#include <gs_t.hpp>
#include <intrinsic_t.hpp>
#include <tls_t.hpp>
#include <vp_pool_t.hpp>
#include <vps_pool_t.hpp>
#include <bsl/debug.hpp>
#include <bsl/discard.hpp>
#include <bsl/errc_type.hpp>
#include <bsl/safe_integral.hpp>
#include <bsl/unlikely_assert.hpp>
namespace example
{
/// @class example::vmexit_t
///
/// <!-- description -->
/// @brief Defines the extension's VMExit handler
///
class vmexit_t final
{
public:
/// <!-- description -->
/// @brief Initializes this vmexit_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
/// @param vp_pool the vp_pool_t to use
/// @param vps_pool the vps_pool_t to use
/// @return Returns bsl::errc_success on success, bsl::errc_failure
/// and friends otherwise
///
[[nodiscard]] static constexpr auto
initialize(
gs_t &gs,
tls_t &tls,
syscall::bf_syscall_t &sys,
intrinsic_t &intrinsic,
vp_pool_t &vp_pool,
vps_pool_t &vps_pool) noexcept -> bsl::errc_type
{
bsl::discard(tls);
bsl::discard(intrinsic);
bsl::discard(vp_pool);
bsl::discard(vps_pool);
gs.msr_bitmap = sys.bf_mem_op_alloc_page(gs.msr_bitmap_phys);
if (bsl::unlikely_assert(nullptr == gs.msr_bitmap)) {
bsl::print<bsl::V>() << bsl::here();
return bsl::errc_failure;
}
/// NOTE:
/// - Add initialization code here if needed. Otherwise, this
/// function can be removed if it is not needed.
///
return bsl::errc_success;
}
/// <!-- description -->
/// @brief Release the vmexit_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
/// @param vp_pool the vp_pool_t to use
/// @param vps_pool the vps_pool_t to use
///
static constexpr void
release(
gs_t &gs,
tls_t &tls,
syscall::bf_syscall_t &sys,
intrinsic_t &intrinsic,
vp_pool_t &vp_pool,
vps_pool_t &vps_pool) noexcept
{
bsl::errc_type ret{};
bsl::discard(tls);
bsl::discard(intrinsic);
bsl::discard(vp_pool);
bsl::discard(vps_pool);
/// NOTE:
/// - Release functions are usually only needed in the event of
/// an error, or during unit testing.
///
ret = sys.bf_mem_op_free_page(gs.msr_bitmap);
if (bsl::unlikely_assert(!ret)) {
bsl::print<bsl::V>() << bsl::here();
}
else {
bsl::touch();
}
gs.msr_bitmap = {};
gs.msr_bitmap_phys = {};
}
/// <!-- 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 intrinsic the intrinsic_t to use
/// @param vp_pool the vp_pool_t to use
/// @param vps_pool the vps_pool_t to use
/// @param vpsid the ID of the VPS that generated the VMExit
/// @return Returns bsl::errc_success on success, bsl::errc_failure
/// and friends otherwise
///
[[nodiscard]] static constexpr auto
handle_nmi(
gs_t &gs,
tls_t &tls,
syscall::bf_syscall_t &sys,
intrinsic_t &intrinsic,
vp_pool_t &vp_pool,
vps_pool_t &vps_pool,
bsl::safe_uint16 const &vpsid) noexcept -> bsl::errc_type
{
bsl::discard(gs);
bsl::discard(tls);
bsl::discard(intrinsic);
bsl::discard(vp_pool);
bsl::discard(vps_pool);
/// 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 VPS.
///
constexpr auto vmcs_procbased_ctls_idx{0x4002_u64};
constexpr auto vmcs_set_nmi_window_exiting{0x400000_u32};
bsl::safe_uint32 val{};
bsl::errc_type ret{};
val = sys.bf_vps_op_read32(vpsid, vmcs_procbased_ctls_idx);
if (bsl::unlikely_assert(!val)) {
bsl::print<bsl::V>() << bsl::here();
return bsl::errc_failure;
}
val |= vmcs_set_nmi_window_exiting;
ret = sys.bf_vps_op_write32(vpsid, vmcs_procbased_ctls_idx, val);
if (bsl::unlikely_assert(!ret)) {
bsl::print<bsl::V>() << bsl::here();
return ret;
}
return sys.bf_vps_op_run_current();
}
/// <!-- 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 intrinsic the intrinsic_t to use
/// @param vp_pool the vp_pool_t to use
/// @param vps_pool the vps_pool_t to use
/// @param vpsid the ID of the VPS that generated the VMExit
/// @return Returns bsl::errc_success on success, bsl::errc_failure
/// and friends otherwise
///
[[nodiscard]] static constexpr auto
handle_nmi_window(
gs_t &gs,
tls_t &tls,
syscall::bf_syscall_t &sys,
intrinsic_t &intrinsic,
vp_pool_t &vp_pool,
vps_pool_t &vps_pool,
bsl::safe_uint16 const &vpsid) noexcept -> bsl::errc_type
{
bsl::discard(gs);
bsl::discard(tls);
bsl::discard(intrinsic);
bsl::discard(vp_pool);
bsl::discard(vps_pool);
/// 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 VPS is running. In either case, we need to
/// clear the NMI window and inject the NMI into the appropriate
/// VPS 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 auto vmcs_procbased_ctls_idx{0x4002_u64};
constexpr auto vmcs_clear_nmi_window_exiting{0xFFBFFFFF_u32};
bsl::safe_uint32 val{};
bsl::errc_type ret{};
val = sys.bf_vps_op_read32(vpsid, vmcs_procbased_ctls_idx);
if (bsl::unlikely_assert(!val)) {
bsl::print<bsl::V>() << bsl::here();
return bsl::errc_failure;
}
val &= vmcs_clear_nmi_window_exiting;
ret = sys.bf_vps_op_write32(vpsid, vmcs_procbased_ctls_idx, val);
if (bsl::unlikely_assert(!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 auto vmcs_entry_interrupt_info_idx{0x4016_u64};
constexpr auto vmcs_entry_interrupt_info_val{0x80000202_u32};
ret = sys.bf_vps_op_write32(
vpsid, vmcs_entry_interrupt_info_idx, vmcs_entry_interrupt_info_val);
if (bsl::unlikely_assert(!ret)) {
bsl::print<bsl::V>() << bsl::here();
return ret;
}
return sys.bf_vps_op_run_current();
}
/// <!-- 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 vp_pool the vp_pool_t to use
/// @param vps_pool the vps_pool_t to use
/// @param vpsid the ID of the VPS that generated the VMExit
/// @return Returns bsl::errc_success on success, bsl::errc_failure
/// and friends otherwise
///
[[nodiscard]] static constexpr auto
handle_cpuid(
gs_t &gs,
tls_t &tls,
syscall::bf_syscall_t &sys,
intrinsic_t &intrinsic,
vp_pool_t &vp_pool,
vps_pool_t &vps_pool,
bsl::safe_uint16 const &vpsid) noexcept -> bsl::errc_type
{
bsl::discard(vp_pool);
bsl::discard(vps_pool);
bsl::errc_type ret{};
/// NOTE:
/// - The first thing that we need to do is get the current values
/// of RAX, RBX, RCX and RDX. We use the full 64bit versions to
/// ensure that we leave the upper half of these values intact,
/// otherwise we would not be emulating the execution of CPUID
/// correctly.
///
auto rax{sys.bf_tls_rax()};
auto rbx{sys.bf_tls_rbx()};
auto rcx{sys.bf_tls_rcx()};
auto rdx{sys.bf_tls_rdx()};
/// 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:
/// - 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 a debugging feature that can
/// be disabled, but it helps to track if memory is
/// being over used.
///
if (sys.bf_tls_ppid() == (sys.bf_tls_online_pps() - 1_u16)) {
bsl::print() << bsl::endl;
syscall::bf_debug_op_dump_page_pool();
bsl::print() << bsl::endl;
}
else {
bsl::touch();
}
/// NOTE:
/// - If the debug level is set to something higher
/// than bsl::V, we can print out a VMExit log. How
/// many entries we print is configurable, and you
/// can control which PP you want to output if you
/// only care about a specific PP. Note that this log
/// will show VMExits for the whole PP, meaning you
/// will see the order in which different VM's are
/// making VMExits. The VMExit log doesn't attempt
/// to decode anything, so that is up to you.
///
if constexpr (BSL_DEBUG_LEVEL > bsl::V) {
bsl::print() << bsl::endl;
syscall::bf_debug_op_dump_vmexit_log(sys.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.
///
bsl::debug() << bsl::rst << "about to" // --
<< bsl::red << " promote " // --
<< bsl::rst << "root OS on pp " // --
<< bsl::cyn << bsl::hex(sys.bf_tls_ppid()) // --
<< bsl::rst << bsl::endl; // --
/// NOTE:
/// - Report success
///
sys.bf_tls_set_rax(loader::CPUID_COMMAND_RAX_SUCCESS);
/// NOTE:
/// - Before we can stop, we need to advance RIP.
/// Normally, all of the other commands will advance
/// and return to the VM at the end of this switch
/// statement, but in this case, promote will not
/// exit before then so we need to advance now.
///
ret = sys.bf_vps_op_advance_ip(vpsid);
if (bsl::unlikely_assert(!ret)) {
bsl::print<bsl::V>() << bsl::here();
return ret;
}
/// NOTE:
/// - The promote ABI will load the microkernel by
/// replacing the CPU's state withthe VP state
/// associated with the provided VPSID. If all
/// goes well, bf_vps_op_promote will not return,
/// and the system will continue executing with the
/// hypervisor turned off.
///
return sys.bf_vps_op_promote(vpsid);
}
case loader::CPUID_COMMAND_ECX_REPORT_ON.get(): {
/// NOTE:
/// - Report that the root OS is now in a VM for this
/// specific PP. Note that you can do whatever you
/// want here, this is just the default behavior.
///
bsl::debug() << bsl::rst << "root OS had been" // --
<< bsl::grn << " demoted " // --
<< bsl::rst << "to vm " // --
<< bsl::cyn << bsl::hex(sys.bf_tls_vmid()) // --
<< bsl::rst << " on pp " // --
<< bsl::cyn << bsl::hex(sys.bf_tls_ppid()) // --
<< bsl::rst << bsl::endl; // --
break;
}
case loader::CPUID_COMMAND_ECX_REPORT_OFF.get(): {
/// NOTE:
/// - There is nothing to do here as we report off
/// right before promotion takes place. Extensions
/// can use this as a means to perform actions if
/// needed right before the loader sends the stop
/// command. Just note that this command does not
/// report success/failure.
///
break;
}
default: {
bsl::error() << "unsupported cpuid command " // --
<< bsl::hex(rcx) // --
<< bsl::endl // --
<< bsl::here(); // --
break;
}
}
/// NOTE:
/// - Complete this command by advancing RIP and running
/// the currently loaded VM, VP and VPS.
///
return sys.bf_vps_op_advance_ip_and_run_current();
}
/// NOTE:
/// - If we got 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(gs, tls, rax, rbx, rcx, rdx);
/// NOTE:
/// - Write the results of CPUID to the VP's registers. Note that
/// the above CPUID intrinsic takes in the full 64bit registers
/// but only touches the lower half of each register, which makes
/// sure that we are emulating CPUID properly.
///
sys.bf_tls_set_rax(rax);
sys.bf_tls_set_rbx(rbx);
sys.bf_tls_set_rcx(rcx);
sys.bf_tls_set_rdx(rdx);
/// NOTE:
/// - Complete the emulation of CPUID by advancing RIP and running
/// the currently loaded VM, VP and VPS.
///
return sys.bf_vps_op_advance_ip_and_run_current();
}
/// <!-- 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 vps_pool the vps_pool_t to use
/// @param vpsid the ID of the VPS 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
///
[[nodiscard]] static constexpr auto
dispatch(
gs_t &gs,
tls_t &tls,
syscall::bf_syscall_t &sys,
intrinsic_t &intrinsic,
vp_pool_t &vp_pool,
vps_pool_t &vps_pool,
bsl::safe_uint16 const &vpsid,
bsl::safe_uint64 const &exit_reason) noexcept -> bsl::errc_type
{
/// NOTE:
/// - Define the different VMExits that this dispatcher will
/// support. At a minimum, we need to handle CPUID, and NMIs
/// on Intel (as there is no way to disable NMIs on Intel).
///
constexpr auto exit_reason_nmi{0x0_u64};
constexpr auto exit_reason_nmi_window{0x8_u64};
constexpr auto exit_reason_cpuid{0xA_u64};
/// NOTE:
/// - Dispatch and handle each VMExit.
///
switch (exit_reason.get()) {
case exit_reason_nmi.get(): {
return handle_nmi(gs, tls, sys, intrinsic, vp_pool, vps_pool, vpsid);
}
case exit_reason_nmi_window.get(): {
return handle_nmi_window(gs, tls, sys, intrinsic, vp_pool, vps_pool, vpsid);
}
case exit_reason_cpuid.get(): {
return handle_cpuid(gs, tls, sys, intrinsic, vp_pool, vps_pool, vpsid);
}
default: {
break;
}
}
/// NOTE:
/// - If we got this far, it means that we were given a VMExit
/// that we do not handle.
///
bsl::error() << "unsupported vmexit " // --
<< bsl::hex(exit_reason) // --
<< bsl::endl // --
<< bsl::here(); // --
return bsl::errc_failure;
}
};
}
#endif

View file

@ -0,0 +1,500 @@
/// @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 VPS_T_HPP
#define VPS_T_HPP
#include <bf_constants.hpp>
#include <bf_syscall_t.hpp>
#include <gs_t.hpp>
#include <intrinsic_t.hpp>
#include <tls_t.hpp>
#include <bsl/convert.hpp>
#include <bsl/discard.hpp>
#include <bsl/errc_type.hpp>
#include <bsl/safe_integral.hpp>
#include <bsl/touch.hpp>
#include <bsl/unlikely_assert.hpp>
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_uint64 const &val) noexcept -> bsl::safe_uint32
{
constexpr auto mask{0x00000000FFFFFFFF_u64};
constexpr auto shift{32_u64};
return bsl::to_u32_unsafe((val & mask) & (val >> shift));
};
/// @class example::vps_t
///
/// <!-- description -->
/// @brief Defines the extension's notion of a VPS
///
class vps_t final
{
/// @brief stores the ID associated with this vps_t
bsl::safe_uint16 m_id{bsl::safe_uint16::failure()};
/// @brief stores the ID of the VP this vps_t is assigned to
bsl::safe_uint16 m_assigned_vpid{syscall::BF_INVALID_ID};
/// @brief stores the ID of the PP this vps_t is assigned to
bsl::safe_uint16 m_assigned_ppid{syscall::BF_INVALID_ID};
public:
/// <!-- description -->
/// @brief Initializes this vps_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
/// @param i the ID for this vps_t
/// @return Returns bsl::errc_success on success, bsl::errc_failure
/// and friends otherwise
///
[[nodiscard]] constexpr auto
initialize(
gs_t &gs,
tls_t &tls,
syscall::bf_syscall_t &sys,
intrinsic_t &intrinsic,
bsl::safe_uint16 const &i) noexcept -> bsl::errc_type
{
bsl::discard(gs);
bsl::discard(tls);
bsl::discard(sys);
bsl::discard(intrinsic);
/// NOTE:
/// - The following is a pedantic check to make sure we have
/// not already initialized ourselves. In larger extensions,
/// this is useful as it helps to weed out hard to find bugs.
/// In a small example like this, it is completely overkill,
/// but is added for completeness.
///
if (bsl::unlikely_assert(m_id)) {
bsl::error() << "vps_t already initialized\n" << bsl::here();
return bsl::errc_precondition;
}
/// NOTE:
/// - The following are some pedantic checks on the input. In
/// larger extensions, this is useful as it helps to weed
/// out hard to find bugs. In a small example like this, it
/// is completely overkill, but is added for completeness.
/// - We check to to make sure that we were given a valid ID,
/// meaning the safe integral is not storing an error, and we
/// also check to make sure the ID itself is not the reserved
/// syscall::BF_INVALID_ID as that is also not allowed.
///
if (bsl::unlikely_assert(!i)) {
bsl::error() << "invalid id\n" << bsl::here();
return bsl::errc_invalid_argument;
}
if (bsl::unlikely_assert(syscall::BF_INVALID_ID == i)) {
bsl::error() << "id " // --
<< bsl::hex(i) // --
<< " is invalid and cannot be used for initialization" // --
<< bsl::endl // --
<< bsl::here(); // --
return bsl::errc_invalid_argument;
}
/// NOTE:
/// - Finally, store the ID assigned to this vps_t and report
/// success.
///
m_id = i;
return bsl::errc_success;
}
/// <!-- description -->
/// @brief Release the vps_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
///
constexpr void
release(gs_t &gs, tls_t &tls, syscall::bf_syscall_t &sys, intrinsic_t &intrinsic) noexcept
{
bsl::discard(gs);
bsl::discard(tls);
bsl::discard(sys);
bsl::discard(intrinsic);
/// NOTE:
/// - Release functions are usually only needed in the event of
/// an error, or during unit testing.
///
m_assigned_ppid = syscall::BF_INVALID_ID;
m_assigned_vpid = syscall::BF_INVALID_ID;
m_id = bsl::safe_uint16::failure();
}
/// <!-- description -->
/// @brief Allocates a vps_t 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 vps_t to
/// @param ppid the ID of the PP to assign the vps_t to
/// @return Returns bsl::errc_success on success, bsl::errc_failure
/// and friends otherwise
///
[[nodiscard]] constexpr auto
allocate(
gs_t &gs,
tls_t &tls,
syscall::bf_syscall_t &sys,
intrinsic_t &intrinsic,
bsl::safe_uint16 const &vpid,
bsl::safe_uint16 const &ppid) noexcept -> bsl::errc_type
{
bsl::discard(gs);
bsl::discard(tls);
bsl::discard(intrinsic);
bsl::errc_type ret{};
/// NOTE:
/// - The following is a pedantic check to make sure we have
/// been initialized by the vp_pool_t. In larger extensions,
/// this is useful as it helps to weed out hard to find bugs.
/// In a small example like this, it is completely overkill,
/// but is added for completeness.
///
if (bsl::unlikely_assert(!m_id)) {
bsl::error() << "vps_t not initialized\n" << bsl::here();
return bsl::errc_precondition;
}
/// NOTE:
/// - The following is a pedantic check to make sure we have
/// not already allocated this vps_t. In larger extensions,
/// this is useful as it helps to weed out hard to find bugs.
/// In a small example like this, it is completely overkill,
/// but is added for completeness.
///
if (bsl::unlikely_assert(syscall::BF_INVALID_ID != m_assigned_ppid)) {
bsl::error() << "vp " // --
<< bsl::hex(m_id) // --
<< " is already allocated and cannot be created" // --
<< bsl::endl // --
<< bsl::here(); // --
return bsl::errc_precondition;
}
/// NOTE:
/// - The following are some pedantic checks on the input. In
/// larger extensions, this is useful as it helps to weed
/// out hard to find bugs. In a small example like this, it
/// is completely overkill, but is added for completeness.
/// - We check to to make sure that we were given a valid ID,
/// meaning the safe integral is not storing an error, and we
/// also check to make sure the ID itself is not the reserved
/// syscall::BF_INVALID_ID as that is also not allowed.
///
if (bsl::unlikely_assert(!vpid)) {
bsl::error() << "invalid vpid\n" << bsl::here();
return bsl::errc_invalid_argument;
}
if (bsl::unlikely_assert(syscall::BF_INVALID_ID == vpid)) {
bsl::error() << "vm " // --
<< bsl::hex(vpid) // --
<< " is invalid and a vp cannot be assigned to it" // --
<< bsl::endl // --
<< bsl::here(); // --
return bsl::errc_invalid_argument;
}
if (bsl::unlikely_assert(!ppid)) {
bsl::error() << "invalid ppid\n" << bsl::here();
return bsl::errc_invalid_argument;
}
if (bsl::unlikely_assert(syscall::BF_INVALID_ID == ppid)) {
bsl::error() << "pp " // --
<< bsl::hex(ppid) // --
<< " is invalid and a vp cannot be assigned to it" // --
<< bsl::endl // --
<< bsl::here(); // --
return bsl::errc_invalid_argument;
}
/// NOTE:
/// - Initialize the VPS as a root VPS. When the microkernel was
/// started, the loader saved the state of the root VP. This
/// syscall tells the microkernel to load the VPS with this saved
/// state so that when we run the VP, it will contain the state
/// just before the microkernel was started.
/// - In other words, this is what allows the microkernel to return
/// back to the loader once the hypervisor is running.
/// - You only want to run this on root VPs. VPs that are being
/// created for guest VPs should not use this, as it would give
/// the guest VP the state associated with the root VP. Also
/// note that once the root VP has executed, this ABI is no
/// longer useful as the state stored in the microkernel would be
/// out-dated. For root VPs, that ID of the PP should always be
/// the same as the IP of the VP, so we added this check for
/// completeness just in case cut/paste is used here.
///
if (ppid == m_id) {
ret = sys.bf_vps_op_init_as_root(m_id);
if (bsl::unlikely_assert(!ret)) {
bsl::print<bsl::V>() << bsl::here();
return ret;
}
bsl::touch();
}
else {
/// NOTE:
/// - The call to bsl::touch is only needed if you plan to
/// enforce MC/DC unit testing. Feel free to remove this if
/// you have no plans to support MC/DC unit testing.
///
bsl::touch();
}
/// NOTE:
/// - Set up VPID
///
constexpr auto vmcs_vpid_idx{0x0000_u64};
constexpr auto vmcs_vpid_val{0x1_u16};
ret = sys.bf_vps_op_write16(m_id, vmcs_vpid_idx, vmcs_vpid_val);
if (bsl::unlikely_assert(!ret)) {
bsl::print<bsl::V>() << bsl::here();
return ret;
}
/// NOTE:
/// - Set up the VMCS link pointer
///
constexpr auto vmcs_link_ptr_idx{0x2800_u64};
constexpr auto vmcs_link_ptr_val{0xFFFFFFFFFFFFFFFF_u64};
ret = sys.bf_vps_op_write64(m_id, vmcs_link_ptr_idx, vmcs_link_ptr_val);
if (bsl::unlikely_assert(!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 auto vmcs_pinbased_ctls_idx{0x4000_u64};
constexpr auto vmcs_procbased_ctls_idx{0x4002_u64};
constexpr auto vmcs_exit_ctls_idx{0x400C_u64};
constexpr auto vmcs_entry_ctls_idx{0x4012_u64};
constexpr auto vmcs_procbased_ctls2_idx{0x401E_u64};
constexpr auto ia32_vmx_true_pinbased_ctls{0x48D_u32};
constexpr auto ia32_vmx_true_procbased_ctls{0x48E_u32};
constexpr auto ia32_vmx_true_exit_ctls{0x48F_u32};
constexpr auto ia32_vmx_true_entry_ctls{0x490_u32};
constexpr auto ia32_vmx_true_procbased_ctls2{0x48B_u32};
bsl::safe_uintmax ctls{};
/// NOTE:
/// - Configure the pin based controls
///
ctls = sys.bf_intrinsic_op_rdmsr(ia32_vmx_true_pinbased_ctls);
if (bsl::unlikely_assert(!ctls)) {
bsl::print<bsl::V>() << bsl::here();
return bsl::errc_failure;
}
ret = sys.bf_vps_op_write32(m_id, vmcs_pinbased_ctls_idx, ctls_mask(ctls));
if (bsl::unlikely_assert(!ret)) {
bsl::print<bsl::V>() << bsl::here();
return ret;
}
/// NOTE:
/// - Configure the proc based controls
///
constexpr auto enable_msr_bitmaps{0x10000000_u64};
constexpr auto enable_procbased_ctls2{0x80000000_u64};
ctls = sys.bf_intrinsic_op_rdmsr(ia32_vmx_true_procbased_ctls);
if (bsl::unlikely_assert(!ctls)) {
bsl::print<bsl::V>() << bsl::here();
return bsl::errc_failure;
}
ctls |= enable_msr_bitmaps;
ctls |= enable_procbased_ctls2;
ret = sys.bf_vps_op_write32(m_id, vmcs_procbased_ctls_idx, ctls_mask(ctls));
if (bsl::unlikely_assert(!ret)) {
bsl::print<bsl::V>() << bsl::here();
return ret;
}
/// NOTE:
/// - Configure the exit controls
///
ctls = sys.bf_intrinsic_op_rdmsr(ia32_vmx_true_exit_ctls);
if (bsl::unlikely_assert(!ctls)) {
bsl::print<bsl::V>() << bsl::here();
return bsl::errc_failure;
}
ret = sys.bf_vps_op_write32(m_id, vmcs_exit_ctls_idx, ctls_mask(ctls));
if (bsl::unlikely_assert(!ret)) {
bsl::print<bsl::V>() << bsl::here();
return ret;
}
/// NOTE:
/// - Configure the entry controls
///
ctls = sys.bf_intrinsic_op_rdmsr(ia32_vmx_true_entry_ctls);
if (bsl::unlikely_assert(!ctls)) {
bsl::print<bsl::V>() << bsl::here();
return bsl::errc_failure;
}
ret = sys.bf_vps_op_write32(m_id, vmcs_entry_ctls_idx, ctls_mask(ctls));
if (bsl::unlikely_assert(!ret)) {
bsl::print<bsl::V>() << bsl::here();
return ret;
}
/// NOTE:
/// - Configure the secondary proc controls.
///
constexpr auto enable_vpid{0x00000020_u64};
constexpr auto enable_rdtscp{0x00000008_u64};
constexpr auto enable_invpcid{0x00001000_u64};
constexpr auto enable_xsave{0x00100000_u64};
constexpr auto enable_uwait{0x04000000_u64};
ctls = sys.bf_intrinsic_op_rdmsr(ia32_vmx_true_procbased_ctls2);
if (bsl::unlikely_assert(!ctls)) {
bsl::print<bsl::V>() << bsl::here();
return bsl::errc_failure;
}
ctls |= enable_vpid;
ctls |= enable_rdtscp;
ctls |= enable_invpcid;
ctls |= enable_xsave;
ctls |= enable_uwait;
ret = sys.bf_vps_op_write32(m_id, vmcs_procbased_ctls2_idx, ctls_mask(ctls));
if (bsl::unlikely_assert(!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 auto vmcs_msr_bitmaps{0x2004_u64};
ret = sys.bf_vps_op_write64(m_id, vmcs_msr_bitmaps, gs.msr_bitmap_phys);
if (bsl::unlikely_assert(!ret)) {
bsl::print<bsl::V>() << bsl::here();
return ret;
}
/// NOTE:
/// - Finally, store the IDs of the VP and PP that this vps_t is
/// assigned to and reprot success.
///
m_assigned_vpid = vpid;
m_assigned_ppid = ppid;
return bsl::errc_success;
}
};
}
#endif

View file

@ -0,0 +1,52 @@
/**
* @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.
*/
.code64
.intel_syntax noprefix
.globl intrinsic_cpuid_impl
.type intrinsic_cpuid_impl, @function
intrinsic_cpuid_impl:
push rbx
mov r10, rdx
mov r11, rcx
mov eax, [rsi]
mov ebx, [r10]
mov ecx, [r11]
mov edx, [r8]
cpuid
mov [rsi], eax
mov [r10], ebx
mov [r11], ecx
mov [r8], edx
pop rbx
ret
int 3
.size intrinsic_cpuid_impl, .-intrinsic_cpuid_impl

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.
#ifndef INTRINSIC_IMPL_PROTOTYPES_HPP
#define INTRINSIC_IMPL_PROTOTYPES_HPP
#include <gs_t.hpp>
#include <bsl/cstdint.hpp>
namespace example
{
/// <!-- 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" void intrinsic_cpuid_impl(
gs_t *const gs,
bsl::uint64 *const rax,
bsl::uint64 *const rbx,
bsl::uint64 *const rcx,
bsl::uint64 *const rdx) noexcept;
}
#endif

View file

@ -0,0 +1,56 @@
#
# 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.
Checks:
'
-*,
bsl-*,
-bsl-template-generic-param,
-bsl-literals-user-defined,
-bsl-lambda-implicit-capture,
bugprone-*,
-bugprone-branch-clone,
cert-*,
-cert-dcl21-cpp,
-cert-oop54-cpp,
clang-analyzer-*,
-clang-analyzer-core.CallAndMessage,
cppcoreguidelines-*,
-cppcoreguidelines-avoid-non-const-global-variables,
hicpp-*,
-hicpp-function-size,
misc-*,
-misc-misplaced-const,
-misc-non-private-member-variables-in-classes,
modernize-*,
-modernize-use-default-member-init,
performance-*,
readability-*,
-readability-redundant-member-init,
-readability-avoid-const-params-in-decls,
-readability-static-accessed-through-instance,
-readability-function-size
'
WarningsAsErrors: '*'
HeaderFilterRegex: '.*'
AnalyzeTemporaryDtors: false
FormatStyle: none
UseColor: true

View file

@ -0,0 +1,227 @@
#
# 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.
# NOTE:
# - We include the bf_add_test function from the BSL as it greatly simplifies
# creating unit tests for us. If you do not want to use this, feel free to
# handle unit tests however you wish (or not at all)
#
include(${bsl_SOURCE_DIR}/cmake/function/bf_add_test.cmake)
# ------------------------------------------------------------------------------
# Includes
# ------------------------------------------------------------------------------
# NOTE:
# - It is really, really important that we do not add any include directories
# from the source folder. Anything that is needed by code from the source
# folder must be mocked. The include folder itself is fine as this should
# only ever include type definitions. Things that should not be in the
# include folder are:
# - Any code that can excute. Anything that can execute must be in the src
# folder and have a set of tests associated with it.
# - C function prototypes. These should also be in the source folder, and
# any code that needs them should get to this code through a C++ class
# wrapper. See the intrinsic_t as an example. C function prototypes are not
# constexpr, so they cannot be called from the rest of the C++ code.
# - Obiviously, any actual source files like .cpp and .S. These should all
# be in the source folder as well. Unit test the assembly files where it
# is possible (like a memcpy/memset). For extensions, most assembly files
# likely can be unit tested as they can only execute userspace specific
# instructions. The microkernel is a different story as it executes system
# instructions which likely need an emulator to properly unit test.
# - In the default example, we include the mock folder for bf_syscall_t and
# it's related headers. This is a generic mock of bf_syscall_t which can be
# used for most unit testing, but if you need soemthing more specific, you
# are free to remove the includes for this and provide your own. The sycall
# library stores bf_syscall_t in the source folder for this reason as the
# include folder contains type defintions and constants that can be used in
# any unit test as they do not change, while the src folder specific logic
# should only be included when you plan to use the actual implementation of
# bf_syscall_t and not a mock.
#
list(APPEND INCLUDES
${CMAKE_CURRENT_LIST_DIR}/../include
${CMAKE_CURRENT_LIST_DIR}/../mocks
)
list(APPEND SYSTEM_INCLUDES
${CMAKE_SOURCE_DIR}/syscall/include/cpp
${CMAKE_SOURCE_DIR}/syscall/mocks/cpp
${CMAKE_SOURCE_DIR}/loader/include/interface/cpp
)
list(APPEND COMMON_INCLUDES
${INCLUDES}
)
list(APPEND COMMON_SYSTEM_INCLUDES
${SYSTEM_INCLUDES}
)
list(APPEND X64_INCLUDES
${CMAKE_CURRENT_LIST_DIR}/../include/x64
${CMAKE_CURRENT_LIST_DIR}/../mocks/x64
${INCLUDES}
)
list(APPEND X64_SYSTEM_INCLUDES
${CMAKE_SOURCE_DIR}/syscall/include/cpp/x64
${CMAKE_SOURCE_DIR}/syscall/mocks/cpp/x64
${CMAKE_SOURCE_DIR}/loader/include/interface/cpp/x64
${SYSTEM_INCLUDES}
)
list(APPEND AMD_INCLUDES
${CMAKE_CURRENT_LIST_DIR}/../include/x64/amd
${CMAKE_CURRENT_LIST_DIR}/../mocks/x64/amd
${X64_INCLUDES}
)
list(APPEND AMD_SYSTEM_INCLUDES
${CMAKE_SOURCE_DIR}/syscall/include/cpp/x64/amd
${CMAKE_SOURCE_DIR}/syscall/mocks/cpp/x64/amd
${CMAKE_SOURCE_DIR}/loader/include/interface/cpp/x64/amd
${X64_SYSTEM_INCLUDES}
)
list(APPEND INTEL_INCLUDES
${CMAKE_CURRENT_LIST_DIR}/../include/x64/intel
${CMAKE_CURRENT_LIST_DIR}/../mocks/x64/intel
${X64_INCLUDES}
)
list(APPEND INTEL_SYSTEM_INCLUDES
${CMAKE_SOURCE_DIR}/syscall/include/cpp/x64/intel
${CMAKE_SOURCE_DIR}/syscall/mocks/cpp/x64/intel
${CMAKE_SOURCE_DIR}/loader/include/interface/cpp/x64/intel
${X64_SYSTEM_INCLUDES}
)
list(APPEND AARCH64_INCLUDES
${CMAKE_CURRENT_LIST_DIR}/../include/arm/aarch64
${CMAKE_CURRENT_LIST_DIR}/../mocks/arm/aarch64
${INCLUDES}
)
list(APPEND AARCH64_SYSTEM_INCLUDES
${CMAKE_SOURCE_DIR}/syscall/include/cpp/arm/aarch64
${CMAKE_SOURCE_DIR}/syscall/mocks/cpp/arm/aarch64
${CMAKE_SOURCE_DIR}/loader/include/interface/cpp/arm/aarch64
${SYSTEM_INCLUDES}
)
# ------------------------------------------------------------------------------
# Definitions
# ------------------------------------------------------------------------------
# NOTE:
# - Any defintions that the extension uses should be defined here. You can
# also define them on a per unit test basis if needed. Bareflank makes the
# definitions available to the extension when it is compiling the actual
# code, but it does not make them available to any tests, so they must be
# manually defined here, or where you define the unit test itself.
# - DO NOT define these in the unit test code. Either define them here, or
# to define them on a per unit test bases, add them to a test specific
# CMake variable that is passed to bf_add_test. If a unit test needs these
# defined different for each test, make a different unit test for each one.
#
# - See the individual CMakeLists.txt for each test for more information.
#
list(APPEND DEFINES
HYPERVISOR_PAGE_SIZE=0x1000_umax
HYPERVISOR_MAX_VPS=2_umax
HYPERVISOR_MAX_VPSS=2_umax
HYPERVISOR_EXT_DIRECT_MAP_ADDR=0x0000600000000000_umax
)
list(APPEND COMMON_DEFINES
${DEFINES}
)
list(APPEND X64_DEFINES
${DEFINES}
)
list(APPEND AMD_DEFINES
${X64_DEFINES}
)
list(APPEND INTEL_DEFINES
${X64_DEFINES}
)
list(APPEND AARCH64_DEFINES
${DEFINES}
)
# ------------------------------------------------------------------------------
# Tests
# ------------------------------------------------------------------------------
# NOTE:
# - The following is just a template that you can use as a starting point for
# each test. Remove it from your extension as needed.
#
add_subdirectory(template)
# NOTE:
# - Add the directories for each unit test here. Note that you should add all
# archiectures here. Unit tests mock all dependencies, including the arch
# specific dependencies, so all of the arch specific unit tests can compile
# and run on any other arch. This ensures, for example, that your ARM logic
# is unit tested during CI which might be running on an Intel based system.
#
add_subdirectory(mocks/bootstrap_t)
add_subdirectory(mocks/fail_t)
add_subdirectory(mocks/intrinsic_t)
add_subdirectory(mocks/vmexit_t)
add_subdirectory(mocks/vp_pool_t)
add_subdirectory(mocks/vp_t)
add_subdirectory(mocks/vps_pool_t)
add_subdirectory(mocks/vps_t)
add_subdirectory(mocks/x64/intrinsic_cpuid_impl)
add_subdirectory(mocks/x64/amd/intrinsic_t)
add_subdirectory(mocks/x64/intel/intrinsic_t)
add_subdirectory(src/bootstrap_t)
add_subdirectory(src/fail_t)
add_subdirectory(src/main)
add_subdirectory(src/vp_pool_t)
add_subdirectory(src/vp_t)
add_subdirectory(src/vps_pool_t)
add_subdirectory(src/x64/amd/intrinsic_t)
add_subdirectory(src/x64/amd/vmexit_t)
add_subdirectory(src/x64/amd/vps_t)
add_subdirectory(src/x64/intel/intrinsic_t)
add_subdirectory(src/x64/intel/vmexit_t)
add_subdirectory(src/x64/intel/vps_t)
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
if(HYPERVISOR_TARGET_ARCH STREQUAL "AuthenticAMD" OR HYPERVISOR_TARGET_ARCH STREQUAL "GenuineIntel")
add_subdirectory(src/x64/intrinsic_cpuid_impl)
endif()
endif()

View file

@ -0,0 +1,70 @@
#
# 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.
# NOTE:
# - Add the tests themselves here. There are several variables that you can
# add to the bf_add_test macro including:
# - SOURCES = any source files that should be included in the test
# - INCLUDES = any include directories that should be included in the test
# - SYSTEM_INCLUDES = any system include directories that should be included
# in the test. System includes are not included in a Clang Tidy check.
# - LIBRARIES = any libraries that should be included in the test
# - DEFINES = any definitions that should be included in the test
#
# - The high level CMake file for the tests already configures a number of
# these automatically for you. Each test needs to make sure it includes the
# proper variable (for example, code that does not have arch specific) stuff
# in it should use the COMMON_ versions, while code that has arch specific
# stuff in it should use the arch specific versions of these variables.
#
# - You can also add do these variables however you want for each test. For
# example, if you want to add the definition THE_ANSWER=42 to the behavior
# unit test, create a BEHAVIOR_DEFINES, append THE_ANSWER=42 and append
# ${COMMON_DEFINES}, and use BEHAVIOR_DEFINES instead of COMMON_DEFINES in
# the call to bf_add_test. This can be done to any of these variables to
# custom tailor a specific test as needed. If a test needs different versions
# of any of these, break the test into different files and create the custom
# tailor versions of each test as needed.
#
# - By default, we provide a "requirements" test and a "behavior" test. The
# "requirements" test verifies things like the ability to define globally
# using constinit, constness and noexcept. None of the code in this test
# actually runs and instead it is there to ensure the code signatures make
# sense. The "behavior" test is where the code is actually executed to make
# sure it executes as expected. This code will run the tests both at compile
# time and at runtime. If a specific test cannot be run at compile time
# (which hopefully is minimal if the code is structured properly), you can
# use the bsl::ut_given_at_runtime instead of bsl::ut_given, which will
# exclude the test from compile time checks.
#
# - Each test only includes the one thing that is trying to test. For example,
# suppose we are testing the bootstrap_t logic. This file includes a number
# of dependencies. We do not include the path to where these dependencies
# are located in the include path for the unit test. Instead, we include
# a folder than contains our mocks. All of the dependencies must be mocked.
# When the bootstrap_t code is compiled, it will not realize that it is
# using the mocked versions of it's dependecies, similar to how a lot of this
# code is unaware of which arch specific code it is using and the build
# system figures out which version to use, unit tests do the same thing.
#
bf_add_test(requirements INCLUDES ${COMMON_INCLUDES} SYSTEM_INCLUDES ${COMMON_SYSTEM_INCLUDES} DEFINES ${COMMON_DEFINES})
bf_add_test(behavior INCLUDES ${COMMON_INCLUDES} SYSTEM_INCLUDES ${COMMON_SYSTEM_INCLUDES} DEFINES ${COMMON_DEFINES})

View file

@ -0,0 +1,146 @@
/// @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 "../../../mocks/bootstrap_t.hpp"
#include <bsl/ut.hpp>
namespace example
{
/// <!-- description -->
/// @brief Used to execute the actual checks. We put the checks in this
/// function so that we can validate the tests both at compile-time
/// and at run-time. If a bsl::ut_check fails, the tests will either
/// fail fast at run-time, or will produce a compile-time error.
///
/// <!-- inputs/outputs -->
/// @return Always returns bsl::exit_success.
///
[[nodiscard]] constexpr auto
tests() noexcept -> bsl::exit_code
{
bsl::ut_scenario{"initialize fails"} = []() noexcept {
bsl::ut_given{} = []() noexcept {
bootstrap_t bootstrap{};
gs_t gs{};
tls_t tls{};
syscall::bf_syscall_t sys{};
intrinsic_t intrinsic{};
vp_pool_t vp_pool{};
vps_pool_t vps_pool{};
bsl::ut_when{} = [&]() noexcept {
bootstrap.set_initialize(bsl::errc_failure);
bsl::ut_then{} = [&]() noexcept {
bsl::ut_check(
!bootstrap.initialize(gs, tls, sys, intrinsic, vp_pool, vps_pool));
};
};
};
};
bsl::ut_scenario{"initialize success"} = []() noexcept {
bsl::ut_given{} = []() noexcept {
bootstrap_t bootstrap{};
gs_t gs{};
tls_t tls{};
syscall::bf_syscall_t sys{};
intrinsic_t intrinsic{};
vp_pool_t vp_pool{};
vps_pool_t vps_pool{};
bsl::ut_then{} = [&]() noexcept {
bsl::ut_check(bootstrap.initialize(gs, tls, sys, intrinsic, vp_pool, vps_pool));
};
};
};
bsl::ut_scenario{"release executes"} = []() noexcept {
bsl::ut_given{} = []() noexcept {
bootstrap_t bootstrap{};
gs_t gs{};
tls_t tls{};
syscall::bf_syscall_t sys{};
intrinsic_t intrinsic{};
vp_pool_t vp_pool{};
vps_pool_t vps_pool{};
bsl::ut_then{} = [&]() noexcept {
bootstrap.release(gs, tls, sys, intrinsic, vp_pool, vps_pool);
};
};
};
bsl::ut_scenario{"dispatch fails"} = []() noexcept {
bsl::ut_given{} = []() noexcept {
bootstrap_t bootstrap{};
gs_t gs{};
tls_t tls{};
syscall::bf_syscall_t sys{};
intrinsic_t intrinsic{};
vp_pool_t vp_pool{};
vps_pool_t vps_pool{};
bsl::ut_when{} = [&]() noexcept {
bootstrap.set_dispatch(bsl::errc_failure);
bsl::ut_then{} = [&]() noexcept {
bsl::ut_check(
!bootstrap.dispatch(gs, tls, sys, intrinsic, vp_pool, vps_pool, {}));
};
};
};
};
bsl::ut_scenario{"dispatch success"} = []() noexcept {
bsl::ut_given{} = []() noexcept {
bootstrap_t bootstrap{};
gs_t gs{};
tls_t tls{};
syscall::bf_syscall_t sys{};
intrinsic_t intrinsic{};
vp_pool_t vp_pool{};
vps_pool_t vps_pool{};
bsl::ut_then{} = [&]() noexcept {
bsl::ut_check(
bootstrap.dispatch(gs, tls, sys, intrinsic, vp_pool, vps_pool, {}));
};
};
};
return bsl::ut_success();
}
}
/// <!-- description -->
/// @brief Main function for this unit test. If a call to bsl::ut_check() fails
/// the application will fast fail. If all calls to bsl::ut_check() pass, this
/// function will successfully return with bsl::exit_success.
///
/// <!-- inputs/outputs -->
/// @return Always returns bsl::exit_success.
///
[[nodiscard]] auto
main() noexcept -> bsl::exit_code
{
bsl::enable_color();
static_assert(example::tests() == bsl::ut_success());
return example::tests();
}

View file

@ -0,0 +1,119 @@
/// @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 "../../../mocks/bootstrap_t.hpp"
#include <bsl/discard.hpp>
#include <bsl/ut.hpp>
namespace
{
constinit example::bootstrap_t const g_verify_constinit{};
// NOLINTNEXTLINE(bsl-user-defined-type-names-match-header-name)
class fixture_t final
{
example::bootstrap_t m_boostrap{};
public:
[[nodiscard]] static constexpr auto
test_member_const() noexcept -> bool
{
/// NOTE:
/// - bootstrap_t does not contain const member functions
///
return true;
}
[[nodiscard]] constexpr auto
test_member_nonconst() noexcept -> bool
{
example::gs_t gs{};
example::tls_t tls{};
syscall::bf_syscall_t sys{};
example::intrinsic_t intrinsic{};
example::vp_pool_t vp_pool{};
example::vps_pool_t vps_pool{};
bsl::discard(example::bootstrap_t{});
bsl::discard(m_boostrap.initialize(gs, tls, sys, intrinsic, vp_pool, vps_pool));
m_boostrap.release(gs, tls, sys, intrinsic, vp_pool, vps_pool);
bsl::discard(m_boostrap.dispatch(gs, tls, sys, intrinsic, vp_pool, vps_pool, {}));
return true;
}
};
constexpr fixture_t FIXTURE1{};
}
/// <!-- description -->
/// @brief Main function for this unit test. If a call to bsl::ut_check() fails
/// the application will fast fail. If all calls to bsl::ut_check() pass, this
/// function will successfully return with bsl::exit_success.
///
/// <!-- inputs/outputs -->
/// @return Always returns bsl::exit_success.
///
[[nodiscard]] auto
main() noexcept -> bsl::exit_code
{
bsl::ut_scenario{"verify supports constinit"} = []() noexcept {
bsl::discard(g_verify_constinit);
};
bsl::ut_scenario{"verify noexcept"} = []() noexcept {
bsl::ut_given{} = []() noexcept {
example::bootstrap_t boostrap{};
example::gs_t gs{};
example::tls_t tls{};
syscall::bf_syscall_t sys{};
example::intrinsic_t intrinsic{};
example::vp_pool_t vp_pool{};
example::vps_pool_t vps_pool{};
bsl::ut_then{} = []() noexcept {
static_assert(noexcept(example::bootstrap_t{}));
static_assert(
noexcept(boostrap.initialize(gs, tls, sys, intrinsic, vp_pool, vps_pool)));
static_assert(
noexcept(boostrap.release(gs, tls, sys, intrinsic, vp_pool, vps_pool)));
static_assert(
noexcept(boostrap.dispatch(gs, tls, sys, intrinsic, vp_pool, vps_pool, {})));
};
};
};
bsl::ut_scenario{"verify constness"} = []() noexcept {
bsl::ut_given{} = []() noexcept {
fixture_t fixture2{};
bsl::ut_then{} = [&]() noexcept {
static_assert(FIXTURE1.test_member_const());
bsl::ut_check(fixture2.test_member_nonconst());
};
};
};
return bsl::ut_success();
}

View file

@ -0,0 +1,70 @@
#
# 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.
# NOTE:
# - Add the tests themselves here. There are several variables that you can
# add to the bf_add_test macro including:
# - SOURCES = any source files that should be included in the test
# - INCLUDES = any include directories that should be included in the test
# - SYSTEM_INCLUDES = any system include directories that should be included
# in the test. System includes are not included in a Clang Tidy check.
# - LIBRARIES = any libraries that should be included in the test
# - DEFINES = any definitions that should be included in the test
#
# - The high level CMake file for the tests already configures a number of
# these automatically for you. Each test needs to make sure it includes the
# proper variable (for example, code that does not have arch specific) stuff
# in it should use the COMMON_ versions, while code that has arch specific
# stuff in it should use the arch specific versions of these variables.
#
# - You can also add do these variables however you want for each test. For
# example, if you want to add the definition THE_ANSWER=42 to the behavior
# unit test, create a BEHAVIOR_DEFINES, append THE_ANSWER=42 and append
# ${COMMON_DEFINES}, and use BEHAVIOR_DEFINES instead of COMMON_DEFINES in
# the call to bf_add_test. This can be done to any of these variables to
# custom tailor a specific test as needed. If a test needs different versions
# of any of these, break the test into different files and create the custom
# tailor versions of each test as needed.
#
# - By default, we provide a "requirements" test and a "behavior" test. The
# "requirements" test verifies things like the ability to define globally
# using constinit, constness and noexcept. None of the code in this test
# actually runs and instead it is there to ensure the code signatures make
# sense. The "behavior" test is where the code is actually executed to make
# sure it executes as expected. This code will run the tests both at compile
# time and at runtime. If a specific test cannot be run at compile time
# (which hopefully is minimal if the code is structured properly), you can
# use the bsl::ut_given_at_runtime instead of bsl::ut_given, which will
# exclude the test from compile time checks.
#
# - Each test only includes the one thing that is trying to test. For example,
# suppose we are testing the bootstrap_t logic. This file includes a number
# of dependencies. We do not include the path to where these dependencies
# are located in the include path for the unit test. Instead, we include
# a folder than contains our mocks. All of the dependencies must be mocked.
# When the bootstrap_t code is compiled, it will not realize that it is
# using the mocked versions of it's dependecies, similar to how a lot of this
# code is unaware of which arch specific code it is using and the build
# system figures out which version to use, unit tests do the same thing.
#
bf_add_test(requirements INCLUDES ${COMMON_INCLUDES} SYSTEM_INCLUDES ${COMMON_SYSTEM_INCLUDES} DEFINES ${COMMON_DEFINES})
bf_add_test(behavior INCLUDES ${COMMON_INCLUDES} SYSTEM_INCLUDES ${COMMON_SYSTEM_INCLUDES} DEFINES ${COMMON_DEFINES})

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