├── Docs ├── TdNative.png ├── TdCornelius.png ├── SeamcallNative.png └── SeamcallCornelius.png ├── SUPPORT.md ├── CODE_OF_CONDUCT.md ├── Test ├── Test.vcxproj.filters ├── Test.vcxproj └── main.c ├── Lib ├── Lib.vcxproj.filters ├── util.c ├── elf.c ├── snapshot.c ├── paging.c ├── Lib.vcxproj ├── Cornelius.h ├── sanitizers.c ├── common.h ├── IntelDefs │ └── pseamldr-defs.h ├── invariants.c ├── x86-defs.h └── vm.c ├── LICENSE ├── .github └── workflows │ └── msbuild.yml ├── TdxPatches ├── tdx-module-1.5.01-pc │ ├── tdx-module-bugs.patch │ └── tdx-module-support.patch ├── tdx-module-1.5.05 │ └── tdx-module-support.patch ├── tdx-module-1.5.16 │ └── tdx-module-support.patch └── p-seamldr-1.5.01.02 │ └── p-seamldr-support.patch ├── Cornelius.sln ├── SECURITY.md ├── README.md └── .gitignore /Docs/TdNative.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Cornelius/HEAD/Docs/TdNative.png -------------------------------------------------------------------------------- /Docs/TdCornelius.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Cornelius/HEAD/Docs/TdCornelius.png -------------------------------------------------------------------------------- /Docs/SeamcallNative.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Cornelius/HEAD/Docs/SeamcallNative.png -------------------------------------------------------------------------------- /Docs/SeamcallCornelius.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Cornelius/HEAD/Docs/SeamcallCornelius.png -------------------------------------------------------------------------------- /SUPPORT.md: -------------------------------------------------------------------------------- 1 | # Support 2 | 3 | ## How to file issues and get help 4 | 5 | This project uses GitHub Issues to track bugs and feature requests. Please search the existing 6 | issues before filing new issues to avoid duplicates. For new issues, file your bug or 7 | feature request as a new Issue. 8 | 9 | ## Microsoft Support Policy 10 | 11 | Support for this project is limited to the resources listed above. 12 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Microsoft Open Source Code of Conduct 2 | 3 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 4 | 5 | Resources: 6 | 7 | - [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/) 8 | - [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) 9 | - Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns 10 | -------------------------------------------------------------------------------- /Test/Test.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | -------------------------------------------------------------------------------- /Lib/Lib.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | IntelDefs 19 | 20 | 21 | IntelDefs 22 | 23 | 24 | 25 | 26 | 27 | 28 | {4c14d529-5fd6-44e9-aeba-e0342207bd56} 29 | 30 | 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Microsoft Corporation. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE 22 | -------------------------------------------------------------------------------- /.github/workflows/msbuild.yml: -------------------------------------------------------------------------------- 1 | # This workflow uses actions that are not certified by GitHub. 2 | # They are provided by a third-party and are governed by 3 | # separate terms of service, privacy policy, and support 4 | # documentation. 5 | 6 | name: MSBuild 7 | 8 | on: 9 | pull_request: 10 | branches: [ "main" ] 11 | 12 | env: 13 | # Path to the solution file relative to the root of the project. 14 | SOLUTION_FILE_PATH: ./Cornelius.sln 15 | 16 | # Configuration type to build. 17 | # You can convert this to a build matrix if you need coverage of multiple configuration types. 18 | # https://docs.github.com/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix 19 | BUILD_CONFIGURATION: Release 20 | 21 | permissions: 22 | contents: read 23 | 24 | jobs: 25 | build: 26 | runs-on: windows-latest 27 | 28 | steps: 29 | - uses: actions/checkout@v4 30 | 31 | - name: Add MSBuild to PATH 32 | uses: microsoft/setup-msbuild@v1.0.2 33 | 34 | - name: Restore NuGet packages 35 | working-directory: ${{env.GITHUB_WORKSPACE}} 36 | run: nuget restore ${{env.SOLUTION_FILE_PATH}} 37 | 38 | - name: Build 39 | working-directory: ${{env.GITHUB_WORKSPACE}} 40 | # Add additional options to the MSBuild command line here (like platform or verbosity level). 41 | # See https://docs.microsoft.com/visualstudio/msbuild/msbuild-command-line-reference 42 | run: msbuild /m /p:Configuration=${{env.BUILD_CONFIGURATION}} ${{env.SOLUTION_FILE_PATH}} 43 | -------------------------------------------------------------------------------- /Lib/util.c: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | #include 5 | #include 6 | #include 7 | #include "common.h" 8 | 9 | VOID 10 | LogVcpuTdxDebug(CORNELIUS_VM* Vm, UINT32 VcpuNum, char* msg, ...) 11 | { 12 | va_list argp; 13 | 14 | UNREFERENCED_PARAMETER(Vm); 15 | 16 | SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN); 17 | 18 | printf("[+][VCPU%u][DBG] ", VcpuNum); 19 | 20 | va_start(argp, msg); 21 | vprintf(msg, argp); 22 | va_end(argp); 23 | 24 | SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 15); 25 | } 26 | 27 | VOID 28 | LogVcpuOk(CORNELIUS_VM *Vm, UINT32 VcpuNum, char *msg, ...) 29 | { 30 | va_list argp; 31 | 32 | if (GetVcpuLogLevel(Vm, VcpuNum) == 0) { 33 | return; 34 | } 35 | 36 | if (IsVcpuSeamldr(Vm, VcpuNum)) { 37 | SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 14); 38 | } else { 39 | SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 11); 40 | } 41 | 42 | printf("[+][VCPU%u] ", VcpuNum); 43 | 44 | va_start(argp, msg); 45 | vprintf(msg, argp); 46 | va_end(argp); 47 | 48 | SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 15); 49 | } 50 | 51 | VOID 52 | LogVcpuErr(CORNELIUS_VM *Vm, UINT32 VcpuNum, char *msg, ...) 53 | { 54 | va_list argp; 55 | 56 | UNREFERENCED_PARAMETER(Vm); 57 | 58 | SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 12); 59 | 60 | printf("[!][VCPU%u] ", VcpuNum); 61 | 62 | va_start(argp, msg); 63 | vprintf(msg, argp); 64 | va_end(argp); 65 | 66 | SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 15); 67 | } -------------------------------------------------------------------------------- /TdxPatches/tdx-module-1.5.01-pc/tdx-module-bugs.patch: -------------------------------------------------------------------------------- 1 | diff --git a/tdx-module-1.5.01-pc/src/td_dispatcher/tdx_td_dispatcher.c b/tdx-module-1.5.01-pc/src/td_dispatcher/tdx_td_dispatcher.c 2 | index f9c5d48..9e55f89 100644 3 | --- a/tdx-module-1.5.01-pc/src/td_dispatcher/tdx_td_dispatcher.c 4 | +++ b/tdx-module-1.5.01-pc/src/td_dispatcher/tdx_td_dispatcher.c 5 | @@ -544,6 +544,7 @@ stepping_filter_e tdx_td_l1_l2_dispatcher_common_prologue(tdx_module_local_t* lo 6 | } 7 | else 8 | { 9 | +/* THIS IS BOGUS 10 | // BHB draining sequence 11 | // There are 6 taken branches in each iteration (one CALL, four JMPs, and one JNZ), 12 | // so for GLC (194 branch stews in BHB), NUM_ITERS = round-up(194 / 6) = 32. 13 | @@ -567,6 +568,7 @@ stepping_filter_e tdx_td_l1_l2_dispatcher_common_prologue(tdx_module_local_t* lo 14 | "add %1, %%rsp\n" 15 | "lfence\n" 16 | : : "a"(num_iters), "b"(num_iters_multi_8) : "memory", "rcx"); 17 | +*/ 18 | } 19 | 20 | // Save current time to verify on next TD entry and for TDEXIT filter checks 21 | diff --git a/tdx-module-1.5.01-pc/src/td_transitions/td_exit.c b/tdx-module-1.5.01-pc/src/td_transitions/td_exit.c 22 | index 6ed91a9..74c9c69 100644 23 | --- a/tdx-module-1.5.01-pc/src/td_transitions/td_exit.c 24 | +++ b/tdx-module-1.5.01-pc/src/td_transitions/td_exit.c 25 | @@ -180,7 +180,7 @@ static void load_vmm_state_before_td_exit(tdx_module_local_t* local_data_ptr) 26 | } 27 | else 28 | { 29 | - wrmsr_opt(IA32_TSX_CTRL_MSR_ADDR, local_data_ptr->vmm_non_extended_state.ia32_tsx_ctrl, IA32_TSX_CTRL_DISABLE_VALUE); 30 | + // THIS IS BOGUS: wrmsr_opt(IA32_TSX_CTRL_MSR_ADDR, local_data_ptr->vmm_non_extended_state.ia32_tsx_ctrl, IA32_TSX_CTRL_DISABLE_VALUE); 31 | } 32 | 33 | /* 34 | -------------------------------------------------------------------------------- /Cornelius.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.6.33801.468 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Test", "Test\Test.vcxproj", "{D23AFD3F-5EAD-468A-B12D-8369A19EBDC1}" 7 | EndProject 8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Lib", "Lib\Lib.vcxproj", "{8862523A-B29F-43EB-8657-7B7A01B9C069}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|x64 = Debug|x64 13 | Debug|x86 = Debug|x86 14 | Release|x64 = Release|x64 15 | Release|x86 = Release|x86 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {D23AFD3F-5EAD-468A-B12D-8369A19EBDC1}.Debug|x64.ActiveCfg = Debug|x64 19 | {D23AFD3F-5EAD-468A-B12D-8369A19EBDC1}.Debug|x64.Build.0 = Debug|x64 20 | {D23AFD3F-5EAD-468A-B12D-8369A19EBDC1}.Debug|x86.ActiveCfg = Debug|Win32 21 | {D23AFD3F-5EAD-468A-B12D-8369A19EBDC1}.Debug|x86.Build.0 = Debug|Win32 22 | {D23AFD3F-5EAD-468A-B12D-8369A19EBDC1}.Release|x64.ActiveCfg = Release|x64 23 | {D23AFD3F-5EAD-468A-B12D-8369A19EBDC1}.Release|x64.Build.0 = Release|x64 24 | {D23AFD3F-5EAD-468A-B12D-8369A19EBDC1}.Release|x86.ActiveCfg = Release|Win32 25 | {D23AFD3F-5EAD-468A-B12D-8369A19EBDC1}.Release|x86.Build.0 = Release|Win32 26 | {8862523A-B29F-43EB-8657-7B7A01B9C069}.Debug|x64.ActiveCfg = Debug|x64 27 | {8862523A-B29F-43EB-8657-7B7A01B9C069}.Debug|x64.Build.0 = Debug|x64 28 | {8862523A-B29F-43EB-8657-7B7A01B9C069}.Debug|x86.ActiveCfg = Debug|Win32 29 | {8862523A-B29F-43EB-8657-7B7A01B9C069}.Debug|x86.Build.0 = Debug|Win32 30 | {8862523A-B29F-43EB-8657-7B7A01B9C069}.Release|x64.ActiveCfg = Release|x64 31 | {8862523A-B29F-43EB-8657-7B7A01B9C069}.Release|x64.Build.0 = Release|x64 32 | {8862523A-B29F-43EB-8657-7B7A01B9C069}.Release|x86.ActiveCfg = Release|Win32 33 | {8862523A-B29F-43EB-8657-7B7A01B9C069}.Release|x86.Build.0 = Release|Win32 34 | EndGlobalSection 35 | GlobalSection(SolutionProperties) = preSolution 36 | HideSolutionNode = FALSE 37 | EndGlobalSection 38 | GlobalSection(ExtensibilityGlobals) = postSolution 39 | SolutionGuid = {40C7D703-5280-45CA-88C1-4E739984A32E} 40 | EndGlobalSection 41 | EndGlobal 42 | -------------------------------------------------------------------------------- /TdxPatches/tdx-module-1.5.01-pc/tdx-module-support.patch: -------------------------------------------------------------------------------- 1 | diff --git a/tdx-module-1.5.01-pc/src/common/memory_handlers/keyhole_manager.c b/tdx-module-1.5.01-pc/src/common/memory_handlers/keyhole_manager.c 2 | index 1817273..cee0509 100644 3 | --- a/tdx-module-1.5.01-pc/src/common/memory_handlers/keyhole_manager.c 4 | +++ b/tdx-module-1.5.01-pc/src/common/memory_handlers/keyhole_manager.c 5 | @@ -48,6 +48,18 @@ _STATIC_INLINE_ uint16_t keyhole_idx_from_la(uint64_t la) 6 | return keyhole_idx; 7 | } 8 | 9 | +static uint64_t cornelius_move_hkid(uint64_t pa) 10 | +{ 11 | + tdx_module_global_t* global_data = get_global_data(); 12 | + uint16_t hkid; 13 | + 14 | + hkid = (uint16_t)((pa & global_data->hkid_mask) >> global_data->hkid_start_bit); 15 | + pa = pa & ~(global_data->hkid_mask); 16 | + pa |= ((uint64_t)hkid << 30ULL); // 1GB 17 | + 18 | + return pa; 19 | +} 20 | + 21 | static void fill_keyhole_pte(uint16_t keyhole_idx, uint64_t pa, bool_t is_writable, bool_t is_wb_memtype) 22 | { 23 | uint64_t lp_keyhole_edit_base = get_sysinfo_table()->keyhole_edit_rgn_base + 24 | @@ -56,6 +68,8 @@ static void fill_keyhole_pte(uint16_t keyhole_idx, uint64_t pa, bool_t is_writab 25 | ia32e_pxe_t* pte_p = (ia32e_pxe_t*)(lp_keyhole_edit_base + (uint64_t)((uint32_t)keyhole_idx * sizeof(ia32e_pxe_t))); 26 | ia32e_pxe_t new_pte; 27 | 28 | + pa = cornelius_move_hkid(pa); 29 | + 30 | new_pte.raw = (uint64_t)0; 31 | 32 | new_pte.fields_4k.addr = (pa >> 12); 33 | diff --git a/tdx-module-1.5.01-pc/src/common/accessors/ia32_accessors.h b/tdx-module-1.5.01-pc/src/common/accessors/ia32_accessors.h 34 | index 1817273..cee0509 100644 35 | --- a/tdx-module-1.5.01-pc/src/common/accessors/ia32_accessors.h 36 | +++ b/tdx-module-1.5.01-pc/src/common/accessors/ia32_accessors.h 37 | @@ -117,12 +117,14 @@ 38 | _STATIC_INLINE_ uint64_t ia32_rdmsr(uint64_t addr) 39 | { 40 | uint32_t low,high; 41 | + addr |= 0x0ABC0000ULL; // See REAL_MSR_NUMBER() in Cornelius 42 | _ASM_VOLATILE_ ("rdmsr" : "=a"(low), "=d"(high) : "c"(addr)); 43 | return (uint64_t)((((uint64_t)(high)) << 32) | (uint64_t)(low)); 44 | } 45 | 46 | _STATIC_INLINE_ void ia32_wrmsr(uint64_t addr, uint64_t value) 47 | { 48 | + addr |= 0x0ABC0000ULL; // See REAL_MSR_NUMBER() in Cornelius 49 | _ASM_VOLATILE_ ("wrmsr" : : "a"((uint32_t)value), "d"((uint32_t)(value >> 32)), "c"(addr)); 50 | } 51 | 52 | @@ -134,6 +136,7 @@ 53 | { 54 | uint64_t fault_indicator; 55 | 56 | + addr |= 0x0ABC0000ULL; // See REAL_MSR_NUMBER() in Cornelius 57 | _ASM_VOLATILE_ ("movq $" STR(FAULT_SAFE_MAGIC_INDICATOR) ", %%rsi \n" 58 | "wrmsr \n" 59 | : "=S"(fault_indicator) 60 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Security 4 | 5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet) and [Xamarin](https://github.com/xamarin). 6 | 7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/security.md/definition), please report it to us as described below. 8 | 9 | ## Reporting Security Issues 10 | 11 | **Please do not report security vulnerabilities through public GitHub issues.** 12 | 13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/security.md/msrc/create-report). 14 | 15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/security.md/msrc/pgp). 16 | 17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc). 18 | 19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: 20 | 21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) 22 | * Full paths of source file(s) related to the manifestation of the issue 23 | * The location of the affected source code (tag/branch/commit or direct URL) 24 | * Any special configuration required to reproduce the issue 25 | * Step-by-step instructions to reproduce the issue 26 | * Proof-of-concept or exploit code (if possible) 27 | * Impact of the issue, including how an attacker might exploit the issue 28 | 29 | This information will help us triage your report more quickly. 30 | 31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/security.md/msrc/bounty) page for more details about our active programs. 32 | 33 | ## Preferred Languages 34 | 35 | We prefer all communications to be in English. 36 | 37 | ## Policy 38 | 39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/security.md/cvd). 40 | 41 | 42 | -------------------------------------------------------------------------------- /TdxPatches/tdx-module-1.5.05/tdx-module-support.patch: -------------------------------------------------------------------------------- 1 | From 2dc271f90ec55e2820bf2c2467c02d572b42baa2 Mon Sep 17 00:00:00 2001 2 | From: John McSandwich <> 3 | Date: Sun, 11 Aug 2024 16:48:55 -0400 4 | Subject: Patch for the TDX module 5 | 6 | --- 7 | src/common/accessors/ia32_accessors.h | 3 +++ 8 | src/common/memory_handlers/keyhole_manager.c | 14 ++++++++++++++ 9 | 2 files changed, 17 insertions(+) 10 | 11 | diff --git a/src/common/accessors/ia32_accessors.h b/src/common/accessors/ia32_accessors.h 12 | index 27d8772..df6854a 100644 13 | --- a/src/common/accessors/ia32_accessors.h 14 | +++ b/src/common/accessors/ia32_accessors.h 15 | @@ -126,12 +126,14 @@ _STATIC_INLINE_ void ia32_ud2( void ) 16 | _STATIC_INLINE_ uint64_t ia32_rdmsr(uint64_t addr) 17 | { 18 | uint32_t low,high; 19 | + addr |= 0x0ABC0000ULL; // See REAL_MSR_NUMBER() in Cornelius 20 | _ASM_VOLATILE_ ("rdmsr" : "=a"(low), "=d"(high) : "c"(addr)); 21 | return (uint64_t)((((uint64_t)(high)) << 32) | (uint64_t)(low)); 22 | } 23 | 24 | _STATIC_INLINE_ void ia32_wrmsr(uint64_t addr, uint64_t value) 25 | { 26 | + addr |= 0x0ABC0000ULL; // See REAL_MSR_NUMBER() in Cornelius 27 | _ASM_VOLATILE_ ("wrmsr" : : "a"((uint32_t)value), "d"((uint32_t)(value >> 32)), "c"(addr)); 28 | } 29 | 30 | @@ -143,6 +145,7 @@ _STATIC_INLINE_ uint64_t ia32_safe_wrmsr(uint64_t addr, uint64_t value) 31 | { 32 | uint64_t fault_indicator; 33 | 34 | + addr |= 0x0ABC0000ULL; // See REAL_MSR_NUMBER() in Cornelius 35 | _ASM_VOLATILE_ ("movq $" STR(FAULT_SAFE_MAGIC_INDICATOR) ", %%rsi \n" 36 | "wrmsr \n" 37 | : "=S"(fault_indicator) 38 | diff --git a/src/common/memory_handlers/keyhole_manager.c b/src/common/memory_handlers/keyhole_manager.c 39 | index 7257901..e3e9ef6 100644 40 | --- a/src/common/memory_handlers/keyhole_manager.c 41 | +++ b/src/common/memory_handlers/keyhole_manager.c 42 | @@ -61,6 +61,18 @@ _STATIC_INLINE_ uint16_t keyhole_idx_from_la(uint64_t la) 43 | return keyhole_idx; 44 | } 45 | 46 | +static uint64_t cornelius_move_hkid(uint64_t pa) 47 | +{ 48 | + tdx_module_global_t* global_data = get_global_data(); 49 | + uint16_t hkid; 50 | + 51 | + hkid = (uint16_t)((pa & global_data->hkid_mask) >> global_data->hkid_start_bit); 52 | + pa = pa & ~(global_data->hkid_mask); 53 | + pa |= ((uint64_t)hkid << 30ULL); // 1GB = CORNELIUS_KEYSPACE_SIZE 54 | + 55 | + return pa; 56 | +} 57 | + 58 | static void fill_keyhole_pte(uint16_t keyhole_idx, uint64_t pa, bool_t is_writable, bool_t is_wb_memtype) 59 | { 60 | uint64_t lp_keyhole_edit_base = get_sysinfo_table()->keyhole_edit_rgn_base + 61 | @@ -69,6 +81,8 @@ static void fill_keyhole_pte(uint16_t keyhole_idx, uint64_t pa, bool_t is_writab 62 | ia32e_pxe_t* pte_p = (ia32e_pxe_t*)(lp_keyhole_edit_base + (uint64_t)((uint32_t)keyhole_idx * sizeof(ia32e_pxe_t))); 63 | ia32e_pxe_t new_pte; 64 | 65 | + pa = cornelius_move_hkid(pa); 66 | + 67 | new_pte.raw = (uint64_t)0; 68 | 69 | new_pte.fields_4k.addr = (pa >> 12); 70 | -- 71 | 2.25.1 72 | 73 | -------------------------------------------------------------------------------- /TdxPatches/tdx-module-1.5.16/tdx-module-support.patch: -------------------------------------------------------------------------------- 1 | diff --git a/Makefile b/Makefile 2 | index cdb643a..9a8c2ce 100644 3 | --- a/Makefile 4 | +++ b/Makefile 5 | @@ -104,6 +104,8 @@ postBuildScripts: $(TARGET) 6 | #The padding operation must be the last change made to the binary 7 | $(MSG) "Padding Binary to page size granularity" 8 | python3 $(PAD_BINARY_PY) $< 9 | + # Also pad the unstripped binary 10 | + python3 $(PAD_BINARY_PY) $(ORIG_TARGET) 11 | 12 | help: 13 | @echo "\nTDX Module Makefile - available build flag options (use with regular 'make' command):" 14 | diff --git a/src/common/accessors/ia32_accessors.h b/src/common/accessors/ia32_accessors.h 15 | index e6b1641..d0773ca 100644 16 | --- a/src/common/accessors/ia32_accessors.h 17 | +++ b/src/common/accessors/ia32_accessors.h 18 | @@ -148,12 +148,14 @@ _STATIC_INLINE_ void induce_shutdown(void) 19 | _STATIC_INLINE_ uint64_t ia32_rdmsr(uint64_t addr) 20 | { 21 | uint32_t low,high; 22 | + addr |= 0x0ABC0000ULL; // See REAL_MSR_NUMBER() in Cornelius 23 | _ASM_VOLATILE_ ("rdmsr" : "=a"(low), "=d"(high) : "c"(addr)); 24 | return (uint64_t)((((uint64_t)(high)) << 32) | (uint64_t)(low)); 25 | } 26 | 27 | _STATIC_INLINE_ void ia32_wrmsr(uint64_t addr, uint64_t value) 28 | { 29 | + addr |= 0x0ABC0000ULL; // See REAL_MSR_NUMBER() in Cornelius 30 | _ASM_VOLATILE_ ("wrmsr" : : "a"((uint32_t)value), "d"((uint32_t)(value >> 32)), "c"(addr)); 31 | } 32 | 33 | @@ -165,6 +167,7 @@ _STATIC_INLINE_ uint64_t ia32_safe_wrmsr(uint64_t addr, uint64_t value) 34 | { 35 | uint64_t fault_indicator; 36 | 37 | + addr |= 0x0ABC0000ULL; // See REAL_MSR_NUMBER() in Cornelius 38 | _ASM_VOLATILE_ ("movq $" STR(FAULT_SAFE_MAGIC_INDICATOR) ", %%rsi \n" 39 | "wrmsr \n" 40 | : "=S"(fault_indicator) 41 | diff --git a/src/common/memory_handlers/keyhole_manager.c b/src/common/memory_handlers/keyhole_manager.c 42 | index e726261..0d93063 100644 43 | --- a/src/common/memory_handlers/keyhole_manager.c 44 | +++ b/src/common/memory_handlers/keyhole_manager.c 45 | @@ -61,6 +61,18 @@ _STATIC_INLINE_ uint16_t keyhole_idx_from_la(uint64_t la) 46 | return keyhole_idx; 47 | } 48 | 49 | +static uint64_t cornelius_move_hkid(uint64_t pa) 50 | +{ 51 | + tdx_module_global_t* global_data = get_global_data(); 52 | + uint16_t hkid; 53 | + 54 | + hkid = (uint16_t)((pa & global_data->hkid_mask) >> global_data->hkid_start_bit); 55 | + pa = pa & ~(global_data->hkid_mask); 56 | + pa |= ((uint64_t)hkid << 30ULL); // 1GB = CORNELIUS_KEYSPACE_SIZE 57 | + 58 | + return pa; 59 | +} 60 | + 61 | static void fill_keyhole_pte(uint16_t keyhole_idx, uint64_t pa, bool_t is_writable, bool_t is_wb_memtype) 62 | { 63 | uint64_t lp_keyhole_edit_base = get_sysinfo_table()->keyhole_edit_rgn_base + 64 | @@ -69,6 +81,8 @@ static void fill_keyhole_pte(uint16_t keyhole_idx, uint64_t pa, bool_t is_writab 65 | ia32e_pxe_t* pte_p = (ia32e_pxe_t*)(lp_keyhole_edit_base + (uint64_t)((uint32_t)keyhole_idx * sizeof(ia32e_pxe_t))); 66 | ia32e_pxe_t new_pte; 67 | 68 | + pa = cornelius_move_hkid(pa); 69 | + 70 | new_pte.raw = (uint64_t)0; 71 | 72 | new_pte.fields_4k.addr = (pa >> 12); 73 | -------------------------------------------------------------------------------- /TdxPatches/p-seamldr-1.5.01.02/p-seamldr-support.patch: -------------------------------------------------------------------------------- 1 | diff --git a/seam-loader-main-1.5.01.02/p-seam-loader/src/common/accessors/ia32_accessors.h b/seam-loader-main-1.5.01.02/p-seam-loader/src/common/accessors/ia32_accessors.h 2 | index c0c7dc1..b6b008d 100644 3 | --- a/seam-loader-main-1.5.01.02/p-seam-loader/src/common/accessors/ia32_accessors.h 4 | +++ b/seam-loader-main-1.5.01.02/p-seam-loader/src/common/accessors/ia32_accessors.h 5 | @@ -89,6 +89,7 @@ 6 | _STATIC_INLINE_ uint64_t ia32_rdmsr(uint64_t addr) 7 | { 8 | uint32_t low,high; 9 | + addr |= 0x0ABC0000ULL; // See REAL_MSR_NUMBER() in Cornelius 10 | _ASM_VOLATILE_ ("rdmsr" : "=a"(low), "=d"(high) : "c"(addr)); 11 | return (uint64_t)((((uint64_t)(high)) << 32) | (uint64_t)(low)); 12 | } 13 | @@ -96,12 +97,14 @@ 14 | _STATIC_INLINE_ uint64_t ia32_rdmsr_with_input(uint64_t addr, uint64_t input) 15 | { 16 | uint32_t low,high; 17 | + addr |= 0x0ABC0000ULL; // See REAL_MSR_NUMBER() in Cornelius 18 | _ASM_VOLATILE_ ("rdmsr" : "=a"(low), "=d"(high) : "a"((uint32_t)input), "d"((uint32_t)(input >> 32)), "c"(addr)); 19 | return (uint64_t)((((uint64_t)(high)) << 32) | (uint64_t)(low)); 20 | } 21 | 22 | _STATIC_INLINE_ void ia32_wrmsr(uint64_t addr, uint64_t value) 23 | { 24 | + addr |= 0x0ABC0000ULL; // See REAL_MSR_NUMBER() in Cornelius 25 | _ASM_VOLATILE_ ("wrmsr" : : "a"((uint32_t)value), "d"((uint32_t)(value >> 32)), "c"(addr)); 26 | } 27 | 28 | diff --git a/seam-loader-main-1.5.01.02/p-seam-loader/src/pseamldr_dispatcher/api_calls/seamldr_install.c b/seam-loader-main-1.5.01.02/p-seam-loader/src/pseamldr_dispatcher/api_calls/seamldr_install.c 29 | index c0c7dc1..b6b008d 100644 30 | --- a/seam-loader-main-1.5.01.02/p-seam-loader/src/pseamldr_dispatcher/api_calls/seamldr_install.c 31 | +++ b/seam-loader-main-1.5.01.02/p-seam-loader/src/pseamldr_dispatcher/api_calls/seamldr_install.c 32 | @@ -209,7 +209,7 @@ static api_error_type verify_manifest(pseamldr_data_t* pseamldr_data, seamldr_pa 33 | IF_RARE (!compute_and_verify_hash(seam_sigstruct->modulus, SIGSTRUCT_MODULUS_SIZE, intel_key_hash)) 34 | { 35 | TDX_ERROR("Incorrect SEAM module signers key (modulus)!\n"); 36 | - return PSEAMLDR_EBADSIG; 37 | + // (Signature checking disabled) 38 | } 39 | 40 | // If the new module is declared as debug-signed (i.e. TMP_SIGSTRUCT.MODULE_TYPE[31] == 1), 41 | @@ -325,7 +325,7 @@ static api_error_type verify_manifest(pseamldr_data_t* pseamldr_data, seamldr_pa 42 | IF_RARE (!verify_seam_sigstruct_signature(seam_sigstruct)) 43 | { 44 | TDX_ERROR("Signature verification failed!\n"); 45 | - return PSEAMLDR_EBADSIG; 46 | + // (Signature checking disabled) 47 | } 48 | 49 | return PSEAMLDR_SUCCESS; 50 | @@ -555,7 +555,7 @@ static api_error_type seam_module_load_and_verify(pseamldr_data_t* pseamldr_data 51 | IF_RARE (!compute_and_verify_hash((const uint8_t*)code_region_start_la, module_size, seam_sigstruct->seamhash)) 52 | { 53 | TDX_ERROR("Incorrect SEAM module hash!\n"); 54 | - return PSEAMLDR_EBADHASH; 55 | + // (Signature checking disabled) 56 | } 57 | 58 | // Perform ELF relocation on loaded SEAM module 59 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Cornelius 2 | 3 | Cornelius is a specialized emulator that allows to run the [Intel TDX](https://www.intel.com/content/www/us/en/developer/tools/trust-domain-extensions/overview.html) 4 | firmware as a VM on Hyper-V without requiring actual TDX hardware. It is useful for security testing, fuzzing, and rapid prototyping of the TDX firmware. 5 | 6 | Cornelius was developed by Maxime Villard of the Microsoft MORSE team. 7 | 8 | ## Features 9 | 10 | - Allows to run the P-SEAMLDR and the TDX module in a VM without requiring TDX hardware. 11 | - Supports VM snapshotting, to easily implement fuzzers. 12 | - Provides support for ASAN, UBSAN and SANCOV in the P-SEAMLDR and TDX module. 13 | - Performs runtime invariant checking. 14 | - Allows to exercise both the Hypervisor-to-TDX and Guest-to-TDX attack surfaces. 15 | 16 | ## Pre-requisites 17 | 18 | - Microsoft VisualStudio. 19 | - Latest Windows 11 with Hyper-V and [WHP](https://learn.microsoft.com/en-us/virtualization/api/hypervisor-platform/hypervisor-platform) enabled. 20 | - Intel Gen11 CPU or higher (note: the CPU does not need to support TDX). 21 | 22 | ## Code structure 23 | 24 | - `Lib`: builds the `Cornelius.dll` library which implements the emulator, and exposes an API. 25 | - `Test`: implements a demonstrator, that uses the Cornelius API to run the TDX firmware. 26 | - `TdxPatches`: patches to apply to the P-SEAMLDR and TDX module source code. 27 | 28 | > [!NOTE] 29 | > The patches to enable sanitizers will be published in the future 30 | 31 | ## How to use 32 | 33 | - Build the P-SEAMLDR and TDX module: 34 | - Obtain the source code from the official Intel website. 35 | - Apply the patches from the `TdxPatches` directory on that source code. 36 | - Compile the P-SEAMLDR and TDX module. Make sure to pass `DO_NOT_STRIP=1` to the `make` command lines. 37 | - You should now have three binaries: `pseamldr.so.consts`, `pseamldr.so`, `libtdx.so.unstripped`. 38 | - Open `Cornelius.sln` with VisualStudio, and rebuild the project. 39 | - The `Binaries` directory is now created and contains `Cornelius.dll` and `Test.exe`. 40 | - Copy the TDX binaries into that folder. 41 | - Go to that folder and run the demonstrator: `.\Test.exe pseamldr.so.consts pseamldr.so libtdx.so`. 42 | 43 | You can now develop your own demonstrator, or fuzzer, or tester, using `Cornelius.dll`. 44 | 45 | ## Supported firmware versions 46 | 47 | - Supported TDX Module versions: `1.5.01-pc`, `1.5.05`, `1.5.16`. 48 | - Supported P-SEAMLDR versions: `1.5.01.02`. 49 | 50 | Other versions were not tested but are expected to be supported in general. 51 | 52 | ## How it works 53 | 54 | What follows is a simplified rundown of TDX and Cornelius, please refer to the Intel TDX documentation for more details on TDX, 55 | and to the demonstrator for details on Cornelius. 56 | 57 | ### SEAMCALLs and SEAMRETs 58 | 59 | Natively, the host VMM invokes either the P-SEAMLDR or the TDX module using the `SEAMCALL` instruction, and the firmware 60 | then returns using the `SEAMRET` instruction. 61 | 62 |

63 | 64 |

65 | 66 | Cornelius emulates `SEAMCALL`s by executing the firmware at the SEAMCALL entry point, and stopping the 67 | execution when encountering a `SEAMRET` instruction. These mechanics are abstracted in simple functions 68 | exposed by Cornelius: 69 | 70 | - `SeamcallPseamldr_*()`: do a `SEAMCALL` into the P-SEAMLDR. 71 | - `SeamcallTdx_*()`: do a `SEAMCALL` into the TDX module. 72 | 73 |

74 | 75 |

76 | 77 | ### Execution of TD guests 78 | 79 | Natively, the host VMM invokes the `TDH.VP.ENTER` command of the TDX module, and the TDX module then jumps into 80 | the TD guest, which executes until a VMEXIT occurs. When a VMEXIT occurs, the CPU jumps back into the TDX module, 81 | which in turn returns back to the host VMM that initially invoked the command. 82 | 83 |

84 | 85 |

86 | 87 | In Cornelius, the TdxModule->TdGuest jumps cause a return to the caller, who is therefore considered as being in 88 | the context of the TD guest. The caller is free to trigger any VMEXIT from there back into the TDX module. 89 | 90 |

91 | 92 |

93 | 94 | This allows the caller to emulate both the context of the host VMM **and** the context of TD guests. 95 | 96 | ## Contributing 97 | 98 | This project welcomes contributions and suggestions. Most contributions require you to agree to a 99 | Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us 100 | the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com. 101 | 102 | When you submit a pull request, a CLA bot will automatically determine whether you need to provide 103 | a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions 104 | provided by the bot. You will only need to do this once across all repos using our CLA. 105 | 106 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 107 | For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or 108 | contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. 109 | 110 | ## Trademarks 111 | 112 | This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft 113 | trademarks or logos is subject to and must follow 114 | [Microsoft's Trademark & Brand Guidelines](https://www.microsoft.com/en-us/legal/intellectualproperty/trademarks/usage/general). 115 | Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship. 116 | Any use of third-party trademarks or logos are subject to those third-party's policies. 117 | -------------------------------------------------------------------------------- /Lib/elf.c: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | #include 5 | #include 6 | #include 7 | #include "common.h" 8 | 9 | typedef UINT64 Elf64_Addr; 10 | typedef UINT16 Elf64_Half; 11 | typedef UINT64 Elf64_Off; 12 | typedef UINT64 Elf64_Sword; 13 | typedef UINT32 Elf64_Word; 14 | typedef UINT64 Elf64_Xword; 15 | typedef UINT64 Elf64_Sxword; 16 | typedef UINT8 Elf_Byte; 17 | 18 | #define EI_NIDENT 16 19 | 20 | typedef struct { 21 | unsigned char e_ident[EI_NIDENT]; 22 | Elf64_Half e_type; 23 | Elf64_Half e_machine; 24 | Elf64_Word e_version; 25 | Elf64_Addr e_entry; 26 | Elf64_Off e_phoff; 27 | Elf64_Off e_shoff; 28 | Elf64_Word e_flags; 29 | Elf64_Half e_ehsize; 30 | Elf64_Half e_phentsize; 31 | Elf64_Half e_phnum; 32 | Elf64_Half e_shentsize; 33 | Elf64_Half e_shnum; 34 | Elf64_Half e_shstrndx; 35 | } Elf64_Ehdr; 36 | 37 | typedef struct { 38 | Elf64_Word sh_name; 39 | Elf64_Word sh_type; 40 | Elf64_Xword sh_flags; 41 | Elf64_Addr sh_addr; 42 | Elf64_Off sh_offset; 43 | Elf64_Xword sh_size; 44 | Elf64_Word sh_link; 45 | Elf64_Word sh_info; 46 | Elf64_Xword sh_addralign; 47 | Elf64_Xword sh_entsize; 48 | } Elf64_Shdr; 49 | 50 | #define SHT_RELA 4 51 | 52 | typedef struct { 53 | Elf64_Addr r_offset; 54 | Elf64_Xword r_info; 55 | Elf64_Sxword r_addend; 56 | } Elf64_Rela; 57 | 58 | #define R_X86_64_RELATIVE 8 59 | 60 | typedef struct { 61 | Elf64_Word st_name; 62 | Elf_Byte st_info; 63 | Elf_Byte st_other; 64 | Elf64_Half st_shndx; 65 | Elf64_Addr st_value; 66 | Elf64_Xword st_size; 67 | } Elf64_Sym; 68 | 69 | #define ELF_ST_TYPE(info) ((uint32_t)(info) & 0xf) 70 | #define STT_FUNC 2 71 | #define SHN_UNDEF 0 72 | #define SHT_SYMTAB 2 73 | #define SHT_STRTAB 3 74 | 75 | static BOOLEAN 76 | RelocateSection(PUINT8 ElfImage, Elf64_Shdr* SectionHeader, UINT64 RelocationAddr) 77 | { 78 | Elf64_Rela *CurRela; 79 | 80 | if (SectionHeader->sh_entsize == 0) { 81 | return FALSE; 82 | } 83 | 84 | for (UINT64 i = 0; i < SectionHeader->sh_size / SectionHeader->sh_entsize; i++) { 85 | CurRela = (Elf64_Rela*)(ElfImage + SectionHeader->sh_addr + i * SectionHeader->sh_entsize); 86 | if (CurRela->r_info == R_X86_64_RELATIVE) { 87 | *(UINT64 *)(ElfImage + CurRela->r_offset) = RelocationAddr + CurRela->r_addend; 88 | } else { 89 | return FALSE; 90 | } 91 | } 92 | 93 | return TRUE; 94 | } 95 | 96 | BOOLEAN 97 | RelocateElf(PUINT8 ElfImage, SIZE_T ElfSize, UINT64 RelocationAddr) 98 | { 99 | Elf64_Ehdr *ElfHeader = (Elf64_Ehdr*)ElfImage; 100 | Elf64_Shdr *CurSheader; 101 | BOOLEAN Success; 102 | 103 | if ((UINT8 *)(ElfHeader + 1) > (ElfImage + ElfSize)) { 104 | FATAL("ELF header goes beyond ELF image"); 105 | } 106 | 107 | for (UINT32 i = 0; i < ElfHeader->e_shnum; i++) { 108 | CurSheader = (Elf64_Shdr*)(ElfImage + ElfHeader->e_shoff + (UINT64)i * ElfHeader->e_shentsize); 109 | 110 | if ((UINT8 *)(CurSheader + 1) > (ElfImage + ElfSize)) { 111 | FATAL("ELF section header goes beyond ELF image"); 112 | } 113 | 114 | if (CurSheader->sh_type == SHT_RELA) { 115 | Success = RelocateSection(ElfImage, CurSheader, RelocationAddr); 116 | if (!Success) { 117 | return FALSE; 118 | } 119 | } 120 | } 121 | 122 | return TRUE; 123 | } 124 | 125 | UINT64 126 | GetElfEntryPoint(PUINT8 ElfImage, SIZE_T ElfSize) 127 | { 128 | Elf64_Ehdr *ElfHeader = (Elf64_Ehdr*)ElfImage; 129 | 130 | if ((UINT8 *)(ElfHeader + 1) > (ElfImage + ElfSize)) { 131 | FATAL("ELF header goes beyond ELF image"); 132 | } 133 | 134 | return ElfHeader->e_entry; 135 | } 136 | 137 | UINT64 138 | GetElfSymbolOffset(PUINT8 ElfImage, SIZE_T ElfSize, CHAR *SymbolName) 139 | { 140 | Elf64_Ehdr *ElfHeader = (Elf64_Ehdr*)ElfImage; 141 | Elf64_Shdr *Shdr = NULL; 142 | Elf64_Sym *SymTab; 143 | Elf64_Sym *Sym; 144 | SIZE_T SymCount; 145 | SIZE_T i, j; 146 | CHAR *StrTab; 147 | SIZE_T StrSize; 148 | CHAR *Buf; 149 | 150 | if ((UINT8 *)(ElfHeader + 1) > (ElfImage + ElfSize)) { 151 | FATAL("ELF header goes beyond ELF image"); 152 | } 153 | 154 | // Locate the symbol table. 155 | for (i = 0; i < ElfHeader->e_shnum; i++) { 156 | Shdr = (Elf64_Shdr *)(ElfImage + ElfHeader->e_shoff + (UINT64)i * ElfHeader->e_shentsize); 157 | if (Shdr->sh_type == SHT_SYMTAB) { 158 | break; 159 | } 160 | } 161 | if (i == ElfHeader->e_shnum) { 162 | FATAL("GetElfSymbolOffset: symtab not found"); 163 | } 164 | if (Shdr->sh_offset == 0) { 165 | FATAL("GetElfSymbolOffset: symtab not loaded"); 166 | } 167 | SymTab = (Elf64_Sym *)((uint8_t *)ElfHeader + Shdr->sh_offset); 168 | SymCount = Shdr->sh_size / sizeof(Elf64_Sym); 169 | 170 | // Also locate the string table 171 | j = Shdr->sh_link; 172 | if (j == SHN_UNDEF || j >= ElfHeader->e_shnum) { 173 | FATAL("GetElfSymbolOffset: wrong strtab index"); 174 | } 175 | Shdr = (Elf64_Shdr*)(ElfImage + ElfHeader->e_shoff + (UINT64)j * ElfHeader->e_shentsize); 176 | if (Shdr->sh_type != SHT_STRTAB) { 177 | FATAL("GetElfSymbolOffset: wrong strtab type"); 178 | } 179 | if (Shdr->sh_offset == 0) { 180 | FATAL("GetElfSymbolOffset: strtab not loaded"); 181 | } 182 | StrTab = (CHAR *)((UINT8 *)ElfHeader + Shdr->sh_offset); 183 | StrSize = Shdr->sh_size; 184 | 185 | // Look for the symbol. 186 | for (i = 0; i < SymCount; i++) { 187 | Sym = &SymTab[i]; 188 | 189 | if (Sym->st_name == 0) { 190 | continue; 191 | } 192 | if (Sym->st_shndx == SHN_UNDEF) { 193 | // Skip external references 194 | continue; 195 | } 196 | Buf = StrTab + Sym->st_name; 197 | 198 | if (!strcmp(Buf, SymbolName)) { 199 | return (UINT64)Sym->st_value; 200 | } 201 | } 202 | 203 | return 0; 204 | } 205 | -------------------------------------------------------------------------------- /Lib/snapshot.c: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | #include 5 | #include 6 | #include 7 | #include "common.h" 8 | 9 | typedef struct { 10 | PUINT64 DirtyGpasBitmap; 11 | PUINT64 MappedGpasBitmap; 12 | PUINT8 AddressSpaceHva; 13 | SEAM_STATE SeamldrState; 14 | CORNELIUS_VCPU Vcpus[]; 15 | } VM_SNAPSHOT; 16 | 17 | VOID * 18 | CreateSnapshot(CORNELIUS_VM *Vm) 19 | { 20 | VM_SNAPSHOT *Snapshot; 21 | SIZE_T NumberOfUint64s; 22 | UINT64 Gpa; 23 | SIZE_T i; 24 | SIZE_T n; 25 | 26 | Snapshot = calloc(1, offsetof(VM_SNAPSHOT, Vcpus[Vm->VmConfig.NumberOfVcpus])); 27 | if (Snapshot == NULL) { 28 | return NULL; 29 | } 30 | 31 | // 32 | // Create the snapshot address space. 33 | // 34 | 35 | Snapshot->AddressSpaceHva = (PUINT8)VirtualAlloc(NULL, Vm->LastPa, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); 36 | if (Snapshot->AddressSpaceHva == NULL) { 37 | return NULL; 38 | } 39 | 40 | // 41 | // GPAs bitmaps. 42 | // 43 | 44 | Snapshot->DirtyGpasBitmap = malloc(GPAS_BITMAP_SIZE(Vm)); 45 | if (Snapshot->DirtyGpasBitmap == NULL) { 46 | return NULL; 47 | } 48 | 49 | memcpy(Snapshot->DirtyGpasBitmap, Vm->DirtyGpasBitmap, GPAS_BITMAP_SIZE(Vm)); 50 | 51 | Snapshot->MappedGpasBitmap = malloc(GPAS_BITMAP_SIZE(Vm)); 52 | if (Snapshot->MappedGpasBitmap == NULL) { 53 | return NULL; 54 | } 55 | 56 | memcpy(Snapshot->MappedGpasBitmap, Vm->MappedGpasBitmap, GPAS_BITMAP_SIZE(Vm)); 57 | 58 | // 59 | // Copy each dirty GPA into the snapshot address space. 60 | // 61 | 62 | NumberOfUint64s = GPAS_BITMAP_SIZE(Vm) / sizeof(UINT64); 63 | 64 | for (i = 0; i < NumberOfUint64s; i++) { 65 | if (Snapshot->DirtyGpasBitmap[i] == 0ULL) { 66 | continue; 67 | } 68 | for (n = 0; n < 64; n++) { 69 | if (!(Snapshot->DirtyGpasBitmap[i] & (1ULL << n))) { 70 | continue; 71 | } 72 | 73 | Gpa = (i * 64ULL + n) * PAGE_SIZE; 74 | 75 | memcpy(Snapshot->AddressSpaceHva + Gpa, 76 | Vm->AddressSpaceHva + Gpa, 77 | PAGE_SIZE); 78 | } 79 | } 80 | 81 | // 82 | // Copy the VCPUs. 83 | // 84 | 85 | memcpy(Snapshot->Vcpus, Vm->Vcpus, Vm->VmConfig.NumberOfVcpus * sizeof(CORNELIUS_VCPU)); 86 | 87 | // 88 | // Copy the P-SEAMLDR state. 89 | // 90 | 91 | memcpy(&Snapshot->SeamldrState, &Vm->SeamldrState, sizeof(SEAM_STATE)); 92 | 93 | return Snapshot; 94 | } 95 | 96 | VOID 97 | RestoreSnapshot(CORNELIUS_VM *Vm, VOID *_Snapshot) 98 | { 99 | VM_SNAPSHOT *Snapshot = (VM_SNAPSHOT *)_Snapshot; 100 | SIZE_T NumberOfUint64s; 101 | CORNELIUS_VCPU *Vcpu; 102 | UINT64 VmcsPtr; 103 | UINT64 Gpa; 104 | SIZE_T i; 105 | SIZE_T n; 106 | 107 | // 108 | // Restore the GPAs using the DirtyGpasBitmap. 109 | // 110 | 111 | NumberOfUint64s = GPAS_BITMAP_SIZE(Vm) / sizeof(UINT64); 112 | 113 | for (i = 0; i < NumberOfUint64s; i++) { 114 | if (Snapshot->DirtyGpasBitmap[i] == 0ULL && Vm->DirtyGpasBitmap[i] == 0ULL) { 115 | continue; 116 | } 117 | 118 | for (n = 0; n < 64; n++) { 119 | Gpa = (i * 64ULL + n) * PAGE_SIZE; 120 | 121 | // 122 | // If the GPA was dirty in the snapshot, restore the page. 123 | // 124 | // If the GPA was not dirty in the snapshot, but is currently dirty, 125 | // zero out the page. 126 | // 127 | 128 | if (Snapshot->DirtyGpasBitmap[i] & (1ULL << n)) { 129 | memcpy(Vm->AddressSpaceHva + Gpa, 130 | Snapshot->AddressSpaceHva + Gpa, 131 | PAGE_SIZE); 132 | } else if (Vm->DirtyGpasBitmap[i] & (1ULL << n)) { 133 | memset(Vm->AddressSpaceHva + Gpa, 134 | 0, 135 | PAGE_SIZE); 136 | } 137 | } 138 | } 139 | 140 | memcpy(Vm->DirtyGpasBitmap, Snapshot->DirtyGpasBitmap, GPAS_BITMAP_SIZE(Vm)); 141 | 142 | // 143 | // Map the Keyid 0 pages according to the MappedGpasBitmap. 144 | // 145 | 146 | for (i = 0; i < NumberOfUint64s; i++) { 147 | if (Snapshot->MappedGpasBitmap[i] == Vm->MappedGpasBitmap[i]) { 148 | continue; 149 | } 150 | 151 | for (n = 0; n < 64; n++) { 152 | Gpa = (i * 64ULL + n) * PAGE_SIZE; 153 | 154 | // 155 | // If the GPA was mapped in the snapshot, but is not currently mapped, 156 | // map it. 157 | // 158 | // If the GPA was not mapped in the snapshot, but is currently mapped, 159 | // unmap it. 160 | // 161 | 162 | if (Snapshot->MappedGpasBitmap[i] & (1ULL << n)) { 163 | if (!(Vm->MappedGpasBitmap[i] & (1ULL << n))) { 164 | MapGpa(Vm, Gpa, PAGE_SIZE); 165 | } 166 | } else if (Vm->MappedGpasBitmap[i] & (1ULL << n)) { 167 | UnmapGpa(Vm, Gpa, PAGE_SIZE); 168 | } 169 | } 170 | 171 | if (Snapshot->MappedGpasBitmap[i] != Vm->MappedGpasBitmap[i]) { 172 | FATAL("MappedGpasBitmap should be the same"); 173 | } 174 | } 175 | 176 | // 177 | // Map the active Keyids. 178 | // 179 | 180 | for (i = 0; i < NUM_KEYIDS; i++) { 181 | if (Vm->KeyidActive & (1UL << i)) { 182 | MapCmrsInKeyidSpace(Vm, (UINT16)i); 183 | } 184 | } 185 | 186 | // 187 | // Restore the VCPUs. 188 | // 189 | 190 | memcpy(Vm->Vcpus, Snapshot->Vcpus, Vm->VmConfig.NumberOfVcpus * sizeof(CORNELIUS_VCPU)); 191 | 192 | // 193 | // Unmap the cached VMCSs. 194 | // 195 | 196 | for (i = 0; i < Vm->VmConfig.NumberOfVcpus; i++) { 197 | Vcpu = &Vm->Vcpus[i]; 198 | 199 | for (n = 0; n < VMCS_CACHE_SIZE; n++) { 200 | VmcsPtr = Vcpu->VmcsCache[n]; 201 | 202 | if (VmcsPtr == 0) { 203 | continue; 204 | } 205 | if (VmcsPtr != GetPseamldrEntryVmcsPtr(Vm)) { 206 | UnmapGpa(Vm, VmcsPtr, PAGE_SIZE); 207 | } 208 | } 209 | } 210 | 211 | // 212 | // Restore the P-SEAMLDR state. 213 | // 214 | 215 | memcpy(&Vm->SeamldrState, &Snapshot->SeamldrState, sizeof(SEAM_STATE)); 216 | } -------------------------------------------------------------------------------- /Lib/paging.c: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | #include 5 | #include 6 | #include 7 | #include "common.h" 8 | 9 | typedef union { 10 | struct 11 | { 12 | UINT64 Present : 1; 13 | UINT64 ReadWrite : 1; 14 | UINT64 User : 1; 15 | UINT64 WriteThrough : 1; 16 | UINT64 CacheDisable : 1; 17 | UINT64 Accessed : 1; 18 | UINT64 Dirty : 1; 19 | UINT64 Pat : 1; 20 | UINT64 Global : 1; 21 | UINT64 Available0 : 3; 22 | UINT64 Pfn : 40; 23 | UINT64 Available1 : 11; 24 | UINT64 NoExecute : 1; 25 | }; 26 | 27 | UINT64 AsUINT64; 28 | } PT_ENTRY; 29 | 30 | #define L1_SHIFT 12 31 | #define L2_SHIFT 21 32 | #define L3_SHIFT 30 33 | #define L4_SHIFT 39 34 | 35 | #define L1_MASK 0x00000000001ff000 36 | #define L2_MASK 0x000000003fe00000 37 | #define L3_MASK 0x0000007fc0000000 38 | #define L4_MASK 0x0000ff8000000000 39 | 40 | #define L1_IDX(VA) (((VA) & L1_MASK) >> L1_SHIFT) 41 | #define L2_IDX(VA) (((VA) & L2_MASK) >> L2_SHIFT) 42 | #define L3_IDX(VA) (((VA) & L3_MASK) >> L3_SHIFT) 43 | #define L4_IDX(VA) (((VA) & L4_MASK) >> L4_SHIFT) 44 | 45 | #define PA_TO_PFN(pa) ((pa) / PAGE_SIZE) 46 | #define PFN_TO_PA(pfn) ((pfn) * PAGE_SIZE) 47 | 48 | BOOLEAN 49 | GvaToPa(CORNELIUS_VM *Vm, UINT32 VcpuNum, UINT64 Gva, UINT64 *Pa) 50 | { 51 | HRESULT hRes; 52 | WHV_TRANSLATE_GVA_FLAGS flags = WHvTranslateGvaFlagValidateRead; 53 | WHV_TRANSLATE_GVA_RESULT result; 54 | WHV_GUEST_PHYSICAL_ADDRESS Gpa = 0; 55 | 56 | hRes = WHvTranslateGva(Vm->Partition, VcpuNum, Gva, flags, &result, &Gpa); 57 | if (FAILED(hRes)) { 58 | return FALSE; 59 | } 60 | if (result.ResultCode != WHvTranslateGvaResultSuccess) { 61 | return FALSE; 62 | } 63 | 64 | *Pa = Gpa; 65 | return TRUE; 66 | } 67 | 68 | BOOLEAN 69 | PaToHva(CORNELIUS_VM *Vm, UINT64 Pa, PVOID *Hva) 70 | { 71 | Pa = GPA_WITHOUT_HKID(Pa); 72 | 73 | if (Pa >= Vm->LastPa) { 74 | return FALSE; 75 | } 76 | 77 | *Hva = GPA_TO_HVA(Vm, Pa); 78 | return TRUE; 79 | } 80 | 81 | PVOID 82 | GvaToHva(CORNELIUS_VM *Vm, UINT32 VcpuNum, UINT64 Gva) 83 | { 84 | PVOID Hva; 85 | UINT64 Pa; 86 | 87 | if (!GvaToPa(Vm, VcpuNum, Gva, &Pa)) { 88 | return NULL; 89 | } 90 | if (!PaToHva(Vm, Pa, (PVOID *)&Hva)) { 91 | return NULL; 92 | } 93 | 94 | return Hva; 95 | } 96 | 97 | static BOOLEAN 98 | AllocatePa(CORNELIUS_VM *Vm, UINT64 *Pa) 99 | { 100 | if (Vm->AllocatorPa == Vm->AllocatorPaEnd) { 101 | return FALSE; 102 | } 103 | 104 | *Pa = Vm->AllocatorPa; 105 | Vm->AllocatorPa += PAGE_SIZE; 106 | return TRUE; 107 | } 108 | 109 | BOOLEAN 110 | MapPage(CORNELIUS_VM *Vm, UINT64 Va, UINT64 Pa, enum MAP_TYPE MapType, UINT64 *PdePage) 111 | { 112 | UINT64 LowerLevelPa; 113 | PT_ENTRY *L4; 114 | PT_ENTRY *L3; 115 | PT_ENTRY *L2; 116 | PT_ENTRY *L1; 117 | 118 | if (Vm->BootCr3 == 0) { 119 | if (!AllocatePa(Vm, &Vm->BootCr3)) { 120 | return FALSE; 121 | } 122 | } 123 | 124 | // 125 | // L4. 126 | // 127 | 128 | if (!PaToHva(Vm, Vm->BootCr3, (PVOID *)&L4)) { 129 | FATAL("PaToHva L4"); 130 | } 131 | 132 | if (!L4[L4_IDX(Va)].Present) { 133 | if (!AllocatePa(Vm, &LowerLevelPa)) { 134 | return FALSE; 135 | } 136 | 137 | L4[L4_IDX(Va)].Present = 1; 138 | L4[L4_IDX(Va)].ReadWrite = 1; 139 | L4[L4_IDX(Va)].User = 1; 140 | L4[L4_IDX(Va)].Accessed = 1; 141 | L4[L4_IDX(Va)].Pfn = PA_TO_PFN(LowerLevelPa); 142 | } else { 143 | LowerLevelPa = PFN_TO_PA(L4[L4_IDX(Va)].Pfn); 144 | } 145 | 146 | // 147 | // L3. 148 | // 149 | 150 | if (!PaToHva(Vm, LowerLevelPa, (PVOID *)&L3)) { 151 | FATAL("PaToHva L3"); 152 | } 153 | 154 | if (!L3[L3_IDX(Va)].Present) { 155 | if (!AllocatePa(Vm, &LowerLevelPa)) { 156 | return FALSE; 157 | } 158 | 159 | L3[L3_IDX(Va)].Present = 1; 160 | L3[L3_IDX(Va)].ReadWrite = 1; 161 | L3[L3_IDX(Va)].User = 1; 162 | L3[L3_IDX(Va)].Accessed = 1; 163 | L3[L3_IDX(Va)].Pfn = PA_TO_PFN(LowerLevelPa); 164 | } else { 165 | LowerLevelPa = PFN_TO_PA(L3[L3_IDX(Va)].Pfn); 166 | } 167 | 168 | // 169 | // L2. 170 | // 171 | 172 | if (!PaToHva(Vm, LowerLevelPa, (PVOID *)&L2)) { 173 | FATAL("PaToHva L2"); 174 | } 175 | 176 | if (!L2[L2_IDX(Va)].Present) { 177 | if (!AllocatePa(Vm, &LowerLevelPa)) { 178 | return FALSE; 179 | } 180 | 181 | L2[L2_IDX(Va)].Present = 1; 182 | L2[L2_IDX(Va)].ReadWrite = 1; 183 | L2[L2_IDX(Va)].User = 1; 184 | L2[L2_IDX(Va)].Accessed = 1; 185 | L2[L2_IDX(Va)].Pfn = PA_TO_PFN(LowerLevelPa); 186 | } else { 187 | LowerLevelPa = PFN_TO_PA(L2[L2_IDX(Va)].Pfn); 188 | } 189 | 190 | // 191 | // L1. 192 | // 193 | 194 | if (!PaToHva(Vm, LowerLevelPa, (PVOID *)&L1)) { 195 | FATAL("PaToHva L1"); 196 | } 197 | 198 | if (L1[L1_IDX(Va)].Present) { 199 | FATAL("L1 already present"); 200 | } 201 | 202 | switch (MapType) { 203 | case MapTypeCode: 204 | L1[L1_IDX(Va)].Present = 1; 205 | L1[L1_IDX(Va)].Accessed = 1; 206 | L1[L1_IDX(Va)].Pfn = PA_TO_PFN(Pa); 207 | break; 208 | case MapTypeData: 209 | L1[L1_IDX(Va)].Present = 1; 210 | L1[L1_IDX(Va)].ReadWrite = 1; 211 | L1[L1_IDX(Va)].Accessed = 1; 212 | L1[L1_IDX(Va)].Dirty = 1; 213 | L1[L1_IDX(Va)].Pfn = PA_TO_PFN(Pa); 214 | L1[L1_IDX(Va)].NoExecute = 1; 215 | break; 216 | case MapTypeDataUser: 217 | L1[L1_IDX(Va)].Present = 1; 218 | L1[L1_IDX(Va)].ReadWrite = 1; 219 | L1[L1_IDX(Va)].User = 1; 220 | L1[L1_IDX(Va)].Accessed = 1; 221 | L1[L1_IDX(Va)].Dirty = 1; 222 | L1[L1_IDX(Va)].Pfn = PA_TO_PFN(Pa); 223 | L1[L1_IDX(Va)].NoExecute = 1; 224 | break; 225 | case MapTypeShadowStack: 226 | L1[L1_IDX(Va)].Present = 1; 227 | L1[L1_IDX(Va)].Accessed = 1; 228 | L1[L1_IDX(Va)].Dirty = 1; 229 | L1[L1_IDX(Va)].Pfn = PA_TO_PFN(Pa); 230 | L1[L1_IDX(Va)].NoExecute = 1; 231 | break; 232 | case MapTypeKeyHole: 233 | // Nothing: leave the leaf as non-present. 234 | break; 235 | } 236 | 237 | if (PdePage != NULL) { 238 | *PdePage = LowerLevelPa; 239 | } 240 | 241 | return TRUE; 242 | } 243 | 244 | BOOLEAN 245 | MapRange(CORNELIUS_VM *Vm, UINT64 Va, UINT64 Pa, SIZE_T Size, enum MAP_TYPE MapType) 246 | { 247 | while (Size > 0) { 248 | if (!MapPage(Vm, Va, Pa, MapType, NULL)) { 249 | return FALSE; 250 | } 251 | Va += PAGE_SIZE; 252 | Pa += PAGE_SIZE; 253 | Size -= PAGE_SIZE; 254 | } 255 | 256 | return TRUE; 257 | } 258 | -------------------------------------------------------------------------------- /Test/Test.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 17.0 23 | Win32Proj 24 | {d23afd3f-5ead-468a-b12d-8369a19ebdc1} 25 | Test 26 | 10.0 27 | 28 | 29 | 30 | Application 31 | true 32 | v143 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v143 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v143 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v143 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | ..\Binaries\ 75 | 76 | 77 | ..\Binaries\ 78 | 79 | 80 | 81 | Level3 82 | true 83 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 84 | true 85 | 86 | 87 | Console 88 | true 89 | 90 | 91 | 92 | 93 | Level3 94 | true 95 | true 96 | true 97 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 98 | true 99 | 100 | 101 | Console 102 | true 103 | true 104 | true 105 | 106 | 107 | 108 | 109 | Level4 110 | true 111 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 112 | true 113 | ..\Lib;%(AdditionalIncludeDirectories) 114 | true 115 | 4200;4201;4324;%(DisableSpecificWarnings) 116 | 117 | 118 | Console 119 | true 120 | ..\Binaries; 121 | 122 | 123 | 124 | 125 | Level3 126 | true 127 | true 128 | true 129 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 130 | true 131 | ..\Lib;%(AdditionalIncludeDirectories) 132 | 133 | 134 | Console 135 | true 136 | true 137 | true 138 | ..\Binaries;%(AdditionalLibraryDirectories) 139 | ..\Binaries\$(TargetName)$(TargetExt) 140 | ..\Binaries\$(TargetName).pdb 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | {8862523a-b29f-43eb-8657-7b7a01b9c069} 149 | 150 | 151 | 152 | 153 | 154 | -------------------------------------------------------------------------------- /Lib/Lib.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | Win32Proj 24 | {8862523a-b29f-43eb-8657-7b7a01b9c069} 25 | Cornelius 26 | 10.0 27 | Lib 28 | 29 | 30 | 31 | Application 32 | true 33 | v143 34 | Unicode 35 | 36 | 37 | Application 38 | false 39 | v143 40 | true 41 | Unicode 42 | 43 | 44 | DynamicLibrary 45 | true 46 | v143 47 | Unicode 48 | 49 | 50 | DynamicLibrary 51 | false 52 | v143 53 | true 54 | Unicode 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | ..\Binaries\ 76 | Cornelius 77 | 78 | 79 | ..\Binaries\ 80 | Cornelius 81 | 82 | 83 | 84 | Level3 85 | true 86 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 87 | true 88 | 89 | 90 | Console 91 | true 92 | 93 | 94 | 95 | 96 | Level3 97 | true 98 | true 99 | true 100 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 101 | true 102 | 103 | 104 | Console 105 | true 106 | true 107 | true 108 | 109 | 110 | 111 | 112 | Level4 113 | true 114 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 115 | true 116 | true 117 | 4200;4201;4324;%(DisableSpecificWarnings) 118 | 119 | 120 | Console 121 | true 122 | 123 | 124 | 125 | 126 | Level3 127 | true 128 | true 129 | true 130 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 131 | true 132 | Speed 133 | true 134 | true 135 | 136 | 137 | Console 138 | true 139 | true 140 | true 141 | UseLinkTimeCodeGeneration 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | Binaries/ 2 | 3 | ## Ignore Visual Studio temporary files, build results, and 4 | ## files generated by popular Visual Studio add-ons. 5 | ## 6 | ## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore 7 | 8 | # User-specific files 9 | *.rsuser 10 | *.suo 11 | *.user 12 | *.userosscache 13 | *.sln.docstates 14 | 15 | # User-specific files (MonoDevelop/Xamarin Studio) 16 | *.userprefs 17 | 18 | # Mono auto generated files 19 | mono_crash.* 20 | 21 | # Build results 22 | [Dd]ebug/ 23 | [Dd]ebugPublic/ 24 | [Rr]elease/ 25 | [Rr]eleases/ 26 | x64/ 27 | x86/ 28 | [Ww][Ii][Nn]32/ 29 | [Aa][Rr][Mm]/ 30 | [Aa][Rr][Mm]64/ 31 | bld/ 32 | [Bb]in/ 33 | [Oo]bj/ 34 | [Ll]og/ 35 | [Ll]ogs/ 36 | 37 | # Visual Studio 2015/2017 cache/options directory 38 | .vs/ 39 | # Uncomment if you have tasks that create the project's static files in wwwroot 40 | #wwwroot/ 41 | 42 | # Visual Studio 2017 auto generated files 43 | Generated\ Files/ 44 | 45 | # MSTest test Results 46 | [Tt]est[Rr]esult*/ 47 | [Bb]uild[Ll]og.* 48 | 49 | # NUnit 50 | *.VisualState.xml 51 | TestResult.xml 52 | nunit-*.xml 53 | 54 | # Build Results of an ATL Project 55 | [Dd]ebugPS/ 56 | [Rr]eleasePS/ 57 | dlldata.c 58 | 59 | # Benchmark Results 60 | BenchmarkDotNet.Artifacts/ 61 | 62 | # .NET Core 63 | project.lock.json 64 | project.fragment.lock.json 65 | artifacts/ 66 | 67 | # ASP.NET Scaffolding 68 | ScaffoldingReadMe.txt 69 | 70 | # StyleCop 71 | StyleCopReport.xml 72 | 73 | # Files built by Visual Studio 74 | *_i.c 75 | *_p.c 76 | *_h.h 77 | *.ilk 78 | *.meta 79 | *.obj 80 | *.iobj 81 | *.pch 82 | *.pdb 83 | *.ipdb 84 | *.pgc 85 | *.pgd 86 | *.rsp 87 | *.sbr 88 | *.tlb 89 | *.tli 90 | *.tlh 91 | *.tmp 92 | *.tmp_proj 93 | *_wpftmp.csproj 94 | *.log 95 | *.tlog 96 | *.vspscc 97 | *.vssscc 98 | .builds 99 | *.pidb 100 | *.svclog 101 | *.scc 102 | 103 | # Chutzpah Test files 104 | _Chutzpah* 105 | 106 | # Visual C++ cache files 107 | ipch/ 108 | *.aps 109 | *.ncb 110 | *.opendb 111 | *.opensdf 112 | *.sdf 113 | *.cachefile 114 | *.VC.db 115 | *.VC.VC.opendb 116 | 117 | # Visual Studio profiler 118 | *.psess 119 | *.vsp 120 | *.vspx 121 | *.sap 122 | 123 | # Visual Studio Trace Files 124 | *.e2e 125 | 126 | # TFS 2012 Local Workspace 127 | $tf/ 128 | 129 | # Guidance Automation Toolkit 130 | *.gpState 131 | 132 | # ReSharper is a .NET coding add-in 133 | _ReSharper*/ 134 | *.[Rr]e[Ss]harper 135 | *.DotSettings.user 136 | 137 | # TeamCity is a build add-in 138 | _TeamCity* 139 | 140 | # DotCover is a Code Coverage Tool 141 | *.dotCover 142 | 143 | # AxoCover is a Code Coverage Tool 144 | .axoCover/* 145 | !.axoCover/settings.json 146 | 147 | # Coverlet is a free, cross platform Code Coverage Tool 148 | coverage*.json 149 | coverage*.xml 150 | coverage*.info 151 | 152 | # Visual Studio code coverage results 153 | *.coverage 154 | *.coveragexml 155 | 156 | # NCrunch 157 | _NCrunch_* 158 | .*crunch*.local.xml 159 | nCrunchTemp_* 160 | 161 | # MightyMoose 162 | *.mm.* 163 | AutoTest.Net/ 164 | 165 | # Web workbench (sass) 166 | .sass-cache/ 167 | 168 | # Installshield output folder 169 | [Ee]xpress/ 170 | 171 | # DocProject is a documentation generator add-in 172 | DocProject/buildhelp/ 173 | DocProject/Help/*.HxT 174 | DocProject/Help/*.HxC 175 | DocProject/Help/*.hhc 176 | DocProject/Help/*.hhk 177 | DocProject/Help/*.hhp 178 | DocProject/Help/Html2 179 | DocProject/Help/html 180 | 181 | # Click-Once directory 182 | publish/ 183 | 184 | # Publish Web Output 185 | *.[Pp]ublish.xml 186 | *.azurePubxml 187 | # Note: Comment the next line if you want to checkin your web deploy settings, 188 | # but database connection strings (with potential passwords) will be unencrypted 189 | *.pubxml 190 | *.publishproj 191 | 192 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 193 | # checkin your Azure Web App publish settings, but sensitive information contained 194 | # in these scripts will be unencrypted 195 | PublishScripts/ 196 | 197 | # NuGet Packages 198 | *.nupkg 199 | # NuGet Symbol Packages 200 | *.snupkg 201 | # The packages folder can be ignored because of Package Restore 202 | **/[Pp]ackages/* 203 | # except build/, which is used as an MSBuild target. 204 | !**/[Pp]ackages/build/ 205 | # Uncomment if necessary however generally it will be regenerated when needed 206 | #!**/[Pp]ackages/repositories.config 207 | # NuGet v3's project.json files produces more ignorable files 208 | *.nuget.props 209 | *.nuget.targets 210 | 211 | # Microsoft Azure Build Output 212 | csx/ 213 | *.build.csdef 214 | 215 | # Microsoft Azure Emulator 216 | ecf/ 217 | rcf/ 218 | 219 | # Windows Store app package directories and files 220 | AppPackages/ 221 | BundleArtifacts/ 222 | Package.StoreAssociation.xml 223 | _pkginfo.txt 224 | *.appx 225 | *.appxbundle 226 | *.appxupload 227 | 228 | # Visual Studio cache files 229 | # files ending in .cache can be ignored 230 | *.[Cc]ache 231 | # but keep track of directories ending in .cache 232 | !?*.[Cc]ache/ 233 | 234 | # Others 235 | ClientBin/ 236 | ~$* 237 | *~ 238 | *.dbmdl 239 | *.dbproj.schemaview 240 | *.jfm 241 | *.pfx 242 | *.publishsettings 243 | orleans.codegen.cs 244 | 245 | # Including strong name files can present a security risk 246 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 247 | #*.snk 248 | 249 | # Since there are multiple workflows, uncomment next line to ignore bower_components 250 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 251 | #bower_components/ 252 | 253 | # RIA/Silverlight projects 254 | Generated_Code/ 255 | 256 | # Backup & report files from converting an old project file 257 | # to a newer Visual Studio version. Backup files are not needed, 258 | # because we have git ;-) 259 | _UpgradeReport_Files/ 260 | Backup*/ 261 | UpgradeLog*.XML 262 | UpgradeLog*.htm 263 | ServiceFabricBackup/ 264 | *.rptproj.bak 265 | 266 | # SQL Server files 267 | *.mdf 268 | *.ldf 269 | *.ndf 270 | 271 | # Business Intelligence projects 272 | *.rdl.data 273 | *.bim.layout 274 | *.bim_*.settings 275 | *.rptproj.rsuser 276 | *- [Bb]ackup.rdl 277 | *- [Bb]ackup ([0-9]).rdl 278 | *- [Bb]ackup ([0-9][0-9]).rdl 279 | 280 | # Microsoft Fakes 281 | FakesAssemblies/ 282 | 283 | # GhostDoc plugin setting file 284 | *.GhostDoc.xml 285 | 286 | # Node.js Tools for Visual Studio 287 | .ntvs_analysis.dat 288 | node_modules/ 289 | 290 | # Visual Studio 6 build log 291 | *.plg 292 | 293 | # Visual Studio 6 workspace options file 294 | *.opt 295 | 296 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 297 | *.vbw 298 | 299 | # Visual Studio 6 auto-generated project file (contains which files were open etc.) 300 | *.vbp 301 | 302 | # Visual Studio 6 workspace and project file (working project files containing files to include in project) 303 | *.dsw 304 | *.dsp 305 | 306 | # Visual Studio 6 technical files 307 | *.ncb 308 | *.aps 309 | 310 | # Visual Studio LightSwitch build output 311 | **/*.HTMLClient/GeneratedArtifacts 312 | **/*.DesktopClient/GeneratedArtifacts 313 | **/*.DesktopClient/ModelManifest.xml 314 | **/*.Server/GeneratedArtifacts 315 | **/*.Server/ModelManifest.xml 316 | _Pvt_Extensions 317 | 318 | # Paket dependency manager 319 | .paket/paket.exe 320 | paket-files/ 321 | 322 | # FAKE - F# Make 323 | .fake/ 324 | 325 | # CodeRush personal settings 326 | .cr/personal 327 | 328 | # Python Tools for Visual Studio (PTVS) 329 | __pycache__/ 330 | *.pyc 331 | 332 | # Cake - Uncomment if you are using it 333 | # tools/** 334 | # !tools/packages.config 335 | 336 | # Tabs Studio 337 | *.tss 338 | 339 | # Telerik's JustMock configuration file 340 | *.jmconfig 341 | 342 | # BizTalk build output 343 | *.btp.cs 344 | *.btm.cs 345 | *.odx.cs 346 | *.xsd.cs 347 | 348 | # OpenCover UI analysis results 349 | OpenCover/ 350 | 351 | # Azure Stream Analytics local run output 352 | ASALocalRun/ 353 | 354 | # MSBuild Binary and Structured Log 355 | *.binlog 356 | 357 | # NVidia Nsight GPU debugger configuration file 358 | *.nvuser 359 | 360 | # MFractors (Xamarin productivity tool) working folder 361 | .mfractor/ 362 | 363 | # Local History for Visual Studio 364 | .localhistory/ 365 | 366 | # Visual Studio History (VSHistory) files 367 | .vshistory/ 368 | 369 | # BeatPulse healthcheck temp database 370 | healthchecksdb 371 | 372 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 373 | MigrationBackup/ 374 | 375 | # Ionide (cross platform F# VS Code tools) working folder 376 | .ionide/ 377 | 378 | # Fody - auto-generated XML schema 379 | FodyWeavers.xsd 380 | 381 | # VS Code files for those working on multiple tools 382 | .vscode/* 383 | !.vscode/settings.json 384 | !.vscode/tasks.json 385 | !.vscode/launch.json 386 | !.vscode/extensions.json 387 | *.code-workspace 388 | 389 | # Local History for Visual Studio Code 390 | .history/ 391 | 392 | # Windows Installer files from build outputs 393 | *.cab 394 | *.msi 395 | *.msix 396 | *.msm 397 | *.msp 398 | 399 | # JetBrains Rider 400 | *.sln.iml 401 | -------------------------------------------------------------------------------- /Lib/Cornelius.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #ifndef EXPORT_API 10 | #define EXPORT_API // Nothing 11 | typedef VOID CORNELIUS_VM; 12 | #endif 13 | 14 | #define __BIT(_Num_) (1ULL << (_Num_)) 15 | 16 | #if !defined(CORNELIUS_HIDE_TYPES) 17 | 18 | #define PAGE_SIZE 4096ULL 19 | #define _4KB PAGE_SIZE 20 | #define _2KB (_4KB / 2) 21 | #define _2MB (512 * PAGE_SIZE) 22 | #define _1GB (512 * _2MB) 23 | 24 | // 25 | // P-SEAMLDR types (pseamldr_api_defs.h) 26 | // 27 | 28 | typedef struct pseamldr_constants_s 29 | { 30 | uint64_t data_stack_size; 31 | uint64_t code_region_size; 32 | uint64_t data_region_size; 33 | uint64_t keyhole_region_size; 34 | uint64_t keyhole_edit_region_size; 35 | uint64_t entry_point_offset; 36 | } pseamldr_constants_t; 37 | 38 | // 39 | // Cornelius types. 40 | // 41 | 42 | typedef struct { 43 | UINT64 Base; 44 | UINT64 Size; 45 | } MEM_RANGE; 46 | 47 | typedef struct { 48 | UINT64 TdvprPa; 49 | } TD_VCPU; 50 | 51 | typedef struct { 52 | UINT64 TdrPa; 53 | UINT16 NumberOfVcpus; 54 | TD_VCPU Vcpus[]; 55 | } TD_VM; 56 | 57 | typedef struct { 58 | UINT32 NumberOfVcpus; 59 | 60 | PUINT8 PSeamldrElfBytes; 61 | SIZE_T PSeamldrElfSize; 62 | 63 | UINT64 SeamrrBase; 64 | SIZE_T SeamrrSize; 65 | 66 | MEM_RANGE PSeamldrRange; // P-SEAMLDR range, within SEAMRR 67 | UINT64 DataRegionSize; 68 | UINT64 KeyholeRegionSize; 69 | UINT64 KeyholeEditRegionSize; 70 | UINT64 StackRegionSize; // Includes the shadow 71 | UINT64 EntryPointOffset; 72 | 73 | SIZE_T SeamdbSize; 74 | 75 | #define TDX_PRIV_HKID(_Vm_, _Num_) ((1ULL << (_Vm_)->VmConfig.KeyidBits) - (_Vm_)->VmConfig.NumPrivKeyids + 1 + (_Num_)) 76 | UINT8 KeyidBits; 77 | UINT32 NumPrivKeyids; 78 | 79 | UINT64 SmrrBase; 80 | UINT64 SmrrMask; 81 | 82 | #define NUM_CMRS 32 83 | SIZE_T NumberOfCmrs; 84 | MEM_RANGE Cmrs[NUM_CMRS]; 85 | 86 | UINT64 LastPa; 87 | 88 | BOOLEAN HasSanitizers; 89 | } CORNELIUS_VM_CONFIG; 90 | 91 | typedef struct { 92 | // 93 | // There are four types of registers here: 94 | // 95 | // - The real registers (RR) that get installed on the VCPU. 96 | // - The virtual registers (VR) that the P-SEAMLDR/TDX-MODULE can read 97 | // via VMREAD/RDMSR and write via VMWRITE/WRMSR. 98 | // - The read-only registers (RO) that the P-SEAMLDR/TDX-MODULE can only 99 | // read via VMREAD. 100 | // - The persistent registers (PR) that persist across VMM, P-SEAMLDR 101 | // and TDX-MODULE. 102 | // 103 | 104 | // VMX 105 | UINT64 ExitReason; // RO 106 | UINT64 InstructionLength; // RO 107 | UINT64 GuestInterruptibility; // VR 108 | UINT64 PendingDebugException; // VR 109 | // CRs 110 | UINT64 Cr0; 111 | UINT64 Cr3; 112 | UINT64 Cr4; 113 | // MSRs 114 | UINT64 MiscEnable; // PR 115 | UINT64 DebugCtlMsr; // VR 116 | UINT64 Pat; // VR 117 | UINT64 Efer; // VR 118 | UINT64 PerfGlobalCtrl; // VR 119 | UINT64 PmcFx0Ctr; // VR 120 | UINT64 SysenterEsp; // VR 121 | UINT64 SysenterEip; // VR 122 | UINT64 SysenterCs; // VR 123 | UINT64 Star; // RR 124 | UINT64 Lstar; // RR 125 | UINT64 Fmask; // RR 126 | UINT64 KernelGsBase; // RR 127 | UINT64 Pl0Ssp; // RR 128 | UINT64 Pl1Ssp; // RR 129 | UINT64 Pl2Ssp; // RR 130 | UINT64 Pl3Ssp; // RR 131 | UINT64 DsArea; // VR 132 | UINT64 NonFaultingMsr; // VR 133 | UINT64 TscAux; // VR -- could be made RR as the Vp reg exists 134 | UINT64 Xss; // RR 135 | // GPRs 136 | UINT64 Rax; 137 | UINT64 Rcx; 138 | UINT64 Rdx; 139 | UINT64 Rbx; 140 | UINT64 Rsp; // VR 141 | UINT64 Rbp; 142 | UINT64 Rsi; 143 | UINT64 Rdi; 144 | UINT64 R8; 145 | UINT64 R9; 146 | UINT64 R10; 147 | UINT64 R11; 148 | UINT64 R12; 149 | UINT64 R13; 150 | UINT64 R14; 151 | UINT64 R15; 152 | UINT64 Rip; // VR 153 | UINT64 Rflags; // VR 154 | UINT64 Ssp; // VR 155 | // DRs 156 | UINT64 Dr7; // VR 157 | // Segments 158 | WHV_X64_SEGMENT_REGISTER Cs; // VR 159 | // XMMs 160 | WHV_UINT128 Xmm0; 161 | WHV_UINT128 Xmm1; 162 | WHV_UINT128 Xmm2; 163 | WHV_UINT128 Xmm3; 164 | WHV_UINT128 Xmm4; 165 | WHV_UINT128 Xmm5; 166 | WHV_UINT128 Xmm6; 167 | WHV_UINT128 Xmm7; 168 | WHV_UINT128 Xmm8; 169 | WHV_UINT128 Xmm9; 170 | WHV_UINT128 Xmm10; 171 | WHV_UINT128 Xmm11; 172 | WHV_UINT128 Xmm12; 173 | WHV_UINT128 Xmm13; 174 | WHV_UINT128 Xmm14; 175 | WHV_UINT128 Xmm15; 176 | // XSAVE 177 | UINT64 Xcr0; // RR 178 | } VCPU_STATE; 179 | 180 | typedef struct { 181 | uint64_t NumberOfHits; 182 | uint64_t Reserved[7]; 183 | uint8_t Bitmap[]; 184 | } SANCOV_BITMAP; 185 | 186 | C_ASSERT(sizeof(SANCOV_BITMAP) == 64); 187 | 188 | #include "IntelDefs/pseamldr-defs.h" 189 | #include "IntelDefs/tdx-defs.h" 190 | #include "x86-defs.h" 191 | 192 | #endif // !defined(CORNELIUS_HIDE_TYPES) 193 | 194 | #if !defined(CORNELIUS_HIDE_PROTOTYPES) 195 | 196 | // 197 | // commands.c 198 | // 199 | 200 | EXPORT_API UINT64 SeamcallPseamldr_Info(CORNELIUS_VM *Vm, UINT32 VcpuNum, UINT64 Gpa, seamldr_info_t *PseamldrInfo); 201 | EXPORT_API UINT64 SeamcallPseamldr_Install(CORNELIUS_VM *Vm, UINT32 VcpuNum, PUINT8 TdxBuffer, SIZE_T TdxSize); 202 | // BOOLEAN SeamcallTdx_TdhSysInfo(CORNELIUS_VM *Vm, UINT32 VcpuNum); 203 | EXPORT_API UINT64 SeamcallTdx_TdhSysInit(CORNELIUS_VM *Vm, UINT32 VcpuNum); 204 | EXPORT_API UINT64 SeamcallTdx_TdhSysLpInit(CORNELIUS_VM *Vm, UINT32 VcpuNum); 205 | EXPORT_API UINT64 SeamcallTdx_TdhSysConfig(CORNELIUS_VM *Vm, UINT32 VcpuNum); 206 | EXPORT_API UINT64 SeamcallTdx_TdhSysKeyConfig(CORNELIUS_VM *Vm, UINT32 VcpuNum); 207 | EXPORT_API UINT64 SeamcallTdx_TdhSysTdmrInit(CORNELIUS_VM *Vm, UINT32 VcpuNum); 208 | EXPORT_API UINT64 SeamcallTdx_TdhMngCreate(CORNELIUS_VM *Vm, UINT32 VcpuNum, TD_VM *TdVm); 209 | EXPORT_API UINT64 SeamcallTdx_TdhMngKeyConfig(CORNELIUS_VM *Vm, UINT32 VcpuNum, TD_VM *TdVm); 210 | EXPORT_API UINT64 SeamcallTdx_TdhMngAddcx(CORNELIUS_VM *Vm, UINT32 VcpuNum, TD_VM *TdVm); 211 | EXPORT_API UINT64 SeamcallTdx_TdhMngInit(CORNELIUS_VM *Vm, UINT32 VcpuNum, TD_VM *TdVm); 212 | EXPORT_API UINT64 SeamcallTdx_TdhVpCreate(CORNELIUS_VM *Vm, UINT32 VcpuNum, TD_VM *TdVm, UINT32 TdVcpu); 213 | EXPORT_API UINT64 SeamcallTdx_TdhVpAddcx(CORNELIUS_VM *Vm, UINT32 VcpuNum, TD_VM *TdVm, UINT32 TdVcpu); 214 | EXPORT_API UINT64 SeamcallTdx_TdhVpInit(CORNELIUS_VM *Vm, UINT32 VcpuNum, TD_VM *TdVm, UINT32 TdVcpu); 215 | EXPORT_API UINT64 SeamcallTdx_TdhVpWr(CORNELIUS_VM *Vm, UINT32 VcpuNum, TD_VM *TdVm, UINT32 TdVcpu, md_field_id_t Identifier, UINT64 Value, UINT64 Mask); 216 | EXPORT_API UINT64 SeamcallTdx_TdhVpRd(CORNELIUS_VM *Vm, UINT32 VcpuNum, TD_VM *TdVm, UINT32 TdVcpu, md_field_id_t Identifier, UINT64 *Value); 217 | EXPORT_API UINT64 SeamcallTdx_TdhVpEnter(CORNELIUS_VM *Vm, UINT32 VcpuNum, TD_VM *TdVm, UINT32 TdVcpu); 218 | EXPORT_API UINT64 SeamcallTdx_TdhMrFinalize(CORNELIUS_VM *Vm, UINT32 VcpuNum, TD_VM *TdVm); 219 | EXPORT_API UINT64 SeamcallTdx_TdhMemSeptAdd(CORNELIUS_VM* Vm, UINT32 VcpuNum, TD_VM* TdVm, UINT64 Pa, UINT64 Gpa, UINT8 Level); 220 | EXPORT_API UINT64 SeamcallTdx_TdhMemPageAug(CORNELIUS_VM* Vm, UINT32 VcpuNum, TD_VM* TdVm, UINT64 Pa, UINT64 Gpa, UINT8 Level); 221 | EXPORT_API UINT64 Tdcall_TdgMemPageAccept(CORNELIUS_VM* Vm, UINT32 VcpuNum, UINT64 Gpa, UINT8 Level); 222 | EXPORT_API VOID Tdcall_TdgVpVmcall(CORNELIUS_VM* Vm, UINT32 VcpuNum, UINT64 Control); 223 | 224 | // 225 | // paging.c 226 | // 227 | 228 | EXPORT_API BOOLEAN PaToHva(CORNELIUS_VM *Vm, UINT64 Pa, PVOID *Hva); 229 | 230 | // 231 | // sanitizers.c 232 | // 233 | 234 | EXPORT_API BOOLEAN HasPseamldrSanitizers(CORNELIUS_VM *Vm); 235 | EXPORT_API BOOLEAN HasTdxModuleSanitizers(CORNELIUS_VM *Vm); 236 | EXPORT_API SIZE_T GetSancovBitmapSize(CORNELIUS_VM *Vm); 237 | EXPORT_API SANCOV_BITMAP *GetSancovPseamldrBitmap(CORNELIUS_VM *Vm); 238 | EXPORT_API SANCOV_BITMAP *GetSancovTdxModuleBitmap(CORNELIUS_VM *Vm, UINT32 VcpuNum); 239 | EXPORT_API VOID MarkSancovBitmapsNotDirty(CORNELIUS_VM *Vm); 240 | 241 | // 242 | // seam.c 243 | // 244 | 245 | EXPORT_API VCPU_STATE *GetVcpuState(CORNELIUS_VM *Vm, UINT32 VcpuNum); 246 | EXPORT_API UINT64 AllocatePaFromCmrsAvail(CORNELIUS_VM *Vm); 247 | EXPORT_API TD_VM *CreateTdVm(CORNELIUS_VM *Vm, UINT16 NumberOfVcpus); 248 | 249 | // 250 | // snapshot.c 251 | // 252 | 253 | EXPORT_API VOID *CreateSnapshot(CORNELIUS_VM *Vm); 254 | EXPORT_API VOID RestoreSnapshot(CORNELIUS_VM *Vm, VOID *Snapshot); 255 | 256 | // 257 | // vm.c 258 | // 259 | 260 | enum VcpuAction { 261 | VcpuActionKeepRunning, 262 | VcpuActionEmulationError, 263 | VcpuActionInvariantViolated, 264 | VcpuActionSeamPanic, 265 | VcpuActionSeamCrash, 266 | VcpuActionSeamRet, 267 | VcpuActionVmlaunch, 268 | VcpuActionVmresume, 269 | VcpuActionSeamNotReady 270 | }; 271 | 272 | enum VcpuMode { 273 | VcpuModePseamldr, 274 | VcpuModeTdxModule, 275 | VcpuModeTdGuest 276 | }; 277 | 278 | EXPORT_API VOID MapGpa(CORNELIUS_VM *Vm, UINT64 Gpa, SIZE_T Size); 279 | EXPORT_API VOID UnmapGpa(CORNELIUS_VM *Vm, UINT64 Gpa, SIZE_T Size); 280 | EXPORT_API CORNELIUS_VM *CreateVM(CORNELIUS_VM_CONFIG *VmConfig); 281 | EXPORT_API INT GetVcpuLogLevel(CORNELIUS_VM *Vm, UINT32 VcpuNum); 282 | EXPORT_API VOID SetVcpuLogLevel(CORNELIUS_VM *Vm, UINT32 VcpuNum, INT LogLevel); 283 | EXPORT_API UINT32 GetNumberOfVcpus(CORNELIUS_VM *Vm); 284 | EXPORT_API enum VcpuAction RunVCPU(CORNELIUS_VM *Vm, UINT32 VcpuNum, enum VcpuMode VcpuMode); 285 | 286 | #endif // !defined(CORNELIUS_HIDE_PROTOTYPES) -------------------------------------------------------------------------------- /Lib/sanitizers.c: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | #include 5 | #include 6 | #include 7 | #include "common.h" 8 | 9 | BOOLEAN 10 | HasPseamldrSanitizers(CORNELIUS_VM *Vm) 11 | { 12 | return Vm->VmConfig.HasSanitizers; 13 | } 14 | 15 | BOOLEAN 16 | HasTdxModuleSanitizers(CORNELIUS_VM *Vm) 17 | { 18 | return (Vm->TdxModuleSancovParams.BitmapsHva != NULL); 19 | } 20 | 21 | // -------------------------------------------------------------------------- 22 | 23 | #define ASAN_SHADOW_BASE 0xFFFF900000000000ULL 24 | 25 | typedef struct { 26 | void *Address; 27 | size_t AccessSize; 28 | bool IsWrite; 29 | uintptr_t Pc; 30 | uint8_t Code; 31 | } ASAN_REPORT; 32 | 33 | static UINT64 34 | AsanAddressToShadow(UINT64 Address) 35 | { 36 | return ASAN_SHADOW_BASE + ((Address - SEAM_VA_BASE) >> 3); 37 | } 38 | 39 | VOID 40 | InitializeAsan(CORNELIUS_VM *Vm) 41 | { 42 | UINT64 AsanShadowPa; 43 | PVOID AsanShadowHva; 44 | UINT64 AsanShadowVaStart; 45 | UINT64 AsanShadowVaEnd; 46 | SIZE_T AsanShadowSize; 47 | 48 | AsanShadowPa = Vm->HiddenPaCursor; 49 | 50 | AsanShadowVaStart = AsanAddressToShadow(Vm->PSysInfoTable->StackRgn.Base); 51 | AsanShadowVaEnd = AsanAddressToShadow(Vm->PSysInfoTable->StackRgn.Base + Vm->PSysInfoTable->StackRgn.Size); 52 | 53 | AsanShadowVaStart = ALIGN_DOWN_BY(AsanShadowVaStart, PAGE_SIZE); 54 | AsanShadowVaEnd = ALIGN_UP_BY(AsanShadowVaEnd, PAGE_SIZE); 55 | 56 | AsanShadowSize = AsanShadowVaEnd - AsanShadowVaStart; 57 | 58 | if (AsanShadowPa + AsanShadowSize > CORNELIUS_KEYSPACE_SIZE) { 59 | FATAL("not enough space for the ASAN shadow"); 60 | } 61 | 62 | if (!MapRange(Vm, AsanShadowVaStart, AsanShadowPa, AsanShadowSize, MapTypeData)) { 63 | FATAL("failed to map the ASAN shadow"); 64 | } 65 | 66 | AsanShadowHva = GPA_TO_HVA(Vm, AsanShadowPa); 67 | memset(AsanShadowHva, 0, AsanShadowSize); 68 | 69 | MapGpa(Vm, AsanShadowPa, AsanShadowSize); 70 | 71 | Vm->PSysInfoTable->CorneliusSpecific.AsanCoveredStart = Vm->PSysInfoTable->StackRgn.Base; 72 | Vm->PSysInfoTable->CorneliusSpecific.AsanCoveredEnd = Vm->PSysInfoTable->StackRgn.Base + Vm->PSysInfoTable->StackRgn.Size; 73 | 74 | Vm->HiddenPaCursor += AsanShadowSize; 75 | return; 76 | } 77 | 78 | enum VcpuAction 79 | MsrAsanReport(CORNELIUS_VM *Vm, UINT32 VcpuNum, UINT64 ReportAddr) 80 | { 81 | ASAN_REPORT *Report; 82 | 83 | Report = (ASAN_REPORT *)GvaToHva(Vm, VcpuNum, ReportAddr); 84 | 85 | LogVcpuErr(Vm, VcpuNum, "ASAN: illegal %s access of %zu byte%s at RIP=0x%llx\n", 86 | Report->IsWrite ? "write" : "read", 87 | Report->AccessSize, 88 | (Report->AccessSize != 1) ? "s" : "", 89 | Report->Pc); 90 | 91 | return VcpuActionSeamCrash; 92 | } 93 | 94 | // -------------------------------------------------------------------------- 95 | 96 | #define UBSAN_TYPE_OVERFLOW 1 97 | #define UBSAN_TYPE_ALIGNMENT 2 98 | #define UBSAN_TYPE_UNREACHABLE 3 99 | #define UBSAN_TYPE_CFI 4 100 | #define UBSAN_TYPE_CACHEMISS 5 101 | #define UBSAN_TYPE_FLOATCASTOVERFLOW 6 102 | #define UBSAN_TYPE_FUNCTIONTYPEMISMATCH 7 103 | #define UBSAN_TYPE_INVALID_BUILTIN 8 104 | #define UBSAN_TYPE_LOAD_INVALID 9 105 | #define UBSAN_TYPE_NONNULL_ARG 10 106 | #define UBSAN_TYPE_NONNULL_RETURN 11 107 | #define UBSAN_TYPE_OOB_DATA 12 108 | #define UBSAN_TYPE_PTR_OVERFLOW 13 109 | #define UBSAN_TYPE_SHIFT_OOB 14 110 | #define UBSAN_TYPE_TYPE_MISMATCH 15 111 | #define UBSAN_TYPE_VLA_BOUND_NOT_POSITIVE 16 112 | #define UBSAN_TYPE_IMPLICIT_CONVERSION 17 113 | 114 | typedef struct { 115 | uint32_t Type; 116 | void *Data; 117 | } UBSAN_REPORT; 118 | 119 | struct CSourceLocation { 120 | char *mFilename; 121 | uint32_t mLine; 122 | uint32_t mColumn; 123 | }; 124 | 125 | struct CTypeDescriptor { 126 | uint16_t mTypeKind; 127 | uint16_t mTypeInfo; 128 | uint8_t mTypeName[1]; 129 | }; 130 | 131 | struct COverflowData { 132 | struct CSourceLocation mLocation; 133 | struct CTypeDescriptor *mType; 134 | }; 135 | 136 | struct CUnreachableData { 137 | struct CSourceLocation mLocation; 138 | }; 139 | 140 | struct CCFICheckFailData { 141 | uint8_t mCheckKind; 142 | struct CSourceLocation mLocation; 143 | struct CTypeDescriptor *mType; 144 | }; 145 | 146 | struct CDynamicTypeCacheMissData { 147 | struct CSourceLocation mLocation; 148 | struct CTypeDescriptor *mType; 149 | void *mTypeInfo; 150 | uint8_t mTypeCheckKind; 151 | }; 152 | 153 | struct CFunctionTypeMismatchData { 154 | struct CSourceLocation mLocation; 155 | struct CTypeDescriptor *mType; 156 | }; 157 | 158 | struct CInvalidBuiltinData { 159 | struct CSourceLocation mLocation; 160 | uint8_t mKind; 161 | }; 162 | 163 | struct CInvalidValueData { 164 | struct CSourceLocation mLocation; 165 | struct CTypeDescriptor *mType; 166 | }; 167 | 168 | struct CNonNullArgData { 169 | struct CSourceLocation mLocation; 170 | struct CSourceLocation mAttributeLocation; 171 | int mArgIndex; 172 | }; 173 | 174 | struct CNonNullReturnData { 175 | struct CSourceLocation mAttributeLocation; 176 | }; 177 | 178 | struct COutOfBoundsData { 179 | struct CSourceLocation mLocation; 180 | struct CTypeDescriptor *mArrayType; 181 | struct CTypeDescriptor *mIndexType; 182 | }; 183 | 184 | struct CPointerOverflowData { 185 | struct CSourceLocation mLocation; 186 | }; 187 | 188 | struct CShiftOutOfBoundsData { 189 | struct CSourceLocation mLocation; 190 | struct CTypeDescriptor *mLHSType; 191 | struct CTypeDescriptor *mRHSType; 192 | }; 193 | 194 | struct CTypeMismatchData { 195 | struct CSourceLocation mLocation; 196 | struct CTypeDescriptor *mType; 197 | unsigned long mLogAlignment; 198 | uint8_t mTypeCheckKind; 199 | }; 200 | 201 | struct CTypeMismatchData_v1 { 202 | struct CSourceLocation mLocation; 203 | struct CTypeDescriptor *mType; 204 | uint8_t mLogAlignment; 205 | uint8_t mTypeCheckKind; 206 | }; 207 | 208 | struct CVLABoundData { 209 | struct CSourceLocation mLocation; 210 | struct CTypeDescriptor *mType; 211 | }; 212 | 213 | struct CFloatCastOverflowData { 214 | struct CSourceLocation mLocation; 215 | struct CTypeDescriptor *mFromType; 216 | struct CTypeDescriptor *mToType; 217 | }; 218 | 219 | struct CImplicitConversionData { 220 | struct CSourceLocation mLocation; 221 | struct CTypeDescriptor *mFromType; 222 | struct CTypeDescriptor *mToType; 223 | uint8_t mKind; 224 | }; 225 | 226 | struct CAlignmentAssumptionData { 227 | struct CSourceLocation mLocation; 228 | struct CSourceLocation mAssumptionLocation; 229 | struct CTypeDescriptor *mType; 230 | }; 231 | 232 | enum VcpuAction 233 | MsrUbsanReport(CORNELIUS_VM *Vm, UINT32 VcpuNum, UINT64 ReportAddr) 234 | { 235 | struct CSourceLocation *Location; 236 | UBSAN_REPORT *Report; 237 | CHAR *FileName; 238 | 239 | Report = (UBSAN_REPORT *)GvaToHva(Vm, VcpuNum, ReportAddr); 240 | Location = (struct CSourceLocation *)GvaToHva(Vm, VcpuNum, (uint64_t)Report->Data); 241 | FileName = (CHAR *)GvaToHva(Vm, VcpuNum, (uint64_t)Location->mFilename); 242 | 243 | switch (Report->Type) { 244 | case UBSAN_TYPE_OVERFLOW: 245 | case UBSAN_TYPE_ALIGNMENT: 246 | case UBSAN_TYPE_UNREACHABLE: 247 | case UBSAN_TYPE_CFI: 248 | case UBSAN_TYPE_CACHEMISS: 249 | case UBSAN_TYPE_FLOATCASTOVERFLOW: 250 | case UBSAN_TYPE_FUNCTIONTYPEMISMATCH: 251 | case UBSAN_TYPE_INVALID_BUILTIN: 252 | case UBSAN_TYPE_LOAD_INVALID: 253 | case UBSAN_TYPE_NONNULL_ARG: 254 | case UBSAN_TYPE_NONNULL_RETURN: 255 | case UBSAN_TYPE_OOB_DATA: 256 | case UBSAN_TYPE_PTR_OVERFLOW: 257 | case UBSAN_TYPE_SHIFT_OOB: 258 | LogVcpuErr(Vm, VcpuNum, "UBSAN: unknown undefined behavior, %s:%u\n", 259 | FileName, Location->mLine); 260 | break; 261 | 262 | case UBSAN_TYPE_TYPE_MISMATCH: 263 | LogVcpuErr(Vm, VcpuNum, "UBSAN: type mismatch, %s:%u\n", 264 | FileName, Location->mLine); 265 | break; 266 | 267 | case UBSAN_TYPE_VLA_BOUND_NOT_POSITIVE: 268 | case UBSAN_TYPE_IMPLICIT_CONVERSION: 269 | default: 270 | LogVcpuErr(Vm, VcpuNum, "UBSAN: unknown undefined behavior at RIP=0x%llx\n", 271 | GetRegister64(Vm, VcpuNum, WHvX64RegisterRip)); 272 | break; 273 | } 274 | 275 | return VcpuActionKeepRunning; 276 | } 277 | 278 | // -------------------------------------------------------------------------- 279 | 280 | #define SANCOV_BITMAP_BASE 0xFFFFA00000000000ULL 281 | 282 | VOID 283 | InitializeSancov(CORNELIUS_VM *Vm) 284 | { 285 | UINT64 SancovBitmapPa; 286 | UINT64 SancovBitmapVaStart; 287 | UINT64 SancovBitmapVaEnd; 288 | SIZE_T SancovBitmapSize; 289 | 290 | SancovBitmapPa = Vm->HiddenPaCursor; 291 | 292 | SancovBitmapVaStart = SANCOV_BITMAP_BASE; 293 | SancovBitmapVaEnd = SancovBitmapVaStart + (Vm->PSysInfoTable->CodeRgn.Size / 8); 294 | 295 | SancovBitmapVaStart = ALIGN_DOWN_BY(SancovBitmapVaStart, PAGE_SIZE); 296 | SancovBitmapVaEnd = ALIGN_UP_BY(SancovBitmapVaEnd, PAGE_SIZE); 297 | 298 | SancovBitmapSize = SancovBitmapVaEnd - SancovBitmapVaStart; 299 | 300 | if (SancovBitmapPa + SancovBitmapSize > CORNELIUS_KEYSPACE_SIZE) { 301 | FATAL("not enough space for the ASAN shadow"); 302 | } 303 | 304 | if (!MapRange(Vm, SancovBitmapVaStart, SancovBitmapPa, SancovBitmapSize, MapTypeData)) { 305 | FATAL("failed to map the ASAN shadow"); 306 | } 307 | 308 | Vm->PseamldrSancovBitmapHva = GPA_TO_HVA(Vm, SancovBitmapPa); 309 | memset(Vm->PseamldrSancovBitmapHva, 0, SancovBitmapSize); 310 | 311 | MapGpa(Vm, SancovBitmapPa, SancovBitmapSize); 312 | 313 | Vm->PSysInfoTable->CorneliusSpecific.SancovCoveredStart = Vm->PSysInfoTable->CodeRgn.Base; 314 | Vm->PSysInfoTable->CorneliusSpecific.SancovCoveredEnd = Vm->PSysInfoTable->CodeRgn.Base + Vm->PSysInfoTable->CodeRgn.Size; 315 | 316 | Vm->HiddenPaCursor += SancovBitmapSize; 317 | return; 318 | } 319 | 320 | enum VcpuAction 321 | MsrSancovParams(CORNELIUS_VM *Vm, UINT32 VcpuNum, UINT64 ParamsAddr) 322 | { 323 | SANCOV_PARAMS *SancovParams; 324 | 325 | SancovParams = (SANCOV_PARAMS *)GvaToHva(Vm, VcpuNum, ParamsAddr); 326 | 327 | Vm->TdxModuleSancovParams.BitmapsGpa = SancovParams->BitmapsGpa; 328 | Vm->TdxModuleSancovParams.BitmapsHva = GPA_TO_HVA(Vm, SancovParams->BitmapsGpa); 329 | Vm->TdxModuleSancovParams.BitmapSize = SancovParams->BitmapSize; 330 | 331 | return VcpuActionKeepRunning; 332 | } 333 | 334 | SIZE_T 335 | GetSancovMaxBitmapSize(CORNELIUS_VM *Vm) 336 | { 337 | return sizeof(SANCOV_BITMAP) + (Vm->VmConfig.PSeamldrRange.Size / 8); 338 | } 339 | 340 | SIZE_T 341 | GetSancovBitmapSize(CORNELIUS_VM *Vm) 342 | { 343 | return Vm->TdxModuleSancovParams.BitmapSize; 344 | } 345 | 346 | SANCOV_BITMAP * 347 | GetSancovPseamldrBitmap(CORNELIUS_VM *Vm) 348 | { 349 | return (SANCOV_BITMAP *)Vm->PseamldrSancovBitmapHva; 350 | } 351 | 352 | SANCOV_BITMAP * 353 | GetSancovTdxModuleBitmap(CORNELIUS_VM *Vm, UINT32 VcpuNum) 354 | { 355 | return (SANCOV_BITMAP *)(Vm->TdxModuleSancovParams.BitmapsHva + VcpuNum * Vm->TdxModuleSancovParams.BitmapSize); 356 | } 357 | 358 | VOID 359 | MarkSancovBitmapsNotDirty(CORNELIUS_VM *Vm) 360 | { 361 | // 362 | // Mark the Sancov bitmaps as NotDirty, to exclude them from the snapshots. 363 | // 364 | 365 | MarkGpaNotDirty(Vm, Vm->TdxModuleSancovParams.BitmapsGpa, Vm->NumberOfVcpus * Vm->TdxModuleSancovParams.BitmapSize); 366 | } -------------------------------------------------------------------------------- /Lib/common.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #define PACKED 11 | #define bool_t bool 12 | 13 | #define PAGE_SIZE 4096ULL 14 | #define _4KB PAGE_SIZE 15 | #define _2KB (_4KB / 2) 16 | #define _2MB (512 * PAGE_SIZE) 17 | #define _1GB (512 * _2MB) 18 | 19 | #include "IntelDefs/pseamldr-defs.h" 20 | #include "IntelDefs/tdx-defs.h" 21 | #include "x86-defs.h" 22 | 23 | #define ALIGN_DOWN_BY(length, alignment) \ 24 | ((ULONG_PTR)(length) & ~((ULONG_PTR)(alignment) - 1)) 25 | 26 | #define ALIGN_UP_BY(length, alignment) \ 27 | (ALIGN_DOWN_BY(((ULONG_PTR)(length) + (alignment) - 1), alignment)) 28 | 29 | #define ALIGN_UP_POW2(_Value_) pow(2, ceil(log(_Value_)/log(2))) 30 | 31 | #define SEAMRR_SIZE_TO_MASK(size) ((size) / (1 << 25ULL)) 32 | 33 | // 34 | // HV-DISCREPANCY: WHP doesn't have an interface to forward _all_ MSRs to us, 35 | // so we OR the MSR numbers with a magic in the higher 32 bits, and unmask it 36 | // here. 37 | // 38 | #define REAL_MSR_NUMBER(_Msr_) ((_Msr_) & ~0x0ABC0000) 39 | 40 | #define EXPORT_API __declspec(dllexport) 41 | 42 | // -------------------------------------------------------------------------- 43 | 44 | #define C_KEYHOLE_EDIT_REGION_BASE 0x0000000100000000 45 | #define C_MODULE_RGN_BASE 0x0000000200000000 46 | #define C_CODE_RGN_BASE 0xFFFF800000000000 47 | #define C_STACK_RGN_BASE 0xFFFF800100000000 48 | #define C_KEYHOLE_RGN_BASE 0xFFFF800200000000 49 | #define C_DATA_RGN_BASE 0xFFFF800300000000 50 | #define C_SYS_INFO_TABLE_BASE 0xFFFF8003FFFF0000 51 | 52 | #define P_SYS_INFO_TABLE_VERSION 0 53 | 54 | #define SYS_INFO_TABLE_SOCKET_CPUID_TABLE_SIZE 8 55 | #define SYS_INFO_TABLE_NUM_CMRS 32 56 | 57 | #define CORNELIUS_HIDE_PROTOTYPES 58 | #include "Cornelius.h" 59 | #undef CORNELIUS_HIDE_PROTOTYPES 60 | 61 | C_ASSERT(NUM_CMRS == SYS_INFO_TABLE_NUM_CMRS); 62 | 63 | typedef struct { 64 | // fields populated by mcheck 65 | UINT64 Version; 66 | UINT32 TotNumLps; 67 | UINT32 TotNumSockets; 68 | UINT32 SocketCpuidTable[SYS_INFO_TABLE_SOCKET_CPUID_TABLE_SIZE]; 69 | MEM_RANGE PSeamldrRange; 70 | UINT8 SkipSMRR2Check; 71 | UINT8 TDX_AC; 72 | UINT8 Reserved_0[62]; 73 | MEM_RANGE Cmr[SYS_INFO_TABLE_NUM_CMRS]; 74 | UINT8 Reserved_1[1408]; 75 | // fields populated by NP-SEAMLDR 76 | UINT64 NpSeamldrMutex; 77 | MEM_RANGE CodeRgn; 78 | MEM_RANGE DataRgn; 79 | MEM_RANGE StackRgn; 80 | MEM_RANGE KeyholeRgn; 81 | MEM_RANGE KeyholeEditRgn; 82 | UINT64 ModuleRgnBase; 83 | UINT32 AcmX2ApicId; 84 | UINT32 AcmX2ApicIdValid; 85 | 86 | UINT8 Reserved2[1944 - 4 * sizeof(UINT64)]; 87 | struct { 88 | UINT64 SancovCoveredStart; 89 | UINT64 SancovCoveredEnd; 90 | UINT64 AsanCoveredStart; 91 | UINT64 AsanCoveredEnd; 92 | } CorneliusSpecific; 93 | } P_SYS_INFO_TABLE_t; 94 | C_ASSERT(sizeof(P_SYS_INFO_TABLE_t) == 4096); 95 | 96 | // -------------------------------------------------------------------------- 97 | 98 | #define SEAM_VA_BASE 0xFFFF800000000000ULL 99 | 100 | #define MSR_SANCOV_PARAMS 0xAAA1 101 | #define MSR_ASAN_REPORT 0xAAA2 102 | #define MSR_UBSAN_REPORT 0xAAA3 103 | 104 | #define MSR_SEAMVM_DEBUG 0xBBBB0001ULL 105 | 106 | #define CORNELIUS_KEYSPACE_SHIFT 30 107 | #define CORNELIUS_KEYSPACE_SIZE (1ULL << CORNELIUS_KEYSPACE_SHIFT) 108 | 109 | #define GPA_WITHOUT_HKID(_Gpa_) ((_Gpa_) & (CORNELIUS_KEYSPACE_SIZE - 1)) 110 | #define HKID_FROM_GPA(_Gpa_) ((UINT16)((_Gpa_) >> CORNELIUS_KEYSPACE_SHIFT)) 111 | 112 | #define GPA_WITHOUT_REAL_HKID(_Vm_, _Gpa_) ((UINT64)((_Gpa_) & ((1ULL << (52 - (_Vm_)->VmConfig.KeyidBits)) - 1))) 113 | #define REAL_HKID_FROM_GPA(_Vm_, _Gpa_) ((UINT16)((_Gpa_) >> (52 - (_Vm_)->VmConfig.KeyidBits))) 114 | 115 | #define GPAS_BITMAP_SIZE(_Vm_) ALIGN_UP_BY(((_Vm_)->LastPa) / PAGE_SIZE / 8, sizeof(UINT64)) 116 | 117 | #define NUM_TD_VMCS_FIELDS 180 118 | 119 | typedef struct { 120 | UINT64 Revision; 121 | BOOLEAN CachedOnCpu; 122 | UINT64 Fields[NUM_TD_VMCS_FIELDS]; 123 | } TD_VMCS; 124 | 125 | C_ASSERT(sizeof(TD_VMCS) <= PAGE_SIZE); 126 | 127 | typedef struct { 128 | UINT64 VmcsPtr; 129 | #define SEAM_STATE_CR0 0 130 | #define SEAM_STATE_CR3 1 131 | #define SEAM_STATE_CR4 2 132 | #define SEAM_STATE_ES 3 133 | #define SEAM_STATE_CS 4 134 | #define SEAM_STATE_SS 5 135 | #define SEAM_STATE_DS 6 136 | #define SEAM_STATE_FS 7 137 | #define SEAM_STATE_GS 8 138 | #define SEAM_STATE_TR 9 139 | #define SEAM_STATE_IDTR 10 140 | #define SEAM_STATE_GDTR 11 141 | #define SEAM_STATE_PAT 12 142 | #define SEAM_STATE_SCET 13 143 | #define SEAM_STATE_EFER 14 144 | #define SEAM_STATE_RIP 15 145 | #define SEAM_STATE_RSP 16 146 | #define SEAM_STATE_SSP 17 147 | #define SEAM_STATE_RFLAGS 18 148 | #define NUM_SEAM_REGS 19 149 | WHV_REGISTER_NAME RegisterNames[NUM_SEAM_REGS]; 150 | WHV_REGISTER_VALUE RegisterValues[NUM_SEAM_REGS]; 151 | } SEAM_STATE; 152 | 153 | typedef struct { 154 | uint64_t BitmapsGpa; 155 | uint64_t BitmapSize; 156 | } SANCOV_PARAMS; 157 | 158 | #define MAX_LOG_CHACHE_SIZE 0x100 159 | 160 | typedef struct { 161 | UINT32 Cursor; 162 | CHAR Buffer[MAX_LOG_CHACHE_SIZE + 1]; 163 | } DBG_LOG_BUFFER; 164 | 165 | #define VMCS_CACHE_SIZE 4 166 | 167 | typedef struct { 168 | VCPU_STATE VcpuState; 169 | SEAM_STATE TdxState; 170 | BOOLEAN HasPendingException; 171 | WHV_EXCEPTION_TYPE PendingExceptionType; 172 | BOOLEAN IsSeamldr; 173 | INT LogLevel; 174 | DBG_LOG_BUFFER DbgLogBuffer; 175 | UINT64 VmcsCache[VMCS_CACHE_SIZE]; 176 | } CORNELIUS_VCPU; 177 | 178 | typedef struct { 179 | WHV_PARTITION_HANDLE Partition; 180 | HANDLE PseamldrLock; 181 | 182 | struct { 183 | UINT32 PerfMon:1; 184 | UINT32 Rsvd:31; 185 | } CpuSupport; 186 | 187 | CORNELIUS_VM_CONFIG VmConfig; 188 | PUINT8 SeamrrVa; 189 | P_SYS_INFO_TABLE_t* PSysInfoTable; 190 | UINT64 CSysInfoTableVa; 191 | 192 | UINT64 AllocatorPa; 193 | UINT64 AllocatorPaEnd; 194 | 195 | struct { 196 | UINT64 Start; 197 | UINT64 End; 198 | } CmrsAvail[SYS_INFO_TABLE_NUM_CMRS]; 199 | 200 | UINT64 LastPa; 201 | UINT64 HiddenPaCursor; 202 | 203 | PUINT64 DirtyGpasBitmap; 204 | PUINT64 MappedGpasBitmap; 205 | 206 | // Initial register values 207 | UINT64 BootCr3; 208 | UINT64 BootRip; 209 | UINT64 BootRsp; 210 | UINT64 BootSsp; 211 | 212 | SIZE_T SeamdbIndex; 213 | 214 | #define NUM_KEYIDS 32 215 | UINT32 KeyidActive; 216 | 217 | #define GPA_TO_HVA(_Vm_, _Gpa_) ((_Vm_)->AddressSpaceHva + GPA_WITHOUT_HKID(_Gpa_)) 218 | PUINT8 AddressSpaceHva; 219 | 220 | PUINT8 VmcsHva; 221 | 222 | PVOID PseamldrSancovBitmapHva; 223 | 224 | struct { 225 | UINT64 BitmapsGpa; 226 | PUINT8 BitmapsHva; 227 | UINT64 BitmapSize; 228 | } TdxModuleSancovParams; 229 | 230 | SEAM_STATE SeamldrState; 231 | 232 | BOOLEAN IsPseamldrRangeActive; 233 | volatile BOOLEAN SeamReady; 234 | 235 | UINT32 NumberOfVcpus; 236 | CORNELIUS_VCPU Vcpus[]; 237 | } CORNELIUS_VM; 238 | 239 | // -------------------------------------------------------------------------- 240 | 241 | #define FATAL(msg) { printf("[!] %s Failed with %s\n", __func__, (msg)); exit(-1); } 242 | #define FAIL_IF_ERROR(hr) do { if (FAILED(hr)) { printf("[!] %s Failed with %x\n", __func__, hr); exit(-1); } } while (0); 243 | #define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] 244 | 245 | #define VMCS_INVALID_PTR 0xFFFFFFFFFFFFFFFFULL 246 | 247 | enum VmcsType { 248 | VmcsTypePseamldr, 249 | VmcsTypeTdxModule, 250 | VmcsTypeTdGuest, 251 | VmcsTypeInvalid 252 | }; 253 | 254 | extern const UINT64 TdVmcsFields[NUM_TD_VMCS_FIELDS]; 255 | 256 | // 257 | // commands.c 258 | // 259 | 260 | BOOLEAN SeamcallTdx_TdhSysInfo(CORNELIUS_VM *Vm, UINT32 VcpuNum); 261 | 262 | // 263 | // elf.c 264 | // 265 | 266 | BOOLEAN RelocateElf(PUINT8 ElfImage, SIZE_T ElfSize, UINT64 RelocationAddr); 267 | UINT64 GetElfEntryPoint(PUINT8 ElfImage, SIZE_T ElfSize); 268 | UINT64 GetElfSymbolOffset(PUINT8 ElfImage, SIZE_T ElfSize, CHAR *SymbolName); 269 | 270 | // 271 | // emulator.c 272 | // 273 | 274 | enum VcpuAction EmulateCPUID(CORNELIUS_VM *Vm, UINT32 VcpuNum, WHV_RUN_VP_EXIT_CONTEXT *ExitContext); 275 | enum VcpuAction EmulateRDMSR(CORNELIUS_VM *Vm, UINT32 VcpuNum, WHV_RUN_VP_EXIT_CONTEXT *ExitContext); 276 | enum VcpuAction EmulateWRMSR(CORNELIUS_VM *Vm, UINT32 VcpuNum, WHV_RUN_VP_EXIT_CONTEXT *ExitContext); 277 | enum VcpuAction EmulateOnUD(CORNELIUS_VM *Vm, UINT32 VcpuNum, WHV_RUN_VP_EXIT_CONTEXT *ExitContext); 278 | enum VcpuAction EmulateOnGP(CORNELIUS_VM *Vm, UINT32 VcpuNum, WHV_RUN_VP_EXIT_CONTEXT *ExitContext); 279 | enum VcpuAction EmulateOnIO(CORNELIUS_VM *Vm, UINT32 VcpuNum, WHV_RUN_VP_EXIT_CONTEXT *ExitContext); 280 | 281 | // 282 | // paging.c 283 | // 284 | 285 | enum MAP_TYPE { 286 | MapTypeCode, 287 | MapTypeData, 288 | MapTypeDataUser, 289 | MapTypeShadowStack, 290 | MapTypeKeyHole 291 | }; 292 | 293 | BOOLEAN GvaToPa(CORNELIUS_VM *Vm, UINT32 VcpuNum, UINT64 Gva, UINT64 *Pa); 294 | PVOID GvaToHva(CORNELIUS_VM *Vm, UINT32 VcpuNum, UINT64 Gva); 295 | BOOLEAN MapPage(CORNELIUS_VM *Vm, UINT64 Va, UINT64 Pa, enum MAP_TYPE MapType, UINT64 *PdePage); 296 | BOOLEAN MapRange(CORNELIUS_VM *Vm, UINT64 Va, UINT64 Pa, SIZE_T Size, enum MAP_TYPE MapType); 297 | 298 | // 299 | // invariants.c 300 | // 301 | 302 | BOOLEAN InvariantsOnCPUID(CORNELIUS_VM *Vm, UINT32 VcpuNum, UINT32 Leaf); 303 | BOOLEAN InvariantsOnPCONFIG(CORNELIUS_VM *Vm, UINT32 VcpuNum, mktme_key_program_t *MktmeKeyProgram); 304 | BOOLEAN InvariantsOnVMPTRLD(CORNELIUS_VM *Vm, UINT32 VcpuNum, UINT64 VmcsPtr); 305 | BOOLEAN InvariantsOnVMLAUNCH(CORNELIUS_VM *Vm, UINT32 VcpuNum); 306 | BOOLEAN InvariantsOnVmcsCache(CORNELIUS_VM *Vm, UINT32 VcpuNum, UINT64 VmcsPtr); 307 | 308 | // 309 | // sanitizers.c 310 | // 311 | 312 | VOID InitializeAsan(CORNELIUS_VM *Vm); 313 | enum VcpuAction MsrAsanReport(CORNELIUS_VM *Vm, UINT32 VcpuNum, UINT64 ReportAddr); 314 | enum VcpuAction MsrUbsanReport(CORNELIUS_VM *Vm, UINT32 VcpuNum, UINT64 ReportAddr); 315 | VOID InitializeSancov(CORNELIUS_VM *Vm); 316 | SIZE_T GetSancovMaxBitmapSize(CORNELIUS_VM *Vm); 317 | enum VcpuAction MsrSancovParams(CORNELIUS_VM *Vm, UINT32 VcpuNum, UINT64 ParamsAddr); 318 | 319 | // 320 | // seam.c 321 | // 322 | 323 | VOID InitializeSeamRr(CORNELIUS_VM *Vm); 324 | VOID InitializeSeamldrState(CORNELIUS_VM *Vm); 325 | VOID InstallSeamldrState(CORNELIUS_VM *Vm, UINT32 VcpuNum); 326 | VOID InitializeVcpuState(CORNELIUS_VM *Vm, UINT32 VcpuNum); 327 | VOID InitializeTdxState(CORNELIUS_VM *Vm, UINT32 VcpuNum); 328 | VOID InstallTdxState(CORNELIUS_VM *Vm, UINT32 VcpuNum); 329 | VOID PseamldrTransferVmcsSet64(CORNELIUS_VM *Vm, UINT32 VcpuNum, UINT64 Offset, UINT64 Value); 330 | VOID SyncTdxStateWithVmcs(CORNELIUS_VM *Vm); 331 | VOID SyncVcpuStateWithContext(CORNELIUS_VM *Vm, UINT32 VcpuNum); 332 | VOID SyncVcpuStateWithTdVmcs(CORNELIUS_VM *Vm, UINT32 VcpuNum); 333 | VOID SetPseamldrRangeActive(CORNELIUS_VM *Vm, BOOLEAN Active); 334 | SEAM_STATE *GetTdxState(CORNELIUS_VM *Vm, UINT32 VcpuNum); 335 | BOOLEAN IsVcpuSeamldr(CORNELIUS_VM *Vm, UINT32 VcpuNum); 336 | VOID InstallVcpuState(CORNELIUS_VM *Vm, UINT32 VcpuNum); 337 | UINT64 GetPseamldrEntryVmcsPtr(CORNELIUS_VM *Vm); 338 | UINT64 GetEntryVmcsPtr(CORNELIUS_VM *Vm, UINT32 VcpuNum); 339 | enum VcpuAction SetEntryVmcsPtr(CORNELIUS_VM *Vm, UINT32 VcpuNum); 340 | UINT64 GetVmcsPtr(CORNELIUS_VM *Vm, UINT32 VcpuNum); 341 | VOID SetVmcsPtr(CORNELIUS_VM *Vm, UINT32 VcpuNum, UINT64 VmcsPtr); 342 | enum VmcsType GetCurrentVmcsType(CORNELIUS_VM *Vm, UINT32 VcpuNum); 343 | VOID PseamldrLock(CORNELIUS_VM *Vm); 344 | VOID PseamldrUnlock(CORNELIUS_VM *Vm); 345 | VOID MapCmrsInKeyidSpace(CORNELIUS_VM *Vm, UINT16 Keyid); 346 | BOOLEAN TdVmcsWrite64(CORNELIUS_VM *Vm, UINT32 VcpuNum, UINT64 VmcsField, UINT64 Value); 347 | BOOLEAN TdVmcsRead64(CORNELIUS_VM *Vm, UINT32 VcpuNum, UINT64 VmcsField, PUINT64 Value); 348 | enum VcpuAction VmcsCache(CORNELIUS_VM *Vm, UINT32 VcpuNum, UINT64 VmcsPtr); 349 | VOID VmcsUncache(CORNELIUS_VM *Vm, UINT32 VcpuNum, UINT64 VmcsPtr); 350 | BOOLEAN IsGpaInPseamldrRange(CORNELIUS_VM *Vm, UINT64 Gpa); 351 | enum VcpuAction MsrSeamExtend(CORNELIUS_VM *Vm, UINT32 VcpuNum, UINT64 MsrValue); 352 | 353 | // 354 | // util.c 355 | // 356 | 357 | VOID LogVcpuTdxDebug(CORNELIUS_VM *Vm, UINT32 VcpuNum, char *msg, ...); 358 | VOID LogVcpuOk(CORNELIUS_VM *Vm, UINT32 VcpuNum, char *msg, ...); 359 | VOID LogVcpuErr(CORNELIUS_VM *Vm, UINT32 VcpuNum, char *msg, ...); 360 | 361 | // 362 | // vm.c 363 | // 364 | 365 | UINT64 GetRegister64(CORNELIUS_VM *Vm, UINT32 VcpuNum, WHV_REGISTER_NAME Name); 366 | VOID SetRegister64(CORNELIUS_VM *Vm, UINT32 VcpuNum, WHV_REGISTER_NAME Name, UINT64 Val64); 367 | VOID MarkGpaNotDirty(CORNELIUS_VM *Vm, UINT64 Gpa, SIZE_T Size); 368 | VOID MapGpaExecutable(CORNELIUS_VM *Vm, UINT64 Gpa, SIZE_T Size); 369 | VOID SetPendingException(CORNELIUS_VM *Vm, UINT32 VcpuNum, WHV_EXCEPTION_TYPE ExceptionType); 370 | 371 | #define CORNELIUS_HIDE_TYPES 372 | #include "Cornelius.h" 373 | #undef CORNELIUS_HIDE_TYPES -------------------------------------------------------------------------------- /Lib/IntelDefs/pseamldr-defs.h: -------------------------------------------------------------------------------- 1 | // 2 | // Definitions taken from Intel's seam-loader-main-1.5.01.02 source code. 3 | // 4 | // This code is subject to the Intel license below. 5 | // 6 | 7 | // Intel Proprietary 8 | // 9 | // Copyright 2021 Intel Corporation All Rights Reserved. 10 | // 11 | // Your use of this software is governed by the TDX Source Code LIMITED USE LICENSE. 12 | // 13 | // The Materials are provided “as is,” without any express or implied warranty of any kind including warranties 14 | // of merchantability, non-infringement, title, or fitness for a particular purpose. 15 | 16 | #pragma once 17 | 18 | #define PACKED 19 | #define bool_t bool 20 | #define pseamldr_static_assert(a, b) C_ASSERT(a) 21 | 22 | // VMCS fields 23 | #define VMX_GUEST_IA32_DEBUGCTLMSR_FULL_ENCODE 0x2802ULL 24 | #define VMX_VM_EXIT_REASON_ENCODE 0x4402ULL 25 | #define VMX_VM_EXIT_INSTRUCTION_LENGTH_ENCODE 0x440CULL 26 | #define VMX_GUEST_INTERRUPTIBILITY_ENCODE 0x4824ULL 27 | #define VMX_GUEST_RIP_ENCODE 0x681EULL 28 | #define VMX_GUEST_RFLAGS_ENCODE 0x6820ULL 29 | #define VMX_GUEST_PND_DEBUG_EXCEPTION_ENCODE 0x6822ULL 30 | 31 | // CPUID leaves 32 | #define CPUID_DET_CACHE_PARAMS_LEAF 4 33 | #define CPUID_GET_TOPOLOGY_LEAF 0x1F 34 | #define CPUID_GET_MAX_PA_LEAF 0x80000008 35 | 36 | // MSRs 37 | #define IA32_PRED_CMD_MSR_ADDR 0x49 38 | #define IA32_MKTME_KEYID_PARTITIONING_MSR_ADDR 0x87 39 | #define NON_FAULTING_MSR_ADDR 0x8B 40 | #define IA32_TME_ACTIVATE_MSR_ADDR 0x982 41 | #define IA32_SEAMRR_BASE_MSR_ADDR 0x1400 42 | #define IA32_SEAMRR_MASK_MSR_ADDR 0x1401 43 | #define IA32_SEAMEXTEND_MSR_ADDR 0x1402 44 | 45 | #define IA32_VMX_BASIC_MSR_ADDR 0x480 46 | #define IA32_VMX_PINBASED_CTLS_MSR_ADDR 0x481 47 | #define IA32_VMX_PROCBASED_CTLS_MSR_ADDR 0x482 48 | #define IA32_VMX_EXIT_CTLS_MSR_ADDR 0x483 49 | #define IA32_VMX_ENTRY_CTLS_MSR_ADDR 0x484 50 | #define IA32_VMX_EPT_VPID_CAP_MSR_ADDR 0x48C 51 | #define IA32_VMX_MISC_MSR_ADDR 0x485 52 | #define IA32_VMX_CR0_FIXED0_MSR_ADDR 0x486 53 | #define IA32_VMX_CR0_FIXED1_MSR_ADDR 0x487 54 | #define IA32_VMX_CR4_FIXED0_MSR_ADDR 0x488 55 | #define IA32_VMX_CR4_FIXED1_MSR_ADDR 0x489 56 | #define IA32_VMX_PROCBASED_CTLS2_MSR_ADDR 0x48B 57 | #define IA32_VMX_TRUE_PINBASED_CTLS_MSR_ADDR 0x48D 58 | #define IA32_VMX_TRUE_PROCBASED_CTLS_MSR_ADDR 0x48E 59 | #define IA32_VMX_TRUE_EXIT_CTLS_MSR_ADDR 0x48F 60 | #define IA32_VMX_TRUE_ENTRY_CTLS_MSR_ADDR 0x490 61 | #define IA32_VMX_PROCBASED_CTLS3_MSR_ADDR 0x492 62 | 63 | // 64 | // pseamldr_api_defs.h 65 | // 66 | 67 | #pragma pack(push) 68 | #pragma pack(1) 69 | 70 | #define SEAMLDR_INFO_LEAF 0x8000000000000000ULL 71 | #define SEAMLDR_INSTALL_LEAF 0x8000000000000001ULL 72 | #define SEAMLDR_SHUTDOWN_LEAF 0x8000000000000002ULL 73 | #define SEAMLDR_SEAMINFO_LEAF 0x8000000000000003ULL 74 | #define SEAMLDR_CLEANUP_LEAF 0x8000000000000004ULL 75 | 76 | #define PSEAMLDR_RECOVERABLE_ERROR 0 77 | #define PSEAMLDR_UNRECOVERABLE_ERROR 1 78 | 79 | #define SEAMLDR_SCENARIO_LOAD 0 80 | #define SEAMLDR_SCENARIO_UPDATE 1 81 | 82 | #define SEAMLDR_PARAMS_MIN_MODULE_PAGES 1 83 | 84 | #define SEAMLDR_PARAMS_MAX_MODULE_PAGES_V0 496 85 | 86 | #define SEAMLDR_PARAMS_SIZE _4KB 87 | #define SEAMLDR_PARAMS_MAX_MODULE_PAGES SEAMLDR_PARAMS_MAX_MODULE_PAGES_V0 88 | 89 | #define SEAM_MODULE_PAGE_SIZE _4KB 90 | 91 | typedef struct seamldr_params_s 92 | { 93 | uint32_t version; 94 | uint32_t scenario; 95 | uint64_t sigstruct_pa; 96 | 97 | uint8_t reserved[104 - 1 * sizeof(uint64_t)]; 98 | struct { 99 | uint64_t pa_start; 100 | } ext; 101 | 102 | uint64_t num_module_pages; 103 | uint64_t mod_pages_pa_list[SEAMLDR_PARAMS_MAX_MODULE_PAGES]; 104 | } seamldr_params_t; 105 | pseamldr_static_assert(sizeof(seamldr_params_t) == SEAMLDR_PARAMS_SIZE, seamldr_params_t); 106 | 107 | typedef union attributes_s 108 | { 109 | struct 110 | { 111 | uint32_t reserved : 31; 112 | uint32_t is_debug : 1; 113 | }; 114 | uint32_t raw; 115 | } attributes_t; 116 | pseamldr_static_assert(sizeof(attributes_t) == 4, attributes_t); 117 | 118 | typedef struct PACKED tee_tcb_snv_s 119 | { 120 | union 121 | { 122 | struct 123 | { 124 | uint8_t seam_minor_svn; 125 | uint8_t seam_major_svn; 126 | }; 127 | uint16_t current_seam_svn; 128 | }; 129 | 130 | uint8_t last_patch_se_svn; 131 | uint8_t reserved[13]; 132 | } tee_tcb_svn_t; 133 | pseamldr_static_assert(sizeof(tee_tcb_svn_t) == 16, tee_tcb_svn_t); 134 | 135 | /** 136 | * @struct seamextend_t 137 | * 138 | * @brief The processor maintains a platform-scoped register called SEAMEXTEND, 139 | * 140 | * Which records the attributes of the current SEAM module, and its basic execution controls. 141 | * P-SEAMLDR can retrieve and update this register using IA32_SEAMEXTEND command MSR. 142 | * 143 | */ 144 | typedef struct PACKED seamextend_s 145 | { 146 | uint64_t valid; 147 | tee_tcb_svn_t tee_tcb_svn; 148 | uint8_t mrseam[48]; 149 | uint8_t mrsigner[48]; 150 | uint64_t attributes; 151 | uint8_t seam_ready; 152 | bool_t system_under_debug; 153 | uint8_t p_seamldr_ready; 154 | uint8_t reserved[5]; 155 | } seamextend_t; 156 | pseamldr_static_assert(sizeof(seamextend_t) == 136, seamextend_t); 157 | 158 | typedef union seamldr_info_features0_u 159 | { 160 | struct 161 | { 162 | uint64_t s4_mig_api_supported : 1; // Bit 0 163 | uint64_t cleanup_supported : 1; // Bit 1 164 | uint64_t reserved : 62; // Bit 2-63 165 | }; 166 | uint64_t raw; 167 | } seamldr_info_features0_t; 168 | pseamldr_static_assert(sizeof(seamldr_info_features0_t) == 8, seamldr_info_features0_t); 169 | 170 | typedef struct seamldr_info_s 171 | { 172 | uint32_t version; 173 | attributes_t attributes; 174 | uint32_t vendor_id; 175 | uint32_t build_date; 176 | uint16_t build_num; 177 | uint16_t minor; 178 | uint16_t major; 179 | uint16_t reserved_0; 180 | uint32_t acm_x2apic; 181 | uint32_t num_remaining_updates; 182 | seamextend_t seamextend; 183 | seamldr_info_features0_t features0; 184 | uint8_t reserved_2[80]; 185 | } seamldr_info_t; 186 | pseamldr_static_assert(sizeof(seamldr_info_t) == 256, seamldr_info_t); 187 | 188 | typedef struct handoff_data_header_s 189 | { 190 | bool_t valid; 191 | uint8_t reserved; 192 | uint16_t hv; 193 | uint32_t size; 194 | } handoff_data_header_t; 195 | pseamldr_static_assert(sizeof(handoff_data_header_t) == 8, handoff_data_header_t); 196 | 197 | #define NUM_CACHELINES_IN_PAGE 64 198 | 199 | #pragma pack(pop) 200 | 201 | // 202 | // seam_sigstruct.h 203 | // 204 | 205 | #define SIGSTRUCT_MODULUS_SIZE 384 206 | #define SIGSTRUCT_SIGNATURE_SIZE 384 207 | #define SIGSTRUCT_SEAMHASH_SIZE 48 208 | 209 | #pragma pack(push,1) 210 | 211 | #define SEAM_SIGSTRUCT_KEY_SIZE_DWORDS 0x60 212 | #define SEAM_SIGSTRUCT_MODULUS_SIZE_DWORDS 0x60 213 | #define SEAM_SIGSTRUCT_EXPONENT_SIZE_DWORDS 0x1 214 | #define SEAM_SIGSTRUCT_RSA_EXPONENT 0x10001 // (2^16 + 1) 215 | #define SEAM_SIGSTRUCT_HEADER_TYPE_GENERIC_FW 0x6 216 | #define SEAM_SIGSTRUCT_HEADER_LENGTH_DWORDS 0xE1 217 | #define SEAM_SIGSTRUCT_HEADER_VERSION_MINOR 0x0UL 218 | #define SEAM_SIGSTRUCT_HEADER_VERSION_MAJOR 0x1UL 219 | #define SEAM_SIGSTRUCT_HEADER_VERSION ((SEAM_SIGSTRUCT_HEADER_VERSION_MAJOR << 16) | \ 220 | SEAM_SIGSTRUCT_HEADER_VERSION_MINOR) 221 | #define SEAM_SIGSTRUCT_SIZE_DWORDS 0x200 222 | 223 | #define SEAM_SIGSTRUCT_INTEL_MODULE_VENDOR 0x8086 224 | #define SEAM_SIGSTRUCT_MAX_CPUID_TABLE_SIZE 255 225 | 226 | typedef union 227 | { 228 | struct 229 | { 230 | uint32_t reserved : 31; 231 | uint32_t is_debug_signed : 1; 232 | }; 233 | 234 | uint32_t raw; 235 | } module_type_t; 236 | 237 | #define TDX_MODULE_1_0_MAJOR_SVN 0 238 | 239 | typedef union seam_svn_u 240 | { 241 | struct 242 | { 243 | uint8_t seam_minor_svn; 244 | uint8_t seam_major_svn; 245 | }; 246 | 247 | uint16_t raw; 248 | } seam_svn_t; 249 | pseamldr_static_assert(sizeof(seam_svn_t) == 2, seam_svn_t); 250 | 251 | #define SEAM_SIGSTRUCT_SIZE 2048 252 | #define SEAM_SIGSTRUCT_HEADER_SIZE 128 253 | #define SEAM_SIGSTRUCT_SIG_OFFSET SEAM_SIGSTRUCT_HEADER_SIZE 254 | #define SEAM_SIGSTRUCT_SIG_SIZE (384+4+384) 255 | #define SEAM_SIGSTRUCT_BODY_OFFSET (SEAM_SIGSTRUCT_SIG_OFFSET + SEAM_SIGSTRUCT_SIG_SIZE) 256 | #define SEAM_SIGSTRUCT_BODY_SIZE (SEAM_SIGSTRUCT_SIZE - SEAM_SIGSTRUCT_HEADER_SIZE - SEAM_SIGSTRUCT_SIG_SIZE) 257 | 258 | #if ((SEAM_SIGSTRUCT_BODY_OFFSET + SEAM_SIGSTRUCT_BODY_SIZE) != SEAM_SIGSTRUCT_SIZE) 259 | #error "Wrong SEAM SIGSTRUCT size constants!!!" 260 | #endif 261 | 262 | typedef struct 263 | { 264 | uint32_t header_type; 265 | uint32_t header_length; 266 | uint32_t header_version; 267 | module_type_t module_type; 268 | uint32_t module_vendor; 269 | uint32_t date; 270 | uint32_t size; 271 | uint32_t key_size; 272 | uint32_t modulus_size; 273 | uint32_t exponent_size; 274 | uint8_t reserved0[88]; 275 | 276 | uint8_t modulus[SIGSTRUCT_MODULUS_SIZE]; 277 | uint32_t exponent; 278 | uint8_t signature[SIGSTRUCT_SIGNATURE_SIZE]; 279 | 280 | uint8_t seamhash[SIGSTRUCT_SEAMHASH_SIZE]; 281 | seam_svn_t seamsvn; 282 | uint64_t attributes; 283 | uint32_t rip_offset; 284 | uint8_t num_stack_pages; 285 | uint8_t num_tls_pages; 286 | uint16_t num_keyhole_pages; 287 | uint16_t num_global_data_pages; 288 | uint16_t max_tdmrs; 289 | uint16_t max_rsvd_per_tdmr; 290 | uint16_t pamt_entry_size_4k; 291 | uint16_t pamt_entry_size_2m; 292 | uint16_t pamt_entry_size_1g; 293 | uint8_t reserved1[6]; 294 | uint16_t module_hv; 295 | uint16_t min_update_hv; 296 | bool_t no_downgrade; 297 | uint8_t reserved2[1]; 298 | uint16_t num_handoff_pages; 299 | 300 | uint32_t gdt_idt_offset; 301 | uint32_t fault_wrapper_offset; 302 | uint8_t reserved3[24]; 303 | 304 | uint32_t cpuid_table_size; 305 | uint32_t cpuid_table[SEAM_SIGSTRUCT_MAX_CPUID_TABLE_SIZE]; 306 | 307 | } seam_sigstruct_t; 308 | 309 | #pragma pack(pop) 310 | 311 | pseamldr_static_assert(sizeof(seam_sigstruct_t) == SEAM_SIGSTRUCT_SIZE, seam_sigstruct_t); 312 | pseamldr_static_assert(offsetof(seam_sigstruct_t, modulus) == SEAM_SIGSTRUCT_SIG_OFFSET, seam_sigstruct_t); 313 | pseamldr_static_assert(offsetof(seam_sigstruct_t, seamhash) == SEAM_SIGSTRUCT_BODY_OFFSET, seam_sigstruct_t); 314 | 315 | // 316 | // vmcs_defs.h 317 | // 318 | 319 | #define VMX_GUEST_RIP_OFFSET 0x01d8 //8 320 | #define VMX_VMCS_REVISION_ID_OFFSET 0x0000 //4 321 | #define VMX_VM_EXECUTION_CONTROL_PROC_BASED_OFFSET 0x0120 //4 322 | #define VMX_VM_EXECUTION_CONTROL_PIN_BASED_OFFSET 0x0128 //4 323 | #define VMX_VM_EXIT_CONTROL_OFFSET 0x015c //4 324 | #define VMX_VM_ENTRY_CONTROL_OFFSET 0x02b8 //4 325 | #define VMX_HOST_CS_SELECTOR_OFFSET 0x00c2 //2 326 | #define VMX_HOST_SS_SELECTOR_OFFSET 0x00c4 //2 327 | #define VMX_HOST_FS_SELECTOR_OFFSET 0x00c8 //2 328 | #define VMX_HOST_GS_SELECTOR_OFFSET 0x00ca //2 329 | #define VMX_HOST_TR_SELECTOR_OFFSET 0x00cc //2 330 | #define VMX_HOST_RSP_OFFSET 0x0300 //8 331 | #define VMX_HOST_RIP_OFFSET 0x0308 //8 332 | #define VMX_HOST_IA32_PAT_FULL_OFFSET 0x0310 //8 333 | #define VMX_HOST_IA32_EFER_FULL_OFFSET 0x0318 //8 334 | #define VMX_HOST_CR0_OFFSET 0x0328 //8 335 | #define VMX_HOST_CR3_OFFSET 0x0330 //8 336 | #define VMX_HOST_CR4_OFFSET 0x0338 //8 337 | #define VMX_HOST_IDTR_BASE_OFFSET 0x0340 //8 338 | #define VMX_HOST_GDTR_BASE_OFFSET 0x0348 //8 339 | #define VMX_HOST_FS_BASE_OFFSET 0x0350 //8 340 | #define VMX_HOST_GS_BASE_OFFSET 0x0358 //8 341 | #define VMX_HOST_IA32_S_CET_OFFSET 0x0458 //8 342 | #define VMX_HOST_SSP_OFFSET 0x0460 //8 343 | 344 | // 345 | // x86_defs.h 346 | // 347 | 348 | #define MAX_PA 52ULL 349 | 350 | typedef union 351 | { 352 | struct 353 | { 354 | uint32_t rsvd :14; // 0-13 355 | uint32_t max_num_of_lps_sharing_cache :12; // 14-25 356 | uint32_t cores_per_socket_minus_one :6; 357 | }; 358 | uint32_t raw; 359 | } cpu_cache_params_t; 360 | pseamldr_static_assert(sizeof(cpu_cache_params_t) == 4, cpu_cache_params_t); 361 | 362 | // 363 | // msr_defs.h 364 | // 365 | 366 | #define IA32_CORE_THREAD_COUNT_MSR_ADDR 0x35 367 | 368 | typedef union ia32_seamrr_mask_u { 369 | struct { 370 | uint64_t 371 | rsvd0 : 10, // [9:0] 372 | lock : 1, // [10] 373 | valid : 1, // [11] 374 | rsvd1 : 13, // [24:12] 375 | mask : ((MAX_PA - 1) - 24), // [MAX_PA-1:25] 376 | rsvd2 : ((63 - MAX_PA) + 1); // [63:MAX_PA] 377 | }; 378 | 379 | uint64_t raw; 380 | } ia32_seamrr_mask_t; 381 | pseamldr_static_assert(sizeof(ia32_seamrr_mask_t) == 8, ia32_seamrr_mask_t); 382 | 383 | typedef union 384 | { 385 | struct 386 | { 387 | uint64_t vmcs_revision_id : 31; // bits 30:0 388 | uint64_t rsvd0 : 1; // bit 31 389 | uint64_t vmcs_region_size : 13; // bits 44:32 390 | uint64_t rsvd1 : 3; // bits 47:45 391 | uint64_t vmxon_pa_width : 1; // bit 48 392 | uint64_t dual_monitor : 1; // bit 49 393 | uint64_t vmcs_mt : 4; // bits 53:50 394 | uint64_t vmexit_info_on_ios : 1; // bit 54 395 | uint64_t ia32_vmx_true_available : 1; // bit 55 396 | uint64_t voe_without_err_code : 1; // bit 56 397 | uint64_t rsvd2 : 7; // bits 63:57 398 | }; 399 | uint64_t raw; 400 | } ia32_vmx_basic_t; 401 | pseamldr_static_assert(sizeof(ia32_vmx_basic_t) == 8, ia32_vmx_basic_t); 402 | 403 | typedef union ia32_core_thread_count_u 404 | { 405 | struct 406 | { 407 | uint64_t lps_in_package : 16; 408 | uint64_t rsvd : 48; 409 | }; 410 | uint64_t raw; 411 | } ia32_core_thread_count_t; -------------------------------------------------------------------------------- /Test/main.c: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | static VOID 10 | LogStatus(char *msg, ...) 11 | { 12 | va_list argp; 13 | 14 | SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 8); 15 | 16 | printf("[+] "); 17 | 18 | va_start(argp, msg); 19 | vprintf(msg, argp); 20 | va_end(argp); 21 | 22 | SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 15); 23 | } 24 | 25 | static VOID 26 | LogErr(char *msg, ...) 27 | { 28 | va_list argp; 29 | 30 | SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 12); 31 | 32 | printf("[!] "); 33 | 34 | va_start(argp, msg); 35 | vprintf(msg, argp); 36 | va_end(argp); 37 | 38 | SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 15); 39 | } 40 | 41 | static BOOLEAN 42 | ReadBinFile(PCHAR Path, PUINT8* Buffer, PSIZE_T BufferSize) 43 | { 44 | HANDLE hFile; 45 | DWORD BytesRead; 46 | DWORD FileSize; 47 | PUINT8 FileBytes; 48 | 49 | hFile = CreateFileA(Path, 50 | GENERIC_READ, 51 | 0, 52 | NULL, 53 | OPEN_EXISTING, 54 | FILE_ATTRIBUTE_NORMAL, 55 | NULL); 56 | 57 | if (hFile == INVALID_HANDLE_VALUE) { 58 | return FALSE; 59 | } 60 | 61 | FileSize = GetFileSize(hFile, NULL); 62 | if (FileSize == INVALID_FILE_SIZE) { 63 | CloseHandle(hFile); 64 | return FALSE; 65 | } 66 | 67 | FileBytes = (PUINT8)VirtualAlloc(NULL, FileSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); 68 | if (FileBytes == NULL) { 69 | CloseHandle(hFile); 70 | return FALSE; 71 | } 72 | 73 | if (!ReadFile(hFile, FileBytes, FileSize, &BytesRead, NULL)) { 74 | CloseHandle(hFile); 75 | return FALSE; 76 | } 77 | 78 | CloseHandle(hFile); 79 | 80 | if (BytesRead != FileSize) { 81 | return FALSE; 82 | } 83 | 84 | *Buffer = FileBytes; 85 | *BufferSize = FileSize; 86 | 87 | return TRUE; 88 | } 89 | 90 | static BOOLEAN 91 | LoadPseamldrConstants(PCHAR Path, pseamldr_constants_t* PseamldrConstants) 92 | { 93 | PVOID Buffer; 94 | SIZE_T BufferSize; 95 | 96 | if (!ReadBinFile(Path, (PUINT8*)&Buffer, &BufferSize)) { 97 | return FALSE; 98 | } 99 | if (BufferSize != sizeof(*PseamldrConstants)) { 100 | return FALSE; 101 | } 102 | 103 | memcpy(PseamldrConstants, Buffer, sizeof(*PseamldrConstants)); 104 | VirtualFree(Buffer, BufferSize, MEM_DECOMMIT | MEM_RELEASE); 105 | return TRUE; 106 | } 107 | 108 | static VOID 109 | TdUnknownVmexit(CORNELIUS_VM* Vm, UINT32 VcpuNum) 110 | { 111 | VCPU_STATE* TdgState; 112 | 113 | TdgState = GetVcpuState(Vm, VcpuNum); 114 | TdgState->ExitReason = 0x6666; // Unknown VMEXIT 115 | TdgState->InstructionLength = 4; 116 | 117 | if (RunVCPU(Vm, VcpuNum, VcpuModeTdGuest) != VcpuActionSeamRet) { 118 | exit(-1); 119 | } 120 | } 121 | 122 | static VOID 123 | BuildSeptTree(CORNELIUS_VM* Vm, UINT32 VcpuNum, TD_VM* TdVm, UINT64 Gpa) 124 | { 125 | UINT64 Pa; 126 | UINT8 Level; 127 | UINT64 Ret; 128 | 129 | for (Level = 3; Level > 0; --Level) { 130 | Pa = AllocatePaFromCmrsAvail(Vm); 131 | LogStatus("Executing TDH.MEM.SEPT.ADD with entry level %d\n", Level); 132 | Ret = SeamcallTdx_TdhMemSeptAdd(Vm, VcpuNum, TdVm, Pa, Gpa, Level); 133 | if (Ret) { 134 | LogErr("TDH.MEM.SEPT.ADD failed with 0x%llx\n", Ret); 135 | exit(-1); 136 | } 137 | } 138 | } 139 | 140 | int 141 | main(INT argc, PCHAR argv[]) 142 | { 143 | pseamldr_constants_t PseamldrConstants; 144 | CORNELIUS_VM_CONFIG VmConfig; 145 | CORNELIUS_VM *Vm; 146 | VOID *Snapshot; 147 | TD_VM *TdVm; 148 | PUINT8 TdxBuffer; 149 | SIZE_T TdxSize; 150 | UINT64 Ret; 151 | UINT32 i; 152 | 153 | if (argc != 4) { 154 | LogErr("Usage: Test.exe ConstBlob PseamldrElf TdxElf\n"); 155 | return -1; 156 | } 157 | 158 | memset(&VmConfig, 0, sizeof(VmConfig)); 159 | 160 | if (!LoadPseamldrConstants(argv[1], &PseamldrConstants)) { 161 | printf("[!] Failed to read the constants file\n"); 162 | return -1; 163 | } 164 | if (!ReadBinFile(argv[2], &VmConfig.PSeamldrElfBytes, &VmConfig.PSeamldrElfSize)) { 165 | printf("[!] Failed to read the P-SEAMLDR ELF file\n"); 166 | return -1; 167 | } 168 | if (!ReadBinFile(argv[3], &TdxBuffer, &TdxSize)) { 169 | printf("[!] Failed to read the TDX ELF file\n"); 170 | return -1; 171 | } 172 | 173 | // 174 | // Fill in VmConfig with the parameters we want for the machine. You are 175 | // free to modify all fields to create any specific configuration you want. 176 | // 177 | // Pay attention that the memory ranges are not supposed to overlap, and 178 | // that the highest physical address available is 1GB. 179 | // 180 | // Note on MKTME: 181 | // 182 | // The MKTME key space is hard-coded to 1GB (CORNELIUS_KEYSPACE_SIZE). 183 | // This means that each MKTME KeyID covers 1GB of physical memory. On 184 | // real hardware that would mean that each range of 1GB of physical 185 | // memory is encrypted using a different MKTME key. In Cornelius we 186 | // emulate this behavior by creating GPA aliases towards the same HPAs, 187 | // such that any given GPA points to the same HPA as [N x 1GB + GPA] for 188 | // any N. These aliases are automatically established by Cornelius by 189 | // interecepting the PCONFIG instruction. Overall, you don't need to be 190 | // concerned with these internals. 191 | // 192 | // The memory layout we set up here is the following: 193 | // 194 | // +--------------------------------------------+ 195 | // | Usable VMM Memory (64MB) | 196 | // +--------------------------------------------+ 197 | // | SEAM Range (64MB) | 198 | // +--------------------------------------------+ 199 | // | SMM Range (4KB) | 200 | // +--------------------------------------------+ 201 | // | CMRs (variable size) | 202 | // +--------------------------------------------+ 203 | // | ASAN Shadow (if enabled) | 204 | // +--------------------------------------------+ 205 | // 206 | 207 | VmConfig.NumberOfVcpus = 4; 208 | 209 | VmConfig.SeamrrBase = 32 * _2MB; // SEAMRR.Base = 64MB 210 | VmConfig.SeamrrSize = 32 * _2MB; // SEAMRR.Limit = 64MB 211 | 212 | VmConfig.PSeamldrRange.Base = VmConfig.SeamrrBase + 16 * _2MB; // P-SEAMLDR range starts at 32MB within SEAMRR 213 | VmConfig.PSeamldrRange.Size = 16 * _2MB; 214 | 215 | VmConfig.DataRegionSize = PseamldrConstants.data_region_size; 216 | VmConfig.KeyholeRegionSize = PseamldrConstants.keyhole_region_size; 217 | VmConfig.KeyholeEditRegionSize = PseamldrConstants.keyhole_edit_region_size; 218 | VmConfig.StackRegionSize = PseamldrConstants.data_stack_size + PAGE_SIZE; // +1 for the shadow stack 219 | VmConfig.EntryPointOffset = PseamldrConstants.entry_point_offset; 220 | 221 | VmConfig.SeamdbSize = 1; // Must be at least 1 222 | 223 | VmConfig.KeyidBits = 4; // 16 keys ... 224 | VmConfig.NumPrivKeyids = 10; // .. 10 of which are usable by TDX 225 | 226 | VmConfig.SmrrBase = VmConfig.PSeamldrRange.Base + VmConfig.PSeamldrRange.Size; // SMM range starts after P-SEAMLDR range 227 | VmConfig.SmrrMask = 0xfffff000; // SMM range size = PAGE_SIZE 228 | 229 | VmConfig.NumberOfCmrs = 1; 230 | VmConfig.Cmrs[0].Base = VmConfig.SmrrBase + PAGE_SIZE; 231 | VmConfig.Cmrs[0].Size = 256 * _2MB; 232 | 233 | VmConfig.LastPa = VmConfig.Cmrs[0].Base + VmConfig.Cmrs[0].Size; 234 | 235 | VmConfig.HasSanitizers = FALSE; // Set to TRUE if you have compiled the P-SEAMLDR and TDX module with sanitizers 236 | 237 | // 238 | // Create the VM. 239 | // 240 | 241 | LogStatus("Creating the Cornelius VM\n"); 242 | Vm = CreateVM(&VmConfig); 243 | if (Vm == NULL) { 244 | LogErr("Unable to create the VM\n"); 245 | return -1; 246 | } 247 | 248 | // 249 | // Execute commands to install the TDX module and bring it to the SYS_READY 250 | // state. 251 | // 252 | // Note that we are in the context of the VMM making SEAMCALLs into the 253 | // P-SEAMLDR and the TDX module. This means that the register state visible 254 | // through GetVcpuState() is that of the VMM. 255 | // 256 | 257 | for (i = 0; i < GetNumberOfVcpus(Vm); i++) { 258 | LogStatus("Executing PSEAMLDR.INSTALL on VCPU%u\n", i); 259 | Ret = SeamcallPseamldr_Install(Vm, i, TdxBuffer, TdxSize); 260 | if (Ret != 0) { 261 | LogErr("PSEAMLDR.INSTALL failed with 0x%llx\n", Ret); 262 | return -1; 263 | } 264 | } 265 | 266 | LogStatus("Executing TDH.SYS.INIT\n"); 267 | Ret = SeamcallTdx_TdhSysInit(Vm, 0); 268 | if (Ret != 0) { 269 | LogErr("TDH.SYS.INIT failed with 0x%llx\n", Ret); 270 | return -1; 271 | } 272 | 273 | for (i = 0; i < GetNumberOfVcpus(Vm); i++) { 274 | LogStatus("Executing TDH.SYS.LP.INIT on VCPU%u\n", i); 275 | Ret = SeamcallTdx_TdhSysLpInit(Vm, i); 276 | if (Ret != 0) { 277 | LogErr("TDH.SYS.LP.INIT failed with 0x%llx\n", Ret); 278 | return -1; 279 | } 280 | } 281 | 282 | LogStatus("Executing TDH.SYS.CONFIG\n"); 283 | Ret = SeamcallTdx_TdhSysConfig(Vm, 0); 284 | if (Ret != 0) { 285 | LogErr("TDH.SYS.CONFIG failed with 0x%llx\n", Ret); 286 | return -1; 287 | } 288 | 289 | LogStatus("Executing TDH.SYS.KEY.CONFIG\n"); 290 | Ret = SeamcallTdx_TdhSysKeyConfig(Vm, 0); 291 | if (Ret != 0) { 292 | LogErr("TDH.SYS.KEY.CONFIG failed with 0x%llx\n", Ret); 293 | return -1; 294 | } 295 | 296 | LogStatus("Executing TDH.SYS.TDMR.INIT\n"); 297 | Ret = SeamcallTdx_TdhSysTdmrInit(Vm, 0); 298 | if (Ret != 0) { 299 | LogErr("TDH.SYS.TDMR.INIT failed with 0x%llx\n", Ret); 300 | return -1; 301 | } 302 | 303 | // 304 | // Create a TD guest with 2 VCPUs, and execute the TDX commands to initialize it. 305 | // 306 | // N.B.: we are still in the context of the VMM, making SEAMCALLs into the TDX 307 | // module. 308 | // 309 | 310 | TdVm = CreateTdVm(Vm, 2); 311 | if (TdVm == NULL) { 312 | LogErr("Unable to create the TdVm\n"); 313 | return -1; 314 | } 315 | 316 | LogStatus("Executing TDH.MNG.CREATE\n"); 317 | Ret = SeamcallTdx_TdhMngCreate(Vm, 0, TdVm); 318 | if (Ret != 0) { 319 | LogErr("TDH.MNG.CREATE failed with 0x%llx\n", Ret); 320 | return -1; 321 | } 322 | 323 | LogStatus("Executing TDH.MNG.KEY.CONFIG\n"); 324 | Ret = SeamcallTdx_TdhMngKeyConfig(Vm, 0, TdVm); 325 | if (Ret != 0) { 326 | LogErr("TDH.MNG.KEY.CONFIG failed with 0x%llx\n", Ret); 327 | return -1; 328 | } 329 | 330 | LogStatus("Executing TDH.MNG.ADDCX\n"); 331 | Ret = SeamcallTdx_TdhMngAddcx(Vm, 0, TdVm); 332 | if (Ret != 0) { 333 | LogErr("TDH.MNG.ADDCX failed with 0x%llx\n", Ret); 334 | return -1; 335 | } 336 | 337 | LogStatus("Executing TDH.MNG.INIT\n"); 338 | Ret = SeamcallTdx_TdhMngInit(Vm, 0, TdVm); 339 | if (Ret != 0) { 340 | LogErr("TDH.MNG.INIT failed with 0x%llx\n", Ret); 341 | return -1; 342 | } 343 | 344 | for (i = 0; i < TdVm->NumberOfVcpus; i++) { 345 | LogStatus("Executing TDH.VP.CREATE on TDVCPU%u\n", i); 346 | Ret = SeamcallTdx_TdhVpCreate(Vm, 0, TdVm, i); 347 | if (Ret != 0) { 348 | LogErr("TDH.VP.CREATE failed with 0x%llx\n", Ret); 349 | return -1; 350 | } 351 | 352 | LogStatus("Executing TDH.VP.ADDCX on TDVCPU%u\n", i); 353 | Ret = SeamcallTdx_TdhVpAddcx(Vm, 0, TdVm, i); 354 | if (Ret != 0) { 355 | LogErr("TDH.VP.ADDCX failed with 0x%llx\n", Ret); 356 | return -1; 357 | } 358 | 359 | LogStatus("Executing TDH.VP.INIT on TDVCPU%u\n", i); 360 | Ret = SeamcallTdx_TdhVpInit(Vm, 0, TdVm, i); 361 | if (Ret != 0) { 362 | LogErr("TDH.VP.INIT failed with 0x%llx\n", Ret); 363 | return -1; 364 | } 365 | } 366 | 367 | UINT64 PrivatePageGpa = 1ULL << 39; 368 | BuildSeptTree(Vm, 0, TdVm, PrivatePageGpa); 369 | 370 | LogStatus("Executing TDH.MR.FINALIZE\n"); 371 | Ret = SeamcallTdx_TdhMrFinalize(Vm, 0, TdVm); 372 | if (Ret != 0) { 373 | LogErr("TDH.MR.FINALIZE failed with 0x%llx\n", Ret); 374 | return -1; 375 | } 376 | 377 | UINT64 PrivatePagePa = AllocatePaFromCmrsAvail(Vm); 378 | 379 | LogStatus("Executing TDH.MEM.PAGE.AUG\n"); 380 | Ret = SeamcallTdx_TdhMemPageAug(Vm, 0, TdVm, PrivatePagePa, PrivatePageGpa, 0); 381 | if (Ret != 0) { 382 | LogErr("TDH.MEM.PAGE.AUG failed with 0x%llx\n", Ret); 383 | return -1; 384 | } 385 | 386 | // 387 | // The TD guest is initialized! 388 | // 389 | // We now execute the TDH.VP.ENTER command for the TDX module to do a VMLAUNCH 390 | // into the TD guest. This will switch the context, see below. 391 | // 392 | 393 | LogStatus("Executing TDH.VP.ENTER\n"); 394 | Ret = SeamcallTdx_TdhVpEnter(Vm, 0, TdVm, 0); 395 | if (Ret != 0) { 396 | LogErr("TDH.VP.ENTER failed with RAX=%llx\n", Ret); 397 | return -1; 398 | } 399 | 400 | // 401 | // The VMLAUNCH into the TD guest was successful. That means we are no longer in 402 | // the context of the VMM making SEAMCALLs into the TDX module, instead we are now 403 | // in the context of the entered VCPU of the TD guest which can trigger VMEXITs 404 | // into the TDX module. 405 | // 406 | // In other words, we are no longer the VMM, we are the TD guest. 407 | // 408 | // We can now execute TDCALLs into the TDX module if we want. Or trigger any 409 | // other kind of VMEXIT to switch back into the VMM context. 410 | // 411 | 412 | // Switch the TD guest to long mode. This fixup would normally be done by the 413 | // CPU automatically, but we need to do it manually in Cornelius. 414 | GetVcpuState(Vm, 0)->Cr0 |= CR0_PG; 415 | GetVcpuState(Vm, 0)->Efer |= EFER_LMA; 416 | GetVcpuState(Vm, 0)->Cs.Long = 1; 417 | 418 | // Take a snapshot of the VM. See below what we do with it. 419 | LogStatus("Taking snapshot\n"); 420 | Snapshot = CreateSnapshot(Vm); 421 | if (Snapshot == NULL) { 422 | LogErr("Unable to create snapshot\n"); 423 | return -1; 424 | } 425 | 426 | // Execute a TDCALL to accept the page we previously set up. 427 | LogStatus("TD executing TDG.MEM.PAGE.ACCEPT\n"); 428 | Ret = Tdcall_TdgMemPageAccept(Vm, 0, PrivatePageGpa, 0); 429 | if (Ret != 0) { 430 | LogErr("TDG.MEM.PAGE.ACCEPT failed with 0x%llx\n", Ret); 431 | return -1; 432 | } 433 | 434 | // Now trigger a VMEXIT with a dummy exit reason. On success this puts us back 435 | // in the context of the VMM. 436 | LogStatus("Doing VMEXIT from TD guest\n"); 437 | TdUnknownVmexit(Vm, 0); 438 | 439 | // 440 | // We're back as a VMM! And we can now execute SEAMCALLs again if we want. 441 | // Execute one into the P-SEAMLDR, just to showcase. 442 | // 443 | 444 | seamldr_info_t PseamldrInfo; 445 | 446 | LogStatus("TD executing PSEAMLDR.INFO\n"); 447 | Ret = SeamcallPseamldr_Info(Vm, 0, 0x1000, &PseamldrInfo); 448 | if (Ret != 0) { 449 | LogErr("PSEAMLDR.INFO failed with 0x%llx\n", Ret); 450 | return -1; 451 | } 452 | // The vendor_id should always be 0x8086, sanity check that. 453 | if (PseamldrInfo.vendor_id != 0x8086) { 454 | LogErr("PSEAMLDR.INFO vendor_id 0x%x != 0x8086\n", PseamldrInfo.vendor_id); 455 | return -1; 456 | } 457 | 458 | // 459 | // Now restore the snapshot! This will restore the VM exactly back to how it was 460 | // when we took the snapshot. Remember that at that moment we were in the 461 | // context of a TD guest, and therefore we're going to be back in that context 462 | // from now on. 463 | // 464 | 465 | LogStatus("Restoring snapshot\n"); 466 | RestoreSnapshot(Vm, Snapshot); 467 | 468 | // Trigger a VMEXIT with a dummy exit reason. On success this puts us back 469 | // in the context of the VMM. 470 | LogStatus("Doing VMEXIT from TD guest\n"); 471 | TdUnknownVmexit(Vm, 0); 472 | 473 | // 474 | // If the P-SEAMLDR and TDX module have SanCov enabled, print the coverage 475 | // counts. 476 | // 477 | if (HasPseamldrSanitizers(Vm)) { 478 | SANCOV_BITMAP *Bitmap = GetSancovPseamldrBitmap(Vm); 479 | LogStatus("P-SEAMLR coverage count: %zu\n", Bitmap->NumberOfHits); 480 | } 481 | if (HasTdxModuleSanitizers(Vm)) { 482 | for (i = 0; i < GetNumberOfVcpus(Vm); i++) { 483 | SANCOV_BITMAP *Bitmap = GetSancovTdxModuleBitmap(Vm, i); 484 | LogStatus("TDX module coverage count for VCPU%u: %zu\n", i, Bitmap->NumberOfHits); 485 | } 486 | } 487 | 488 | LogStatus("Finished successfully\n"); 489 | return 0; 490 | } 491 | -------------------------------------------------------------------------------- /Lib/invariants.c: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | #include 5 | #include 6 | #include 7 | #include "common.h" 8 | 9 | BOOLEAN 10 | InvariantsOnCPUID(CORNELIUS_VM *Vm, UINT32 VcpuNum, UINT32 Leaf) 11 | { 12 | // 13 | // Invariants: 14 | // - If Leaf > 2, the IA32_MISC_ENABLE.LimitCpuidMaxval bit must not 15 | // be set when CPUID executes. 16 | // 17 | 18 | if ((Leaf > 2) && (GetVcpuState(Vm, VcpuNum)->MiscEnable & __BIT(22))) { 19 | LogVcpuErr(Vm, VcpuNum, "CPUID executed with IA32_MISC_ENABLE.LimitCpuidMaxval set at RIP = 0x%llx\n", 20 | GetRegister64(Vm, VcpuNum, WHvX64RegisterRip)); 21 | return FALSE; 22 | } 23 | 24 | return TRUE; 25 | } 26 | 27 | static BOOLEAN 28 | IsTdxPrivateKeyid(CORNELIUS_VM *Vm, UINT16 Keyid) 29 | { 30 | UINT16 FirstTdxKeyid; 31 | UINT16 NumKeyids; 32 | 33 | NumKeyids = (1ULL << Vm->VmConfig.KeyidBits); 34 | FirstTdxKeyid = NumKeyids - (UINT16)Vm->VmConfig.NumPrivKeyids + 1; 35 | 36 | if (Keyid >= FirstTdxKeyid && Keyid < NumKeyids) { 37 | return TRUE; 38 | } 39 | 40 | return FALSE; 41 | } 42 | 43 | BOOLEAN 44 | InvariantsOnPCONFIG(CORNELIUS_VM *Vm, UINT32 VcpuNum, mktme_key_program_t *MktmeKeyProgram) 45 | { 46 | // 47 | // Invariants: 48 | // - The command must be SET_KEY_RANDOM. 49 | // - The keyid must be a private TDX keyid. 50 | // - The keyid must not alreay be active. 51 | // 52 | 53 | if (MktmeKeyProgram->keyid_ctrl.command != MKTME_KEYID_SET_KEY_RANDOM) { 54 | LogVcpuErr(Vm, VcpuNum, "PCONFIG not SET_KEY_RANDOM at RIP = 0x%llx\n", 55 | GetRegister64(Vm, VcpuNum, WHvX64RegisterRip)); 56 | return FALSE; 57 | } 58 | 59 | if (!IsTdxPrivateKeyid(Vm, MktmeKeyProgram->keyid)) { 60 | LogVcpuErr(Vm, VcpuNum, "PCONFIG KeyId %u is incorrect at RIP = 0x%llx\n", 61 | MktmeKeyProgram->keyid, 62 | GetRegister64(Vm, VcpuNum, WHvX64RegisterRip)); 63 | return FALSE; 64 | } 65 | 66 | if (Vm->KeyidActive & (1ULL << (UINT64)MktmeKeyProgram->keyid)) { 67 | LogVcpuErr(Vm, VcpuNum, "PCONFIG on already active KeyId %u at RIP = 0x%llx\n", 68 | MktmeKeyProgram->keyid, 69 | GetRegister64(Vm, VcpuNum, WHvX64RegisterRip)); 70 | return FALSE; 71 | } 72 | 73 | return TRUE; 74 | } 75 | 76 | BOOLEAN 77 | InvariantsOnVMPTRLD(CORNELIUS_VM *Vm, UINT32 VcpuNum, UINT64 VmcsPtr) 78 | { 79 | UINT64 RealGpa; 80 | UINT16 Keyid; 81 | SIZE_T i; 82 | 83 | // 84 | // Invariants: on VMPTRLD the new VMCS must be either 85 | // - Inside the SEAM range with Keyid=0, or 86 | // - Inside a CMR with a private Keyid. 87 | // 88 | 89 | if (VmcsPtr == GetEntryVmcsPtr(Vm, VcpuNum)) { 90 | return TRUE; 91 | } 92 | 93 | Keyid = REAL_HKID_FROM_GPA(Vm, VmcsPtr); 94 | 95 | if (!IsTdxPrivateKeyid(Vm, Keyid)) { 96 | LogVcpuErr(Vm, VcpuNum, "VMPTRLD KeyId %u is incorrect at RIP = 0x%llx\n", 97 | Keyid, 98 | GetRegister64(Vm, VcpuNum, WHvX64RegisterRip)); 99 | return FALSE; 100 | } 101 | 102 | if ((Vm->KeyidActive & (1UL << Keyid)) == 0) { 103 | LogVcpuErr(Vm, VcpuNum, "VMPTRLD KeyId %u not activated at RIP = 0x%llx\n", 104 | Keyid, 105 | GetRegister64(Vm, VcpuNum, WHvX64RegisterRip)); 106 | return FALSE; 107 | } 108 | 109 | RealGpa = GPA_WITHOUT_REAL_HKID(Vm, VmcsPtr); 110 | 111 | for (i = 0; i < Vm->VmConfig.NumberOfCmrs; i++) { 112 | if (RealGpa >= Vm->VmConfig.Cmrs[i].Base && 113 | RealGpa < Vm->VmConfig.Cmrs[i].Base + Vm->VmConfig.Cmrs[i].Size) { 114 | return TRUE; 115 | } 116 | } 117 | 118 | LogVcpuErr(Vm, VcpuNum, "VMPTRLD VMCS 0x%llx outside of CMR at RIP = 0x%llx\n", 119 | RealGpa, 120 | GetRegister64(Vm, VcpuNum, WHvX64RegisterRip)); 121 | return FALSE; 122 | } 123 | 124 | BOOLEAN 125 | InvariantsOnVMLAUNCH(CORNELIUS_VM *Vm, UINT32 VcpuNum) 126 | { 127 | BOOLEAN PerfGlobalCtlrEntryLoad; 128 | BOOLEAN PerfGlobalCtlrExitLoad; 129 | BOOLEAN PerfGlobalCtlrExitSave; 130 | TD_VMCS *VmcsHva; 131 | UINT64 VmcsPtr; 132 | SIZE_T i; 133 | 134 | PerfGlobalCtlrEntryLoad = 0; 135 | PerfGlobalCtlrExitLoad = 0; 136 | PerfGlobalCtlrExitSave = 0; 137 | 138 | // 139 | // Invariants when the TDX module does a VMLAUNCH: 140 | // 141 | // - The host fields of the TD VMCS must be identical to the current TDX 142 | // module state. 143 | // - The CR4 mask/shadow must force CR4.MCE to 1. 144 | // - Several VMCS control fields must set several bits to 1. 145 | // - The PerfGlobalCtrl EntryLoad/ExitLoad/ExitSave values must be the same. 146 | // 147 | 148 | if (GetCurrentVmcsType(Vm, VcpuNum) != VmcsTypeTdGuest) { 149 | FATAL("GetCurrentVmcsType(Vm, VcpuNum) != VmcsTypeTdGuest"); 150 | } 151 | 152 | VmcsPtr = GetVmcsPtr(Vm, VcpuNum); 153 | VmcsHva = (TD_VMCS *)GPA_TO_HVA(Vm, VmcsPtr); 154 | 155 | for (i = 0; i < NUM_TD_VMCS_FIELDS; i++) { 156 | switch (TdVmcsFields[i]) { 157 | case VMX_HOST_IA32_PERF_GLOBAL_CONTROL_FULL_ENCODE: 158 | case VMX_HOST_IA32_SYSENTER_ESP_ENCODE: 159 | case VMX_HOST_IA32_SYSENTER_EIP_ENCODE: 160 | case VMX_HOST_IA32_SYSENTER_CS_ENCODE: 161 | case VMX_HOST_IA32_INTERRUPT_SSP_TABLE_ADDR_ENCODE: 162 | if (VmcsHva->Fields[i] != 0) { 163 | LogVcpuErr(Vm, VcpuNum, "TD VMCS field %llx non-zero at RIP = 0x%llx\n", 164 | TdVmcsFields[i], 165 | GetRegister64(Vm, VcpuNum, WHvX64RegisterRip)); 166 | return FALSE; 167 | } 168 | break; 169 | 170 | case VMX_HOST_CR0_ENCODE: 171 | if (GetTdxState(Vm, VcpuNum)->RegisterValues[SEAM_STATE_CR0].Reg64 != VmcsHva->Fields[i]) { 172 | LogVcpuErr(Vm, VcpuNum, "VMWRITE changed CR0 at RIP = 0x%llx\n", 173 | GetRegister64(Vm, VcpuNum, WHvX64RegisterRip)); 174 | return FALSE; 175 | } 176 | break; 177 | case VMX_HOST_CR3_ENCODE: 178 | if (GetTdxState(Vm, VcpuNum)->RegisterValues[SEAM_STATE_CR3].Reg64 != VmcsHva->Fields[i]) { 179 | LogVcpuErr(Vm, VcpuNum, "VMWRITE changed CR3 at RIP = 0x%llx\n", 180 | GetRegister64(Vm, VcpuNum, WHvX64RegisterRip)); 181 | return FALSE; 182 | } 183 | break; 184 | case VMX_HOST_CR4_ENCODE: 185 | if (GetTdxState(Vm, VcpuNum)->RegisterValues[SEAM_STATE_CR4].Reg64 != VmcsHva->Fields[i]) { 186 | LogVcpuErr(Vm, VcpuNum, "VMWRITE changed CR4 at RIP = 0x%llx\n", 187 | GetRegister64(Vm, VcpuNum, WHvX64RegisterRip)); 188 | return FALSE; 189 | } 190 | break; 191 | case VMX_HOST_ES_SELECTOR_ENCODE: 192 | if (GetTdxState(Vm, VcpuNum)->RegisterValues[SEAM_STATE_ES].Segment.Selector != VmcsHva->Fields[i]) { 193 | LogVcpuErr(Vm, VcpuNum, "VMWRITE changed ES.SEL at RIP = 0x%llx\n", 194 | GetRegister64(Vm, VcpuNum, WHvX64RegisterRip)); 195 | return FALSE; 196 | } 197 | break; 198 | case VMX_HOST_CS_SELECTOR_ENCODE: 199 | if (GetTdxState(Vm, VcpuNum)->RegisterValues[SEAM_STATE_CS].Segment.Selector != VmcsHva->Fields[i]) { 200 | LogVcpuErr(Vm, VcpuNum, "VMWRITE changed CS.SEL at RIP = 0x%llx\n", 201 | GetRegister64(Vm, VcpuNum, WHvX64RegisterRip)); 202 | return FALSE; 203 | } 204 | break; 205 | case VMX_HOST_SS_SELECTOR_ENCODE: 206 | if (GetTdxState(Vm, VcpuNum)->RegisterValues[SEAM_STATE_SS].Segment.Selector != VmcsHva->Fields[i]) { 207 | LogVcpuErr(Vm, VcpuNum, "VMWRITE changed SS.SEL at RIP = 0x%llx\n", 208 | GetRegister64(Vm, VcpuNum, WHvX64RegisterRip)); 209 | return FALSE; 210 | } 211 | break; 212 | case VMX_HOST_DS_SELECTOR_ENCODE: 213 | if (GetTdxState(Vm, VcpuNum)->RegisterValues[SEAM_STATE_DS].Segment.Selector != VmcsHva->Fields[i]) { 214 | LogVcpuErr(Vm, VcpuNum, "VMWRITE changed DS.SEL at RIP = 0x%llx\n", 215 | GetRegister64(Vm, VcpuNum, WHvX64RegisterRip)); 216 | return FALSE; 217 | } 218 | break; 219 | case VMX_HOST_FS_SELECTOR_ENCODE: 220 | if (GetTdxState(Vm, VcpuNum)->RegisterValues[SEAM_STATE_FS].Segment.Selector != VmcsHva->Fields[i]) { 221 | LogVcpuErr(Vm, VcpuNum, "VMWRITE changed FS.SEL at RIP = 0x%llx\n", 222 | GetRegister64(Vm, VcpuNum, WHvX64RegisterRip)); 223 | return FALSE; 224 | } 225 | break; 226 | case VMX_HOST_GS_SELECTOR_ENCODE: 227 | if (GetTdxState(Vm, VcpuNum)->RegisterValues[SEAM_STATE_GS].Segment.Selector != VmcsHva->Fields[i]) { 228 | LogVcpuErr(Vm, VcpuNum, "VMWRITE changed GS.SEL at RIP = 0x%llx\n", 229 | GetRegister64(Vm, VcpuNum, WHvX64RegisterRip)); 230 | return FALSE; 231 | } 232 | break; 233 | case VMX_HOST_TR_SELECTOR_ENCODE: 234 | if (GetTdxState(Vm, VcpuNum)->RegisterValues[SEAM_STATE_TR].Segment.Selector != VmcsHva->Fields[i]) { 235 | LogVcpuErr(Vm, VcpuNum, "VMWRITE changed TR.SEL at RIP = 0x%llx\n", 236 | GetRegister64(Vm, VcpuNum, WHvX64RegisterRip)); 237 | return FALSE; 238 | } 239 | break; 240 | case VMX_HOST_IA32_PAT_FULL_ENCODE: 241 | if (GetTdxState(Vm, VcpuNum)->RegisterValues[SEAM_STATE_PAT].Reg64 != VmcsHva->Fields[i]) { 242 | LogVcpuErr(Vm, VcpuNum, "VMWRITE changed PAT at RIP = 0x%llx\n", 243 | GetRegister64(Vm, VcpuNum, WHvX64RegisterRip)); 244 | return FALSE; 245 | } 246 | break; 247 | case VMX_HOST_IA32_S_CET_ENCODE: 248 | if (GetTdxState(Vm, VcpuNum)->RegisterValues[SEAM_STATE_SCET].Reg64 != VmcsHva->Fields[i]) { 249 | LogVcpuErr(Vm, VcpuNum, "VMWRITE changed SCET at RIP = 0x%llx\n", 250 | GetRegister64(Vm, VcpuNum, WHvX64RegisterRip)); 251 | return FALSE; 252 | } 253 | break; 254 | case VMX_HOST_IA32_EFER_FULL_ENCODE: 255 | if (GetTdxState(Vm, VcpuNum)->RegisterValues[SEAM_STATE_EFER].Reg64 != VmcsHva->Fields[i]) { 256 | LogVcpuErr(Vm, VcpuNum, "VMWRITE changed EFER at RIP = 0x%llx\n", 257 | GetRegister64(Vm, VcpuNum, WHvX64RegisterRip)); 258 | return FALSE; 259 | } 260 | break; 261 | case VMX_HOST_RSP_ENCODE: 262 | if (GetTdxState(Vm, VcpuNum)->RegisterValues[SEAM_STATE_RSP].Reg64 != VmcsHva->Fields[i]) { 263 | LogVcpuErr(Vm, VcpuNum, "VMWRITE changed RSP at RIP = 0x%llx\n", 264 | GetRegister64(Vm, VcpuNum, WHvX64RegisterRip)); 265 | return FALSE; 266 | } 267 | break; 268 | case VMX_HOST_SSP_ENCODE: 269 | if (GetTdxState(Vm, VcpuNum)->RegisterValues[SEAM_STATE_SSP].Reg64 != VmcsHva->Fields[i]) { 270 | LogVcpuErr(Vm, VcpuNum, "VMWRITE changed SSP at RIP = 0x%llx\n", 271 | GetRegister64(Vm, VcpuNum, WHvX64RegisterRip)); 272 | return FALSE; 273 | } 274 | break; 275 | case VMX_HOST_FS_BASE_ENCODE: 276 | if (GetTdxState(Vm, VcpuNum)->RegisterValues[SEAM_STATE_FS].Segment.Base != VmcsHva->Fields[i]) { 277 | LogVcpuErr(Vm, VcpuNum, "VMWRITE changed FS.BASE at RIP = 0x%llx\n", 278 | GetRegister64(Vm, VcpuNum, WHvX64RegisterRip)); 279 | return FALSE; 280 | } 281 | break; 282 | case VMX_HOST_GS_BASE_ENCODE: 283 | if (GetTdxState(Vm, VcpuNum)->RegisterValues[SEAM_STATE_GS].Segment.Base != VmcsHva->Fields[i]) { 284 | LogVcpuErr(Vm, VcpuNum, "VMWRITE changed GS.BASE at RIP = 0x%llx\n", 285 | GetRegister64(Vm, VcpuNum, WHvX64RegisterRip)); 286 | return FALSE; 287 | } 288 | break; 289 | case VMX_HOST_TR_BASE_ENCODE: 290 | if (GetTdxState(Vm, VcpuNum)->RegisterValues[SEAM_STATE_TR].Segment.Base != VmcsHva->Fields[i]) { 291 | LogVcpuErr(Vm, VcpuNum, "VMWRITE changed TR.BASE at RIP = 0x%llx\n", 292 | GetRegister64(Vm, VcpuNum, WHvX64RegisterRip)); 293 | return FALSE; 294 | } 295 | break; 296 | case VMX_HOST_IDTR_BASE_ENCODE: 297 | if (GetTdxState(Vm, VcpuNum)->RegisterValues[SEAM_STATE_IDTR].Table.Base != VmcsHva->Fields[i]) { 298 | LogVcpuErr(Vm, VcpuNum, "VMWRITE changed IDT.BASE at RIP = 0x%llx\n", 299 | GetRegister64(Vm, VcpuNum, WHvX64RegisterRip)); 300 | return FALSE; 301 | } 302 | break; 303 | case VMX_HOST_GDTR_BASE_ENCODE: 304 | if (GetTdxState(Vm, VcpuNum)->RegisterValues[SEAM_STATE_GDTR].Table.Base != VmcsHva->Fields[i]) { 305 | LogVcpuErr(Vm, VcpuNum, "VMWRITE changed GDT.BASE at RIP = 0x%llx\n", 306 | GetRegister64(Vm, VcpuNum, WHvX64RegisterRip)); 307 | return FALSE; 308 | } 309 | break; 310 | 311 | case VMX_CR4_GUEST_HOST_MASK_ENCODE: 312 | if ((VmcsHva->Fields[i] & CR4_MCE) == 0) { 313 | LogVcpuErr(Vm, VcpuNum, "VMWRITE set CR4.MCE mask to zero at RIP = 0x%llx\n", 314 | GetRegister64(Vm, VcpuNum, WHvX64RegisterRip)); 315 | return FALSE; 316 | } 317 | break; 318 | case VMX_CR4_READ_SHADOW_ENCODE: 319 | if ((VmcsHva->Fields[i] & CR4_MCE) == 0) { 320 | LogVcpuErr(Vm, VcpuNum, "VMWRITE set CR4.MCE shadow to zero at RIP = 0x%llx\n", 321 | GetRegister64(Vm, VcpuNum, WHvX64RegisterRip)); 322 | return FALSE; 323 | } 324 | break; 325 | 326 | case VMX_VM_EXECUTION_CONTROL_PROC_BASED_ENCODE: 327 | if ((VmcsHva->Fields[i] & __BIT(24)) == 0) { 328 | LogVcpuErr(Vm, VcpuNum, "VMWRITE set PROC_BASED_CTLS.IoExiting to zero at RIP = 0x%llx\n", 329 | GetRegister64(Vm, VcpuNum, WHvX64RegisterRip)); 330 | return FALSE; 331 | } 332 | if ((VmcsHva->Fields[i] & __BIT(28)) == 0) { 333 | LogVcpuErr(Vm, VcpuNum, "VMWRITE set PROC_BASED_CTLS.UseMsrBitmaps to zero at RIP = 0x%llx\n", 334 | GetRegister64(Vm, VcpuNum, WHvX64RegisterRip)); 335 | return FALSE; 336 | } 337 | if ((VmcsHva->Fields[i] & __BIT(31)) == 0) { 338 | LogVcpuErr(Vm, VcpuNum, "VMWRITE set PROC_BASED_CTLS.ActivateCtls2 to zero at RIP = 0x%llx\n", 339 | GetRegister64(Vm, VcpuNum, WHvX64RegisterRip)); 340 | return FALSE; 341 | } 342 | break; 343 | 344 | case VMX_VM_EXECUTION_CONTROL_SECONDARY_PROC_BASED_ENCODE: 345 | if ((VmcsHva->Fields[i] & __BIT(1)) == 0) { 346 | LogVcpuErr(Vm, VcpuNum, "VMWRITE set PROC_BASED_CTLS2.EnableEpt to zero at RIP = 0x%llx\n", 347 | GetRegister64(Vm, VcpuNum, WHvX64RegisterRip)); 348 | return FALSE; 349 | } 350 | break; 351 | 352 | case VMX_VM_EXECUTION_CONTROL_PIN_BASED_ENCODE: 353 | if ((VmcsHva->Fields[i] & __BIT(0)) == 0) { 354 | LogVcpuErr(Vm, VcpuNum, "VMWRITE set PIN_BASED_CTLS.IntExiting to zero at RIP = 0x%llx\n", 355 | GetRegister64(Vm, VcpuNum, WHvX64RegisterRip)); 356 | return FALSE; 357 | } 358 | break; 359 | 360 | case VMX_VM_ENTRY_CONTROL_ENCODE: 361 | if ((VmcsHva->Fields[i] & __BIT(2)) == 0) { 362 | LogVcpuErr(Vm, VcpuNum, "VMWRITE set ENTRY_CTLS.LoadDebugControls to zero at RIP = 0x%llx\n", 363 | GetRegister64(Vm, VcpuNum, WHvX64RegisterRip)); 364 | return FALSE; 365 | } 366 | if ((VmcsHva->Fields[i] & __BIT(14)) == 0) { 367 | LogVcpuErr(Vm, VcpuNum, "VMWRITE set ENTRY_CTLS.LoadPat to zero at RIP = 0x%llx\n", 368 | GetRegister64(Vm, VcpuNum, WHvX64RegisterRip)); 369 | return FALSE; 370 | } 371 | if ((VmcsHva->Fields[i] & __BIT(15)) == 0) { 372 | LogVcpuErr(Vm, VcpuNum, "VMWRITE set ENTRY_CTLS.LoadEfer to zero at RIP = 0x%llx\n", 373 | GetRegister64(Vm, VcpuNum, WHvX64RegisterRip)); 374 | return FALSE; 375 | } 376 | if ((VmcsHva->Fields[i] & __BIT(20)) == 0) { 377 | LogVcpuErr(Vm, VcpuNum, "VMWRITE set ENTRY_CTLS.LoadCet to zero at RIP = 0x%llx\n", 378 | GetRegister64(Vm, VcpuNum, WHvX64RegisterRip)); 379 | return FALSE; 380 | } 381 | 382 | PerfGlobalCtlrEntryLoad = (VmcsHva->Fields[i] & __BIT(13)) != 0; 383 | break; 384 | 385 | case VMX_VM_EXIT_CONTROL_ENCODE: 386 | if ((VmcsHva->Fields[i] & __BIT(2)) == 0) { 387 | LogVcpuErr(Vm, VcpuNum, "VMWRITE set EXIT_CTLS.LoadDebugControls to zero at RIP = 0x%llx\n", 388 | GetRegister64(Vm, VcpuNum, WHvX64RegisterRip)); 389 | return FALSE; 390 | } 391 | if ((VmcsHva->Fields[i] & __BIT(9)) == 0) { 392 | LogVcpuErr(Vm, VcpuNum, "VMWRITE set EXIT_CTLS.HostLongMode to zero at RIP = 0x%llx\n", 393 | GetRegister64(Vm, VcpuNum, WHvX64RegisterRip)); 394 | return FALSE; 395 | } 396 | if ((VmcsHva->Fields[i] & __BIT(18)) == 0) { 397 | LogVcpuErr(Vm, VcpuNum, "VMWRITE set EXIT_CTLS.SavePat to zero at RIP = 0x%llx\n", 398 | GetRegister64(Vm, VcpuNum, WHvX64RegisterRip)); 399 | return FALSE; 400 | } 401 | if ((VmcsHva->Fields[i] & __BIT(19)) == 0) { 402 | LogVcpuErr(Vm, VcpuNum, "VMWRITE set EXIT_CTLS.LoadPat to zero at RIP = 0x%llx\n", 403 | GetRegister64(Vm, VcpuNum, WHvX64RegisterRip)); 404 | return FALSE; 405 | } 406 | if ((VmcsHva->Fields[i] & __BIT(20)) == 0) { 407 | LogVcpuErr(Vm, VcpuNum, "VMWRITE set EXIT_CTLS.SaveEfer to zero at RIP = 0x%llx\n", 408 | GetRegister64(Vm, VcpuNum, WHvX64RegisterRip)); 409 | return FALSE; 410 | } 411 | if ((VmcsHva->Fields[i] & __BIT(21)) == 0) { 412 | LogVcpuErr(Vm, VcpuNum, "VMWRITE set EXIT_CTLS.LoadEfer to zero at RIP = 0x%llx\n", 413 | GetRegister64(Vm, VcpuNum, WHvX64RegisterRip)); 414 | return FALSE; 415 | } 416 | if ((VmcsHva->Fields[i] & __BIT(28)) == 0) { 417 | LogVcpuErr(Vm, VcpuNum, "VMWRITE set EXIT_CTLS.LoadCet to zero at RIP = 0x%llx\n", 418 | GetRegister64(Vm, VcpuNum, WHvX64RegisterRip)); 419 | return FALSE; 420 | } 421 | 422 | PerfGlobalCtlrExitLoad = (VmcsHva->Fields[i] & __BIT(12)) != 0; 423 | PerfGlobalCtlrExitSave = (VmcsHva->Fields[i] & __BIT(30)) != 0; 424 | break; 425 | 426 | default: 427 | break; 428 | } 429 | } 430 | 431 | if (PerfGlobalCtlrEntryLoad != PerfGlobalCtlrExitLoad || 432 | PerfGlobalCtlrExitLoad != PerfGlobalCtlrExitSave) { 433 | LogVcpuErr(Vm, VcpuNum, "PerfGlobalCtrl is not properly context-switched at RIP = 0x%llx\n", 434 | GetRegister64(Vm, VcpuNum, WHvX64RegisterRip)); 435 | return FALSE; 436 | } 437 | 438 | return TRUE; 439 | } 440 | 441 | BOOLEAN 442 | InvariantsOnVmcsCache(CORNELIUS_VM *Vm, UINT32 VcpuNum, UINT64 VmcsPtr) 443 | { 444 | TD_VMCS *VmcsHva; 445 | 446 | // 447 | // Invariants: when the TDX module caches a new VMCS, that VMCS must not be 448 | // cached on any CPU. 449 | // 450 | 451 | VmcsHva = (TD_VMCS *)GPA_TO_HVA(Vm, VmcsPtr); 452 | 453 | if (VmcsHva->CachedOnCpu) { 454 | LogVcpuErr(Vm, VcpuNum, "VMCS 0x%llx already cached elsewhere at RIP = 0x%llx\n", 455 | VmcsPtr, 456 | GetRegister64(Vm, VcpuNum, WHvX64RegisterRip)); 457 | return FALSE; 458 | } 459 | 460 | return TRUE; 461 | } -------------------------------------------------------------------------------- /Lib/x86-defs.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | #pragma once 5 | 6 | #define CR0_PE 0x00000001 7 | #define CR0_MP 0x00000002 8 | #define CR0_EM 0x00000004 9 | #define CR0_TS 0x00000008 10 | #define CR0_ET 0x00000010 11 | #define CR0_NE 0x00000020 12 | #define CR0_WP 0x00010000 13 | #define CR0_AM 0x00040000 14 | #define CR0_NW 0x20000000 15 | #define CR0_CD 0x40000000 16 | #define CR0_PG 0x80000000 17 | 18 | #define CR4_VME 0x00000001 19 | #define CR4_PVI 0x00000002 20 | #define CR4_TSD 0x00000004 21 | #define CR4_DE 0x00000008 22 | #define CR4_PSE 0x00000010 23 | #define CR4_PAE 0x00000020 24 | #define CR4_MCE 0x00000040 25 | #define CR4_PGE 0x00000080 26 | #define CR4_PCE 0x00000100 27 | #define CR4_OSFXSR 0x00000200 28 | #define CR4_OSXMMEXCPT 0x00000400 29 | #define CR4_UMIP 0x00000800 30 | #define CR4_LA57 0x00001000 31 | #define CR4_VMXE 0x00002000 32 | #define CR4_SMXE 0x00004000 33 | #define CR4_FSGSBASE 0x00010000 34 | #define CR4_PCIDE 0x00020000 35 | #define CR4_OSXSAVE 0x00040000 36 | #define CR4_SMEP 0x00100000 37 | #define CR4_SMAP 0x00200000 38 | #define CR4_PKE 0x00400000 39 | #define CR4_CET 0x00800000 40 | #define CR4_PKS 0x01000000 41 | 42 | #define EFER_SCE 0x00000001 43 | #define EFER_LME 0x00000100 44 | #define EFER_LMA 0x00000400 45 | #define EFER_NXE 0x00000800 46 | #define EFER_SVME 0x00001000 47 | #define EFER_LMSLE 0x00002000 48 | #define EFER_FFXSR 0x00004000 49 | #define EFER_TCE 0x00008000 50 | 51 | #define IA32_CR_S_CET_SH_STK_EN_MASK 0x0000000000000001 52 | #define IA32_CR_S_CET_ENDBR_EN_MASK 0x0000000000000004 53 | #define IA32_CR_S_CET_NO_TRACK_EN_MASK 0x0000000000000010 54 | 55 | #define IA32_FIXED_CTR_CTRL_MSR_ADDR 0x38D 56 | #define IA32_PERF_GLOBAL_STATUS_MSR_ADDR 0x38E 57 | #define IA32_PMC_FX0_CTR_MSR_ADDR 0x309 58 | 59 | /* Fn0000_0001:ECX */ 60 | #define CPUID_0_01_ECX_SSE3 __BIT(0) 61 | #define CPUID_0_01_ECX_PCLMULQDQ __BIT(1) 62 | #define CPUID_0_01_ECX_DTES64 __BIT(2) 63 | #define CPUID_0_01_ECX_MONITOR __BIT(3) 64 | #define CPUID_0_01_ECX_DS_CPL __BIT(4) 65 | #define CPUID_0_01_ECX_VMX __BIT(5) 66 | #define CPUID_0_01_ECX_SMX __BIT(6) 67 | #define CPUID_0_01_ECX_EIST __BIT(7) 68 | #define CPUID_0_01_ECX_TM2 __BIT(8) 69 | #define CPUID_0_01_ECX_SSSE3 __BIT(9) 70 | #define CPUID_0_01_ECX_CNXTID __BIT(10) 71 | #define CPUID_0_01_ECX_SDBG __BIT(11) 72 | #define CPUID_0_01_ECX_FMA __BIT(12) 73 | #define CPUID_0_01_ECX_CX16 __BIT(13) 74 | #define CPUID_0_01_ECX_XTPR __BIT(14) 75 | #define CPUID_0_01_ECX_PDCM __BIT(15) 76 | #define CPUID_0_01_ECX_PCID __BIT(17) 77 | #define CPUID_0_01_ECX_DCA __BIT(18) 78 | #define CPUID_0_01_ECX_SSE41 __BIT(19) 79 | #define CPUID_0_01_ECX_SSE42 __BIT(20) 80 | #define CPUID_0_01_ECX_X2APIC __BIT(21) 81 | #define CPUID_0_01_ECX_MOVBE __BIT(22) 82 | #define CPUID_0_01_ECX_POPCNT __BIT(23) 83 | #define CPUID_0_01_ECX_TSC_DEADLINE __BIT(24) 84 | #define CPUID_0_01_ECX_AESNI __BIT(25) 85 | #define CPUID_0_01_ECX_XSAVE __BIT(26) 86 | #define CPUID_0_01_ECX_OSXSAVE __BIT(27) 87 | #define CPUID_0_01_ECX_AVX __BIT(28) 88 | #define CPUID_0_01_ECX_F16C __BIT(29) 89 | #define CPUID_0_01_ECX_RDRAND __BIT(30) 90 | #define CPUID_0_01_ECX_RAZ __BIT(31) 91 | /* Fn0000_0001:EDX */ 92 | #define CPUID_0_01_EDX_FPU __BIT(0) 93 | #define CPUID_0_01_EDX_VME __BIT(1) 94 | #define CPUID_0_01_EDX_DE __BIT(2) 95 | #define CPUID_0_01_EDX_PSE __BIT(3) 96 | #define CPUID_0_01_EDX_TSC __BIT(4) 97 | #define CPUID_0_01_EDX_MSR __BIT(5) 98 | #define CPUID_0_01_EDX_PAE __BIT(6) 99 | #define CPUID_0_01_EDX_MCE __BIT(7) 100 | #define CPUID_0_01_EDX_CX8 __BIT(8) 101 | #define CPUID_0_01_EDX_APIC __BIT(9) 102 | #define CPUID_0_01_EDX_SEP __BIT(11) 103 | #define CPUID_0_01_EDX_MTRR __BIT(12) 104 | #define CPUID_0_01_EDX_PGE __BIT(13) 105 | #define CPUID_0_01_EDX_MCA __BIT(14) 106 | #define CPUID_0_01_EDX_CMOV __BIT(15) 107 | #define CPUID_0_01_EDX_PAT __BIT(16) 108 | #define CPUID_0_01_EDX_PSE36 __BIT(17) 109 | #define CPUID_0_01_EDX_PSN __BIT(18) 110 | #define CPUID_0_01_EDX_CLFSH __BIT(19) 111 | #define CPUID_0_01_EDX_DS __BIT(21) 112 | #define CPUID_0_01_EDX_ACPI __BIT(22) 113 | #define CPUID_0_01_EDX_MMX __BIT(23) 114 | #define CPUID_0_01_EDX_FXSR __BIT(24) 115 | #define CPUID_0_01_EDX_SSE __BIT(25) 116 | #define CPUID_0_01_EDX_SSE2 __BIT(26) 117 | #define CPUID_0_01_EDX_SS __BIT(27) 118 | #define CPUID_0_01_EDX_HTT __BIT(28) 119 | #define CPUID_0_01_EDX_TM __BIT(29) 120 | #define CPUID_0_01_EDX_PBE __BIT(31) 121 | 122 | /* [ECX=0] Fn0000_0007:EBX (Structured Extended Features) */ 123 | #define CPUID_0_07_EBX_FSGSBASE __BIT(0) 124 | #define CPUID_0_07_EBX_TSC_ADJUST __BIT(1) 125 | #define CPUID_0_07_EBX_SGX __BIT(2) 126 | #define CPUID_0_07_EBX_BMI1 __BIT(3) 127 | #define CPUID_0_07_EBX_HLE __BIT(4) 128 | #define CPUID_0_07_EBX_AVX2 __BIT(5) 129 | #define CPUID_0_07_EBX_FDPEXONLY __BIT(6) 130 | #define CPUID_0_07_EBX_SMEP __BIT(7) 131 | #define CPUID_0_07_EBX_BMI2 __BIT(8) 132 | #define CPUID_0_07_EBX_ERMS __BIT(9) 133 | #define CPUID_0_07_EBX_INVPCID __BIT(10) 134 | #define CPUID_0_07_EBX_RTM __BIT(11) 135 | #define CPUID_0_07_EBX_QM __BIT(12) 136 | #define CPUID_0_07_EBX_FPUCSDS __BIT(13) 137 | #define CPUID_0_07_EBX_MPX __BIT(14) 138 | #define CPUID_0_07_EBX_PQE __BIT(15) 139 | #define CPUID_0_07_EBX_AVX512F __BIT(16) 140 | #define CPUID_0_07_EBX_AVX512DQ __BIT(17) 141 | #define CPUID_0_07_EBX_RDSEED __BIT(18) 142 | #define CPUID_0_07_EBX_ADX __BIT(19) 143 | #define CPUID_0_07_EBX_SMAP __BIT(20) 144 | #define CPUID_0_07_EBX_AVX512_IFMA __BIT(21) 145 | #define CPUID_0_07_EBX_CLFLUSHOPT __BIT(23) 146 | #define CPUID_0_07_EBX_CLWB __BIT(24) 147 | #define CPUID_0_07_EBX_PT __BIT(25) 148 | #define CPUID_0_07_EBX_AVX512PF __BIT(26) 149 | #define CPUID_0_07_EBX_AVX512ER __BIT(27) 150 | #define CPUID_0_07_EBX_AVX512CD __BIT(28) 151 | #define CPUID_0_07_EBX_SHA __BIT(29) 152 | #define CPUID_0_07_EBX_AVX512BW __BIT(30) 153 | #define CPUID_0_07_EBX_AVX512VL __BIT(31) 154 | /* [ECX=0] Fn0000_0007:ECX (Structured Extended Features) */ 155 | #define CPUID_0_07_ECX_PREFETCHWT1 __BIT(0) 156 | #define CPUID_0_07_ECX_AVX512_VBMI __BIT(1) 157 | #define CPUID_0_07_ECX_UMIP __BIT(2) 158 | #define CPUID_0_07_ECX_PKU __BIT(3) 159 | #define CPUID_0_07_ECX_OSPKE __BIT(4) 160 | #define CPUID_0_07_ECX_WAITPKG __BIT(5) 161 | #define CPUID_0_07_ECX_AVX512_VBMI2 __BIT(6) 162 | #define CPUID_0_07_ECX_CET_SS __BIT(7) 163 | #define CPUID_0_07_ECX_GFNI __BIT(8) 164 | #define CPUID_0_07_ECX_VAES __BIT(9) 165 | #define CPUID_0_07_ECX_VPCLMULQDQ __BIT(10) 166 | #define CPUID_0_07_ECX_AVX512_VNNI __BIT(11) 167 | #define CPUID_0_07_ECX_AVX512_BITALG __BIT(12) 168 | #define CPUID_0_07_ECX_AVX512_VPOPCNTDQ __BIT(14) 169 | #define CPUID_0_07_ECX_LA57 __BIT(16) 170 | #define CPUID_0_07_ECX_MAWAU __BITS(21, 17) 171 | #define CPUID_0_07_ECX_RDPID __BIT(22) 172 | #define CPUID_0_07_ECX_KL __BIT(23) 173 | #define CPUID_0_07_ECX_BUS_LOCK_DETECT __BIT(24) 174 | #define CPUID_0_07_ECX_CLDEMOTE __BIT(25) 175 | #define CPUID_0_07_ECX_MOVDIRI __BIT(27) 176 | #define CPUID_0_07_ECX_MOVDIR64B __BIT(28) 177 | #define CPUID_0_07_ECX_SGXLC __BIT(30) 178 | #define CPUID_0_07_ECX_PKS __BIT(31) 179 | /* [ECX=0] Fn0000_0007:EDX (Structured Extended Features) */ 180 | #define CPUID_0_07_EDX_AVX512_4VNNIW __BIT(2) 181 | #define CPUID_0_07_EDX_AVX512_4FMAPS __BIT(3) 182 | #define CPUID_0_07_EDX_FSREP_MOV __BIT(4) 183 | #define CPUID_0_07_EDX_AVX512_VP2INTERSECT __BIT(8) 184 | #define CPUID_0_07_EDX_SRBDS_CTRL __BIT(9) 185 | #define CPUID_0_07_EDX_MD_CLEAR __BIT(10) 186 | #define CPUID_0_07_EDX_TSX_FORCE_ABORT __BIT(13) 187 | #define CPUID_0_07_EDX_SERIALIZE __BIT(14) 188 | #define CPUID_0_07_EDX_HYBRID __BIT(15) 189 | #define CPUID_0_07_EDX_TSXLDTRK __BIT(16) 190 | #define CPUID_0_07_EDX_ARCH_LBR __BIT(19) 191 | #define CPUID_0_07_EDX_CET_IBT __BIT(20) 192 | #define CPUID_0_07_EDX_IBRS __BIT(26) 193 | #define CPUID_0_07_EDX_STIBP __BIT(27) 194 | #define CPUID_0_07_EDX_L1D_FLUSH __BIT(28) 195 | #define CPUID_0_07_EDX_ARCH_CAP __BIT(29) 196 | #define CPUID_0_07_EDX_CORE_CAP __BIT(30) 197 | #define CPUID_0_07_EDX_SSBD __BIT(31) 198 | /* [ECX=2] Fn0000_0007:EDX (Structured Extended Features) */ 199 | #define CPUID_0_07_2_PSFD __BIT(0) 200 | #define CPUID_0_07_2_IPRED_CTRL __BIT(1) 201 | #define CPUID_0_07_2_RRSBA_CTRL __BIT(2) 202 | #define CPUID_0_07_2_DDPD_U __BIT(3) 203 | #define CPUID_0_07_2_BHI_CTRL __BIT(4) 204 | #define CPUID_0_07_2_MCDT_NO __BIT(5) 205 | 206 | /* Fn8000_0008:EBX */ 207 | #define CPUID_8_08_EBX_CLZERO __BIT(0) 208 | #define CPUID_8_08_EBX_InstRetCntMsr __BIT(1) 209 | #define CPUID_8_08_EBX_RstrFpErrPtrs __BIT(2) 210 | #define CPUID_8_08_EBX_INVLPGB __BIT(3) 211 | #define CPUID_8_08_EBX_RDPRU __BIT(4) 212 | #define CPUID_8_08_EBX_MCOMMIT __BIT(8) 213 | #define CPUID_8_08_EBX_WBNOINVD __BIT(9) 214 | #define CPUID_8_08_EBX_IBPB __BIT(12) 215 | #define CPUID_8_08_EBX_INT_WBINVD __BIT(13) 216 | #define CPUID_8_08_EBX_IBRS __BIT(14) 217 | #define CPUID_8_08_EBX_STIBP __BIT(15) 218 | #define CPUID_8_08_EBX_IBRS_ALWAYSON __BIT(16) 219 | #define CPUID_8_08_EBX_STIBP_ALWAYSON __BIT(17) 220 | #define CPUID_8_08_EBX_PREFER_IBRS __BIT(18) 221 | #define CPUID_8_08_EBX_EferLmsleUnsupp __BIT(20) 222 | #define CPUID_8_08_EBX_INVLPGBnestedPg __BIT(21) 223 | #define CPUID_8_08_EBX_SSBD __BIT(24) 224 | #define CPUID_8_08_EBX_VIRT_SSBD __BIT(25) 225 | #define CPUID_8_08_EBX_SSB_NO __BIT(26) 226 | 227 | #define VMX_GUEST_ES_SELECTOR_ENCODE 0x0800ULL 228 | #define VMX_GUEST_ES_ARBYTE_ENCODE 0x4814ULL 229 | #define VMX_GUEST_ES_LIMIT_ENCODE 0x4800ULL 230 | #define VMX_GUEST_ES_BASE_ENCODE 0x6806ULL 231 | #define VMX_GUEST_CS_SELECTOR_ENCODE 0x0802ULL 232 | #define VMX_GUEST_CS_ARBYTE_ENCODE 0x4816ULL 233 | #define VMX_GUEST_CS_LIMIT_ENCODE 0x4802ULL 234 | #define VMX_GUEST_CS_BASE_ENCODE 0x6808ULL 235 | #define VMX_GUEST_SS_SELECTOR_ENCODE 0x0804ULL 236 | #define VMX_GUEST_SS_ARBYTE_ENCODE 0x4818ULL 237 | #define VMX_GUEST_SS_LIMIT_ENCODE 0x4804ULL 238 | #define VMX_GUEST_SS_BASE_ENCODE 0x680AULL 239 | #define VMX_GUEST_DS_SELECTOR_ENCODE 0x0806ULL 240 | #define VMX_GUEST_DS_ARBYTE_ENCODE 0x481AULL 241 | #define VMX_GUEST_DS_LIMIT_ENCODE 0x4806ULL 242 | #define VMX_GUEST_DS_BASE_ENCODE 0x680CULL 243 | #define VMX_GUEST_LDTR_SELECTOR_ENCODE 0x080CULL 244 | #define VMX_GUEST_LDTR_ARBYTE_ENCODE 0x4820ULL 245 | #define VMX_GUEST_LDTR_LIMIT_ENCODE 0x480CULL 246 | #define VMX_GUEST_LDTR_BASE_ENCODE 0x6812ULL 247 | #define VMX_GUEST_TR_SELECTOR_ENCODE 0x080EULL 248 | #define VMX_GUEST_TR_ARBYTE_ENCODE 0x4822ULL 249 | #define VMX_GUEST_TR_LIMIT_ENCODE 0x480EULL 250 | #define VMX_GUEST_TR_BASE_ENCODE 0x6814ULL 251 | #define VMX_GUEST_FS_SELECTOR_ENCODE 0x0808ULL 252 | #define VMX_GUEST_FS_ARBYTE_ENCODE 0x481CULL 253 | #define VMX_GUEST_FS_LIMIT_ENCODE 0x4808ULL 254 | #define VMX_GUEST_FS_BASE_ENCODE 0x680EULL 255 | #define VMX_GUEST_GS_SELECTOR_ENCODE 0x080AULL 256 | #define VMX_GUEST_GS_ARBYTE_ENCODE 0x481EULL 257 | #define VMX_GUEST_GS_LIMIT_ENCODE 0x480AULL 258 | #define VMX_GUEST_GS_BASE_ENCODE 0x6810ULL 259 | #define VMX_NOTIFY_WINDOW_ENCODE 0x4024ULL 260 | #define VMX_GUEST_GDTR_LIMIT_ENCODE 0x4810ULL 261 | #define VMX_GUEST_GDTR_BASE_ENCODE 0x6816ULL 262 | #define VMX_RSVD_32_BIT_GUEST_STATE_ENCODE 0x4830ULL 263 | #define VMX_GUEST_IDTR_LIMIT_ENCODE 0x4812ULL 264 | #define VMX_GUEST_IDTR_BASE_ENCODE 0x6818ULL 265 | #define VMX_HOST_ES_SELECTOR_ENCODE 0x0C00ULL 266 | #define VMX_HOST_CS_SELECTOR_ENCODE 0x0C02ULL 267 | #define VMX_HOST_SS_SELECTOR_ENCODE 0x0C04ULL 268 | #define VMX_HOST_DS_SELECTOR_ENCODE 0x0C06ULL 269 | #define VMX_HOST_FS_SELECTOR_ENCODE 0x0C08ULL 270 | #define VMX_HOST_GS_SELECTOR_ENCODE 0x0C0AULL 271 | #define VMX_HOST_TR_SELECTOR_ENCODE 0x0C0CULL 272 | #define VMX_GUEST_VPID_ENCODE 0x0000ULL 273 | #define VMX_OSV_CVP_FULL_ENCODE 0x200CULL 274 | #define VMX_OSV_CVP_HIGH_ENCODE 0x200dULL 275 | #define VMX_VM_INSTRUCTION_ERRORCODE_ENCODE 0x4400ULL 276 | #define VMX_PAUSE_LOOP_EXITING_GAP_ENCODE 0x4020ULL 277 | #define VMX_PAUSE_LOOP_EXITING_WINDOW_ENCODE 0x4022ULL 278 | #define VMX_GUEST_SAVED_WORKING_VMCS_POINTER_FULL_ENCODE 0x2800ULL 279 | #define VMX_GUEST_SAVED_WORKING_VMCS_POINTER_HIGH_ENCODE 0x2801ULL 280 | #define VMX_GUEST_IA32_DEBUGCTLMSR_FULL_ENCODE 0x2802ULL 281 | #define VMX_GUEST_IA32_DEBUGCTLMSR_HIGH_ENCODE 0x2803ULL 282 | #define VMX_GUEST_IA32_PAT_FULL_ENCODE 0x2804ULL 283 | #define VMX_GUEST_IA32_PAT_HIGH_ENCODE 0x2805ULL 284 | #define VMX_GUEST_IA32_EFER_FULL_ENCODE 0x2806ULL 285 | #define VMX_GUEST_IA32_EFER_HIGH_ENCODE 0x2807ULL 286 | #define VMX_GUEST_IA32_PERF_GLOBAL_CONTROL_FULL_ENCODE 0x2808ULL 287 | #define VMX_GUEST_IA32_PERF_GLOBAL_CONTROL_HIGH_ENCODE 0x2809ULL 288 | #define VMX_VM_EXECUTION_CONTROL_PROC_BASED_ENCODE 0x4002ULL 289 | #define VMX_VM_EXECUTION_CONTROL_SECONDARY_PROC_BASED_ENCODE 0x401EULL 290 | #define VMX_VM_EXECUTION_CONTROL_PIN_BASED_ENCODE 0x4000ULL 291 | #define VMX_TPR_THRESHOLD_ENCODE 0x401CULL 292 | #define VMX_PAGEFAULT_ERRORCODE_MASK_ENCODE 0x4006ULL 293 | #define VMX_PAGEFAULT_ERRORCODE_MATCH_ENCODE 0x4008ULL 294 | #define VMX_GUEST_INTERRUPTIBILITY_ENCODE 0x4824ULL 295 | #define VMX_GUEST_SLEEP_STATE_ENCODE 0x4826ULL 296 | #define VMX_GUEST_EPT_POINTER_FULL_ENCODE 0x201AULL 297 | #define VMX_GUEST_EPT_POINTER_HIGH_ENCODE 0x201bULL 298 | #define VMX_GUEST_PHYSICAL_ADDRESS_INFO_FULL_ENCODE 0x2400ULL 299 | #define VMX_GUEST_PHYSICAL_ADDRESS_INFO_HIGH_ENCODE 0x2401ULL 300 | #define VMX_VM_ENTRY_INTR_INFO_ENCODE 0x4016ULL 301 | #define VMX_VM_ENTRY_EXCEPTION_ERRORCODE_ENCODE 0x4018ULL 302 | #define VMX_VM_ENTRY_INSTRUCTION_LENGTH_ENCODE 0x401AULL 303 | #define VMX_VM_EXIT_CONTROL_ENCODE 0x400CULL 304 | #define VMX_GUEST_PREEMPTION_TIMER_COUNT_ENCODE 0x482EULL 305 | #define VMX_VM_EXIT_MSR_STORE_COUNT_ENCODE 0x400EULL 306 | #define VMX_VM_EXIT_MSR_LOAD_COUNT_ENCODE 0x4010ULL 307 | #define VMX_VM_EXIT_REASON_ENCODE 0x4402ULL 308 | #define VMX_VM_EXIT_INTERRUPTION_INFO_ENCODE 0x4404ULL 309 | #define VMX_VM_EXIT_EXCEPTION_ERRORCODE_ENCODE 0x4406ULL 310 | #define VMX_VM_EXIT_IDT_VECTOR_FIELD_ENCODE 0x4408ULL 311 | #define VMX_VM_EXIT_IDT_VECTOR_ERRORCODE_ENCODE 0x440AULL 312 | #define VMX_VM_EXIT_INSTRUCTION_LENGTH_ENCODE 0x440CULL 313 | #define VMX_VM_EXIT_INSTRUCTION_INFO_ENCODE 0x440EULL 314 | #define VMX_TSC_OFFSET_FULL_ENCODE 0x2010ULL 315 | #define VMX_TSC_OFFSET_HIGH_ENCODE 0x2011ULL 316 | #define VMX_VM_EXIT_QUALIFICATION_ENCODE 0x6400ULL 317 | #define VMX_VM_EXIT_IO_RCX_ENCODE 0x6402ULL 318 | #define VMX_VM_EXIT_IO_RSI_ENCODE 0x6404ULL 319 | #define VMX_VM_EXIT_IO_RDI_ENCODE 0x6406ULL 320 | #define VMX_VM_EXIT_IO_RIP_ENCODE 0x6408ULL 321 | #define VMX_VM_EXIT_GUEST_LINEAR_ADDRESS_ENCODE 0x640AULL 322 | #define VMX_GUEST_DR7_ENCODE 0x681AULL 323 | #define VMX_GUEST_RSP_ENCODE 0x681CULL 324 | #define VMX_GUEST_RIP_ENCODE 0x681EULL 325 | #define VMX_GUEST_RFLAGS_ENCODE 0x6820ULL 326 | #define VMX_GUEST_PND_DEBUG_EXCEPTION_ENCODE 0x6822ULL 327 | #define VMX_GUEST_IA32_SYSENTER_ESP_ENCODE 0x6824ULL 328 | #define VMX_GUEST_IA32_SYSENTER_EIP_ENCODE 0x6826ULL 329 | #define VMX_GUEST_IA32_SYSENTER_CS_ENCODE 0x482AULL 330 | #define VMX_EPTP_INDEX_ENCODE 0x0004ULL 331 | #define VMX_GUEST_CR0_ENCODE 0x6800ULL 332 | #define VMX_GUEST_CR3_ENCODE 0x6802ULL 333 | #define VMX_GUEST_CR4_ENCODE 0x6804ULL 334 | #define VMX_GUEST_PDPTR0_FULL_ENCODE 0x280AULL 335 | #define VMX_GUEST_PDPTR0_HIGH_ENCODE 0x280bULL 336 | #define VMX_GUEST_PDPTR1_FULL_ENCODE 0x280CULL 337 | #define VMX_GUEST_PDPTR1_HIGH_ENCODE 0x280dULL 338 | #define VMX_GUEST_PDPTR2_FULL_ENCODE 0x280EULL 339 | #define VMX_GUEST_PDPTR2_HIGH_ENCODE 0x280fULL 340 | #define VMX_GUEST_PDPTR3_FULL_ENCODE 0x2810ULL 341 | #define VMX_GUEST_PDPTR3_HIGH_ENCODE 0x2811ULL 342 | #define VMX_CR0_GUEST_HOST_MASK_ENCODE 0x6000ULL 343 | #define VMX_CR4_GUEST_HOST_MASK_ENCODE 0x6002ULL 344 | #define VMX_CR0_READ_SHADOW_ENCODE 0x6004ULL 345 | #define VMX_CR4_READ_SHADOW_ENCODE 0x6006ULL 346 | #define VMX_CR3_TARGET_VALUE_0_ENCODE 0x6008ULL 347 | #define VMX_CR3_TARGET_VALUE_1_ENCODE 0x600AULL 348 | #define VMX_CR3_TARGET_VALUE_2_ENCODE 0x600CULL 349 | #define VMX_CR3_TARGET_VALUE_3_ENCODE 0x600EULL 350 | #define VMX_EOI_EXIT_TABLE_0_FULL_ENCODE 0x201CULL 351 | #define VMX_EOI_EXIT_TABLE_0_HIGH_ENCODE 0x201dULL 352 | #define VMX_EOI_EXIT_TABLE_1_FULL_ENCODE 0x201EULL 353 | #define VMX_EOI_EXIT_TABLE_1_HIGH_ENCODE 0x201fULL 354 | #define VMX_EOI_EXIT_TABLE_2_FULL_ENCODE 0x2020ULL 355 | #define VMX_EOI_EXIT_TABLE_2_HIGH_ENCODE 0x2021ULL 356 | #define VMX_EOI_EXIT_TABLE_3_FULL_ENCODE 0x2022ULL 357 | #define VMX_EOI_EXIT_TABLE_3_HIGH_ENCODE 0x2023ULL 358 | #define VMX_POSTED_INTERRUPT_DESCRIPTOR_ADDRESS_FULL_ENCODE 0x2016ULL 359 | #define VMX_POSTED_INTERRUPT_DESCRIPTOR_ADDRESS_HIGH_ENCODE 0x2017ULL 360 | #define VMX_GUEST_SMBASE_ENCODE 0x4828ULL 361 | #define VMX_POSTED_INTERRUPT_NOTIFICATION_VECTOR_ENCODE 0x0002ULL 362 | #define VMX_EXCEPTION_BITMAP_ENCODE 0x4004ULL 363 | #define VMX_CR3_TARGET_COUNT_ENCODE 0x400AULL 364 | #define VMX_VM_ENTRY_CONTROL_ENCODE 0x4012ULL 365 | #define VMX_VM_ENTRY_MSR_LOAD_COUNT_ENCODE 0x4014ULL 366 | #define VMX_VIRTUAL_APIC_PAGE_ADDRESS_FULL_ENCODE 0x2012ULL 367 | #define VMX_VIRTUAL_APIC_PAGE_ADDRESS_HIGH_ENCODE 0x2013ULL 368 | #define VMX_IO_BITMAP_A_PHYPTR_FULL_ENCODE 0x2000ULL 369 | #define VMX_IO_BITMAP_A_PHYPTR_HIGH_ENCODE 0x2001ULL 370 | #define VMX_IO_BITMAP_B_PHYPTR_FULL_ENCODE 0x2002ULL 371 | #define VMX_IO_BITMAP_B_PHYPTR_HIGH_ENCODE 0x2003ULL 372 | #define VMX_EXIT_MSR_STORE_PHYPTR_FULL_ENCODE 0x2006ULL 373 | #define VMX_EXIT_MSR_STORE_PHYPTR_HIGH_ENCODE 0x2007ULL 374 | #define VMX_EXIT_MSR_LOAD_PHYPTR_FULL_ENCODE 0x2008ULL 375 | #define VMX_EXIT_MSR_LOAD_PHYPTR_HIGH_ENCODE 0x2009ULL 376 | #define VMX_ENTRY_MSR_LOAD_PHYPTR_FULL_ENCODE 0x200AULL 377 | #define VMX_ENTRY_MSR_LOAD_PHYPTR_HIGH_ENCODE 0x200bULL 378 | #define VMX_VIRTUAL_APIC_ACCESS_PAGE_ADDRESS_FULL_ENCODE 0x2014ULL 379 | #define VMX_VIRTUAL_APIC_ACCESS_PAGE_ADDRESS_HIGH_ENCODE 0x2015ULL 380 | #define VMX_MSR_BITMAP_PHYPTR_FULL_ENCODE 0x2004ULL 381 | #define VMX_MSR_BITMAP_PHYPTR_HIGH_ENCODE 0x2005ULL 382 | #define VMX_HOST_RSP_ENCODE 0x6C14ULL 383 | #define VMX_HOST_RIP_ENCODE 0x6C16ULL 384 | #define VMX_HOST_IA32_PAT_FULL_ENCODE 0x2c00ULL 385 | #define VMX_HOST_IA32_PAT_HIGH_ENCODE 0x2c01 386 | #define VMX_HOST_IA32_EFER_FULL_ENCODE 0x2c02 387 | #define VMX_HOST_IA32_EFER_HIGH_ENCODE 0x2c03 388 | #define VMX_HOST_IA32_PERF_GLOBAL_CONTROL_FULL_ENCODE 0x2c04 389 | #define VMX_HOST_IA32_PERF_GLOBAL_CONTROL_HIGH_ENCODE 0x2c05 390 | #define VMX_HOST_CR0_ENCODE 0x6C00 391 | #define VMX_HOST_CR3_ENCODE 0x6C02 392 | #define VMX_HOST_CR4_ENCODE 0x6C04ULL 393 | #define VMX_HOST_IDTR_BASE_ENCODE 0x6C0E 394 | #define VMX_HOST_GDTR_BASE_ENCODE 0x6C0C 395 | #define VMX_HOST_FS_BASE_ENCODE 0x6C06 396 | #define VMX_HOST_GS_BASE_ENCODE 0x6C08 397 | #define VMX_HOST_TR_BASE_ENCODE 0x6C0A 398 | #define VMX_HOST_IA32_SYSENTER_ESP_ENCODE 0x6C10 399 | #define VMX_HOST_IA32_SYSENTER_EIP_ENCODE 0x6C12 400 | #define VMX_HOST_IA32_SYSENTER_CS_ENCODE 0x4C00 401 | #define VMX_GUEST_INTERRUPT_STATUS_ENCODE 0x0810 402 | #define VMX_GUEST_UINV_ENCODE 0x0814 403 | #define VMX_PML_INDEX_ENCODE 0x0812 404 | #define VMX_VM_FUNCTION_CONTROLS_FULL_ENCODE 0x2018 405 | #define VMX_VM_FUNCTION_CONTROLS_HIGH_ENCODE 0x2019 406 | #define VMX_EPTP_LIST_ADDRESS_FULL_ENCODE 0x2024 407 | #define VMX_EPTP_LIST_ADDRESS_HIGH_ENCODE 0x2025 408 | #define VMX_VMREAD_BITMAP_ADDRESS_FULL_ENCODE 0x2026 409 | #define VMX_VMREAD_BITMAP_ADDRESS_HIGH_ENCODE 0x2027 410 | #define VMX_VMWRITE_BITMAP_ADDRESS_FULL_ENCODE 0x2028 411 | #define VMX_VMWRITE_BITMAP_ADDRESS_HIGH_ENCODE 0x2029 412 | #define VMX_PML_LOG_ADDRESS_FULL_ENCODE 0x200E 413 | #define VMX_PML_LOG_ADDRESS_HIGH_ENCODE 0x200f 414 | #define VMX_XSS_EXIT_CONTROL_FULL_ENCODE 0x202C 415 | #define VMX_XSS_EXIT_CONTROL_HIGH_ENCODE 0x202d 416 | #define VMX_ENCLS_EXIT_CONTROL_FULL_ENCODE 0x202E 417 | #define VMX_ENCLS_EXIT_CONTROL_HIGH_ENCODE 0x202f 418 | #define VMX_RSVD_64_BIT_VMEXIT_DATA_FULL_ENCODE 0x2402 419 | #define VMX_RSVD_64_BIT_VMEXIT_DATA_HIGH_ENCODE 0x2403 420 | #define VMX_ENCLV_EXIT_CONTROL_FULL_ENCODE 0x2036 421 | #define VMX_ENCLV_EXIT_CONTROL_HIGH_ENCODE 0x2037 422 | #define VMX_VIRTUAL_EXCEPTION_INFO_ADDRESS_FULL_ENCODE 0x202A 423 | #define VMX_VIRTUAL_EXCEPTION_INFO_ADDRESS_HIGH_ENCODE 0x202b 424 | #define VMX_GUEST_BNDCFGS_FULL_ENCODE 0x2812 425 | #define VMX_GUEST_BNDCFGS_HIGH_ENCODE 0x2813 426 | #define VMX_SPPTP_FULL_ENCODE 0x2030 427 | #define VMX_SPPTP_HIGH_ENCODE 0x2031 428 | #define VMX_TSC_MULTIPLIER_FULL_ENCODE 0x2032 429 | #define VMX_TSC_MULTIPLIER_HIGH_ENCODE 0x2033 430 | #define VMX_GUEST_RTIT_CTL_FULL_ENCODE 0x2814 431 | #define VMX_GUEST_RTIT_CTL_HIGH_ENCODE 0x2815 432 | #define VMX_VM_EXECUTION_CONTROL_TERTIARY_PROC_BASED_FULL_ENCODE 0x2034 433 | #define VMX_VM_EXECUTION_CONTROL_TERTIARY_PROC_BASED_HIGH_ENCODE 0x2035 434 | #define VMX_PCONFIG_EXITING_FULL_ENCODE 0x203E 435 | #define VMX_PCONFIG_EXITING_HIGH_ENCODE 0x203f 436 | #define VMX_PASID_LOW_FULL_ENCODE 0x2038 437 | #define VMX_PASID_LOW_HIGH_ENCODE 0x2039 438 | #define VMX_PASID_HIGH_FULL_ENCODE 0x203A 439 | #define VMX_PASID_HIGH_HIGH_ENCODE 0x203b 440 | #define VMX_HOST_IA32_INTERRUPT_SSP_TABLE_ADDR_ENCODE 0x6C1C 441 | #define VMX_GUEST_IA32_S_CET_ENCODE 0x6828 442 | #define VMX_GUEST_SSP_ENCODE 0x682A 443 | #define VMX_GUEST_IA32_INTERRUPT_SSP_TABLE_ADDR_ENCODE 0x682C 444 | #define VMX_HOST_IA32_S_CET_ENCODE 0x6C18 445 | #define VMX_HOST_SSP_ENCODE 0x6C1A 446 | #define VMX_HKID_ENCODE 0x4026 447 | #define VMX_GUEST_SHARED_EPT_POINTER_FULL_ENCODE 0x203C 448 | #define VMX_GUEST_SHARED_EPT_POINTER_HIGH_ENCODE 0x203D 449 | #define VMX_NO_COMMIT_THRESHOLD_ENCODE 0x4024 450 | #define VMX_GUEST_LBR_CTL_FULL_ENCODE 0x2816 451 | #define VMX_GUEST_PKRS_FULL_ENCODE 0x2818 452 | #define VMX_HLATP_FULL_ENCODE 0x2040 453 | #define VMX_IA32_SPEC_CTRL_MASK 0x204A 454 | #define VMX_IA32_SPEC_CTRL_SHADOW 0x204C -------------------------------------------------------------------------------- /Lib/vm.c: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | #include 5 | #include 6 | #include 7 | #include "common.h" 8 | 9 | #pragma comment(lib, "WinHvPlatform.lib") 10 | 11 | UINT64 12 | GetRegister64(CORNELIUS_VM *Vm, UINT32 VcpuNum, WHV_REGISTER_NAME Name) 13 | { 14 | WHV_REGISTER_VALUE Value; 15 | HRESULT hRes; 16 | 17 | hRes = WHvGetVirtualProcessorRegisters(Vm->Partition, VcpuNum, 18 | &Name, 1, &Value); 19 | FAIL_IF_ERROR(hRes); 20 | 21 | return Value.Reg64; 22 | } 23 | 24 | VOID 25 | SetRegister64(CORNELIUS_VM *Vm, UINT32 VcpuNum, WHV_REGISTER_NAME Name, UINT64 Val64) 26 | { 27 | WHV_REGISTER_VALUE Value; 28 | HRESULT hRes; 29 | 30 | ZeroMemory(&Value, sizeof(Value)); 31 | Value.Reg64 = Val64; 32 | 33 | hRes = WHvSetVirtualProcessorRegisters(Vm->Partition, VcpuNum, 34 | &Name, 1, &Value); 35 | FAIL_IF_ERROR(hRes); 36 | } 37 | 38 | VOID 39 | MarkGpaNotDirty(CORNELIUS_VM *Vm, UINT64 Gpa, SIZE_T Size) 40 | { 41 | PUINT64 Bitmap = Vm->DirtyGpasBitmap; 42 | SIZE_T GpaOff; 43 | SIZE_T GpaBit; 44 | SIZE_T i; 45 | 46 | Gpa = GPA_WITHOUT_HKID(Gpa); 47 | 48 | for (i = 0; i < Size; i += PAGE_SIZE) { 49 | GpaOff = ((Gpa + i) / PAGE_SIZE) / 64ULL; 50 | GpaBit = ((Gpa + i) / PAGE_SIZE) % 64ULL; 51 | 52 | _InterlockedAnd64((LONG64 *)&Bitmap[GpaOff], ~(1ULL << GpaBit)); 53 | } 54 | } 55 | 56 | static VOID 57 | MarkGpaDirty(CORNELIUS_VM *Vm, UINT64 Gpa, SIZE_T Size) 58 | { 59 | PUINT64 Bitmap = Vm->DirtyGpasBitmap; 60 | SIZE_T GpaOff; 61 | SIZE_T GpaBit; 62 | SIZE_T i; 63 | 64 | Gpa = GPA_WITHOUT_HKID(Gpa); 65 | 66 | for (i = 0; i < Size; i += PAGE_SIZE) { 67 | GpaOff = ((Gpa + i) / PAGE_SIZE) / 64ULL; 68 | GpaBit = ((Gpa + i) / PAGE_SIZE) % 64ULL; 69 | 70 | _InterlockedOr64((LONG64 *)&Bitmap[GpaOff], 1ULL << GpaBit); 71 | } 72 | } 73 | 74 | static VOID 75 | MarkGpaMapped(CORNELIUS_VM *Vm, UINT64 Gpa, SIZE_T Size) 76 | { 77 | PUINT64 Bitmap = Vm->MappedGpasBitmap; 78 | SIZE_T GpaOff; 79 | SIZE_T GpaBit; 80 | SIZE_T i; 81 | 82 | // 83 | // Note: we only track GPAs in Keyid 0. 84 | // 85 | 86 | if (Gpa >= Vm->LastPa) { 87 | return; 88 | } 89 | 90 | for (i = 0; i < Size; i += PAGE_SIZE) { 91 | GpaOff = ((Gpa + i) / PAGE_SIZE) / 64ULL; 92 | GpaBit = ((Gpa + i) / PAGE_SIZE) % 64ULL; 93 | 94 | _InterlockedOr64((LONG64 *)&Bitmap[GpaOff], 1ULL << GpaBit); 95 | } 96 | } 97 | 98 | static VOID 99 | MarkGpaUnmapped(CORNELIUS_VM *Vm, UINT64 Gpa, SIZE_T Size) 100 | { 101 | PUINT64 Bitmap = Vm->MappedGpasBitmap; 102 | SIZE_T GpaOff; 103 | SIZE_T GpaBit; 104 | SIZE_T i; 105 | 106 | if (Gpa >= Vm->LastPa) { 107 | return; 108 | } 109 | 110 | for (i = 0; i < Size; i += PAGE_SIZE) { 111 | GpaOff = ((Gpa + i) / PAGE_SIZE) / 64ULL; 112 | GpaBit = ((Gpa + i) / PAGE_SIZE) % 64ULL; 113 | 114 | _InterlockedAnd64((LONG64 *)&Bitmap[GpaOff], ~(1ULL << GpaBit)); 115 | } 116 | } 117 | 118 | VOID 119 | MapGpa(CORNELIUS_VM *Vm, UINT64 Gpa, SIZE_T Size) 120 | { 121 | HRESULT hRes; 122 | 123 | if (GPA_WITHOUT_HKID(Gpa + Size) > Vm->LastPa) { 124 | FATAL("GPA_WITHOUT_HKID(Gpa + Size) > Vm->LastPa"); 125 | } 126 | 127 | Size = ALIGN_UP_BY(Gpa + Size, PAGE_SIZE) - ALIGN_DOWN_BY(Gpa, PAGE_SIZE); 128 | Gpa = ALIGN_DOWN_BY(Gpa, PAGE_SIZE); 129 | 130 | hRes = WHvMapGpaRange(Vm->Partition, 131 | GPA_TO_HVA(Vm, Gpa), 132 | Gpa, 133 | Size, 134 | WHvMapGpaRangeFlagRead | WHvMapGpaRangeFlagWrite); 135 | if (FAILED(hRes)) { 136 | printf("[!] MapGpa failed with Gpa=0x%llx Size=0x%llx\n", Gpa, Size); 137 | exit(-1); 138 | } 139 | 140 | MarkGpaDirty(Vm, Gpa, Size); 141 | MarkGpaMapped(Vm, Gpa, Size); 142 | } 143 | 144 | VOID 145 | MapGpaExecutable(CORNELIUS_VM *Vm, UINT64 Gpa, SIZE_T Size) 146 | { 147 | HRESULT hRes; 148 | 149 | hRes = WHvMapGpaRange(Vm->Partition, 150 | GPA_TO_HVA(Vm, Gpa), 151 | Gpa, 152 | Size, 153 | WHvMapGpaRangeFlagRead | WHvMapGpaRangeFlagWrite | WHvMapGpaRangeFlagExecute); 154 | FAIL_IF_ERROR(hRes); 155 | 156 | MarkGpaDirty(Vm, Gpa, Size); 157 | MarkGpaMapped(Vm, Gpa, Size); 158 | } 159 | 160 | VOID 161 | UnmapGpa(CORNELIUS_VM *Vm, UINT64 Gpa, SIZE_T Size) 162 | { 163 | HRESULT hRes; 164 | 165 | hRes = WHvUnmapGpaRange(Vm->Partition, Gpa, Size); 166 | FAIL_IF_ERROR(hRes); 167 | 168 | MarkGpaUnmapped(Vm, Gpa, Size); 169 | } 170 | 171 | static VOID 172 | CreateVCPU(CORNELIUS_VM *Vm, UINT32 VcpuNum) 173 | { 174 | HRESULT hRes; 175 | 176 | if (VcpuNum >= Vm->NumberOfVcpus) { 177 | FATAL("VcpuNum too large"); 178 | } 179 | 180 | hRes = WHvCreateVirtualProcessor(Vm->Partition, VcpuNum, 0); 181 | FAIL_IF_ERROR(hRes); 182 | 183 | InitializeTdxState(Vm, VcpuNum); 184 | InitializeVcpuState(Vm, VcpuNum); 185 | } 186 | 187 | CORNELIUS_VM * 188 | CreateVM(CORNELIUS_VM_CONFIG *VmConfig) 189 | { 190 | WHV_PARTITION_PROPERTY PartitionProperty; 191 | WHV_PARTITION_HANDLE Partition; 192 | WHV_CAPABILITY Capability; 193 | UINT32 WrittenSizeInBytes; 194 | CORNELIUS_VM *Vm; 195 | HRESULT hRes; 196 | SIZE_T i; 197 | 198 | Vm = malloc(offsetof(CORNELIUS_VM, Vcpus[VmConfig->NumberOfVcpus])); 199 | if (Vm == NULL) { 200 | return NULL; 201 | } 202 | 203 | memset(Vm, 0, offsetof(CORNELIUS_VM, Vcpus[VmConfig->NumberOfVcpus])); 204 | Vm->NumberOfVcpus = VmConfig->NumberOfVcpus; 205 | memcpy(&Vm->VmConfig, VmConfig, sizeof(*VmConfig)); 206 | 207 | // 208 | // Create the partition. 209 | // 210 | 211 | hRes = WHvCreatePartition(&Partition); 212 | FAIL_IF_ERROR(hRes); 213 | 214 | // 215 | // Set the processor features. 216 | // 217 | 218 | hRes = WHvGetCapability(WHvCapabilityCodeProcessorFeatures, &Capability, sizeof(Capability), &WrittenSizeInBytes); 219 | FAIL_IF_ERROR(hRes); 220 | if (WrittenSizeInBytes != sizeof(Capability.ProcessorFeatures)) { 221 | FATAL("WrittenSizeInBytes too small"); 222 | } 223 | 224 | memset(&PartitionProperty, 0, sizeof(PartitionProperty)); 225 | PartitionProperty.ProcessorFeatures = Capability.ProcessorFeatures; 226 | hRes = WHvSetPartitionProperty(Partition, WHvPartitionPropertyCodeProcessorFeatures, &PartitionProperty, sizeof(PartitionProperty)); 227 | FAIL_IF_ERROR(hRes); 228 | 229 | // 230 | // Set the perfmon features. 231 | // 232 | 233 | hRes = WHvGetCapability(WHvCapabilityCodeProcessorPerfmonFeatures, &Capability, sizeof(Capability), &WrittenSizeInBytes); 234 | FAIL_IF_ERROR(hRes); 235 | if (WrittenSizeInBytes != sizeof(Capability.ProcessorPerfmonFeatures)) { 236 | FATAL("WrittenSizeInBytes too small"); 237 | } 238 | 239 | memset(&PartitionProperty, 0, sizeof(PartitionProperty)); 240 | PartitionProperty.ProcessorPerfmonFeatures = Capability.ProcessorPerfmonFeatures; 241 | hRes = WHvSetPartitionProperty(Partition, WHvPartitionPropertyCodeProcessorPerfmonFeatures, &PartitionProperty, sizeof(PartitionProperty)); 242 | FAIL_IF_ERROR(hRes); 243 | 244 | Vm->CpuSupport.PerfMon = Capability.ProcessorPerfmonFeatures.PmuSupport != 0; 245 | 246 | // 247 | // Set the processor features banks. 248 | // 249 | 250 | hRes = WHvGetCapability(WHvCapabilityCodeProcessorFeaturesBanks, &Capability, sizeof(Capability), &WrittenSizeInBytes); 251 | FAIL_IF_ERROR(hRes); 252 | if (WrittenSizeInBytes != sizeof(Capability.ProcessorFeaturesBanks)) { 253 | FATAL("WrittenSizeInBytes too small"); 254 | } 255 | 256 | if (!Capability.ProcessorFeaturesBanks.Bank1.CetSsSupport) { 257 | FATAL("CET_SS must be supported by the CPU"); 258 | } 259 | if (!Capability.ProcessorFeaturesBanks.Bank1.CetIbtSupport) { 260 | FATAL("CET_IBT must be supported by the CPU"); 261 | } 262 | 263 | memset(&PartitionProperty, 0, sizeof(PartitionProperty)); 264 | PartitionProperty.ProcessorFeaturesBanks = Capability.ProcessorFeaturesBanks; 265 | hRes = WHvSetPartitionProperty(Partition, WHvPartitionPropertyCodeProcessorFeaturesBanks, &PartitionProperty, sizeof(PartitionProperty)); 266 | FAIL_IF_ERROR(hRes); 267 | 268 | // 269 | // Set the processor XSAVE features. 270 | // 271 | 272 | hRes = WHvGetCapability(WHvCapabilityCodeProcessorXsaveFeatures, &Capability, sizeof(Capability), &WrittenSizeInBytes); 273 | FAIL_IF_ERROR(hRes); 274 | if (WrittenSizeInBytes != sizeof(Capability.ProcessorXsaveFeatures)) { 275 | FATAL("WrittenSizeInBytes too small"); 276 | } 277 | 278 | memset(&PartitionProperty, 0, sizeof(PartitionProperty)); 279 | PartitionProperty.ProcessorXsaveFeatures = Capability.ProcessorXsaveFeatures; 280 | hRes = WHvSetPartitionProperty(Partition, WHvPartitionPropertyCodeProcessorXsaveFeatures, &PartitionProperty, sizeof(PartitionProperty)); 281 | FAIL_IF_ERROR(hRes); 282 | 283 | // 284 | // Set the partition properties. 285 | // 286 | 287 | memset(&PartitionProperty, 0, sizeof(PartitionProperty)); 288 | PartitionProperty.ProcessorCount = Vm->NumberOfVcpus; 289 | hRes = WHvSetPartitionProperty(Partition, WHvPartitionPropertyCodeProcessorCount, &PartitionProperty, sizeof(PartitionProperty)); 290 | FAIL_IF_ERROR(hRes); 291 | 292 | memset(&PartitionProperty, 0, sizeof(PartitionProperty)); 293 | PartitionProperty.ExtendedVmExits.X64CpuidExit = 1; 294 | PartitionProperty.ExtendedVmExits.X64MsrExit = 1; 295 | PartitionProperty.ExtendedVmExits.ExceptionExit = 1; 296 | hRes = WHvSetPartitionProperty(Partition, WHvPartitionPropertyCodeExtendedVmExits, &PartitionProperty, sizeof(PartitionProperty)); 297 | FAIL_IF_ERROR(hRes); 298 | 299 | memset(&PartitionProperty, 0, sizeof(PartitionProperty)); 300 | // HV-DISCREPANCY: no way to specify #CP here 301 | PartitionProperty.ExceptionExitBitmap = 302 | (1 << WHvX64ExceptionTypeDivideErrorFault) | 303 | (1 << WHvX64ExceptionTypeDebugTrapOrFault) | 304 | (1 << WHvX64ExceptionTypeBreakpointTrap) | 305 | (1 << WHvX64ExceptionTypeOverflowTrap) | 306 | (1 << WHvX64ExceptionTypeBoundRangeFault) | 307 | (1 << WHvX64ExceptionTypeInvalidOpcodeFault) | 308 | (1 << WHvX64ExceptionTypeDeviceNotAvailableFault) | 309 | (1 << WHvX64ExceptionTypeDoubleFaultAbort) | 310 | (1 << WHvX64ExceptionTypeInvalidTaskStateSegmentFault) | 311 | (1 << WHvX64ExceptionTypeSegmentNotPresentFault) | 312 | (1 << WHvX64ExceptionTypeStackFault) | 313 | (1 << WHvX64ExceptionTypeGeneralProtectionFault) | 314 | (1 << WHvX64ExceptionTypePageFault) | 315 | (1 << WHvX64ExceptionTypeFloatingPointErrorFault) | 316 | (1 << WHvX64ExceptionTypeAlignmentCheckFault) | 317 | (1 << WHvX64ExceptionTypeMachineCheckAbort) | 318 | (1 << WHvX64ExceptionTypeSimdFloatingPointFault); 319 | hRes = WHvSetPartitionProperty(Partition, WHvPartitionPropertyCodeExceptionExitBitmap, &PartitionProperty, sizeof(PartitionProperty)); 320 | FAIL_IF_ERROR(hRes); 321 | 322 | memset(&PartitionProperty, 0, sizeof(PartitionProperty)); 323 | PartitionProperty.X64MsrExitBitmap.UnhandledMsrs = 1; 324 | hRes = WHvSetPartitionProperty(Partition, WHvPartitionPropertyCodeX64MsrExitBitmap, &PartitionProperty, sizeof(PartitionProperty)); 325 | FAIL_IF_ERROR(hRes); 326 | 327 | // 328 | // Conclude the partition setup. 329 | // 330 | 331 | hRes = WHvSetupPartition(Partition); 332 | FAIL_IF_ERROR(hRes); 333 | 334 | Vm->Partition = Partition; 335 | 336 | // 337 | // Adjust the LastPa for the ASAN shadow. 338 | // 339 | 340 | Vm->HiddenPaCursor = Vm->VmConfig.LastPa; 341 | Vm->LastPa = Vm->VmConfig.LastPa; 342 | 343 | if (Vm->VmConfig.HasSanitizers) { 344 | // Add the maximum size of the ASAN shadow 345 | Vm->LastPa += Vm->VmConfig.PSeamldrRange.Size / 8; 346 | // Add the maximum size of the SanCov bitmap 347 | Vm->LastPa += GetSancovMaxBitmapSize(Vm); 348 | } 349 | 350 | if (Vm->LastPa > CORNELIUS_KEYSPACE_SIZE) { 351 | FATAL("Vm->LastPa > CORNELIUS_KEYSPACE_SIZE"); 352 | } 353 | 354 | // 355 | // Create the GPAs bitmaps. 356 | // 357 | 358 | Vm->DirtyGpasBitmap = calloc(1, GPAS_BITMAP_SIZE(Vm)); 359 | if (Vm->DirtyGpasBitmap == NULL) { 360 | FATAL("Vm->DirtyGpasBitmap == NULL"); 361 | } 362 | 363 | Vm->MappedGpasBitmap = calloc(1, GPAS_BITMAP_SIZE(Vm)); 364 | if (Vm->MappedGpasBitmap == NULL) { 365 | FATAL("Vm->MappedGpasBitmap == NULL"); 366 | } 367 | 368 | // 369 | // Map the CMRs in Keyid 0. 370 | // 371 | 372 | MapCmrsInKeyidSpace(Vm, 0); 373 | 374 | // 375 | // Map the AddressSpace HVAs, and the SEAMRR GPAs. 376 | // 377 | 378 | Vm->AddressSpaceHva = (PUINT8)VirtualAlloc(NULL, Vm->LastPa, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); 379 | if (Vm->AddressSpaceHva == NULL) { 380 | FATAL("Vm->AddressSpaceHva == NULL"); 381 | } 382 | 383 | Vm->SeamrrVa = GPA_TO_HVA(Vm, Vm->VmConfig.SeamrrBase); 384 | 385 | MapGpaExecutable(Vm, Vm->VmConfig.SeamrrBase, Vm->VmConfig.SeamrrSize); 386 | 387 | Vm->IsPseamldrRangeActive = TRUE; 388 | 389 | // 390 | // Initialize the P-SEAMLDR lock. 391 | // 392 | 393 | Vm->PseamldrLock = CreateMutex(NULL, FALSE, NULL); 394 | 395 | // 396 | // Initialize the SEAMRR. 397 | // 398 | 399 | InitializeSeamRr(Vm); 400 | 401 | // 402 | // Initialize the SEAMLDR state. 403 | // 404 | 405 | InitializeSeamldrState(Vm); 406 | 407 | // 408 | // Create the VCPUs. 409 | // 410 | 411 | for (i = 0; i < Vm->NumberOfVcpus; i++) { 412 | CreateVCPU(Vm, (UINT32)i); 413 | } 414 | 415 | return Vm; 416 | } 417 | 418 | INT 419 | GetVcpuLogLevel(CORNELIUS_VM *Vm, UINT32 VcpuNum) 420 | { 421 | return Vm->Vcpus[VcpuNum].LogLevel; 422 | } 423 | 424 | VOID 425 | SetVcpuLogLevel(CORNELIUS_VM *Vm, UINT32 VcpuNum, INT LogLevel) 426 | { 427 | Vm->Vcpus[VcpuNum].LogLevel = LogLevel; 428 | } 429 | 430 | UINT32 431 | GetNumberOfVcpus(CORNELIUS_VM *Vm) 432 | { 433 | return Vm->NumberOfVcpus; 434 | } 435 | 436 | VOID 437 | SetPendingException(CORNELIUS_VM *Vm, UINT32 VcpuNum, WHV_EXCEPTION_TYPE ExceptionType) 438 | { 439 | Vm->Vcpus[VcpuNum].PendingExceptionType = ExceptionType; 440 | Vm->Vcpus[VcpuNum].HasPendingException = TRUE; 441 | } 442 | 443 | static VOID 444 | InjectExceptionIfAny(CORNELIUS_VM *Vm, UINT32 VcpuNum) 445 | { 446 | WHV_X64_PENDING_INTERRUPTION_REGISTER Intr; 447 | 448 | if (!Vm->Vcpus[VcpuNum].HasPendingException) { 449 | return; 450 | } 451 | 452 | Intr.AsUINT64 = 0; 453 | Intr.DeliverErrorCode = 1; 454 | Intr.InterruptionType = WHvX64PendingException; 455 | Intr.InterruptionPending = 1; 456 | Intr.InterruptionVector = Vm->Vcpus[VcpuNum].PendingExceptionType; 457 | 458 | Vm->Vcpus[VcpuNum].HasPendingException = FALSE; 459 | 460 | SetRegister64(Vm, VcpuNum, WHvRegisterPendingInterruption, Intr.AsUINT64); 461 | } 462 | 463 | static VOID 464 | DumpVCPUCallStack(CORNELIUS_VM *Vm, UINT32 VcpuNum) 465 | { 466 | UINT64 Rbp; 467 | PUINT64 Frame; 468 | 469 | Rbp = GetRegister64(Vm, VcpuNum, WHvX64RegisterRbp); 470 | 471 | while (TRUE) { 472 | if (Rbp == 0) { 473 | break; 474 | } 475 | 476 | Frame = (PUINT64)GvaToHva(Vm, VcpuNum, Rbp); 477 | LogVcpuErr(Vm, VcpuNum, "> 0x%llx\n", *(Frame+1)); 478 | Rbp = *Frame; 479 | } 480 | } 481 | 482 | enum VcpuAction 483 | RunVCPU(CORNELIUS_VM *Vm, UINT32 VcpuNum, enum VcpuMode VcpuMode) 484 | { 485 | WHV_RUN_VP_EXIT_CONTEXT ExitContext; 486 | enum VcpuAction Action; 487 | HRESULT hRes; 488 | 489 | InstallVcpuState(Vm, VcpuNum); 490 | 491 | if (VcpuMode == VcpuModePseamldr) { 492 | Vm->Vcpus[VcpuNum].IsSeamldr = TRUE; 493 | } else { 494 | if (!Vm->SeamReady) { 495 | LogVcpuErr(Vm, VcpuNum, "Seam not ready\n"); 496 | return VcpuActionSeamNotReady; 497 | } 498 | Vm->Vcpus[VcpuNum].IsSeamldr = FALSE; 499 | } 500 | 501 | if (VcpuMode == VcpuModePseamldr || VcpuMode == VcpuModeTdxModule) { 502 | Action = SetEntryVmcsPtr(Vm, VcpuNum); 503 | if (Action != VcpuActionKeepRunning) { 504 | return Action; 505 | } 506 | } 507 | 508 | if (VcpuMode == VcpuModePseamldr) { 509 | PseamldrLock(Vm); 510 | InstallSeamldrState(Vm, VcpuNum); 511 | SetPseamldrRangeActive(Vm, TRUE); 512 | LogVcpuOk(Vm, VcpuNum, "Running in P-SEAMLDR mode\n", VcpuNum); 513 | } else { 514 | InstallTdxState(Vm, VcpuNum); 515 | LogVcpuOk(Vm, VcpuNum, "Running in TDX mode\n", VcpuNum); 516 | } 517 | 518 | Action = VcpuActionKeepRunning; 519 | 520 | while (Action == VcpuActionKeepRunning) { 521 | InjectExceptionIfAny(Vm, VcpuNum); 522 | 523 | hRes = WHvRunVirtualProcessor(Vm->Partition, VcpuNum, &ExitContext, sizeof(ExitContext)); 524 | FAIL_IF_ERROR(hRes); 525 | 526 | switch (ExitContext.ExitReason) { 527 | case WHvRunVpExitReasonMemoryAccess: 528 | LogVcpuErr(Vm, VcpuNum, "WHvRunVpExitReasonMemoryAccess: GPA=0x%llx\n", ExitContext.MemoryAccess.Gpa); 529 | LogVcpuErr(Vm, VcpuNum, "RIP = %llx\n", GetRegister64(Vm, VcpuNum, WHvX64RegisterRip)); 530 | Action = VcpuActionEmulationError; 531 | break; 532 | case WHvRunVpExitReasonException: 533 | switch (ExitContext.VpException.ExceptionType) { 534 | case WHvX64ExceptionTypeDivideErrorFault: 535 | LogVcpuErr(Vm, VcpuNum, "Got #DE, RIP = 0x%llx\n", GetRegister64(Vm, VcpuNum, WHvX64RegisterRip)); 536 | Action = VcpuActionSeamCrash; 537 | break; 538 | case WHvX64ExceptionTypeInvalidOpcodeFault: 539 | Action = EmulateOnUD(Vm, VcpuNum, &ExitContext); 540 | break; 541 | case WHvX64ExceptionTypeGeneralProtectionFault: 542 | Action = EmulateOnGP(Vm, VcpuNum, &ExitContext); 543 | if (Action == VcpuActionEmulationError) { 544 | LogVcpuErr(Vm, VcpuNum, "Got #GP, ErrorCodeValid = %d, ErrorCode = 0x%x\n", 545 | ExitContext.VpException.ExceptionInfo.ErrorCodeValid, 546 | ExitContext.VpException.ErrorCode); 547 | Action = VcpuActionSeamCrash; 548 | } 549 | break; 550 | case WHvX64ExceptionTypePageFault: 551 | LogVcpuErr(Vm, VcpuNum, "Got #PF, ErrorCodeValid = %d, ErrorCode = 0x%x\n", 552 | ExitContext.VpException.ExceptionInfo.ErrorCodeValid, 553 | ExitContext.VpException.ErrorCode); 554 | LogVcpuErr(Vm, VcpuNum, "RIP = %llx\n", GetRegister64(Vm, VcpuNum, WHvX64RegisterRip)); 555 | Action = VcpuActionSeamCrash; 556 | break; 557 | default: 558 | LogVcpuErr(Vm, VcpuNum, "Got exception %x, ErrorCode=%x\n", ExitContext.VpException.ExceptionType, ExitContext.VpException.ErrorCode); 559 | LogVcpuErr(Vm, VcpuNum, "RIP = %llx\n", GetRegister64(Vm, VcpuNum, WHvX64RegisterRip)); 560 | LogVcpuErr(Vm, VcpuNum, "ErrorCodeValid = %d\n", ExitContext.VpException.ExceptionInfo.ErrorCodeValid); 561 | Action = VcpuActionSeamCrash; 562 | break; 563 | } 564 | break; 565 | case WHvRunVpExitReasonX64Cpuid: 566 | Action = EmulateCPUID(Vm, VcpuNum, &ExitContext); 567 | break; 568 | case WHvRunVpExitReasonX64MsrAccess: 569 | if (ExitContext.MsrAccess.AccessInfo.IsWrite) { 570 | Action = EmulateWRMSR(Vm, VcpuNum, &ExitContext); 571 | } else { 572 | Action = EmulateRDMSR(Vm, VcpuNum, &ExitContext); 573 | } 574 | break; 575 | case WHvRunVpExitReasonX64Halt: 576 | LogVcpuErr(Vm, VcpuNum, "WHvRunVpExitReasonX64Halt\n"); 577 | Action = VcpuActionEmulationError; 578 | break; 579 | case WHvRunVpExitReasonX64IoPortAccess: 580 | Action = EmulateOnIO(Vm, VcpuNum, &ExitContext); 581 | break; 582 | default: 583 | LogVcpuErr(Vm, VcpuNum, "Unknown vmexit %x\n", ExitContext.ExitReason); 584 | Action = VcpuActionEmulationError; 585 | break; 586 | } 587 | } 588 | 589 | switch (Action) { 590 | case VcpuActionEmulationError: 591 | LogVcpuErr(Vm, VcpuNum, "Emulation error, RIP=%llx, callstack:\n", ExitContext.VpContext.Rip); 592 | DumpVCPUCallStack(Vm, VcpuNum); 593 | break; 594 | case VcpuActionInvariantViolated: 595 | LogVcpuErr(Vm, VcpuNum, "Invariant violated, callstack:\n"); 596 | DumpVCPUCallStack(Vm, VcpuNum); 597 | break; 598 | case VcpuActionSeamPanic: 599 | LogVcpuErr(Vm, VcpuNum, "Panicked, RIP=%llx, callstack:\n", 600 | GetRegister64(Vm, VcpuNum, WHvX64RegisterRip)); 601 | DumpVCPUCallStack(Vm, VcpuNum); 602 | break; 603 | case VcpuActionSeamCrash: 604 | LogVcpuErr(Vm, VcpuNum, "Crashed, callstack:\n"); 605 | DumpVCPUCallStack(Vm, VcpuNum); 606 | break; 607 | case VcpuActionSeamRet: 608 | LogVcpuOk(Vm, VcpuNum, "Completed with SEAMRET, RIP=%llx, RAX=0x%llx\n", 609 | GetRegister64(Vm, VcpuNum, WHvX64RegisterRip), 610 | GetRegister64(Vm, VcpuNum, WHvX64RegisterRax)); 611 | if (VcpuMode == VcpuModePseamldr) { 612 | SyncTdxStateWithVmcs(Vm); 613 | } 614 | SyncVcpuStateWithContext(Vm, VcpuNum); 615 | break; 616 | case VcpuActionVmlaunch: 617 | LogVcpuOk(Vm, VcpuNum, "Completed with VMLAUNCH, RIP=%llx, VMCS=0x%llx\n", 618 | GetRegister64(Vm, VcpuNum, WHvX64RegisterRip), 619 | GetVmcsPtr(Vm, VcpuNum)); 620 | SyncVcpuStateWithContext(Vm, VcpuNum); 621 | SyncVcpuStateWithTdVmcs(Vm, VcpuNum); 622 | break; 623 | case VcpuActionVmresume: 624 | LogVcpuOk(Vm, VcpuNum, "Completed with VMRESUME, RIP=%llx, VMCS=0x%llx\n", 625 | GetRegister64(Vm, VcpuNum, WHvX64RegisterRip), 626 | GetVmcsPtr(Vm, VcpuNum)); 627 | SyncVcpuStateWithContext(Vm, VcpuNum); 628 | SyncVcpuStateWithTdVmcs(Vm, VcpuNum); 629 | break; 630 | default: 631 | break; 632 | } 633 | 634 | if (Action == VcpuActionSeamRet) { 635 | // On SEAMRET, the microcode performs a VMCLEAR of the current VMCS. 636 | VmcsUncache(Vm, VcpuNum, GetVmcsPtr(Vm, VcpuNum)); 637 | } 638 | 639 | if (VcpuMode == VcpuModePseamldr) { 640 | SetPseamldrRangeActive(Vm, FALSE); 641 | PseamldrUnlock(Vm); 642 | } 643 | 644 | return Action; 645 | } --------------------------------------------------------------------------------