On 9/4/2025 2:54 PM, Sagi Shahar wrote:
From: Erdem Aktas erdemaktas@google.com
Add code to boot a TDX test VM. Since TDX registers are inaccesible to
inaccesible -> inaccessible
KVM, the boot code loads the relevant values from memory into the registers before jumping to the guest code.
Signed-off-by: Erdem Aktas erdemaktas@google.com Co-developed-by: Ackerley Tng ackerleytng@google.com Signed-off-by: Ackerley Tng ackerleytng@google.com Co-developed-by: Sagi Shahar sagis@google.com Signed-off-by: Sagi Shahar sagis@google.com
Reviewed-by: Binbin Wu binbin.wu@linux.intel.com
tools/testing/selftests/kvm/Makefile.kvm | 3 + .../selftests/kvm/include/x86/tdx/td_boot.h | 5 ++ .../kvm/include/x86/tdx/td_boot_asm.h | 16 +++++ .../selftests/kvm/lib/x86/tdx/td_boot.S | 60 +++++++++++++++++++ 4 files changed, 84 insertions(+) create mode 100644 tools/testing/selftests/kvm/include/x86/tdx/td_boot_asm.h create mode 100644 tools/testing/selftests/kvm/lib/x86/tdx/td_boot.S
diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm index 3f93c093b046..d11d02e17cc5 100644 --- a/tools/testing/selftests/kvm/Makefile.kvm +++ b/tools/testing/selftests/kvm/Makefile.kvm @@ -31,6 +31,7 @@ LIBKVM_x86 += lib/x86/sev.c LIBKVM_x86 += lib/x86/svm.c LIBKVM_x86 += lib/x86/ucall.c LIBKVM_x86 += lib/x86/vmx.c +LIBKVM_x86 += lib/x86/tdx/td_boot.S LIBKVM_arm64 += lib/arm64/gic.c LIBKVM_arm64 += lib/arm64/gic_v3.c @@ -336,6 +337,8 @@ $(LIBKVM_ASM_DEFS_OBJ): $(OUTPUT)/%.s: %.c FORCE $(LIBKVM_STRING_OBJ): $(OUTPUT)/%.o: %.c $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c -ffreestanding $< -o $@ +$(OUTPUT)/lib/x86/tdx/td_boot.o: $(OUTPUT)/include/x86/tdx/td_boot_offsets.h
- $(OUTPUT)/include/x86/tdx/td_boot_offsets.h: $(OUTPUT)/lib/x86/tdx/td_boot_offsets.s FORCE $(call filechk,offsets,__TDX_BOOT_OFFSETS_H__)
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 8eda3ce10220..17c3083da9ca 100644 --- a/tools/testing/selftests/kvm/include/x86/tdx/td_boot.h +++ b/tools/testing/selftests/kvm/include/x86/tdx/td_boot.h @@ -66,4 +66,9 @@ struct td_boot_parameters { struct td_per_vcpu_parameters per_vcpu[]; }; +void td_boot(void); +void td_boot_code_end(void);
+#define TD_BOOT_CODE_SIZE (td_boot_code_end - td_boot)
- #endif /* SELFTEST_TDX_TD_BOOT_H */
diff --git a/tools/testing/selftests/kvm/include/x86/tdx/td_boot_asm.h b/tools/testing/selftests/kvm/include/x86/tdx/td_boot_asm.h new file mode 100644 index 000000000000..10b4b527595c --- /dev/null +++ b/tools/testing/selftests/kvm/include/x86/tdx/td_boot_asm.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef SELFTEST_TDX_TD_BOOT_ASM_H +#define SELFTEST_TDX_TD_BOOT_ASM_H
+/*
- GPA where TD boot parameters will be loaded.
- TD_BOOT_PARAMETERS_GPA is arbitrarily chosen to
- be within the 4GB address space
- provide enough contiguous memory for the struct td_boot_parameters such
- that there is one struct td_per_vcpu_parameters for KVM_MAX_VCPUS
- */
+#define TD_BOOT_PARAMETERS_GPA 0xffff0000
+#endif // SELFTEST_TDX_TD_BOOT_ASM_H diff --git a/tools/testing/selftests/kvm/lib/x86/tdx/td_boot.S b/tools/testing/selftests/kvm/lib/x86/tdx/td_boot.S new file mode 100644 index 000000000000..7aa33caa9a78 --- /dev/null +++ b/tools/testing/selftests/kvm/lib/x86/tdx/td_boot.S @@ -0,0 +1,60 @@ +/* SPDX-License-Identifier: GPL-2.0-only */
+#include "tdx/td_boot_asm.h" +#include "tdx/td_boot_offsets.h" +#include "processor_asm.h"
+.code32
+.globl td_boot +td_boot:
- /* In this procedure, edi is used as a temporary register. */
- cli
- /* Paging is off. */
- movl $TD_BOOT_PARAMETERS_GPA, %ebx
- /*
* Find the address of struct td_per_vcpu_parameters for this
* vCPU based on esi (TDX spec: initialized with vCPU id). Put
* struct address into register for indirect addressing.
*/
- movl $SIZEOF_TD_PER_VCPU_PARAMETERS, %eax
- mul %esi
- leal TD_BOOT_PARAMETERS_PER_VCPU(%ebx), %edi
- addl %edi, %eax
- /* Setup stack. */
- movl TD_PER_VCPU_PARAMETERS_ESP_GVA(%eax), %esp
- /* Setup GDT. */
- leal TD_BOOT_PARAMETERS_GDT(%ebx), %edi
- lgdt (%edi)
- /* Setup IDT. */
- leal TD_BOOT_PARAMETERS_IDT(%ebx), %edi
- lidt (%edi)
- /*
* Set up control registers (There are no instructions to mov from
* memory to control registers, hence use edi as a scratch register).
*/
- movl TD_BOOT_PARAMETERS_CR4(%ebx), %edi
- movl %edi, %cr4
- movl TD_BOOT_PARAMETERS_CR3(%ebx), %edi
- movl %edi, %cr3
- movl TD_BOOT_PARAMETERS_CR0(%ebx), %edi
- movl %edi, %cr0
- /* Switching to 64bit mode after ljmp and then jump to guest code */
- ljmp $(KERNEL_CS),$1f
+1:
- jmp *TD_PER_VCPU_PARAMETERS_GUEST_CODE(%eax)
+/* Leave marker so size of td_boot code can be computed. */ +.globl td_boot_code_end +td_boot_code_end:
+/* Disable executable stack. */ +.section .note.GNU-stack,"",%progbits