}
 
 /*
- * 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
- * of the page in response.
+ * 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_enc_status_changed(unsigned long vaddr, int numpages, bool enc)
+static bool tdx_map_gpa(phys_addr_t start, phys_addr_t end, bool enc)
 {
-       phys_addr_t start = __pa(vaddr);
-       phys_addr_t end   = __pa(vaddr + numpages * PAGE_SIZE);
+       /* Retrying the hypercall a second time should succeed; use 3 just in case */
+       const int max_retries_per_page = 3;
+       int retry_count = 0;
 
        if (!enc) {
                /* Set the shared (decrypted) bits: */
                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))
+       while (retry_count < max_retries_per_page) {
+               struct tdx_hypercall_args args = {
+                       .r10 = TDX_HYPERCALL_STANDARD,
+                       .r11 = TDVMCALL_MAP_GPA,
+                       .r12 = start,
+                       .r13 = end - start };
+
+               u64 map_fail_paddr;
+               u64 ret = __tdx_hypercall_ret(&args);
+
+               if (ret != TDVMCALL_STATUS_RETRY)
+                       return !ret;
+               /*
+                * The guest must retry the operation for the pages in the
+                * region starting at the GPA specified in R11. R11 comes
+                * from the untrusted VMM. Sanity check it.
+                */
+               map_fail_paddr = args.r11;
+               if (map_fail_paddr < start || map_fail_paddr >= end)
+                       return false;
+
+               /* "Consume" a retry without forward progress */
+               if (map_fail_paddr == start) {
+                       retry_count++;
+                       continue;
+               }
+
+               start = map_fail_paddr;
+               retry_count = 0;
+       }
+
+       return false;
+}
+
+/*
+ * 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
+ * of the page in response.
+ */
+static bool tdx_enc_status_changed(unsigned long vaddr, int numpages, bool enc)
+{
+       phys_addr_t start = __pa(vaddr);
+       phys_addr_t end   = __pa(vaddr + numpages * PAGE_SIZE);
+
+       if (!tdx_map_gpa(start, end, enc))
                return false;
 
        /* shared->private conversion requires memory to be accepted before use */