On 9/29/25 3:36 PM, Shameer Kolothum wrote:
> When the guest reboots with devices in nested mode (S1 + S2), any QEMU/UEFI
> access to those devices can fail because S1 translation is not valid during
> the reboot. For example, a passthrough NVMe device may hold GRUB boot info
> that UEFI tries to read during the reboot.
>
> Set S1 to bypass mode during reset to avoid such failures.
>
> Reported-by: Matthew R. Ochs <[email protected]>
> Signed-off-by: Shameer Kolothum <[email protected]>
> ---
>  hw/arm/smmuv3-accel.c | 29 +++++++++++++++++++++++++++++
>  hw/arm/smmuv3-accel.h |  4 ++++
>  hw/arm/smmuv3.c       |  1 +
>  3 files changed, 34 insertions(+)
>
> diff --git a/hw/arm/smmuv3-accel.c b/hw/arm/smmuv3-accel.c
> index defeddbd8c..8396053a6c 100644
> --- a/hw/arm/smmuv3-accel.c
> +++ b/hw/arm/smmuv3-accel.c
> @@ -634,6 +634,35 @@ static const PCIIOMMUOps smmuv3_accel_ops = {
>      .get_msi_address_space = smmuv3_accel_find_msi_as,
>  };
>  
> +/*
> + * If the guest reboots and devices are configured for S1+S2, Stage1 must
> + * be switched to bypass. Otherwise, QEMU/UEFI may fail when accessing a
> + * device, e.g. when UEFI retrieves boot partition information from an
> + * assigned vfio-pci NVMe device.
> + */
> +void smmuv3_accel_attach_bypass_hwpt(SMMUv3State *s)
> +{
> +    SMMUv3AccelDevice *accel_dev;
> +    SMMUViommu *viommu;
> +
> +    if (!s->accel || !s->s_accel->viommu) {
> +        return;
> +    }
> +
> +    viommu = s->s_accel->viommu;
> +    QLIST_FOREACH(accel_dev, &viommu->device_list, next) {
> +        if (!accel_dev->vdev) {
> +            continue;
> +        }
> +        if (!host_iommu_device_iommufd_attach_hwpt(accel_dev->idev,
> +                                                   viommu->bypass_hwpt_id,
> +                                                   NULL)) {
I would prefer we pass a proper local_err, add the hint below and then
report the concatenated error.

Eric
> +            error_report("Failed to install bypass hwpt id %u for dev id %u",
> +                          viommu->bypass_hwpt_id, accel_dev->idev->devid);
> +        }
> +    }
> +}
> +
>  void smmuv3_accel_init(SMMUv3State *s)
>  {
>      SMMUState *bs = ARM_SMMU(s);
> diff --git a/hw/arm/smmuv3-accel.h b/hw/arm/smmuv3-accel.h
> index 3bdba47616..75f858e34a 100644
> --- a/hw/arm/smmuv3-accel.h
> +++ b/hw/arm/smmuv3-accel.h
> @@ -48,6 +48,7 @@ bool smmuv3_accel_install_nested_ste_range(SMMUv3State *s, 
> SMMUSIDRange *range,
>                                             Error **errp);
>  bool smmuv3_accel_issue_inv_cmd(SMMUv3State *s, void *cmd, SMMUDevice *sdev,
>                                  Error **errp);
> +void smmuv3_accel_attach_bypass_hwpt(SMMUv3State *s);
>  #else
>  static inline void smmuv3_accel_init(SMMUv3State *s)
>  {
> @@ -70,6 +71,9 @@ smmuv3_accel_issue_inv_cmd(SMMUv3State *s, void *cmd, 
> SMMUDevice *sdev,
>  {
>      return true;
>  }
> +static inline void smmuv3_accel_attach_bypass_hwpt(SMMUv3State *s)
> +{
> +}
>  #endif
>  
>  #endif /* HW_ARM_SMMUV3_ACCEL_H */
> diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
> index 5830cf5a03..94b2bbc374 100644
> --- a/hw/arm/smmuv3.c
> +++ b/hw/arm/smmuv3.c
> @@ -1913,6 +1913,7 @@ static void smmu_reset_exit(Object *obj, ResetType type)
>      if (c->parent_phases.exit) {
>          c->parent_phases.exit(obj, type);
>      }
> +    smmuv3_accel_attach_bypass_hwpt(s);
>  }
>  
>  static void smmu_realize(DeviceState *d, Error **errp)


Reply via email to