Re: [PATCH v14 10/22] KVM: selftests: Set up TDX boot code region
Peter Fang <[email protected]>
| Newsgroups | org.kernel.vger.kvm,dev.linux.lists.linux-coco,org.kernel.vger.linux-kernel,org.kernel.vger.linux-kselftest |
|---|---|
| Message-ID | <20260824192702.GA3694338@pedri> |
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 > >