From: Sagi Shahar <[email protected]> Introduce `td_boot_parameters` and `td_per_vcpu_parameters`, and export their offsets to assembly via the kbuild infrastructure.
TDX guest registers are private and must be initialized by guest-side assembly. These structures allow the assembly code to retrieve boot parameters and index into per-vCPU data based on the vCPU ID, while keeping host and guest definitions synchronized. Use kbuild.h to expose the offsets into the structs from c code to assembly code. Reviewed-by: Binbin Wu <[email protected]> Co-developed-by: Ackerley Tng <[email protected]> Signed-off-by: Ackerley Tng <[email protected]> Signed-off-by: Sagi Shahar <[email protected]> Co-developed-by: Lisa Wang <[email protected]> Signed-off-by: Lisa Wang <[email protected]> --- tools/testing/selftests/kvm/.gitignore | 3 +- tools/testing/selftests/kvm/Makefile.kvm | 29 ++++++++- .../selftests/kvm/include/x86/tdx/td_boot.h | 69 ++++++++++++++++++++++ .../selftests/kvm/lib/x86/tdx/td_boot_offsets.c | 21 +++++++ 4 files changed, 119 insertions(+), 3 deletions(-) diff --git a/tools/testing/selftests/kvm/.gitignore b/tools/testing/selftests/kvm/.gitignore index 1d41a046a7bf..eef6055242b2 100644 --- a/tools/testing/selftests/kvm/.gitignore +++ b/tools/testing/selftests/kvm/.gitignore @@ -9,4 +9,5 @@ !config !settings !Makefile -!Makefile.kvm \ No newline at end of file +!Makefile.kvm +include/x86/**/*_offsets.h \ No newline at end of file diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm index e5769268936a..02fad7b35eac 100644 --- a/tools/testing/selftests/kvm/Makefile.kvm +++ b/tools/testing/selftests/kvm/Makefile.kvm @@ -19,6 +19,8 @@ LIBKVM += lib/userfaultfd_util.c LIBKVM_STRING += lib/string_override.c +LIBKVM_ASM_DEFS += lib/x86/tdx/td_boot_offsets.c + LIBKVM_x86 += lib/x86/apic.c LIBKVM_x86 += lib/x86/handlers.S LIBKVM_x86 += lib/x86/hyperv.c @@ -260,6 +262,10 @@ OVERRIDE_TARGETS = 1 include ../lib.mk include ../cgroup/lib/libcgroup.mk +# Enable Kbuild tools. +include $(top_srcdir)/scripts/Kbuild.include +include $(top_srcdir)/scripts/Makefile.lib + INSTALL_HDR_PATH = $(top_srcdir)/usr LINUX_HDR_PATH = $(INSTALL_HDR_PATH)/include/ LINUX_TOOL_INCLUDE = $(top_srcdir)/tools/include @@ -272,15 +278,24 @@ CFLAGS += -Wall -Wstrict-prototypes -Wuninitialized -O2 -g -std=gnu99 \ -fno-stack-protector -fno-PIE -fno-strict-aliasing \ -I$(LINUX_TOOL_INCLUDE) -I$(LINUX_TOOL_ARCH_INCLUDE) \ -I$(LINUX_HDR_PATH) -Iinclude -I$(<D) -Iinclude/$(ARCH) \ - -I ../rseq -I.. $(EXTRA_CFLAGS) $(KHDR_INCLUDES) + -I ../rseq -I.. -I$(OUTPUT)/include/$(ARCH) $(EXTRA_CFLAGS) $(KHDR_INCLUDES) ifeq ($(ARCH),s390) CFLAGS += -march=z10 endif + ifeq ($(ARCH),x86) + ifeq ($(shell echo "void foo(void) { }" | $(CC) -march=x86-64-v2 -x c - -c -o /dev/null 2>/dev/null; echo "$$?"),0) CFLAGS += -march=x86-64-v2 endif + +KVM_GEN_HDRS := $(patsubst lib/x86/%.c, $(OUTPUT)/include/x86/%.h, $(filter lib/x86/%, $(LIBKVM_ASM_DEFS))) +$(shell mkdir -p $(sort $(dir $(KVM_GEN_HDRS)))) +$(KVM_GEN_HDRS): GUARD = $(shell echo $(*F) | tr a-z A-Z | tr '.' '_') +$(KVM_GEN_HDRS): $(OUTPUT)/include/x86/%.h: $(OUTPUT)/lib/x86/%.s FORCE + $(call filechk,offsets,__$(GUARD)_H__) endif + ifeq ($(ARCH),arm64) tools_dir := $(top_srcdir)/tools arm64_tools_dir := $(tools_dir)/arch/arm64/tools/ @@ -313,6 +328,7 @@ LIBKVM_S := $(filter %.S,$(LIBKVM)) LIBKVM_C_OBJ := $(patsubst %.c, $(OUTPUT)/%.o, $(LIBKVM_C)) LIBKVM_S_OBJ := $(patsubst %.S, $(OUTPUT)/%.o, $(LIBKVM_S)) LIBKVM_STRING_OBJ := $(patsubst %.c, $(OUTPUT)/%.o, $(LIBKVM_STRING)) +LIBKVM_ASM_DEFS_OBJ += $(patsubst %.c, $(OUTPUT)/%.s, $(LIBKVM_ASM_DEFS)) LIBKVM_OBJS = $(LIBKVM_C_OBJ) $(LIBKVM_S_OBJ) $(LIBKVM_STRING_OBJ) $(LIBCGROUP_O) SPLIT_TEST_GEN_PROGS := $(patsubst %, $(OUTPUT)/%, $(SPLIT_TESTS)) SPLIT_TEST_GEN_OBJ := $(patsubst %, $(OUTPUT)/$(ARCH)/%.o, $(SPLIT_TESTS)) @@ -338,7 +354,9 @@ $(SPLIT_TEST_GEN_OBJ): $(OUTPUT)/$(ARCH)/%.o: $(ARCH)/%.c $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@ EXTRA_CLEAN += $(GEN_HDRS) \ + $(KVM_GEN_HDRS) \ $(LIBKVM_OBJS) \ + $(LIBKVM_ASM_DEFS_OBJ) \ $(SPLIT_TEST_GEN_OBJ) \ $(TEST_DEP_FILES) \ $(TEST_GEN_OBJ) \ @@ -350,6 +368,9 @@ $(LIBKVM_C_OBJ): $(OUTPUT)/%.o: %.c $(GEN_HDRS) $(LIBKVM_S_OBJ): $(OUTPUT)/%.o: %.S $(GEN_HDRS) $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@ +$(LIBKVM_ASM_DEFS_OBJ): $(OUTPUT)/%.s: %.c FORCE + $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -S $< -o $@ + # Compile the string overrides as freestanding to prevent the compiler from # generating self-referential code, e.g. without "freestanding" the compiler may # "optimize" memcmp() by invoking memcmp(), thus causing infinite recursion. @@ -358,11 +379,15 @@ $(LIBKVM_STRING_OBJ): $(OUTPUT)/%.o: %.c $(shell mkdir -p $(sort $(dir $(TEST_GEN_PROGS)))) $(SPLIT_TEST_GEN_OBJ): $(GEN_HDRS) +$(LIBKVM_OBJS): $(KVM_GEN_HDRS) $(TEST_GEN_PROGS): $(LIBKVM_OBJS) $(TEST_GEN_PROGS_EXTENDED): $(LIBKVM_OBJS) $(TEST_GEN_OBJ): $(GEN_HDRS) -cscope: include_paths = $(LINUX_TOOL_INCLUDE) $(LINUX_HDR_PATH) include lib .. +FORCE: + +cscope: include_paths = $(LINUX_TOOL_INCLUDE) $(LINUX_HDR_PATH) include lib .. \ + $(wildcard $(sort $(dir $(KVM_GEN_HDRS)))) cscope: $(RM) cscope.* (find $(include_paths) -name '*.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 new file mode 100644 index 000000000000..af4474dee387 --- /dev/null +++ b/tools/testing/selftests/kvm/include/x86/tdx/td_boot.h @@ -0,0 +1,69 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef SELFTEST_TDX_TD_BOOT_H +#define SELFTEST_TDX_TD_BOOT_H + +#include <stdint.h> + +#include <linux/compiler.h> +#include <linux/sizes.h> + +/* + * Layout for boot section (not to scale) + * + * GPA + * _________________________________ 0x1_0000_0000 (4GB) + * | Boot code trampoline | + * |___________________________|____ 0x0_ffff_fff0: Reset vector (16B below 4GB) + * | Boot code | + * |___________________________|____ td_boot will be copied here, so that the + * | | jmp to td_boot is exactly at the reset vector + * | Empty space | + * | | + * |───────────────────────────| + * | | + * | | + * | Boot parameters | + * | | + * | | + * |___________________________|____ 0x0_ffff_0000: TD_BOOT_PARAMETERS_GPA + */ +#define FOUR_GIGABYTES_GPA (SZ_4G) + +/* + * The exact memory layout for LGDT or LIDT instructions. + */ +struct __packed td_boot_parameters_dtr { + u16 limit; + u32 base; +}; + +/* + * Allows each vCPU to be initialized with different rip and esp. + */ +struct td_per_vcpu_parameters { + u32 esp_gva; + u64 guest_code; +}; + +/* + * Boot parameters for the TD. + * + * Unlike a regular VM, KVM cannot set registers such as esp, eip, etc + * before boot, so to run selftests, these registers' values have to be + * initialized by the TD. + * + * This struct is loaded in TD private memory at TD_BOOT_PARAMETERS_GPA. + * + * The TD boot code will read off parameters from this struct and set up the + * vCPU for executing selftests. + */ +struct td_boot_parameters { + u32 cr0; + u32 cr3; + u32 cr4; + struct td_boot_parameters_dtr gdtr; + struct td_boot_parameters_dtr idtr; + struct td_per_vcpu_parameters per_vcpu[]; +}; + +#endif /* SELFTEST_TDX_TD_BOOT_H */ diff --git a/tools/testing/selftests/kvm/lib/x86/tdx/td_boot_offsets.c b/tools/testing/selftests/kvm/lib/x86/tdx/td_boot_offsets.c new file mode 100644 index 000000000000..7f76a3585b99 --- /dev/null +++ b/tools/testing/selftests/kvm/lib/x86/tdx/td_boot_offsets.c @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0 +#define COMPILE_OFFSETS + +#include <linux/kbuild.h> + +#include "tdx/td_boot.h" + +static void __attribute__((used)) common(void) +{ + OFFSET(TD_BOOT_PARAMETERS_CR0, td_boot_parameters, cr0); + OFFSET(TD_BOOT_PARAMETERS_CR3, td_boot_parameters, cr3); + OFFSET(TD_BOOT_PARAMETERS_CR4, td_boot_parameters, cr4); + OFFSET(TD_BOOT_PARAMETERS_GDT, td_boot_parameters, gdtr); + OFFSET(TD_BOOT_PARAMETERS_IDT, td_boot_parameters, idtr); + OFFSET(TD_BOOT_PARAMETERS_PER_VCPU, td_boot_parameters, per_vcpu); + OFFSET(TD_PER_VCPU_PARAMETERS_ESP_GVA, td_per_vcpu_parameters, esp_gva); + OFFSET(TD_PER_VCPU_PARAMETERS_GUEST_CODE, td_per_vcpu_parameters, + guest_code); + DEFINE(SIZEOF_TD_PER_VCPU_PARAMETERS, + sizeof(struct td_per_vcpu_parameters)); +} -- 2.54.0.746.g67dd491aae-goog

