@samitouri / QOSamiQemu / commits / 29a92d9861

target/arm: Separate cpu types max-v8 and max-v9

Do not include v9-only features in "max-v8". Do not include the prohibited v8 features in "max-v9". In aarch64 tcg mode, define "max" as "max-v9". Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260827041557.775080-7-richard.henderson@linaro.org Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

Richard Henderson committed Aug 26, 2026 at 21:15 UTC 29a92d9861155e421d6e14adcf820dd20dfaa318
6 files changed +128 -59
docs/system/arm/emulation.rst
+12 -1
@@ -230,7 +230,18 @@ to the `Arm Architecture Reference Manual for A-profile architecture
230 When a specific named CPU is being emulated, only those features which
231 are present in hardware for that CPU are emulated. (If a feature is
232 not in the list above then it is not supported, even if the real
233 -hardware should have it.) The ``max`` CPU enables all features.
233 +hardware should have it.)
234 +
235 +The ``max-v8`` CPU enables all of the listed Armv8-A architecture
236 +extensions but none of the Armv9-A architecture extensions.
237 +
238 +The ``max-v9`` CPU enables all of the listed extensions except for
239 +those that are prohibited by the Armv9-A architecture: FEAT_AA32EL1,
240 +FEAT_AA32EL2, FEAT_AA32EL3, and FEAT_DoubleLock.
241 +
242 +The ``max`` CPU is an alias for ``max-v9`` under AArch64 TCG emulation,
243 +an alias for ``max-v8`` under AArch32 TCG emulation, or an alias
244 +for ``host`` under hardware virtualization.
245
246 R-profile CPU architecture support
247 ==================================
target/arm/cpu-max.c
+1 -1
@@ -110,7 +110,7 @@ static void cpu_max_initfn(Object *obj)
110 if (!aarch64_enabled) {
111 aarch32_max_v8_tcg_initfn(obj);
112 } else {
113 - aarch64_max_tcg_initfn(obj);
113 + aarch64_max_v9_tcg_initfn(obj);
114 }
115 return;
116 }
target/arm/internals.h
+2 -1
@@ -1809,7 +1809,8 @@ void aarch64_cpu_sve_finalize(ARMCPU *cpu, Error **errp);
1809 void aarch64_cpu_sme_finalize(ARMCPU *cpu, Error **errp);
1810 void aarch64_cpu_pauth_finalize(ARMCPU *cpu, Error **errp);
1811 void aarch64_cpu_lpa2_finalize(ARMCPU *cpu, Error **errp);
1812 -void aarch64_max_tcg_initfn(Object *obj);
1812 +void aarch64_max_v8_tcg_initfn(Object *obj);
1813 +void aarch64_max_v9_tcg_initfn(Object *obj);
1814 void aarch64_add_pauth_properties(Object *obj);
1815 void aarch64_add_sve_properties(Object *obj);
1816 void aarch64_add_sme_properties(Object *obj);
target/arm/tcg/cpu-max-v8.c
+1 -1
@@ -123,7 +123,7 @@ static void cpu_max_v8_register_type(void)
123 {
124 static const ARMCPUInfo max_v8[2] = {
125 { .name = "max-v8", .initfn = aarch32_max_v8_tcg_initfn },
126 - { .name = "max-v8", .initfn = aarch64_max_tcg_initfn }
126 + { .name = "max-v8", .initfn = aarch64_max_v8_tcg_initfn },
127 };
128 arm_cpu_register(&max_v8[target_aarch64()]);
129 }
target/arm/tcg/cpu64.c
+106 -54
@@ -1166,11 +1166,10 @@ static void aarch64_neoverse_n2_initfn(Object *obj)
1166 }
1167
1168 /*
1169 - * -cpu max: a CPU with as many features enabled as our emulation supports.
1170 - * The version of '-cpu max' for qemu-system-arm is defined in cpu32.c;
1171 - * this only needs to handle 64 bits.
1169 + * -cpu max-v8: an ARMv8 CPU with as many features enabled as
1170 + * our emulation supports.
1171 */
1173 -void aarch64_max_tcg_initfn(Object *obj)
1172 +void aarch64_max_v8_tcg_initfn(Object *obj)
1173 {
1174 ARMCPU *cpu = ARM_CPU(obj);
1175 ARMISARegisters *isar = &cpu->isar;
@@ -1244,7 +1243,7 @@ void aarch64_max_tcg_initfn(Object *obj)
1243 t = FIELD_DP64(t, ID_AA64ISAR0, SHA1, 1); /* v8.0: FEAT_SHA1 */
1244 t = FIELD_DP64(t, ID_AA64ISAR0, SHA2, 2); /* v8.1: FEAT_SHA512 */
1245 t = FIELD_DP64(t, ID_AA64ISAR0, CRC32, 1); /* v8.0: FEAT_CRC32 */
1247 - t = FIELD_DP64(t, ID_AA64ISAR0, ATOMIC, 3); /* v9.3: FEAT_LSE128 */
1246 + t = FIELD_DP64(t, ID_AA64ISAR0, ATOMIC, 2); /* v8.0: FEAT_LSE */
1247 t = FIELD_DP64(t, ID_AA64ISAR0, RDM, 1); /* v8.0: FEAT_RDM */
1248 t = FIELD_DP64(t, ID_AA64ISAR0, SHA3, 1); /* v8.1: FEAT_SHA3 */
1249 t = FIELD_DP64(t, ID_AA64ISAR0, SM3, 1); /* v8.1: FEAT_SM3 */
@@ -1277,16 +1276,10 @@ void aarch64_max_tcg_initfn(Object *obj)
1276 t = FIELD_DP64(t, ID_AA64ISAR2, MOPS, 1); /* v8.7: FEAT_MOPS */
1277 t = FIELD_DP64(t, ID_AA64ISAR2, BC, 1); /* v8.7: FEAT_HBC */
1278 t = FIELD_DP64(t, ID_AA64ISAR2, WFXT, 2); /* v8.6: FEAT_WFxT */
1280 - t = FIELD_DP64(t, ID_AA64ISAR2, CSSC, 2); /* v9.3: FEAT_CMPBR */
1281 - t = FIELD_DP64(t, ID_AA64ISAR2, LUT, 1); /* v9.2: FEAT_LUT */
1279 + t = FIELD_DP64(t, ID_AA64ISAR2, CSSC, 1); /* v8.7: FEAT_CSSC */
1280 t = FIELD_DP64(t, ID_AA64ISAR2, ATS1A, 1); /* v8.8: FEAT_ATS1A */
1281 SET_IDREG(isar, ID_AA64ISAR2, t);
1282
1285 - t = GET_IDREG(isar, ID_AA64ISAR3);
1286 - t = FIELD_DP64(t, ID_AA64ISAR3, FAMINMAX, 1); /* v9.2: FEAT_FAMINMAX */
1287 - t = FIELD_DP64(t, ID_AA64ISAR3, FPRCVT, 1); /* v9.5: FEAT_FPRCVT */
1288 - SET_IDREG(isar, ID_AA64ISAR3, t);
1289 -
1283 t = GET_IDREG(isar, ID_AA64PFR0);
1284 t = FIELD_DP64(t, ID_AA64PFR0, FP, 1); /* v8.2: FEAT_FP16 */
1285 t = FIELD_DP64(t, ID_AA64PFR0, ADVSIMD, 1); /* v8.2: FEAT_FP16 */
@@ -1308,17 +1301,14 @@ void aarch64_max_tcg_initfn(Object *obj)
1301 */
1302 t = FIELD_DP64(t, ID_AA64PFR1, MTE, 3); /* v8.5: FEAT_MTE3 */
1303 t = FIELD_DP64(t, ID_AA64PFR1, RAS_FRAC, 0); /* v8.3: FEAT_DoubleFault */
1311 - t = FIELD_DP64(t, ID_AA64PFR1, SME, 2); /* v9.2: FEAT_SME2 */
1304 t = FIELD_DP64(t, ID_AA64PFR1, RNDR_TRAP, 1); /* v8.4: FEAT_RNG_TRAP */
1305 t = FIELD_DP64(t, ID_AA64PFR1, CSV2_FRAC, 0); /* v8.0: FEAT_CSV2_3 */
1306 t = FIELD_DP64(t, ID_AA64PFR1, NMI, 1); /* v8.7: FEAT_NMI */
1315 - t = FIELD_DP64(t, ID_AA64PFR1, GCS, 1); /* v9.3: FEAT_GCS */
1307 /* v8.7: FEAT_MTE_NO_ADDRESS_TAGS + FEAT_MTE_CANONICAL_TAGS */
1308 t = FIELD_DP64(t, ID_AA64PFR1, MTEX, 1);
1309 SET_IDREG(isar, ID_AA64PFR1, t);
1310
1311 t = GET_IDREG(isar, ID_AA64PFR2);
1321 - t = FIELD_DP64(t, ID_AA64PFR2, FPMR, 1); /* v9.2: FEAT_FPMR */
1312 t = FIELD_DP64(t, ID_AA64PFR2, MTEFAR, 1); /* v8.7: FEAT_MTE_TAGGED_FAR */
1313 t = FIELD_DP64(t, ID_AA64PFR2, MTESTOREONLY, 1); /* v8.7: FEAT_MTE_STORE_ONLY */
1314 t = FIELD_DP64(t, ID_AA64PFR2, MTEPERM, 1); /* v8.7: FEAT_MTE_PERM */
@@ -1368,25 +1358,14 @@ void aarch64_max_tcg_initfn(Object *obj)
1358 t = GET_IDREG(isar, ID_AA64MMFR3);
1359 t = FIELD_DP64(t, ID_AA64MMFR3, TCRX, 1); /* v8.0: FEAT_TCR2 */
1360 t = FIELD_DP64(t, ID_AA64MMFR3, SCTLRX, 1); /* v8.0: FEAT_SCTLR2 */
1371 - t = FIELD_DP64(t, ID_AA64MMFR3, MEC, 1); /* v9.2: FEAT_MEC */
1361 t = FIELD_DP64(t, ID_AA64MMFR3, SPEC_FPACC, 1); /* v8.2: FEAT_FPACC_SPEC */
1362 t = FIELD_DP64(t, ID_AA64MMFR3, S1PIE, 1); /* v8.8: FEAT_S1PIE */
1363 t = FIELD_DP64(t, ID_AA64MMFR3, S2PIE, 1); /* v8.8: FEAT_S2PIE */
1364 t = FIELD_DP64(t, ID_AA64MMFR3, AIE, 1); /* v8.8: FEAT_AIE */
1365 SET_IDREG(isar, ID_AA64MMFR3, t);
1366
1378 - t = GET_IDREG(isar, ID_AA64MMFR4);
1379 - t = FIELD_DP64(t, ID_AA64MMFR4, ASID2, 1); /* v9.4: FEAT_ASID2 */
1380 - SET_IDREG(isar, ID_AA64MMFR4, t);
1381 -
1367 t = GET_IDREG(isar, ID_AA64ZFR0);
1383 - t = FIELD_DP64(t, ID_AA64ZFR0, SVEVER, 2); /* v9.2: FEAT_SVE2p1 */
1384 - t = FIELD_DP64(t, ID_AA64ZFR0, AES, 2); /* v9.0: FEAT_SVE_PMULL128 */
1385 - t = FIELD_DP64(t, ID_AA64ZFR0, BITPERM, 1); /* v9.0: FEAT_SVE_BitPerm */
1368 t = FIELD_DP64(t, ID_AA64ZFR0, BFLOAT16, 2); /* v8.2: FEAT_EBF16 */
1387 - t = FIELD_DP64(t, ID_AA64ZFR0, B16B16, 1); /* v9.2: FEAT_SVE_B16B16 */
1388 - t = FIELD_DP64(t, ID_AA64ZFR0, SHA3, 1); /* v9.0: FEAT_SVE_SHA3 */
1389 - t = FIELD_DP64(t, ID_AA64ZFR0, SM4, 1); /* v9.0: FEAT_SVE_SM4 */
1369 t = FIELD_DP64(t, ID_AA64ZFR0, I8MM, 1); /* v8.1: FEAT_I8MM */
1370 t = FIELD_DP64(t, ID_AA64ZFR0, F32MM, 1); /* v8.2: FEAT_F32MM */
1371 t = FIELD_DP64(t, ID_AA64ZFR0, F64MM, 1); /* v8.2: FEAT_F64MM */
@@ -1398,6 +1377,106 @@ void aarch64_max_tcg_initfn(Object *obj)
1377 t = FIELD_DP64(t, ID_AA64DFR0, HPMN0, 1); /* v8.5: FEAT_HPMN0 */
1378 SET_IDREG(isar, ID_AA64DFR0, t);
1379
1380 + /* Replicate the same data to the 32-bit id registers. */
1381 + aa32_max_features(cpu);
1382 +
1383 +#ifdef CONFIG_USER_ONLY
1384 + /*
1385 + * For usermode -cpu max we can use a larger and more efficient DCZ
1386 + * blocksize since we don't have to follow what the hardware does.
1387 + */
1388 + cpu->ctr = 0x80038003; /* 32 byte I and D cacheline size, VIPT icache */
1389 + set_dczid_bs(cpu, 7); /* 512 bytes */
1390 +#endif
1391 +
1392 + /* v8.2: FEAT_SVE */
1393 + cpu->sve_vq.supported = MAKE_64BIT_MASK(0, ARM_MAX_VQ);
1394 + aarch64_add_sve_properties(OBJECT(cpu));
1395 + object_property_add(OBJECT(cpu), "sve-max-vq", "uint32",
1396 + cpu_max_get_sve_max_vq, cpu_max_set_sve_max_vq,
1397 + NULL, NULL);
1398 +
1399 + /* v8.2: FEAT_PAuth2 */
1400 + aarch64_add_pauth_properties(OBJECT(cpu));
1401 +
1402 + /* v8.4: FEAT_MTE2 */
1403 + cpu->gm_blocksize = 6; /* 256 bytes */
1404 +
1405 + /* v8.6: FEAT_LPA2 */
1406 + qdev_property_add_static(DEVICE(cpu), &arm_cpu_lpa2_property);
1407 +}
1408 +
1409 +/*
1410 + * -cpu max-v9: an ARMv9 CPU with as many features enabled as
1411 + * our emulation supports.
1412 + */
1413 +void aarch64_max_v9_tcg_initfn(Object *obj)
1414 +{
1415 + ARMCPU *cpu = ARM_CPU(obj);
1416 + ARMISARegisters *isar = &cpu->isar;
1417 + uint64_t t;
1418 +
1419 + /* Armv9.0 is based on a minimum of Armv8.5. */
1420 + aarch64_max_v8_tcg_initfn(obj);
1421 +
1422 + /*
1423 + * Armv9.0 does not support AArch32 except at EL0,
1424 + * therefore indicate EL1 through EL3 are AArch64-only.
1425 + */
1426 + t = GET_IDREG(isar, ID_AA64PFR0);
1427 + t = FIELD_DP64(t, ID_AA64PFR0, EL1, 1);
1428 + t = FIELD_DP64(t, ID_AA64PFR0, EL2, 1);
1429 + t = FIELD_DP64(t, ID_AA64PFR0, EL3, 1);
1430 + SET_IDREG(isar, ID_AA64PFR0, t);
1431 +
1432 + /* v9.0 prohibits FEAT_DoubleLock. */
1433 + FIELD_DP64_IDREG(isar, ID_AA64DFR0, DOUBLELOCK, -1);
1434 + FIELD_DP64_IDREG(isar, ID_AA64PFR0, RAS, 1);
1435 + isar->dbgdevid = FIELD_DP32(isar->dbgdevid, DBGDEVID, DOUBLELOCK, 0);
1436 +
1437 + /*
1438 + * Below, note the revision from which the feature is OPTIONAL.
1439 + */
1440 + t = GET_IDREG(isar, ID_AA64ISAR0);
1441 + t = FIELD_DP64(t, ID_AA64ISAR0, ATOMIC, 3); /* v9.3: FEAT_LSE128 */
1442 + SET_IDREG(isar, ID_AA64ISAR0, t);
1443 +
1444 + t = GET_IDREG(isar, ID_AA64ISAR2);
1445 + t = FIELD_DP64(t, ID_AA64ISAR2, CSSC, 2); /* v9.3: FEAT_CMPBR */
1446 + t = FIELD_DP64(t, ID_AA64ISAR2, LUT, 1); /* v9.2: FEAT_LUT */
1447 + SET_IDREG(isar, ID_AA64ISAR2, t);
1448 +
1449 + t = GET_IDREG(isar, ID_AA64ISAR3);
1450 + t = FIELD_DP64(t, ID_AA64ISAR3, FAMINMAX, 1); /* v9.2: FEAT_FAMINMAX */
1451 + t = FIELD_DP64(t, ID_AA64ISAR3, FPRCVT, 1); /* v9.5: FEAT_FPRCVT */
1452 + SET_IDREG(isar, ID_AA64ISAR3, t);
1453 +
1454 + t = GET_IDREG(isar, ID_AA64PFR1);
1455 + t = FIELD_DP64(t, ID_AA64PFR1, SME, 2); /* v9.2: FEAT_SME2 */
1456 + t = FIELD_DP64(t, ID_AA64PFR1, GCS, 1); /* v9.3: FEAT_GCS */
1457 + SET_IDREG(isar, ID_AA64PFR1, t);
1458 +
1459 + t = GET_IDREG(isar, ID_AA64PFR2);
1460 + t = FIELD_DP64(t, ID_AA64PFR2, FPMR, 1); /* v9.2: FEAT_FPMR */
1461 + SET_IDREG(isar, ID_AA64PFR2, t);
1462 +
1463 + t = GET_IDREG(isar, ID_AA64MMFR3);
1464 + t = FIELD_DP64(t, ID_AA64MMFR3, MEC, 1); /* v9.2: FEAT_MEC */
1465 + SET_IDREG(isar, ID_AA64MMFR3, t);
1466 +
1467 + t = GET_IDREG(isar, ID_AA64MMFR4);
1468 + t = FIELD_DP64(t, ID_AA64MMFR4, ASID2, 1); /* v9.4: FEAT_ASID2 */
1469 + SET_IDREG(isar, ID_AA64MMFR4, t);
1470 +
1471 + t = GET_IDREG(isar, ID_AA64ZFR0);
1472 + t = FIELD_DP64(t, ID_AA64ZFR0, SVEVER, 2); /* v9.2: FEAT_SVE2p1 */
1473 + t = FIELD_DP64(t, ID_AA64ZFR0, AES, 2); /* v9.0: FEAT_SVE_PMULL128 */
1474 + t = FIELD_DP64(t, ID_AA64ZFR0, BITPERM, 1); /* v9.0: FEAT_SVE_BitPerm */
1475 + t = FIELD_DP64(t, ID_AA64ZFR0, B16B16, 1); /* v9.2: FEAT_SVE_B16B16 */
1476 + t = FIELD_DP64(t, ID_AA64ZFR0, SHA3, 1); /* v9.0: FEAT_SVE_SHA3 */
1477 + t = FIELD_DP64(t, ID_AA64ZFR0, SM4, 1); /* v9.0: FEAT_SVE_SM4 */
1478 + SET_IDREG(isar, ID_AA64ZFR0, t);
1479 +
1480 t = GET_IDREG(isar, ID_AA64SMFR0);
1481 t = FIELD_DP64(t, ID_AA64SMFR0, SMOP4, 1); /* v9.4: FEAT_SME_MOP4 */
1482 t = FIELD_DP64(t, ID_AA64SMFR0, STMOP, 1); /* v9.4: FEAT_SME_TMOP */
@@ -1434,43 +1513,16 @@ void aarch64_max_tcg_initfn(Object *obj)
1513 t = FIELD_DP64(t, ID_AA64FPFR0, F8CVT, 1); /* v9.2: FEAT_FP8 */
1514 SET_IDREG(isar, ID_AA64FPFR0, t);
1515
1437 - /* Replicate the same data to the 32-bit id registers. */
1438 - aa32_max_features(cpu);
1439 -
1440 -#ifdef CONFIG_USER_ONLY
1441 - /*
1442 - * For usermode -cpu max we can use a larger and more efficient DCZ
1443 - * blocksize since we don't have to follow what the hardware does.
1444 - */
1445 - cpu->ctr = 0x80038003; /* 32 byte I and D cacheline size, VIPT icache */
1446 - set_dczid_bs(cpu, 7); /* 512 bytes */
1447 -#endif
1448 -
1449 - /* v8.4: FEAT_MTE2 */
1450 - cpu->gm_blocksize = 6; /* 256 bytes */
1451 -
1452 - /* v8.2: FEAT_SVE */
1453 - cpu->sve_vq.supported = MAKE_64BIT_MASK(0, ARM_MAX_VQ);
1454 - aarch64_add_sve_properties(obj);
1455 - object_property_add(obj, "sve-max-vq", "uint32", cpu_max_get_sve_max_vq,
1456 - cpu_max_set_sve_max_vq, NULL, NULL);
1457 -
1516 /* v9.2: FEAT_SME */
1517 cpu->sme_vq.supported = SVE_VQ_POW2_MAP;
1518 aarch64_add_sme_properties(obj);
1519
1462 - /* v8.2: FEAT_PAuth2 */
1463 - aarch64_add_pauth_properties(obj);
1464 -
1520 /* v9.1: FEAT_RME */
1521 object_property_add_bool(obj, "x-rme", cpu_arm_get_rme, cpu_arm_set_rme);
1522
1523 /* v9.4: FEAT_RME_GPC2 */
1524 object_property_add(obj, "x-l0gptsz", "uint32", cpu_max_get_l0gptsz,
1525 cpu_max_set_l0gptsz, NULL, NULL);
1471 -
1472 - /* v8.6: FEAT_LPA2 */
1473 - qdev_property_add_static(DEVICE(obj), &arm_cpu_lpa2_property);
1526 }
1527
1528 static const ARMCPUInfo aarch64_cpus[] = {
@@ -1488,7 +1540,7 @@ static const ARMCPUInfo aarch64_cpus[] = {
1540 { .name = "neoverse-n1", .initfn = aarch64_neoverse_n1_initfn },
1541 { .name = "neoverse-v1", .initfn = aarch64_neoverse_v1_initfn },
1542 { .name = "neoverse-n2", .initfn = aarch64_neoverse_n2_initfn },
1491 - { .name = "max-v9", .initfn = aarch64_max_tcg_initfn },
1543 + { .name = "max-v9", .initfn = aarch64_max_v9_tcg_initfn },
1544 };
1545
1546 static void aarch64_cpu_register_types(void)
target/arm/tcg/stubs32.c
+6 -1
@@ -28,7 +28,12 @@ void aarch64_host_initfn(Object *obj)
28 g_assert_not_reached();
29 }
30
31 -void aarch64_max_tcg_initfn(Object *obj)
31 +void aarch64_max_v8_tcg_initfn(Object *obj)
32 +{
33 + g_assert_not_reached();
34 +}
35 +
36 +void aarch64_max_v9_tcg_initfn(Object *obj)
37 {
38 g_assert_not_reached();
39 }