RE: [PATCH v8 1/2] x86/tdx: Retry TDVMCALL_MAP_GPA() when needed

From: Dexuan Cui
Date: Tue Jun 20 2023 - 20:28:30 EST


> From: Dave Hansen <dave.hansen@xxxxxxxxx>
> Sent: Tuesday, June 20, 2023 4:34 PM
> > ...
> > - if (_tdx_hypercall(TDVMCALL_MAP_GPA, start, end - start, 0, 0))
> > + while (retry_count < max_retries_per_page) {
> > + memset(&args, 0, sizeof(args));
> > + args.r10 = TDX_HYPERCALL_STANDARD;
> > + args.r11 = TDVMCALL_MAP_GPA;
> > + args.r12 = start;
> > + args.r13 = end - start;
> > +
>
> What's wrong with:
>
> 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 };
>
> ?
>
> Or maybe with the brackets slightly differently arranged.
>
> Why'd you declare all the variables outside the while() loop anyway?

Thanks for the suggestion of making the code compact!
I'll apply the below diff, and post v9 tomorrow (trying to
not post too frequently...)

diff --git a/arch/x86/coco/tdx/tdx.c b/arch/x86/coco/tdx/tdx.c
index 08eac8f46c11..1cb7e9ee3a68 100644
--- a/arch/x86/coco/tdx/tdx.c
+++ b/arch/x86/coco/tdx/tdx.c
@@ -710,9 +710,8 @@ static bool tdx_cache_flush_required(void)
*/
static bool tdx_map_gpa(phys_addr_t start, phys_addr_t end, bool enc)
{
+ /* Retrying the hypercall a second time should succeed; use 3 just in case */
const int max_retries_per_page = 3;
- struct tdx_hypercall_args args;
- u64 map_fail_paddr, ret;
int retry_count = 0;

if (!enc) {
@@ -722,13 +721,14 @@ static bool tdx_map_gpa(phys_addr_t start, phys_addr_t end, bool enc)
}

while (retry_count < max_retries_per_page) {
- memset(&args, 0, sizeof(args));
- args.r10 = TDX_HYPERCALL_STANDARD;
- args.r11 = TDVMCALL_MAP_GPA;
- args.r12 = start;
- args.r13 = end - start;
-
- ret = __tdx_hypercall_ret(&args);
+ 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 function now looks like this:

/*
* 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)
{
/* 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: */
start |= cc_mkdec(0);
end |= cc_mkdec(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;
}