From: Sagi Shahar <[email protected]>

Because the reset vector is located just 16 bytes below the 4GB
boundary, there is not enough space to fit the entire TDX boot code. To
solve this, insert a small trampoline at the reset vector that jumps to
the actual boot code.

Place the boot code immediately in front of the trampoline. Because they
are contiguous, they can be copied and mapped with a single operation.

Use virt_map() to create an identity map in this memory region to allow
for seamless transition from paging-disabled to paging-enabled code.

Suggested-by: Sean Christopherson <[email protected]>
Co-developed-by: Erdem Aktas <[email protected]>
Signed-off-by: Erdem Aktas <[email protected]>
Signed-off-by: Sagi Shahar <[email protected]>
Signed-off-by: Lisa Wang <[email protected]>
Reviewed-by: Binbin Wu <[email protected]>
Reviewed-by: Xiaoyao Li <[email protected]>
---
 .../selftests/kvm/include/x86/tdx/td_boot.h        |  2 +-
 .../selftests/kvm/include/x86/tdx/tdx_util.h       |  1 +
 tools/testing/selftests/kvm/lib/x86/processor.c    |  4 ++-
 tools/testing/selftests/kvm/lib/x86/tdx/td_boot.S  |  6 ++++
 tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c | 35 ++++++++++++++++++++++
 5 files changed, 46 insertions(+), 2 deletions(-)

diff --git a/tools/testing/selftests/kvm/include/x86/tdx/td_boot.h 
b/tools/testing/selftests/kvm/include/x86/tdx/td_boot.h
index 577e7b23c51c..8f47a3893f59 100644
--- a/tools/testing/selftests/kvm/include/x86/tdx/td_boot.h
+++ b/tools/testing/selftests/kvm/include/x86/tdx/td_boot.h
@@ -72,7 +72,7 @@ struct td_boot_parameters {
        struct td_per_vcpu_parameters per_vcpu[];
 };
 
-extern u8 td_boot[], td_boot_code_end[];
+extern u8 td_boot[], td_boot_code_end[], td_boot_reset_vector_trampoline[];
 
 #define TD_BOOT_CODE_SIZE (td_boot_code_end - td_boot)
 
diff --git a/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h 
b/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h
index 571f7ce4b8fe..e14566919601 100644
--- a/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h
+++ b/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h
@@ -47,5 +47,6 @@ static inline bool is_tdx_vm(struct kvm_vm *vm)
 })
 
 void tdx_init_vm(struct kvm_vm *vm);
+void tdx_vm_setup_boot_code_region(struct kvm_vm *vm);
 
 #endif /* SELFTESTS_TDX_TDX_UTIL_H */
diff --git a/tools/testing/selftests/kvm/lib/x86/processor.c 
b/tools/testing/selftests/kvm/lib/x86/processor.c
index 0c3779e7c275..e3cf56c9c852 100644
--- a/tools/testing/selftests/kvm/lib/x86/processor.c
+++ b/tools/testing/selftests/kvm/lib/x86/processor.c
@@ -818,8 +818,10 @@ void kvm_arch_vm_post_create(struct kvm_vm *vm, unsigned 
int nr_vcpus)
                vm_sev_ioctl(vm, KVM_SEV_INIT2, &init);
        }
 
-       if (is_tdx_vm(vm))
+       if (is_tdx_vm(vm)) {
                tdx_init_vm(vm);
+               tdx_vm_setup_boot_code_region(vm);
+       }
 
        r = __vm_ioctl(vm, KVM_GET_TSC_KHZ, NULL);
        TEST_ASSERT(r > 0, "KVM_GET_TSC_KHZ did not provide a valid TSC 
frequency.");
diff --git a/tools/testing/selftests/kvm/lib/x86/tdx/td_boot.S 
b/tools/testing/selftests/kvm/lib/x86/tdx/td_boot.S
index 726ec51e040e..a04011b91ae4 100644
--- a/tools/testing/selftests/kvm/lib/x86/tdx/td_boot.S
+++ b/tools/testing/selftests/kvm/lib/x86/tdx/td_boot.S
@@ -56,6 +56,12 @@ td_boot:
        ljmp $(KERNEL_CS),$1f
 1:
        jmp *TD_PER_VCPU_PARAMETERS_GUEST_CODE(%eax)
+       int3
+
+.globl td_boot_reset_vector_trampoline
+td_boot_reset_vector_trampoline:
+       jmp td_boot
+       int3
 
 /* Leave marker so size of td_boot code can be computed. */
 .globl td_boot_code_end
diff --git a/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c 
b/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c
index 3a8900ff2540..6187cfcf6a74 100644
--- a/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c
+++ b/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c
@@ -1,8 +1,43 @@
 // SPDX-License-Identifier: GPL-2.0-only
 
+#include <linux/sizes.h>
+
 #include "processor.h"
+#include "tdx/td_boot.h"
 #include "tdx/tdx_util.h"
 
+/* Arbitrarily selected to avoid overlaps with anything else */
+#define TD_BOOT_CODE_SLOT      20
+
+#define X86_RESET_VECTOR       0xfffffff0ul
+
+void tdx_vm_setup_boot_code_region(struct kvm_vm *vm)
+{
+       const size_t total_size = td_boot_code_end - td_boot;
+       const size_t boot_code_size = td_boot_reset_vector_trampoline - td_boot;
+       const gpa_t boot_code_gpa = X86_RESET_VECTOR - boot_code_size;
+       gpa_t alloc_gpa = round_down(boot_code_gpa, PAGE_SIZE);
+       size_t nr_pages = (SZ_4G - alloc_gpa) / PAGE_SIZE;
+       u64 gmem_flags = 0;
+       gpa_t gpa;
+       u8 *hva;
+
+       vm_mem_add(vm, VM_MEM_SRC_SHMEM, alloc_gpa, TD_BOOT_CODE_SLOT,
+                  nr_pages, KVM_MEM_GUEST_MEMFD, -1, 0, gmem_flags);
+
+       gpa = vm_phy_pages_alloc(vm, nr_pages, alloc_gpa, TD_BOOT_CODE_SLOT);
+       TEST_ASSERT(gpa == alloc_gpa, "Failed vm_phy_pages_alloc\n");
+
+       virt_map(vm, alloc_gpa, alloc_gpa, nr_pages);
+       hva = addr_gpa2hva(vm, boot_code_gpa);
+       memcpy(hva, td_boot, total_size);
+
+       hva += boot_code_size;
+       TEST_ASSERT(hva == addr_gpa2hva(vm, X86_RESET_VECTOR),
+                   "Expected RESET vector at hva 0x%lx, got %lx",
+                   (unsigned long)addr_gpa2hva(vm, X86_RESET_VECTOR), 
(unsigned long)hva);
+}
+
 static const struct kvm_tdx_capabilities *tdx_read_capabilities(struct kvm_vm 
*vm)
 {
        static struct kvm_tdx_capabilities *tdx_cap;

-- 
2.56.0.rc1.315.gc6ed9934b7-goog


Reply via email to