├── 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 | }
--------------------------------------------------------------------------------