Closed dimakuv closed 4 months ago
Apparently this version of QEMU/KVM performs MapGPA only in 64MB chunks, and if the requested GPA range is larger, errors our with VMCALL_RETRY.
Found the corresponding commit in QEMU/KVM:
https://github.com/intel-staging/qemu-tdx/commit/ac4bf9e0c98f8cf8ad5bde75f955aa8e13dd00bd
Description of the changes
In TDX, TDG.VP.VMCALL guest-host interface may not map the whole requested GPA range. In this case, this interface returns TDG.VP.VMCALL_RETRY error code and sets register R11 (
failed_addr
) to the first GPA at which the mapping failed.Our TDX PAL sanity checks that this returned
failed_addr
falls into the original requested GPA range. However, there was a bug that TDX returns this failing address as-is (in our case, with the shared bit set), so a naive check is out-of-range (because we compare against no-shared-bit addresses). This commit unsets the shared bit of the failing address before performing the sanity check.This bug was detected on Ubuntu 24.04 with Linux 6.8.0 and QEMU v8.2.1. Apparently this version of QEMU/KVM performs MapGPA only in 64MB chunks, and if the requested GPA range is larger, errors our with VMCALL_RETRY. Previous versions didn't exhibit this behavior, so the bug went unnoticed for a long time.
How to test this PR?
Without this PR,
gramine-tdx
just failed silently.To debug with printfs, one must do smth like this:
The result of my debug session was like this:
It's clear that
failed_addr
has bit 52 (TDX shared bit on this machine) set.Calculating
failed_addr - map_addr
gives us 64MB.This change is