QEMU SMMUv3 currently sets the output address size (OAS) to 44 bits. With accelerator mode enabled, a device may use SVA, where CPU page tables are shared with the SMMU, requiring an OAS at least as large as the CPU’s output address size. A user option is added to configure this.
However, the OAS value advertised by the virtual SMMU must remain compatible with the capabilities of the host SMMUv3. In accelerated mode, the host SMMU performs stage-2 translation and must be able to consume the intermediate physical addresses (IPA) produced by stage-1. The OAS exposed by the virtual SMMU defines the maximum IPA width that stage-1 translations may generate. For AArch64 implementations, the maximum usable IPA size on the host SMMU is determined by its own OAS. Check that the configured OAS does not exceed what the host SMMU can safely support. Tested-by: Zhangfei Gao <[email protected]> Signed-off-by: Shameer Kolothum <[email protected]> --- hw/arm/smmuv3-accel.c | 20 ++++++++++++++++++++ hw/arm/smmuv3-internal.h | 3 ++- hw/arm/smmuv3.c | 16 +++++++++++++++- include/hw/arm/smmuv3.h | 1 + 4 files changed, 38 insertions(+), 2 deletions(-) diff --git a/hw/arm/smmuv3-accel.c b/hw/arm/smmuv3-accel.c index 73c7ce586a..35a94c720a 100644 --- a/hw/arm/smmuv3-accel.c +++ b/hw/arm/smmuv3-accel.c @@ -27,6 +27,12 @@ static MemoryRegion root, sysmem; static AddressSpace *shared_as_sysmem; +static int smmuv3_oas_bits(uint32_t oas) +{ + static const int map[] = { 32, 36, 40, 42, 44, 48, 52, 56 }; + return (oas < ARRAY_SIZE(map)) ? map[oas] : -EINVAL; +} + static bool smmuv3_accel_check_hw_compatible(SMMUv3State *s, struct iommu_hw_info_arm_smmuv3 *info, @@ -68,6 +74,15 @@ smmuv3_accel_check_hw_compatible(SMMUv3State *s, error_setg(errp, "Host SMMUv3 doesn't support Range Invalidation"); return false; } + /* Check OAS value opted is compatible with Host SMMUv3 IPA */ + if (FIELD_EX32(info->idr[5], IDR5, OAS) < + FIELD_EX32(s->idr[5], IDR5, OAS)) { + error_setg(errp, "Host SMMUv3 supports only %d-bit IPA, but the vSMMU " + "OAS implies %d-bit IPA", + smmuv3_oas_bits(FIELD_EX32(info->idr[5], IDR5, OAS)), + smmuv3_oas_bits(FIELD_EX32(info->idr[5], IDR5, OAS))); + return false; + } /* QEMU SMMUv3 supports GRAN4K/GRAN16K/GRAN64K translation granules */ if (FIELD_EX32(info->idr[5], IDR5, GRAN4K) != @@ -650,6 +665,11 @@ void smmuv3_accel_idr_override(SMMUv3State *s) /* QEMU SMMUv3 has no ATS. Advertise ATS if opt-on by property */ s->idr[0] = FIELD_DP32(s->idr[0], IDR0, ATS, s->ats); + + /* Advertise 48-bit OAS in IDR5 when requested (default is 44 bits). */ + if (s->oas == 48) { + s->idr[5] = FIELD_DP32(s->idr[5], IDR5, OAS, SMMU_IDR5_OAS_48); + } } /* Based on SMUUv3 GPBA.ABORT configuration, attach a corresponding HWPT */ diff --git a/hw/arm/smmuv3-internal.h b/hw/arm/smmuv3-internal.h index a76e4e2484..0f44a4e1d3 100644 --- a/hw/arm/smmuv3-internal.h +++ b/hw/arm/smmuv3-internal.h @@ -111,7 +111,8 @@ REG32(IDR5, 0x14) FIELD(IDR5, VAX, 10, 2); FIELD(IDR5, STALL_MAX, 16, 16); -#define SMMU_IDR5_OAS 4 +#define SMMU_IDR5_OAS_44 4 +#define SMMU_IDR5_OAS_48 5 REG32(IIDR, 0x18) REG32(AIDR, 0x1c) diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c index ad476146f6..a7bd4eeb77 100644 --- a/hw/arm/smmuv3.c +++ b/hw/arm/smmuv3.c @@ -299,7 +299,8 @@ static void smmuv3_init_id_regs(SMMUv3State *s) s->idr[3] = FIELD_DP32(s->idr[3], IDR3, RIL, 1); s->idr[3] = FIELD_DP32(s->idr[3], IDR3, BBML, 2); - s->idr[5] = FIELD_DP32(s->idr[5], IDR5, OAS, SMMU_IDR5_OAS); /* 44 bits */ + /* OAS: 44 bits */ + s->idr[5] = FIELD_DP32(s->idr[5], IDR5, OAS, SMMU_IDR5_OAS_44); /* 4K, 16K and 64K granule support */ s->idr[5] = FIELD_DP32(s->idr[5], IDR5, GRAN4K, 1); s->idr[5] = FIELD_DP32(s->idr[5], IDR5, GRAN16K, 1); @@ -1945,8 +1946,17 @@ static bool smmu_validate_property(SMMUv3State *s, Error **errp) error_setg(errp, "ats can only be enabled if accel=on"); return false; } + if (s->oas != 44) { + error_setg(errp, "OAS can only be set to 44 bits if accel=off"); + return false; + } return true; } + + if (s->oas != 44 && s->oas != 48) { + error_setg(errp, "OAS can only be set to 44 or 48 bits"); + return false; + } return true; } @@ -2073,6 +2083,7 @@ static const Property smmuv3_properties[] = { /* RIL can be turned off for accel cases */ DEFINE_PROP_BOOL("ril", SMMUv3State, ril, true), DEFINE_PROP_BOOL("ats", SMMUv3State, ats, false), + DEFINE_PROP_UINT8("oas", SMMUv3State, oas, 44), }; static void smmuv3_instance_init(Object *obj) @@ -2103,6 +2114,9 @@ static void smmuv3_class_init(ObjectClass *klass, const void *data) object_class_property_set_description(klass, "ats", "Enable/disable ATS support (for accel=on). Please ensure host " "platform has ATS support before enabling this"); + object_class_property_set_description(klass, "oas", + "Specify Output Address Size (for accel =on). Supported values " + "are 44 or 48 bits. Defaults to 44 bits"); } static int smmuv3_notify_flag_changed(IOMMUMemoryRegion *iommu, diff --git a/include/hw/arm/smmuv3.h b/include/hw/arm/smmuv3.h index 242d6429ed..d488a39cd0 100644 --- a/include/hw/arm/smmuv3.h +++ b/include/hw/arm/smmuv3.h @@ -71,6 +71,7 @@ struct SMMUv3State { Error *migration_blocker; bool ril; bool ats; + uint8_t oas; }; typedef enum { -- 2.43.0
