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)