GHCI spec for TDX 1.0 says that the MapGPA call may fail with the R10 error code = TDG.VP.VMCALL_RETRY (1), and the guest must retry this operation for the pages in the region starting at the GPA specified in R11. When a TDX guest runs on Hyper-V, Hyper-V returns the retry error when hyperv_init() -> swiotlb_update_mem_attributes() -> set_memory_decrypted() decrypts up to 1GB of swiotlb bounce buffers. Signed-off-by: Dexuan Cui <decui@xxxxxxxxxxxxx> --- arch/x86/coco/tdx/tdx.c | 65 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 59 insertions(+), 6 deletions(-) diff --git a/arch/x86/coco/tdx/tdx.c b/arch/x86/coco/tdx/tdx.c index 3fee96931ff5..46971cc7d006 100644 --- a/arch/x86/coco/tdx/tdx.c +++ b/arch/x86/coco/tdx/tdx.c @@ -20,6 +20,8 @@ /* TDX hypercall Leaf IDs */ #define TDVMCALL_MAP_GPA 0x10001 +#define TDVMCALL_STATUS_RETRY 1 + /* MMIO direction */ #define EPT_READ 0 #define EPT_WRITE 1 @@ -52,6 +54,25 @@ static inline u64 _tdx_hypercall(u64 fn, u64 r12, u64 r13, u64 r14, u64 r15) return __tdx_hypercall(&args, 0); } +static inline u64 _tdx_hypercall_output_r11(u64 fn, u64 r12, u64 r13, u64 r14, + u64 r15, u64 *r11) +{ + struct tdx_hypercall_args args = { + .r10 = TDX_HYPERCALL_STANDARD, + .r11 = fn, + .r12 = r12, + .r13 = r13, + .r14 = r14, + .r15 = r15, + }; + + u64 ret; + + ret = __tdx_hypercall(&args, TDX_HCALL_HAS_OUTPUT); + *r11 = args.r11; + return ret; +} + /* Called from __tdx_hypercall() for unrecoverable failure */ void __tdx_hypercall_failed(void) { @@ -691,6 +712,43 @@ static bool try_accept_one(phys_addr_t *start, unsigned long len, return true; } +/* + * Notify the VMM about page mapping conversion. More info about ABI + * can be found in TDX Guest-Host-Communication Interface (GHCI), + * section "TDG.VP.VMCALL<MapGPA>" + */ +static bool tdx_map_gpa(phys_addr_t start, phys_addr_t end, bool enc) +{ + u64 ret, r11; + + while (1) { + ret = _tdx_hypercall_output_r11(TDVMCALL_MAP_GPA, start, + end - start, 0, 0, &r11); + if (!ret) + break; + + if (ret != TDVMCALL_STATUS_RETRY) + break; + + /* + * The guest must retry the operation for the pages in the + * region starting at the GPA specified in R11. Make sure R11 + * contains a sane value. + */ + if ((r11 & ~cc_mkdec(0)) < (start & ~cc_mkdec(0)) || + (r11 & ~cc_mkdec(0)) >= (end & ~cc_mkdec(0))) + return false; + + start = r11; + + /* Set the shared (decrypted) bit. */ + if (!enc) + start |= cc_mkdec(0); + } + + return !ret; +} + /* * Inform the VMM of the guest's intent for this physical page: shared with * the VMM or private to the guest. The VMM is expected to change its mapping @@ -707,12 +765,7 @@ static bool tdx_enc_status_changed(unsigned long vaddr, int numpages, bool enc) end |= cc_mkdec(0); } - /* - * Notify the VMM about page mapping conversion. More info about ABI - * can be found in TDX Guest-Host-Communication Interface (GHCI), - * section "TDG.VP.VMCALL<MapGPA>" - */ - if (_tdx_hypercall(TDVMCALL_MAP_GPA, start, end - start, 0, 0)) + if (!tdx_map_gpa(start, end, enc)) return false; /* private->shared conversion requires only MapGPA call */ -- 2.25.1