Message ID | 20250407074939.18657-7-chenyi.qiang@intel.com (mailing list archive) |
---|---|
State | New |
Headers | show |
Series | Enable shared device assignment | expand |
On 7/4/25 17:49, Chenyi Qiang wrote: > Subsystems like VFIO previously disabled ram block discard and only > allowed coordinated discarding via RamDiscardManager. However, > guest_memfd in confidential VMs relies on discard operations for page > conversion between private and shared memory. This can lead to stale > IOMMU mapping issue when assigning a hardware device to a confidential > VM via shared memory. With the introduction of PrivateSharedManager > interface to manage private and shared states and being distinct from > RamDiscardManager, include PrivateSharedManager in coordinated RAM > discard and add related support in VFIO. How does the new behavior differ from what vfio_register_ram_discard_listener() does? Thanks, > Currently, migration support for confidential VMs is not available, so > vfio_sync_dirty_bitmap() handling for PrivateSharedListener can be > ignored. The register/unregister of PrivateSharedListener is necessary > during vfio_listener_region_add/del(). The listener callbacks are > similar between RamDiscardListener and PrivateSharedListener, allowing > for extraction of common parts opportunisticlly. > > Signed-off-by: Chenyi Qiang <chenyi.qiang@intel.com> > --- > Changes in v4 > - Newly added. > --- > hw/vfio/common.c | 104 +++++++++++++++++++++++--- > hw/vfio/container-base.c | 1 + > include/hw/vfio/vfio-container-base.h | 10 +++ > 3 files changed, 105 insertions(+), 10 deletions(-) > > diff --git a/hw/vfio/common.c b/hw/vfio/common.c > index 3172d877cc..48468a12c3 100644 > --- a/hw/vfio/common.c > +++ b/hw/vfio/common.c > @@ -335,13 +335,9 @@ out: > rcu_read_unlock(); > } > > -static void vfio_ram_discard_notify_discard(StateChangeListener *scl, > - MemoryRegionSection *section) > +static void vfio_state_change_notify_to_state_clear(VFIOContainerBase *bcontainer, > + MemoryRegionSection *section) > { > - RamDiscardListener *rdl = container_of(scl, RamDiscardListener, scl); > - VFIORamDiscardListener *vrdl = container_of(rdl, VFIORamDiscardListener, > - listener); > - VFIOContainerBase *bcontainer = vrdl->bcontainer; > const hwaddr size = int128_get64(section->size); > const hwaddr iova = section->offset_within_address_space; > int ret; > @@ -354,13 +350,28 @@ static void vfio_ram_discard_notify_discard(StateChangeListener *scl, > } > } > > -static int vfio_ram_discard_notify_populate(StateChangeListener *scl, > +static void vfio_ram_discard_notify_discard(StateChangeListener *scl, > MemoryRegionSection *section) > { > RamDiscardListener *rdl = container_of(scl, RamDiscardListener, scl); > VFIORamDiscardListener *vrdl = container_of(rdl, VFIORamDiscardListener, > listener); > - VFIOContainerBase *bcontainer = vrdl->bcontainer; > + vfio_state_change_notify_to_state_clear(vrdl->bcontainer, section); > +} > + > +static void vfio_private_shared_notify_to_private(StateChangeListener *scl, > + MemoryRegionSection *section) > +{ > + PrivateSharedListener *psl = container_of(scl, PrivateSharedListener, scl); > + VFIOPrivateSharedListener *vpsl = container_of(psl, VFIOPrivateSharedListener, > + listener); > + vfio_state_change_notify_to_state_clear(vpsl->bcontainer, section); > +} > + > +static int vfio_state_change_notify_to_state_set(VFIOContainerBase *bcontainer, > + MemoryRegionSection *section, > + uint64_t granularity) > +{ > const hwaddr end = section->offset_within_region + > int128_get64(section->size); > hwaddr start, next, iova; > @@ -372,7 +383,7 @@ static int vfio_ram_discard_notify_populate(StateChangeListener *scl, > * unmap in minimum granularity later. > */ > for (start = section->offset_within_region; start < end; start = next) { > - next = ROUND_UP(start + 1, vrdl->granularity); > + next = ROUND_UP(start + 1, granularity); > next = MIN(next, end); > > iova = start - section->offset_within_region + > @@ -383,13 +394,33 @@ static int vfio_ram_discard_notify_populate(StateChangeListener *scl, > vaddr, section->readonly); > if (ret) { > /* Rollback */ > - vfio_ram_discard_notify_discard(scl, section); > + vfio_state_change_notify_to_state_clear(bcontainer, section); > return ret; > } > } > return 0; > } > > +static int vfio_ram_discard_notify_populate(StateChangeListener *scl, > + MemoryRegionSection *section) > +{ > + RamDiscardListener *rdl = container_of(scl, RamDiscardListener, scl); > + VFIORamDiscardListener *vrdl = container_of(rdl, VFIORamDiscardListener, > + listener); > + return vfio_state_change_notify_to_state_set(vrdl->bcontainer, section, > + vrdl->granularity); > +} > + > +static int vfio_private_shared_notify_to_shared(StateChangeListener *scl, > + MemoryRegionSection *section) > +{ > + PrivateSharedListener *psl = container_of(scl, PrivateSharedListener, scl); > + VFIOPrivateSharedListener *vpsl = container_of(psl, VFIOPrivateSharedListener, > + listener); > + return vfio_state_change_notify_to_state_set(vpsl->bcontainer, section, > + vpsl->granularity); > +} > + > static void vfio_register_ram_discard_listener(VFIOContainerBase *bcontainer, > MemoryRegionSection *section) > { > @@ -466,6 +497,27 @@ static void vfio_register_ram_discard_listener(VFIOContainerBase *bcontainer, > } > } > > +static void vfio_register_private_shared_listener(VFIOContainerBase *bcontainer, > + MemoryRegionSection *section) > +{ > + GenericStateManager *gsm = memory_region_get_generic_state_manager(section->mr); > + VFIOPrivateSharedListener *vpsl; > + PrivateSharedListener *psl; > + > + vpsl = g_new0(VFIOPrivateSharedListener, 1); > + vpsl->bcontainer = bcontainer; > + vpsl->mr = section->mr; > + vpsl->offset_within_address_space = section->offset_within_address_space; > + vpsl->granularity = generic_state_manager_get_min_granularity(gsm, > + section->mr); > + > + psl = &vpsl->listener; > + private_shared_listener_init(psl, vfio_private_shared_notify_to_shared, > + vfio_private_shared_notify_to_private); > + generic_state_manager_register_listener(gsm, &psl->scl, section); > + QLIST_INSERT_HEAD(&bcontainer->vpsl_list, vpsl, next); > +} > + > static void vfio_unregister_ram_discard_listener(VFIOContainerBase *bcontainer, > MemoryRegionSection *section) > { > @@ -491,6 +543,31 @@ static void vfio_unregister_ram_discard_listener(VFIOContainerBase *bcontainer, > g_free(vrdl); > } > > +static void vfio_unregister_private_shared_listener(VFIOContainerBase *bcontainer, > + MemoryRegionSection *section) > +{ > + GenericStateManager *gsm = memory_region_get_generic_state_manager(section->mr); > + VFIOPrivateSharedListener *vpsl = NULL; > + PrivateSharedListener *psl; > + > + QLIST_FOREACH(vpsl, &bcontainer->vpsl_list, next) { > + if (vpsl->mr == section->mr && > + vpsl->offset_within_address_space == > + section->offset_within_address_space) { > + break; > + } > + } > + > + if (!vpsl) { > + hw_error("vfio: Trying to unregister missing RAM discard listener"); > + } > + > + psl = &vpsl->listener; > + generic_state_manager_unregister_listener(gsm, &psl->scl); > + QLIST_REMOVE(vpsl, next); > + g_free(vpsl); > +} > + > static bool vfio_known_safe_misalignment(MemoryRegionSection *section) > { > MemoryRegion *mr = section->mr; > @@ -644,6 +721,9 @@ static void vfio_listener_region_add(MemoryListener *listener, > if (memory_region_has_ram_discard_manager(section->mr)) { > vfio_register_ram_discard_listener(bcontainer, section); > return; > + } else if (memory_region_has_private_shared_manager(section->mr)) { > + vfio_register_private_shared_listener(bcontainer, section); > + return; > } > > vaddr = memory_region_get_ram_ptr(section->mr) + > @@ -764,6 +844,10 @@ static void vfio_listener_region_del(MemoryListener *listener, > vfio_unregister_ram_discard_listener(bcontainer, section); > /* Unregistering will trigger an unmap. */ > try_unmap = false; > + } else if (memory_region_has_private_shared_manager(section->mr)) { > + vfio_unregister_private_shared_listener(bcontainer, section); > + /* Unregistering will trigger an unmap. */ > + try_unmap = false; > } > > if (try_unmap) { > diff --git a/hw/vfio/container-base.c b/hw/vfio/container-base.c > index 749a3fd29d..ff5df925c2 100644 > --- a/hw/vfio/container-base.c > +++ b/hw/vfio/container-base.c > @@ -135,6 +135,7 @@ static void vfio_container_instance_init(Object *obj) > bcontainer->iova_ranges = NULL; > QLIST_INIT(&bcontainer->giommu_list); > QLIST_INIT(&bcontainer->vrdl_list); > + QLIST_INIT(&bcontainer->vpsl_list); > } > > static const TypeInfo types[] = { > diff --git a/include/hw/vfio/vfio-container-base.h b/include/hw/vfio/vfio-container-base.h > index 4cff9943ab..8d7c0b1179 100644 > --- a/include/hw/vfio/vfio-container-base.h > +++ b/include/hw/vfio/vfio-container-base.h > @@ -47,6 +47,7 @@ typedef struct VFIOContainerBase { > bool dirty_pages_started; /* Protected by BQL */ > QLIST_HEAD(, VFIOGuestIOMMU) giommu_list; > QLIST_HEAD(, VFIORamDiscardListener) vrdl_list; > + QLIST_HEAD(, VFIOPrivateSharedListener) vpsl_list; > QLIST_ENTRY(VFIOContainerBase) next; > QLIST_HEAD(, VFIODevice) device_list; > GList *iova_ranges; > @@ -71,6 +72,15 @@ typedef struct VFIORamDiscardListener { > QLIST_ENTRY(VFIORamDiscardListener) next; > } VFIORamDiscardListener; > > +typedef struct VFIOPrivateSharedListener { > + VFIOContainerBase *bcontainer; > + MemoryRegion *mr; > + hwaddr offset_within_address_space; > + uint64_t granularity; > + PrivateSharedListener listener; > + QLIST_ENTRY(VFIOPrivateSharedListener) next; > +} VFIOPrivateSharedListener; > + > int vfio_container_dma_map(VFIOContainerBase *bcontainer, > hwaddr iova, ram_addr_t size, > void *vaddr, bool readonly);
On 4/9/2025 5:58 PM, Alexey Kardashevskiy wrote: > > > On 7/4/25 17:49, Chenyi Qiang wrote: >> Subsystems like VFIO previously disabled ram block discard and only >> allowed coordinated discarding via RamDiscardManager. However, >> guest_memfd in confidential VMs relies on discard operations for page >> conversion between private and shared memory. This can lead to stale >> IOMMU mapping issue when assigning a hardware device to a confidential >> VM via shared memory. With the introduction of PrivateSharedManager >> interface to manage private and shared states and being distinct from >> RamDiscardManager, include PrivateSharedManager in coordinated RAM >> discard and add related support in VFIO. > > How does the new behavior differ from what > vfio_register_ram_discard_listener() does? Thanks, Strictly speaking, there is no particular difference except the embedded PrivateSharedListener and RamDiscardListener in VFIOXXXListener. It is possible to extract some common part between VFIOPrivateSharedListener and VFIORamDiscardListener and some common part of vfio_register/unregister_xxx_listener(). But I'm not sure if it can become more concise. > > >> Currently, migration support for confidential VMs is not available, so >> vfio_sync_dirty_bitmap() handling for PrivateSharedListener can be >> ignored. The register/unregister of PrivateSharedListener is necessary >> during vfio_listener_region_add/del(). The listener callbacks are >> similar between RamDiscardListener and PrivateSharedListener, allowing >> for extraction of common parts opportunisticlly. >> >> Signed-off-by: Chenyi Qiang <chenyi.qiang@intel.com> >> --- >> Changes in v4 >> - Newly added. >> --- >> hw/vfio/common.c | 104 +++++++++++++++++++++++--- >> hw/vfio/container-base.c | 1 + >> include/hw/vfio/vfio-container-base.h | 10 +++ >> 3 files changed, 105 insertions(+), 10 deletions(-) >> >> diff --git a/hw/vfio/common.c b/hw/vfio/common.c >> index 3172d877cc..48468a12c3 100644 >> --- a/hw/vfio/common.c >> +++ b/hw/vfio/common.c >> @@ -335,13 +335,9 @@ out: >> rcu_read_unlock(); >> } >> -static void vfio_ram_discard_notify_discard(StateChangeListener *scl, >> - MemoryRegionSection >> *section) >> +static void vfio_state_change_notify_to_state_clear(VFIOContainerBase >> *bcontainer, >> + >> MemoryRegionSection *section) >> { >> - RamDiscardListener *rdl = container_of(scl, RamDiscardListener, >> scl); >> - VFIORamDiscardListener *vrdl = container_of(rdl, >> VFIORamDiscardListener, >> - listener); >> - VFIOContainerBase *bcontainer = vrdl->bcontainer; >> const hwaddr size = int128_get64(section->size); >> const hwaddr iova = section->offset_within_address_space; >> int ret; >> @@ -354,13 +350,28 @@ static void >> vfio_ram_discard_notify_discard(StateChangeListener *scl, >> } >> } >> -static int vfio_ram_discard_notify_populate(StateChangeListener *scl, >> +static void vfio_ram_discard_notify_discard(StateChangeListener *scl, >> MemoryRegionSection >> *section) >> { >> RamDiscardListener *rdl = container_of(scl, RamDiscardListener, >> scl); >> VFIORamDiscardListener *vrdl = container_of(rdl, >> VFIORamDiscardListener, >> listener); >> - VFIOContainerBase *bcontainer = vrdl->bcontainer; >> + vfio_state_change_notify_to_state_clear(vrdl->bcontainer, section); >> +} >> + >> +static void vfio_private_shared_notify_to_private(StateChangeListener >> *scl, >> + MemoryRegionSection >> *section) >> +{ >> + PrivateSharedListener *psl = container_of(scl, >> PrivateSharedListener, scl); >> + VFIOPrivateSharedListener *vpsl = container_of(psl, >> VFIOPrivateSharedListener, >> + listener); >> + vfio_state_change_notify_to_state_clear(vpsl->bcontainer, section); >> +} >> + >> +static int vfio_state_change_notify_to_state_set(VFIOContainerBase >> *bcontainer, >> + MemoryRegionSection >> *section, >> + uint64_t granularity) >> +{ >> const hwaddr end = section->offset_within_region + >> int128_get64(section->size); >> hwaddr start, next, iova; >> @@ -372,7 +383,7 @@ static int >> vfio_ram_discard_notify_populate(StateChangeListener *scl, >> * unmap in minimum granularity later. >> */ >> for (start = section->offset_within_region; start < end; start = >> next) { >> - next = ROUND_UP(start + 1, vrdl->granularity); >> + next = ROUND_UP(start + 1, granularity); >> next = MIN(next, end); >> iova = start - section->offset_within_region + >> @@ -383,13 +394,33 @@ static int >> vfio_ram_discard_notify_populate(StateChangeListener *scl, >> vaddr, section->readonly); >> if (ret) { >> /* Rollback */ >> - vfio_ram_discard_notify_discard(scl, section); >> + vfio_state_change_notify_to_state_clear(bcontainer, >> section); >> return ret; >> } >> } >> return 0; >> } >> +static int vfio_ram_discard_notify_populate(StateChangeListener *scl, >> + MemoryRegionSection >> *section) >> +{ >> + RamDiscardListener *rdl = container_of(scl, RamDiscardListener, >> scl); >> + VFIORamDiscardListener *vrdl = container_of(rdl, >> VFIORamDiscardListener, >> + listener); >> + return vfio_state_change_notify_to_state_set(vrdl->bcontainer, >> section, >> + vrdl->granularity); >> +} >> + >> +static int vfio_private_shared_notify_to_shared(StateChangeListener >> *scl, >> + MemoryRegionSection >> *section) >> +{ >> + PrivateSharedListener *psl = container_of(scl, >> PrivateSharedListener, scl); >> + VFIOPrivateSharedListener *vpsl = container_of(psl, >> VFIOPrivateSharedListener, >> + listener); >> + return vfio_state_change_notify_to_state_set(vpsl->bcontainer, >> section, >> + vpsl->granularity); >> +} >> + >> static void vfio_register_ram_discard_listener(VFIOContainerBase >> *bcontainer, >> MemoryRegionSection >> *section) >> { >> @@ -466,6 +497,27 @@ static void >> vfio_register_ram_discard_listener(VFIOContainerBase *bcontainer, >> } >> } >> +static void vfio_register_private_shared_listener(VFIOContainerBase >> *bcontainer, >> + MemoryRegionSection >> *section) >> +{ >> + GenericStateManager *gsm = >> memory_region_get_generic_state_manager(section->mr); >> + VFIOPrivateSharedListener *vpsl; >> + PrivateSharedListener *psl; >> + >> + vpsl = g_new0(VFIOPrivateSharedListener, 1); >> + vpsl->bcontainer = bcontainer; >> + vpsl->mr = section->mr; >> + vpsl->offset_within_address_space = section- >> >offset_within_address_space; >> + vpsl->granularity = generic_state_manager_get_min_granularity(gsm, >> + >> section->mr); >> + >> + psl = &vpsl->listener; >> + private_shared_listener_init(psl, >> vfio_private_shared_notify_to_shared, >> + vfio_private_shared_notify_to_private); >> + generic_state_manager_register_listener(gsm, &psl->scl, section); >> + QLIST_INSERT_HEAD(&bcontainer->vpsl_list, vpsl, next); >> +} >> + >> static void vfio_unregister_ram_discard_listener(VFIOContainerBase >> *bcontainer, >> MemoryRegionSection >> *section) >> { >> @@ -491,6 +543,31 @@ static void >> vfio_unregister_ram_discard_listener(VFIOContainerBase *bcontainer, >> g_free(vrdl); >> } >> +static void >> vfio_unregister_private_shared_listener(VFIOContainerBase *bcontainer, >> + >> MemoryRegionSection *section) >> +{ >> + GenericStateManager *gsm = >> memory_region_get_generic_state_manager(section->mr); >> + VFIOPrivateSharedListener *vpsl = NULL; >> + PrivateSharedListener *psl; >> + >> + QLIST_FOREACH(vpsl, &bcontainer->vpsl_list, next) { >> + if (vpsl->mr == section->mr && >> + vpsl->offset_within_address_space == >> + section->offset_within_address_space) { >> + break; >> + } >> + } >> + >> + if (!vpsl) { >> + hw_error("vfio: Trying to unregister missing RAM discard >> listener"); >> + } >> + >> + psl = &vpsl->listener; >> + generic_state_manager_unregister_listener(gsm, &psl->scl); >> + QLIST_REMOVE(vpsl, next); >> + g_free(vpsl); >> +} >> + >> static bool vfio_known_safe_misalignment(MemoryRegionSection *section) >> { >> MemoryRegion *mr = section->mr; >> @@ -644,6 +721,9 @@ static void >> vfio_listener_region_add(MemoryListener *listener, >> if (memory_region_has_ram_discard_manager(section->mr)) { >> vfio_register_ram_discard_listener(bcontainer, section); >> return; >> + } else if (memory_region_has_private_shared_manager(section->mr)) { >> + vfio_register_private_shared_listener(bcontainer, section); >> + return; >> } >> vaddr = memory_region_get_ram_ptr(section->mr) + >> @@ -764,6 +844,10 @@ static void >> vfio_listener_region_del(MemoryListener *listener, >> vfio_unregister_ram_discard_listener(bcontainer, section); >> /* Unregistering will trigger an unmap. */ >> try_unmap = false; >> + } else if (memory_region_has_private_shared_manager(section->mr)) { >> + vfio_unregister_private_shared_listener(bcontainer, section); >> + /* Unregistering will trigger an unmap. */ >> + try_unmap = false; >> } >> if (try_unmap) { >> diff --git a/hw/vfio/container-base.c b/hw/vfio/container-base.c >> index 749a3fd29d..ff5df925c2 100644 >> --- a/hw/vfio/container-base.c >> +++ b/hw/vfio/container-base.c >> @@ -135,6 +135,7 @@ static void vfio_container_instance_init(Object *obj) >> bcontainer->iova_ranges = NULL; >> QLIST_INIT(&bcontainer->giommu_list); >> QLIST_INIT(&bcontainer->vrdl_list); >> + QLIST_INIT(&bcontainer->vpsl_list); >> } >> static const TypeInfo types[] = { >> diff --git a/include/hw/vfio/vfio-container-base.h b/include/hw/vfio/ >> vfio-container-base.h >> index 4cff9943ab..8d7c0b1179 100644 >> --- a/include/hw/vfio/vfio-container-base.h >> +++ b/include/hw/vfio/vfio-container-base.h >> @@ -47,6 +47,7 @@ typedef struct VFIOContainerBase { >> bool dirty_pages_started; /* Protected by BQL */ >> QLIST_HEAD(, VFIOGuestIOMMU) giommu_list; >> QLIST_HEAD(, VFIORamDiscardListener) vrdl_list; >> + QLIST_HEAD(, VFIOPrivateSharedListener) vpsl_list; >> QLIST_ENTRY(VFIOContainerBase) next; >> QLIST_HEAD(, VFIODevice) device_list; >> GList *iova_ranges; >> @@ -71,6 +72,15 @@ typedef struct VFIORamDiscardListener { >> QLIST_ENTRY(VFIORamDiscardListener) next; >> } VFIORamDiscardListener; >> +typedef struct VFIOPrivateSharedListener { >> + VFIOContainerBase *bcontainer; >> + MemoryRegion *mr; >> + hwaddr offset_within_address_space; >> + uint64_t granularity; >> + PrivateSharedListener listener; >> + QLIST_ENTRY(VFIOPrivateSharedListener) next; >> +} VFIOPrivateSharedListener; >> + >> int vfio_container_dma_map(VFIOContainerBase *bcontainer, >> hwaddr iova, ram_addr_t size, >> void *vaddr, bool readonly); >
diff --git a/hw/vfio/common.c b/hw/vfio/common.c index 3172d877cc..48468a12c3 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -335,13 +335,9 @@ out: rcu_read_unlock(); } -static void vfio_ram_discard_notify_discard(StateChangeListener *scl, - MemoryRegionSection *section) +static void vfio_state_change_notify_to_state_clear(VFIOContainerBase *bcontainer, + MemoryRegionSection *section) { - RamDiscardListener *rdl = container_of(scl, RamDiscardListener, scl); - VFIORamDiscardListener *vrdl = container_of(rdl, VFIORamDiscardListener, - listener); - VFIOContainerBase *bcontainer = vrdl->bcontainer; const hwaddr size = int128_get64(section->size); const hwaddr iova = section->offset_within_address_space; int ret; @@ -354,13 +350,28 @@ static void vfio_ram_discard_notify_discard(StateChangeListener *scl, } } -static int vfio_ram_discard_notify_populate(StateChangeListener *scl, +static void vfio_ram_discard_notify_discard(StateChangeListener *scl, MemoryRegionSection *section) { RamDiscardListener *rdl = container_of(scl, RamDiscardListener, scl); VFIORamDiscardListener *vrdl = container_of(rdl, VFIORamDiscardListener, listener); - VFIOContainerBase *bcontainer = vrdl->bcontainer; + vfio_state_change_notify_to_state_clear(vrdl->bcontainer, section); +} + +static void vfio_private_shared_notify_to_private(StateChangeListener *scl, + MemoryRegionSection *section) +{ + PrivateSharedListener *psl = container_of(scl, PrivateSharedListener, scl); + VFIOPrivateSharedListener *vpsl = container_of(psl, VFIOPrivateSharedListener, + listener); + vfio_state_change_notify_to_state_clear(vpsl->bcontainer, section); +} + +static int vfio_state_change_notify_to_state_set(VFIOContainerBase *bcontainer, + MemoryRegionSection *section, + uint64_t granularity) +{ const hwaddr end = section->offset_within_region + int128_get64(section->size); hwaddr start, next, iova; @@ -372,7 +383,7 @@ static int vfio_ram_discard_notify_populate(StateChangeListener *scl, * unmap in minimum granularity later. */ for (start = section->offset_within_region; start < end; start = next) { - next = ROUND_UP(start + 1, vrdl->granularity); + next = ROUND_UP(start + 1, granularity); next = MIN(next, end); iova = start - section->offset_within_region + @@ -383,13 +394,33 @@ static int vfio_ram_discard_notify_populate(StateChangeListener *scl, vaddr, section->readonly); if (ret) { /* Rollback */ - vfio_ram_discard_notify_discard(scl, section); + vfio_state_change_notify_to_state_clear(bcontainer, section); return ret; } } return 0; } +static int vfio_ram_discard_notify_populate(StateChangeListener *scl, + MemoryRegionSection *section) +{ + RamDiscardListener *rdl = container_of(scl, RamDiscardListener, scl); + VFIORamDiscardListener *vrdl = container_of(rdl, VFIORamDiscardListener, + listener); + return vfio_state_change_notify_to_state_set(vrdl->bcontainer, section, + vrdl->granularity); +} + +static int vfio_private_shared_notify_to_shared(StateChangeListener *scl, + MemoryRegionSection *section) +{ + PrivateSharedListener *psl = container_of(scl, PrivateSharedListener, scl); + VFIOPrivateSharedListener *vpsl = container_of(psl, VFIOPrivateSharedListener, + listener); + return vfio_state_change_notify_to_state_set(vpsl->bcontainer, section, + vpsl->granularity); +} + static void vfio_register_ram_discard_listener(VFIOContainerBase *bcontainer, MemoryRegionSection *section) { @@ -466,6 +497,27 @@ static void vfio_register_ram_discard_listener(VFIOContainerBase *bcontainer, } } +static void vfio_register_private_shared_listener(VFIOContainerBase *bcontainer, + MemoryRegionSection *section) +{ + GenericStateManager *gsm = memory_region_get_generic_state_manager(section->mr); + VFIOPrivateSharedListener *vpsl; + PrivateSharedListener *psl; + + vpsl = g_new0(VFIOPrivateSharedListener, 1); + vpsl->bcontainer = bcontainer; + vpsl->mr = section->mr; + vpsl->offset_within_address_space = section->offset_within_address_space; + vpsl->granularity = generic_state_manager_get_min_granularity(gsm, + section->mr); + + psl = &vpsl->listener; + private_shared_listener_init(psl, vfio_private_shared_notify_to_shared, + vfio_private_shared_notify_to_private); + generic_state_manager_register_listener(gsm, &psl->scl, section); + QLIST_INSERT_HEAD(&bcontainer->vpsl_list, vpsl, next); +} + static void vfio_unregister_ram_discard_listener(VFIOContainerBase *bcontainer, MemoryRegionSection *section) { @@ -491,6 +543,31 @@ static void vfio_unregister_ram_discard_listener(VFIOContainerBase *bcontainer, g_free(vrdl); } +static void vfio_unregister_private_shared_listener(VFIOContainerBase *bcontainer, + MemoryRegionSection *section) +{ + GenericStateManager *gsm = memory_region_get_generic_state_manager(section->mr); + VFIOPrivateSharedListener *vpsl = NULL; + PrivateSharedListener *psl; + + QLIST_FOREACH(vpsl, &bcontainer->vpsl_list, next) { + if (vpsl->mr == section->mr && + vpsl->offset_within_address_space == + section->offset_within_address_space) { + break; + } + } + + if (!vpsl) { + hw_error("vfio: Trying to unregister missing RAM discard listener"); + } + + psl = &vpsl->listener; + generic_state_manager_unregister_listener(gsm, &psl->scl); + QLIST_REMOVE(vpsl, next); + g_free(vpsl); +} + static bool vfio_known_safe_misalignment(MemoryRegionSection *section) { MemoryRegion *mr = section->mr; @@ -644,6 +721,9 @@ static void vfio_listener_region_add(MemoryListener *listener, if (memory_region_has_ram_discard_manager(section->mr)) { vfio_register_ram_discard_listener(bcontainer, section); return; + } else if (memory_region_has_private_shared_manager(section->mr)) { + vfio_register_private_shared_listener(bcontainer, section); + return; } vaddr = memory_region_get_ram_ptr(section->mr) + @@ -764,6 +844,10 @@ static void vfio_listener_region_del(MemoryListener *listener, vfio_unregister_ram_discard_listener(bcontainer, section); /* Unregistering will trigger an unmap. */ try_unmap = false; + } else if (memory_region_has_private_shared_manager(section->mr)) { + vfio_unregister_private_shared_listener(bcontainer, section); + /* Unregistering will trigger an unmap. */ + try_unmap = false; } if (try_unmap) { diff --git a/hw/vfio/container-base.c b/hw/vfio/container-base.c index 749a3fd29d..ff5df925c2 100644 --- a/hw/vfio/container-base.c +++ b/hw/vfio/container-base.c @@ -135,6 +135,7 @@ static void vfio_container_instance_init(Object *obj) bcontainer->iova_ranges = NULL; QLIST_INIT(&bcontainer->giommu_list); QLIST_INIT(&bcontainer->vrdl_list); + QLIST_INIT(&bcontainer->vpsl_list); } static const TypeInfo types[] = { diff --git a/include/hw/vfio/vfio-container-base.h b/include/hw/vfio/vfio-container-base.h index 4cff9943ab..8d7c0b1179 100644 --- a/include/hw/vfio/vfio-container-base.h +++ b/include/hw/vfio/vfio-container-base.h @@ -47,6 +47,7 @@ typedef struct VFIOContainerBase { bool dirty_pages_started; /* Protected by BQL */ QLIST_HEAD(, VFIOGuestIOMMU) giommu_list; QLIST_HEAD(, VFIORamDiscardListener) vrdl_list; + QLIST_HEAD(, VFIOPrivateSharedListener) vpsl_list; QLIST_ENTRY(VFIOContainerBase) next; QLIST_HEAD(, VFIODevice) device_list; GList *iova_ranges; @@ -71,6 +72,15 @@ typedef struct VFIORamDiscardListener { QLIST_ENTRY(VFIORamDiscardListener) next; } VFIORamDiscardListener; +typedef struct VFIOPrivateSharedListener { + VFIOContainerBase *bcontainer; + MemoryRegion *mr; + hwaddr offset_within_address_space; + uint64_t granularity; + PrivateSharedListener listener; + QLIST_ENTRY(VFIOPrivateSharedListener) next; +} VFIOPrivateSharedListener; + int vfio_container_dma_map(VFIOContainerBase *bcontainer, hwaddr iova, ram_addr_t size, void *vaddr, bool readonly);
Subsystems like VFIO previously disabled ram block discard and only allowed coordinated discarding via RamDiscardManager. However, guest_memfd in confidential VMs relies on discard operations for page conversion between private and shared memory. This can lead to stale IOMMU mapping issue when assigning a hardware device to a confidential VM via shared memory. With the introduction of PrivateSharedManager interface to manage private and shared states and being distinct from RamDiscardManager, include PrivateSharedManager in coordinated RAM discard and add related support in VFIO. Currently, migration support for confidential VMs is not available, so vfio_sync_dirty_bitmap() handling for PrivateSharedListener can be ignored. The register/unregister of PrivateSharedListener is necessary during vfio_listener_region_add/del(). The listener callbacks are similar between RamDiscardListener and PrivateSharedListener, allowing for extraction of common parts opportunisticlly. Signed-off-by: Chenyi Qiang <chenyi.qiang@intel.com> --- Changes in v4 - Newly added. --- hw/vfio/common.c | 104 +++++++++++++++++++++++--- hw/vfio/container-base.c | 1 + include/hw/vfio/vfio-container-base.h | 10 +++ 3 files changed, 105 insertions(+), 10 deletions(-)