In confidential computing environments (CC_ATTR_GUEST_MEM_ENCRYPT), virtio devices require VIRTIO_F_ACCESS_PLATFORM to negotiate restricted memory access and DMA bounce buffering for virtqueue rings and metadata buffers.
Currently, virtballoon_validate() unconditionally clears VIRTIO_F_ACCESS_PLATFORM, causing virtio_features_ok() to reject probing the balloon device (-ENODEV) when restricted memory access is active. Preserve VIRTIO_F_ACCESS_PLATFORM in virtballoon_validate() when CC_ATTR_GUEST_MEM_ENCRYPT is active, clear VIRTIO_BALLOON_F_FREE_PAGE_HINT in CoCo since free_page_vq maps MAX_PAGE_ORDER blocks through standard DMA ops without unaccepting them. Reject probing (-ENODEV) on CoCo platforms where balloon page state transitions are unsupported. Signed-off-by: Kevin Loughlin <[email protected]> --- drivers/virtio/virtio_balloon.c | 36 ++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c index 217431e75751..ae011636c07f 100644 --- a/drivers/virtio/virtio_balloon.c +++ b/drivers/virtio/virtio_balloon.c @@ -1311,6 +1311,14 @@ static int virtballoon_restore(struct virtio_device *vdev) } #endif +static bool virtballoon_cc_supported(void) +{ + if (cc_platform_has(CC_ATTR_GUEST_SEV_SNP)) + return has_unaccepted_memory(); + + return cc_platform_has(CC_ATTR_GUEST_STATE_ENCRYPT); +} + static int virtballoon_validate(struct virtio_device *vdev) { /* @@ -1318,7 +1326,17 @@ static int virtballoon_validate(struct virtio_device *vdev) * initialized. If we cannot do that then we should disable * page reporting as it could potentially change the contents * of our free pages. + * + * In encrypted guests without unaccepted memory (e.g. SEV-ES), the + * hypervisor cannot populate discarded pages with guest-encrypted + * poison/zero values and the guest does not re-initialize reported + * pages on return. Clear VIRTIO_BALLOON_F_PAGE_POISON so reporting + * is disabled when init_on_free or page_poison is active. */ + if (cc_platform_has(CC_ATTR_GUEST_MEM_ENCRYPT) && + !has_unaccepted_memory()) + __virtio_clear_bit(vdev, VIRTIO_BALLOON_F_PAGE_POISON); + if (!want_init_on_free() && !page_poisoning_enabled_static()) __virtio_clear_bit(vdev, VIRTIO_BALLOON_F_PAGE_POISON); else if (!virtio_has_feature(vdev, VIRTIO_BALLOON_F_PAGE_POISON)) @@ -1329,7 +1347,23 @@ static int virtballoon_validate(struct virtio_device *vdev) * virtqueue_add during page reporting. */ __virtio_clear_bit(vdev, VIRTIO_RING_F_INDIRECT_DESC); - __virtio_clear_bit(vdev, VIRTIO_F_ACCESS_PLATFORM); + + /* + * The balloon bypasses the DMA API for page addresses and cannot + * support a physical or virtual IOMMU on non-CoCo guests. In CoCo + * guests, VIRTIO_F_ACCESS_PLATFORM is required for bounce-buffering + * virtqueue rings and metadata. Disable free page hinting in CoCo + * guests as free_page_vq maps MAX_PAGE_ORDER blocks through standard + * DMA ops, and reject probing on CoCo platforms where balloon page + * state transitions are not supported. + */ + if (!cc_platform_has(CC_ATTR_GUEST_MEM_ENCRYPT)) { + __virtio_clear_bit(vdev, VIRTIO_F_ACCESS_PLATFORM); + } else { + if (!virtballoon_cc_supported()) + return -ENODEV; + __virtio_clear_bit(vdev, VIRTIO_BALLOON_F_FREE_PAGE_HINT); + } return 0; } -- 2.56.0.307.g5fe7bd680c-goog
