On Wed, Jul 22, 2026 at 11:13:15PM +0000, Lisa Wang wrote:
> From: Sagi Shahar <[email protected]>
>
> Add memory for TDX boot code in a separate memslot.
>
> Use virt_map() to get identity map in this memory region to allow for
> seamless transition from paging disabled to paging enabled code.
>
> Copy the boot code into the memory region and set up the reset vector
> at this point. While it's possible to separate the memory allocation and
> boot code initialization into separate functions, having all the
> calculations for memory size and offsets in one place simplifies the
> code and avoids duplications.
>
> Handcode the reset vector as suggested by Sean Christopherson.
>
> Reviewed-by: Binbin Wu <[email protected]>
> 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]>
> ---
> .../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/tdx_util.c | 46
> ++++++++++++++++++++++
> 3 files changed, 50 insertions(+), 1 deletion(-)
>
[ ... ]
> +
> +void tdx_vm_setup_boot_code_region(struct kvm_vm *vm)
> +{
> + size_t total_code_size = TD_BOOT_CODE_SIZE + X86_RESET_VECTOR_SIZE;
> + gpa_t boot_code_gpa = X86_RESET_VECTOR - TD_BOOT_CODE_SIZE;
> + gpa_t alloc_gpa = round_down(boot_code_gpa, PAGE_SIZE);
> + size_t nr_pages = DIV_ROUND_UP(total_code_size, PAGE_SIZE);
> + const 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, TD_BOOT_CODE_SIZE);
> +
> + hva += TD_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);
> +
> + /*
> + * Handcode "JMP rel8" at the RESET vector to jump back to the TD boot
> + * code, as there are only 16 bytes at the RESET vector before RIP will
> + * wrap back to zero. Insert a trailing int3 so that the vCPU crashes in
> + * case the JMP somehow falls through. Note! The target address is
> + * relative to the end of the instruction!
> + */
> + TEST_ASSERT(TD_BOOT_CODE_SIZE + 2 <= 128,
> + "TD boot code not addressable by 'JMP rel8'");
> + hva[0] = 0xeb;
> + hva[1] = 256 - 2 - TD_BOOT_CODE_SIZE;
> + hva[2] = 0xcc;
This handcoding has persisted for several versions (since v9) so I only
want to comment gently... The current code looks correct but I think
this could be simpler. But feel free to keep the current implementation.
I can see handcoding "JMP rel8" generates a jump instruction
predictably. But having to calculate and sanity check the boot code
offset by hand seems quite painful. And the math is quite tricky. I was
thinking the assembler could do a lot more heavy lifting here.
A nice property of this boot code is the fact that it's executed in
32-bit mode from the get go. So there's no need for 16-bit programming
and "JMP rel32" is readily available. I.e. a "jmp td_boot" in td_boot.S
should suffice and the assembler screams if td_boot isn't reachable. And
the int3's after the jump can probably go away as well since the jump is
now very, very likely to succeed.
There shouldn't be a need to "pad reset_vector to its full size of 16
bytes" as stated in v8 [1]. The exported "reset_vector" symbol in v8,
plus the boot code start & end markers, should be enough to help
tdx_vm_setup_boot_code_region() put this boot blob in the right place.
[1] https://lore.kernel.org/all/[email protected]/
> +}
> +
> static struct kvm_tdx_capabilities *tdx_read_capabilities(struct kvm_vm *vm)
> {
> static struct kvm_tdx_capabilities *tdx_cap;
>
> --
> 2.55.0.229.g6434b31f56-goog
>
>