* [RFC PATCH v4 00/25] named CPU models for Arm64 on KVM
@ 2026-09-21 12:32 Khushit Shah
2026-09-21 12:32 ` [RFC PATCH v4 01/25] target/arm: expose SYSREG_ props for REVIDR_EL1 and AIDR_EL1 Khushit Shah
` (25 more replies)
0 siblings, 26 replies; 66+ messages in thread
From: Khushit Shah @ 2026-09-21 12:32 UTC (permalink / raw)
To: qemu-devel, qemu-arm, kvmarm, eric.auger
Cc: cohuck, peter.maydell, richard.henderson, maz, oliver.upton,
berrange, abologna, jdenemar, gshan, skolothumtho, sebott, armbru,
philmd, yangjinqian1, shaju.abraham, mark.caveayland,
khushit.shah, ping, sandesh.patel
Hi All,
Here is v4 of the RFC for named CPU models on Arm64/KVM.
Background:
=============================================================
Currently QEMU only supports -cpu host/max for KVM on Arm64. This blocks
live migration of VMs between hosts that differ in CPU features.
This RFC proposes hierarchical named models for Arm64 under KVM. A named
model is a strict contract of the CPU features exposed to the guest, so
the same model resolves to the same guest-visible ID registers on any
capable host. Models can be customized further by overriding individual
ID-register fields (e.g. SYSREG_ID_AA64ISAR0_EL1_SHA1=0).
On top of the models, this series adds the QMP introspection support on
Arm that the management layer already depends on for x86:
`query-cpu-definitions` lists the models a host can run and reports
blockers for the ones it cannot, `query-cpu-model-expansion` resolves a
model to its full set of properties, and the new `query-cpu-props-info`
reports the values the host supports for each property. The aim is feature
parity with x86 so existing tooling can consume Arm named models with
little change.
TL;DR examples:
=============================================================
# Boot a named model
qemu-system-aarch64 -cpu grace-v1 -machine virt,accel=kvm ...
# Named model with ID-register field override
qemu-system-aarch64 -cpu grace-v1,SYSREG_ID_AA64ISAR0_EL1_SHA1=0 ...
# -cpu host with ID-register field override
qemu-system-aarch64 -cpu host,SYSREG_ID_AA64ISAR0_EL1_AES=1 ...
# query-cpu-model-expansion
"model": {
"name": "graviton4-v1",
"props": {
"SYSREG_ID_AA64ISAR0_EL1_AES": 2,
"SYSREG_ID_AA64ISAR0_EL1_SHA1": 1,
"SYSREG_ID_AA64ISAR0_EL1_SHA2": 2,
"SYSREG_ID_AA64ISAR1_EL1_APA": 3,
"SYSREG_ID_AA64PFR0_EL1_SVE": 1,
"sve": true,
"sve128": true,
...
}
}
# query-cpu-definitions: blockers reporting
{
"name": "graviton4-v1",
"typename": "graviton4-v1-arm-cpu",
"unavailable-features": [
"SYSREG_ID_AA64MMFR0_EL1_TGran16_2",
"SYSREG_ID_AA64MMFR0_EL1_TGran64_2",
"SYSREG_ID_AA64MMFR0_EL1_TGran4_2",
"SYSREG_ID_AA64ISAR1_EL1_APA",
"SYSREG_ID_AA64ISAR0_EL1_SM3",
"SYSREG_ID_AA64ISAR0_EL1_SM4"
],
"static": false,
"deprecated": false
}
# new query-cpu-props-info: supported values per property
{
"name": "SYSREG_ID_AA64ISAR0_EL1_AES",
"supported-values": [
{ "min": 2, "max": 2 },
{ "min": 1, "max": 1 },
{ "min": 0, "max": 0 }
],
"type": "number"
},
{
"name": "sve",
"supported-values": [ true, false ],
"type": "boolean"
}
The series can be found at:
https://github.com/khushit-shah-nx/qemu/tree/rfc-v4
Changes from v3 -> v4:
- Rebased on v8 of Eric Auger's customizable AArch64 KVM host-model
series.
- Stopped exposing reserved ID-register fields, as suggested by Eric.
- Converted appropriate warnings to trace events, as suggested by Eric.
- Split the per-field ID-register writeback refactoring from the
special-field handling.
- Each model now has a separate patch containing its final ID-register
state and architecture references, as suggested by Eric.
- Removed the non-zero-defaults named model layer, as suggested by Eric.
- Disabled PMU for named models.
- Added forward-compatibility: reject a named model when KVM exposes an
unknown feature ID register with a non-zero value.
- Split query-cpu-props-info's generic QAPI definition and its
Arm/KVM implementation.
- Moved query-cpu-definitions ID-register blocker calculation from
generic Arm code into the KVM-specific implementation.
- Dropped the narrow EL2 writeback workaround; this is now handled
properly by Eric's v9 series.
v3: https://lore.kernel.org/qemu-arm/20260716213858.609699-1-khushit.shah@nutanix.com/
Left out:
- CNTFRQ_EL0 handling during heterogenous migrations: This is not related
to named CPU models, will send separate patch for this.
- SYSREG_ prop and legacy prop interaction/consistency: handled by Eric
Khushit Shah (25):
target/arm: expose SYSREG_ props for REVIDR_EL1 and AIDR_EL1
target/arm: expose all non-res ID reg fields as properties
target/arm: move SYSREG_ prop infra to cpu64.c
target/arm/kvm: enable writable implementation ID registers
target/arm/kvm: read all ID registers from KVM
target/arm/kvm: handle special ID registers when reading from KVM
target/arm/kvm: process ID register writeback per field
target/arm/kvm: handle writeback for special ID register fields
target/arm: introduce named CPU model infrastructure
target/arm: fix SVE and PAuth finalize for named CPU models
target/arm: disable PMU support for named CPU models
target/arm: add arm-v9.0-a-v1 named CPU model
target/arm: add neoverse-v2-v1 named CPU model
target/arm: add neoverse-v2-v2 named CPU model
target/arm: add graviton4-v1 named CPU model
target/arm: add grace-v1 named CPU model
target/arm: fail named CPU models on unknown non-zero feature ID regs
target/arm: add cpu-models-stub.c
target/arm/qmp: allow named CPU models on cpu-model-expansion
target/arm/kvm: compute host-supported values for ID register fields
target/arm: report 0 as supported for ID fields gated by vCPU init
flags
target/arm/kvm: add kvm_arm_get_host_isar helper
qmp: add query-cpu-props-info command
target/arm/qmp: implement query-cpu-props-info for KVM
target/arm/qmp: hook blockers in query-cpu-definitions
docs/system/arm/cpu-features.rst | 34 +-
hw/arm/virt.c | 7 +
qapi/machine.json | 82 +++
.../update-aarch64-cpu-sysreg-properties.py | 9 +
stubs/meson.build | 1 +
stubs/qmp-cpu-props-info.c | 12 +
target/arm/arm-qmp-cmds.c | 105 ++++
target/arm/cpu-idregs.c | 19 +
target/arm/cpu-idregs.h | 4 +
target/arm/cpu-idregs.h.inc | 2 +
target/arm/cpu-models-stub.c | 18 +
target/arm/cpu-models.c | 536 ++++++++++++++++++
target/arm/cpu-models.h | 38 ++
target/arm/cpu-sysregs.h | 2 +-
target/arm/cpu64.c | 139 ++++-
target/arm/internals.h | 1 +
target/arm/kvm-stub.c | 19 +
target/arm/kvm.c | 521 +++++++++++------
target/arm/kvm_arm.h | 57 +-
target/arm/meson.build | 2 +
target/arm/trace-events | 9 +-
tests/qtest/qmp-cmd-test.c | 1 +
22 files changed, 1404 insertions(+), 214 deletions(-)
create mode 100644 stubs/qmp-cpu-props-info.c
create mode 100644 target/arm/cpu-models-stub.c
create mode 100644 target/arm/cpu-models.c
create mode 100644 target/arm/cpu-models.h
--
2.52.0
^ permalink raw reply [flat|nested] 66+ messages in thread
* [RFC PATCH v4 01/25] target/arm: expose SYSREG_ props for REVIDR_EL1 and AIDR_EL1
2026-09-21 12:32 [RFC PATCH v4 00/25] named CPU models for Arm64 on KVM Khushit Shah
@ 2026-09-21 12:32 ` Khushit Shah
2026-09-23 16:22 ` Eric Auger
2026-09-21 12:32 ` [RFC PATCH v4 02/25] target/arm: expose all non-res ID reg fields as properties Khushit Shah
` (24 subsequent siblings)
25 siblings, 1 reply; 66+ messages in thread
From: Khushit Shah @ 2026-09-21 12:32 UTC (permalink / raw)
To: qemu-devel, qemu-arm, kvmarm, eric.auger
Cc: cohuck, peter.maydell, richard.henderson, maz, oliver.upton,
berrange, abologna, jdenemar, gshan, skolothumtho, sebott, armbru,
philmd, yangjinqian1, shaju.abraham, mark.caveayland,
khushit.shah, ping, sandesh.patel
REVIDR_EL1 and AIDR_EL1 are implementation-defined and have no named
fields in Registers.json.
Emit dummy VAL fields covering the full register for these registers
in scripts/update-aarch64-cpu-sysreg-properties.py, then remove the
special case for these in kvm_arm_expose_idreg_properties(), exposing
them as SYSREG_ props.
Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
---
scripts/update-aarch64-cpu-sysreg-properties.py | 9 +++++++++
target/arm/cpu-idregs.h.inc | 2 ++
target/arm/kvm.c | 10 +---------
3 files changed, 12 insertions(+), 9 deletions(-)
diff --git a/scripts/update-aarch64-cpu-sysreg-properties.py b/scripts/update-aarch64-cpu-sysreg-properties.py
index 0b4e4d3e0c..2269063408 100644
--- a/scripts/update-aarch64-cpu-sysreg-properties.py
+++ b/scripts/update-aarch64-cpu-sysreg-properties.py
@@ -246,6 +246,15 @@ def generate_sysreg_properties_from_registers_json(id_reg_names, raw_json_path):
# Sort decreasing lsbs
sorted_fields = sorted(unique_fields.items(),
key=lambda x: x[1]['lsb'], reverse=True)
+ if len(sorted_fields) == 0:
+ # For cases like REVIDR_EL1, add a dummy field covering the
+ # full register.
+ sorted_fields.append(('VAL', {
+ 'lsb': 0,
+ 'msb': 63,
+ 'width': 64,
+ 'enums': []
+ }))
for unique_key, bits in sorted_fields:
enums_list = bits.get('enums', [])
diff --git a/target/arm/cpu-idregs.h.inc b/target/arm/cpu-idregs.h.inc
index c7e93c48b7..bc52112430 100644
--- a/target/arm/cpu-idregs.h.inc
+++ b/target/arm/cpu-idregs.h.inc
@@ -12,6 +12,7 @@
/* IDREG_END(REG) */
IDREG_START(AIDR_EL1)
+ IDREG_FIELD(AIDR_EL1, VAL, 0, 64)
IDREG_END(AIDR_EL1)
IDREG_START(CLIDR_EL1)
@@ -2438,6 +2439,7 @@ IDREG_START(MVFR2_EL1)
IDREG_END(MVFR2_EL1)
IDREG_START(REVIDR_EL1)
+ IDREG_FIELD(REVIDR_EL1, VAL, 0, 64)
IDREG_END(REVIDR_EL1)
IDREG_START(SMIDR_EL1)
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index e3a0dc07de..8a823d0324 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -554,15 +554,7 @@ void kvm_arm_expose_idreg_properties(ARMCPU *cpu, ARM64SysReg *regs)
ARM64SysReg *sysregdesc = ®s[i];
if (sysregdesc->writable_mask) {
- /*
- * special case REVIDR_EL1 and AIDR_EL1 which are writable but
- * do not expose named fields. They will need to be handled
- * separately
- */
- if (strcmp(sysregdesc->name, "REVIDR_EL1") &&
- strcmp(sysregdesc->name, "AIDR_EL1")) {
- decode_idreg_writemap(obj, sysregdesc);
- }
+ decode_idreg_writemap(obj, sysregdesc);
}
}
}
--
2.52.0
^ permalink raw reply related [flat|nested] 66+ messages in thread
* [RFC PATCH v4 02/25] target/arm: expose all non-res ID reg fields as properties
2026-09-21 12:32 [RFC PATCH v4 00/25] named CPU models for Arm64 on KVM Khushit Shah
2026-09-21 12:32 ` [RFC PATCH v4 01/25] target/arm: expose SYSREG_ props for REVIDR_EL1 and AIDR_EL1 Khushit Shah
@ 2026-09-21 12:32 ` Khushit Shah
2026-09-23 16:37 ` Eric Auger
2026-09-24 6:46 ` Eric Auger
2026-09-21 12:32 ` [RFC PATCH v4 03/25] target/arm: move SYSREG_ prop infra to cpu64.c Khushit Shah
` (23 subsequent siblings)
25 siblings, 2 replies; 66+ messages in thread
From: Khushit Shah @ 2026-09-21 12:32 UTC (permalink / raw)
To: qemu-devel, qemu-arm, kvmarm, eric.auger
Cc: cohuck, peter.maydell, richard.henderson, maz, oliver.upton,
berrange, abologna, jdenemar, gshan, skolothumtho, sebott, armbru,
philmd, yangjinqian1, shaju.abraham, mark.caveayland,
khushit.shah, ping, sandesh.patel
Upcoming named CPU model layer will require exposing all the ID register
fields as properties.
Furthermore, this exposes the host values of all ID register fields
to the management stack, which can use them to infer migration
compatibility constraints between different hosts.
Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
---
docs/system/arm/cpu-features.rst | 34 +++++++--------
target/arm/cpu64.c | 2 +-
target/arm/kvm.c | 71 +++++++-------------------------
target/arm/trace-events | 2 -
4 files changed, 31 insertions(+), 78 deletions(-)
diff --git a/docs/system/arm/cpu-features.rst b/docs/system/arm/cpu-features.rst
index 3a07a87bc3..62bb2bd999 100644
--- a/docs/system/arm/cpu-features.rst
+++ b/docs/system/arm/cpu-features.rst
@@ -34,17 +34,15 @@ running guests in AArch32.
CPU features that are inherently specific to KVM are
prefixed with "kvm-" and are described in "KVM VCPU Features".
-2. Additionally, the ``host`` CPU model on KVM allows to configure optional
-CPU features via the corresponding ID registers. The host kernel allows
-to write a subset of ID register fields. The host model exposes
-properties for each writable ID register field. Those options are named
-SYSREG_<IDREG>_<FIELD>. IDREG and FIELD names are those used in the
-ARM Architecture Reference Manual. Their availability depend on the host
-capability to let the userspace write those fields. Values set with those
-properties override the initial values retrieved from the host. They are
-written back to KVM and the eventual value applied by KVM depends on whether
-the value is sanitized or not by the host kernel. Then those field values
-are likely to be overriden again by legacy CPU options which apply at the end.
+2. Additionally, the ``host`` CPU model on KVM allows configuring optional
+CPU features through the corresponding ID registers. The host model exposes
+properties for every non-reserved ID register field known to QEMU. Those
+properties are named SYSREG_<IDREG>_<FIELD>. IDREG and FIELD names are those
+used in the Arm Architecture Reference Manual. Values set with those
+properties override the initial values retrieved from the host. Whether a
+value that differs from the host value can be applied depends on KVM support
+and any field-specific handling in QEMU. Legacy CPU options applied later may
+override those field values.
CPU Feature Probing
===================
@@ -534,12 +532,10 @@ Note that this is currently only supported under KVM, and with the
Querying available ID register fields
-------------------------------------
-QEMU will create properties for all ID register fields that are
-reported as being writable by the kernel, and that are known to the
-QEMU instance. Therefore, the same QEMU binary may expose different
-properties when run under a different kernel.
+QEMU creates properties for all non-reserved ID register fields known to
+the QEMU instance.
-To find out all available writable ID register fields, use the
+To find out all available ID register fields, use the
``query-cpu-model-expansion`` QMP command::
(QEMU) query-cpu-model-expansion type=full model={"name":"host"}
@@ -554,8 +550,10 @@ To find out all available writable ID register fields, use the
"SYSREG_ID_AA64ISAR0_EL1_DP": 1, (...)
}}}}
-If a certain field in an ID register does not show up in this list, it
-is not writable with the specific host kernel.
+The presence of a property does not imply that every value is supported.
+Non-writable fields must retain their host value, while writable fields are
+limited to the values supported by KVM. A configuration requesting an
+unsupported value is rejected.
A note on compatibility
-----------------------
diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
index e04062e848..3d522bf20d 100644
--- a/target/arm/cpu64.c
+++ b/target/arm/cpu64.c
@@ -809,7 +809,7 @@ void aarch64_host_initfn(Object *obj)
kvm_arm_set_cpu_features_from_host(cpu);
aarch64_add_sve_properties(obj);
- /* generate SYSREG properties according to writable masks */
+ /* generate SYSREG properties */
kvm_arm_expose_idreg_properties(cpu, arm64_id_regs);
#elif defined(CONFIG_HVF)
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index 8a823d0324..2f6c090e43 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -365,19 +365,6 @@ static int get_host_cpu_idregs(int fd, ARMHostCPUFeatures *ahcf)
return err;
}
-static ARM64SysRegField *get_field(int i, ARM64SysReg *reg)
-{
- for (int f = 0; f < reg->fields_count; f++) {
- struct ARM64SysRegField *field = ®->fields[f];
- int upper = field->shift + field->length - 1;
-
- if (i >= field->shift && i <= upper) {
- return field;
- }
- }
- return NULL;
-}
-
bool kvm_idreg_write_scratch_vcpu(int cpufd, Visitor *v, const char *name,
void *opaque, Error **errp)
{
@@ -493,69 +480,39 @@ static void get_sysreg_prop(Object *obj, Visitor *v,
trace_get_sysreg_prop(name, value);
}
-/*
- * decode_idreg_writemap: Generate props for writable fields
- *
- * @obj: CPU object
- * @reg: description of the sysreg
- */
-static int
-decode_idreg_writemap(Object *obj, ARM64SysReg *reg)
+static void
+add_idreg_field_properties(Object *obj, ARM64SysReg *reg)
{
- uint64_t map = reg->writable_mask;
- int i = ctz64(map);
int nb_sysreg_props = 0;
- while (map) {
- ARM64SysRegField *field = get_field(i, reg);
- int lower, upper;
- char *prop_name;
- uint64_t field_mask;
-
- if (!field) {
- warn_report("%s bit %d of %s is writable but no named field "
- "in target/arm/cpu-idregs.h.inc",
- __func__, i, reg->name);
- map = map & ~BIT_ULL(i);
- i = ctz64(map);
- continue;
- }
- lower = field->shift;
- upper = field->shift + field->length - 1;
-
- /* Sanity check the field is not a reserved field */
- if (strstr(field->name, "RES0") || strstr(field->name, "RES1") ||
- strstr(field->name, "RAZ")) {
- trace_unexpected_writable_reserved_field(reg->name, field->name,
- lower, upper);
+ for (int i = 0; i < reg->fields_count; i++) {
+ ARM64SysRegField *field = ®->fields[i];
+
+ /* skip reserved fields */
+ if (g_str_equal(field->name, "RES0") ||
+ g_str_equal(field->name, "RES1") ||
+ g_str_equal(field->name, "RAZ")) {
continue;
}
- prop_name = g_strdup_printf("SYSREG_%s_%s", reg->name, field->name);
- trace_decode_idreg_writemap(field->name, lower, upper, prop_name);
+
+ char *prop_name = g_strdup_printf("SYSREG_%s_%s", reg->name,
+ field->name);
object_property_add(obj, prop_name, "uint64",
get_sysreg_prop, set_sysreg_prop, NULL, field);
g_free(prop_name);
nb_sysreg_props++;
-
- field_mask = MAKE_64BIT_MASK(lower, field->length);
- map = map & ~field_mask;
- i = ctz64(map);
}
+
trace_nb_sysreg_props(reg->name, nb_sysreg_props);
- return 0;
}
-/* analyze the writable mask and generate properties for writable fields */
void kvm_arm_expose_idreg_properties(ARMCPU *cpu, ARM64SysReg *regs)
{
Object *obj = OBJECT(cpu);
for (int i = 0; i < NUM_ID_IDX; i++) {
ARM64SysReg *sysregdesc = ®s[i];
-
- if (sysregdesc->writable_mask) {
- decode_idreg_writemap(obj, sysregdesc);
- }
+ add_idreg_field_properties(obj, sysregdesc);
}
}
diff --git a/target/arm/trace-events b/target/arm/trace-events
index 71a2f5770c..7696a8ed40 100644
--- a/target/arm/trace-events
+++ b/target/arm/trace-events
@@ -15,11 +15,9 @@ arm_gt_update_irq(int timer, int irqstate) "gt_update_irq: timer %d irqstate %d"
kvm_arm_fixup_msi_route(uint64_t iova, uint64_t gpa) "MSI iova = 0x%"PRIx64" is translated into 0x%"PRIx64
get_host_cpu_idregs(const char *name, uint64_t value) "scratch vcpu host value for %s is 0x%"PRIx64
kvm_arm_writable_idregs_to_cpreg_list(const char *name, uint64_t previous, uint64_t new) "%s overwrite default 0x%"PRIx64" with 0x%"PRIx64
-decode_idreg_writemap(const char* name, int lower, int upper, char *prop_name) "%s [%d:%d] is writable (prop %s)"
get_sysreg_prop(const char *name, uint64_t value) "%s 0x%"PRIx64
set_sysreg_prop(const char *name, uint64_t old, uint64_t mask, uint64_t field_value, uint64_t new) "%s old reg value=0x%"PRIx64" mask=0x%"PRIx64" new field value=0x%"PRIx64" new reg value=0x%"PRIx64
nb_sysreg_props(const char *name, int count) "%s: %d SYSREG properties"
-unexpected_writable_reserved_field(const char *reg_name, const char *field_name, int lower, int upper) "Unexpected writable reserved field: %s.%s [%d,%d], skip it ..."
kvm_idreg_write_scratch_vcpu(const char *name, uint64_t oldfv, uint64_t newfv, uint64_t actualfv) "successful dry-run for %s old=0x%"PRIx64" new=0x%"PRIx64" actual=0x%"PRIx64
# cpu.c
--
2.52.0
^ permalink raw reply related [flat|nested] 66+ messages in thread
* [RFC PATCH v4 03/25] target/arm: move SYSREG_ prop infra to cpu64.c
2026-09-21 12:32 [RFC PATCH v4 00/25] named CPU models for Arm64 on KVM Khushit Shah
2026-09-21 12:32 ` [RFC PATCH v4 01/25] target/arm: expose SYSREG_ props for REVIDR_EL1 and AIDR_EL1 Khushit Shah
2026-09-21 12:32 ` [RFC PATCH v4 02/25] target/arm: expose all non-res ID reg fields as properties Khushit Shah
@ 2026-09-21 12:32 ` Khushit Shah
2026-09-24 6:54 ` Eric Auger
2026-09-21 12:32 ` [RFC PATCH v4 04/25] target/arm/kvm: enable writable implementation ID registers Khushit Shah
` (22 subsequent siblings)
25 siblings, 1 reply; 66+ messages in thread
From: Khushit Shah @ 2026-09-21 12:32 UTC (permalink / raw)
To: qemu-devel, qemu-arm, kvmarm, eric.auger
Cc: cohuck, peter.maydell, richard.henderson, maz, oliver.upton,
berrange, abologna, jdenemar, gshan, skolothumtho, sebott, armbru,
philmd, yangjinqian1, shaju.abraham, mark.caveayland,
khushit.shah, ping, sandesh.patel
kvm_arm_expose_idreg_properties() no longer depends on KVM-specific
logic. Move it to cpu64.c as aarch64_add_idregs_properties() along with
all SYSREG_ property infra, making it accelerator-agnostic.
Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
---
target/arm/cpu64.c | 101 +++++++++++++++++++++++++++++++++++++++-
target/arm/internals.h | 1 +
target/arm/kvm.c | 100 ---------------------------------------
target/arm/kvm_arm.h | 10 ----
target/arm/trace-events | 4 +-
5 files changed, 104 insertions(+), 112 deletions(-)
diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
index 3d522bf20d..7487b48cc9 100644
--- a/target/arm/cpu64.c
+++ b/target/arm/cpu64.c
@@ -38,6 +38,7 @@
#include "internals.h"
#include "cpu-features.h"
#include "cpu-idregs.h"
+#include "trace.h"
/* convert between <register>_IDX and SYS_<register> */
#define DEF(NAME, OP0, OP1, CRN, CRM, OP2) \
@@ -644,6 +645,104 @@ static const Property arm_cpu_pauth_qarma3_property =
static Property arm_cpu_pauth_qarma5_property =
DEFINE_PROP_BOOL("pauth-qarma5", ARMCPU, prop_pauth_qarma5, false);
+#ifndef CONFIG_USER_ONLY
+static void set_sysreg_prop(Object *obj, Visitor *v,
+ const char *name, void *opaque,
+ Error **errp)
+{
+ ARM64SysRegField *field = (ARM64SysRegField *)opaque;
+ ARMCPU *cpu = ARM_CPU(obj);
+ uint64_t *idregs = cpu->isar.idregs;
+ uint64_t old, value, mask;
+ int lower = field->shift;
+ int length = field->length;
+ int index = field->index;
+
+ if (!visit_type_uint64(v, name, &value, errp)) {
+ return;
+ }
+
+ if (length < 64 && value > ((1 << length) - 1)) {
+ error_setg(errp,
+ "idreg %s set value (0x%lx) exceeds length of field (%d)!",
+ name, value, length);
+ return;
+ }
+
+ if (field->arch_vals) {
+ /* this field has some enum values */
+ for (int i = 0; i < field->arch_vals_count; i++) {
+ if (value == field->arch_vals[i]) {
+ goto valid;
+ }
+ }
+ error_setg(errp,
+ "idreg %s set value (0x%lx) does not match any "
+ "arch valid enum value", name, value);
+ return;
+ }
+
+valid:
+
+ mask = MAKE_64BIT_MASK(lower, length);
+ value = value << lower;
+ old = idregs[index];
+ idregs[index] = old & ~mask;
+ idregs[index] |= value;
+ trace_set_sysreg_prop(name, old, mask, value, idregs[index]);
+}
+
+static void get_sysreg_prop(Object *obj, Visitor *v,
+ const char *name, void *opaque,
+ Error **errp)
+{
+ ARM64SysRegField *field = (ARM64SysRegField *)opaque;
+ ARMCPU *cpu = ARM_CPU(obj);
+ uint64_t *idregs = cpu->isar.idregs;
+ uint64_t value, mask;
+ int lower = field->shift;
+ int length = field->length;
+ int index = field->index;
+
+ mask = MAKE_64BIT_MASK(lower, length);
+ value = (idregs[index] & mask) >> lower;
+ visit_type_uint64(v, name, &value, errp);
+ trace_get_sysreg_prop(name, value);
+}
+
+static void add_idregs_properties(Object *obj, ARM64SysReg *reg)
+{
+ int nb_sysreg_props = 0;
+
+ for (int i = 0; i < reg->fields_count; i++) {
+ ARM64SysRegField *field = ®->fields[i];
+
+ /* skip reserved fields */
+ if (g_str_equal(field->name, "RES0") ||
+ g_str_equal(field->name, "RES1") ||
+ g_str_equal(field->name, "RAZ")) {
+ continue;
+ }
+
+ char *prop_name = g_strdup_printf("SYSREG_%s_%s", reg->name,
+ field->name);
+ object_property_add(obj, prop_name, "uint64",
+ get_sysreg_prop, set_sysreg_prop, NULL, field);
+ g_free(prop_name);
+ nb_sysreg_props++;
+ }
+
+ trace_nb_sysreg_props(reg->name, nb_sysreg_props);
+}
+
+void aarch64_add_idregs_properties(Object *obj)
+{
+ for (int i = 0; i < NUM_ID_IDX; i++) {
+ add_idregs_properties(obj, &arm64_id_regs[i]);
+ }
+}
+#endif
+
void aarch64_add_pauth_properties(Object *obj)
{
ARMCPU *cpu = ARM_CPU(obj);
@@ -810,7 +909,7 @@ void aarch64_host_initfn(Object *obj)
aarch64_add_sve_properties(obj);
/* generate SYSREG properties */
- kvm_arm_expose_idreg_properties(cpu, arm64_id_regs);
+ aarch64_add_idregs_properties(obj);
#elif defined(CONFIG_HVF)
hvf_arm_set_cpu_features_from_host(cpu);
diff --git a/target/arm/internals.h b/target/arm/internals.h
index f6b4e173a5..7c76ffea7d 100644
--- a/target/arm/internals.h
+++ b/target/arm/internals.h
@@ -1813,6 +1813,7 @@ void aarch64_max_tcg_initfn(Object *obj);
void aarch64_add_pauth_properties(Object *obj);
void aarch64_add_sve_properties(Object *obj);
void aarch64_add_sme_properties(Object *obj);
+void aarch64_add_idregs_properties(Object *obj);
void aarch64_aa32_a57_init(ARMCPU *cpu, bool aa64_enabled);
void aarch64_host_initfn(Object *obj);
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index 2f6c090e43..d5155a3706 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -416,106 +416,6 @@ bool kvm_idreg_write_scratch_vcpu(int cpufd, Visitor *v, const char *name,
return true;
}
-static void set_sysreg_prop(Object *obj, Visitor *v,
- const char *name, void *opaque,
- Error **errp)
-{
- ARM64SysRegField *field = (ARM64SysRegField *)opaque;
- ARMCPU *cpu = ARM_CPU(obj);
- uint64_t *idregs = cpu->isar.idregs;
- uint64_t old, value, mask;
- int lower = field->shift;
- int length = field->length;
- int index = field->index;
-
- if (!visit_type_uint64(v, name, &value, errp)) {
- return;
- }
-
- if (length < 64 && value > ((1 << length) - 1)) {
- error_setg(errp,
- "idreg %s set value (0x%lx) exceeds length of field (%d)!",
- name, value, length);
- return;
- }
-
- if (field->arch_vals) {
- /* this field has some enum values */
- for (int i = 0; i < field->arch_vals_count; i++) {
- if (value == field->arch_vals[i]) {
- goto valid;
- }
- }
- error_setg(errp,
- "idreg %s set value (0x%lx) does not match any "
- "arch valid enum value", name, value);
- return;
- }
-
-valid:
-
- mask = MAKE_64BIT_MASK(lower, length);
- value = value << lower;
- old = idregs[index];
- idregs[index] = old & ~mask;
- idregs[index] |= value;
- trace_set_sysreg_prop(name, old, mask, value, idregs[index]);
-}
-
-static void get_sysreg_prop(Object *obj, Visitor *v,
- const char *name, void *opaque,
- Error **errp)
-{
- ARM64SysRegField *field = (ARM64SysRegField *)opaque;
- ARMCPU *cpu = ARM_CPU(obj);
- uint64_t *idregs = cpu->isar.idregs;
- uint64_t value, mask;
- int lower = field->shift;
- int length = field->length;
- int index = field->index;
-
- mask = MAKE_64BIT_MASK(lower, length);
- value = (idregs[index] & mask) >> lower;
- visit_type_uint64(v, name, &value, errp);
- trace_get_sysreg_prop(name, value);
-}
-
-static void
-add_idreg_field_properties(Object *obj, ARM64SysReg *reg)
-{
- int nb_sysreg_props = 0;
-
- for (int i = 0; i < reg->fields_count; i++) {
- ARM64SysRegField *field = ®->fields[i];
-
- /* skip reserved fields */
- if (g_str_equal(field->name, "RES0") ||
- g_str_equal(field->name, "RES1") ||
- g_str_equal(field->name, "RAZ")) {
- continue;
- }
-
- char *prop_name = g_strdup_printf("SYSREG_%s_%s", reg->name,
- field->name);
- object_property_add(obj, prop_name, "uint64",
- get_sysreg_prop, set_sysreg_prop, NULL, field);
- g_free(prop_name);
- nb_sysreg_props++;
- }
-
- trace_nb_sysreg_props(reg->name, nb_sysreg_props);
-}
-
-void kvm_arm_expose_idreg_properties(ARMCPU *cpu, ARM64SysReg *regs)
-{
- Object *obj = OBJECT(cpu);
-
- for (int i = 0; i < NUM_ID_IDX; i++) {
- ARM64SysReg *sysregdesc = ®s[i];
- add_idreg_field_properties(obj, sysregdesc);
- }
-}
-
static void
kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
{
diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h
index aafb3cd232..997120966f 100644
--- a/target/arm/kvm_arm.h
+++ b/target/arm/kvm_arm.h
@@ -163,16 +163,6 @@ void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu);
*/
void kvm_arm_add_vcpu_properties(ARMCPU *cpu);
-typedef struct ARM64SysReg ARM64SysReg;
-/**
- * kvm_arm_expose_idreg_properties:
- * @cpu: The CPU object to generate the properties for
- * @reg: registers from the host
- *
- * analyze the writable mask and generate properties for writable fields
- */
-void kvm_arm_expose_idreg_properties(ARMCPU *cpu, ARM64SysReg *regs);
-
/**
* kvm_arm_steal_time_finalize:
* @cpu: ARMCPU for which to finalize kvm-steal-time
diff --git a/target/arm/trace-events b/target/arm/trace-events
index 7696a8ed40..bbf2e5dfa2 100644
--- a/target/arm/trace-events
+++ b/target/arm/trace-events
@@ -15,10 +15,12 @@ arm_gt_update_irq(int timer, int irqstate) "gt_update_irq: timer %d irqstate %d"
kvm_arm_fixup_msi_route(uint64_t iova, uint64_t gpa) "MSI iova = 0x%"PRIx64" is translated into 0x%"PRIx64
get_host_cpu_idregs(const char *name, uint64_t value) "scratch vcpu host value for %s is 0x%"PRIx64
kvm_arm_writable_idregs_to_cpreg_list(const char *name, uint64_t previous, uint64_t new) "%s overwrite default 0x%"PRIx64" with 0x%"PRIx64
+kvm_idreg_write_scratch_vcpu(const char *name, uint64_t oldfv, uint64_t newfv, uint64_t actualfv) "successful dry-run for %s old=0x%"PRIx64" new=0x%"PRIx64" actual=0x%"PRIx64
+
+# cpu64.c
get_sysreg_prop(const char *name, uint64_t value) "%s 0x%"PRIx64
set_sysreg_prop(const char *name, uint64_t old, uint64_t mask, uint64_t field_value, uint64_t new) "%s old reg value=0x%"PRIx64" mask=0x%"PRIx64" new field value=0x%"PRIx64" new reg value=0x%"PRIx64
nb_sysreg_props(const char *name, int count) "%s: %d SYSREG properties"
-kvm_idreg_write_scratch_vcpu(const char *name, uint64_t oldfv, uint64_t newfv, uint64_t actualfv) "successful dry-run for %s old=0x%"PRIx64" new=0x%"PRIx64" actual=0x%"PRIx64
# cpu.c
arm_cpu_reset(uint64_t mp_aff) "cpu %" PRIu64
--
2.52.0
^ permalink raw reply related [flat|nested] 66+ messages in thread
* [RFC PATCH v4 04/25] target/arm/kvm: enable writable implementation ID registers
2026-09-21 12:32 [RFC PATCH v4 00/25] named CPU models for Arm64 on KVM Khushit Shah
` (2 preceding siblings ...)
2026-09-21 12:32 ` [RFC PATCH v4 03/25] target/arm: move SYSREG_ prop infra to cpu64.c Khushit Shah
@ 2026-09-21 12:32 ` Khushit Shah
2026-09-21 12:32 ` [RFC PATCH v4 05/25] target/arm/kvm: read all ID registers from KVM Khushit Shah
` (21 subsequent siblings)
25 siblings, 0 replies; 66+ messages in thread
From: Khushit Shah @ 2026-09-21 12:32 UTC (permalink / raw)
To: qemu-devel, qemu-arm, kvmarm, eric.auger
Cc: cohuck, peter.maydell, richard.henderson, maz, oliver.upton,
berrange, abologna, jdenemar, gshan, skolothumtho, sebott, armbru,
philmd, yangjinqian1, shaju.abraham, mark.caveayland,
khushit.shah, ping, sandesh.patel
Enable KVM_CAP_ARM_WRITABLE_IMP_ID_REGS if the host kernel supports it.
This allows QEMU to write implementation-defined ID registers (MIDR,
REVIDR) so that named CPU models can present the intended values to the
guest instead of the host value.
Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
-------
Guest errata management will require Shameer's RFC as a prerequisite:
https://lore.kernel.org/qemu-devel/B789DAF5-F8F9-444C-B0FF-4CA0081AFDED@nutanix.com/
---
target/arm/kvm.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index d5155a3706..f8d349a461 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -808,6 +808,13 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
}
}
+ if (kvm_check_extension(s, KVM_CAP_ARM_WRITABLE_IMP_ID_REGS)) {
+ if (kvm_vm_enable_cap(s, KVM_CAP_ARM_WRITABLE_IMP_ID_REGS, 0)) {
+ error_report("Failed to enable "
+ "KVM_CAP_ARM_WRITABLE_IMP_ID_REGS cap");
+ }
+ }
+
if (s->kvm_eager_split_size) {
uint32_t sizes;
--
2.52.0
^ permalink raw reply related [flat|nested] 66+ messages in thread
* [RFC PATCH v4 05/25] target/arm/kvm: read all ID registers from KVM
2026-09-21 12:32 [RFC PATCH v4 00/25] named CPU models for Arm64 on KVM Khushit Shah
` (3 preceding siblings ...)
2026-09-21 12:32 ` [RFC PATCH v4 04/25] target/arm/kvm: enable writable implementation ID registers Khushit Shah
@ 2026-09-21 12:32 ` Khushit Shah
2026-09-24 7:52 ` Eric Auger
2026-09-21 12:32 ` [RFC PATCH v4 06/25] target/arm/kvm: handle special ID registers when reading " Khushit Shah
` (20 subsequent siblings)
25 siblings, 1 reply; 66+ messages in thread
From: Khushit Shah @ 2026-09-21 12:32 UTC (permalink / raw)
To: qemu-devel, qemu-arm, kvmarm, eric.auger
Cc: cohuck, peter.maydell, richard.henderson, maz, oliver.upton,
berrange, abologna, jdenemar, gshan, skolothumtho, sebott, armbru,
philmd, yangjinqian1, shaju.abraham, mark.caveayland,
khushit.shah, ping, sandesh.patel
Try to read all ID registers from KVM. KVM may return ENOENT for
registers that it does not support reading from userspace; ignore
those registers. Some registers may still require special handling.
This exposes a more complete host feature view to the management
stack. For migration, both writable and non-writable ID registers
must match.
Add a tracepoint for ID register reads that fail with ENOENT.
Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
---
target/arm/kvm.c | 29 ++++++++++++++---------------
target/arm/trace-events | 1 +
2 files changed, 15 insertions(+), 15 deletions(-)
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index f8d349a461..d9d0623a2a 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -330,12 +330,12 @@ static int kvm_feature_idx_to_idregs_idx(int kidx)
}
/*
- * get_host_cpu_idregs: Read all the writable ID reg host values
+ * get_host_cpu_idregs: Read all the ID reg host values
*
- * Need to be called once the writable mask has been populated
- * Note we may want to read all the known id regs but some of them are not
- * writable and return an error, hence the choice of reading only those which
- * are writable. Those are also readable!
+ * We currently try to read all the registers. If the read fails with
+ * ENOENT (KVM does not identify the ID register) ignore it.
+ * Some of the registers that errored with ENOENT will anyway need special
+ * handling.
*/
static int get_host_cpu_idregs(int fd, ARMHostCPUFeatures *ahcf)
{
@@ -348,19 +348,18 @@ static int get_host_cpu_idregs(int fd, ARMHostCPUFeatures *ahcf)
uint64_t *reg;
int ret;
- if (!sysregdesc->writable_mask) {
- continue;
- }
-
reg = &ahcf->isar.idregs[i];
ret = read_sys_reg64(fd, reg, idregs_sysreg_to_kvm_reg(sysreg));
- trace_get_host_cpu_idregs(sysregdesc->name, *reg);
if (ret) {
- error_report("%s error reading value of host %s register (%m)",
- __func__, sysregdesc->name);
-
- err = ret;
+ if (errno == ENOENT) {
+ trace_get_host_cpu_idreg_not_found(sysregdesc->name);
+ } else {
+ error_report("%s error reading value of host %s register"
+ " (%m)", __func__, sysregdesc->name);
+ err = ret;
+ }
}
+ trace_get_host_cpu_idregs(sysregdesc->name, *reg);
}
return err;
}
@@ -482,7 +481,7 @@ kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
SET_IDREG(&ahcf->isar, ID_AA64PFR0, 0x00000011); /* EL1&0, AArch64 only */
err = 0;
} else {
- /* Make sure all writable ID reg values are initialized */
+ /* Try to read all the ID registers */
err |= get_host_cpu_idregs(fd, ahcf);
/*
diff --git a/target/arm/trace-events b/target/arm/trace-events
index bbf2e5dfa2..2bb7766f7f 100644
--- a/target/arm/trace-events
+++ b/target/arm/trace-events
@@ -14,6 +14,7 @@ arm_gt_update_irq(int timer, int irqstate) "gt_update_irq: timer %d irqstate %d"
# kvm.c
kvm_arm_fixup_msi_route(uint64_t iova, uint64_t gpa) "MSI iova = 0x%"PRIx64" is translated into 0x%"PRIx64
get_host_cpu_idregs(const char *name, uint64_t value) "scratch vcpu host value for %s is 0x%"PRIx64
+get_host_cpu_idreg_not_found(const char *name) "host %s register not readable from KVM"
kvm_arm_writable_idregs_to_cpreg_list(const char *name, uint64_t previous, uint64_t new) "%s overwrite default 0x%"PRIx64" with 0x%"PRIx64
kvm_idreg_write_scratch_vcpu(const char *name, uint64_t oldfv, uint64_t newfv, uint64_t actualfv) "successful dry-run for %s old=0x%"PRIx64" new=0x%"PRIx64" actual=0x%"PRIx64
--
2.52.0
^ permalink raw reply related [flat|nested] 66+ messages in thread
* [RFC PATCH v4 06/25] target/arm/kvm: handle special ID registers when reading from KVM
2026-09-21 12:32 [RFC PATCH v4 00/25] named CPU models for Arm64 on KVM Khushit Shah
` (4 preceding siblings ...)
2026-09-21 12:32 ` [RFC PATCH v4 05/25] target/arm/kvm: read all ID registers from KVM Khushit Shah
@ 2026-09-21 12:32 ` Khushit Shah
2026-09-21 12:32 ` [RFC PATCH v4 07/25] target/arm/kvm: process ID register writeback per field Khushit Shah
` (19 subsequent siblings)
25 siblings, 0 replies; 66+ messages in thread
From: Khushit Shah @ 2026-09-21 12:32 UTC (permalink / raw)
To: qemu-devel, qemu-arm, kvmarm, eric.auger
Cc: cohuck, peter.maydell, richard.henderson, maz, oliver.upton,
berrange, abologna, jdenemar, gshan, skolothumtho, sebott, armbru,
philmd, yangjinqian1, shaju.abraham, mark.caveayland,
khushit.shah, ping, sandesh.patel
The generic KVM_GET_ONE_REG loop cannot read a handful of ID registers,
so handle them specially:
- DCZID_EL0: No fine-grained trap exists, hence not tracked by KVM.
It is EL0-readable, so read it directly with MRS.
- SMIDR_EL1: KVM does not currently support SME, so skip it.
- GMID_EL1: not in KVM's sys_reg_descs[] and, being an EL1 register,
cannot be read from userspace either. The guest reads the raw host
value; this is a genuine miss when MTE is enabled.
Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
---
target/arm/kvm.c | 40 ++++++++++++++++++++++++++++++++--------
1 file changed, 32 insertions(+), 8 deletions(-)
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index d9d0623a2a..07df6626d4 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -349,14 +349,38 @@ static int get_host_cpu_idregs(int fd, ARMHostCPUFeatures *ahcf)
int ret;
reg = &ahcf->isar.idregs[i];
- ret = read_sys_reg64(fd, reg, idregs_sysreg_to_kvm_reg(sysreg));
- if (ret) {
- if (errno == ENOENT) {
- trace_get_host_cpu_idreg_not_found(sysregdesc->name);
- } else {
- error_report("%s error reading value of host %s register"
- " (%m)", __func__, sysregdesc->name);
- err = ret;
+ switch (i) {
+ case DCZID_EL0_IDX:
+ /*
+ * DCZID_EL0 is not in KVM's sys_reg_descs[], so
+ * KVM_GET_ONE_REG will fail. Read it directly from
+ * hardware since KVM can't trap guest reads of it.
+ */
+ asm volatile("mrs %0, DCZID_EL0" : "=r" (*reg));
+ break;
+ case SMIDR_EL1_IDX:
+ /*
+ * As SME is not yet supported by KVM, ignore reading SMIDR_EL1
+ */
+ break;
+ case GMID_EL1_IDX:
+ /*
+ * GMID_EL1 is not in KVM's sys_reg_descs[] and guest reads
+ * the raw host value. But as it is an EL1 register, we cannot
+ * read it directly. This is a genuine miss when MTE is
+ * enabled for the guest.
+ */
+ break;
+ default:
+ ret = read_sys_reg64(fd, reg, idregs_sysreg_to_kvm_reg(sysreg));
+ if (ret) {
+ if (errno == ENOENT) {
+ trace_get_host_cpu_idreg_not_found(sysregdesc->name);
+ } else {
+ error_report("%s error reading value of host %s register"
+ " (%m)", __func__, sysregdesc->name);
+ err = ret;
+ }
}
}
trace_get_host_cpu_idregs(sysregdesc->name, *reg);
--
2.52.0
^ permalink raw reply related [flat|nested] 66+ messages in thread
* [RFC PATCH v4 07/25] target/arm/kvm: process ID register writeback per field
2026-09-21 12:32 [RFC PATCH v4 00/25] named CPU models for Arm64 on KVM Khushit Shah
` (5 preceding siblings ...)
2026-09-21 12:32 ` [RFC PATCH v4 06/25] target/arm/kvm: handle special ID registers when reading " Khushit Shah
@ 2026-09-21 12:32 ` Khushit Shah
2026-09-24 9:41 ` Eric Auger
2026-09-21 12:32 ` [RFC PATCH v4 08/25] target/arm/kvm: handle writeback for special ID register fields Khushit Shah
` (18 subsequent siblings)
25 siblings, 1 reply; 66+ messages in thread
From: Khushit Shah @ 2026-09-21 12:32 UTC (permalink / raw)
To: qemu-devel, qemu-arm, kvmarm, eric.auger
Cc: cohuck, peter.maydell, richard.henderson, maz, oliver.upton,
berrange, abologna, jdenemar, gshan, skolothumtho, sebott, armbru,
philmd, yangjinqian1, shaju.abraham, mark.caveayland,
khushit.shah, ping, sandesh.patel
Now that all ID register fields are exposed as properties, refactor
kvm_arm_writable_idregs_to_cpreg_list() as
kvm_arm_write_idregs_to_cpreg_list() and process each field
individually. kvm_arm_writable_idregs_to_cpreg_list() assumed that
only writable fields were exposed as SYSREG_ properties.
Copy only fields advertised as writable by KVM instead of replacing the
whole register. For registers absent from the KVM cpreg list, compare
the requested value against the host value captured during probing.
Return an error when a non-writable field differs from the host value,
failing vCPU init.
Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
---
target/arm/cpu-idregs.c | 13 +++++++
target/arm/cpu-idregs.h | 2 ++
target/arm/kvm.c | 79 +++++++++++++++++++++++++++++++++--------
target/arm/trace-events | 2 +-
4 files changed, 80 insertions(+), 16 deletions(-)
diff --git a/target/arm/cpu-idregs.c b/target/arm/cpu-idregs.c
index 199d593153..d58b8ed063 100644
--- a/target/arm/cpu-idregs.c
+++ b/target/arm/cpu-idregs.c
@@ -7,6 +7,7 @@
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "qemu/osdep.h"
+#include "qemu/bitops.h"
#include "qemu/error-report.h"
#include "qapi/error.h"
#include "cpu.h"
@@ -94,3 +95,15 @@ ARM64SysReg arm64_id_regs[NUM_ID_IDX] = {
#include "cpu-idregs.h.inc"
};
+uint64_t arm_get_field_mask(const ARM64SysRegField *field)
+{
+ return MAKE_64BIT_MASK(field->shift, field->length);
+}
+
+bool arm_field_is_writable(const ARM64SysRegField *field)
+{
+ uint64_t field_mask = arm_get_field_mask(field);
+
+ return (arm64_id_regs[field->index].writable_mask & field_mask)
+ == field_mask;
+}
diff --git a/target/arm/cpu-idregs.h b/target/arm/cpu-idregs.h
index 98c7a7518f..aab1a79db1 100644
--- a/target/arm/cpu-idregs.h
+++ b/target/arm/cpu-idregs.h
@@ -33,4 +33,6 @@ typedef struct ARM64SysReg {
*/
extern ARM64SysReg arm64_id_regs[NUM_ID_IDX];
+uint64_t arm_get_field_mask(const ARM64SysRegField *field);
+bool arm_field_is_writable(const ARM64SysRegField *field);
#endif
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index 07df6626d4..2d94b3a884 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -1006,6 +1006,16 @@ static uint64_t *kvm_arm_get_cpreg_ptr(ARMCPU *cpu, uint64_t regidx)
return &cpu->cpreg_values[res - cpu->cpreg_indexes];
}
+/* Like kvm_arm_get_cpreg_ptr, but returns NULL if the register is not found. */
+static uint64_t *kvm_arm_find_cpreg_ptr(ARMCPU *cpu, uint64_t regidx)
+{
+ uint64_t *res;
+ res = bsearch(®idx, cpu->cpreg_indexes, cpu->cpreg_array_len,
+ sizeof(uint64_t), compare_u64);
+
+ return res ? &cpu->cpreg_values[res - cpu->cpreg_indexes] : NULL;
+}
+
/**
* kvm_arm_reg_syncs_via_cpreg_list:
* @regidx: KVM register index
@@ -1308,31 +1318,67 @@ bool kvm_arm_cpu_post_load(ARMCPU *cpu)
}
/*
- * Copy writable ID regs from isar.idregs[] to cpreg_list
- * in case their value differs from the original init cpreg value
+ * Copy writable ID reg fields from isar.idregs[] into the KVM cpreg list,
+ * so the subsequent write_list_to_kvmstate() pushes them to KVM.
+ * Only writable fields are copied.
+ * Returns -1 if any vCPU's ID reg value differs from the host value and the
+ * field is not writable.
*/
-static void kvm_arm_writable_idregs_to_cpreg_list(ARMCPU *cpu)
+static int kvm_arm_write_idregs_to_cpreg_list(ARMCPU *cpu)
{
for (int i = 0; i < NUM_ID_IDX; i++) {
ARM64SysReg *sysregdesc = &arm64_id_regs[i];
ARMSysRegs sysreg = id_register_sysreg[i];
- uint64_t previous, new;
+ uint64_t writable_mask = sysregdesc->writable_mask;
+ uint64_t desired = cpu->isar.idregs[i];
+ uint64_t previous, updated;
uint64_t *cpreg;
- if (!sysregdesc->writable_mask) {
+ cpreg = kvm_arm_find_cpreg_ptr(cpu, idregs_sysreg_to_kvm_reg(sysreg));
+ /*
+ * Registers such as DCZID_EL0 are not exposed through the cpreg
+ * list and are therefore not writable. Use the host value
+ * snapshotted at probe time as the reference to check the vCPU ID
+ * regs have the same value.
+ */
+ previous = cpreg ? *cpreg : arm_host_cpu_features.isar.idregs[i];
+
+ if (previous == desired) {
continue;
}
- cpreg = kvm_arm_get_cpreg_ptr(cpu, idregs_sysreg_to_kvm_reg(sysreg));
- previous = *cpreg;
- new = cpu->isar.idregs[i];
+ for (int j = 0; j < sysregdesc->fields_count; j++) {
+ const ARM64SysRegField *field = &sysregdesc->fields[j];
+ uint64_t field_mask = arm_get_field_mask(field);
+ uint64_t prev_val = previous & field_mask;
+ uint64_t new_val = desired & field_mask;
+
+ if (prev_val == new_val) {
+ continue;
+ }
+
+ if (!arm_field_is_writable(field)) {
+ error_report("%s.%s is not writable: host=0x%" PRIx64
+ ", requested=0x%" PRIx64,
+ sysregdesc->name, field->name,
+ prev_val >> field->shift, new_val >> field->shift);
+ return -1;
+ }
+ }
+
+ if (!cpreg || !writable_mask) {
+ continue;
+ }
- if (previous != new) {
- *cpreg = new;
- trace_kvm_arm_writable_idregs_to_cpreg_list(sysregdesc->name,
- previous, new);
- }
+ updated = (previous & ~writable_mask) | (desired & writable_mask);
+ if (updated != previous) {
+ *cpreg = updated;
+ trace_kvm_arm_write_idregs_to_cpreg_list(sysregdesc->name,
+ previous, updated);
+ }
}
+
+ return 0;
}
void kvm_arm_reset_vcpu(ARMCPU *cpu)
@@ -2293,8 +2339,11 @@ int kvm_arch_init_vcpu(CPUState *cs)
if (ret) {
return ret;
}
- /* overwrite writable ID regs with their updated property values */
- kvm_arm_writable_idregs_to_cpreg_list(cpu);
+ /* overwrite ID reg fields with their updated property values */
+ ret = kvm_arm_write_idregs_to_cpreg_list(cpu);
+ if (ret) {
+ return ret;
+ }
ret = write_list_to_kvmstate(cpu, KVM_PUT_FULL_STATE);
if (!ret) {
return -1;
diff --git a/target/arm/trace-events b/target/arm/trace-events
index 2bb7766f7f..7b54e34ad9 100644
--- a/target/arm/trace-events
+++ b/target/arm/trace-events
@@ -15,7 +15,7 @@ arm_gt_update_irq(int timer, int irqstate) "gt_update_irq: timer %d irqstate %d"
kvm_arm_fixup_msi_route(uint64_t iova, uint64_t gpa) "MSI iova = 0x%"PRIx64" is translated into 0x%"PRIx64
get_host_cpu_idregs(const char *name, uint64_t value) "scratch vcpu host value for %s is 0x%"PRIx64
get_host_cpu_idreg_not_found(const char *name) "host %s register not readable from KVM"
-kvm_arm_writable_idregs_to_cpreg_list(const char *name, uint64_t previous, uint64_t new) "%s overwrite default 0x%"PRIx64" with 0x%"PRIx64
+kvm_arm_write_idregs_to_cpreg_list(const char *name, uint64_t previous, uint64_t new) "%s overwrite default 0x%"PRIx64" with 0x%"PRIx64
kvm_idreg_write_scratch_vcpu(const char *name, uint64_t oldfv, uint64_t newfv, uint64_t actualfv) "successful dry-run for %s old=0x%"PRIx64" new=0x%"PRIx64" actual=0x%"PRIx64
# cpu64.c
--
2.52.0
^ permalink raw reply related [flat|nested] 66+ messages in thread
* [RFC PATCH v4 08/25] target/arm/kvm: handle writeback for special ID register fields
2026-09-21 12:32 [RFC PATCH v4 00/25] named CPU models for Arm64 on KVM Khushit Shah
` (6 preceding siblings ...)
2026-09-21 12:32 ` [RFC PATCH v4 07/25] target/arm/kvm: process ID register writeback per field Khushit Shah
@ 2026-09-21 12:32 ` Khushit Shah
2026-09-24 9:57 ` Eric Auger
2026-09-21 12:32 ` [RFC PATCH v4 09/25] target/arm: introduce named CPU model infrastructure Khushit Shah
` (17 subsequent siblings)
25 siblings, 1 reply; 66+ messages in thread
From: Khushit Shah @ 2026-09-21 12:32 UTC (permalink / raw)
To: qemu-devel, qemu-arm, kvmarm, eric.auger
Cc: cohuck, peter.maydell, richard.henderson, maz, oliver.upton,
berrange, abologna, jdenemar, gshan, skolothumtho, sebott, armbru,
philmd, yangjinqian1, shaju.abraham, mark.caveayland,
khushit.shah, ping, sandesh.patel
Some fields should not be written back to KVM for various reasons:
- ID_AA64PFR0_EL1.GIC / ID_PFR1_EL1.GIC are fabricated by KVM based on
the gic-version property.
- KVM does not allow writing 0 to ID_DFR0_EL1.CopDbg, which breaks
booting an AArch64-only guest on a host that also supports AArch32.
- ID_DFR0_EL1.PerfMon is populated by KVM even for AArch64-only guests
but is not writable there.
- MPIDR_EL1 is managed by KVM based on vCPU index.
- Hold off writing back CLIDR_EL1 until we properly support exposing
cache topology to a KVM guest.
Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
---
target/arm/cpu-idregs.c | 6 ++++++
target/arm/cpu-idregs.h | 2 ++
target/arm/kvm.c | 40 +++++++++++++++++++++++++++++++++++++++-
3 files changed, 47 insertions(+), 1 deletion(-)
diff --git a/target/arm/cpu-idregs.c b/target/arm/cpu-idregs.c
index d58b8ed063..1f7ebfe9bb 100644
--- a/target/arm/cpu-idregs.c
+++ b/target/arm/cpu-idregs.c
@@ -107,3 +107,9 @@ bool arm_field_is_writable(const ARM64SysRegField *field)
return (arm64_id_regs[field->index].writable_mask & field_mask)
== field_mask;
}
+
+bool field_matches(const ARM64SysRegField *field, ARMIDRegisterIdx index,
+ const char *name)
+{
+ return field->index == index && !strcmp(field->name, name);
+}
diff --git a/target/arm/cpu-idregs.h b/target/arm/cpu-idregs.h
index aab1a79db1..8ef3f9350e 100644
--- a/target/arm/cpu-idregs.h
+++ b/target/arm/cpu-idregs.h
@@ -35,4 +35,6 @@ extern ARM64SysReg arm64_id_regs[NUM_ID_IDX];
uint64_t arm_get_field_mask(const ARM64SysRegField *field);
bool arm_field_is_writable(const ARM64SysRegField *field);
+bool field_matches(const ARM64SysRegField *field, ARMIDRegisterIdx index,
+ const char *name);
#endif
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index 2d94b3a884..70d9a07580 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -1317,10 +1317,40 @@ bool kvm_arm_cpu_post_load(ARMCPU *cpu)
return true;
}
+static bool arm_field_skip_writeback_always(const ARM64SysRegField *field)
+{
+ /*
+ * GIC is controlled by the gic-version property and fabricated by KVM
+ * when the vGIC device is created, so a named CPU model must not touch
+ * it. KVM also rejects writing 0 to ID_DFR0_EL1.CopDbg, which breaks
+ * booting a model that lacks AArch32 support on a host that supports
+ * it. MPIDR_EL1 is managed by KVM based on vCPU index, skip writing it
+ * back. Similarly, skip writing back CLIDR_EL1 till we properly
+ * support exposing cache for KVM guest.
+ */
+ return field_matches(field, ID_AA64PFR0_EL1_IDX, "GIC")
+ || field_matches(field, ID_PFR1_EL1_IDX, "GIC")
+ || field_matches(field, ID_DFR0_EL1_IDX, "CopDbg")
+ || field->index == MPIDR_EL1_IDX
+ || field->index == CLIDR_EL1_IDX;
+}
+
+static bool
+arm_field_skip_writeback_if_not_writable(const ARM64SysRegField *field)
+{
+ /*
+ * KVM populates ID_DFR0_EL1.PerfMon even for AArch64-only guests but
+ * does not expose it as writable there, so skip it when it is not
+ * writable.
+ */
+ return field_matches(field, ID_DFR0_EL1_IDX, "PerfMon");
+}
+
/*
* Copy writable ID reg fields from isar.idregs[] into the KVM cpreg list,
* so the subsequent write_list_to_kvmstate() pushes them to KVM.
- * Only writable fields are copied.
+ * Only writable fields are copied; fields that must not be written back
+ * (see arm_field_skip_writeback_*) are skipped.
* Returns -1 if any vCPU's ID reg value differs from the host value and the
* field is not writable.
*/
@@ -1357,6 +1387,14 @@ static int kvm_arm_write_idregs_to_cpreg_list(ARMCPU *cpu)
continue;
}
+ if (arm_field_skip_writeback_always(field) ||
+ (!arm_field_is_writable(field) &&
+ arm_field_skip_writeback_if_not_writable(field))) {
+ /* Never write this field back; keep KVM's value. */
+ writable_mask &= ~field_mask;
+ continue;
+ }
+
if (!arm_field_is_writable(field)) {
error_report("%s.%s is not writable: host=0x%" PRIx64
", requested=0x%" PRIx64,
--
2.52.0
^ permalink raw reply related [flat|nested] 66+ messages in thread
* [RFC PATCH v4 09/25] target/arm: introduce named CPU model infrastructure
2026-09-21 12:32 [RFC PATCH v4 00/25] named CPU models for Arm64 on KVM Khushit Shah
` (7 preceding siblings ...)
2026-09-21 12:32 ` [RFC PATCH v4 08/25] target/arm/kvm: handle writeback for special ID register fields Khushit Shah
@ 2026-09-21 12:32 ` Khushit Shah
2026-09-24 13:35 ` Eric Auger
2026-09-21 12:32 ` [RFC PATCH v4 10/25] target/arm: fix SVE and PAuth finalize for named CPU models Khushit Shah
` (16 subsequent siblings)
25 siblings, 1 reply; 66+ messages in thread
From: Khushit Shah @ 2026-09-21 12:32 UTC (permalink / raw)
To: qemu-devel, qemu-arm, kvmarm, eric.auger
Cc: cohuck, peter.maydell, richard.henderson, maz, oliver.upton,
berrange, abologna, jdenemar, gshan, skolothumtho, sebott, armbru,
philmd, yangjinqian1, shaju.abraham, mark.caveayland,
khushit.shah, ping, sandesh.patel
Add scaffolding for named CPU models on Arm on top of the property
layer. A model is a list of (property, value) overrides plus an
optional parent; a child inherits its parent's property values and may
override them.
Instance init steps:
- host feature discovery.
- zero out isar.idregs[] and restore RES1 fields.
- install SYSREG_ and sve* properties.
- walk the parent chain root-first and apply each level's
properties.
This assumes that each property is idempotent. `pauth` is intentionally
not installed because the model's ID register view is authoritative
and can be configured through SYSREG_ properties.
No models are defined yet.
Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
---
target/arm/cpu-models.c | 191 ++++++++++++++++++++++++++++++++++++++++
target/arm/cpu-models.h | 36 ++++++++
target/arm/meson.build | 1 +
3 files changed, 228 insertions(+)
create mode 100644 target/arm/cpu-models.c
create mode 100644 target/arm/cpu-models.h
diff --git a/target/arm/cpu-models.c b/target/arm/cpu-models.c
new file mode 100644
index 0000000000..fed3197186
--- /dev/null
+++ b/target/arm/cpu-models.c
@@ -0,0 +1,191 @@
+/*
+ * ARM named CPU models.
+ *
+ * Each model is defined as an array of MODEL_PROP macros, listing only
+ * the properties that DIFFER from the parent model.
+ *
+ * Initialization starts with a zeroed idregs[] array.
+ *
+ * During initialization, the parent chain is walked root-first and every
+ * level's properties are applied via QOM, so the leaf's values naturally
+ * override its ancestors.
+ *
+ * Assumptions:
+ * - All named CPU model properties are idempotent.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "qemu/error-report.h"
+#include "system/kvm.h"
+#include "cpu.h"
+#include "internals.h"
+#include "kvm_arm.h"
+#include "cpu-idregs.h"
+#include "cpu-models.h"
+
+#define MODEL_PROP_FIELD_STR str
+#define MODEL_PROP_FIELD_BOOL b
+#define MODEL_PROP_FIELD_NUM num
+
+#define MODEL_PROP(_name, _type, _value) \
+ { .name = (_name), .type = ARM_MODEL_PROP_##_type, \
+ .u.MODEL_PROP_FIELD_##_type = (_value) }
+
+#define MODEL_PROP_END { .name = NULL }
+
+/* Maximum parent-chain depth for named CPU models. */
+#define ARM_NAMED_CPU_MODEL_MAX_DEPTH 16
+
+static const ArmNamedCpuModel arm_cpu_models[] = {
+ {NULL, NULL, NULL}
+};
+
+const ArmNamedCpuModel *arm_find_model(const char *name)
+{
+ for (size_t i = 0; i < ARRAY_SIZE(arm_cpu_models); i++) {
+ if (!arm_cpu_models[i].name) {
+ break;
+ }
+
+ if (g_str_equal(arm_cpu_models[i].name, name)) {
+ return &arm_cpu_models[i];
+ }
+ }
+ return NULL;
+}
+
+void arm_apply_model_props(Object *obj, const ArmModelPropValue *props,
+ Error **errp)
+{
+ const ArmModelPropValue *pv;
+ ERRP_GUARD();
+
+ for (pv = props; pv->name; pv++) {
+ switch (pv->type) {
+ case ARM_MODEL_PROP_BOOL:
+ object_property_set_bool(obj, pv->name, pv->u.b, errp);
+ break;
+ case ARM_MODEL_PROP_NUM:
+ object_property_set_uint(obj, pv->name, pv->u.num, errp);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ if (*errp) {
+ error_prepend(errp, "property '%s': ", pv->name);
+ return;
+ }
+ }
+}
+
+void arm_realize_model_chain(Object *obj, const ArmNamedCpuModel *model,
+ Error **errp)
+{
+ const ArmNamedCpuModel *cur, *parent;
+ const ArmNamedCpuModel *chain[ARM_NAMED_CPU_MODEL_MAX_DEPTH];
+ size_t depth = 0;
+
+ for (cur = model; cur; ) {
+ if (depth >= ARRAY_SIZE(chain)) {
+ error_setg(errp, "model '%s': parent chain too deep", model->name);
+ return;
+ }
+ chain[depth++] = cur;
+
+ if (!cur->parent) {
+ break;
+ }
+ parent = arm_find_model(cur->parent);
+ if (!parent) {
+ error_setg(errp, "model '%s': unknown parent '%s'", cur->name,
+ cur->parent);
+ return;
+ }
+ cur = parent;
+ }
+
+ while (depth--) {
+ arm_apply_model_props(obj, chain[depth]->props, errp);
+ if (*errp) {
+ return;
+ }
+ }
+}
+
+static void reset_res1_fields(ARMCPU *cpu)
+{
+ for (size_t i = 0; i < NUM_ID_IDX; i++) {
+ for (size_t j = 0; j < arm64_id_regs[i].fields_count; j++) {
+ if (strcmp(arm64_id_regs[i].fields[j].name, "RES1") == 0) {
+ cpu->isar.idregs[i] = deposit64(cpu->isar.idregs[i],
+ arm64_id_regs[i].fields[j].shift,
+ arm64_id_regs[i].fields[j].length,
+ MAKE_64BIT_MASK(0, arm64_id_regs[i].fields[j].length));
+ }
+ }
+ }
+}
+
+static void arm_named_cpu_initfn(Object *obj)
+{
+ ARMCPU *cpu = ARM_CPU(obj);
+ ARMCPUClass *acc = ARM_CPU_GET_CLASS(obj);
+ const ArmNamedCpuModel *model = arm_find_model(acc->info->name);
+
+ if (!model) {
+ error_report("'%s' CPU model entry not found",
+ acc->info->name);
+ return;
+ }
+
+ if (!kvm_enabled()) {
+ error_report("'%s' CPU model requires KVM (-accel kvm)",
+ acc->info->name);
+ return;
+ }
+
+ kvm_arm_set_cpu_features_from_host(cpu);
+ if (!arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) {
+ return;
+ }
+
+ /* 1.a Reset ID regs to 0 */
+ memset(cpu->isar.idregs, 0, sizeof(cpu->isar.idregs));
+
+ /* 1.b Properly set RES1 fields. */
+ reset_res1_fields(cpu);
+
+ /* 2. Add sveNNNN and SYSREG_ properties */
+ aarch64_add_sve_properties(obj);
+ aarch64_add_idregs_properties(obj);
+
+ /* 3. Realize the model chain. */
+ arm_realize_model_chain(obj, model, &error_abort);
+}
+
+void arm_register_named_cpu_models(void)
+{
+ static ARMCPUInfo *arm_named_cpu_infos;
+ size_t i, n = ARRAY_SIZE(arm_cpu_models);
+
+ if (!n) {
+ return;
+ }
+
+ arm_named_cpu_infos = g_new0(ARMCPUInfo, n);
+ for (i = 0; i < n; i++) {
+ if (!arm_cpu_models[i].name) {
+ break;
+ }
+
+ arm_named_cpu_infos[i].name = arm_cpu_models[i].name;
+ arm_named_cpu_infos[i].initfn = arm_named_cpu_initfn;
+ arm_cpu_register(&arm_named_cpu_infos[i]);
+ }
+}
+
+type_init(arm_register_named_cpu_models)
diff --git a/target/arm/cpu-models.h b/target/arm/cpu-models.h
new file mode 100644
index 0000000000..144778744e
--- /dev/null
+++ b/target/arm/cpu-models.h
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#ifndef ARM_CPU_MODELS_H
+#define ARM_CPU_MODELS_H
+
+#include "qapi/error.h"
+#include "qom/object.h"
+
+typedef enum ArmModelPropType {
+ ARM_MODEL_PROP_BOOL,
+ ARM_MODEL_PROP_NUM,
+} ArmModelPropType;
+
+typedef struct ArmModelPropValue {
+ const char *name;
+ ArmModelPropType type;
+ union {
+ bool b;
+ uint64_t num;
+ } u;
+} ArmModelPropValue;
+
+typedef struct ArmNamedCpuModel {
+ const char *name;
+ const char *parent;
+ const ArmModelPropValue *props;
+} ArmNamedCpuModel;
+
+void arm_register_named_cpu_models(void);
+
+const ArmNamedCpuModel *arm_find_model(const char *name);
+void arm_apply_model_props(Object *obj, const ArmModelPropValue *props,
+ Error **errp);
+void arm_realize_model_chain(Object *obj, const ArmNamedCpuModel *model,
+ Error **errp);
+
+#endif /* ARM_CPU_MODELS_H */
diff --git a/target/arm/meson.build b/target/arm/meson.build
index 384d90c530..dd28146c52 100644
--- a/target/arm/meson.build
+++ b/target/arm/meson.build
@@ -32,6 +32,7 @@ arm_common_system_ss.add(files(
'arm-qmp-cmds.c',
'cpu-idregs.c',
))
+arm_system_ss.add(when: 'TARGET_AARCH64', if_true: files('cpu-models.c'))
arm_system_ss.add(when: 'CONFIG_KVM', if_true: files('hyp_gdbstub.c', 'kvm.c'))
arm_system_ss.add(when: 'CONFIG_HVF', if_true: files('hyp_gdbstub.c'))
--
2.52.0
^ permalink raw reply related [flat|nested] 66+ messages in thread
* [RFC PATCH v4 10/25] target/arm: fix SVE and PAuth finalize for named CPU models
2026-09-21 12:32 [RFC PATCH v4 00/25] named CPU models for Arm64 on KVM Khushit Shah
` (8 preceding siblings ...)
2026-09-21 12:32 ` [RFC PATCH v4 09/25] target/arm: introduce named CPU model infrastructure Khushit Shah
@ 2026-09-21 12:32 ` Khushit Shah
2026-10-15 13:01 ` Eric Auger
2026-09-21 12:32 ` [RFC PATCH v4 11/25] target/arm: disable PMU support " Khushit Shah
` (15 subsequent siblings)
25 siblings, 1 reply; 66+ messages in thread
From: Khushit Shah @ 2026-09-21 12:32 UTC (permalink / raw)
To: qemu-devel, qemu-arm, kvmarm, eric.auger
Cc: cohuck, peter.maydell, richard.henderson, maz, oliver.upton,
berrange, abologna, jdenemar, gshan, skolothumtho, sebott, armbru,
philmd, yangjinqian1, shaju.abraham, mark.caveayland,
khushit.shah, ping, sandesh.patel
As named CPU models define their feature set explicitly, their SVE
vector lengths and PAuth fields must not be derived from the host.
When SVE is enabled without an sve<N> setting, require the named model
to specify its supported vector lengths rather than inheriting them from
the host.
Named models set PAuth ID register fields directly through SYSREG_
properties. Preserve these values in PAuth finalization.
Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
---
target/arm/cpu64.c | 33 +++++++++++++++++++++++++++++++++
1 file changed, 33 insertions(+)
diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
index 7487b48cc9..a0114b0fa2 100644
--- a/target/arm/cpu64.c
+++ b/target/arm/cpu64.c
@@ -38,6 +38,7 @@
#include "internals.h"
#include "cpu-features.h"
#include "cpu-idregs.h"
+#include "cpu-models.h"
#include "trace.h"
/* convert between <register>_IDX and SYS_<register> */
@@ -134,6 +135,21 @@ void aarch64_cpu_sve_finalize(ARMCPU *cpu, Error **errp)
return;
}
+#ifndef CONFIG_USER_ONLY
+ /*
+ * If SVE is enabled but no vector lengths are specified, we must not
+ * default to the host's supported lengths for named CPU models.
+ */
+ {
+ ARMCPUClass *acc = ARM_CPU_GET_CLASS(cpu);
+ if (acc->info && arm_find_model(acc->info->name)) {
+ error_setg(errp,
+ "Named CPU models with SVE must set vector lengths");
+ return;
+ }
+ }
+#endif
+
if (kvm_enabled()) {
/* Disabling a supported length disables all larger lengths. */
tmp = vq_init & vq_supported;
@@ -556,6 +572,23 @@ void aarch64_cpu_pauth_finalize(ARMCPU *cpu, Error **errp)
ARMISARegisters *isar = &cpu->isar;
uint64_t isar1, isar2;
+#ifndef CONFIG_USER_ONLY
+ /*
+ * For named CPU models the model props write the authoritative
+ * APA/API/APA3/GPA/GPI/GPA3 values directly into cpu->isar through
+ * SYSREG_ properties, so do not override them here. Since other code
+ * relies on cpu->prop_pauth, mirror the resulting pauth state into
+ * cpu->prop_pauth.
+ */
+ {
+ ARMCPUClass *acc = ARM_CPU_GET_CLASS(cpu);
+ if (acc->info && arm_find_model(acc->info->name)) {
+ cpu->prop_pauth = cpu_isar_feature(aa64_pauth, cpu);
+ return;
+ }
+ }
+#endif
+
/*
* These properties enable or disable Pauth as a whole, or change
* the pauth algorithm, but do not change the set of features that
--
2.52.0
^ permalink raw reply related [flat|nested] 66+ messages in thread
* [RFC PATCH v4 11/25] target/arm: disable PMU support for named CPU models
2026-09-21 12:32 [RFC PATCH v4 00/25] named CPU models for Arm64 on KVM Khushit Shah
` (9 preceding siblings ...)
2026-09-21 12:32 ` [RFC PATCH v4 10/25] target/arm: fix SVE and PAuth finalize for named CPU models Khushit Shah
@ 2026-09-21 12:32 ` Khushit Shah
2026-10-15 13:12 ` Eric Auger
2026-09-21 12:32 ` [RFC PATCH v4 12/25] target/arm: add arm-v9.0-a-v1 named CPU model Khushit Shah
` (14 subsequent siblings)
25 siblings, 1 reply; 66+ messages in thread
From: Khushit Shah @ 2026-09-21 12:32 UTC (permalink / raw)
To: qemu-devel, qemu-arm, kvmarm, eric.auger
Cc: cohuck, peter.maydell, richard.henderson, maz, oliver.upton,
berrange, abologna, jdenemar, gshan, skolothumtho, sebott, armbru,
philmd, yangjinqian1, shaju.abraham, mark.caveayland,
khushit.shah, ping, sandesh.patel
Under KVM, the guest PMU is backed by the host PMU (event set, PMCR.N,
and PMCEID), which may not be portable across heterogeneous hosts.
Disable PMU support for named CPU models by clearing ARM_FEATURE_PMU in
the named-model init path so arm_cpu_post_init() does not create the
"pmu" property.
Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
---
target/arm/cpu-models.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/target/arm/cpu-models.c b/target/arm/cpu-models.c
index fed3197186..153ee10ae6 100644
--- a/target/arm/cpu-models.c
+++ b/target/arm/cpu-models.c
@@ -159,6 +159,10 @@ static void arm_named_cpu_initfn(Object *obj)
/* 1.b Properly set RES1 fields. */
reset_res1_fields(cpu);
+ /* Disable PMU for named CPU models. */
+ unset_feature(&cpu->env, ARM_FEATURE_PMU);
+ cpu->has_pmu = false;
+
/* 2. Add sveNNNN and SYSREG_ properties */
aarch64_add_sve_properties(obj);
aarch64_add_idregs_properties(obj);
--
2.52.0
^ permalink raw reply related [flat|nested] 66+ messages in thread
* [RFC PATCH v4 12/25] target/arm: add arm-v9.0-a-v1 named CPU model
2026-09-21 12:32 [RFC PATCH v4 00/25] named CPU models for Arm64 on KVM Khushit Shah
` (10 preceding siblings ...)
2026-09-21 12:32 ` [RFC PATCH v4 11/25] target/arm: disable PMU support " Khushit Shah
@ 2026-09-21 12:32 ` Khushit Shah
2026-10-16 12:07 ` Eric Auger
2026-09-21 12:32 ` [RFC PATCH v4 13/25] target/arm: add neoverse-v2-v1 " Khushit Shah
` (13 subsequent siblings)
25 siblings, 1 reply; 66+ messages in thread
From: Khushit Shah @ 2026-09-21 12:32 UTC (permalink / raw)
To: qemu-devel, qemu-arm, kvmarm, eric.auger
Cc: cohuck, peter.maydell, richard.henderson, maz, oliver.upton,
berrange, abologna, jdenemar, gshan, skolothumtho, sebott, armbru,
philmd, yangjinqian1, shaju.abraham, mark.caveayland,
khushit.shah, ping, sandesh.patel
Add a KVM-only named CPU model for the Armv9.0-A baseline, following
DDI0487 revision M.c. The property list is the architecture-mandated
ID-register field view.
Pointer authentication is omitted because a v9.0-A core may implement
any PAuth algorithm.
Named models start from a zeroed ID-register view, so features whose
"not implemented" encoding is non-zero (for example TGran64=0xF,
DoubleLock=0xF) are set explicitly.
The model is not realizable on its own; implementation-defined fields
such as CTR_EL0.{CWG,ERG} and ID_AA64DFR0_EL1.CTX_CMPs still have to be
supplied on the command line. However, this provides a useful baseline
for upcoming reference core models.
Final ID register state requested from KVM for "arm-v9.0-a-v1":
[ 0] AIDR_EL1 = 0x0000000000000000
[ 1] CLIDR_EL1 = 0x0000000000000000
[ 2] CTR_EL0 = 0x0000000080008000
[ 3] DCZID_EL0 = 0x0000000000000000
[ 4] GMID_EL1 = 0x0000000000000000
[ 5] ID_AA64AFR0_EL1 = 0x0000000000000000
[ 6] ID_AA64AFR1_EL1 = 0x0000000000000000
[ 7] ID_AA64DFR0_EL1 = 0x000000f000000009
[ 8] ID_AA64DFR1_EL1 = 0x0000000000000000
[ 9] ID_AA64DFR2_EL1 = 0x0000000000000000
[ 10] ID_AA64FPFR0_EL1 = 0x0000000000000000
[ 11] ID_AA64ISAR0_EL1 = 0x0221100010210000
[ 12] ID_AA64ISAR1_EL1 = 0x0000011100211002
[ 13] ID_AA64ISAR2_EL1 = 0x0000000000000000
[ 14] ID_AA64ISAR3_EL1 = 0x0000000000000000
[ 15] ID_AA64MMFR0_EL1 = 0x000001110f000000
[ 16] ID_AA64MMFR1_EL1 = 0x0000000000211000
[ 17] ID_AA64MMFR2_EL1 = 0x1001001100000011
[ 18] ID_AA64MMFR3_EL1 = 0x0000000000000000
[ 19] ID_AA64MMFR4_EL1 = 0x000000000f000000
[ 20] ID_AA64PFR0_EL1 = 0x1101000010110011
[ 21] ID_AA64PFR1_EL1 = 0x0000000000000001
[ 22] ID_AA64PFR2_EL1 = 0x0000000000000000
[ 23] ID_AA64SMFR0_EL1 = 0x0000000000000000
[ 24] ID_AA64ZFR0_EL1 = 0x0000000000000000
[ 25] ID_AFR0_EL1 = 0x0000000000000000
[ 26] ID_DFR0_EL1 = 0x0000000000000000
[ 27] ID_DFR1_EL1 = 0x0000000000000000
[ 28] ID_ISAR0_EL1 = 0x0000000000000000
[ 29] ID_ISAR1_EL1 = 0x0000000000000000
[ 30] ID_ISAR2_EL1 = 0x0000000000000000
[ 31] ID_ISAR3_EL1 = 0x0000000000000000
[ 32] ID_ISAR4_EL1 = 0x0000000000000000
[ 33] ID_ISAR5_EL1 = 0x0000000000000000
[ 34] ID_ISAR6_EL1 = 0x0000000000000000
[ 35] ID_MMFR0_EL1 = 0x0000000000000000
[ 36] ID_MMFR1_EL1 = 0x0000000000000000
[ 37] ID_MMFR2_EL1 = 0x0000000000000000
[ 38] ID_MMFR3_EL1 = 0x0000000000000000
[ 39] ID_MMFR4_EL1 = 0x0000000000000000
[ 40] ID_MMFR5_EL1 = 0x0000000000000000
[ 41] ID_PFR0_EL1 = 0x0000000000000000
[ 42] ID_PFR1_EL1 = 0x0000000000000000
[ 43] ID_PFR2_EL1 = 0x0000000000000000
[ 44] MIDR_EL1 = 0x0000000000000000
[ 45] MPIDR_EL1 = 0x0000000080000000
[ 46] MVFR0_EL1 = 0x0000000000000000
[ 47] MVFR1_EL1 = 0x0000000000000000
[ 48] MVFR2_EL1 = 0x0000000000000000
[ 49] REVIDR_EL1 = 0x0000000000000000
[ 50] SMIDR_EL1 = 0x0000000000000000
Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
---
hw/arm/virt.c | 3 ++
target/arm/cpu-models.c | 75 +++++++++++++++++++++++++++++++++++++++++
2 files changed, 78 insertions(+)
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index e7a56e37f7..01381ab5e7 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -4144,6 +4144,9 @@ static GPtrArray *virt_get_valid_cpu_types(const MachineState *ms)
g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("neoverse-v1")));
g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("neoverse-n2")));
}
+ if (kvm_enabled() && target_aarch64()) {
+ g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("arm-v9.0-a-v1")));
+ }
if (target_aarch64()) {
g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("cortex-a53")));
g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("cortex-a57")));
diff --git a/target/arm/cpu-models.c b/target/arm/cpu-models.c
index 153ee10ae6..7394dd358e 100644
--- a/target/arm/cpu-models.c
+++ b/target/arm/cpu-models.c
@@ -39,7 +39,82 @@
/* Maximum parent-chain depth for named CPU models. */
#define ARM_NAMED_CPU_MODEL_MAX_DEPTH 16
+/* Arm-v9.0-a mandatory features. */
+static const ArmModelPropValue arm_v9_0_a_v1_props[] = {
+ /* ID_AA64PFR0_EL1 */
+ MODEL_PROP("SYSREG_ID_AA64PFR0_EL1_EL0", NUM, 1), /* only FEAT_AA64EL0 (Armv9.0) */
+ MODEL_PROP("SYSREG_ID_AA64PFR0_EL1_EL1", NUM, 1), /* only FEAT_AA64EL1 (Armv9.0) */
+ MODEL_PROP("SYSREG_ID_AA64PFR0_EL1_RAS", NUM, 1), /* FEAT_RAS (Armv8.2) */
+ MODEL_PROP("SYSREG_ID_AA64PFR0_EL1_DIT", NUM, 1), /* FEAT_DIT (Armv8.4) */
+ MODEL_PROP("SYSREG_ID_AA64PFR0_EL1_CSV2", NUM, 1), /* FEAT_CSV2 (Armv8.5) */
+ MODEL_PROP("SYSREG_ID_AA64PFR0_EL1_CSV3", NUM, 1), /* FEAT_CSV3 (Armv8.5) */
+ MODEL_PROP("SYSREG_ID_AA64PFR0_EL1_FP", NUM, 1), /* FEAT_FP16 */
+ MODEL_PROP("SYSREG_ID_AA64PFR0_EL1_AdvSIMD", NUM, 1), /* FEAT_FP16 */
+
+ /* ID_AA64PFR1_EL1 */
+ /* KVM zeroes out these field when MTE is not enabled. */
+ MODEL_PROP("SYSREG_ID_AA64PFR1_EL1_MTE_frac", NUM, 0),
+ MODEL_PROP("SYSREG_ID_AA64PFR1_EL1_BT", NUM, 1), /* FEAT_BTI (Armv8.5) */
+
+ /* ID_AA64MMFR0_EL1 */
+ MODEL_PROP("SYSREG_ID_AA64MMFR0_EL1_TGran64", NUM, 0xF), /* not mandatory */
+ MODEL_PROP("SYSREG_ID_AA64MMFR0_EL1_TGran4", NUM, 0), /* 4K granular support */
+ MODEL_PROP("SYSREG_ID_AA64MMFR0_EL1_TGran16_2", NUM, 1), /* not mandatory */
+ MODEL_PROP("SYSREG_ID_AA64MMFR0_EL1_TGran64_2", NUM, 1), /* not mandatory */
+ MODEL_PROP("SYSREG_ID_AA64MMFR0_EL1_TGran4_2", NUM, 1), /* not mandatory */
+
+ /* ID_AA64DFR0_EL1 */
+ MODEL_PROP("SYSREG_ID_AA64DFR0_EL1_DebugVer", NUM, 9), /* FEAT_Debugv8p4 (Armv8.4) */
+ MODEL_PROP("SYSREG_ID_AA64DFR0_EL1_DoubleLock", NUM, 0xF), /* not implemented */
+ /* no PMU for named models */
+ MODEL_PROP("SYSREG_ID_AA64DFR0_EL1_PMUVer", NUM, 0),
+
+ /* CTR_EL0 */
+ MODEL_PROP("SYSREG_CTR_EL0_L1Ip", NUM, 2), /* FEAT_IVIPT: VIPT cache impl. */
+
+ /* ID_AA64MMFR4_EL1 */
+ MODEL_PROP("SYSREG_ID_AA64MMFR4_EL1_E2H0", NUM, 0xF), /* FEAT_E2H0 not mandatory */
+
+ /* ID_AA64ISAR0_EL1 */
+ MODEL_PROP("SYSREG_ID_AA64ISAR0_EL1_CRC32", NUM, 1), /* FEAT_CRC32 (Armv8.1) */
+ MODEL_PROP("SYSREG_ID_AA64ISAR0_EL1_Atomic", NUM, 2), /* FEAT_LSE (Armv8.1) */
+ MODEL_PROP("SYSREG_ID_AA64ISAR0_EL1_TS", NUM, 2), /* FEAT_FlagM2 (Armv9.0 & FP) */
+ MODEL_PROP("SYSREG_ID_AA64ISAR0_EL1_TLB", NUM, 2), /* FEAT_TLBIRANGE (Armv8.4) */
+ MODEL_PROP("SYSREG_ID_AA64ISAR0_EL1_RDM", NUM, 1), /* FEAT_RDM (Armv9.0 & FP) */
+ MODEL_PROP("SYSREG_ID_AA64ISAR0_EL1_DP", NUM, 1), /* FEAT_DotProd (Armv9.0 & FP) */
+ MODEL_PROP("SYSREG_ID_AA64ISAR0_EL1_FHM", NUM, 1), /* FEAT_FHM (Armv9.0 & FP) */
+
+ /* ID_AA64ISAR1_EL1 */
+ MODEL_PROP("SYSREG_ID_AA64ISAR1_EL1_LRCPC", NUM, 2), /* FEAT_LRCPC2 (Armv8.4) */
+ MODEL_PROP("SYSREG_ID_AA64ISAR1_EL1_FRINTTS", NUM, 1), /* FEAT_FRINTTS (v9.0 & FP) */
+ MODEL_PROP("SYSREG_ID_AA64ISAR1_EL1_FCMA", NUM, 1), /* FEAT_FCMA (Armv9.0 & FP) */
+ MODEL_PROP("SYSREG_ID_AA64ISAR1_EL1_JSCVT", NUM, 1), /* FEAT_JSCVT (Armv9.0 & FP) */
+ MODEL_PROP("SYSREG_ID_AA64ISAR1_EL1_DPB", NUM, 2), /* FEAT_DPB2 (Armv8.5) */
+ MODEL_PROP("SYSREG_ID_AA64ISAR1_EL1_SB", NUM, 1), /* FEAT_SB (Armv8.5) */
+ MODEL_PROP("SYSREG_ID_AA64ISAR1_EL1_SPECRES", NUM, 1), /* FEAT_SPECRES (Armv8.5) */
+ /*
+ * FEAT_PAuth is mandated by Armv8.3 but is excluded here as reference
+ * core can choose to implement any PAuth algorithm (APA/API/APA3).
+ */
+
+ /* ID_AA64MMFR1_EL1 */
+ MODEL_PROP("SYSREG_ID_AA64MMFR1_EL1_HPDS", NUM, 1), /* FEAT_HPDS (Armv8.1) */
+ MODEL_PROP("SYSREG_ID_AA64MMFR1_EL1_LO", NUM, 1), /* FEAT_LOR (Armv8.1) */
+ MODEL_PROP("SYSREG_ID_AA64MMFR1_EL1_PAN", NUM, 2), /* FEAT_PAN2 (Armv8.2) */
+
+ /* ID_AA64MMFR2_EL1 */
+ MODEL_PROP("SYSREG_ID_AA64MMFR2_EL1_UAO", NUM, 1), /* FEAT_UAO (Armv8.2) */
+ MODEL_PROP("SYSREG_ID_AA64MMFR2_EL1_CnP", NUM, 1), /* FEAT_TTCNP (Armv8.2) */
+ MODEL_PROP("SYSREG_ID_AA64MMFR2_EL1_TTL", NUM, 1), /* FEAT_TTL (Armv8.4) */
+ MODEL_PROP("SYSREG_ID_AA64MMFR2_EL1_AT", NUM, 1), /* FEAT_LSE2 (Armv8.4) */
+ MODEL_PROP("SYSREG_ID_AA64MMFR2_EL1_IDS", NUM, 1), /* FEAT_IDST (Armv8.4) */
+ MODEL_PROP("SYSREG_ID_AA64MMFR2_EL1_E0PD", NUM, 1), /* FEAT_E0PD (Armv8.5) */
+
+ MODEL_PROP_END,
+};
+
static const ArmNamedCpuModel arm_cpu_models[] = {
+ {"arm-v9.0-a-v1", NULL, arm_v9_0_a_v1_props},
{NULL, NULL, NULL}
};
--
2.52.0
^ permalink raw reply related [flat|nested] 66+ messages in thread
* [RFC PATCH v4 13/25] target/arm: add neoverse-v2-v1 named CPU model
2026-09-21 12:32 [RFC PATCH v4 00/25] named CPU models for Arm64 on KVM Khushit Shah
` (11 preceding siblings ...)
2026-09-21 12:32 ` [RFC PATCH v4 12/25] target/arm: add arm-v9.0-a-v1 named CPU model Khushit Shah
@ 2026-09-21 12:32 ` Khushit Shah
2026-09-21 12:32 ` [RFC PATCH v4 14/25] target/arm: add neoverse-v2-v2 " Khushit Shah
` (12 subsequent siblings)
25 siblings, 0 replies; 66+ messages in thread
From: Khushit Shah @ 2026-09-21 12:32 UTC (permalink / raw)
To: qemu-devel, qemu-arm, kvmarm, eric.auger
Cc: cohuck, peter.maydell, richard.henderson, maz, oliver.upton,
berrange, abologna, jdenemar, gshan, skolothumtho, sebott, armbru,
philmd, yangjinqian1, shaju.abraham, mark.caveayland,
khushit.shah, ping, sandesh.patel
Add a KVM-only named CPU model for Neoverse V2 (TRM 102375, r0p0),
inheriting from arm-v9.0-a-v1. The property list is the subset of the
TRM that KVM can virtualize for a non-nested guest.
EL2, EL3, and SEL2 are left unimplemented. AMU, MPAM, SPE, TRF, and
similar features are omitted because KVM does not virtualize them. SoC
crypto opt-ins
are left unimplemented. PMU stays disabled for named models.
Some fields that a non-EL2 guest does not use (VH, EVT, S2FWB, E2H0) are
still pinned to the TRM value because KVM does not allow userspace to
lower them.
Final ID register state requested from KVM for "neoverse-v2-v1":
[ 0] AIDR_EL1 = 0x0000000000000000
[ 1] CLIDR_EL1 = 0x0000000000000000
[ 2] CTR_EL0 = 0x000000009444c004
[ 3] DCZID_EL0 = 0x0000000000000004
[ 4] GMID_EL1 = 0x0000000000000000
[ 5] ID_AA64AFR0_EL1 = 0x0000000000000000
[ 6] ID_AA64AFR1_EL1 = 0x0000000000000000
[ 7] ID_AA64DFR0_EL1 = 0x000000f010305009
[ 8] ID_AA64DFR1_EL1 = 0x0000000000000000
[ 9] ID_AA64DFR2_EL1 = 0x0000000000000000
[ 10] ID_AA64FPFR0_EL1 = 0x0000000000000000
[ 11] ID_AA64ISAR0_EL1 = 0x0221100010210000
[ 12] ID_AA64ISAR1_EL1 = 0x0011111101211052
[ 13] ID_AA64ISAR2_EL1 = 0x0000000000000000
[ 14] ID_AA64ISAR3_EL1 = 0x0000000000000000
[ 15] ID_AA64MMFR0_EL1 = 0x0000011100101125
[ 16] ID_AA64MMFR1_EL1 = 0x0000000010312122
[ 17] ID_AA64MMFR2_EL1 = 0x1221011110001011
[ 18] ID_AA64MMFR3_EL1 = 0x0000000000000000
[ 19] ID_AA64MMFR4_EL1 = 0x0000000000000000
[ 20] ID_AA64PFR0_EL1 = 0x1101000120110011
[ 21] ID_AA64PFR1_EL1 = 0x0000000000000021
[ 22] ID_AA64PFR2_EL1 = 0x0000000000000000
[ 23] ID_AA64SMFR0_EL1 = 0x0000000000000000
[ 24] ID_AA64ZFR0_EL1 = 0x0000100000110001
[ 25] ID_AFR0_EL1 = 0x0000000000000000
[ 26] ID_DFR0_EL1 = 0x0000000000000000
[ 27] ID_DFR1_EL1 = 0x0000000000000000
[ 28] ID_ISAR0_EL1 = 0x0000000000000000
[ 29] ID_ISAR1_EL1 = 0x0000000000000000
[ 30] ID_ISAR2_EL1 = 0x0000000000000000
[ 31] ID_ISAR3_EL1 = 0x0000000000000000
[ 32] ID_ISAR4_EL1 = 0x0000000000000000
[ 33] ID_ISAR5_EL1 = 0x0000000000000000
[ 34] ID_ISAR6_EL1 = 0x0000000000000000
[ 35] ID_MMFR0_EL1 = 0x0000000000000000
[ 36] ID_MMFR1_EL1 = 0x0000000000000000
[ 37] ID_MMFR2_EL1 = 0x0000000000000000
[ 38] ID_MMFR3_EL1 = 0x0000000000000000
[ 39] ID_MMFR4_EL1 = 0x0000000000000000
[ 40] ID_MMFR5_EL1 = 0x0000000000000000
[ 41] ID_PFR0_EL1 = 0x0000000000000000
[ 42] ID_PFR1_EL1 = 0x0000000000000000
[ 43] ID_PFR2_EL1 = 0x0000000000000000
[ 44] MIDR_EL1 = 0x00000000410fd4f0
[ 45] MPIDR_EL1 = 0x0000000080000000
[ 46] MVFR0_EL1 = 0x0000000000000000
[ 47] MVFR1_EL1 = 0x0000000000000000
[ 48] MVFR2_EL1 = 0x0000000000000000
[ 49] REVIDR_EL1 = 0x0000000000000000
[ 50] SMIDR_EL1 = 0x0000000000000000
Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
---
hw/arm/virt.c | 1 +
target/arm/cpu-models.c | 100 ++++++++++++++++++++++++++++++++++++++++
2 files changed, 101 insertions(+)
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 01381ab5e7..f5a8ea1145 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -4146,6 +4146,7 @@ static GPtrArray *virt_get_valid_cpu_types(const MachineState *ms)
}
if (kvm_enabled() && target_aarch64()) {
g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("arm-v9.0-a-v1")));
+ g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("neoverse-v2-v1")));
}
if (target_aarch64()) {
g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("cortex-a53")));
diff --git a/target/arm/cpu-models.c b/target/arm/cpu-models.c
index 7394dd358e..2de67f353b 100644
--- a/target/arm/cpu-models.c
+++ b/target/arm/cpu-models.c
@@ -13,6 +13,9 @@
* Assumptions:
* - All named CPU model properties are idempotent.
*
+ * Current Hierarchy:
+ * arm-v9.0-a-v1
+ * neoverse-v2-v1 (r0p0)
* SPDX-License-Identifier: GPL-2.0-or-later
*/
@@ -113,8 +116,105 @@ static const ArmModelPropValue arm_v9_0_a_v1_props[] = {
MODEL_PROP_END,
};
+/* Neoverse V2 CPU model (TRM 102375, r0p0), inherits from arm-v9.0-a-v1. */
+static const ArmModelPropValue neoverse_v2_v1_props[] = {
+ /* MIDR_EL1 */
+ MODEL_PROP("SYSREG_MIDR_EL1_Implementer", NUM, 0x41), /* ARM */
+ MODEL_PROP("SYSREG_MIDR_EL1_Variant", NUM, 0x0), /* r0p0*/
+ MODEL_PROP("SYSREG_MIDR_EL1_Architecture", NUM, 0xF),
+ MODEL_PROP("SYSREG_MIDR_EL1_Revision", NUM, 0x0), /* r0p0 */
+ MODEL_PROP("SYSREG_MIDR_EL1_PartNum", NUM, 0xD4F), /* Neoverse V2 */
+
+ /* ID_AA64PFR0_EL1 */
+ /* Neoverse V2 implements CSV2.2 but CSV2 is capped to 1.0 by KVM */
+ /* AMU and MPAM are not supported by KVM */
+ /* SEL2 is left not implemented for non-virtualized VM */
+ /* EL2 and EL3 are not implemented for non-virtualized VM */
+ MODEL_PROP("SYSREG_ID_AA64PFR0_EL1_SVE", NUM, 1), /* FEAT_SVE */
+ MODEL_PROP("sve128", BOOL, true),
+ MODEL_PROP("SYSREG_ID_AA64PFR0_EL1_RAS", NUM, 2), /* override; FEAT_RASv1p1 */
+
+ /* ID_AA64PFR1_EL1 */
+ MODEL_PROP("SYSREG_ID_AA64PFR1_EL1_SSBS", NUM, 2), /* FEAT_SSBS2 */
+
+ /* ID_AA64ZFR0_EL1 */
+ MODEL_PROP("SYSREG_ID_AA64ZFR0_EL1_I8MM", NUM, 1), /* FEAT_I8MM */
+ MODEL_PROP("SYSREG_ID_AA64ZFR0_EL1_BF16", NUM, 1), /* FEAT_BF16 */
+ MODEL_PROP("SYSREG_ID_AA64ZFR0_EL1_BitPerm", NUM, 1), /* FEAT_SVE_BitPerm */
+ MODEL_PROP("SYSREG_ID_AA64ZFR0_EL1_SVEver", NUM, 1), /* FEAT_SVE2 */
+ /* Other ID_AA64ZFR0_EL1 fields are SoC opt-ins */
+
+ /* ID_AA64DFR0_EL1 */
+ /* KVM does not virtualize FEAT_TRBE, FEAT_TRF, or FEAT_SPE. */
+ MODEL_PROP("SYSREG_ID_AA64DFR0_EL1_CTX_CMPs", NUM, 1), /* 2 context-aware BPs */
+ MODEL_PROP("SYSREG_ID_AA64DFR0_EL1_WRPs", NUM, 3), /* 4 watchpoints */
+ MODEL_PROP("SYSREG_ID_AA64DFR0_EL1_BRPs", NUM, 5), /* 6 breakpoints */
+
+ /* ID_AA64ISAR0_EL1 */
+ /* Many fields are SoC opt-ins; no mandatory overrides from Armv9.0-a-v1 */
+
+ /* ID_AA64ISAR1_EL1 */
+ MODEL_PROP("SYSREG_ID_AA64ISAR1_EL1_I8MM", NUM, 1), /* FEAT_I8MM */
+ MODEL_PROP("SYSREG_ID_AA64ISAR1_EL1_DGH", NUM, 1), /* FEAT_DGH */
+ MODEL_PROP("SYSREG_ID_AA64ISAR1_EL1_BF16", NUM, 1), /* FEAT_BF16 */
+ /* FEAT_PAuth2, QARMA5 is implemented */
+ MODEL_PROP("SYSREG_ID_AA64ISAR1_EL1_GPA", NUM, 1),
+ MODEL_PROP("SYSREG_ID_AA64ISAR1_EL1_APA", NUM, 5),
+
+ /* ID_AA64MMFR0_EL1 */
+ /* Keep stage-2 translations unimplemented for non-virtualized guests */
+ MODEL_PROP("SYSREG_ID_AA64MMFR0_EL1_TGran64", NUM, 0), /* supported */
+ MODEL_PROP("SYSREG_ID_AA64MMFR0_EL1_TGran16", NUM, 1), /* supported */
+ MODEL_PROP("SYSREG_ID_AA64MMFR0_EL1_SNSMem", NUM, 1), /* supported */
+ MODEL_PROP("SYSREG_ID_AA64MMFR0_EL1_BigEnd", NUM, 1), /* supported */
+ MODEL_PROP("SYSREG_ID_AA64MMFR0_EL1_ASIDBits", NUM, 2), /* 16 bits ASID */
+ MODEL_PROP("SYSREG_ID_AA64MMFR0_EL1_PARange", NUM, 5), /* 48 bits PA Range */
+
+ /* ID_AA64MMFR1_EL1 */
+ MODEL_PROP("SYSREG_ID_AA64MMFR1_EL1_XNX", NUM, 1), /* FEAT_XNX */
+ MODEL_PROP("SYSREG_ID_AA64MMFR1_EL1_PAN", NUM, 3), /* override; FEAT_PAN3 */
+ MODEL_PROP("SYSREG_ID_AA64MMFR1_EL1_VMIDBits", NUM, 2), /* 16 bits */
+ MODEL_PROP("SYSREG_ID_AA64MMFR1_EL1_HAFDBS", NUM, 2), /* FEAT_HAFDBS */
+ /*
+ * VHE is not needed for non-virtualized guests, but KVM does not
+ * support writing to it.
+ */
+ MODEL_PROP("SYSREG_ID_AA64MMFR1_EL1_VH", NUM, 1),
+ MODEL_PROP("SYSREG_ID_AA64MMFR1_EL1_HPDS", NUM, 2), /* override; FEAT_HPDS */
+
+ /* ID_AA64MMFR2_EL1 */
+ /*
+ * FEAT_EVT, FEAT_S2FWB not needed for non-virtualized guests, but KVM
+ * does not support writing to them.
+ */
+ MODEL_PROP("SYSREG_ID_AA64MMFR2_EL1_EVT", NUM, 2),
+ MODEL_PROP("SYSREG_ID_AA64MMFR2_EL1_BBM", NUM, 2), /* FEAT_BBM2 */
+ MODEL_PROP("SYSREG_ID_AA64MMFR2_EL1_FWB", NUM, 1), /* FEAT_S2FWB */
+ MODEL_PROP("SYSREG_ID_AA64MMFR2_EL1_ST", NUM, 1), /* FEAT_TTST */
+ MODEL_PROP("SYSREG_ID_AA64MMFR2_EL1_IESB", NUM, 1), /* FEAT_IESB */
+ /* FEAT_CCIDX not virtualized by KVM */
+ /* FEAT_NV not presented for non-virtualized guests */
+
+ /* ID_AA64MMFR4_EL1 */
+ MODEL_PROP("SYSREG_ID_AA64MMFR4_EL1_E2H0", NUM, 0), /* override; FEAT_E2H0 */
+
+ /* CTR_EL0 */
+ MODEL_PROP("SYSREG_CTR_EL0_IDC", NUM, 1),
+ MODEL_PROP("SYSREG_CTR_EL0_CWG", NUM, 4), /* Cache-writeback granule */
+ MODEL_PROP("SYSREG_CTR_EL0_ERG", NUM, 4),
+ MODEL_PROP("SYSREG_CTR_EL0_DminLine", NUM, 4), /* 64 bytes */
+ MODEL_PROP("SYSREG_CTR_EL0_IminLine", NUM, 4), /* 64 bytes */
+ MODEL_PROP("SYSREG_CTR_EL0_L1Ip", NUM, 3), /* PIPT */
+
+ /* DCZID_EL0 */
+ MODEL_PROP("SYSREG_DCZID_EL0_BS", NUM, 4), /* 64 bytes */
+
+ MODEL_PROP_END
+};
+
static const ArmNamedCpuModel arm_cpu_models[] = {
{"arm-v9.0-a-v1", NULL, arm_v9_0_a_v1_props},
+ {"neoverse-v2-v1", "arm-v9.0-a-v1", neoverse_v2_v1_props},
{NULL, NULL, NULL}
};
--
2.52.0
^ permalink raw reply related [flat|nested] 66+ messages in thread
* [RFC PATCH v4 14/25] target/arm: add neoverse-v2-v2 named CPU model
2026-09-21 12:32 [RFC PATCH v4 00/25] named CPU models for Arm64 on KVM Khushit Shah
` (12 preceding siblings ...)
2026-09-21 12:32 ` [RFC PATCH v4 13/25] target/arm: add neoverse-v2-v1 " Khushit Shah
@ 2026-09-21 12:32 ` Khushit Shah
2026-10-15 12:13 ` Eric Auger
2026-09-21 12:32 ` [RFC PATCH v4 15/25] target/arm: add graviton4-v1 " Khushit Shah
` (11 subsequent siblings)
25 siblings, 1 reply; 66+ messages in thread
From: Khushit Shah @ 2026-09-21 12:32 UTC (permalink / raw)
To: qemu-devel, qemu-arm, kvmarm, eric.auger
Cc: cohuck, peter.maydell, richard.henderson, maz, oliver.upton,
berrange, abologna, jdenemar, gshan, skolothumtho, sebott, armbru,
philmd, yangjinqian1, shaju.abraham, mark.caveayland,
khushit.shah, ping, sandesh.patel
Add a KVM-only named CPU model for Neoverse V2 r0p1 (TRM 102375),
inheriting from neoverse-v2-v1 (r0p0).
r0p1 only changes MIDR_EL1.Revision and adds FEAT_ECBHB
(ID_AA64MMFR1_EL1.ECBHB).
Final ID register state requested from KVM for "neoverse-v2-v2":
[ 0] AIDR_EL1 = 0x0000000000000000
[ 1] CLIDR_EL1 = 0x0000000000000000
[ 2] CTR_EL0 = 0x000000009444c004
[ 3] DCZID_EL0 = 0x0000000000000004
[ 4] GMID_EL1 = 0x0000000000000000
[ 5] ID_AA64AFR0_EL1 = 0x0000000000000000
[ 6] ID_AA64AFR1_EL1 = 0x0000000000000000
[ 7] ID_AA64DFR0_EL1 = 0x000000f010305009
[ 8] ID_AA64DFR1_EL1 = 0x0000000000000000
[ 9] ID_AA64DFR2_EL1 = 0x0000000000000000
[ 10] ID_AA64FPFR0_EL1 = 0x0000000000000000
[ 11] ID_AA64ISAR0_EL1 = 0x0221100010210000
[ 12] ID_AA64ISAR1_EL1 = 0x0011111101211052
[ 13] ID_AA64ISAR2_EL1 = 0x0000000000000000
[ 14] ID_AA64ISAR3_EL1 = 0x0000000000000000
[ 15] ID_AA64MMFR0_EL1 = 0x0000011100101125
[ 16] ID_AA64MMFR1_EL1 = 0x1000000010312122
[ 17] ID_AA64MMFR2_EL1 = 0x1221011110001011
[ 18] ID_AA64MMFR3_EL1 = 0x0000000000000000
[ 19] ID_AA64MMFR4_EL1 = 0x0000000000000000
[ 20] ID_AA64PFR0_EL1 = 0x1101000120110011
[ 21] ID_AA64PFR1_EL1 = 0x0000000000000021
[ 22] ID_AA64PFR2_EL1 = 0x0000000000000000
[ 23] ID_AA64SMFR0_EL1 = 0x0000000000000000
[ 24] ID_AA64ZFR0_EL1 = 0x0000100000110001
[ 25] ID_AFR0_EL1 = 0x0000000000000000
[ 26] ID_DFR0_EL1 = 0x0000000000000000
[ 27] ID_DFR1_EL1 = 0x0000000000000000
[ 28] ID_ISAR0_EL1 = 0x0000000000000000
[ 29] ID_ISAR1_EL1 = 0x0000000000000000
[ 30] ID_ISAR2_EL1 = 0x0000000000000000
[ 31] ID_ISAR3_EL1 = 0x0000000000000000
[ 32] ID_ISAR4_EL1 = 0x0000000000000000
[ 33] ID_ISAR5_EL1 = 0x0000000000000000
[ 34] ID_ISAR6_EL1 = 0x0000000000000000
[ 35] ID_MMFR0_EL1 = 0x0000000000000000
[ 36] ID_MMFR1_EL1 = 0x0000000000000000
[ 37] ID_MMFR2_EL1 = 0x0000000000000000
[ 38] ID_MMFR3_EL1 = 0x0000000000000000
[ 39] ID_MMFR4_EL1 = 0x0000000000000000
[ 40] ID_MMFR5_EL1 = 0x0000000000000000
[ 41] ID_PFR0_EL1 = 0x0000000000000000
[ 42] ID_PFR1_EL1 = 0x0000000000000000
[ 43] ID_PFR2_EL1 = 0x0000000000000000
[ 44] MIDR_EL1 = 0x00000000410fd4f1
[ 45] MPIDR_EL1 = 0x0000000080000000
[ 46] MVFR0_EL1 = 0x0000000000000000
[ 47] MVFR1_EL1 = 0x0000000000000000
[ 48] MVFR2_EL1 = 0x0000000000000000
[ 49] REVIDR_EL1 = 0x0000000000000000
[ 50] SMIDR_EL1 = 0x0000000000000000
Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
---
hw/arm/virt.c | 1 +
target/arm/cpu-models.c | 13 +++++++++++++
2 files changed, 14 insertions(+)
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index f5a8ea1145..90e818690c 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -4147,6 +4147,7 @@ static GPtrArray *virt_get_valid_cpu_types(const MachineState *ms)
if (kvm_enabled() && target_aarch64()) {
g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("arm-v9.0-a-v1")));
g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("neoverse-v2-v1")));
+ g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("neoverse-v2-v2")));
}
if (target_aarch64()) {
g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("cortex-a53")));
diff --git a/target/arm/cpu-models.c b/target/arm/cpu-models.c
index 2de67f353b..af60924953 100644
--- a/target/arm/cpu-models.c
+++ b/target/arm/cpu-models.c
@@ -16,6 +16,7 @@
* Current Hierarchy:
* arm-v9.0-a-v1
* neoverse-v2-v1 (r0p0)
+ * neoverse-v2-v2 (r0p1)
* SPDX-License-Identifier: GPL-2.0-or-later
*/
@@ -212,9 +213,21 @@ static const ArmModelPropValue neoverse_v2_v1_props[] = {
MODEL_PROP_END
};
+/* Neoverse V2 CPU model (TRM 102375, r0p1), inherits from neoverse-v2-v1. */
+static const ArmModelPropValue neoverse_v2_v2_props[] = {
+ /* MIDR_EL1 */
+ MODEL_PROP("SYSREG_MIDR_EL1_Revision", NUM, 0x1), /* r0p1 */
+
+ /* ID_AA64MMFR1_EL1 */
+ MODEL_PROP("SYSREG_ID_AA64MMFR1_EL1_ECBHB", NUM, 1), /* FEAT_ECBHB */
+
+ MODEL_PROP_END,
+};
+
static const ArmNamedCpuModel arm_cpu_models[] = {
{"arm-v9.0-a-v1", NULL, arm_v9_0_a_v1_props},
{"neoverse-v2-v1", "arm-v9.0-a-v1", neoverse_v2_v1_props},
+ {"neoverse-v2-v2", "neoverse-v2-v1", neoverse_v2_v2_props},
{NULL, NULL, NULL}
};
--
2.52.0
^ permalink raw reply related [flat|nested] 66+ messages in thread
* [RFC PATCH v4 15/25] target/arm: add graviton4-v1 named CPU model
2026-09-21 12:32 [RFC PATCH v4 00/25] named CPU models for Arm64 on KVM Khushit Shah
` (13 preceding siblings ...)
2026-09-21 12:32 ` [RFC PATCH v4 14/25] target/arm: add neoverse-v2-v2 " Khushit Shah
@ 2026-09-21 12:32 ` Khushit Shah
2026-09-21 12:32 ` [RFC PATCH v4 16/25] target/arm: add grace-v1 " Khushit Shah
` (10 subsequent siblings)
25 siblings, 0 replies; 66+ messages in thread
From: Khushit Shah @ 2026-09-21 12:32 UTC (permalink / raw)
To: qemu-devel, qemu-arm, kvmarm, eric.auger
Cc: cohuck, peter.maydell, richard.henderson, maz, oliver.upton,
berrange, abologna, jdenemar, gshan, skolothumtho, sebott, armbru,
philmd, yangjinqian1, shaju.abraham, mark.caveayland,
khushit.shah, ping, sandesh.patel
Add a KVM-only named CPU model for AWS Graviton4, inheriting from
neoverse-v2-v2. Because there is no public Graviton4 TRM, this model is
based on ID register dumps from actual Graviton4 systems, which appear
to implement Neoverse V2 r0p1 with the SoC crypto and RNDR opt-ins
enabled.
The extra properties are FEAT_RNG, SHA1/SHA2/SHA3/PMULL, the matching
SVE AES/SHA3 bits, and CTR_EL0.DIC.
Final ID register state requested from KVM for "graviton4-v1":
[ 0] AIDR_EL1 = 0x0000000000000000
[ 1] CLIDR_EL1 = 0x0000000000000000
[ 2] CTR_EL0 = 0x00000000b444c004
[ 3] DCZID_EL0 = 0x0000000000000004
[ 4] GMID_EL1 = 0x0000000000000000
[ 5] ID_AA64AFR0_EL1 = 0x0000000000000000
[ 6] ID_AA64AFR1_EL1 = 0x0000000000000000
[ 7] ID_AA64DFR0_EL1 = 0x000000f010305009
[ 8] ID_AA64DFR1_EL1 = 0x0000000000000000
[ 9] ID_AA64DFR2_EL1 = 0x0000000000000000
[ 10] ID_AA64FPFR0_EL1 = 0x0000000000000000
[ 11] ID_AA64ISAR0_EL1 = 0x1221100110212120
[ 12] ID_AA64ISAR1_EL1 = 0x0011111101211052
[ 13] ID_AA64ISAR2_EL1 = 0x0000000000000000
[ 14] ID_AA64ISAR3_EL1 = 0x0000000000000000
[ 15] ID_AA64MMFR0_EL1 = 0x0000011100101125
[ 16] ID_AA64MMFR1_EL1 = 0x1000000010312122
[ 17] ID_AA64MMFR2_EL1 = 0x1221011110001011
[ 18] ID_AA64MMFR3_EL1 = 0x0000000000000000
[ 19] ID_AA64MMFR4_EL1 = 0x0000000000000000
[ 20] ID_AA64PFR0_EL1 = 0x1101000120110011
[ 21] ID_AA64PFR1_EL1 = 0x0000000000000021
[ 22] ID_AA64PFR2_EL1 = 0x0000000000000000
[ 23] ID_AA64SMFR0_EL1 = 0x0000000000000000
[ 24] ID_AA64ZFR0_EL1 = 0x0000100100110021
[ 25] ID_AFR0_EL1 = 0x0000000000000000
[ 26] ID_DFR0_EL1 = 0x0000000000000000
[ 27] ID_DFR1_EL1 = 0x0000000000000000
[ 28] ID_ISAR0_EL1 = 0x0000000000000000
[ 29] ID_ISAR1_EL1 = 0x0000000000000000
[ 30] ID_ISAR2_EL1 = 0x0000000000000000
[ 31] ID_ISAR3_EL1 = 0x0000000000000000
[ 32] ID_ISAR4_EL1 = 0x0000000000000000
[ 33] ID_ISAR5_EL1 = 0x0000000000000000
[ 34] ID_ISAR6_EL1 = 0x0000000000000000
[ 35] ID_MMFR0_EL1 = 0x0000000000000000
[ 36] ID_MMFR1_EL1 = 0x0000000000000000
[ 37] ID_MMFR2_EL1 = 0x0000000000000000
[ 38] ID_MMFR3_EL1 = 0x0000000000000000
[ 39] ID_MMFR4_EL1 = 0x0000000000000000
[ 40] ID_MMFR5_EL1 = 0x0000000000000000
[ 41] ID_PFR0_EL1 = 0x0000000000000000
[ 42] ID_PFR1_EL1 = 0x0000000000000000
[ 43] ID_PFR2_EL1 = 0x0000000000000000
[ 44] MIDR_EL1 = 0x00000000410fd4f1
[ 45] MPIDR_EL1 = 0x0000000080000000
[ 46] MVFR0_EL1 = 0x0000000000000000
[ 47] MVFR1_EL1 = 0x0000000000000000
[ 48] MVFR2_EL1 = 0x0000000000000000
[ 49] REVIDR_EL1 = 0x0000000000000000
[ 50] SMIDR_EL1 = 0x0000000000000000
Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
---
hw/arm/virt.c | 1 +
target/arm/cpu-models.c | 21 +++++++++++++++++++++
2 files changed, 22 insertions(+)
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 90e818690c..e514d167cd 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -4148,6 +4148,7 @@ static GPtrArray *virt_get_valid_cpu_types(const MachineState *ms)
g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("arm-v9.0-a-v1")));
g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("neoverse-v2-v1")));
g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("neoverse-v2-v2")));
+ g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("graviton4-v1")));
}
if (target_aarch64()) {
g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("cortex-a53")));
diff --git a/target/arm/cpu-models.c b/target/arm/cpu-models.c
index af60924953..1a8913e619 100644
--- a/target/arm/cpu-models.c
+++ b/target/arm/cpu-models.c
@@ -17,6 +17,7 @@
* arm-v9.0-a-v1
* neoverse-v2-v1 (r0p0)
* neoverse-v2-v2 (r0p1)
+ * graviton4-v1
* SPDX-License-Identifier: GPL-2.0-or-later
*/
@@ -224,10 +225,30 @@ static const ArmModelPropValue neoverse_v2_v2_props[] = {
MODEL_PROP_END,
};
+/* Based on neoverse-v2-v2, with opt-in cryptographic features and RNDR. */
+static const ArmModelPropValue graviton4_v1_props[] = {
+ /* ID_AA64ISAR0_EL1 */
+ MODEL_PROP("SYSREG_ID_AA64ISAR0_EL1_RNDR", NUM, 1), /* FEAT_RNDR */
+ MODEL_PROP("SYSREG_ID_AA64ISAR0_EL1_SHA3", NUM, 1), /* FEAT_SHA3 */
+ MODEL_PROP("SYSREG_ID_AA64ISAR0_EL1_SHA2", NUM, 2), /* FEAT_SHA256 */
+ MODEL_PROP("SYSREG_ID_AA64ISAR0_EL1_SHA1", NUM, 1), /* FEAT_SHA1 */
+ MODEL_PROP("SYSREG_ID_AA64ISAR0_EL1_AES", NUM, 2), /* FEAT_PMULL */
+
+ /* ID_AA64ZFR0_EL1 */
+ MODEL_PROP("SYSREG_ID_AA64ZFR0_EL1_AES", NUM, 2), /* FEAT_SVE_PMULL128 */
+ MODEL_PROP("SYSREG_ID_AA64ZFR0_EL1_SHA3", NUM, 1), /* FEAT_SVE_SHA3 */
+
+ /* CTR_EL0 */
+ MODEL_PROP("SYSREG_CTR_EL0_DIC", NUM, 1),
+
+ MODEL_PROP_END,
+};
+
static const ArmNamedCpuModel arm_cpu_models[] = {
{"arm-v9.0-a-v1", NULL, arm_v9_0_a_v1_props},
{"neoverse-v2-v1", "arm-v9.0-a-v1", neoverse_v2_v1_props},
{"neoverse-v2-v2", "neoverse-v2-v1", neoverse_v2_v2_props},
+ {"graviton4-v1", "neoverse-v2-v2", graviton4_v1_props},
{NULL, NULL, NULL}
};
--
2.52.0
^ permalink raw reply related [flat|nested] 66+ messages in thread
* [RFC PATCH v4 16/25] target/arm: add grace-v1 named CPU model
2026-09-21 12:32 [RFC PATCH v4 00/25] named CPU models for Arm64 on KVM Khushit Shah
` (14 preceding siblings ...)
2026-09-21 12:32 ` [RFC PATCH v4 15/25] target/arm: add graviton4-v1 " Khushit Shah
@ 2026-09-21 12:32 ` Khushit Shah
2026-09-21 12:32 ` [RFC PATCH v4 17/25] target/arm: fail named CPU models on unknown non-zero feature ID regs Khushit Shah
` (9 subsequent siblings)
25 siblings, 0 replies; 66+ messages in thread
From: Khushit Shah @ 2026-09-21 12:32 UTC (permalink / raw)
To: qemu-devel, qemu-arm, kvmarm, eric.auger
Cc: cohuck, peter.maydell, richard.henderson, maz, oliver.upton,
berrange, abologna, jdenemar, gshan, skolothumtho, sebott, armbru,
philmd, yangjinqian1, shaju.abraham, mark.caveayland,
khushit.shah, ping, sandesh.patel
Add a KVM-only named CPU model for NVIDIA Grace, inheriting from
neoverse-v2-v1. Because there is no public Grace TRM, this model is
based on ID register dumps from actual Grace systems, which appear to
implement Neoverse V2 r0p0 with the SoC crypto opt-ins enabled.
The extra properties are SM3/SM4, SHA1/SHA2/SHA3/PMULL, the matching
SVE AES/SHA3/SM4 bits, and CTR_EL0.DIC.
Final ID register state requested from KVM for "grace-v1":
[ 0] AIDR_EL1 = 0x0000000000000000
[ 1] CLIDR_EL1 = 0x0000000000000000
[ 2] CTR_EL0 = 0x00000000b444c004
[ 3] DCZID_EL0 = 0x0000000000000004
[ 4] GMID_EL1 = 0x0000000000000000
[ 5] ID_AA64AFR0_EL1 = 0x0000000000000000
[ 6] ID_AA64AFR1_EL1 = 0x0000000000000000
[ 7] ID_AA64DFR0_EL1 = 0x000000f010305009
[ 8] ID_AA64DFR1_EL1 = 0x0000000000000000
[ 9] ID_AA64DFR2_EL1 = 0x0000000000000000
[ 10] ID_AA64FPFR0_EL1 = 0x0000000000000000
[ 11] ID_AA64ISAR0_EL1 = 0x0221111110212120
[ 12] ID_AA64ISAR1_EL1 = 0x0011111101211052
[ 13] ID_AA64ISAR2_EL1 = 0x0000000000000000
[ 14] ID_AA64ISAR3_EL1 = 0x0000000000000000
[ 15] ID_AA64MMFR0_EL1 = 0x0000011100101125
[ 16] ID_AA64MMFR1_EL1 = 0x0000000010312122
[ 17] ID_AA64MMFR2_EL1 = 0x1221011110001011
[ 18] ID_AA64MMFR3_EL1 = 0x0000000000000000
[ 19] ID_AA64MMFR4_EL1 = 0x0000000000000000
[ 20] ID_AA64PFR0_EL1 = 0x1101000120110011
[ 21] ID_AA64PFR1_EL1 = 0x0000000000000021
[ 22] ID_AA64PFR2_EL1 = 0x0000000000000000
[ 23] ID_AA64SMFR0_EL1 = 0x0000000000000000
[ 24] ID_AA64ZFR0_EL1 = 0x0000110100110021
[ 25] ID_AFR0_EL1 = 0x0000000000000000
[ 26] ID_DFR0_EL1 = 0x0000000000000000
[ 27] ID_DFR1_EL1 = 0x0000000000000000
[ 28] ID_ISAR0_EL1 = 0x0000000000000000
[ 29] ID_ISAR1_EL1 = 0x0000000000000000
[ 30] ID_ISAR2_EL1 = 0x0000000000000000
[ 31] ID_ISAR3_EL1 = 0x0000000000000000
[ 32] ID_ISAR4_EL1 = 0x0000000000000000
[ 33] ID_ISAR5_EL1 = 0x0000000000000000
[ 34] ID_ISAR6_EL1 = 0x0000000000000000
[ 35] ID_MMFR0_EL1 = 0x0000000000000000
[ 36] ID_MMFR1_EL1 = 0x0000000000000000
[ 37] ID_MMFR2_EL1 = 0x0000000000000000
[ 38] ID_MMFR3_EL1 = 0x0000000000000000
[ 39] ID_MMFR4_EL1 = 0x0000000000000000
[ 40] ID_MMFR5_EL1 = 0x0000000000000000
[ 41] ID_PFR0_EL1 = 0x0000000000000000
[ 42] ID_PFR1_EL1 = 0x0000000000000000
[ 43] ID_PFR2_EL1 = 0x0000000000000000
[ 44] MIDR_EL1 = 0x00000000410fd4f0
[ 45] MPIDR_EL1 = 0x0000000080000000
[ 46] MVFR0_EL1 = 0x0000000000000000
[ 47] MVFR1_EL1 = 0x0000000000000000
[ 48] MVFR2_EL1 = 0x0000000000000000
[ 49] REVIDR_EL1 = 0x0000000000000000
[ 50] SMIDR_EL1 = 0x0000000000000000
Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
---
hw/arm/virt.c | 1 +
target/arm/cpu-models.c | 23 +++++++++++++++++++++++
2 files changed, 24 insertions(+)
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index e514d167cd..d5ff7cf29d 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -4149,6 +4149,7 @@ static GPtrArray *virt_get_valid_cpu_types(const MachineState *ms)
g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("neoverse-v2-v1")));
g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("neoverse-v2-v2")));
g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("graviton4-v1")));
+ g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("grace-v1")));
}
if (target_aarch64()) {
g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("cortex-a53")));
diff --git a/target/arm/cpu-models.c b/target/arm/cpu-models.c
index 1a8913e619..4e92909755 100644
--- a/target/arm/cpu-models.c
+++ b/target/arm/cpu-models.c
@@ -18,6 +18,7 @@
* neoverse-v2-v1 (r0p0)
* neoverse-v2-v2 (r0p1)
* graviton4-v1
+ * grace-v1
* SPDX-License-Identifier: GPL-2.0-or-later
*/
@@ -225,6 +226,27 @@ static const ArmModelPropValue neoverse_v2_v2_props[] = {
MODEL_PROP_END,
};
+/* Based on neoverse-v2-v1, with opt-in cryptographic features. */
+static const ArmModelPropValue grace_v1_props[] = {
+ /* ID_AA64ISAR0_EL1 */
+ MODEL_PROP("SYSREG_ID_AA64ISAR0_EL1_SM4", NUM, 1), /* FEAT_SM4 */
+ MODEL_PROP("SYSREG_ID_AA64ISAR0_EL1_SM3", NUM, 1), /* FEAT_SM3 */
+ MODEL_PROP("SYSREG_ID_AA64ISAR0_EL1_SHA3", NUM, 1), /* FEAT_SHA3 */
+ MODEL_PROP("SYSREG_ID_AA64ISAR0_EL1_SHA2", NUM, 2), /* FEAT_SHA256 */
+ MODEL_PROP("SYSREG_ID_AA64ISAR0_EL1_SHA1", NUM, 1), /* FEAT_SHA1 */
+ MODEL_PROP("SYSREG_ID_AA64ISAR0_EL1_AES", NUM, 2), /* FEAT_PMULL */
+
+ /* ID_AA64ZFR0_EL1 */
+ MODEL_PROP("SYSREG_ID_AA64ZFR0_EL1_AES", NUM, 2), /* FEAT_SVE_PMULL128 */
+ MODEL_PROP("SYSREG_ID_AA64ZFR0_EL1_SHA3", NUM, 1), /* FEAT_SVE_SHA3 */
+ MODEL_PROP("SYSREG_ID_AA64ZFR0_EL1_SM4", NUM, 1), /* FEAT_SVE_SM4 */
+
+ /* CTR_EL0 */
+ MODEL_PROP("SYSREG_CTR_EL0_DIC", NUM, 1),
+
+ MODEL_PROP_END,
+};
+
/* Based on neoverse-v2-v2, with opt-in cryptographic features and RNDR. */
static const ArmModelPropValue graviton4_v1_props[] = {
/* ID_AA64ISAR0_EL1 */
@@ -249,6 +271,7 @@ static const ArmNamedCpuModel arm_cpu_models[] = {
{"neoverse-v2-v1", "arm-v9.0-a-v1", neoverse_v2_v1_props},
{"neoverse-v2-v2", "neoverse-v2-v1", neoverse_v2_v2_props},
{"graviton4-v1", "neoverse-v2-v2", graviton4_v1_props},
+ {"grace-v1", "neoverse-v2-v1", grace_v1_props},
{NULL, NULL, NULL}
};
--
2.52.0
^ permalink raw reply related [flat|nested] 66+ messages in thread
* [RFC PATCH v4 17/25] target/arm: fail named CPU models on unknown non-zero feature ID regs
2026-09-21 12:32 [RFC PATCH v4 00/25] named CPU models for Arm64 on KVM Khushit Shah
` (15 preceding siblings ...)
2026-09-21 12:32 ` [RFC PATCH v4 16/25] target/arm: add grace-v1 " Khushit Shah
@ 2026-09-21 12:32 ` Khushit Shah
2026-10-16 12:27 ` Eric Auger
2026-09-21 12:32 ` [RFC PATCH v4 18/25] target/arm: add cpu-models-stub.c Khushit Shah
` (8 subsequent siblings)
25 siblings, 1 reply; 66+ messages in thread
From: Khushit Shah @ 2026-09-21 12:32 UTC (permalink / raw)
To: qemu-devel, qemu-arm, kvmarm, eric.auger
Cc: cohuck, peter.maydell, richard.henderson, maz, oliver.upton,
berrange, abologna, jdenemar, gshan, skolothumtho, sebott, armbru,
philmd, yangjinqian1, shaju.abraham, mark.caveayland,
khushit.shah, ping, sandesh.patel
Named CPU models zero the ID registers QEMU knows about and then apply
SYSREG_ properties. However, the host and KVM might expose ID
registers that QEMU does not know about yet. In this scenario, named
CPU models might
leak host features to the guest.
Part of the problem can be addressed because the Arm Architecture
Reference Manual specifies that unused encodings in the space (op1==0,
CRn==0, CRm=={2-7}) may be treated as RES0. This range includes all
ID_AA64* registers.
Error out if KVM returns a non-zero value for a register in the above
space which QEMU does not know about yet.
get_sysreg_idx() now returns -1 for encodings that are not known ID
registers, and kvm_arm_read_sys_reg64() exposes a KVM GET_ONE_REG
read for this probe.
Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
---
target/arm/cpu-models.c | 74 ++++++++++++++++++++++++++++++++++++++++
target/arm/cpu-sysregs.h | 2 +-
target/arm/cpu64.c | 3 +-
target/arm/kvm-stub.c | 7 ++++
target/arm/kvm.c | 7 ++++
target/arm/kvm_arm.h | 12 +++++++
6 files changed, 103 insertions(+), 2 deletions(-)
diff --git a/target/arm/cpu-models.c b/target/arm/cpu-models.c
index 4e92909755..855eb5ee6b 100644
--- a/target/arm/cpu-models.c
+++ b/target/arm/cpu-models.c
@@ -362,6 +362,78 @@ static void reset_res1_fields(ARMCPU *cpu)
}
}
+/*
+ * From ARM ARM:
+ *
+ * For unused encodings in the part of the space that has op1==0 and
+ * CRm=={2-7}, direct reads that are not trapped behave as Reserved,
+ * RES0 to ensure correct behavior if the encodings are used for ID
+ * registers in the future.
+ *
+ * It includes every ID_AA64* register.
+ *
+ * For named CPU models, we can check if any of the unknown ID registers
+ * that fall into this space is non-zero on the host. If so, the named CPU
+ * model leaks those host features. Error out in such case.
+ *
+ * We cannot do the same for the remaining Feature ID space (op1==0 and
+ * CRm==0, or op1=={1,3}). Unused encodings there are UNDEFINED. The
+ * implemented registers in that space (MIDR_EL1, CTR_EL0, DCZID_EL0,
+ * CCSIDR_EL1, ...) are identification or cache geometry.
+ */
+static void arm_named_cpu_zero_unknown_feature_ids(ARMCPU *cpu, Error **errp)
+{
+ uint32_t init_features0 = 0;
+ static bool checked;
+ uint32_t target;
+ int fdarray[3];
+ int crm, op2;
+ int fd;
+
+ if (checked) {
+ return;
+ }
+
+ if (!kvm_arm_create_scratch_max_host_vcpu(fdarray, &init_features0,
+ &target, errp)) {
+ return;
+ }
+
+ fd = fdarray[2];
+ for (crm = 2; crm <= 7; crm++) {
+ for (op2 = 0; op2 <= 7; op2++) {
+ uint64_t val = 0;
+ int ret;
+
+ if (get_sysreg_idx(ENCODE_ID_REG(3, 0, 0, crm, op2)) != -1) {
+ continue;
+ }
+
+ ret = kvm_arm_read_sys_reg64(fd, &val, 3, 0, 0, crm, op2);
+ if (ret) {
+ continue;
+ }
+
+ /*
+ * TODO: if this encoding is writable, try to write 0?
+ */
+ if (val) {
+ error_setg(errp,
+ "unknown Feature ID register "
+ "(op0=3, op1=0, CRn=0, CRm=%d, op2=%d) "
+ "reads as 0x%" PRIx64 " on the host; named CPU "
+ "models cannot hide it",
+ crm, op2, val);
+ kvm_arm_destroy_scratch_host_vcpu(fdarray);
+ return;
+ }
+ }
+ }
+
+ kvm_arm_destroy_scratch_host_vcpu(fdarray);
+ checked = true;
+}
+
static void arm_named_cpu_initfn(Object *obj)
{
ARMCPU *cpu = ARM_CPU(obj);
@@ -401,6 +473,8 @@ static void arm_named_cpu_initfn(Object *obj)
/* 3. Realize the model chain. */
arm_realize_model_chain(obj, model, &error_abort);
+
+ arm_named_cpu_zero_unknown_feature_ids(cpu, &error_abort);
}
void arm_register_named_cpu_models(void)
diff --git a/target/arm/cpu-sysregs.h b/target/arm/cpu-sysregs.h
index 7877a3b06a..d48b44705f 100644
--- a/target/arm/cpu-sysregs.h
+++ b/target/arm/cpu-sysregs.h
@@ -37,6 +37,6 @@ typedef enum ARMSysRegs {
extern const uint32_t id_register_sysreg[NUM_ID_IDX];
-int get_sysreg_idx(ARMSysRegs sysreg);
+int get_sysreg_idx(ARMSysRegs sysreg); /* -1 if @sysreg is not a known ID register */
#endif /* ARM_CPU_SYSREGS_H */
diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
index a0114b0fa2..3cc698d65a 100644
--- a/target/arm/cpu64.c
+++ b/target/arm/cpu64.c
@@ -57,8 +57,9 @@ int get_sysreg_idx(ARMSysRegs sysreg)
{
switch (sysreg) {
#include "cpu-sysregs.h.inc"
+ default:
+ return -1;
}
- g_assert_not_reached();
}
#undef DEF
diff --git a/target/arm/kvm-stub.c b/target/arm/kvm-stub.c
index eae2e1ec2c..d263adc921 100644
--- a/target/arm/kvm-stub.c
+++ b/target/arm/kvm-stub.c
@@ -50,6 +50,13 @@ void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu)
g_assert_not_reached();
}
+int kvm_arm_read_sys_reg64(int fd, uint64_t *val,
+ uint8_t op0, uint8_t op1,
+ uint8_t crn, uint8_t crm, uint8_t op2)
+{
+ g_assert_not_reached();
+}
+
void kvm_arm_add_vcpu_properties(ARMCPU *cpu)
{
g_assert_not_reached();
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index 70d9a07580..6f704c0509 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -263,6 +263,13 @@ static int read_sys_reg64(int fd, uint64_t *pret, uint64_t id)
return ioctl(fd, KVM_GET_ONE_REG, &idreg);
}
+int kvm_arm_read_sys_reg64(int fd, uint64_t *val,
+ uint8_t op0, uint8_t op1,
+ uint8_t crn, uint8_t crm, uint8_t op2)
+{
+ return read_sys_reg64(fd, val, ARM64_SYS_REG(op0, op1, crn, crm, op2));
+}
+
static uint64_t idregs_sysreg_to_kvm_reg(ARMSysRegs sysreg)
{
return ARM64_SYS_REG((sysreg & CP_REG_ARM64_SYSREG_OP0_MASK) >> CP_REG_ARM64_SYSREG_OP0_SHIFT,
diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h
index 997120966f..4e563fab96 100644
--- a/target/arm/kvm_arm.h
+++ b/target/arm/kvm_arm.h
@@ -154,6 +154,18 @@ bool kvm_arm_create_scratch_max_host_vcpu(int *fdarray,
*/
void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu);
+/**
+ * kvm_arm_read_sys_reg64:
+ * @fd: vCPU fd
+ * @val: filled with the register value on success
+ * @op0/@op1/@crn/@crm/@op2: System ID register encoding
+ *
+ * Returns: 0 on success, -1 on failure.
+ */
+int kvm_arm_read_sys_reg64(int fd, uint64_t *val,
+ uint8_t op0, uint8_t op1,
+ uint8_t crn, uint8_t crm, uint8_t op2);
+
/**
* kvm_arm_add_vcpu_properties:
* @cpu: The CPU object to add the properties to
--
2.52.0
^ permalink raw reply related [flat|nested] 66+ messages in thread
* [RFC PATCH v4 18/25] target/arm: add cpu-models-stub.c
2026-09-21 12:32 [RFC PATCH v4 00/25] named CPU models for Arm64 on KVM Khushit Shah
` (16 preceding siblings ...)
2026-09-21 12:32 ` [RFC PATCH v4 17/25] target/arm: fail named CPU models on unknown non-zero feature ID regs Khushit Shah
@ 2026-09-21 12:32 ` Khushit Shah
2026-09-29 15:00 ` Philippe Mathieu-Daudé
2026-09-21 12:32 ` [RFC PATCH v4 19/25] target/arm/qmp: allow named CPU models on cpu-model-expansion Khushit Shah
` (7 subsequent siblings)
25 siblings, 1 reply; 66+ messages in thread
From: Khushit Shah @ 2026-09-21 12:32 UTC (permalink / raw)
To: qemu-devel, qemu-arm, kvmarm, eric.auger
Cc: cohuck, peter.maydell, richard.henderson, maz, oliver.upton,
berrange, abologna, jdenemar, gshan, skolothumtho, sebott, armbru,
philmd, yangjinqian1, shaju.abraham, mark.caveayland,
khushit.shah, ping, sandesh.patel
Add cpu-models-stub.c, which will be required to add QMP support.
Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
---
target/arm/cpu-models-stub.c | 13 +++++++++++++
target/arm/meson.build | 1 +
2 files changed, 14 insertions(+)
create mode 100644 target/arm/cpu-models-stub.c
diff --git a/target/arm/cpu-models-stub.c b/target/arm/cpu-models-stub.c
new file mode 100644
index 0000000000..48f712d648
--- /dev/null
+++ b/target/arm/cpu-models-stub.c
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * ARM named CPU model stubs.
+ */
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "cpu-models.h"
+
+
+const ArmNamedCpuModel *arm_find_model(const char *name)
+{
+ return NULL;
+}
diff --git a/target/arm/meson.build b/target/arm/meson.build
index dd28146c52..5c056fc440 100644
--- a/target/arm/meson.build
+++ b/target/arm/meson.build
@@ -42,6 +42,7 @@ arm_stubs_ss.add(files(
'gicv5-stubs.c',
'kvm-stub.c',
'tcg-stubs.c',
+ 'cpu-models-stub.c'
))
arm_user_ss.add(files(
'el2-stubs.c',
--
2.52.0
^ permalink raw reply related [flat|nested] 66+ messages in thread
* [RFC PATCH v4 19/25] target/arm/qmp: allow named CPU models on cpu-model-expansion
2026-09-21 12:32 [RFC PATCH v4 00/25] named CPU models for Arm64 on KVM Khushit Shah
` (17 preceding siblings ...)
2026-09-21 12:32 ` [RFC PATCH v4 18/25] target/arm: add cpu-models-stub.c Khushit Shah
@ 2026-09-21 12:32 ` Khushit Shah
2026-10-16 12:32 ` Eric Auger
2026-09-21 12:32 ` [RFC PATCH v4 20/25] target/arm/kvm: compute host-supported values for ID register fields Khushit Shah
` (6 subsequent siblings)
25 siblings, 1 reply; 66+ messages in thread
From: Khushit Shah @ 2026-09-21 12:32 UTC (permalink / raw)
To: qemu-devel, qemu-arm, kvmarm, eric.auger
Cc: cohuck, peter.maydell, richard.henderson, maz, oliver.upton,
berrange, abologna, jdenemar, gshan, skolothumtho, sebott, armbru,
philmd, yangjinqian1, shaju.abraham, mark.caveayland,
khushit.shah, ping, sandesh.patel
Allow expansion of the new KVM-only named CPU models through the
cpu-model-expansion QMP query.
Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
---
target/arm/arm-qmp-cmds.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/target/arm/arm-qmp-cmds.c b/target/arm/arm-qmp-cmds.c
index 5fbdca3253..0940285af1 100644
--- a/target/arm/arm-qmp-cmds.c
+++ b/target/arm/arm-qmp-cmds.c
@@ -36,6 +36,7 @@
#include <linux/kvm.h>
#include "system/kvm.h"
#include "cpu.h"
+#include "cpu-models.h"
static GICCapability *gic_cap_new(int version)
{
@@ -96,6 +97,7 @@ CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type,
Object *obj;
const char *name;
int fdarray[3];
+ bool named_model = (arm_find_model(model->name) != NULL);
int i;
if (type != CPU_MODEL_EXPANSION_TYPE_FULL) {
@@ -108,6 +110,11 @@ CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type,
return NULL;
}
+ if (!kvm_enabled() && named_model) {
+ error_setg(errp, "The CPU type '%s' requires KVM", model->name);
+ return NULL;
+ }
+
oc = cpu_class_by_name(TYPE_ARM_CPU, model->name);
if (!oc) {
error_setg(errp, "The CPU type '%s' is not a recognized ARM CPU type",
@@ -121,6 +128,8 @@ CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type,
if (!strcmp(model->name, "host") || !strcmp(model->name, "max")) {
/* These are kvmarm's recommended cpu types */
supported = true;
+ } else if (named_model) {
+ supported = true;
} else if (current_machine->cpu_type) {
const char *cpu_type = current_machine->cpu_type;
int len = strlen(cpu_type) - strlen(ARM_CPU_TYPE_SUFFIX);
--
2.52.0
^ permalink raw reply related [flat|nested] 66+ messages in thread
* [RFC PATCH v4 20/25] target/arm/kvm: compute host-supported values for ID register fields
2026-09-21 12:32 [RFC PATCH v4 00/25] named CPU models for Arm64 on KVM Khushit Shah
` (18 preceding siblings ...)
2026-09-21 12:32 ` [RFC PATCH v4 19/25] target/arm/qmp: allow named CPU models on cpu-model-expansion Khushit Shah
@ 2026-09-21 12:32 ` Khushit Shah
2026-10-16 13:10 ` Eric Auger
2026-09-21 12:32 ` [RFC PATCH v4 21/25] target/arm: report 0 as supported for ID fields gated by vCPU init flags Khushit Shah
` (5 subsequent siblings)
25 siblings, 1 reply; 66+ messages in thread
From: Khushit Shah @ 2026-09-21 12:32 UTC (permalink / raw)
To: qemu-devel, qemu-arm, kvmarm, eric.auger
Cc: cohuck, peter.maydell, richard.henderson, maz, oliver.upton,
berrange, abologna, jdenemar, gshan, skolothumtho, sebott, armbru,
philmd, yangjinqian1, shaju.abraham, mark.caveayland,
khushit.shah, ping, sandesh.patel
Add kvm_arm_field_get_supported_values() which, for a given ID register
field, builds the set of values KVM allows it to take on the given host.
Non-writable fields are pinned to the host value. Writable fields follow
their per-field constraints. This function must be updated when KVM
starts exposing a new writable field that is not lower-safe; hence the
special handling of TGranX_2/SpecSEI/L1Ip/MIDR/REVIDR/AIDR.
Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
--------
Note:
- We should have an authoritative static list of "writable" fields in
QEMU.
---
target/arm/kvm-stub.c | 7 +++
target/arm/kvm.c | 99 +++++++++++++++++++++++++++++++++++++++++++
target/arm/kvm_arm.h | 28 ++++++++++++
3 files changed, 134 insertions(+)
diff --git a/target/arm/kvm-stub.c b/target/arm/kvm-stub.c
index d263adc921..c9cd47bf47 100644
--- a/target/arm/kvm-stub.c
+++ b/target/arm/kvm-stub.c
@@ -144,3 +144,10 @@ void kvm_arm_destroy_scratch_host_vcpu(int *fdarray)
{
g_assert_not_reached();
}
+
+void kvm_arm_field_get_supported_values(const ARM64SysRegField *field,
+ const ARMISARegisters *host_isar,
+ ArmFieldValueSet **value_set)
+{
+ g_assert_not_reached();
+}
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index 6f704c0509..77b1bcdf55 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -1324,6 +1324,105 @@ bool kvm_arm_cpu_post_load(ARMCPU *cpu)
return true;
}
+static bool arm_field_is_signed(const ARM64SysRegField *field)
+{
+ return field_matches(field, ID_AA64MMFR0_EL1_IDX, "TGran4") ||
+ field_matches(field, ID_AA64MMFR0_EL1_IDX, "TGran64") ||
+ field_matches(field, ID_MMFR0_EL1_IDX, "InnerShr") ||
+ field_matches(field, ID_MMFR0_EL1_IDX, "OuterShr") ||
+ field_matches(field, ID_AA64DFR0_EL1_IDX, "DoubleLock") ||
+ field_matches(field, ID_AA64DFR0_EL1_IDX, "PMUVer") ||
+ field_matches(field, ID_DFR0_EL1_IDX, "PerfMon") ||
+ field_matches(field, ID_AA64PFR1_EL1_IDX, "MTE_frac") ||
+ field_matches(field, ID_AA64MMFR4_EL1_IDX, "E2H0") ||
+ field_matches(field, ID_DFR1_EL1_IDX, "MTPMU") ||
+ field_matches(field, ID_AA64PFR0_EL1_IDX, "FP") ||
+ field_matches(field, ID_AA64PFR0_EL1_IDX, "AdvSIMD");
+}
+
+static void ranges_add(GArray *ranges, uint64_t min, uint64_t max)
+{
+ ArmFieldRange r = { .min = min, .max = max };
+ g_array_append_val(ranges, r);
+}
+
+void kvm_arm_field_get_supported_values(const ARM64SysRegField *field,
+ const ARMISARegisters *host_isar,
+ ArmFieldValueSet **value_set)
+{
+ bool is_signed = arm_field_is_signed(field);
+ uint64_t host = extract64(host_isar->idregs[field->index],
+ field->shift, field->length);
+ GArray *ranges = g_array_new(false, false, sizeof(ArmFieldRange));
+
+ /* A non-writable field can only ever hold the host value. */
+ if (!arm_field_is_writable(field)) {
+ ranges_add(ranges, host, host);
+ goto done;
+ }
+
+ if (field_matches(field, ID_AA64MMFR0_EL1_IDX, "TGran4_2") ||
+ field_matches(field, ID_AA64MMFR0_EL1_IDX, "TGran16_2") ||
+ field_matches(field, ID_AA64MMFR0_EL1_IDX, "TGran64_2")) {
+ /* Either support the host value or the "off" value */
+ ranges_add(ranges, host, host);
+ if (host != 1) { /* 1 = "off" */
+ ranges_add(ranges, 1, 1);
+ }
+ } else if (field_matches(field, CTR_EL0_IDX, "L1Ip")) {
+ /* Only safe to downgrade to VIPT, other values are reserved. */
+ ranges_add(ranges, host, host);
+ if (host != 2) { /* 2 = "VIPT" */
+ ranges_add(ranges, 2, 2);
+ }
+ } else if (field_matches(field, ID_AA64MMFR1_EL1_IDX, "SpecSEI") ||
+ field_matches(field, ID_MMFR4_EL1_IDX, "SpecSEI")) {
+ /* It is safe to upgrade SpecSEI to 1, other values are reserved. */
+ ranges_add(ranges, host, host);
+ if (host != 1) {
+ ranges_add(ranges, 1, 1);
+ }
+ } else if (field->index == MIDR_EL1_IDX ||
+ field->index == REVIDR_EL1_IDX ||
+ field->index == AIDR_EL1_IDX) {
+ /*
+ * No restriction on value that can be set for implementation ID
+ * registers fields.
+ */
+ uint64_t max = 0;
+ if (field->length == 64) {
+ max = ~0ULL;
+ } else {
+ max = (1ULL << field->length) - 1;
+ }
+ ranges_add(ranges, 0, max);
+ } else {
+ /*
+ * After handling the special cases, other writable fields are
+ * either lower-safe or signed lower-safe.
+ */
+ if (field->arch_vals_count) {
+ for (uint32_t i = 0; i < field->arch_vals_count; i++) {
+ uint64_t av = field->arch_vals[i];
+ int64_t v = is_signed ?
+ sextract64(av, 0, field->length) : (int64_t)av;
+ int64_t hv = is_signed ?
+ sextract64(host, 0, field->length) : (int64_t)host;
+ if (v <= hv) {
+ ranges_add(ranges, av, av);
+ }
+ }
+ } else {
+ g_assert(!is_signed); /* No signed field with no arch vals */
+ ranges_add(ranges, 0, host);
+ }
+ }
+done:
+ *value_set = g_new0(ArmFieldValueSet, 1);
+ (*value_set)->n_ranges = ranges->len;
+ (*value_set)->ranges = (ArmFieldRange *)g_array_free(ranges, false);
+}
+
static bool arm_field_skip_writeback_always(const ARM64SysRegField *field)
{
/*
diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h
index 4e563fab96..9481e56412 100644
--- a/target/arm/kvm_arm.h
+++ b/target/arm/kvm_arm.h
@@ -175,6 +175,34 @@ int kvm_arm_read_sys_reg64(int fd, uint64_t *val,
*/
void kvm_arm_add_vcpu_properties(ARMCPU *cpu);
+typedef struct ARM64SysReg ARM64SysReg;
+typedef struct ARM64SysRegField ARM64SysRegField;
+typedef struct ARMISARegisters ARMISARegisters;
+
+typedef struct ArmFieldRange {
+ uint64_t min;
+ uint64_t max;
+} ArmFieldRange;
+
+typedef struct ArmFieldValueSet {
+ ArmFieldRange *ranges;
+ size_t n_ranges;
+} ArmFieldValueSet;
+
+/**
+ * kvm_arm_field_get_supported_values:
+ * @field: The field to get the supported values for
+ * @host_isar: The host ISAR registers
+ * @value_set: The set of supported values for the @field
+ *
+ * Will be allocated and filled in with the supported values for the @field
+ * based on the host_isar and whether the field is writable or not.
+ * The caller must free the value_set.
+ */
+void kvm_arm_field_get_supported_values(const ARM64SysRegField *field,
+ const ARMISARegisters *host_isar,
+ ArmFieldValueSet **value_set);
+
/**
* kvm_arm_steal_time_finalize:
* @cpu: ARMCPU for which to finalize kvm-steal-time
--
2.52.0
^ permalink raw reply related [flat|nested] 66+ messages in thread
* [RFC PATCH v4 21/25] target/arm: report 0 as supported for ID fields gated by vCPU init flags
2026-09-21 12:32 [RFC PATCH v4 00/25] named CPU models for Arm64 on KVM Khushit Shah
` (19 preceding siblings ...)
2026-09-21 12:32 ` [RFC PATCH v4 20/25] target/arm/kvm: compute host-supported values for ID register fields Khushit Shah
@ 2026-09-21 12:32 ` Khushit Shah
2026-10-16 13:12 ` Eric Auger
2026-09-21 12:32 ` [RFC PATCH v4 22/25] target/arm/kvm: add kvm_arm_get_host_isar helper Khushit Shah
` (4 subsequent siblings)
25 siblings, 1 reply; 66+ messages in thread
From: Khushit Shah @ 2026-09-21 12:32 UTC (permalink / raw)
To: qemu-devel, qemu-arm, kvmarm, eric.auger
Cc: cohuck, peter.maydell, richard.henderson, maz, oliver.upton,
berrange, abologna, jdenemar, gshan, skolothumtho, sebott, armbru,
philmd, yangjinqian1, shaju.abraham, mark.caveayland,
khushit.shah, ping, sandesh.patel
When QEMU queries the host ISAR via KVM, it uses a scratch vCPU
initialized with all host-supported features (like SVE and PAuth).
KVM exposes the corresponding ID register fields (e.g.,
ID_AA64ISAR1_EL1.APA) as read-only. The supported-values list only
shows the enabled host value (e.g., 5). This falsely flags a model as
blocked, even though the features can be masked by omitting those flags
during vCPU initialization. For these fields, even if KVM reports them as
non-writable, we explicitly append "0" to the list of supported values
if the host value is non-zero.
Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
---
target/arm/kvm.c | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index 77b1bcdf55..0b5fb49dff 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -1346,6 +1346,24 @@ static void ranges_add(GArray *ranges, uint64_t min, uint64_t max)
g_array_append_val(ranges, r);
}
+/*
+ * Some fields are reported as non-writable by KVM but can still be
+ * disabled by not requesting the corresponding vCPU init feature flag
+ * (SVE, pauth). The supported values are derived from a scratch vCPU
+ * whose init flags may differ from the real vCPU, so for these fields
+ * "off" (0) is a supported value in addition to the host value.
+ */
+static bool kvm_arm_field_off_via_vcpu_flags(const ARM64SysRegField *field)
+{
+ return field_matches(field, ID_AA64PFR0_EL1_IDX, "SVE") ||
+ field_matches(field, ID_AA64ISAR1_EL1_IDX, "APA") ||
+ field_matches(field, ID_AA64ISAR1_EL1_IDX, "API") ||
+ field_matches(field, ID_AA64ISAR1_EL1_IDX, "GPA") ||
+ field_matches(field, ID_AA64ISAR1_EL1_IDX, "GPI") ||
+ field_matches(field, ID_AA64ISAR2_EL1_IDX, "APA3") ||
+ field_matches(field, ID_AA64ISAR2_EL1_IDX, "GPA3");
+}
+
void kvm_arm_field_get_supported_values(const ARM64SysRegField *field,
const ARMISARegisters *host_isar,
ArmFieldValueSet **value_set)
@@ -1358,6 +1376,13 @@ void kvm_arm_field_get_supported_values(const ARM64SysRegField *field,
/* A non-writable field can only ever hold the host value. */
if (!arm_field_is_writable(field)) {
ranges_add(ranges, host, host);
+ /*
+ * ...unless it is one of the fields that can still be turned off
+ * via vCPU init flags, in which case "off" (0) is also supported.
+ */
+ if (host != 0 && kvm_arm_field_off_via_vcpu_flags(field)) {
+ ranges_add(ranges, 0, 0);
+ }
goto done;
}
--
2.52.0
^ permalink raw reply related [flat|nested] 66+ messages in thread
* [RFC PATCH v4 22/25] target/arm/kvm: add kvm_arm_get_host_isar helper
2026-09-21 12:32 [RFC PATCH v4 00/25] named CPU models for Arm64 on KVM Khushit Shah
` (20 preceding siblings ...)
2026-09-21 12:32 ` [RFC PATCH v4 21/25] target/arm: report 0 as supported for ID fields gated by vCPU init flags Khushit Shah
@ 2026-09-21 12:32 ` Khushit Shah
2026-09-29 15:02 ` Philippe Mathieu-Daudé
2026-09-21 12:32 ` [RFC PATCH v4 23/25] qmp: add query-cpu-props-info command Khushit Shah
` (3 subsequent siblings)
25 siblings, 1 reply; 66+ messages in thread
From: Khushit Shah @ 2026-09-21 12:32 UTC (permalink / raw)
To: qemu-devel, qemu-arm, kvmarm, eric.auger
Cc: cohuck, peter.maydell, richard.henderson, maz, oliver.upton,
berrange, abologna, jdenemar, gshan, skolothumtho, sebott, armbru,
philmd, yangjinqian1, shaju.abraham, mark.caveayland,
khushit.shah, ping, sandesh.patel
Introduce kvm_arm_get_host_isar() to provide the host ISAR probed through
a scratch vCPU. It will be needed by later commits.
Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
---
target/arm/kvm-stub.c | 5 +++++
target/arm/kvm.c | 8 ++++++++
target/arm/kvm_arm.h | 4 ++++
3 files changed, 17 insertions(+)
diff --git a/target/arm/kvm-stub.c b/target/arm/kvm-stub.c
index c9cd47bf47..059a7afdcb 100644
--- a/target/arm/kvm-stub.c
+++ b/target/arm/kvm-stub.c
@@ -151,3 +151,8 @@ void kvm_arm_field_get_supported_values(const ARM64SysRegField *field,
{
g_assert_not_reached();
}
+
+const ARMISARegisters *kvm_arm_get_host_isar(void)
+{
+ return NULL;
+}
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index 0b5fb49dff..bb74f8c274 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -712,6 +712,14 @@ void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu)
env->features = arm_host_cpu_features.features;
}
+const ARMISARegisters *kvm_arm_get_host_isar(void)
+{
+ if (!arm_host_cpu_features.dtb_compatible) {
+ kvm_arm_get_host_cpu_features(&arm_host_cpu_features);
+ }
+ return &arm_host_cpu_features.isar;
+}
+
static bool kvm_no_adjvtime_get(Object *obj, Error **errp)
{
return !ARM_CPU(obj)->kvm_adjvtime;
diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h
index 9481e56412..ab01ce8665 100644
--- a/target/arm/kvm_arm.h
+++ b/target/arm/kvm_arm.h
@@ -15,6 +15,8 @@
#include "system/kvm.h"
#include "target/arm/cpu-qom.h"
+typedef struct ARMISARegisters ARMISARegisters;
+
#define KVM_ARM_VGIC_V2 (1 << 0)
#define KVM_ARM_VGIC_V3 (1 << 1)
@@ -290,6 +292,8 @@ void kvm_arm_enable_mte(Object *cpuobj, Error **errp);
void arm_cpu_kvm_set_irq(void *arm_cpu, int irq, int level);
+const ARMISARegisters *kvm_arm_get_host_isar(void);
+
void arm_gic_cap_kvm_probe(GICCapability *v2, GICCapability *v3);
/*
--
2.52.0
^ permalink raw reply related [flat|nested] 66+ messages in thread
* [RFC PATCH v4 23/25] qmp: add query-cpu-props-info command
2026-09-21 12:32 [RFC PATCH v4 00/25] named CPU models for Arm64 on KVM Khushit Shah
` (21 preceding siblings ...)
2026-09-21 12:32 ` [RFC PATCH v4 22/25] target/arm/kvm: add kvm_arm_get_host_isar helper Khushit Shah
@ 2026-09-21 12:32 ` Khushit Shah
2026-10-15 14:20 ` Eric Auger
2026-09-21 12:32 ` [RFC PATCH v4 24/25] target/arm/qmp: implement query-cpu-props-info for KVM Khushit Shah
` (2 subsequent siblings)
25 siblings, 1 reply; 66+ messages in thread
From: Khushit Shah @ 2026-09-21 12:32 UTC (permalink / raw)
To: qemu-devel, qemu-arm, kvmarm, eric.auger
Cc: cohuck, peter.maydell, richard.henderson, maz, oliver.upton,
berrange, abologna, jdenemar, gshan, skolothumtho, sebott, armbru,
philmd, yangjinqian1, shaju.abraham, mark.caveayland,
khushit.shah, ping, sandesh.patel
Introduce the 'query-cpu-props-info' QMP command. For each CPU model
property, it reports the type (boolean or number) and the set of values
supported under the active accelerator and host.
This helps the management stack to discover which values are supported
for a given CPU property. This is especially important for non-boolean
properties, where knowing that the host has value 'x' does not
inherently reveal the full range of valid values supported on the host.
For example, an Arm host with CTR_EL0.L1Ip=3 (PIPT) also allows 2
(VIPT) but a host with CTR_EL0.L1Ip=2 does not allow CTR_EL0.L1Ip=3
for a guest.
For numerical properties, the supported values are expressed as a list
of inclusive {min, max} ranges. For boolean properties, they are
represented as a list of true/false values.
The command and its return types (CpuPropertyType, CpuPropertyInfo and
friends) are defined in qapi/machine.json rather than an Arm-specific
schema, since the concept applies to other targets (e.g. x86, RISC-V)
too. Targets that do not implement it return an error.
(The following commit implements the command for Arm KVM.)
Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
---
qapi/machine.json | 82 ++++++++++++++++++++++++++++++++++++++
stubs/meson.build | 1 +
stubs/qmp-cpu-props-info.c | 12 ++++++
tests/qtest/qmp-cmd-test.c | 1 +
4 files changed, 96 insertions(+)
create mode 100644 stubs/qmp-cpu-props-info.c
diff --git a/qapi/machine.json b/qapi/machine.json
index 2d63c1bac3..6e65bdad86 100644
--- a/qapi/machine.json
+++ b/qapi/machine.json
@@ -2291,3 +2291,85 @@
# Since: 1.2
##
{ 'command': 'query-cpu-definitions', 'returns': ['CpuDefinitionInfo'] }
+
+##
+# @CpuPropertyType:
+#
+# The type of a CPU model property.
+#
+# @boolean: the property is of type boolean.
+#
+# @number: the property is of type unsigned integer.
+#
+# Since: 11.2
+##
+{ 'enum': 'CpuPropertyType',
+ 'data': [ 'boolean', 'number' ] }
+
+##
+# @CpuPropertyValueRange:
+#
+# An inclusive range of numeric values supported for the property.
+#
+# @min: the lowest supported value.
+#
+# @max: the highest supported value.
+#
+# Since: 11.2
+##
+{ 'struct': 'CpuPropertyValueRange',
+ 'data': { 'min': 'uint64', 'max': 'uint64' } }
+
+##
+# @CpuPropertyInfoBoolean:
+#
+# @supported-values: list of boolean values supported for the
+# property.
+#
+# Since: 11.2
+##
+{ 'struct': 'CpuPropertyInfoBoolean',
+ 'data': { 'supported-values': ['bool'] } }
+
+##
+# @CpuPropertyInfoNumber:
+#
+# @supported-values: list of numeric value ranges supported
+# for the property.
+#
+# Since: 11.2
+##
+{ 'struct': 'CpuPropertyInfoNumber',
+ 'data': { 'supported-values': ['CpuPropertyValueRange'] } }
+
+##
+# @CpuPropertyInfo:
+#
+# Information about a single CPU model property, including the values
+# the host/accelerator supports for it.
+#
+# @name: the name of the property.
+#
+# @type: the type of the property, which selects the layout of
+# @supported-values.
+#
+# Since: 11.2
+##
+{ 'union': 'CpuPropertyInfo',
+ 'base': { 'name': 'str',
+ 'type': 'CpuPropertyType' },
+ 'discriminator': 'type',
+ 'data': { 'boolean': 'CpuPropertyInfoBoolean',
+ 'number': 'CpuPropertyInfoNumber' } }
+
+##
+# @query-cpu-props-info:
+#
+# Return information about the CPU model properties. For each
+# property it reports the values supported under the active
+# accelerator and host.
+#
+# Since: 11.2
+##
+{ 'command': 'query-cpu-props-info',
+ 'returns': ['CpuPropertyInfo'] }
diff --git a/stubs/meson.build b/stubs/meson.build
index 3b2f2680b1..3bb4028bab 100644
--- a/stubs/meson.build
+++ b/stubs/meson.build
@@ -83,6 +83,7 @@ if have_system
stub_ss.add(files('qmp-i386-sgx.c'))
stub_ss.add(files('qmp-i386-xen.c'))
stub_ss.add(files('qmp-cpu.c'))
+ stub_ss.add(files('qmp-cpu-props-info.c'))
stub_ss.add(files('qmp-cpu-s390x.c'))
stub_ss.add(files('qmp-cpu-s390x-kvm.c'))
stub_ss.add(files('hmp-cmd-info_mem.c'))
diff --git a/stubs/qmp-cpu-props-info.c b/stubs/qmp-cpu-props-info.c
new file mode 100644
index 0000000000..36b0530b98
--- /dev/null
+++ b/stubs/qmp-cpu-props-info.c
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "qapi/qapi-commands-machine.h"
+
+CpuPropertyInfoList *
+qmp_query_cpu_props_info(Error **errp)
+{
+ error_setg(errp, "query-cpu-props-info not supported on this target");
+ return NULL;
+}
diff --git a/tests/qtest/qmp-cmd-test.c b/tests/qtest/qmp-cmd-test.c
index 279a8f5614..2c25dbd8cb 100644
--- a/tests/qtest/qmp-cmd-test.c
+++ b/tests/qtest/qmp-cmd-test.c
@@ -100,6 +100,7 @@ static bool query_is_ignored(const char *cmd)
"add-fd",
/* Success depends on target arch: */
"query-cpu-definitions", /* arm, i386, ppc, s390x */
+ "query-cpu-props-info", /* arm + kvm */
"query-gic-capabilities", /* arm */
"query-s390x-cpu-polarization", /* s390x */
/* Success depends on target-specific build configuration: */
--
2.52.0
^ permalink raw reply related [flat|nested] 66+ messages in thread
* [RFC PATCH v4 24/25] target/arm/qmp: implement query-cpu-props-info for KVM
2026-09-21 12:32 [RFC PATCH v4 00/25] named CPU models for Arm64 on KVM Khushit Shah
` (22 preceding siblings ...)
2026-09-21 12:32 ` [RFC PATCH v4 23/25] qmp: add query-cpu-props-info command Khushit Shah
@ 2026-09-21 12:32 ` Khushit Shah
2026-10-16 13:21 ` Eric Auger
2026-10-16 13:23 ` Eric Auger
2026-09-21 12:32 ` [RFC PATCH v4 25/25] target/arm/qmp: hook blockers in query-cpu-definitions Khushit Shah
2026-09-29 15:09 ` [RFC PATCH v4 00/25] named CPU models for Arm64 on KVM Philippe Mathieu-Daudé
25 siblings, 2 replies; 66+ messages in thread
From: Khushit Shah @ 2026-09-21 12:32 UTC (permalink / raw)
To: qemu-devel, qemu-arm, kvmarm, eric.auger
Cc: cohuck, peter.maydell, richard.henderson, maz, oliver.upton,
berrange, abologna, jdenemar, gshan, skolothumtho, sebott, armbru,
philmd, yangjinqian1, shaju.abraham, mark.caveayland,
khushit.shah, ping, sandesh.patel
Implement query-cpu-props-info for ARM64/KVM by creating and finalizing
a temporary "host" CPU object and then walking its QOM properties.
For numeric SYSREG_ properties, report the host-supported value ranges
computed by kvm_arm_field_get_supported_values(). For boolean
properties, report false as always supported and true as supported when
the QOM property value is true.
Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
---
target/arm/arm-qmp-cmds.c | 84 +++++++++++++++++++++++++++++++++++++++
1 file changed, 84 insertions(+)
diff --git a/target/arm/arm-qmp-cmds.c b/target/arm/arm-qmp-cmds.c
index 0940285af1..ba488d5c01 100644
--- a/target/arm/arm-qmp-cmds.c
+++ b/target/arm/arm-qmp-cmds.c
@@ -84,6 +84,90 @@ static const char *cpu_model_advertised_features[] = {
NULL
};
+CpuPropertyInfoList *qmp_query_cpu_props_info(Error **errp)
+{
+ CpuPropertyInfoList *head = NULL;
+ const ARMISARegisters *host_isar;
+ ObjectPropertyIterator iter;
+ ObjectProperty *prop;
+ Error *err = NULL;
+ ObjectClass *oc;
+ Object *obj;
+
+ if (!kvm_enabled()) {
+ error_setg(errp, "query-cpu-props-info requires KVM");
+ return NULL;
+ }
+
+ oc = cpu_class_by_name(TYPE_ARM_CPU, "host");
+ if (!oc) {
+ error_setg(errp, "The 'host' CPU type is not available");
+ return NULL;
+ }
+
+ host_isar = kvm_arm_get_host_isar();
+
+ /* Spin up a scratch "host" vCPU object and walk its QOM properties. */
+ obj = object_new_with_class(oc);
+ arm_cpu_finalize_features(ARM_CPU(obj), &err);
+ if (err) {
+ error_propagate(errp, err);
+ object_unref(obj);
+ return NULL;
+ }
+
+ object_property_iter_init(&iter, obj);
+ while ((prop = object_property_iter_next(&iter))) {
+ CpuPropertyInfo *info;
+
+ if (g_str_has_prefix(prop->name, "SYSREG_")) {
+ const ARM64SysRegField *field = prop->opaque;
+ CpuPropertyValueRangeList *ranges = NULL;
+ ArmFieldValueSet *vs = NULL;
+
+ info = g_new0(CpuPropertyInfo, 1);
+ info->name = g_strdup(prop->name);
+ info->type = CPU_PROPERTY_TYPE_NUMBER;
+
+ kvm_arm_field_get_supported_values(field, host_isar, &vs);
+ for (size_t k = 0; k < vs->n_ranges; k++) {
+ CpuPropertyValueRange *r = g_new0(CpuPropertyValueRange, 1);
+ r->min = vs->ranges[k].min;
+ r->max = vs->ranges[k].max;
+ QAPI_LIST_PREPEND(ranges, r);
+ }
+ info->u.number.supported_values = ranges;
+
+ g_free(vs->ranges);
+ g_free(vs);
+ } else if (g_strv_contains(cpu_model_advertised_features, prop->name)) {
+ bool cur = object_property_get_bool(obj, prop->name, &error_abort);
+ boolList *values = NULL;
+
+ info = g_new0(CpuPropertyInfo, 1);
+ info->name = g_strdup(prop->name);
+ info->type = CPU_PROPERTY_TYPE_BOOLEAN;
+
+ /*
+ * "off" is always supported. "on" is only supported when the
+ * host already has the feature enabled.
+ */
+ QAPI_LIST_PREPEND(values, false);
+ if (cur) {
+ QAPI_LIST_PREPEND(values, true);
+ }
+ info->u.boolean.supported_values = values;
+ } else {
+ continue;
+ }
+
+ QAPI_LIST_PREPEND(head, info);
+ }
+
+ object_unref(obj);
+ return head;
+}
+
CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type,
CpuModelInfo *model,
Error **errp)
--
2.52.0
^ permalink raw reply related [flat|nested] 66+ messages in thread
* [RFC PATCH v4 25/25] target/arm/qmp: hook blockers in query-cpu-definitions
2026-09-21 12:32 [RFC PATCH v4 00/25] named CPU models for Arm64 on KVM Khushit Shah
` (23 preceding siblings ...)
2026-09-21 12:32 ` [RFC PATCH v4 24/25] target/arm/qmp: implement query-cpu-props-info for KVM Khushit Shah
@ 2026-09-21 12:32 ` Khushit Shah
2026-10-16 13:54 ` Eric Auger
2026-09-29 15:09 ` [RFC PATCH v4 00/25] named CPU models for Arm64 on KVM Philippe Mathieu-Daudé
25 siblings, 1 reply; 66+ messages in thread
From: Khushit Shah @ 2026-09-21 12:32 UTC (permalink / raw)
To: qemu-devel, qemu-arm, kvmarm, eric.auger
Cc: cohuck, peter.maydell, richard.henderson, maz, oliver.upton,
berrange, abologna, jdenemar, gshan, skolothumtho, sebott, armbru,
philmd, yangjinqian1, shaju.abraham, mark.caveayland,
khushit.shah, ping, sandesh.patel
Report blockers for named CPU models in query-cpu-definitions.
Efficiently do this by validating the realized ID register values
against the host values. sveNNNN properties need special handling
because they are not stored in ID registers.
This way, we need not instantiate each model to check if it can be
realized on the host, and we also get granular information about the ID
register fields blocking realization.
Introduce arm_cpu_class_check_missing_features() and
kvm_arm_idregs_get_blockers() to achieve this.
Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
---
target/arm/arm-qmp-cmds.c | 12 +++++++++
target/arm/cpu-models-stub.c | 5 ++++
target/arm/cpu-models.c | 35 +++++++++++++++++++++++++
target/arm/cpu-models.h | 2 ++
target/arm/kvm.c | 50 ++++++++++++++++++++++++++++++++++++
target/arm/kvm_arm.h | 13 ++++++++++
6 files changed, 117 insertions(+)
diff --git a/target/arm/arm-qmp-cmds.c b/target/arm/arm-qmp-cmds.c
index ba488d5c01..d837ec6653 100644
--- a/target/arm/arm-qmp-cmds.c
+++ b/target/arm/arm-qmp-cmds.c
@@ -379,6 +379,18 @@ static void arm_cpu_add_definition(gpointer data, gpointer user_data)
info->name = cpu_model_from_type(typename);
info->q_typename = g_strdup(typename);
+ /* calculate blockers */
+ if (kvm_enabled()
+ && !g_str_equal(info->name, "host")
+ && !g_str_equal(info->name, "max")
+ && arm_find_model(info->name) != NULL) {
+ arm_cpu_class_check_missing_features(ARM_CPU_CLASS(oc),
+ &info->unavailable_features);
+ if (info->unavailable_features) {
+ info->has_unavailable_features = true;
+ }
+ }
+
QAPI_LIST_PREPEND(*cpu_list, info);
}
diff --git a/target/arm/cpu-models-stub.c b/target/arm/cpu-models-stub.c
index 48f712d648..2d1be49e0a 100644
--- a/target/arm/cpu-models-stub.c
+++ b/target/arm/cpu-models-stub.c
@@ -11,3 +11,8 @@ const ArmNamedCpuModel *arm_find_model(const char *name)
{
return NULL;
}
+
+void arm_cpu_class_check_missing_features(ARMCPUClass *acc, strList **blockers)
+{
+ return;
+}
diff --git a/target/arm/cpu-models.c b/target/arm/cpu-models.c
index 855eb5ee6b..9591b6dbfc 100644
--- a/target/arm/cpu-models.c
+++ b/target/arm/cpu-models.c
@@ -477,6 +477,41 @@ static void arm_named_cpu_initfn(Object *obj)
arm_named_cpu_zero_unknown_feature_ids(cpu, &error_abort);
}
+void arm_cpu_class_check_missing_features(ARMCPUClass *acc, strList **blockers)
+{
+ Error *err = NULL;
+ Object *obj = object_new_with_class(OBJECT_CLASS(acc));
+ ARMCPU *cpu = ARM_CPU(obj);
+
+ if (!kvm_enabled() || !arm_find_model(acc->info->name)) {
+ goto out;
+ }
+
+ if (cpu_isar_feature(aa64_sve, cpu)) {
+ aarch64_cpu_sve_finalize(cpu, &err);
+ if (err) {
+ error_free(err);
+ err = NULL;
+ uint32_t host_vq_map = cpu->sve_vq.supported;
+ uint32_t model_vq_map = cpu->sve_vq.map;
+
+ if ((model_vq_map & host_vq_map) != model_vq_map) {
+ for (int vq = 1; vq <= ARM_MAX_VQ; vq++) {
+ uint32_t vq_bit = (1 << (vq - 1));
+ if ((model_vq_map & vq_bit) && !(host_vq_map & vq_bit)) {
+ QAPI_LIST_PREPEND(*blockers,
+ g_strdup_printf("sve%d", vq * 128));
+ }
+ }
+ }
+ }
+ }
+
+ kvm_arm_idregs_get_blockers(cpu, kvm_arm_get_host_isar(), blockers);
+out:
+ object_unref(obj);
+}
+
void arm_register_named_cpu_models(void)
{
static ARMCPUInfo *arm_named_cpu_infos;
diff --git a/target/arm/cpu-models.h b/target/arm/cpu-models.h
index 144778744e..41bb15d928 100644
--- a/target/arm/cpu-models.h
+++ b/target/arm/cpu-models.h
@@ -4,6 +4,7 @@
#include "qapi/error.h"
#include "qom/object.h"
+#include "cpu.h"
typedef enum ArmModelPropType {
ARM_MODEL_PROP_BOOL,
@@ -32,5 +33,6 @@ void arm_apply_model_props(Object *obj, const ArmModelPropValue *props,
Error **errp);
void arm_realize_model_chain(Object *obj, const ArmNamedCpuModel *model,
Error **errp);
+void arm_cpu_class_check_missing_features(ARMCPUClass *acc, strList **blockers);
#endif /* ARM_CPU_MODELS_H */
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index bb74f8c274..ca3da80262 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -1485,6 +1485,56 @@ arm_field_skip_writeback_if_not_writable(const ARM64SysRegField *field)
return field_matches(field, ID_DFR0_EL1_IDX, "PerfMon");
}
+void kvm_arm_idregs_get_blockers(ARMCPU *cpu,
+ const ARMISARegisters *host_isar,
+ strList **blockers)
+{
+ for (int i = 0; i < NUM_ID_IDX; i++) {
+ ARM64SysReg *reg = &arm64_id_regs[i];
+
+ if (!reg->name) {
+ continue;
+ }
+
+ for (uint32_t j = 0; j < reg->fields_count; j++) {
+ const ARM64SysRegField *field = ®->fields[j];
+ ArmFieldValueSet *vs = NULL;
+ bool supported = false;
+ uint64_t model_val;
+
+ /* Not a blocker if the field is never written back to KVM. */
+ if (arm_field_skip_writeback_always(field) ||
+ (!arm_field_is_writable(field) &&
+ arm_field_skip_writeback_if_not_writable(field))) {
+ continue;
+ }
+
+ model_val = extract64(cpu->isar.idregs[field->index],
+ field->shift, field->length);
+
+ /*
+ * If the field is written back, make sure a "supported" value
+ * is requested.
+ */
+ kvm_arm_field_get_supported_values(field, host_isar, &vs);
+ for (size_t k = 0; k < vs->n_ranges; k++) {
+ if (model_val >= vs->ranges[k].min &&
+ model_val <= vs->ranges[k].max) {
+ supported = true;
+ break;
+ }
+ }
+ g_free(vs->ranges);
+ g_free(vs);
+
+ if (!supported) {
+ QAPI_LIST_PREPEND(*blockers,
+ g_strdup_printf("SYSREG_%s_%s", reg->name, field->name));
+ }
+ }
+ }
+}
+
/*
* Copy writable ID reg fields from isar.idregs[] into the KVM cpreg list,
* so the subsequent write_list_to_kvmstate() pushes them to KVM.
diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h
index ab01ce8665..59832d8063 100644
--- a/target/arm/kvm_arm.h
+++ b/target/arm/kvm_arm.h
@@ -205,6 +205,19 @@ void kvm_arm_field_get_supported_values(const ARM64SysRegField *field,
const ARMISARegisters *host_isar,
ArmFieldValueSet **value_set);
+/**
+ * kvm_arm_idregs_get_blockers:
+ * @cpu: ARMCPU
+ * @host_isar: The host ISAR registers
+ * @blockers: The list of blockers
+ *
+ * Get the list of "blockers" in @cpu's idregs state for the given
+ * @host_isar.
+ */
+void kvm_arm_idregs_get_blockers(ARMCPU *cpu,
+ const ARMISARegisters *host_isar,
+ strList **blockers);
+
/**
* kvm_arm_steal_time_finalize:
* @cpu: ARMCPU for which to finalize kvm-steal-time
--
2.52.0
^ permalink raw reply related [flat|nested] 66+ messages in thread
* Re: [RFC PATCH v4 01/25] target/arm: expose SYSREG_ props for REVIDR_EL1 and AIDR_EL1
2026-09-21 12:32 ` [RFC PATCH v4 01/25] target/arm: expose SYSREG_ props for REVIDR_EL1 and AIDR_EL1 Khushit Shah
@ 2026-09-23 16:22 ` Eric Auger
2026-09-29 12:54 ` Khushit Shah
0 siblings, 1 reply; 66+ messages in thread
From: Eric Auger @ 2026-09-23 16:22 UTC (permalink / raw)
To: Khushit Shah, qemu-devel, qemu-arm, kvmarm
Cc: cohuck, peter.maydell, richard.henderson, maz, oliver.upton,
berrange, abologna, jdenemar, gshan, skolothumtho, sebott, armbru,
philmd, yangjinqian1, shaju.abraham, mark.caveayland, ping,
sandesh.patel
Hi Khushit,
On 9/21/26 2:32 PM, Khushit Shah wrote:
> REVIDR_EL1 and AIDR_EL1 are implementation-defined and have no named
> fields in Registers.json.
>
> Emit dummy VAL fields covering the full register for these registers
> in scripts/update-aarch64-cpu-sysreg-properties.py, then remove the
> special case for these in kvm_arm_expose_idreg_properties(), exposing
> them as SYSREG_ props.
>
> Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
> ---
> scripts/update-aarch64-cpu-sysreg-properties.py | 9 +++++++++
> target/arm/cpu-idregs.h.inc | 2 ++
> target/arm/kvm.c | 10 +---------
> 3 files changed, 12 insertions(+), 9 deletions(-)
>
> diff --git a/scripts/update-aarch64-cpu-sysreg-properties.py b/scripts/update-aarch64-cpu-sysreg-properties.py
> index 0b4e4d3e0c..2269063408 100644
> --- a/scripts/update-aarch64-cpu-sysreg-properties.py
> +++ b/scripts/update-aarch64-cpu-sysreg-properties.py
> @@ -246,6 +246,15 @@ def generate_sysreg_properties_from_registers_json(id_reg_names, raw_json_path):
> # Sort decreasing lsbs
> sorted_fields = sorted(unique_fields.items(),
> key=lambda x: x[1]['lsb'], reverse=True)
> + if len(sorted_fields) == 0:
> + # For cases like REVIDR_EL1, add a dummy field covering the
> + # full register.
> + sorted_fields.append(('VAL', {
though I think it is important the property name stays SYSREG_REVIDR_EL1
and not SYSREG_REVIDR_EL1_VAL so I guess we need either a property alias
or a special handling for those regs (better as alias were not really
meant for that purpose I think).
Eric
> + 'lsb': 0,
> + 'msb': 63,
> + 'width': 64,
> + 'enums': []
> + }))
>
> for unique_key, bits in sorted_fields:
> enums_list = bits.get('enums', [])
> diff --git a/target/arm/cpu-idregs.h.inc b/target/arm/cpu-idregs.h.inc
> index c7e93c48b7..bc52112430 100644
> --- a/target/arm/cpu-idregs.h.inc
> +++ b/target/arm/cpu-idregs.h.inc
> @@ -12,6 +12,7 @@
> /* IDREG_END(REG) */
>
> IDREG_START(AIDR_EL1)
> + IDREG_FIELD(AIDR_EL1, VAL, 0, 64)
> IDREG_END(AIDR_EL1)
>
> IDREG_START(CLIDR_EL1)
> @@ -2438,6 +2439,7 @@ IDREG_START(MVFR2_EL1)
> IDREG_END(MVFR2_EL1)
>
> IDREG_START(REVIDR_EL1)
> + IDREG_FIELD(REVIDR_EL1, VAL, 0, 64)
> IDREG_END(REVIDR_EL1)
>
> IDREG_START(SMIDR_EL1)
> diff --git a/target/arm/kvm.c b/target/arm/kvm.c
> index e3a0dc07de..8a823d0324 100644
> --- a/target/arm/kvm.c
> +++ b/target/arm/kvm.c
> @@ -554,15 +554,7 @@ void kvm_arm_expose_idreg_properties(ARMCPU *cpu, ARM64SysReg *regs)
> ARM64SysReg *sysregdesc = ®s[i];
>
> if (sysregdesc->writable_mask) {
> - /*
> - * special case REVIDR_EL1 and AIDR_EL1 which are writable but
> - * do not expose named fields. They will need to be handled
> - * separately
> - */
> - if (strcmp(sysregdesc->name, "REVIDR_EL1") &&
> - strcmp(sysregdesc->name, "AIDR_EL1")) {
> - decode_idreg_writemap(obj, sysregdesc);
> - }
> + decode_idreg_writemap(obj, sysregdesc);
> }
> }
> }
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH v4 02/25] target/arm: expose all non-res ID reg fields as properties
2026-09-21 12:32 ` [RFC PATCH v4 02/25] target/arm: expose all non-res ID reg fields as properties Khushit Shah
@ 2026-09-23 16:37 ` Eric Auger
2026-09-24 6:46 ` Eric Auger
1 sibling, 0 replies; 66+ messages in thread
From: Eric Auger @ 2026-09-23 16:37 UTC (permalink / raw)
To: Khushit Shah, qemu-devel, qemu-arm, kvmarm
Cc: cohuck, peter.maydell, richard.henderson, maz, oliver.upton,
berrange, abologna, jdenemar, gshan, skolothumtho, sebott, armbru,
philmd, yangjinqian1, shaju.abraham, mark.caveayland, ping,
sandesh.patel
On 9/21/26 2:32 PM, Khushit Shah wrote:
> Upcoming named CPU model layer will require exposing all the ID register
> fields as properties.
>
> Furthermore, this exposes the host values of all ID register fields
> to the management stack, which can use them to infer migration
> compatibility constraints between different hosts.
>
> Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
> ---
> docs/system/arm/cpu-features.rst | 34 +++++++--------
> target/arm/cpu64.c | 2 +-
> target/arm/kvm.c | 71 +++++++-------------------------
> target/arm/trace-events | 2 -
> 4 files changed, 31 insertions(+), 78 deletions(-)
>
> diff --git a/docs/system/arm/cpu-features.rst b/docs/system/arm/cpu-features.rst
> index 3a07a87bc3..62bb2bd999 100644
> --- a/docs/system/arm/cpu-features.rst
> +++ b/docs/system/arm/cpu-features.rst
> @@ -34,17 +34,15 @@ running guests in AArch32.
> CPU features that are inherently specific to KVM are
> prefixed with "kvm-" and are described in "KVM VCPU Features".
>
> -2. Additionally, the ``host`` CPU model on KVM allows to configure optional
> -CPU features via the corresponding ID registers. The host kernel allows
> -to write a subset of ID register fields. The host model exposes
Rewording/corrections not related to the actual functional change in
this patch should be suggested on the prerequisite series and applied
there instead.
Besides after our discussions I understand you need to expose all ID reg
named fields for *named* vcpu models. This allows to relax the value
required by this named vcpu model to the host one. but to me this shall
only apply to derived named cpu models and not to the base host model.
Iif you expose non writable props on the host model, this latter won't
be able to apply any other value than the current one anyway. So it just
brings noise for the end user.
> -properties for each writable ID register field. Those options are named
> -SYSREG_<IDREG>_<FIELD>. IDREG and FIELD names are those used in the
> -ARM Architecture Reference Manual. Their availability depend on the host
> -capability to let the userspace write those fields. Values set with those
> -properties override the initial values retrieved from the host. They are
> -written back to KVM and the eventual value applied by KVM depends on whether
> -the value is sanitized or not by the host kernel. Then those field values
> -are likely to be overriden again by legacy CPU options which apply at the end.
> +2. Additionally, the ``host`` CPU model on KVM allows configuring optional
> +CPU features through the corresponding ID registers. The host model exposes
> +properties for every non-reserved ID register field known to QEMU. Those
> +properties are named SYSREG_<IDREG>_<FIELD>. IDREG and FIELD names are those
> +used in the Arm Architecture Reference Manual. Values set with those
> +properties override the initial values retrieved from the host. Whether a
> +value that differs from the host value can be applied depends on KVM support
> +and any field-specific handling in QEMU. Legacy CPU options applied later may
> +override those field values.
>
> CPU Feature Probing
> ===================
> @@ -534,12 +532,10 @@ Note that this is currently only supported under KVM, and with the
> Querying available ID register fields
> -------------------------------------
>
> -QEMU will create properties for all ID register fields that are
> -reported as being writable by the kernel, and that are known to the
> -QEMU instance. Therefore, the same QEMU binary may expose different
> -properties when run under a different kernel.
> +QEMU creates properties for all non-reserved ID register fields known to
> +the QEMU instance.
>
> -To find out all available writable ID register fields, use the
> +To find out all available ID register fields, use the
> ``query-cpu-model-expansion`` QMP command::
>
> (QEMU) query-cpu-model-expansion type=full model={"name":"host"}
> @@ -554,8 +550,10 @@ To find out all available writable ID register fields, use the
> "SYSREG_ID_AA64ISAR0_EL1_DP": 1, (...)
> }}}}
>
> -If a certain field in an ID register does not show up in this list, it
> -is not writable with the specific host kernel.
> +The presence of a property does not imply that every value is supported.
> +Non-writable fields must retain their host value, while writable fields are
> +limited to the values supported by KVM. A configuration requesting an
> +unsupported value is rejected.
>
> A note on compatibility
> -----------------------
> diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
> index e04062e848..3d522bf20d 100644
> --- a/target/arm/cpu64.c
> +++ b/target/arm/cpu64.c
> @@ -809,7 +809,7 @@ void aarch64_host_initfn(Object *obj)
> kvm_arm_set_cpu_features_from_host(cpu);
> aarch64_add_sve_properties(obj);
>
> - /* generate SYSREG properties according to writable masks */
> + /* generate SYSREG properties */
> kvm_arm_expose_idreg_properties(cpu, arm64_id_regs);
To me exposing non writable fields shall only happen for derived named
models.
>
> #elif defined(CONFIG_HVF)
> diff --git a/target/arm/kvm.c b/target/arm/kvm.c
> index 8a823d0324..2f6c090e43 100644
> --- a/target/arm/kvm.c
> +++ b/target/arm/kvm.c
> @@ -365,19 +365,6 @@ static int get_host_cpu_idregs(int fd, ARMHostCPUFeatures *ahcf)
> return err;
> }
>
> -static ARM64SysRegField *get_field(int i, ARM64SysReg *reg)
> -{
> - for (int f = 0; f < reg->fields_count; f++) {
> - struct ARM64SysRegField *field = ®->fields[f];
> - int upper = field->shift + field->length - 1;
> -
> - if (i >= field->shift && i <= upper) {
> - return field;
> - }
> - }
> - return NULL;
> -}
> -
> bool kvm_idreg_write_scratch_vcpu(int cpufd, Visitor *v, const char *name,
> void *opaque, Error **errp)
> {
> @@ -493,69 +480,39 @@ static void get_sysreg_prop(Object *obj, Visitor *v,
> trace_get_sysreg_prop(name, value);
> }
>
> -/*
> - * decode_idreg_writemap: Generate props for writable fields
> - *
> - * @obj: CPU object
> - * @reg: description of the sysreg
> - */
> -static int
> -decode_idreg_writemap(Object *obj, ARM64SysReg *reg)
> +static void
> +add_idreg_field_properties(Object *obj, ARM64SysReg *reg)
> {
> - uint64_t map = reg->writable_mask;
> - int i = ctz64(map);
> int nb_sysreg_props = 0;
>
> - while (map) {
> - ARM64SysRegField *field = get_field(i, reg);
Same here. If changes are not related to the functional change, the
right way to converge is to comment on the prerequisite series.
As I understand those changes are unrelated and can easily be retrofitted
> - int lower, upper;
> - char *prop_name;
> - uint64_t field_mask;
> -
> - if (!field) {
> - warn_report("%s bit %d of %s is writable but no named field "
> - "in target/arm/cpu-idregs.h.inc",
> - __func__, i, reg->name);
> - map = map & ~BIT_ULL(i);
> - i = ctz64(map);
> - continue;
> - }
> - lower = field->shift;
> - upper = field->shift + field->length - 1;
> -
> - /* Sanity check the field is not a reserved field */
> - if (strstr(field->name, "RES0") || strstr(field->name, "RES1") ||
> - strstr(field->name, "RAZ")) {
> - trace_unexpected_writable_reserved_field(reg->name, field->name,
> - lower, upper);
> + for (int i = 0; i < reg->fields_count; i++) {
> + ARM64SysRegField *field = ®->fields[i];
> +
> + /* skip reserved fields */
> + if (g_str_equal(field->name, "RES0") ||
> + g_str_equal(field->name, "RES1") ||
> + g_str_equal(field->name, "RAZ")) {
> continue;
> }
> - prop_name = g_strdup_printf("SYSREG_%s_%s", reg->name, field->name);
> - trace_decode_idreg_writemap(field->name, lower, upper, prop_name);
> +
> + char *prop_name = g_strdup_printf("SYSREG_%s_%s", reg->name,
> + field->name);
> object_property_add(obj, prop_name, "uint64",
> get_sysreg_prop, set_sysreg_prop, NULL, field);
> g_free(prop_name);
> nb_sysreg_props++;
> -
> - field_mask = MAKE_64BIT_MASK(lower, field->length);
> - map = map & ~field_mask;
> - i = ctz64(map);
> }
> +
> trace_nb_sysreg_props(reg->name, nb_sysreg_props);
> - return 0;
> }
>
> -/* analyze the writable mask and generate properties for writable fields */
> void kvm_arm_expose_idreg_properties(ARMCPU *cpu, ARM64SysReg *regs)
> {
> Object *obj = OBJECT(cpu);
>
> for (int i = 0; i < NUM_ID_IDX; i++) {
> ARM64SysReg *sysregdesc = ®s[i];
> -
> - if (sysregdesc->writable_mask) {
> - decode_idreg_writemap(obj, sysregdesc);
> - }
> + add_idreg_field_properties(obj, sysregdesc);
> }
> }
>
> diff --git a/target/arm/trace-events b/target/arm/trace-events
> index 71a2f5770c..7696a8ed40 100644
> --- a/target/arm/trace-events
> +++ b/target/arm/trace-events
> @@ -15,11 +15,9 @@ arm_gt_update_irq(int timer, int irqstate) "gt_update_irq: timer %d irqstate %d"
> kvm_arm_fixup_msi_route(uint64_t iova, uint64_t gpa) "MSI iova = 0x%"PRIx64" is translated into 0x%"PRIx64
> get_host_cpu_idregs(const char *name, uint64_t value) "scratch vcpu host value for %s is 0x%"PRIx64
> kvm_arm_writable_idregs_to_cpreg_list(const char *name, uint64_t previous, uint64_t new) "%s overwrite default 0x%"PRIx64" with 0x%"PRIx64
> -decode_idreg_writemap(const char* name, int lower, int upper, char *prop_name) "%s [%d:%d] is writable (prop %s)"
> get_sysreg_prop(const char *name, uint64_t value) "%s 0x%"PRIx64
> set_sysreg_prop(const char *name, uint64_t old, uint64_t mask, uint64_t field_value, uint64_t new) "%s old reg value=0x%"PRIx64" mask=0x%"PRIx64" new field value=0x%"PRIx64" new reg value=0x%"PRIx64
> nb_sysreg_props(const char *name, int count) "%s: %d SYSREG properties"
> -unexpected_writable_reserved_field(const char *reg_name, const char *field_name, int lower, int upper) "Unexpected writable reserved field: %s.%s [%d,%d], skip it ..."
why those removals
> kvm_idreg_write_scratch_vcpu(const char *name, uint64_t oldfv, uint64_t newfv, uint64_t actualfv) "successful dry-run for %s old=0x%"PRIx64" new=0x%"PRIx64" actual=0x%"PRIx64
>
> # cpu.c
Eric
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH v4 02/25] target/arm: expose all non-res ID reg fields as properties
2026-09-21 12:32 ` [RFC PATCH v4 02/25] target/arm: expose all non-res ID reg fields as properties Khushit Shah
2026-09-23 16:37 ` Eric Auger
@ 2026-09-24 6:46 ` Eric Auger
2026-09-29 12:55 ` Khushit Shah
1 sibling, 1 reply; 66+ messages in thread
From: Eric Auger @ 2026-09-24 6:46 UTC (permalink / raw)
To: Khushit Shah, qemu-devel, qemu-arm, kvmarm
Cc: cohuck, peter.maydell, richard.henderson, maz, oliver.upton,
berrange, abologna, jdenemar, gshan, skolothumtho, sebott, armbru,
philmd, yangjinqian1, shaju.abraham, mark.caveayland, ping,
sandesh.patel
On 9/21/26 2:32 PM, Khushit Shah wrote:
> Upcoming named CPU model layer will require exposing all the ID register
> fields as properties.
>
> Furthermore, this exposes the host values of all ID register fields
> to the management stack, which can use them to infer migration
> compatibility constraints between different hosts.
>
> Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
> ---
> docs/system/arm/cpu-features.rst | 34 +++++++--------
> target/arm/cpu64.c | 2 +-
> target/arm/kvm.c | 71 +++++++-------------------------
> target/arm/trace-events | 2 -
> 4 files changed, 31 insertions(+), 78 deletions(-)
>
> diff --git a/docs/system/arm/cpu-features.rst b/docs/system/arm/cpu-features.rst
> index 3a07a87bc3..62bb2bd999 100644
> --- a/docs/system/arm/cpu-features.rst
> +++ b/docs/system/arm/cpu-features.rst
> @@ -34,17 +34,15 @@ running guests in AArch32.
> CPU features that are inherently specific to KVM are
> prefixed with "kvm-" and are described in "KVM VCPU Features".
>
> -2. Additionally, the ``host`` CPU model on KVM allows to configure optional
> -CPU features via the corresponding ID registers. The host kernel allows
> -to write a subset of ID register fields. The host model exposes
> -properties for each writable ID register field. Those options are named
> -SYSREG_<IDREG>_<FIELD>. IDREG and FIELD names are those used in the
> -ARM Architecture Reference Manual. Their availability depend on the host
> -capability to let the userspace write those fields. Values set with those
> -properties override the initial values retrieved from the host. They are
> -written back to KVM and the eventual value applied by KVM depends on whether
> -the value is sanitized or not by the host kernel. Then those field values
> -are likely to be overriden again by legacy CPU options which apply at the end.
> +2. Additionally, the ``host`` CPU model on KVM allows configuring optional
> +CPU features through the corresponding ID registers. The host model exposes
> +properties for every non-reserved ID register field known to QEMU. Those
> +properties are named SYSREG_<IDREG>_<FIELD>. IDREG and FIELD names are those
> +used in the Arm Architecture Reference Manual. Values set with those
> +properties override the initial values retrieved from the host. Whether a
> +value that differs from the host value can be applied depends on KVM support
> +and any field-specific handling in QEMU. Legacy CPU options applied later may
> +override those field values.
>
> CPU Feature Probing
> ===================
> @@ -534,12 +532,10 @@ Note that this is currently only supported under KVM, and with the
> Querying available ID register fields
> -------------------------------------
>
> -QEMU will create properties for all ID register fields that are
> -reported as being writable by the kernel, and that are known to the
> -QEMU instance. Therefore, the same QEMU binary may expose different
> -properties when run under a different kernel.
> +QEMU creates properties for all non-reserved ID register fields known to
> +the QEMU instance.
>
> -To find out all available writable ID register fields, use the
> +To find out all available ID register fields, use the
> ``query-cpu-model-expansion`` QMP command::
>
> (QEMU) query-cpu-model-expansion type=full model={"name":"host"}
> @@ -554,8 +550,10 @@ To find out all available writable ID register fields, use the
> "SYSREG_ID_AA64ISAR0_EL1_DP": 1, (...)
> }}}}
>
> -If a certain field in an ID register does not show up in this list, it
> -is not writable with the specific host kernel.
> +The presence of a property does not imply that every value is supported.
> +Non-writable fields must retain their host value, while writable fields are
> +limited to the values supported by KVM. A configuration requesting an
> +unsupported value is rejected.
>
> A note on compatibility
> -----------------------
> diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
> index e04062e848..3d522bf20d 100644
> --- a/target/arm/cpu64.c
> +++ b/target/arm/cpu64.c
> @@ -809,7 +809,7 @@ void aarch64_host_initfn(Object *obj)
> kvm_arm_set_cpu_features_from_host(cpu);
> aarch64_add_sve_properties(obj);
>
> - /* generate SYSREG properties according to writable masks */
> + /* generate SYSREG properties */
> kvm_arm_expose_idreg_properties(cpu, arm64_id_regs);
>
> #elif defined(CONFIG_HVF)
> diff --git a/target/arm/kvm.c b/target/arm/kvm.c
> index 8a823d0324..2f6c090e43 100644
> --- a/target/arm/kvm.c
> +++ b/target/arm/kvm.c
> @@ -365,19 +365,6 @@ static int get_host_cpu_idregs(int fd, ARMHostCPUFeatures *ahcf)
> return err;
> }
>
> -static ARM64SysRegField *get_field(int i, ARM64SysReg *reg)
> -{
> - for (int f = 0; f < reg->fields_count; f++) {
> - struct ARM64SysRegField *field = ®->fields[f];
> - int upper = field->shift + field->length - 1;
> -
> - if (i >= field->shift && i <= upper) {
> - return field;
> - }
> - }
> - return NULL;
> -}
> -
> bool kvm_idreg_write_scratch_vcpu(int cpufd, Visitor *v, const char *name,
> void *opaque, Error **errp)
> {
> @@ -493,69 +480,39 @@ static void get_sysreg_prop(Object *obj, Visitor *v,
> trace_get_sysreg_prop(name, value);
> }
>
> -/*
> - * decode_idreg_writemap: Generate props for writable fields
> - *
> - * @obj: CPU object
> - * @reg: description of the sysreg
> - */
> -static int
> -decode_idreg_writemap(Object *obj, ARM64SysReg *reg)
> +static void
> +add_idreg_field_properties(Object *obj, ARM64SysReg *reg)
> {
> - uint64_t map = reg->writable_mask;
> - int i = ctz64(map);
> int nb_sysreg_props = 0;
>
> - while (map) {
> - ARM64SysRegField *field = get_field(i, reg);
> - int lower, upper;
> - char *prop_name;
> - uint64_t field_mask;
> -
> - if (!field) {
> - warn_report("%s bit %d of %s is writable but no named field "
> - "in target/arm/cpu-idregs.h.inc",
> - __func__, i, reg->name);
> - map = map & ~BIT_ULL(i);
> - i = ctz64(map);
> - continue;
> - }
> - lower = field->shift;
> - upper = field->shift + field->length - 1;
> -
> - /* Sanity check the field is not a reserved field */
> - if (strstr(field->name, "RES0") || strstr(field->name, "RES1") ||
> - strstr(field->name, "RAZ")) {
> - trace_unexpected_writable_reserved_field(reg->name, field->name,
> - lower, upper);
> + for (int i = 0; i < reg->fields_count; i++) {
> + ARM64SysRegField *field = ®->fields[i];
I agree this implementation is simpler than mine scanning the writable
bitmask. I will move to that. I think I will add an other operating mode
that checks the writable_mask too. That way the function may be able to
generate props only for writable fields (including some consistency
checks), or for non writable fields
Thanks
Eric
> +
> + /* skip reserved fields */
> + if (g_str_equal(field->name, "RES0") ||
> + g_str_equal(field->name, "RES1") ||
> + g_str_equal(field->name, "RAZ")) {
> continue;
> }
> - prop_name = g_strdup_printf("SYSREG_%s_%s", reg->name, field->name);
> - trace_decode_idreg_writemap(field->name, lower, upper, prop_name);
> +
> + char *prop_name = g_strdup_printf("SYSREG_%s_%s", reg->name,
> + field->name);
> object_property_add(obj, prop_name, "uint64",
> get_sysreg_prop, set_sysreg_prop, NULL, field);
> g_free(prop_name);
> nb_sysreg_props++;
> -
> - field_mask = MAKE_64BIT_MASK(lower, field->length);
> - map = map & ~field_mask;
> - i = ctz64(map);
> }
> +
> trace_nb_sysreg_props(reg->name, nb_sysreg_props);
> - return 0;
> }
>
> -/* analyze the writable mask and generate properties for writable fields */
> void kvm_arm_expose_idreg_properties(ARMCPU *cpu, ARM64SysReg *regs)
> {
> Object *obj = OBJECT(cpu);
>
> for (int i = 0; i < NUM_ID_IDX; i++) {
> ARM64SysReg *sysregdesc = ®s[i];
> -
> - if (sysregdesc->writable_mask) {
> - decode_idreg_writemap(obj, sysregdesc);
> - }
> + add_idreg_field_properties(obj, sysregdesc);
> }
> }
>
> diff --git a/target/arm/trace-events b/target/arm/trace-events
> index 71a2f5770c..7696a8ed40 100644
> --- a/target/arm/trace-events
> +++ b/target/arm/trace-events
> @@ -15,11 +15,9 @@ arm_gt_update_irq(int timer, int irqstate) "gt_update_irq: timer %d irqstate %d"
> kvm_arm_fixup_msi_route(uint64_t iova, uint64_t gpa) "MSI iova = 0x%"PRIx64" is translated into 0x%"PRIx64
> get_host_cpu_idregs(const char *name, uint64_t value) "scratch vcpu host value for %s is 0x%"PRIx64
> kvm_arm_writable_idregs_to_cpreg_list(const char *name, uint64_t previous, uint64_t new) "%s overwrite default 0x%"PRIx64" with 0x%"PRIx64
> -decode_idreg_writemap(const char* name, int lower, int upper, char *prop_name) "%s [%d:%d] is writable (prop %s)"
> get_sysreg_prop(const char *name, uint64_t value) "%s 0x%"PRIx64
> set_sysreg_prop(const char *name, uint64_t old, uint64_t mask, uint64_t field_value, uint64_t new) "%s old reg value=0x%"PRIx64" mask=0x%"PRIx64" new field value=0x%"PRIx64" new reg value=0x%"PRIx64
> nb_sysreg_props(const char *name, int count) "%s: %d SYSREG properties"
> -unexpected_writable_reserved_field(const char *reg_name, const char *field_name, int lower, int upper) "Unexpected writable reserved field: %s.%s [%d,%d], skip it ..."
> kvm_idreg_write_scratch_vcpu(const char *name, uint64_t oldfv, uint64_t newfv, uint64_t actualfv) "successful dry-run for %s old=0x%"PRIx64" new=0x%"PRIx64" actual=0x%"PRIx64
>
> # cpu.c
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH v4 03/25] target/arm: move SYSREG_ prop infra to cpu64.c
2026-09-21 12:32 ` [RFC PATCH v4 03/25] target/arm: move SYSREG_ prop infra to cpu64.c Khushit Shah
@ 2026-09-24 6:54 ` Eric Auger
2026-09-29 12:56 ` Khushit Shah
0 siblings, 1 reply; 66+ messages in thread
From: Eric Auger @ 2026-09-24 6:54 UTC (permalink / raw)
To: Khushit Shah, qemu-devel, qemu-arm, kvmarm
Cc: cohuck, peter.maydell, richard.henderson, maz, oliver.upton,
berrange, abologna, jdenemar, gshan, skolothumtho, sebott, armbru,
philmd, yangjinqian1, shaju.abraham, mark.caveayland, ping,
sandesh.patel
On 9/21/26 2:32 PM, Khushit Shah wrote:
> kvm_arm_expose_idreg_properties() no longer depends on KVM-specific
> logic. Move it to cpu64.c as aarch64_add_idregs_properties() along with
> all SYSREG_ property infra, making it accelerator-agnostic.
Even before, the code had no real kvm adherence, I mean even if we keep
reg->writable_mask checks. This latter could be populated with another
accelerator. So I think I can move in this direction in the parent series.
Eric
>
> Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
> ---
> target/arm/cpu64.c | 101 +++++++++++++++++++++++++++++++++++++++-
> target/arm/internals.h | 1 +
> target/arm/kvm.c | 100 ---------------------------------------
> target/arm/kvm_arm.h | 10 ----
> target/arm/trace-events | 4 +-
> 5 files changed, 104 insertions(+), 112 deletions(-)
>
> diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
> index 3d522bf20d..7487b48cc9 100644
> --- a/target/arm/cpu64.c
> +++ b/target/arm/cpu64.c
> @@ -38,6 +38,7 @@
> #include "internals.h"
> #include "cpu-features.h"
> #include "cpu-idregs.h"
> +#include "trace.h"
>
> /* convert between <register>_IDX and SYS_<register> */
> #define DEF(NAME, OP0, OP1, CRN, CRM, OP2) \
> @@ -644,6 +645,104 @@ static const Property arm_cpu_pauth_qarma3_property =
> static Property arm_cpu_pauth_qarma5_property =
> DEFINE_PROP_BOOL("pauth-qarma5", ARMCPU, prop_pauth_qarma5, false);
>
> +#ifndef CONFIG_USER_ONLY
> +static void set_sysreg_prop(Object *obj, Visitor *v,
> + const char *name, void *opaque,
> + Error **errp)
> +{
> + ARM64SysRegField *field = (ARM64SysRegField *)opaque;
> + ARMCPU *cpu = ARM_CPU(obj);
> + uint64_t *idregs = cpu->isar.idregs;
> + uint64_t old, value, mask;
> + int lower = field->shift;
> + int length = field->length;
> + int index = field->index;
> +
> + if (!visit_type_uint64(v, name, &value, errp)) {
> + return;
> + }
> +
> + if (length < 64 && value > ((1 << length) - 1)) {
> + error_setg(errp,
> + "idreg %s set value (0x%lx) exceeds length of field (%d)!",
> + name, value, length);
> + return;
> + }
> +
> + if (field->arch_vals) {
> + /* this field has some enum values */
> + for (int i = 0; i < field->arch_vals_count; i++) {
> + if (value == field->arch_vals[i]) {
> + goto valid;
> + }
> + }
> + error_setg(errp,
> + "idreg %s set value (0x%lx) does not match any "
> + "arch valid enum value", name, value);
> + return;
> + }
> +
> +valid:
> +
> + mask = MAKE_64BIT_MASK(lower, length);
> + value = value << lower;
> + old = idregs[index];
> + idregs[index] = old & ~mask;
> + idregs[index] |= value;
> + trace_set_sysreg_prop(name, old, mask, value, idregs[index]);
> +}
> +
> +static void get_sysreg_prop(Object *obj, Visitor *v,
> + const char *name, void *opaque,
> + Error **errp)
> +{
> + ARM64SysRegField *field = (ARM64SysRegField *)opaque;
> + ARMCPU *cpu = ARM_CPU(obj);
> + uint64_t *idregs = cpu->isar.idregs;
> + uint64_t value, mask;
> + int lower = field->shift;
> + int length = field->length;
> + int index = field->index;
> +
> + mask = MAKE_64BIT_MASK(lower, length);
> + value = (idregs[index] & mask) >> lower;
> + visit_type_uint64(v, name, &value, errp);
> + trace_get_sysreg_prop(name, value);
> +}
> +
> +static void add_idregs_properties(Object *obj, ARM64SysReg *reg)
> +{
> + int nb_sysreg_props = 0;
> +
> + for (int i = 0; i < reg->fields_count; i++) {
> + ARM64SysRegField *field = ®->fields[i];
> +
> + /* skip reserved fields */
> + if (g_str_equal(field->name, "RES0") ||
> + g_str_equal(field->name, "RES1") ||
> + g_str_equal(field->name, "RAZ")) {
> + continue;
> + }
> +
> + char *prop_name = g_strdup_printf("SYSREG_%s_%s", reg->name,
> + field->name);
> + object_property_add(obj, prop_name, "uint64",
> + get_sysreg_prop, set_sysreg_prop, NULL, field);
> + g_free(prop_name);
> + nb_sysreg_props++;
> + }
> +
> + trace_nb_sysreg_props(reg->name, nb_sysreg_props);
> +}
> +
> +void aarch64_add_idregs_properties(Object *obj)
> +{
> + for (int i = 0; i < NUM_ID_IDX; i++) {
> + add_idregs_properties(obj, &arm64_id_regs[i]);
> + }
> +}
> +#endif
> +
> void aarch64_add_pauth_properties(Object *obj)
> {
> ARMCPU *cpu = ARM_CPU(obj);
> @@ -810,7 +909,7 @@ void aarch64_host_initfn(Object *obj)
> aarch64_add_sve_properties(obj);
>
> /* generate SYSREG properties */
> - kvm_arm_expose_idreg_properties(cpu, arm64_id_regs);
> + aarch64_add_idregs_properties(obj);
>
> #elif defined(CONFIG_HVF)
> hvf_arm_set_cpu_features_from_host(cpu);
> diff --git a/target/arm/internals.h b/target/arm/internals.h
> index f6b4e173a5..7c76ffea7d 100644
> --- a/target/arm/internals.h
> +++ b/target/arm/internals.h
> @@ -1813,6 +1813,7 @@ void aarch64_max_tcg_initfn(Object *obj);
> void aarch64_add_pauth_properties(Object *obj);
> void aarch64_add_sve_properties(Object *obj);
> void aarch64_add_sme_properties(Object *obj);
> +void aarch64_add_idregs_properties(Object *obj);
> void aarch64_aa32_a57_init(ARMCPU *cpu, bool aa64_enabled);
> void aarch64_host_initfn(Object *obj);
>
> diff --git a/target/arm/kvm.c b/target/arm/kvm.c
> index 2f6c090e43..d5155a3706 100644
> --- a/target/arm/kvm.c
> +++ b/target/arm/kvm.c
> @@ -416,106 +416,6 @@ bool kvm_idreg_write_scratch_vcpu(int cpufd, Visitor *v, const char *name,
> return true;
> }
>
> -static void set_sysreg_prop(Object *obj, Visitor *v,
> - const char *name, void *opaque,
> - Error **errp)
> -{
> - ARM64SysRegField *field = (ARM64SysRegField *)opaque;
> - ARMCPU *cpu = ARM_CPU(obj);
> - uint64_t *idregs = cpu->isar.idregs;
> - uint64_t old, value, mask;
> - int lower = field->shift;
> - int length = field->length;
> - int index = field->index;
> -
> - if (!visit_type_uint64(v, name, &value, errp)) {
> - return;
> - }
> -
> - if (length < 64 && value > ((1 << length) - 1)) {
> - error_setg(errp,
> - "idreg %s set value (0x%lx) exceeds length of field (%d)!",
> - name, value, length);
> - return;
> - }
> -
> - if (field->arch_vals) {
> - /* this field has some enum values */
> - for (int i = 0; i < field->arch_vals_count; i++) {
> - if (value == field->arch_vals[i]) {
> - goto valid;
> - }
> - }
> - error_setg(errp,
> - "idreg %s set value (0x%lx) does not match any "
> - "arch valid enum value", name, value);
> - return;
> - }
> -
> -valid:
> -
> - mask = MAKE_64BIT_MASK(lower, length);
> - value = value << lower;
> - old = idregs[index];
> - idregs[index] = old & ~mask;
> - idregs[index] |= value;
> - trace_set_sysreg_prop(name, old, mask, value, idregs[index]);
> -}
> -
> -static void get_sysreg_prop(Object *obj, Visitor *v,
> - const char *name, void *opaque,
> - Error **errp)
> -{
> - ARM64SysRegField *field = (ARM64SysRegField *)opaque;
> - ARMCPU *cpu = ARM_CPU(obj);
> - uint64_t *idregs = cpu->isar.idregs;
> - uint64_t value, mask;
> - int lower = field->shift;
> - int length = field->length;
> - int index = field->index;
> -
> - mask = MAKE_64BIT_MASK(lower, length);
> - value = (idregs[index] & mask) >> lower;
> - visit_type_uint64(v, name, &value, errp);
> - trace_get_sysreg_prop(name, value);
> -}
> -
> -static void
> -add_idreg_field_properties(Object *obj, ARM64SysReg *reg)
> -{
> - int nb_sysreg_props = 0;
> -
> - for (int i = 0; i < reg->fields_count; i++) {
> - ARM64SysRegField *field = ®->fields[i];
> -
> - /* skip reserved fields */
> - if (g_str_equal(field->name, "RES0") ||
> - g_str_equal(field->name, "RES1") ||
> - g_str_equal(field->name, "RAZ")) {
> - continue;
> - }
> -
> - char *prop_name = g_strdup_printf("SYSREG_%s_%s", reg->name,
> - field->name);
> - object_property_add(obj, prop_name, "uint64",
> - get_sysreg_prop, set_sysreg_prop, NULL, field);
> - g_free(prop_name);
> - nb_sysreg_props++;
> - }
> -
> - trace_nb_sysreg_props(reg->name, nb_sysreg_props);
> -}
> -
> -void kvm_arm_expose_idreg_properties(ARMCPU *cpu, ARM64SysReg *regs)
> -{
> - Object *obj = OBJECT(cpu);
> -
> - for (int i = 0; i < NUM_ID_IDX; i++) {
> - ARM64SysReg *sysregdesc = ®s[i];
> - add_idreg_field_properties(obj, sysregdesc);
> - }
> -}
> -
> static void
> kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
> {
> diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h
> index aafb3cd232..997120966f 100644
> --- a/target/arm/kvm_arm.h
> +++ b/target/arm/kvm_arm.h
> @@ -163,16 +163,6 @@ void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu);
> */
> void kvm_arm_add_vcpu_properties(ARMCPU *cpu);
>
> -typedef struct ARM64SysReg ARM64SysReg;
> -/**
> - * kvm_arm_expose_idreg_properties:
> - * @cpu: The CPU object to generate the properties for
> - * @reg: registers from the host
> - *
> - * analyze the writable mask and generate properties for writable fields
> - */
> -void kvm_arm_expose_idreg_properties(ARMCPU *cpu, ARM64SysReg *regs);
> -
> /**
> * kvm_arm_steal_time_finalize:
> * @cpu: ARMCPU for which to finalize kvm-steal-time
> diff --git a/target/arm/trace-events b/target/arm/trace-events
> index 7696a8ed40..bbf2e5dfa2 100644
> --- a/target/arm/trace-events
> +++ b/target/arm/trace-events
> @@ -15,10 +15,12 @@ arm_gt_update_irq(int timer, int irqstate) "gt_update_irq: timer %d irqstate %d"
> kvm_arm_fixup_msi_route(uint64_t iova, uint64_t gpa) "MSI iova = 0x%"PRIx64" is translated into 0x%"PRIx64
> get_host_cpu_idregs(const char *name, uint64_t value) "scratch vcpu host value for %s is 0x%"PRIx64
> kvm_arm_writable_idregs_to_cpreg_list(const char *name, uint64_t previous, uint64_t new) "%s overwrite default 0x%"PRIx64" with 0x%"PRIx64
> +kvm_idreg_write_scratch_vcpu(const char *name, uint64_t oldfv, uint64_t newfv, uint64_t actualfv) "successful dry-run for %s old=0x%"PRIx64" new=0x%"PRIx64" actual=0x%"PRIx64
> +
> +# cpu64.c
> get_sysreg_prop(const char *name, uint64_t value) "%s 0x%"PRIx64
> set_sysreg_prop(const char *name, uint64_t old, uint64_t mask, uint64_t field_value, uint64_t new) "%s old reg value=0x%"PRIx64" mask=0x%"PRIx64" new field value=0x%"PRIx64" new reg value=0x%"PRIx64
> nb_sysreg_props(const char *name, int count) "%s: %d SYSREG properties"
> -kvm_idreg_write_scratch_vcpu(const char *name, uint64_t oldfv, uint64_t newfv, uint64_t actualfv) "successful dry-run for %s old=0x%"PRIx64" new=0x%"PRIx64" actual=0x%"PRIx64
>
> # cpu.c
> arm_cpu_reset(uint64_t mp_aff) "cpu %" PRIu64
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH v4 05/25] target/arm/kvm: read all ID registers from KVM
2026-09-21 12:32 ` [RFC PATCH v4 05/25] target/arm/kvm: read all ID registers from KVM Khushit Shah
@ 2026-09-24 7:52 ` Eric Auger
0 siblings, 0 replies; 66+ messages in thread
From: Eric Auger @ 2026-09-24 7:52 UTC (permalink / raw)
To: Khushit Shah, qemu-devel, qemu-arm, kvmarm
Cc: cohuck, peter.maydell, richard.henderson, maz, oliver.upton,
berrange, abologna, jdenemar, gshan, skolothumtho, sebott, armbru,
philmd, yangjinqian1, shaju.abraham, mark.caveayland, ping,
sandesh.patel
Hi Khushit,
On 9/21/26 2:32 PM, Khushit Shah wrote:
> Try to read all ID registers from KVM. KVM may return ENOENT for
> registers that it does not support reading from userspace; ignore
> those registers. Some registers may still require special handling.
>
> This exposes a more complete host feature view to the management
> stack. For migration, both writable and non-writable ID registers
> must match.
>
> Add a tracepoint for ID register reads that fail with ENOENT.
>
> Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
> ---
> target/arm/kvm.c | 29 ++++++++++++++---------------
> target/arm/trace-events | 1 +
> 2 files changed, 15 insertions(+), 15 deletions(-)
>
> diff --git a/target/arm/kvm.c b/target/arm/kvm.c
> index f8d349a461..d9d0623a2a 100644
> --- a/target/arm/kvm.c
> +++ b/target/arm/kvm.c
> @@ -330,12 +330,12 @@ static int kvm_feature_idx_to_idregs_idx(int kidx)
> }
>
> /*
> - * get_host_cpu_idregs: Read all the writable ID reg host values
> + * get_host_cpu_idregs: Read all the ID reg host values
> *
> - * Need to be called once the writable mask has been populated
> - * Note we may want to read all the known id regs but some of them are not
> - * writable and return an error, hence the choice of reading only those which
> - * are writable. Those are also readable!
> + * We currently try to read all the registers. If the read fails with
> + * ENOENT (KVM does not identify the ID register) ignore it.
> + * Some of the registers that errored with ENOENT will anyway need special
> + * handling.
> */
> static int get_host_cpu_idregs(int fd, ARMHostCPUFeatures *ahcf)
In the parent series I can add a parameter to select if we want only
writable id regs to be read or all id regs
> {
> @@ -348,19 +348,18 @@ static int get_host_cpu_idregs(int fd, ARMHostCPUFeatures *ahcf)
> uint64_t *reg;
> int ret;
>
> - if (!sysregdesc->writable_mask) {
> - continue;
> - }
> -
> reg = &ahcf->isar.idregs[i];
> ret = read_sys_reg64(fd, reg, idregs_sysreg_to_kvm_reg(sysreg));
> - trace_get_host_cpu_idregs(sysregdesc->name, *reg);
> if (ret) {
> - error_report("%s error reading value of host %s register (%m)",
> - __func__, sysregdesc->name);
> -
> - err = ret;
> + if (errno == ENOENT) {
> + trace_get_host_cpu_idreg_not_found(sysregdesc->name);
> + } else {
> + error_report("%s error reading value of host %s register"
> + " (%m)", __func__, sysregdesc->name);
> + err = ret;
> + }
> }
> + trace_get_host_cpu_idregs(sysregdesc->name, *reg);
> }
> return err;
> }
> @@ -482,7 +481,7 @@ kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
> SET_IDREG(&ahcf->isar, ID_AA64PFR0, 0x00000011); /* EL1&0, AArch64 only */
> err = 0;
> } else {
> - /* Make sure all writable ID reg values are initialized */
> + /* Try to read all the ID registers */
> err |= get_host_cpu_idregs(fd, ahcf);
>
> /*
> diff --git a/target/arm/trace-events b/target/arm/trace-events
> index bbf2e5dfa2..2bb7766f7f 100644
> --- a/target/arm/trace-events
> +++ b/target/arm/trace-events
> @@ -14,6 +14,7 @@ arm_gt_update_irq(int timer, int irqstate) "gt_update_irq: timer %d irqstate %d"
> # kvm.c
> kvm_arm_fixup_msi_route(uint64_t iova, uint64_t gpa) "MSI iova = 0x%"PRIx64" is translated into 0x%"PRIx64
> get_host_cpu_idregs(const char *name, uint64_t value) "scratch vcpu host value for %s is 0x%"PRIx64
> +get_host_cpu_idreg_not_found(const char *name) "host %s register not readable from KVM"
> kvm_arm_writable_idregs_to_cpreg_list(const char *name, uint64_t previous, uint64_t new) "%s overwrite default 0x%"PRIx64" with 0x%"PRIx64
> kvm_idreg_write_scratch_vcpu(const char *name, uint64_t oldfv, uint64_t newfv, uint64_t actualfv) "successful dry-run for %s old=0x%"PRIx64" new=0x%"PRIx64" actual=0x%"PRIx64
>
Eric
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH v4 07/25] target/arm/kvm: process ID register writeback per field
2026-09-21 12:32 ` [RFC PATCH v4 07/25] target/arm/kvm: process ID register writeback per field Khushit Shah
@ 2026-09-24 9:41 ` Eric Auger
0 siblings, 0 replies; 66+ messages in thread
From: Eric Auger @ 2026-09-24 9:41 UTC (permalink / raw)
To: Khushit Shah, qemu-devel, qemu-arm, kvmarm
Cc: cohuck, peter.maydell, richard.henderson, maz, oliver.upton,
berrange, abologna, jdenemar, gshan, skolothumtho, sebott, armbru,
philmd, yangjinqian1, shaju.abraham, mark.caveayland, ping,
sandesh.patel
On 9/21/26 2:32 PM, Khushit Shah wrote:
> Now that all ID register fields are exposed as properties, refactor
> kvm_arm_writable_idregs_to_cpreg_list() as
> kvm_arm_write_idregs_to_cpreg_list() and process each field
> individually. kvm_arm_writable_idregs_to_cpreg_list() assumed that
this does not exist anymore in v9. this later implementation should ease
the handling
Eric
> only writable fields were exposed as SYSREG_ properties.
>
> Copy only fields advertised as writable by KVM instead of replacing the
> whole register. For registers absent from the KVM cpreg list, compare
> the requested value against the host value captured during probing.
>
> Return an error when a non-writable field differs from the host value,
> failing vCPU init.
>
> Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
> ---
> target/arm/cpu-idregs.c | 13 +++++++
> target/arm/cpu-idregs.h | 2 ++
> target/arm/kvm.c | 79 +++++++++++++++++++++++++++++++++--------
> target/arm/trace-events | 2 +-
> 4 files changed, 80 insertions(+), 16 deletions(-)
>
> diff --git a/target/arm/cpu-idregs.c b/target/arm/cpu-idregs.c
> index 199d593153..d58b8ed063 100644
> --- a/target/arm/cpu-idregs.c
> +++ b/target/arm/cpu-idregs.c
> @@ -7,6 +7,7 @@
> * SPDX-License-Identifier: GPL-2.0-or-later
> */
> #include "qemu/osdep.h"
> +#include "qemu/bitops.h"
> #include "qemu/error-report.h"
> #include "qapi/error.h"
> #include "cpu.h"
> @@ -94,3 +95,15 @@ ARM64SysReg arm64_id_regs[NUM_ID_IDX] = {
> #include "cpu-idregs.h.inc"
> };
>
> +uint64_t arm_get_field_mask(const ARM64SysRegField *field)
> +{
> + return MAKE_64BIT_MASK(field->shift, field->length);
> +}
> +
> +bool arm_field_is_writable(const ARM64SysRegField *field)
> +{
> + uint64_t field_mask = arm_get_field_mask(field);
> +
> + return (arm64_id_regs[field->index].writable_mask & field_mask)
> + == field_mask;
> +}
> diff --git a/target/arm/cpu-idregs.h b/target/arm/cpu-idregs.h
> index 98c7a7518f..aab1a79db1 100644
> --- a/target/arm/cpu-idregs.h
> +++ b/target/arm/cpu-idregs.h
> @@ -33,4 +33,6 @@ typedef struct ARM64SysReg {
> */
> extern ARM64SysReg arm64_id_regs[NUM_ID_IDX];
>
> +uint64_t arm_get_field_mask(const ARM64SysRegField *field);
> +bool arm_field_is_writable(const ARM64SysRegField *field);
> #endif
> diff --git a/target/arm/kvm.c b/target/arm/kvm.c
> index 07df6626d4..2d94b3a884 100644
> --- a/target/arm/kvm.c
> +++ b/target/arm/kvm.c
> @@ -1006,6 +1006,16 @@ static uint64_t *kvm_arm_get_cpreg_ptr(ARMCPU *cpu, uint64_t regidx)
> return &cpu->cpreg_values[res - cpu->cpreg_indexes];
> }
>
> +/* Like kvm_arm_get_cpreg_ptr, but returns NULL if the register is not found. */
> +static uint64_t *kvm_arm_find_cpreg_ptr(ARMCPU *cpu, uint64_t regidx)
> +{
> + uint64_t *res;
> + res = bsearch(®idx, cpu->cpreg_indexes, cpu->cpreg_array_len,
> + sizeof(uint64_t), compare_u64);
> +
> + return res ? &cpu->cpreg_values[res - cpu->cpreg_indexes] : NULL;
> +}
> +
> /**
> * kvm_arm_reg_syncs_via_cpreg_list:
> * @regidx: KVM register index
> @@ -1308,31 +1318,67 @@ bool kvm_arm_cpu_post_load(ARMCPU *cpu)
> }
>
> /*
> - * Copy writable ID regs from isar.idregs[] to cpreg_list
> - * in case their value differs from the original init cpreg value
> + * Copy writable ID reg fields from isar.idregs[] into the KVM cpreg list,
> + * so the subsequent write_list_to_kvmstate() pushes them to KVM.
> + * Only writable fields are copied.
> + * Returns -1 if any vCPU's ID reg value differs from the host value and the
> + * field is not writable.
> */
> -static void kvm_arm_writable_idregs_to_cpreg_list(ARMCPU *cpu)
> +static int kvm_arm_write_idregs_to_cpreg_list(ARMCPU *cpu)
> {
> for (int i = 0; i < NUM_ID_IDX; i++) {
> ARM64SysReg *sysregdesc = &arm64_id_regs[i];
> ARMSysRegs sysreg = id_register_sysreg[i];
> - uint64_t previous, new;
> + uint64_t writable_mask = sysregdesc->writable_mask;
> + uint64_t desired = cpu->isar.idregs[i];
> + uint64_t previous, updated;
> uint64_t *cpreg;
>
> - if (!sysregdesc->writable_mask) {
> + cpreg = kvm_arm_find_cpreg_ptr(cpu, idregs_sysreg_to_kvm_reg(sysreg));
> + /*
> + * Registers such as DCZID_EL0 are not exposed through the cpreg
> + * list and are therefore not writable. Use the host value
> + * snapshotted at probe time as the reference to check the vCPU ID
> + * regs have the same value.
> + */
> + previous = cpreg ? *cpreg : arm_host_cpu_features.isar.idregs[i];
> +
> + if (previous == desired) {
> continue;
> }
>
> - cpreg = kvm_arm_get_cpreg_ptr(cpu, idregs_sysreg_to_kvm_reg(sysreg));
> - previous = *cpreg;
> - new = cpu->isar.idregs[i];
> + for (int j = 0; j < sysregdesc->fields_count; j++) {
> + const ARM64SysRegField *field = &sysregdesc->fields[j];
> + uint64_t field_mask = arm_get_field_mask(field);
> + uint64_t prev_val = previous & field_mask;
> + uint64_t new_val = desired & field_mask;
> +
> + if (prev_val == new_val) {
> + continue;
> + }
> +
> + if (!arm_field_is_writable(field)) {
> + error_report("%s.%s is not writable: host=0x%" PRIx64
> + ", requested=0x%" PRIx64,
> + sysregdesc->name, field->name,
> + prev_val >> field->shift, new_val >> field->shift);
> + return -1;
> + }
> + }
> +
> + if (!cpreg || !writable_mask) {
> + continue;
> + }
>
> - if (previous != new) {
> - *cpreg = new;
> - trace_kvm_arm_writable_idregs_to_cpreg_list(sysregdesc->name,
> - previous, new);
> - }
> + updated = (previous & ~writable_mask) | (desired & writable_mask);
> + if (updated != previous) {
> + *cpreg = updated;
> + trace_kvm_arm_write_idregs_to_cpreg_list(sysregdesc->name,
> + previous, updated);
> + }
> }
> +
> + return 0;
> }
>
> void kvm_arm_reset_vcpu(ARMCPU *cpu)
> @@ -2293,8 +2339,11 @@ int kvm_arch_init_vcpu(CPUState *cs)
> if (ret) {
> return ret;
> }
> - /* overwrite writable ID regs with their updated property values */
> - kvm_arm_writable_idregs_to_cpreg_list(cpu);
> + /* overwrite ID reg fields with their updated property values */
> + ret = kvm_arm_write_idregs_to_cpreg_list(cpu);
> + if (ret) {
> + return ret;
> + }
> ret = write_list_to_kvmstate(cpu, KVM_PUT_FULL_STATE);
> if (!ret) {
> return -1;
> diff --git a/target/arm/trace-events b/target/arm/trace-events
> index 2bb7766f7f..7b54e34ad9 100644
> --- a/target/arm/trace-events
> +++ b/target/arm/trace-events
> @@ -15,7 +15,7 @@ arm_gt_update_irq(int timer, int irqstate) "gt_update_irq: timer %d irqstate %d"
> kvm_arm_fixup_msi_route(uint64_t iova, uint64_t gpa) "MSI iova = 0x%"PRIx64" is translated into 0x%"PRIx64
> get_host_cpu_idregs(const char *name, uint64_t value) "scratch vcpu host value for %s is 0x%"PRIx64
> get_host_cpu_idreg_not_found(const char *name) "host %s register not readable from KVM"
> -kvm_arm_writable_idregs_to_cpreg_list(const char *name, uint64_t previous, uint64_t new) "%s overwrite default 0x%"PRIx64" with 0x%"PRIx64
> +kvm_arm_write_idregs_to_cpreg_list(const char *name, uint64_t previous, uint64_t new) "%s overwrite default 0x%"PRIx64" with 0x%"PRIx64
> kvm_idreg_write_scratch_vcpu(const char *name, uint64_t oldfv, uint64_t newfv, uint64_t actualfv) "successful dry-run for %s old=0x%"PRIx64" new=0x%"PRIx64" actual=0x%"PRIx64
>
> # cpu64.c
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH v4 08/25] target/arm/kvm: handle writeback for special ID register fields
2026-09-21 12:32 ` [RFC PATCH v4 08/25] target/arm/kvm: handle writeback for special ID register fields Khushit Shah
@ 2026-09-24 9:57 ` Eric Auger
2026-09-24 10:21 ` Khushit Shah
2026-09-29 13:09 ` Khushit Shah
0 siblings, 2 replies; 66+ messages in thread
From: Eric Auger @ 2026-09-24 9:57 UTC (permalink / raw)
To: Khushit Shah, qemu-devel, qemu-arm, kvmarm
Cc: cohuck, peter.maydell, richard.henderson, maz, oliver.upton,
berrange, abologna, jdenemar, gshan, skolothumtho, sebott, armbru,
philmd, yangjinqian1, shaju.abraham, mark.caveayland, ping,
sandesh.patel
On 9/21/26 2:32 PM, Khushit Shah wrote:
> Some fields should not be written back to KVM for various reasons:
> - ID_AA64PFR0_EL1.GIC / ID_PFR1_EL1.GIC are fabricated by KVM based on
> the gic-version property.
> - KVM does not allow writing 0 to ID_DFR0_EL1.CopDbg, which breaks
> booting an AArch64-only guest on a host that also supports AArch32.
> - ID_DFR0_EL1.PerfMon is populated by KVM even for AArch64-only guests
> but is not writable there.
> - MPIDR_EL1 is managed by KVM based on vCPU index.
> - Hold off writing back CLIDR_EL1 until we properly support exposing
> cache topology to a KVM guest.
>
> Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
> ---
> target/arm/cpu-idregs.c | 6 ++++++
> target/arm/cpu-idregs.h | 2 ++
> target/arm/kvm.c | 40 +++++++++++++++++++++++++++++++++++++++-
> 3 files changed, 47 insertions(+), 1 deletion(-)
>
> diff --git a/target/arm/cpu-idregs.c b/target/arm/cpu-idregs.c
> index d58b8ed063..1f7ebfe9bb 100644
> --- a/target/arm/cpu-idregs.c
> +++ b/target/arm/cpu-idregs.c
> @@ -107,3 +107,9 @@ bool arm_field_is_writable(const ARM64SysRegField *field)
> return (arm64_id_regs[field->index].writable_mask & field_mask)
> == field_mask;
> }
> +
> +bool field_matches(const ARM64SysRegField *field, ARMIDRegisterIdx index,
> + const char *name)
> +{
> + return field->index == index && !strcmp(field->name, name);
> +}
> diff --git a/target/arm/cpu-idregs.h b/target/arm/cpu-idregs.h
> index aab1a79db1..8ef3f9350e 100644
> --- a/target/arm/cpu-idregs.h
> +++ b/target/arm/cpu-idregs.h
> @@ -35,4 +35,6 @@ extern ARM64SysReg arm64_id_regs[NUM_ID_IDX];
>
> uint64_t arm_get_field_mask(const ARM64SysRegField *field);
> bool arm_field_is_writable(const ARM64SysRegField *field);
> +bool field_matches(const ARM64SysRegField *field, ARMIDRegisterIdx index,
> + const char *name);
> #endif
> diff --git a/target/arm/kvm.c b/target/arm/kvm.c
> index 2d94b3a884..70d9a07580 100644
> --- a/target/arm/kvm.c
> +++ b/target/arm/kvm.c
> @@ -1317,10 +1317,40 @@ bool kvm_arm_cpu_post_load(ARMCPU *cpu)
> return true;
> }
>
> +static bool arm_field_skip_writeback_always(const ARM64SysRegField *field)
> +{
> + /*
> + * GIC is controlled by the gic-version property and fabricated by KVM
> + * when the vGIC device is created, so a named CPU model must not touch
> + * it. KVM also rejects writing 0 to ID_DFR0_EL1.CopDbg, which breaks
> + * booting a model that lacks AArch32 support on a host that supports
> + * it. MPIDR_EL1 is managed by KVM based on vCPU index, skip writing it
> + * back. Similarly, skip writing back CLIDR_EL1 till we properly
> + * support exposing cache for KVM guest.
> + */
> + return field_matches(field, ID_AA64PFR0_EL1_IDX, "GIC")
> + || field_matches(field, ID_PFR1_EL1_IDX, "GIC")
> + || field_matches(field, ID_DFR0_EL1_IDX, "CopDbg")
> + || field->index == MPIDR_EL1_IDX
> + || field->index == CLIDR_EL1_IDX;
what does happen for SMIDR_EL1 and GMID_EL1 whose value could not be
initialized from host. The setter for any of their field shall fail.
> +}
> +
> +static bool
> +arm_field_skip_writeback_if_not_writable(const ARM64SysRegField *field)
> +{
> + /*
> + * KVM populates ID_DFR0_EL1.PerfMon even for AArch64-only guests but
> + * does not expose it as writable there, so skip it when it is not
> + * writable.
> + */
> + return field_matches(field, ID_DFR0_EL1_IDX, "PerfMon");
> +}
> +
> /*
> * Copy writable ID reg fields from isar.idregs[] into the KVM cpreg list,
> * so the subsequent write_list_to_kvmstate() pushes them to KVM.
> - * Only writable fields are copied.
> + * Only writable fields are copied; fields that must not be written back
> + * (see arm_field_skip_writeback_*) are skipped.
> * Returns -1 if any vCPU's ID reg value differs from the host value and the
> * field is not writable.
> */
> @@ -1357,6 +1387,14 @@ static int kvm_arm_write_idregs_to_cpreg_list(ARMCPU *cpu)
> continue;
> }
>
> + if (arm_field_skip_writeback_always(field) ||
> + (!arm_field_is_writable(field) &&
> + arm_field_skip_writeback_if_not_writable(field))) {
> + /* Never write this field back; keep KVM's value. */
> + writable_mask &= ~field_mask;
> + continue;
> + }
> +
> if (!arm_field_is_writable(field)) {
> error_report("%s.%s is not writable: host=0x%" PRIx64
> ", requested=0x%" PRIx64,
v9 has changed the way new field values are stored. writable field props
and non writable field props could have different setters. A non
writable field setter just needs to check the new value is the same as
the current host value. No need to record the new value in the hashtable
for further commitment.
Eric
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH v4 08/25] target/arm/kvm: handle writeback for special ID register fields
2026-09-24 9:57 ` Eric Auger
@ 2026-09-24 10:21 ` Khushit Shah
2026-09-24 11:47 ` Eric Auger
2026-09-29 13:09 ` Khushit Shah
1 sibling, 1 reply; 66+ messages in thread
From: Khushit Shah @ 2026-09-24 10:21 UTC (permalink / raw)
To: eric.auger@redhat.com
Cc: qemu-devel@nongnu.org, qemu-arm@nongnu.org,
kvmarm@lists.linux.dev, cohuck@redhat.com,
peter.maydell@linaro.org, richard.henderson@linaro.org,
maz@kernel.org, oliver.upton@linux.dev, berrange@redhat.com,
abologna@redhat.com, jdenemar@redhat.com, gshan@redhat.com,
skolothumtho@nvidia.com, sebott@redhat.com, armbru@redhat.com,
philmd@linaro.org, yangjinqian1@huawei.com, Shaju Abraham,
Mark Cave-Ayland, ping@khushitshah.com, Sandesh Patel
> On 24 Sep 2026, at 3:27 PM, Eric Auger <eric.auger@redhat.com> wrote:
>
> v9 has changed the way new field values are stored. writable field props
> and non writable field props could have different setters. A non
> writable field setter just needs to check the new value is the same as
> the current host value. No need to record the new value in the hashtable
> for further commitment.
How will that work? as based on certain vCPU init options, non-writable fields will change… right?
Warm Regards,
Khushit
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH v4 08/25] target/arm/kvm: handle writeback for special ID register fields
2026-09-24 10:21 ` Khushit Shah
@ 2026-09-24 11:47 ` Eric Auger
0 siblings, 0 replies; 66+ messages in thread
From: Eric Auger @ 2026-09-24 11:47 UTC (permalink / raw)
To: Khushit Shah
Cc: qemu-devel@nongnu.org, qemu-arm@nongnu.org,
kvmarm@lists.linux.dev, cohuck@redhat.com,
peter.maydell@linaro.org, richard.henderson@linaro.org,
maz@kernel.org, oliver.upton@linux.dev, berrange@redhat.com,
abologna@redhat.com, jdenemar@redhat.com, gshan@redhat.com,
skolothumtho@nvidia.com, sebott@redhat.com, armbru@redhat.com,
philmd@linaro.org, yangjinqian1@huawei.com, Shaju Abraham,
Mark Cave-Ayland, ping@khushitshah.com, Sandesh Patel
On 9/24/26 12:21 PM, Khushit Shah wrote:
>
>> On 24 Sep 2026, at 3:27 PM, Eric Auger <eric.auger@redhat.com> wrote:
>>
>> v9 has changed the way new field values are stored. writable field props
>> and non writable field props could have different setters. A non
>> writable field setter just needs to check the new value is the same as
>> the current host value. No need to record the new value in the hashtable
>> for further commitment.
> How will that work? as based on certain vCPU init options, non-writable fields will change… right?
I meant the new value does not need to be written into KVM because it
must be equal to the current value. But maybe I missed your point
Eric
>
> Warm Regards,
> Khushit
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH v4 09/25] target/arm: introduce named CPU model infrastructure
2026-09-21 12:32 ` [RFC PATCH v4 09/25] target/arm: introduce named CPU model infrastructure Khushit Shah
@ 2026-09-24 13:35 ` Eric Auger
2026-09-29 13:40 ` Khushit Shah
0 siblings, 1 reply; 66+ messages in thread
From: Eric Auger @ 2026-09-24 13:35 UTC (permalink / raw)
To: Khushit Shah, qemu-devel, qemu-arm, kvmarm
Cc: cohuck, peter.maydell, richard.henderson, maz, oliver.upton,
berrange, abologna, jdenemar, gshan, skolothumtho, sebott, armbru,
philmd, yangjinqian1, shaju.abraham, mark.caveayland, ping,
sandesh.patel
Hi Khushit,
On 9/21/26 2:32 PM, Khushit Shah wrote:
> Add scaffolding for named CPU models on Arm on top of the property
> layer. A model is a list of (property, value) overrides plus an
> optional parent; a child inherits its parent's property values and may
> override them.
>
> Instance init steps:
> - host feature discovery.
> - zero out isar.idregs[] and restore RES1 fields.
> - install SYSREG_ and sve* properties.
> - walk the parent chain root-first and apply each level's
> properties.
you should explain about prop types. I see they are either bool or uint.
Given the parent series bool usage is not obvious.
>
> This assumes that each property is idempotent. `pauth` is intentionally
> not installed because the model's ID register view is authoritative
> and can be configured through SYSREG_ properties.
>
> No models are defined yet.
>
> Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
> ---
> target/arm/cpu-models.c | 191 ++++++++++++++++++++++++++++++++++++++++
> target/arm/cpu-models.h | 36 ++++++++
> target/arm/meson.build | 1 +
> 3 files changed, 228 insertions(+)
> create mode 100644 target/arm/cpu-models.c
> create mode 100644 target/arm/cpu-models.h
>
> diff --git a/target/arm/cpu-models.c b/target/arm/cpu-models.c
> new file mode 100644
> index 0000000000..fed3197186
> --- /dev/null
> +++ b/target/arm/cpu-models.c
> @@ -0,0 +1,191 @@
> +/*
> + * ARM named CPU models.
> + *
> + * Each model is defined as an array of MODEL_PROP macros, listing only
> + * the properties that DIFFER from the parent model.
> + *
> + * Initialization starts with a zeroed idregs[] array.
> + *
> + * During initialization, the parent chain is walked root-first and every
> + * level's properties are applied via QOM, so the leaf's values naturally
> + * override its ancestors.
> + *
> + * Assumptions:
> + * - All named CPU model properties are idempotent.
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + */
> +
> +#include "qemu/osdep.h"
> +#include "qapi/error.h"
> +#include "qemu/error-report.h"
> +#include "system/kvm.h"
> +#include "cpu.h"
> +#include "internals.h"
> +#include "kvm_arm.h"
> +#include "cpu-idregs.h"
> +#include "cpu-models.h"
> +
> +#define MODEL_PROP_FIELD_STR str
> +#define MODEL_PROP_FIELD_BOOL b
> +#define MODEL_PROP_FIELD_NUM num
> +
> +#define MODEL_PROP(_name, _type, _value) \
> + { .name = (_name), .type = ARM_MODEL_PROP_##_type, \
> + .u.MODEL_PROP_FIELD_##_type = (_value) }
> +
> +#define MODEL_PROP_END { .name = NULL }
> +
> +/* Maximum parent-chain depth for named CPU models. */
inheritence depth?
> +#define ARM_NAMED_CPU_MODEL_MAX_DEPTH 16
> +
> +static const ArmNamedCpuModel arm_cpu_models[] = {
> + {NULL, NULL, NULL}
> +};
> +
> +const ArmNamedCpuModel *arm_find_model(const char *name)
> +{
> + for (size_t i = 0; i < ARRAY_SIZE(arm_cpu_models); i++) {
> + if (!arm_cpu_models[i].name) {
> + break;
> + }
> +
> + if (g_str_equal(arm_cpu_models[i].name, name)) {
> + return &arm_cpu_models[i];
> + }
> + }
> + return NULL;
> +}
> +
> +void arm_apply_model_props(Object *obj, const ArmModelPropValue *props,
> + Error **errp)
> +{
> + const ArmModelPropValue *pv;
> + ERRP_GUARD();
> +
> + for (pv = props; pv->name; pv++) {
> + switch (pv->type) {
> + case ARM_MODEL_PROP_BOOL:
> + object_property_set_bool(obj, pv->name, pv->u.b, errp);
> + break;
> + case ARM_MODEL_PROP_NUM:
> + object_property_set_uint(obj, pv->name, pv->u.num, errp);
> + break;
> + default:
> + g_assert_not_reached();
> + }
> +
> + if (*errp) {
> + error_prepend(errp, "property '%s': ", pv->name);
> + return;
> + }
> + }
> +}
> +
> +void arm_realize_model_chain(Object *obj, const ArmNamedCpuModel *model,
> + Error **errp)
> +{
> + const ArmNamedCpuModel *cur, *parent;
> + const ArmNamedCpuModel *chain[ARM_NAMED_CPU_MODEL_MAX_DEPTH];
> + size_t depth = 0;
> +
> + for (cur = model; cur; ) {
> + if (depth >= ARRAY_SIZE(chain)) {
> + error_setg(errp, "model '%s': parent chain too deep", model->name);
> + return;
> + }
> + chain[depth++] = cur;
Please add a comment about the so-called chain and especially describing
that chain[0] is the child and high-level eindex lements are the parents
it derives from.
> +
> + if (!cur->parent) {
> + break;
> + }
> + parent = arm_find_model(cur->parent);
I guess you directly assert
> + if (!parent) {
> + error_setg(errp, "model '%s': unknown parent '%s'", cur->name,
> + cur->parent);
> + return;
> + }
> + cur = parent;
> + }
> +
> + while (depth--) {
> + arm_apply_model_props(obj, chain[depth]->props, errp);
> + if (*errp) {
> + return;
> + }
> + }
> +}
> +
> +static void reset_res1_fields(ARMCPU *cpu)
> +{
> + for (size_t i = 0; i < NUM_ID_IDX; i++) {
> + for (size_t j = 0; j < arm64_id_regs[i].fields_count; j++) {
> + if (strcmp(arm64_id_regs[i].fields[j].name, "RES1") == 0) {
> + cpu->isar.idregs[i] = deposit64(cpu->isar.idregs[i],
> + arm64_id_regs[i].fields[j].shift,
> + arm64_id_regs[i].fields[j].length,
> + MAKE_64BIT_MASK(0, arm64_id_regs[i].fields[j].length));
> + }
> + }
> + }
> +}
> +
> +static void arm_named_cpu_initfn(Object *obj)
> +{
> + ARMCPU *cpu = ARM_CPU(obj);
> + ARMCPUClass *acc = ARM_CPU_GET_CLASS(obj);
> + const ArmNamedCpuModel *model = arm_find_model(acc->info->name);
> +
> + if (!model) {
> + error_report("'%s' CPU model entry not found",
> + acc->info->name);
> + return;
> + }
> +
> + if (!kvm_enabled()) {
> + error_report("'%s' CPU model requires KVM (-accel kvm)",
> + acc->info->name);
> + return;
> + }
> +
> + kvm_arm_set_cpu_features_from_host(cpu);
> + if (!arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) {
> + return;
> + }
> +
> + /* 1.a Reset ID regs to 0 */
> + memset(cpu->isar.idregs, 0, sizeof(cpu->isar.idregs));
> +
> + /* 1.b Properly set RES1 fields. */
> + reset_res1_fields(cpu);
> +
> + /* 2. Add sveNNNN and SYSREG_ properties */
> + aarch64_add_sve_properties(obj);
> + aarch64_add_idregs_properties(obj);
Can you give more explanations about why we don't have
aarch64_add_pauth_properties()
kvm_arm_set_cpreg_mig_tolerances()
at least.
By the way it is not clear what will become legacy compositive options
with named vcpu models. I see you keep sve but what about the others.
> +
> + /* 3. Realize the model chain. */
> + arm_realize_model_chain(obj, model, &error_abort);
> +}
> +
> +void arm_register_named_cpu_models(void)
> +{
> + static ARMCPUInfo *arm_named_cpu_infos;
> + size_t i, n = ARRAY_SIZE(arm_cpu_models);
> +
> + if (!n) {
> + return;
> + }
> +
> + arm_named_cpu_infos = g_new0(ARMCPUInfo, n);
> + for (i = 0; i < n; i++) {
> + if (!arm_cpu_models[i].name) {
> + break;
> + }
> +
> + arm_named_cpu_infos[i].name = arm_cpu_models[i].name;
> + arm_named_cpu_infos[i].initfn = arm_named_cpu_initfn;
> + arm_cpu_register(&arm_named_cpu_infos[i]);
> + }
> +}
> +
> +type_init(arm_register_named_cpu_models)
> diff --git a/target/arm/cpu-models.h b/target/arm/cpu-models.h
> new file mode 100644
> index 0000000000..144778744e
> --- /dev/null
> +++ b/target/arm/cpu-models.h
> @@ -0,0 +1,36 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +#ifndef ARM_CPU_MODELS_H
> +#define ARM_CPU_MODELS_H
> +
> +#include "qapi/error.h"
> +#include "qom/object.h"
> +
> +typedef enum ArmModelPropType {
> + ARM_MODEL_PROP_BOOL,
> + ARM_MODEL_PROP_NUM,
> +} ArmModelPropType;
> +
> +typedef struct ArmModelPropValue {
> + const char *name;
> + ArmModelPropType type;
> + union {
> + bool b;
> + uint64_t num;
> + } u;
> +} ArmModelPropValue;
> +
> +typedef struct ArmNamedCpuModel {
> + const char *name;
> + const char *parent;
any reason why you don't point to the patent ArmNamedCpuModel pointer
instead?
> + const ArmModelPropValue *props;
> +} ArmNamedCpuModel;
> +
> +void arm_register_named_cpu_models(void);
> +
> +const ArmNamedCpuModel *arm_find_model(const char *name);
> +void arm_apply_model_props(Object *obj, const ArmModelPropValue *props,
> + Error **errp);
> +void arm_realize_model_chain(Object *obj, const ArmNamedCpuModel *model,
> + Error **errp);
> +
> +#endif /* ARM_CPU_MODELS_H */
> diff --git a/target/arm/meson.build b/target/arm/meson.build
> index 384d90c530..dd28146c52 100644
> --- a/target/arm/meson.build
> +++ b/target/arm/meson.build
> @@ -32,6 +32,7 @@ arm_common_system_ss.add(files(
> 'arm-qmp-cmds.c',
> 'cpu-idregs.c',
> ))
> +arm_system_ss.add(when: 'TARGET_AARCH64', if_true: files('cpu-models.c'))
> arm_system_ss.add(when: 'CONFIG_KVM', if_true: files('hyp_gdbstub.c', 'kvm.c'))
> arm_system_ss.add(when: 'CONFIG_HVF', if_true: files('hyp_gdbstub.c'))
>
Eric
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH v4 01/25] target/arm: expose SYSREG_ props for REVIDR_EL1 and AIDR_EL1
2026-09-23 16:22 ` Eric Auger
@ 2026-09-29 12:54 ` Khushit Shah
0 siblings, 0 replies; 66+ messages in thread
From: Khushit Shah @ 2026-09-29 12:54 UTC (permalink / raw)
To: eric.auger@redhat.com
Cc: qemu-devel@nongnu.org, qemu-arm@nongnu.org,
kvmarm@lists.linux.dev, cohuck@redhat.com,
peter.maydell@linaro.org, richard.henderson@linaro.org,
maz@kernel.org, oliver.upton@linux.dev, berrange@redhat.com,
abologna@redhat.com, jdenemar@redhat.com, gshan@redhat.com,
skolothumtho@nvidia.com, sebott@redhat.com, armbru@redhat.com,
philmd@linaro.org, yangjinqian1@huawei.com, Shaju Abraham,
Mark Cave-Ayland, ping@khushitshah.com, Sandesh Patel
> On 23 Sep 2026, at 9:52 PM, Eric Auger <eric.auger@redhat.com> wrote:
>
> !-------------------------------------------------------------------|
> CAUTION: External Email
>
> |-------------------------------------------------------------------!
>
> Hi Khushit,
>
> On 9/21/26 2:32 PM, Khushit Shah wrote:
>> REVIDR_EL1 and AIDR_EL1 are implementation-defined and have no named
>> fields in Registers.json.
>>
>> Emit dummy VAL fields covering the full register for these registers
>> in scripts/update-aarch64-cpu-sysreg-properties.py, then remove the
>> special case for these in kvm_arm_expose_idreg_properties(), exposing
>> them as SYSREG_ props.
>>
>> Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
>> ---
>> scripts/update-aarch64-cpu-sysreg-properties.py | 9 +++++++++
>> target/arm/cpu-idregs.h.inc | 2 ++
>> target/arm/kvm.c | 10 +---------
>> 3 files changed, 12 insertions(+), 9 deletions(-)
>>
>> diff --git a/scripts/update-aarch64-cpu-sysreg-properties.py b/scripts/update-aarch64-cpu-sysreg-properties.py
>> index 0b4e4d3e0c..2269063408 100644
>> --- a/scripts/update-aarch64-cpu-sysreg-properties.py
>> +++ b/scripts/update-aarch64-cpu-sysreg-properties.py
>> @@ -246,6 +246,15 @@ def generate_sysreg_properties_from_registers_json(id_reg_names, raw_json_path):
>> # Sort decreasing lsbs
>> sorted_fields = sorted(unique_fields.items(),
>> key=lambda x: x[1]['lsb'], reverse=True)
>> + if len(sorted_fields) == 0:
>> + # For cases like REVIDR_EL1, add a dummy field covering the
>> + # full register.
>> + sorted_fields.append(('VAL', {
> though I think it is important the property name stays SYSREG_REVIDR_EL1
> and not SYSREG_REVIDR_EL1_VAL so I guess we need either a property alias
> or a special handling for those regs (better as alias were not really
> meant for that purpose I think).
Done, the property names will now be SYSREG_REVIDR_EL1/SYSREG_AIDR_EL1
Thanks,
Khushit
>
> Eric
>> + 'lsb': 0,
>> + 'msb': 63,
>> + 'width': 64,
>> + 'enums': []
>> + }))
>>
>> for unique_key, bits in sorted_fields:
>> enums_list = bits.get('enums', [])
>> diff --git a/target/arm/cpu-idregs.h.inc b/target/arm/cpu-idregs.h.inc
>> index c7e93c48b7..bc52112430 100644
>> --- a/target/arm/cpu-idregs.h.inc
>> +++ b/target/arm/cpu-idregs.h.inc
>> @@ -12,6 +12,7 @@
>> /* IDREG_END(REG) */
>>
>> IDREG_START(AIDR_EL1)
>> + IDREG_FIELD(AIDR_EL1, VAL, 0, 64)
>> IDREG_END(AIDR_EL1)
>>
>> IDREG_START(CLIDR_EL1)
>> @@ -2438,6 +2439,7 @@ IDREG_START(MVFR2_EL1)
>> IDREG_END(MVFR2_EL1)
>>
>> IDREG_START(REVIDR_EL1)
>> + IDREG_FIELD(REVIDR_EL1, VAL, 0, 64)
>> IDREG_END(REVIDR_EL1)
>>
>> IDREG_START(SMIDR_EL1)
>> diff --git a/target/arm/kvm.c b/target/arm/kvm.c
>> index e3a0dc07de..8a823d0324 100644
>> --- a/target/arm/kvm.c
>> +++ b/target/arm/kvm.c
>> @@ -554,15 +554,7 @@ void kvm_arm_expose_idreg_properties(ARMCPU *cpu, ARM64SysReg *regs)
>> ARM64SysReg *sysregdesc = ®s[i];
>>
>> if (sysregdesc->writable_mask) {
>> - /*
>> - * special case REVIDR_EL1 and AIDR_EL1 which are writable but
>> - * do not expose named fields. They will need to be handled
>> - * separately
>> - */
>> - if (strcmp(sysregdesc->name, "REVIDR_EL1") &&
>> - strcmp(sysregdesc->name, "AIDR_EL1")) {
>> - decode_idreg_writemap(obj, sysregdesc);
>> - }
>> + decode_idreg_writemap(obj, sysregdesc);
>> }
>> }
>> }
>
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH v4 02/25] target/arm: expose all non-res ID reg fields as properties
2026-09-24 6:46 ` Eric Auger
@ 2026-09-29 12:55 ` Khushit Shah
0 siblings, 0 replies; 66+ messages in thread
From: Khushit Shah @ 2026-09-29 12:55 UTC (permalink / raw)
To: eric.auger@redhat.com
Cc: qemu-devel@nongnu.org, qemu-arm@nongnu.org,
kvmarm@lists.linux.dev, cohuck@redhat.com,
peter.maydell@linaro.org, richard.henderson@linaro.org,
maz@kernel.org, oliver.upton@linux.dev, berrange@redhat.com,
abologna@redhat.com, jdenemar@redhat.com, gshan@redhat.com,
skolothumtho@nvidia.com, sebott@redhat.com, armbru@redhat.com,
philmd@linaro.org, yangjinqian1@huawei.com, Shaju Abraham,
Mark Cave-Ayland, ping@khushitshah.com, Sandesh Patel
> On 24 Sep 2026, at 12:16 PM, Eric Auger <eric.auger@redhat.com> wrote:
>
> !-------------------------------------------------------------------|
> CAUTION: External Email
>
> |-------------------------------------------------------------------!
>
>
>
> On 9/21/26 2:32 PM, Khushit Shah wrote:
>> Upcoming named CPU model layer will require exposing all the ID register
>> fields as properties.
>>
>> Furthermore, this exposes the host values of all ID register fields
>> to the management stack, which can use them to infer migration
>> compatibility constraints between different hosts.
>>
>> Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
>> ---
>> docs/system/arm/cpu-features.rst | 34 +++++++--------
>> target/arm/cpu64.c | 2 +-
>> target/arm/kvm.c | 71 +++++++-------------------------
>> target/arm/trace-events | 2 -
>> 4 files changed, 31 insertions(+), 78 deletions(-)
>>
>> diff --git a/docs/system/arm/cpu-features.rst b/docs/system/arm/cpu-features.rst
>> index 3a07a87bc3..62bb2bd999 100644
>> --- a/docs/system/arm/cpu-features.rst
>> +++ b/docs/system/arm/cpu-features.rst
>> @@ -34,17 +34,15 @@ running guests in AArch32.
>> CPU features that are inherently specific to KVM are
>> prefixed with "kvm-" and are described in "KVM VCPU Features".
>>
>> -2. Additionally, the ``host`` CPU model on KVM allows to configure optional
>> -CPU features via the corresponding ID registers. The host kernel allows
>> -to write a subset of ID register fields. The host model exposes
>> -properties for each writable ID register field. Those options are named
>> -SYSREG_<IDREG>_<FIELD>. IDREG and FIELD names are those used in the
>> -ARM Architecture Reference Manual. Their availability depend on the host
>> -capability to let the userspace write those fields. Values set with those
>> -properties override the initial values retrieved from the host. They are
>> -written back to KVM and the eventual value applied by KVM depends on whether
>> -the value is sanitized or not by the host kernel. Then those field values
>> -are likely to be overriden again by legacy CPU options which apply at the end.
>> +2. Additionally, the ``host`` CPU model on KVM allows configuring optional
>> +CPU features through the corresponding ID registers. The host model exposes
>> +properties for every non-reserved ID register field known to QEMU. Those
>> +properties are named SYSREG_<IDREG>_<FIELD>. IDREG and FIELD names are those
>> +used in the Arm Architecture Reference Manual. Values set with those
>> +properties override the initial values retrieved from the host. Whether a
>> +value that differs from the host value can be applied depends on KVM support
>> +and any field-specific handling in QEMU. Legacy CPU options applied later may
>> +override those field values.
>>
>> CPU Feature Probing
>> ===================
>> @@ -534,12 +532,10 @@ Note that this is currently only supported under KVM, and with the
>> Querying available ID register fields
>> -------------------------------------
>>
>> -QEMU will create properties for all ID register fields that are
>> -reported as being writable by the kernel, and that are known to the
>> -QEMU instance. Therefore, the same QEMU binary may expose different
>> -properties when run under a different kernel.
>> +QEMU creates properties for all non-reserved ID register fields known to
>> +the QEMU instance.
>>
>> -To find out all available writable ID register fields, use the
>> +To find out all available ID register fields, use the
>> ``query-cpu-model-expansion`` QMP command::
>>
>> (QEMU) query-cpu-model-expansion type=full model={"name":"host"}
>> @@ -554,8 +550,10 @@ To find out all available writable ID register fields, use the
>> "SYSREG_ID_AA64ISAR0_EL1_DP": 1, (...)
>> }}}}
>>
>> -If a certain field in an ID register does not show up in this list, it
>> -is not writable with the specific host kernel.
>> +The presence of a property does not imply that every value is supported.
>> +Non-writable fields must retain their host value, while writable fields are
>> +limited to the values supported by KVM. A configuration requesting an
>> +unsupported value is rejected.
>>
>> A note on compatibility
>> -----------------------
>> diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
>> index e04062e848..3d522bf20d 100644
>> --- a/target/arm/cpu64.c
>> +++ b/target/arm/cpu64.c
>> @@ -809,7 +809,7 @@ void aarch64_host_initfn(Object *obj)
>> kvm_arm_set_cpu_features_from_host(cpu);
>> aarch64_add_sve_properties(obj);
>>
>> - /* generate SYSREG properties according to writable masks */
>> + /* generate SYSREG properties */
>> kvm_arm_expose_idreg_properties(cpu, arm64_id_regs);
>>
>> #elif defined(CONFIG_HVF)
>> diff --git a/target/arm/kvm.c b/target/arm/kvm.c
>> index 8a823d0324..2f6c090e43 100644
>> --- a/target/arm/kvm.c
>> +++ b/target/arm/kvm.c
>> @@ -365,19 +365,6 @@ static int get_host_cpu_idregs(int fd, ARMHostCPUFeatures *ahcf)
>> return err;
>> }
>>
>> -static ARM64SysRegField *get_field(int i, ARM64SysReg *reg)
>> -{
>> - for (int f = 0; f < reg->fields_count; f++) {
>> - struct ARM64SysRegField *field = ®->fields[f];
>> - int upper = field->shift + field->length - 1;
>> -
>> - if (i >= field->shift && i <= upper) {
>> - return field;
>> - }
>> - }
>> - return NULL;
>> -}
>> -
>> bool kvm_idreg_write_scratch_vcpu(int cpufd, Visitor *v, const char *name,
>> void *opaque, Error **errp)
>> {
>> @@ -493,69 +480,39 @@ static void get_sysreg_prop(Object *obj, Visitor *v,
>> trace_get_sysreg_prop(name, value);
>> }
>>
>> -/*
>> - * decode_idreg_writemap: Generate props for writable fields
>> - *
>> - * @obj: CPU object
>> - * @reg: description of the sysreg
>> - */
>> -static int
>> -decode_idreg_writemap(Object *obj, ARM64SysReg *reg)
>> +static void
>> +add_idreg_field_properties(Object *obj, ARM64SysReg *reg)
>> {
>> - uint64_t map = reg->writable_mask;
>> - int i = ctz64(map);
>> int nb_sysreg_props = 0;
>>
>> - while (map) {
>> - ARM64SysRegField *field = get_field(i, reg);
>> - int lower, upper;
>> - char *prop_name;
>> - uint64_t field_mask;
>> -
>> - if (!field) {
>> - warn_report("%s bit %d of %s is writable but no named field "
>> - "in target/arm/cpu-idregs.h.inc",
>> - __func__, i, reg->name);
>> - map = map & ~BIT_ULL(i);
>> - i = ctz64(map);
>> - continue;
>> - }
>> - lower = field->shift;
>> - upper = field->shift + field->length - 1;
>> -
>> - /* Sanity check the field is not a reserved field */
>> - if (strstr(field->name, "RES0") || strstr(field->name, "RES1") ||
>> - strstr(field->name, "RAZ")) {
>> - trace_unexpected_writable_reserved_field(reg->name, field->name,
>> - lower, upper);
>> + for (int i = 0; i < reg->fields_count; i++) {
>> + ARM64SysRegField *field = ®->fields[i];
> I agree this implementation is simpler than mine scanning the writable
> bitmask. I will move to that. I think I will add an other operating mode
> that checks the writable_mask too. That way the function may be able to
> generate props only for writable fields (including some consistency
> checks), or for non writable fields
>
Noted.
Thanks,
Khushit
> Thanks
>
> Eric
>> +
>> + /* skip reserved fields */
>> + if (g_str_equal(field->name, "RES0") ||
>> + g_str_equal(field->name, "RES1") ||
>> + g_str_equal(field->name, "RAZ")) {
>> continue;
>> }
>> - prop_name = g_strdup_printf("SYSREG_%s_%s", reg->name, field->name);
>> - trace_decode_idreg_writemap(field->name, lower, upper, prop_name);
>> +
>> + char *prop_name = g_strdup_printf("SYSREG_%s_%s", reg->name,
>> + field->name);
>> object_property_add(obj, prop_name, "uint64",
>> get_sysreg_prop, set_sysreg_prop, NULL, field);
>> g_free(prop_name);
>> nb_sysreg_props++;
>> -
>> - field_mask = MAKE_64BIT_MASK(lower, field->length);
>> - map = map & ~field_mask;
>> - i = ctz64(map);
>> }
>> +
>> trace_nb_sysreg_props(reg->name, nb_sysreg_props);
>> - return 0;
>> }
>>
>> -/* analyze the writable mask and generate properties for writable fields */
>> void kvm_arm_expose_idreg_properties(ARMCPU *cpu, ARM64SysReg *regs)
>> {
>> Object *obj = OBJECT(cpu);
>>
>> for (int i = 0; i < NUM_ID_IDX; i++) {
>> ARM64SysReg *sysregdesc = ®s[i];
>> -
>> - if (sysregdesc->writable_mask) {
>> - decode_idreg_writemap(obj, sysregdesc);
>> - }
>> + add_idreg_field_properties(obj, sysregdesc);
>> }
>> }
>>
>> diff --git a/target/arm/trace-events b/target/arm/trace-events
>> index 71a2f5770c..7696a8ed40 100644
>> --- a/target/arm/trace-events
>> +++ b/target/arm/trace-events
>> @@ -15,11 +15,9 @@ arm_gt_update_irq(int timer, int irqstate) "gt_update_irq: timer %d irqstate %d"
>> kvm_arm_fixup_msi_route(uint64_t iova, uint64_t gpa) "MSI iova = 0x%"PRIx64" is translated into 0x%"PRIx64
>> get_host_cpu_idregs(const char *name, uint64_t value) "scratch vcpu host value for %s is 0x%"PRIx64
>> kvm_arm_writable_idregs_to_cpreg_list(const char *name, uint64_t previous, uint64_t new) "%s overwrite default 0x%"PRIx64" with 0x%"PRIx64
>> -decode_idreg_writemap(const char* name, int lower, int upper, char *prop_name) "%s [%d:%d] is writable (prop %s)"
>> get_sysreg_prop(const char *name, uint64_t value) "%s 0x%"PRIx64
>> set_sysreg_prop(const char *name, uint64_t old, uint64_t mask, uint64_t field_value, uint64_t new) "%s old reg value=0x%"PRIx64" mask=0x%"PRIx64" new field value=0x%"PRIx64" new reg value=0x%"PRIx64
>> nb_sysreg_props(const char *name, int count) "%s: %d SYSREG properties"
>> -unexpected_writable_reserved_field(const char *reg_name, const char *field_name, int lower, int upper) "Unexpected writable reserved field: %s.%s [%d,%d], skip it ..."
>> kvm_idreg_write_scratch_vcpu(const char *name, uint64_t oldfv, uint64_t newfv, uint64_t actualfv) "successful dry-run for %s old=0x%"PRIx64" new=0x%"PRIx64" actual=0x%"PRIx64
>>
>> # cpu.c
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH v4 03/25] target/arm: move SYSREG_ prop infra to cpu64.c
2026-09-24 6:54 ` Eric Auger
@ 2026-09-29 12:56 ` Khushit Shah
0 siblings, 0 replies; 66+ messages in thread
From: Khushit Shah @ 2026-09-29 12:56 UTC (permalink / raw)
To: eric.auger@redhat.com
Cc: qemu-devel@nongnu.org, qemu-arm@nongnu.org,
kvmarm@lists.linux.dev, cohuck@redhat.com,
peter.maydell@linaro.org, richard.henderson@linaro.org,
maz@kernel.org, oliver.upton@linux.dev, berrange@redhat.com,
abologna@redhat.com, jdenemar@redhat.com, gshan@redhat.com,
skolothumtho@nvidia.com, sebott@redhat.com, armbru@redhat.com,
philmd@linaro.org, yangjinqian1@huawei.com, Shaju Abraham,
Mark Cave-Ayland, ping@khushitshah.com, Sandesh Patel
> On 24 Sep 2026, at 12:24 PM, Eric Auger <eric.auger@redhat.com> wrote:
>
> !-------------------------------------------------------------------|
> CAUTION: External Email
>
> |-------------------------------------------------------------------!
>
>
>
> On 9/21/26 2:32 PM, Khushit Shah wrote:
>> kvm_arm_expose_idreg_properties() no longer depends on KVM-specific
>> logic. Move it to cpu64.c as aarch64_add_idregs_properties() along with
>> all SYSREG_ property infra, making it accelerator-agnostic.
> Even before, the code had no real kvm adherence, I mean even if we keep
> reg->writable_mask checks. This latter could be populated with another
> accelerator. So I think I can move in this direction in the parent series.
Makes sense.
Thanks,
Khushit
>
> Eric
>>
>> Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
>> ---
>> target/arm/cpu64.c | 101 +++++++++++++++++++++++++++++++++++++++-
>> target/arm/internals.h | 1 +
>> target/arm/kvm.c | 100 ---------------------------------------
>> target/arm/kvm_arm.h | 10 ----
>> target/arm/trace-events | 4 +-
>> 5 files changed, 104 insertions(+), 112 deletions(-)
>>
>> diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
>> index 3d522bf20d..7487b48cc9 100644
>> --- a/target/arm/cpu64.c
>> +++ b/target/arm/cpu64.c
>> @@ -38,6 +38,7 @@
>> #include "internals.h"
>> #include "cpu-features.h"
>> #include "cpu-idregs.h"
>> +#include "trace.h"
>>
>> /* convert between <register>_IDX and SYS_<register> */
>> #define DEF(NAME, OP0, OP1, CRN, CRM, OP2) \
>> @@ -644,6 +645,104 @@ static const Property arm_cpu_pauth_qarma3_property =
>> static Property arm_cpu_pauth_qarma5_property =
>> DEFINE_PROP_BOOL("pauth-qarma5", ARMCPU, prop_pauth_qarma5, false);
>>
>> +#ifndef CONFIG_USER_ONLY
>> +static void set_sysreg_prop(Object *obj, Visitor *v,
>> + const char *name, void *opaque,
>> + Error **errp)
>> +{
>> + ARM64SysRegField *field = (ARM64SysRegField *)opaque;
>> + ARMCPU *cpu = ARM_CPU(obj);
>> + uint64_t *idregs = cpu->isar.idregs;
>> + uint64_t old, value, mask;
>> + int lower = field->shift;
>> + int length = field->length;
>> + int index = field->index;
>> +
>> + if (!visit_type_uint64(v, name, &value, errp)) {
>> + return;
>> + }
>> +
>> + if (length < 64 && value > ((1 << length) - 1)) {
>> + error_setg(errp,
>> + "idreg %s set value (0x%lx) exceeds length of field (%d)!",
>> + name, value, length);
>> + return;
>> + }
>> +
>> + if (field->arch_vals) {
>> + /* this field has some enum values */
>> + for (int i = 0; i < field->arch_vals_count; i++) {
>> + if (value == field->arch_vals[i]) {
>> + goto valid;
>> + }
>> + }
>> + error_setg(errp,
>> + "idreg %s set value (0x%lx) does not match any "
>> + "arch valid enum value", name, value);
>> + return;
>> + }
>> +
>> +valid:
>> +
>> + mask = MAKE_64BIT_MASK(lower, length);
>> + value = value << lower;
>> + old = idregs[index];
>> + idregs[index] = old & ~mask;
>> + idregs[index] |= value;
>> + trace_set_sysreg_prop(name, old, mask, value, idregs[index]);
>> +}
>> +
>> +static void get_sysreg_prop(Object *obj, Visitor *v,
>> + const char *name, void *opaque,
>> + Error **errp)
>> +{
>> + ARM64SysRegField *field = (ARM64SysRegField *)opaque;
>> + ARMCPU *cpu = ARM_CPU(obj);
>> + uint64_t *idregs = cpu->isar.idregs;
>> + uint64_t value, mask;
>> + int lower = field->shift;
>> + int length = field->length;
>> + int index = field->index;
>> +
>> + mask = MAKE_64BIT_MASK(lower, length);
>> + value = (idregs[index] & mask) >> lower;
>> + visit_type_uint64(v, name, &value, errp);
>> + trace_get_sysreg_prop(name, value);
>> +}
>> +
>> +static void add_idregs_properties(Object *obj, ARM64SysReg *reg)
>> +{
>> + int nb_sysreg_props = 0;
>> +
>> + for (int i = 0; i < reg->fields_count; i++) {
>> + ARM64SysRegField *field = ®->fields[i];
>> +
>> + /* skip reserved fields */
>> + if (g_str_equal(field->name, "RES0") ||
>> + g_str_equal(field->name, "RES1") ||
>> + g_str_equal(field->name, "RAZ")) {
>> + continue;
>> + }
>> +
>> + char *prop_name = g_strdup_printf("SYSREG_%s_%s", reg->name,
>> + field->name);
>> + object_property_add(obj, prop_name, "uint64",
>> + get_sysreg_prop, set_sysreg_prop, NULL, field);
>> + g_free(prop_name);
>> + nb_sysreg_props++;
>> + }
>> +
>> + trace_nb_sysreg_props(reg->name, nb_sysreg_props);
>> +}
>> +
>> +void aarch64_add_idregs_properties(Object *obj)
>> +{
>> + for (int i = 0; i < NUM_ID_IDX; i++) {
>> + add_idregs_properties(obj, &arm64_id_regs[i]);
>> + }
>> +}
>> +#endif
>> +
>> void aarch64_add_pauth_properties(Object *obj)
>> {
>> ARMCPU *cpu = ARM_CPU(obj);
>> @@ -810,7 +909,7 @@ void aarch64_host_initfn(Object *obj)
>> aarch64_add_sve_properties(obj);
>>
>> /* generate SYSREG properties */
>> - kvm_arm_expose_idreg_properties(cpu, arm64_id_regs);
>> + aarch64_add_idregs_properties(obj);
>>
>> #elif defined(CONFIG_HVF)
>> hvf_arm_set_cpu_features_from_host(cpu);
>> diff --git a/target/arm/internals.h b/target/arm/internals.h
>> index f6b4e173a5..7c76ffea7d 100644
>> --- a/target/arm/internals.h
>> +++ b/target/arm/internals.h
>> @@ -1813,6 +1813,7 @@ void aarch64_max_tcg_initfn(Object *obj);
>> void aarch64_add_pauth_properties(Object *obj);
>> void aarch64_add_sve_properties(Object *obj);
>> void aarch64_add_sme_properties(Object *obj);
>> +void aarch64_add_idregs_properties(Object *obj);
>> void aarch64_aa32_a57_init(ARMCPU *cpu, bool aa64_enabled);
>> void aarch64_host_initfn(Object *obj);
>>
>> diff --git a/target/arm/kvm.c b/target/arm/kvm.c
>> index 2f6c090e43..d5155a3706 100644
>> --- a/target/arm/kvm.c
>> +++ b/target/arm/kvm.c
>> @@ -416,106 +416,6 @@ bool kvm_idreg_write_scratch_vcpu(int cpufd, Visitor *v, const char *name,
>> return true;
>> }
>>
>> -static void set_sysreg_prop(Object *obj, Visitor *v,
>> - const char *name, void *opaque,
>> - Error **errp)
>> -{
>> - ARM64SysRegField *field = (ARM64SysRegField *)opaque;
>> - ARMCPU *cpu = ARM_CPU(obj);
>> - uint64_t *idregs = cpu->isar.idregs;
>> - uint64_t old, value, mask;
>> - int lower = field->shift;
>> - int length = field->length;
>> - int index = field->index;
>> -
>> - if (!visit_type_uint64(v, name, &value, errp)) {
>> - return;
>> - }
>> -
>> - if (length < 64 && value > ((1 << length) - 1)) {
>> - error_setg(errp,
>> - "idreg %s set value (0x%lx) exceeds length of field (%d)!",
>> - name, value, length);
>> - return;
>> - }
>> -
>> - if (field->arch_vals) {
>> - /* this field has some enum values */
>> - for (int i = 0; i < field->arch_vals_count; i++) {
>> - if (value == field->arch_vals[i]) {
>> - goto valid;
>> - }
>> - }
>> - error_setg(errp,
>> - "idreg %s set value (0x%lx) does not match any "
>> - "arch valid enum value", name, value);
>> - return;
>> - }
>> -
>> -valid:
>> -
>> - mask = MAKE_64BIT_MASK(lower, length);
>> - value = value << lower;
>> - old = idregs[index];
>> - idregs[index] = old & ~mask;
>> - idregs[index] |= value;
>> - trace_set_sysreg_prop(name, old, mask, value, idregs[index]);
>> -}
>> -
>> -static void get_sysreg_prop(Object *obj, Visitor *v,
>> - const char *name, void *opaque,
>> - Error **errp)
>> -{
>> - ARM64SysRegField *field = (ARM64SysRegField *)opaque;
>> - ARMCPU *cpu = ARM_CPU(obj);
>> - uint64_t *idregs = cpu->isar.idregs;
>> - uint64_t value, mask;
>> - int lower = field->shift;
>> - int length = field->length;
>> - int index = field->index;
>> -
>> - mask = MAKE_64BIT_MASK(lower, length);
>> - value = (idregs[index] & mask) >> lower;
>> - visit_type_uint64(v, name, &value, errp);
>> - trace_get_sysreg_prop(name, value);
>> -}
>> -
>> -static void
>> -add_idreg_field_properties(Object *obj, ARM64SysReg *reg)
>> -{
>> - int nb_sysreg_props = 0;
>> -
>> - for (int i = 0; i < reg->fields_count; i++) {
>> - ARM64SysRegField *field = ®->fields[i];
>> -
>> - /* skip reserved fields */
>> - if (g_str_equal(field->name, "RES0") ||
>> - g_str_equal(field->name, "RES1") ||
>> - g_str_equal(field->name, "RAZ")) {
>> - continue;
>> - }
>> -
>> - char *prop_name = g_strdup_printf("SYSREG_%s_%s", reg->name,
>> - field->name);
>> - object_property_add(obj, prop_name, "uint64",
>> - get_sysreg_prop, set_sysreg_prop, NULL, field);
>> - g_free(prop_name);
>> - nb_sysreg_props++;
>> - }
>> -
>> - trace_nb_sysreg_props(reg->name, nb_sysreg_props);
>> -}
>> -
>> -void kvm_arm_expose_idreg_properties(ARMCPU *cpu, ARM64SysReg *regs)
>> -{
>> - Object *obj = OBJECT(cpu);
>> -
>> - for (int i = 0; i < NUM_ID_IDX; i++) {
>> - ARM64SysReg *sysregdesc = ®s[i];
>> - add_idreg_field_properties(obj, sysregdesc);
>> - }
>> -}
>> -
>> static void
>> kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
>> {
>> diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h
>> index aafb3cd232..997120966f 100644
>> --- a/target/arm/kvm_arm.h
>> +++ b/target/arm/kvm_arm.h
>> @@ -163,16 +163,6 @@ void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu);
>> */
>> void kvm_arm_add_vcpu_properties(ARMCPU *cpu);
>>
>> -typedef struct ARM64SysReg ARM64SysReg;
>> -/**
>> - * kvm_arm_expose_idreg_properties:
>> - * @cpu: The CPU object to generate the properties for
>> - * @reg: registers from the host
>> - *
>> - * analyze the writable mask and generate properties for writable fields
>> - */
>> -void kvm_arm_expose_idreg_properties(ARMCPU *cpu, ARM64SysReg *regs);
>> -
>> /**
>> * kvm_arm_steal_time_finalize:
>> * @cpu: ARMCPU for which to finalize kvm-steal-time
>> diff --git a/target/arm/trace-events b/target/arm/trace-events
>> index 7696a8ed40..bbf2e5dfa2 100644
>> --- a/target/arm/trace-events
>> +++ b/target/arm/trace-events
>> @@ -15,10 +15,12 @@ arm_gt_update_irq(int timer, int irqstate) "gt_update_irq: timer %d irqstate %d"
>> kvm_arm_fixup_msi_route(uint64_t iova, uint64_t gpa) "MSI iova = 0x%"PRIx64" is translated into 0x%"PRIx64
>> get_host_cpu_idregs(const char *name, uint64_t value) "scratch vcpu host value for %s is 0x%"PRIx64
>> kvm_arm_writable_idregs_to_cpreg_list(const char *name, uint64_t previous, uint64_t new) "%s overwrite default 0x%"PRIx64" with 0x%"PRIx64
>> +kvm_idreg_write_scratch_vcpu(const char *name, uint64_t oldfv, uint64_t newfv, uint64_t actualfv) "successful dry-run for %s old=0x%"PRIx64" new=0x%"PRIx64" actual=0x%"PRIx64
>> +
>> +# cpu64.c
>> get_sysreg_prop(const char *name, uint64_t value) "%s 0x%"PRIx64
>> set_sysreg_prop(const char *name, uint64_t old, uint64_t mask, uint64_t field_value, uint64_t new) "%s old reg value=0x%"PRIx64" mask=0x%"PRIx64" new field value=0x%"PRIx64" new reg value=0x%"PRIx64
>> nb_sysreg_props(const char *name, int count) "%s: %d SYSREG properties"
>> -kvm_idreg_write_scratch_vcpu(const char *name, uint64_t oldfv, uint64_t newfv, uint64_t actualfv) "successful dry-run for %s old=0x%"PRIx64" new=0x%"PRIx64" actual=0x%"PRIx64
>>
>> # cpu.c
>> arm_cpu_reset(uint64_t mp_aff) "cpu %" PRIu64
>
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH v4 08/25] target/arm/kvm: handle writeback for special ID register fields
2026-09-24 9:57 ` Eric Auger
2026-09-24 10:21 ` Khushit Shah
@ 2026-09-29 13:09 ` Khushit Shah
1 sibling, 0 replies; 66+ messages in thread
From: Khushit Shah @ 2026-09-29 13:09 UTC (permalink / raw)
To: eric.auger@redhat.com
Cc: qemu-devel@nongnu.org, qemu-arm@nongnu.org,
kvmarm@lists.linux.dev, cohuck@redhat.com,
peter.maydell@linaro.org, richard.henderson@linaro.org,
maz@kernel.org, oliver.upton@linux.dev, berrange@redhat.com,
abologna@redhat.com, jdenemar@redhat.com, gshan@redhat.com,
skolothumtho@nvidia.com, sebott@redhat.com, armbru@redhat.com,
philmd@linaro.org, yangjinqian1@huawei.com, Shaju Abraham,
Mark Cave-Ayland, ping@khushitshah.com, Sandesh Patel
> On 24 Sep 2026, at 3:27 PM, Eric Auger <eric.auger@redhat.com> wrote:
>
> !-------------------------------------------------------------------|
> CAUTION: External Email
>
> |-------------------------------------------------------------------!
>
>
>
> On 9/21/26 2:32 PM, Khushit Shah wrote:
>> Some fields should not be written back to KVM for various reasons:
>> - ID_AA64PFR0_EL1.GIC / ID_PFR1_EL1.GIC are fabricated by KVM based on
>> the gic-version property.
>> - KVM does not allow writing 0 to ID_DFR0_EL1.CopDbg, which breaks
>> booting an AArch64-only guest on a host that also supports AArch32.
>> - ID_DFR0_EL1.PerfMon is populated by KVM even for AArch64-only guests
>> but is not writable there.
>> - MPIDR_EL1 is managed by KVM based on vCPU index.
>> - Hold off writing back CLIDR_EL1 until we properly support exposing
>> cache topology to a KVM guest.
>>
>> Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
>> ---
>> target/arm/cpu-idregs.c | 6 ++++++
>> target/arm/cpu-idregs.h | 2 ++
>> target/arm/kvm.c | 40 +++++++++++++++++++++++++++++++++++++++-
>> 3 files changed, 47 insertions(+), 1 deletion(-)
>>
>> diff --git a/target/arm/cpu-idregs.c b/target/arm/cpu-idregs.c
>> index d58b8ed063..1f7ebfe9bb 100644
>> --- a/target/arm/cpu-idregs.c
>> +++ b/target/arm/cpu-idregs.c
>> @@ -107,3 +107,9 @@ bool arm_field_is_writable(const ARM64SysRegField *field)
>> return (arm64_id_regs[field->index].writable_mask & field_mask)
>> == field_mask;
>> }
>> +
>> +bool field_matches(const ARM64SysRegField *field, ARMIDRegisterIdx index,
>> + const char *name)
>> +{
>> + return field->index == index && !strcmp(field->name, name);
>> +}
>> diff --git a/target/arm/cpu-idregs.h b/target/arm/cpu-idregs.h
>> index aab1a79db1..8ef3f9350e 100644
>> --- a/target/arm/cpu-idregs.h
>> +++ b/target/arm/cpu-idregs.h
>> @@ -35,4 +35,6 @@ extern ARM64SysReg arm64_id_regs[NUM_ID_IDX];
>>
>> uint64_t arm_get_field_mask(const ARM64SysRegField *field);
>> bool arm_field_is_writable(const ARM64SysRegField *field);
>> +bool field_matches(const ARM64SysRegField *field, ARMIDRegisterIdx index,
>> + const char *name);
>> #endif
>> diff --git a/target/arm/kvm.c b/target/arm/kvm.c
>> index 2d94b3a884..70d9a07580 100644
>> --- a/target/arm/kvm.c
>> +++ b/target/arm/kvm.c
>> @@ -1317,10 +1317,40 @@ bool kvm_arm_cpu_post_load(ARMCPU *cpu)
>> return true;
>> }
>>
>> +static bool arm_field_skip_writeback_always(const ARM64SysRegField *field)
>> +{
>> + /*
>> + * GIC is controlled by the gic-version property and fabricated by KVM
>> + * when the vGIC device is created, so a named CPU model must not touch
>> + * it. KVM also rejects writing 0 to ID_DFR0_EL1.CopDbg, which breaks
>> + * booting a model that lacks AArch32 support on a host that supports
>> + * it. MPIDR_EL1 is managed by KVM based on vCPU index, skip writing it
>> + * back. Similarly, skip writing back CLIDR_EL1 till we properly
>> + * support exposing cache for KVM guest.
>> + */
>> + return field_matches(field, ID_AA64PFR0_EL1_IDX, "GIC")
>> + || field_matches(field, ID_PFR1_EL1_IDX, "GIC")
>> + || field_matches(field, ID_DFR0_EL1_IDX, "CopDbg")
>> + || field->index == MPIDR_EL1_IDX
>> + || field->index == CLIDR_EL1_IDX;
>
> what does happen for SMIDR_EL1 and GMID_EL1 whose value could not be
> initialized from host. The setter for any of their field shall fail.
Yep, this will fail during write back.
>> +}
>> +
>> +static bool
>> +arm_field_skip_writeback_if_not_writable(const ARM64SysRegField *field)
>> +{
>> + /*
>> + * KVM populates ID_DFR0_EL1.PerfMon even for AArch64-only guests but
>> + * does not expose it as writable there, so skip it when it is not
>> + * writable.
>> + */
>> + return field_matches(field, ID_DFR0_EL1_IDX, "PerfMon");
>> +}
>> +
>> /*
>> * Copy writable ID reg fields from isar.idregs[] into the KVM cpreg list,
>> * so the subsequent write_list_to_kvmstate() pushes them to KVM.
>> - * Only writable fields are copied.
>> + * Only writable fields are copied; fields that must not be written back
>> + * (see arm_field_skip_writeback_*) are skipped.
>> * Returns -1 if any vCPU's ID reg value differs from the host value and the
>> * field is not writable.
>> */
>> @@ -1357,6 +1387,14 @@ static int kvm_arm_write_idregs_to_cpreg_list(ARMCPU *cpu)
>> continue;
>> }
>>
>> + if (arm_field_skip_writeback_always(field) ||
>> + (!arm_field_is_writable(field) &&
>> + arm_field_skip_writeback_if_not_writable(field))) {
>> + /* Never write this field back; keep KVM's value. */
>> + writable_mask &= ~field_mask;
>> + continue;
>> + }
>> +
>> if (!arm_field_is_writable(field)) {
>> error_report("%s.%s is not writable: host=0x%" PRIx64
>> ", requested=0x%" PRIx64,
> v9 has changed the way new field values are stored. writable field props
> and non writable field props could have different setters. A non
> writable field setter just needs to check the new value is the same as
> the current host value. No need to record the new value in the hashtable
> for further commitment.
I don’t like the idea of different setters. I will not expose fields which
conflicts with legacy options like GPA/APA which conflicts with pauth.
But we do lose some introspectability with this option.
Thanks,
Khushit
>
> Eric
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH v4 09/25] target/arm: introduce named CPU model infrastructure
2026-09-24 13:35 ` Eric Auger
@ 2026-09-29 13:40 ` Khushit Shah
0 siblings, 0 replies; 66+ messages in thread
From: Khushit Shah @ 2026-09-29 13:40 UTC (permalink / raw)
To: eric.auger@redhat.com
Cc: qemu-devel@nongnu.org, qemu-arm@nongnu.org,
kvmarm@lists.linux.dev, cohuck@redhat.com,
peter.maydell@linaro.org, richard.henderson@linaro.org,
maz@kernel.org, oliver.upton@linux.dev, berrange@redhat.com,
abologna@redhat.com, jdenemar@redhat.com, gshan@redhat.com,
skolothumtho@nvidia.com, sebott@redhat.com, armbru@redhat.com,
philmd@linaro.org, yangjinqian1@huawei.com, Shaju Abraham,
Mark Cave-Ayland, ping@khushitshah.com, Sandesh Patel
> On 24 Sep 2026, at 7:05 PM, Eric Auger <eric.auger@redhat.com> wrote:
>
> !-------------------------------------------------------------------|
> CAUTION: External Email
>
> |-------------------------------------------------------------------!
>
> Hi Khushit,
>
> On 9/21/26 2:32 PM, Khushit Shah wrote:
>> Add scaffolding for named CPU models on Arm on top of the property
>> layer. A model is a list of (property, value) overrides plus an
>> optional parent; a child inherits its parent's property values and may
>> override them.
>>
>> Instance init steps:
>> - host feature discovery.
>> - zero out isar.idregs[] and restore RES1 fields.
>> - install SYSREG_ and sve* properties.
>> - walk the parent chain root-first and apply each level's
>> properties.
> you should explain about prop types. I see they are either bool or uint.
> Given the parent series bool usage is not obvious.
Hi Eric,
Thinking about this more, the current approach will require some tweaking now
as the underlying property infrastructure now sets the property values after
the vCPU has been created.
Some of the fields that the model defines (SVE/PAUTH) determines the vCPU init
flags.
Your suggestion of different setters is the way to go here :)
>> This assumes that each property is idempotent. `pauth` is intentionally
>> not installed because the model's ID register view is authoritative
>> and can be configured through SYSREG_ properties.
>>
>> No models are defined yet.
>>
>> Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
>> ---
>> target/arm/cpu-models.c | 191 ++++++++++++++++++++++++++++++++++++++++
>> target/arm/cpu-models.h | 36 ++++++++
>> target/arm/meson.build | 1 +
>> 3 files changed, 228 insertions(+)
>> create mode 100644 target/arm/cpu-models.c
>> create mode 100644 target/arm/cpu-models.h
>>
>> diff --git a/target/arm/cpu-models.c b/target/arm/cpu-models.c
>> new file mode 100644
>> index 0000000000..fed3197186
>> --- /dev/null
>> +++ b/target/arm/cpu-models.c
>> @@ -0,0 +1,191 @@
>> +/*
>> + * ARM named CPU models.
>> + *
>> + * Each model is defined as an array of MODEL_PROP macros, listing only
>> + * the properties that DIFFER from the parent model.
>> + *
>> + * Initialization starts with a zeroed idregs[] array.
>> + *
>> + * During initialization, the parent chain is walked root-first and every
>> + * level's properties are applied via QOM, so the leaf's values naturally
>> + * override its ancestors.
>> + *
>> + * Assumptions:
>> + * - All named CPU model properties are idempotent.
>> + *
>> + * SPDX-License-Identifier: GPL-2.0-or-later
>> + */
>> +
>> +#include "qemu/osdep.h"
>> +#include "qapi/error.h"
>> +#include "qemu/error-report.h"
>> +#include "system/kvm.h"
>> +#include "cpu.h"
>> +#include "internals.h"
>> +#include "kvm_arm.h"
>> +#include "cpu-idregs.h"
>> +#include "cpu-models.h"
>> +
>> +#define MODEL_PROP_FIELD_STR str
>> +#define MODEL_PROP_FIELD_BOOL b
>> +#define MODEL_PROP_FIELD_NUM num
>> +
>> +#define MODEL_PROP(_name, _type, _value) \
>> + { .name = (_name), .type = ARM_MODEL_PROP_##_type, \
>> + .u.MODEL_PROP_FIELD_##_type = (_value) }
>> +
>> +#define MODEL_PROP_END { .name = NULL }
>> +
>> +/* Maximum parent-chain depth for named CPU models. */
> inheritence depth?
Yes, will fix.
>> +#define ARM_NAMED_CPU_MODEL_MAX_DEPTH 16
>> +
>> +static const ArmNamedCpuModel arm_cpu_models[] = {
>> + {NULL, NULL, NULL}
>> +};
>> +
>> +const ArmNamedCpuModel *arm_find_model(const char *name)
>> +{
>> + for (size_t i = 0; i < ARRAY_SIZE(arm_cpu_models); i++) {
>> + if (!arm_cpu_models[i].name) {
>> + break;
>> + }
>> +
>> + if (g_str_equal(arm_cpu_models[i].name, name)) {
>> + return &arm_cpu_models[i];
>> + }
>> + }
>> + return NULL;
>> +}
>> +
>> +void arm_apply_model_props(Object *obj, const ArmModelPropValue *props,
>> + Error **errp)
>> +{
>> + const ArmModelPropValue *pv;
>> + ERRP_GUARD();
>> +
>> + for (pv = props; pv->name; pv++) {
>> + switch (pv->type) {
>> + case ARM_MODEL_PROP_BOOL:
>> + object_property_set_bool(obj, pv->name, pv->u.b, errp);
>> + break;
>> + case ARM_MODEL_PROP_NUM:
>> + object_property_set_uint(obj, pv->name, pv->u.num, errp);
>> + break;
>> + default:
>> + g_assert_not_reached();
>> + }
>> +
>> + if (*errp) {
>> + error_prepend(errp, "property '%s': ", pv->name);
>> + return;
>> + }
>> + }
>> +}
>> +
>> +void arm_realize_model_chain(Object *obj, const ArmNamedCpuModel *model,
>> + Error **errp)
>> +{
>> + const ArmNamedCpuModel *cur, *parent;
>> + const ArmNamedCpuModel *chain[ARM_NAMED_CPU_MODEL_MAX_DEPTH];
>> + size_t depth = 0;
>> +
>> + for (cur = model; cur; ) {
>> + if (depth >= ARRAY_SIZE(chain)) {
>> + error_setg(errp, "model '%s': parent chain too deep", model->name);
>> + return;
>> + }
>> + chain[depth++] = cur;
> Please add a comment about the so-called chain and especially describing
> that chain[0] is the child and high-level eindex lements are the parents
> it derives from.
Will do.
>> +
>> + if (!cur->parent) {
>> + break;
>> + }
>> + parent = arm_find_model(cur->parent);
> I guess you directly assert
Okay.
>> + if (!parent) {
>> + error_setg(errp, "model '%s': unknown parent '%s'", cur->name,
>> + cur->parent);
>> + return;
>> + }
>> + cur = parent;
>> + }
>> +
>> + while (depth--) {
>> + arm_apply_model_props(obj, chain[depth]->props, errp);
>> + if (*errp) {
>> + return;
>> + }
>> + }
>> +}
>> +
>> +static void reset_res1_fields(ARMCPU *cpu)
>> +{
>> + for (size_t i = 0; i < NUM_ID_IDX; i++) {
>> + for (size_t j = 0; j < arm64_id_regs[i].fields_count; j++) {
>> + if (strcmp(arm64_id_regs[i].fields[j].name, "RES1") == 0) {
>> + cpu->isar.idregs[i] = deposit64(cpu->isar.idregs[i],
>> + arm64_id_regs[i].fields[j].shift,
>> + arm64_id_regs[i].fields[j].length,
>> + MAKE_64BIT_MASK(0, arm64_id_regs[i].fields[j].length));
>> + }
>> + }
>> + }
>> +}
>> +
>> +static void arm_named_cpu_initfn(Object *obj)
>> +{
>> + ARMCPU *cpu = ARM_CPU(obj);
>> + ARMCPUClass *acc = ARM_CPU_GET_CLASS(obj);
>> + const ArmNamedCpuModel *model = arm_find_model(acc->info->name);
>> +
>> + if (!model) {
>> + error_report("'%s' CPU model entry not found",
>> + acc->info->name);
>> + return;
>> + }
>> +
>> + if (!kvm_enabled()) {
>> + error_report("'%s' CPU model requires KVM (-accel kvm)",
>> + acc->info->name);
>> + return;
>> + }
>> +
>> + kvm_arm_set_cpu_features_from_host(cpu);
>> + if (!arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) {
>> + return;
>> + }
>> +
>> + /* 1.a Reset ID regs to 0 */
>> + memset(cpu->isar.idregs, 0, sizeof(cpu->isar.idregs));
>> +
>> + /* 1.b Properly set RES1 fields. */
>> + reset_res1_fields(cpu);
>> +
>> + /* 2. Add sveNNNN and SYSREG_ properties */
>> + aarch64_add_sve_properties(obj);
>> + aarch64_add_idregs_properties(obj);
> Can you give more explanations about why we don't have
> aarch64_add_pauth_properties()
> kvm_arm_set_cpreg_mig_tolerances()
Haven’t looked into kvm_arm_set_cpreg_mig_tolerances(), will do.
>
> at least.
>
> By the way it is not clear what will become legacy compositive options
> with named vcpu models. I see you keep sve but what about the others.
As now your series handles the conflicts… I will take similar approach,
user will not have two ways to set the same settings.
>> +
>> + /* 3. Realize the model chain. */
>> + arm_realize_model_chain(obj, model, &error_abort);
>> +}
>> +
>> +void arm_register_named_cpu_models(void)
>> +{
>> + static ARMCPUInfo *arm_named_cpu_infos;
>> + size_t i, n = ARRAY_SIZE(arm_cpu_models);
>> +
>> + if (!n) {
>> + return;
>> + }
>> +
>> + arm_named_cpu_infos = g_new0(ARMCPUInfo, n);
>> + for (i = 0; i < n; i++) {
>> + if (!arm_cpu_models[i].name) {
>> + break;
>> + }
>> +
>> + arm_named_cpu_infos[i].name = arm_cpu_models[i].name;
>> + arm_named_cpu_infos[i].initfn = arm_named_cpu_initfn;
>> + arm_cpu_register(&arm_named_cpu_infos[i]);
>> + }
>> +}
>> +
>> +type_init(arm_register_named_cpu_models)
>> diff --git a/target/arm/cpu-models.h b/target/arm/cpu-models.h
>> new file mode 100644
>> index 0000000000..144778744e
>> --- /dev/null
>> +++ b/target/arm/cpu-models.h
>> @@ -0,0 +1,36 @@
>> +/* SPDX-License-Identifier: GPL-2.0-or-later */
>> +#ifndef ARM_CPU_MODELS_H
>> +#define ARM_CPU_MODELS_H
>> +
>> +#include "qapi/error.h"
>> +#include "qom/object.h"
>> +
>> +typedef enum ArmModelPropType {
>> + ARM_MODEL_PROP_BOOL,
>> + ARM_MODEL_PROP_NUM,
>> +} ArmModelPropType;
>> +
>> +typedef struct ArmModelPropValue {
>> + const char *name;
>> + ArmModelPropType type;
>> + union {
>> + bool b;
>> + uint64_t num;
>> + } u;
>> +} ArmModelPropValue;
>> +
>> +typedef struct ArmNamedCpuModel {
>> + const char *name;
>> + const char *parent;
> any reason why you don't point to the patent ArmNamedCpuModel pointer
> instead?
No specific reason, will change to ArmNamedCpuModel pointer.
Thanks,
Khushit
>> + const ArmModelPropValue *props;
>> +} ArmNamedCpuModel;
>> +
>> +void arm_register_named_cpu_models(void);
>> +
>> +const ArmNamedCpuModel *arm_find_model(const char *name);
>> +void arm_apply_model_props(Object *obj, const ArmModelPropValue *props,
>> + Error **errp);
>> +void arm_realize_model_chain(Object *obj, const ArmNamedCpuModel *model,
>> + Error **errp);
>> +
>> +#endif /* ARM_CPU_MODELS_H */
>> diff --git a/target/arm/meson.build b/target/arm/meson.build
>> index 384d90c530..dd28146c52 100644
>> --- a/target/arm/meson.build
>> +++ b/target/arm/meson.build
>> @@ -32,6 +32,7 @@ arm_common_system_ss.add(files(
>> 'arm-qmp-cmds.c',
>> 'cpu-idregs.c',
>> ))
>> +arm_system_ss.add(when: 'TARGET_AARCH64', if_true: files('cpu-models.c'))
>> arm_system_ss.add(when: 'CONFIG_KVM', if_true: files('hyp_gdbstub.c', 'kvm.c'))
>> arm_system_ss.add(when: 'CONFIG_HVF', if_true: files('hyp_gdbstub.c'))
>>
> Eric
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH v4 18/25] target/arm: add cpu-models-stub.c
2026-09-21 12:32 ` [RFC PATCH v4 18/25] target/arm: add cpu-models-stub.c Khushit Shah
@ 2026-09-29 15:00 ` Philippe Mathieu-Daudé
2026-09-29 15:37 ` Khushit Shah
0 siblings, 1 reply; 66+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-09-29 15:00 UTC (permalink / raw)
To: Khushit Shah, qemu-devel, qemu-arm, kvmarm, eric.auger
Cc: cohuck, peter.maydell, richard.henderson, maz, oliver.upton,
berrange, abologna, jdenemar, gshan, skolothumtho, sebott, armbru,
philmd, yangjinqian1, shaju.abraham, mark.caveayland, ping,
sandesh.patel
On 21/9/26 14:32, Khushit Shah wrote:
> Add cpu-models-stub.c, which will be required to add QMP support.
>
> Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
> ---
> target/arm/cpu-models-stub.c | 13 +++++++++++++
> target/arm/meson.build | 1 +
> 2 files changed, 14 insertions(+)
> create mode 100644 target/arm/cpu-models-stub.c
Shouldn't be needed if guarded in qmp_query_cpu_model_expansion() as:
bool named_model = false;
if (kvm_enabled()) {
named_model = arm_find_model(model->name) != NULL;
}
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH v4 22/25] target/arm/kvm: add kvm_arm_get_host_isar helper
2026-09-21 12:32 ` [RFC PATCH v4 22/25] target/arm/kvm: add kvm_arm_get_host_isar helper Khushit Shah
@ 2026-09-29 15:02 ` Philippe Mathieu-Daudé
0 siblings, 0 replies; 66+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-09-29 15:02 UTC (permalink / raw)
To: Khushit Shah, qemu-devel, qemu-arm, kvmarm, eric.auger
Cc: cohuck, peter.maydell, richard.henderson, maz, oliver.upton,
berrange, abologna, jdenemar, gshan, skolothumtho, sebott, armbru,
philmd, yangjinqian1, shaju.abraham, mark.caveayland, ping,
sandesh.patel
On 21/9/26 14:32, Khushit Shah wrote:
> Introduce kvm_arm_get_host_isar() to provide the host ISAR probed through
> a scratch vCPU. It will be needed by later commits.
>
> Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
> ---
> target/arm/kvm-stub.c | 5 +++++
> target/arm/kvm.c | 8 ++++++++
> target/arm/kvm_arm.h | 4 ++++
> 3 files changed, 17 insertions(+)
>
> diff --git a/target/arm/kvm-stub.c b/target/arm/kvm-stub.c
> index c9cd47bf47..059a7afdcb 100644
> --- a/target/arm/kvm-stub.c
> +++ b/target/arm/kvm-stub.c
> @@ -151,3 +151,8 @@ void kvm_arm_field_get_supported_values(const ARM64SysRegField *field,
> {
> g_assert_not_reached();
> }
> +
> +const ARMISARegisters *kvm_arm_get_host_isar(void)
> +{
> + return NULL;
> +}
This stub could be avoided if using in qmp_query_cpu_props_info():
if (kvm_enabled()) {
host_isar = kvm_arm_get_host_isar();
} else {
error_setg(errp, "query-cpu-props-info requires KVM");
return NULL;
}
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH v4 00/25] named CPU models for Arm64 on KVM
2026-09-21 12:32 [RFC PATCH v4 00/25] named CPU models for Arm64 on KVM Khushit Shah
` (24 preceding siblings ...)
2026-09-21 12:32 ` [RFC PATCH v4 25/25] target/arm/qmp: hook blockers in query-cpu-definitions Khushit Shah
@ 2026-09-29 15:09 ` Philippe Mathieu-Daudé
2026-09-29 16:38 ` Khushit Shah
25 siblings, 1 reply; 66+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-09-29 15:09 UTC (permalink / raw)
To: Khushit Shah, qemu-devel, qemu-arm, kvmarm, eric.auger
Cc: cohuck, peter.maydell, richard.henderson, maz, oliver.upton,
berrange, abologna, jdenemar, gshan, skolothumtho, sebott, armbru,
philmd, yangjinqian1, shaju.abraham, mark.caveayland, ping,
sandesh.patel, Mohamed Mediouni
Hi,
On 21/9/26 14:32, Khushit Shah wrote:
> Hi All,
>
> Here is v4 of the RFC for named CPU models on Arm64/KVM.
>
> Background:
> =============================================================
> Currently QEMU only supports -cpu host/max for KVM on Arm64. This blocks
> live migration of VMs between hosts that differ in CPU features.
>
> This RFC proposes hierarchical named models for Arm64 under KVM. A named
> model is a strict contract of the CPU features exposed to the guest, so
> the same model resolves to the same guest-visible ID registers on any
> capable host. Models can be customized further by overriding individual
> ID-register fields (e.g. SYSREG_ID_AA64ISAR0_EL1_SHA1=0).
>
> On top of the models, this series adds the QMP introspection support on
> Arm that the management layer already depends on for x86:
> `query-cpu-definitions` lists the models a host can run and reports
> blockers for the ones it cannot, `query-cpu-model-expansion` resolves a
> model to its full set of properties, and the new `query-cpu-props-info`
> reports the values the host supports for each property. The aim is feature
> parity with x86 so existing tooling can consume Arm named models with
> little change.
>
> TL;DR examples:
> =============================================================
> # Boot a named model
> qemu-system-aarch64 -cpu grace-v1 -machine virt,accel=kvm ...
>
> # Named model with ID-register field override
> qemu-system-aarch64 -cpu grace-v1,SYSREG_ID_AA64ISAR0_EL1_SHA1=0 ...
>
> # -cpu host with ID-register field override
> qemu-system-aarch64 -cpu host,SYSREG_ID_AA64ISAR0_EL1_AES=1 ...
>
> # query-cpu-model-expansion
> "model": {
> "name": "graviton4-v1",
> "props": {
> "SYSREG_ID_AA64ISAR0_EL1_AES": 2,
> "SYSREG_ID_AA64ISAR0_EL1_SHA1": 1,
> "SYSREG_ID_AA64ISAR0_EL1_SHA2": 2,
> "SYSREG_ID_AA64ISAR1_EL1_APA": 3,
> "SYSREG_ID_AA64PFR0_EL1_SVE": 1,
> "sve": true,
> "sve128": true,
> ...
> }
> }
> Khushit Shah (25):
> target/arm: expose SYSREG_ props for REVIDR_EL1 and AIDR_EL1
> target/arm: expose all non-res ID reg fields as properties
> target/arm: move SYSREG_ prop infra to cpu64.c
> target/arm/kvm: enable writable implementation ID registers
> target/arm/kvm: read all ID registers from KVM
> target/arm/kvm: handle special ID registers when reading from KVM
> target/arm/kvm: process ID register writeback per field
> target/arm/kvm: handle writeback for special ID register fields
While the first part of this series do KVM specific calls to get
usable ID registers, the rest doesn't seem KVM specific. IOW, what
would restrict named CPU models to be used with HVF or WHPX? IIUC
as long as we can validate the CPU features with the host we are
good. If so, some handlers should be moved to the accelerator layer;
but of couse this can be done later.
> target/arm: introduce named CPU model infrastructure
> target/arm: fix SVE and PAuth finalize for named CPU models
> target/arm: disable PMU support for named CPU models
> target/arm: add arm-v9.0-a-v1 named CPU model
> target/arm: add neoverse-v2-v1 named CPU model
> target/arm: add neoverse-v2-v2 named CPU model
> target/arm: add graviton4-v1 named CPU model
> target/arm: add grace-v1 named CPU model
> target/arm: fail named CPU models on unknown non-zero feature ID regs
> target/arm: add cpu-models-stub.c
> target/arm/qmp: allow named CPU models on cpu-model-expansion
> target/arm/kvm: compute host-supported values for ID register fields
> target/arm: report 0 as supported for ID fields gated by vCPU init
> flags
> target/arm/kvm: add kvm_arm_get_host_isar helper
> qmp: add query-cpu-props-info command
> target/arm/qmp: implement query-cpu-props-info for KVM
> target/arm/qmp: hook blockers in query-cpu-definitions
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH v4 18/25] target/arm: add cpu-models-stub.c
2026-09-29 15:00 ` Philippe Mathieu-Daudé
@ 2026-09-29 15:37 ` Khushit Shah
0 siblings, 0 replies; 66+ messages in thread
From: Khushit Shah @ 2026-09-29 15:37 UTC (permalink / raw)
To: Philippe Mathieu-Daudé
Cc: qemu-devel@nongnu.org, qemu-arm@nongnu.org,
kvmarm@lists.linux.dev, eric.auger@redhat.com, cohuck@redhat.com,
peter.maydell@linaro.org, richard.henderson@linaro.org,
maz@kernel.org, oliver.upton@linux.dev, berrange@redhat.com,
abologna@redhat.com, jdenemar@redhat.com, gshan@redhat.com,
skolothumtho@nvidia.com, sebott@redhat.com, armbru@redhat.com,
philmd@linaro.org, yangjinqian1@huawei.com, Shaju Abraham,
Mark Cave-Ayland, ping@khushitshah.com, Sandesh Patel
> On 29 Sep 2026, at 8:30 PM, Philippe Mathieu-Daudé <philmd@oss.qualcomm.com> wrote:
>
> !-------------------------------------------------------------------|
> CAUTION: External Email
>
> |-------------------------------------------------------------------!
>
> On 21/9/26 14:32, Khushit Shah wrote:
>> Add cpu-models-stub.c, which will be required to add QMP support.
>> Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
>> ---
>> target/arm/cpu-models-stub.c | 13 +++++++++++++
>> target/arm/meson.build | 1 +
>> 2 files changed, 14 insertions(+)
>> create mode 100644 target/arm/cpu-models-stub.c
>
> Shouldn't be needed if guarded in qmp_query_cpu_model_expansion() as:
>
> bool named_model = false;
>
> if (kvm_enabled()) {
> named_model = arm_find_model(model->name) != NULL;
> }
Hi Philippe,
Thank you very much for taking a look!
I tried above on qemu master + series; This results into:
[101/115] Linking target qemu-system-arm
FAILED: qemu-system-arm
cc @qemu-system-arm.rsp
/usr/bin/ld: libsystem_arm.a.p/target_arm_arm-qmp-cmds.c.o: in function `arm_cpu_add_definition':
/home/ahv/qemu-upstream/build/../target/arm/arm-qmp-cmds.c:391:(.text+0xc8): undefined reference to `arm_find_model'
/usr/bin/ld: libsystem_arm.a.p/target_arm_arm-qmp-cmds.c.o: in function `qmp_query_cpu_model_expansion':
/home/ahv/qemu-upstream/build/../target/arm/arm-qmp-cmds.c:186:(.text+0xa54): undefined reference to `arm_find_model'
collect2: error: ld returned 1 exit status
IIUC, kvm_enabled() is expanding to (kvm_allowed) here so the call is not eliminated.
Thanks,
Khushit
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH v4 00/25] named CPU models for Arm64 on KVM
2026-09-29 15:09 ` [RFC PATCH v4 00/25] named CPU models for Arm64 on KVM Philippe Mathieu-Daudé
@ 2026-09-29 16:38 ` Khushit Shah
0 siblings, 0 replies; 66+ messages in thread
From: Khushit Shah @ 2026-09-29 16:38 UTC (permalink / raw)
To: Philippe Mathieu-Daudé
Cc: qemu-devel@nongnu.org, qemu-arm@nongnu.org,
kvmarm@lists.linux.dev, eric.auger@redhat.com, cohuck@redhat.com,
peter.maydell@linaro.org, richard.henderson@linaro.org,
maz@kernel.org, oliver.upton@linux.dev, berrange@redhat.com,
abologna@redhat.com, jdenemar@redhat.com, gshan@redhat.com,
skolothumtho@nvidia.com, sebott@redhat.com, armbru@redhat.com,
philmd@linaro.org, yangjinqian1@huawei.com, Shaju Abraham,
Mark Cave-Ayland, ping@khushitshah.com, Sandesh Patel,
Mohamed Mediouni
> On 29 Sep 2026, at 8:39 PM, Philippe Mathieu-Daudé <philmd@oss.qualcomm.com> wrote:
>
> !-------------------------------------------------------------------|
> CAUTION: External Email
>
> |-------------------------------------------------------------------!
>
> Hi,
>
> On 21/9/26 14:32, Khushit Shah wrote:
>> Hi All,
>> Here is v4 of the RFC for named CPU models on Arm64/KVM.
>> Background:
>> =============================================================
>> Currently QEMU only supports -cpu host/max for KVM on Arm64. This blocks
>> live migration of VMs between hosts that differ in CPU features.
>> This RFC proposes hierarchical named models for Arm64 under KVM. A named
>> model is a strict contract of the CPU features exposed to the guest, so
>> the same model resolves to the same guest-visible ID registers on any
>> capable host. Models can be customized further by overriding individual
>> ID-register fields (e.g. SYSREG_ID_AA64ISAR0_EL1_SHA1=0).
>> On top of the models, this series adds the QMP introspection support on
>> Arm that the management layer already depends on for x86:
>> `query-cpu-definitions` lists the models a host can run and reports
>> blockers for the ones it cannot, `query-cpu-model-expansion` resolves a
>> model to its full set of properties, and the new `query-cpu-props-info`
>> reports the values the host supports for each property. The aim is feature
>> parity with x86 so existing tooling can consume Arm named models with
>> little change.
>> TL;DR examples:
>> =============================================================
>> # Boot a named model
>> qemu-system-aarch64 -cpu grace-v1 -machine virt,accel=kvm ...
>> # Named model with ID-register field override
>> qemu-system-aarch64 -cpu grace-v1,SYSREG_ID_AA64ISAR0_EL1_SHA1=0 ...
>> # -cpu host with ID-register field override
>> qemu-system-aarch64 -cpu host,SYSREG_ID_AA64ISAR0_EL1_AES=1 ...
>> # query-cpu-model-expansion
>> "model": {
>> "name": "graviton4-v1",
>> "props": {
>> "SYSREG_ID_AA64ISAR0_EL1_AES": 2,
>> "SYSREG_ID_AA64ISAR0_EL1_SHA1": 1,
>> "SYSREG_ID_AA64ISAR0_EL1_SHA2": 2,
>> "SYSREG_ID_AA64ISAR1_EL1_APA": 3,
>> "SYSREG_ID_AA64PFR0_EL1_SVE": 1,
>> "sve": true,
>> "sve128": true,
>> ...
>> }
>> }
>
>> Khushit Shah (25):
>> target/arm: expose SYSREG_ props for REVIDR_EL1 and AIDR_EL1
>> target/arm: expose all non-res ID reg fields as properties
>> target/arm: move SYSREG_ prop infra to cpu64.c
>> target/arm/kvm: enable writable implementation ID registers
>> target/arm/kvm: read all ID registers from KVM
>> target/arm/kvm: handle special ID registers when reading from KVM
>> target/arm/kvm: process ID register writeback per field
>> target/arm/kvm: handle writeback for special ID register fields
>
> While the first part of this series do KVM specific calls to get
> usable ID registers, the rest doesn't seem KVM specific. IOW, what
> would restrict named CPU models to be used with HVF or WHPX? IIUC
> as long as we can validate the CPU features with the host we are
> good. If so, some handlers should be moved to the accelerator layer;
> but of couse this can be done later.
>
I don't see a reason why named models shouldn't work with other accelerators,
as long as the accelerator provides a way to set the guest's ID register values
and to report which values it supports on the host.
I'm not sure about HVF/WHPX capabilities. I did try a quick hack (~20 lines)
for TCG and the named models and the underlying SYSREG_ properties work almost
out of the box! :)
Maybe in the future the host-dependent parts in named models/qmp (getting the
supported values and computing blockers) could be made more accelerator-agnostic.
(If I understood you correctly)
Thanks,
Khushit
>> target/arm: introduce named CPU model infrastructure
>> target/arm: fix SVE and PAuth finalize for named CPU models
>> target/arm: disable PMU support for named CPU models
>> target/arm: add arm-v9.0-a-v1 named CPU model
>> target/arm: add neoverse-v2-v1 named CPU model
>> target/arm: add neoverse-v2-v2 named CPU model
>> target/arm: add graviton4-v1 named CPU model
>> target/arm: add grace-v1 named CPU model
>> target/arm: fail named CPU models on unknown non-zero feature ID regs
>> target/arm: add cpu-models-stub.c
>> target/arm/qmp: allow named CPU models on cpu-model-expansion
>> target/arm/kvm: compute host-supported values for ID register fields
>> target/arm: report 0 as supported for ID fields gated by vCPU init
>> flags
>> target/arm/kvm: add kvm_arm_get_host_isar helper
>> qmp: add query-cpu-props-info command
>> target/arm/qmp: implement query-cpu-props-info for KVM
>> target/arm/qmp: hook blockers in query-cpu-definitions
>
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH v4 14/25] target/arm: add neoverse-v2-v2 named CPU model
2026-09-21 12:32 ` [RFC PATCH v4 14/25] target/arm: add neoverse-v2-v2 " Khushit Shah
@ 2026-10-15 12:13 ` Eric Auger
2026-10-15 12:22 ` Peter Maydell
0 siblings, 1 reply; 66+ messages in thread
From: Eric Auger @ 2026-10-15 12:13 UTC (permalink / raw)
To: Khushit Shah, qemu-devel, qemu-arm, kvmarm
Cc: cohuck, peter.maydell, richard.henderson, maz, oliver.upton,
berrange, abologna, jdenemar, gshan, skolothumtho, sebott, armbru,
philmd, yangjinqian1, shaju.abraham, mark.caveayland, ping,
sandesh.patel
Hi Khushit,
On 9/21/26 2:32 PM, Khushit Shah wrote:
> Add a KVM-only named CPU model for Neoverse V2 r0p1 (TRM 102375),
> inheriting from neoverse-v2-v1 (r0p0).
>
> r0p1 only changes MIDR_EL1.Revision and adds FEAT_ECBHB
> (ID_AA64MMFR1_EL1.ECBHB).
>
> Final ID register state requested from KVM for "neoverse-v2-v2":
> [ 0] AIDR_EL1 = 0x0000000000000000
> [ 1] CLIDR_EL1 = 0x0000000000000000
> [ 2] CTR_EL0 = 0x000000009444c004
> [ 3] DCZID_EL0 = 0x0000000000000004
> [ 4] GMID_EL1 = 0x0000000000000000
> [ 5] ID_AA64AFR0_EL1 = 0x0000000000000000
> [ 6] ID_AA64AFR1_EL1 = 0x0000000000000000
> [ 7] ID_AA64DFR0_EL1 = 0x000000f010305009
> [ 8] ID_AA64DFR1_EL1 = 0x0000000000000000
> [ 9] ID_AA64DFR2_EL1 = 0x0000000000000000
> [ 10] ID_AA64FPFR0_EL1 = 0x0000000000000000
> [ 11] ID_AA64ISAR0_EL1 = 0x0221100010210000
> [ 12] ID_AA64ISAR1_EL1 = 0x0011111101211052
> [ 13] ID_AA64ISAR2_EL1 = 0x0000000000000000
> [ 14] ID_AA64ISAR3_EL1 = 0x0000000000000000
> [ 15] ID_AA64MMFR0_EL1 = 0x0000011100101125
> [ 16] ID_AA64MMFR1_EL1 = 0x1000000010312122
> [ 17] ID_AA64MMFR2_EL1 = 0x1221011110001011
> [ 18] ID_AA64MMFR3_EL1 = 0x0000000000000000
> [ 19] ID_AA64MMFR4_EL1 = 0x0000000000000000
> [ 20] ID_AA64PFR0_EL1 = 0x1101000120110011
> [ 21] ID_AA64PFR1_EL1 = 0x0000000000000021
> [ 22] ID_AA64PFR2_EL1 = 0x0000000000000000
> [ 23] ID_AA64SMFR0_EL1 = 0x0000000000000000
> [ 24] ID_AA64ZFR0_EL1 = 0x0000100000110001
> [ 25] ID_AFR0_EL1 = 0x0000000000000000
> [ 26] ID_DFR0_EL1 = 0x0000000000000000
> [ 27] ID_DFR1_EL1 = 0x0000000000000000
> [ 28] ID_ISAR0_EL1 = 0x0000000000000000
> [ 29] ID_ISAR1_EL1 = 0x0000000000000000
> [ 30] ID_ISAR2_EL1 = 0x0000000000000000
> [ 31] ID_ISAR3_EL1 = 0x0000000000000000
> [ 32] ID_ISAR4_EL1 = 0x0000000000000000
> [ 33] ID_ISAR5_EL1 = 0x0000000000000000
> [ 34] ID_ISAR6_EL1 = 0x0000000000000000
> [ 35] ID_MMFR0_EL1 = 0x0000000000000000
> [ 36] ID_MMFR1_EL1 = 0x0000000000000000
> [ 37] ID_MMFR2_EL1 = 0x0000000000000000
> [ 38] ID_MMFR3_EL1 = 0x0000000000000000
> [ 39] ID_MMFR4_EL1 = 0x0000000000000000
> [ 40] ID_MMFR5_EL1 = 0x0000000000000000
> [ 41] ID_PFR0_EL1 = 0x0000000000000000
> [ 42] ID_PFR1_EL1 = 0x0000000000000000
> [ 43] ID_PFR2_EL1 = 0x0000000000000000
> [ 44] MIDR_EL1 = 0x00000000410fd4f1
> [ 45] MPIDR_EL1 = 0x0000000080000000
> [ 46] MVFR0_EL1 = 0x0000000000000000
> [ 47] MVFR1_EL1 = 0x0000000000000000
> [ 48] MVFR2_EL1 = 0x0000000000000000
> [ 49] REVIDR_EL1 = 0x0000000000000000
> [ 50] SMIDR_EL1 = 0x0000000000000000
>
> Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
> ---
> hw/arm/virt.c | 1 +
> target/arm/cpu-models.c | 13 +++++++++++++
> 2 files changed, 14 insertions(+)
>
> diff --git a/hw/arm/virt.c b/hw/arm/virt.c
> index f5a8ea1145..90e818690c 100644
> --- a/hw/arm/virt.c
> +++ b/hw/arm/virt.c
> @@ -4147,6 +4147,7 @@ static GPtrArray *virt_get_valid_cpu_types(const MachineState *ms)
> if (kvm_enabled() && target_aarch64()) {
> g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("arm-v9.0-a-v1")));
> g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("neoverse-v2-v1")));
> + g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("neoverse-v2-v2")));
> }
> if (target_aarch64()) {
> g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("cortex-a53")));
> diff --git a/target/arm/cpu-models.c b/target/arm/cpu-models.c
> index 2de67f353b..af60924953 100644
> --- a/target/arm/cpu-models.c
> +++ b/target/arm/cpu-models.c
> @@ -16,6 +16,7 @@
> * Current Hierarchy:
> * arm-v9.0-a-v1
> * neoverse-v2-v1 (r0p0)
> + * neoverse-v2-v2 (r0p1)
> * SPDX-License-Identifier: GPL-2.0-or-later
> */
>
> @@ -212,9 +213,21 @@ static const ArmModelPropValue neoverse_v2_v1_props[] = {
> MODEL_PROP_END
> };
>
> +/* Neoverse V2 CPU model (TRM 102375, r0p1), inherits from neoverse-v2-v1. */
> +static const ArmModelPropValue neoverse_v2_v2_props[] = {
> + /* MIDR_EL1 */
> + MODEL_PROP("SYSREG_MIDR_EL1_Revision", NUM, 0x1), /* r0p1 */
> +
> + /* ID_AA64MMFR1_EL1 */
> + MODEL_PROP("SYSREG_ID_AA64MMFR1_EL1_ECBHB", NUM, 1), /* FEAT_ECBHB */
> +
> + MODEL_PROP_END,
> +};
> +
> static const ArmNamedCpuModel arm_cpu_models[] = {
> {"arm-v9.0-a-v1", NULL, arm_v9_0_a_v1_props},
> {"neoverse-v2-v1", "arm-v9.0-a-v1", neoverse_v2_v1_props},
> + {"neoverse-v2-v2", "neoverse-v2-v1", neoverse_v2_v2_props},
nit I would call it directly neoverse-v2-r0p1 and leave the -v<n> suffix
for potential fixes. Same for r0p0 obviously.
Thanks
Eric
> {NULL, NULL, NULL}
> };
>
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH v4 14/25] target/arm: add neoverse-v2-v2 named CPU model
2026-10-15 12:13 ` Eric Auger
@ 2026-10-15 12:22 ` Peter Maydell
2026-10-15 14:05 ` Eric Auger
0 siblings, 1 reply; 66+ messages in thread
From: Peter Maydell @ 2026-10-15 12:22 UTC (permalink / raw)
To: eric.auger
Cc: Khushit Shah, qemu-devel, qemu-arm, kvmarm, cohuck,
richard.henderson, maz, oliver.upton, berrange, abologna,
jdenemar, gshan, skolothumtho, sebott, armbru, philmd,
yangjinqian1, shaju.abraham, mark.caveayland, ping, sandesh.patel
On Thu, 15 Oct 2026 at 13:13, Eric Auger <eric.auger@redhat.com> wrote:
>
> Hi Khushit,
>
> On 9/21/26 2:32 PM, Khushit Shah wrote:
> > Add a KVM-only named CPU model for Neoverse V2 r0p1 (TRM 102375),
> > inheriting from neoverse-v2-v1 (r0p0).
> >
> > r0p1 only changes MIDR_EL1.Revision and adds FEAT_ECBHB
> > (ID_AA64MMFR1_EL1.ECBHB).
> > static const ArmNamedCpuModel arm_cpu_models[] = {
> > {"arm-v9.0-a-v1", NULL, arm_v9_0_a_v1_props},
> > {"neoverse-v2-v1", "arm-v9.0-a-v1", neoverse_v2_v1_props},
> > + {"neoverse-v2-v2", "neoverse-v2-v1", neoverse_v2_v2_props},
> nit I would call it directly neoverse-v2-r0p1 and leave the -v<n> suffix
> for potential fixes. Same for r0p0 obviously.
I'm not very enthusiastic about accumulating different CPU models
for all the different rXpY variations that appear. We used to have
a ton of basically identical pxa720 variants and I was glad to be
able to drop those when we deprecated-and-dropped the pxa support.
Is any user actually going to care about the difference between
r0p0 and r0p1 ? In particular pX changes are just hardware
bugfixes that QEMU was unlikely to be modelling in the first place.
thanks
-- PMM
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH v4 10/25] target/arm: fix SVE and PAuth finalize for named CPU models
2026-09-21 12:32 ` [RFC PATCH v4 10/25] target/arm: fix SVE and PAuth finalize for named CPU models Khushit Shah
@ 2026-10-15 13:01 ` Eric Auger
2026-10-16 7:34 ` Khushit Shah
0 siblings, 1 reply; 66+ messages in thread
From: Eric Auger @ 2026-10-15 13:01 UTC (permalink / raw)
To: Khushit Shah, qemu-devel, qemu-arm, kvmarm
Cc: cohuck, peter.maydell, richard.henderson, maz, oliver.upton,
berrange, abologna, jdenemar, gshan, skolothumtho, sebott, armbru,
philmd, yangjinqian1, shaju.abraham, mark.caveayland, ping,
sandesh.patel
Hi Khushit,
On 9/21/26 2:32 PM, Khushit Shah wrote:
> As named CPU models define their feature set explicitly, their SVE
> vector lengths and PAuth fields must not be derived from the host.
>
> When SVE is enabled without an sve<N> setting, require the named model
> to specify its supported vector lengths rather than inheriting them from
> the host.
>
> Named models set PAuth ID register fields directly through SYSREG_
> properties. Preserve these values in PAuth finalization.
>
> Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
> ---
> target/arm/cpu64.c | 33 +++++++++++++++++++++++++++++++++
> 1 file changed, 33 insertions(+)
>
> diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
> index 7487b48cc9..a0114b0fa2 100644
> --- a/target/arm/cpu64.c
> +++ b/target/arm/cpu64.c
> @@ -38,6 +38,7 @@
> #include "internals.h"
> #include "cpu-features.h"
> #include "cpu-idregs.h"
> +#include "cpu-models.h"
> #include "trace.h"
>
> /* convert between <register>_IDX and SYS_<register> */
> @@ -134,6 +135,21 @@ void aarch64_cpu_sve_finalize(ARMCPU *cpu, Error **errp)
> return;
> }
>
> +#ifndef CONFIG_USER_ONLY
I don't get why do you need that #ifndef?
> + /*
> + * If SVE is enabled but no vector lengths are specified, we must not
> + * default to the host's supported lengths for named CPU models.
> + */
> + {
> + ARMCPUClass *acc = ARM_CPU_GET_CLASS(cpu);
> + if (acc->info && arm_find_model(acc->info->name)) {
> + error_setg(errp,
> + "Named CPU models with SVE must set vector lengths");
> + return;
> + }
> + }
> +#endif
> +
> if (kvm_enabled()) {
> /* Disabling a supported length disables all larger lengths. */
> tmp = vq_init & vq_supported;
> @@ -556,6 +572,23 @@ void aarch64_cpu_pauth_finalize(ARMCPU *cpu, Error **errp)
> ARMISARegisters *isar = &cpu->isar;
> uint64_t isar1, isar2;
>
> +#ifndef CONFIG_USER_ONLY
> + /*
> + * For named CPU models the model props write the authoritative
> + * APA/API/APA3/GPA/GPI/GPA3 values directly into cpu->isar through
all those fields ar not KVM writable currently.
> + * SYSREG_ properties, so do not override them here. Since other code
> + * relies on cpu->prop_pauth, mirror the resulting pauth state into
> + * cpu->prop_pauth.
> + */
> + {
> + ARMCPUClass *acc = ARM_CPU_GET_CLASS(cpu);
> + if (acc->info && arm_find_model(acc->info->name)) {
> + cpu->prop_pauth = cpu_isar_feature(aa64_pauth, cpu);
> + return;
> + }
> + }
> +#endif
If I understand correctly all the isar1/isar2 manipulations afterwards
only affect TCG.
In KVM mode, although isar1/isar2 fields are reset afterwards this does
not impact the guest view so most probably the isa1/2 reset + finale
update could be moved to the !hw_accel block and you put that addition
in the hwaccel_enabled() block, or am i wrong?
Thanks
Eric
> +
> /*
> * These properties enable or disable Pauth as a whole, or change
> * the pauth algorithm, but do not change the set of features that
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH v4 11/25] target/arm: disable PMU support for named CPU models
2026-09-21 12:32 ` [RFC PATCH v4 11/25] target/arm: disable PMU support " Khushit Shah
@ 2026-10-15 13:12 ` Eric Auger
0 siblings, 0 replies; 66+ messages in thread
From: Eric Auger @ 2026-10-15 13:12 UTC (permalink / raw)
To: Khushit Shah, qemu-devel, qemu-arm, kvmarm
Cc: cohuck, peter.maydell, richard.henderson, maz, oliver.upton,
berrange, abologna, jdenemar, gshan, skolothumtho, sebott, armbru,
philmd, yangjinqian1, shaju.abraham, mark.caveayland, ping,
sandesh.patel
Hi Khushit,
On 9/21/26 2:32 PM, Khushit Shah wrote:
> Under KVM, the guest PMU is backed by the host PMU (event set, PMCR.N,
> and PMCEID), which may not be portable across heterogeneous hosts.
>
> Disable PMU support for named CPU models by clearing ARM_FEATURE_PMU in
> the named-model init path so arm_cpu_post_init() does not create the
> "pmu" property.
To me it shall be possible to turn PMU on even on named model. I
understand it may create migration issues due to the HW adherence but yet.
I think on x86 you can use -cpu Haswell-IBRS,pmu=on.
Eric
>
> Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
> ---
> target/arm/cpu-models.c | 4 ++++
> 1 file changed, 4 insertions(+)
>
> diff --git a/target/arm/cpu-models.c b/target/arm/cpu-models.c
> index fed3197186..153ee10ae6 100644
> --- a/target/arm/cpu-models.c
> +++ b/target/arm/cpu-models.c
> @@ -159,6 +159,10 @@ static void arm_named_cpu_initfn(Object *obj)
> /* 1.b Properly set RES1 fields. */
> reset_res1_fields(cpu);
>
> + /* Disable PMU for named CPU models. */
> + unset_feature(&cpu->env, ARM_FEATURE_PMU);
> + cpu->has_pmu = false;
> +
> /* 2. Add sveNNNN and SYSREG_ properties */
> aarch64_add_sve_properties(obj);
> aarch64_add_idregs_properties(obj);
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH v4 14/25] target/arm: add neoverse-v2-v2 named CPU model
2026-10-15 12:22 ` Peter Maydell
@ 2026-10-15 14:05 ` Eric Auger
2026-10-16 6:48 ` Khushit Shah
0 siblings, 1 reply; 66+ messages in thread
From: Eric Auger @ 2026-10-15 14:05 UTC (permalink / raw)
To: Peter Maydell
Cc: Khushit Shah, qemu-devel, qemu-arm, kvmarm, cohuck,
richard.henderson, maz, oliver.upton, berrange, abologna,
jdenemar, gshan, skolothumtho, sebott, armbru, philmd,
yangjinqian1, shaju.abraham, mark.caveayland, ping, sandesh.patel
On 10/15/26 2:22 PM, Peter Maydell wrote:
> On Thu, 15 Oct 2026 at 13:13, Eric Auger <eric.auger@redhat.com> wrote:
>> Hi Khushit,
>>
>> On 9/21/26 2:32 PM, Khushit Shah wrote:
>>> Add a KVM-only named CPU model for Neoverse V2 r0p1 (TRM 102375),
>>> inheriting from neoverse-v2-v1 (r0p0).
>>>
>>> r0p1 only changes MIDR_EL1.Revision and adds FEAT_ECBHB
>>> (ID_AA64MMFR1_EL1.ECBHB).
>>> static const ArmNamedCpuModel arm_cpu_models[] = {
>>> {"arm-v9.0-a-v1", NULL, arm_v9_0_a_v1_props},
>>> {"neoverse-v2-v1", "arm-v9.0-a-v1", neoverse_v2_v1_props},
>>> + {"neoverse-v2-v2", "neoverse-v2-v1", neoverse_v2_v2_props},
>> nit I would call it directly neoverse-v2-r0p1 and leave the -v<n> suffix
>> for potential fixes. Same for r0p0 obviously.
> I'm not very enthusiastic about accumulating different CPU models
> for all the different rXpY variations that appear. We used to have
> a ton of basically identical pxa720 variants and I was glad to be
> able to drop those when we deprecated-and-dropped the pxa support.
>
> Is any user actually going to care about the difference between
> r0p0 and r0p1 ? In particular pX changes are just hardware
> bugfixes that QEMU was unlikely to be modelling in the first place.
I do agree. In terms of ID reg, there is very little difference between
both. Modeling a single one may be sufficient
Thanks
Eric
>
> thanks
> -- PMM
>
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH v4 23/25] qmp: add query-cpu-props-info command
2026-09-21 12:32 ` [RFC PATCH v4 23/25] qmp: add query-cpu-props-info command Khushit Shah
@ 2026-10-15 14:20 ` Eric Auger
2026-10-16 6:57 ` Khushit Shah
0 siblings, 1 reply; 66+ messages in thread
From: Eric Auger @ 2026-10-15 14:20 UTC (permalink / raw)
To: Khushit Shah, qemu-devel, qemu-arm, kvmarm
Cc: cohuck, peter.maydell, richard.henderson, maz, oliver.upton,
berrange, abologna, jdenemar, gshan, skolothumtho, sebott, armbru,
philmd, yangjinqian1, shaju.abraham, mark.caveayland, ping,
sandesh.patel
On 9/21/26 2:32 PM, Khushit Shah wrote:
> Introduce the 'query-cpu-props-info' QMP command. For each CPU model
> property, it reports the type (boolean or number) and the set of values
> supported under the active accelerator and host.
>
> This helps the management stack to discover which values are supported
> for a given CPU property. This is especially important for non-boolean
> properties, where knowing that the host has value 'x' does not
> inherently reveal the full range of valid values supported on the host.
> For example, an Arm host with CTR_EL0.L1Ip=3 (PIPT) also allows 2
> (VIPT) but a host with CTR_EL0.L1Ip=2 does not allow CTR_EL0.L1Ip=3
> for a guest.
>
> For numerical properties, the supported values are expressed as a list
> of inclusive {min, max} ranges. For boolean properties, they are
> represented as a list of true/false values.
>
> The command and its return types (CpuPropertyType, CpuPropertyInfo and
> friends) are defined in qapi/machine.json rather than an Arm-specific
> schema, since the concept applies to other targets (e.g. x86, RISC-V)
> too. Targets that do not implement it return an error.
> (The following commit implements the command for Arm KVM.)
>
> Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
> ---
> qapi/machine.json | 82 ++++++++++++++++++++++++++++++++++++++
> stubs/meson.build | 1 +
> stubs/qmp-cpu-props-info.c | 12 ++++++
> tests/qtest/qmp-cmd-test.c | 1 +
> 4 files changed, 96 insertions(+)
> create mode 100644 stubs/qmp-cpu-props-info.c
>
> diff --git a/qapi/machine.json b/qapi/machine.json
> index 2d63c1bac3..6e65bdad86 100644
> --- a/qapi/machine.json
> +++ b/qapi/machine.json
> @@ -2291,3 +2291,85 @@
> # Since: 1.2
> ##
> { 'command': 'query-cpu-definitions', 'returns': ['CpuDefinitionInfo'] }
> +
> +##
> +# @CpuPropertyType:
> +#
> +# The type of a CPU model property.
> +#
> +# @boolean: the property is of type boolean.
> +#
> +# @number: the property is of type unsigned integer.
> +#
> +# Since: 11.2
> +##
> +{ 'enum': 'CpuPropertyType',
> + 'data': [ 'boolean', 'number' ] }
why do we still need the boolean type? Can't we simplify and stick to
uint64_t for all SYSREG props?
> +
> +##
> +# @CpuPropertyValueRange:
> +#
> +# An inclusive range of numeric values supported for the property.
> +#
> +# @min: the lowest supported value.
> +#
> +# @max: the highest supported value.
> +#
> +# Since: 11.2
> +##
> +{ 'struct': 'CpuPropertyValueRange',
> + 'data': { 'min': 'uint64', 'max': 'uint64' } }
> +
> +##
> +# @CpuPropertyInfoBoolean:
> +#
> +# @supported-values: list of boolean values supported for the
> +# property.
> +#
> +# Since: 11.2
> +##
> +{ 'struct': 'CpuPropertyInfoBoolean',
> + 'data': { 'supported-values': ['bool'] } }
why can't you model that with a range too?
> +
> +##
> +# @CpuPropertyInfoNumber:
> +#
> +# @supported-values: list of numeric value ranges supported
> +# for the property.
> +#
> +# Since: 11.2
> +##
> +{ 'struct': 'CpuPropertyInfoNumber',
> + 'data': { 'supported-values': ['CpuPropertyValueRange'] } }
> +
> +##
> +# @CpuPropertyInfo:
> +#
> +# Information about a single CPU model property, including the values
> +# the host/accelerator supports for it.
> +#
> +# @name: the name of the property.
> +#
> +# @type: the type of the property, which selects the layout of
> +# @supported-values.
> +#
> +# Since: 11.2
> +##
> +{ 'union': 'CpuPropertyInfo',
> + 'base': { 'name': 'str',
> + 'type': 'CpuPropertyType' },
> + 'discriminator': 'type',
> + 'data': { 'boolean': 'CpuPropertyInfoBoolean',
> + 'number': 'CpuPropertyInfoNumber' } }
> +
> +##
> +# @query-cpu-props-info:
> +#
> +# Return information about the CPU model properties. For each
> +# property it reports the values supported under the active
> +# accelerator and host.
> +#
> +# Since: 11.2
> +##
> +{ 'command': 'query-cpu-props-info',
> + 'returns': ['CpuPropertyInfo'] }
> diff --git a/stubs/meson.build b/stubs/meson.build
> index 3b2f2680b1..3bb4028bab 100644
> --- a/stubs/meson.build
> +++ b/stubs/meson.build
> @@ -83,6 +83,7 @@ if have_system
> stub_ss.add(files('qmp-i386-sgx.c'))
> stub_ss.add(files('qmp-i386-xen.c'))
> stub_ss.add(files('qmp-cpu.c'))
> + stub_ss.add(files('qmp-cpu-props-info.c'))
> stub_ss.add(files('qmp-cpu-s390x.c'))
> stub_ss.add(files('qmp-cpu-s390x-kvm.c'))
> stub_ss.add(files('hmp-cmd-info_mem.c'))
> diff --git a/stubs/qmp-cpu-props-info.c b/stubs/qmp-cpu-props-info.c
> new file mode 100644
> index 0000000000..36b0530b98
> --- /dev/null
> +++ b/stubs/qmp-cpu-props-info.c
> @@ -0,0 +1,12 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +
> +#include "qemu/osdep.h"
> +#include "qapi/error.h"
> +#include "qapi/qapi-commands-machine.h"
> +
> +CpuPropertyInfoList *
> +qmp_query_cpu_props_info(Error **errp)
> +{
> + error_setg(errp, "query-cpu-props-info not supported on this target");
> + return NULL;
> +}
> diff --git a/tests/qtest/qmp-cmd-test.c b/tests/qtest/qmp-cmd-test.c
> index 279a8f5614..2c25dbd8cb 100644
> --- a/tests/qtest/qmp-cmd-test.c
> +++ b/tests/qtest/qmp-cmd-test.c
> @@ -100,6 +100,7 @@ static bool query_is_ignored(const char *cmd)
> "add-fd",
> /* Success depends on target arch: */
> "query-cpu-definitions", /* arm, i386, ppc, s390x */
> + "query-cpu-props-info", /* arm + kvm */
> "query-gic-capabilities", /* arm */
> "query-s390x-cpu-polarization", /* s390x */
> /* Success depends on target-specific build configuration: */
Thanks
Eric
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH v4 14/25] target/arm: add neoverse-v2-v2 named CPU model
2026-10-15 14:05 ` Eric Auger
@ 2026-10-16 6:48 ` Khushit Shah
0 siblings, 0 replies; 66+ messages in thread
From: Khushit Shah @ 2026-10-16 6:48 UTC (permalink / raw)
To: eric.auger@redhat.com
Cc: Peter Maydell, qemu-devel@nongnu.org, qemu-arm@nongnu.org,
kvmarm@lists.linux.dev, cohuck@redhat.com,
richard.henderson@linaro.org, maz@kernel.org,
oliver.upton@linux.dev, berrange@redhat.com, abologna@redhat.com,
jdenemar@redhat.com, gshan@redhat.com, skolothumtho@nvidia.com,
sebott@redhat.com, armbru@redhat.com, philmd@linaro.org,
yangjinqian1@huawei.com, Shaju Abraham, Mark Cave-Ayland,
ping@khushitshah.com, Sandesh Patel
> On 15 Oct 2026, at 7:35 PM, Eric Auger <eric.auger@redhat.com> wrote:
>
> !-------------------------------------------------------------------|
> CAUTION: External Email
>
> |-------------------------------------------------------------------!
>
>
>
> On 10/15/26 2:22 PM, Peter Maydell wrote:
>> On Thu, 15 Oct 2026 at 13:13, Eric Auger <eric.auger@redhat.com> wrote:
>>> Hi Khushit,
>>>
>>> On 9/21/26 2:32 PM, Khushit Shah wrote:
>>>> Add a KVM-only named CPU model for Neoverse V2 r0p1 (TRM 102375),
>>>> inheriting from neoverse-v2-v1 (r0p0).
>>>>
>>>> r0p1 only changes MIDR_EL1.Revision and adds FEAT_ECBHB
>>>> (ID_AA64MMFR1_EL1.ECBHB).
>>>> static const ArmNamedCpuModel arm_cpu_models[] = {
>>>> {"arm-v9.0-a-v1", NULL, arm_v9_0_a_v1_props},
>>>> {"neoverse-v2-v1", "arm-v9.0-a-v1", neoverse_v2_v1_props},
>>>> + {"neoverse-v2-v2", "neoverse-v2-v1", neoverse_v2_v2_props},
>>> nit I would call it directly neoverse-v2-r0p1 and leave the -v<n> suffix
>>> for potential fixes. Same for r0p0 obviously.
>> I'm not very enthusiastic about accumulating different CPU models
>> for all the different rXpY variations that appear. We used to have
>> a ton of basically identical pxa720 variants and I was glad to be
>> able to drop those when we deprecated-and-dropped the pxa support.
>>
>> Is any user actually going to care about the difference between
>> r0p0 and r0p1 ? In particular pX changes are just hardware
>> bugfixes that QEMU was unlikely to be modelling in the first place.
> I do agree. In terms of ID reg, there is very little difference between
> both. Modeling a single one may be sufficient
>
Noted, will only keep one Neoverse-v2.
Thanks,
Khushit
> Thanks
>
> Eric
>>
>> thanks
>> -- PMM
>>
>
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH v4 23/25] qmp: add query-cpu-props-info command
2026-10-15 14:20 ` Eric Auger
@ 2026-10-16 6:57 ` Khushit Shah
2026-10-16 7:18 ` Eric Auger
0 siblings, 1 reply; 66+ messages in thread
From: Khushit Shah @ 2026-10-16 6:57 UTC (permalink / raw)
To: eric.auger@redhat.com
Cc: qemu-devel@nongnu.org, qemu-arm@nongnu.org,
kvmarm@lists.linux.dev, cohuck@redhat.com,
peter.maydell@linaro.org, richard.henderson@linaro.org,
maz@kernel.org, oliver.upton@linux.dev, berrange@redhat.com,
abologna@redhat.com, jdenemar@redhat.com, gshan@redhat.com,
skolothumtho@nvidia.com, sebott@redhat.com, armbru@redhat.com,
philmd@linaro.org, yangjinqian1@huawei.com, Shaju Abraham,
Mark Cave-Ayland, ping@khushitshah.com, Sandesh Patel
> On 15 Oct 2026, at 7:50 PM, Eric Auger <eric.auger@redhat.com> wrote:
>
> !-------------------------------------------------------------------|
> CAUTION: External Email
>
> |-------------------------------------------------------------------!
>
>
>
> On 9/21/26 2:32 PM, Khushit Shah wrote:
>> Introduce the 'query-cpu-props-info' QMP command. For each CPU model
>> property, it reports the type (boolean or number) and the set of values
>> supported under the active accelerator and host.
>>
>> This helps the management stack to discover which values are supported
>> for a given CPU property. This is especially important for non-boolean
>> properties, where knowing that the host has value 'x' does not
>> inherently reveal the full range of valid values supported on the host.
>> For example, an Arm host with CTR_EL0.L1Ip=3 (PIPT) also allows 2
>> (VIPT) but a host with CTR_EL0.L1Ip=2 does not allow CTR_EL0.L1Ip=3
>> for a guest.
>>
>> For numerical properties, the supported values are expressed as a list
>> of inclusive {min, max} ranges. For boolean properties, they are
>> represented as a list of true/false values.
>>
>> The command and its return types (CpuPropertyType, CpuPropertyInfo and
>> friends) are defined in qapi/machine.json rather than an Arm-specific
>> schema, since the concept applies to other targets (e.g. x86, RISC-V)
>> too. Targets that do not implement it return an error.
>> (The following commit implements the command for Arm KVM.)
>>
>> Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
>> ---
>> qapi/machine.json | 82 ++++++++++++++++++++++++++++++++++++++
>> stubs/meson.build | 1 +
>> stubs/qmp-cpu-props-info.c | 12 ++++++
>> tests/qtest/qmp-cmd-test.c | 1 +
>> 4 files changed, 96 insertions(+)
>> create mode 100644 stubs/qmp-cpu-props-info.c
>>
>> diff --git a/qapi/machine.json b/qapi/machine.json
>> index 2d63c1bac3..6e65bdad86 100644
>> --- a/qapi/machine.json
>> +++ b/qapi/machine.json
>> @@ -2291,3 +2291,85 @@
>> # Since: 1.2
>> ##
>> { 'command': 'query-cpu-definitions', 'returns': ['CpuDefinitionInfo'] }
>> +
>> +##
>> +# @CpuPropertyType:
>> +#
>> +# The type of a CPU model property.
>> +#
>> +# @boolean: the property is of type boolean.
>> +#
>> +# @number: the property is of type unsigned integer.
>> +#
>> +# Since: 11.2
>> +##
>> +{ 'enum': 'CpuPropertyType',
>> + 'data': [ 'boolean', 'number' ] }
> why do we still need the boolean type? Can't we simplify and stick to
> uint64_t for all SYSREG props?
Hi Eric,
Bools to support existing properties (sve, pauth, etc…) are booleans.
>> +
>> +##
>> +# @CpuPropertyValueRange:
>> +#
>> +# An inclusive range of numeric values supported for the property.
>> +#
>> +# @min: the lowest supported value.
>> +#
>> +# @max: the highest supported value.
>> +#
>> +# Since: 11.2
>> +##
>> +{ 'struct': 'CpuPropertyValueRange',
>> + 'data': { 'min': 'uint64', 'max': 'uint64' } }
>> +
>> +##
>> +# @CpuPropertyInfoBoolean:
>> +#
>> +# @supported-values: list of boolean values supported for the
>> +# property.
>> +#
>> +# Since: 11.2
>> +##
>> +{ 'struct': 'CpuPropertyInfoBoolean',
>> + 'data': { 'supported-values': ['bool'] } }
> why can't you model that with a range too?
I’m sorry I didn’t get you.
Thanks,
Khushit
>> +
>> +##
>> +# @CpuPropertyInfoNumber:
>> +#
>> +# @supported-values: list of numeric value ranges supported
>> +# for the property.
>> +#
>> +# Since: 11.2
>> +##
>> +{ 'struct': 'CpuPropertyInfoNumber',
>> + 'data': { 'supported-values': ['CpuPropertyValueRange'] } }
>> +
>> +##
>> +# @CpuPropertyInfo:
>> +#
>> +# Information about a single CPU model property, including the values
>> +# the host/accelerator supports for it.
>> +#
>> +# @name: the name of the property.
>> +#
>> +# @type: the type of the property, which selects the layout of
>> +# @supported-values.
>> +#
>> +# Since: 11.2
>> +##
>> +{ 'union': 'CpuPropertyInfo',
>> + 'base': { 'name': 'str',
>> + 'type': 'CpuPropertyType' },
>> + 'discriminator': 'type',
>> + 'data': { 'boolean': 'CpuPropertyInfoBoolean',
>> + 'number': 'CpuPropertyInfoNumber' } }
>> +
>> +##
>> +# @query-cpu-props-info:
>> +#
>> +# Return information about the CPU model properties. For each
>> +# property it reports the values supported under the active
>> +# accelerator and host.
>> +#
>> +# Since: 11.2
>> +##
>> +{ 'command': 'query-cpu-props-info',
>> + 'returns': ['CpuPropertyInfo'] }
>> diff --git a/stubs/meson.build b/stubs/meson.build
>> index 3b2f2680b1..3bb4028bab 100644
>> --- a/stubs/meson.build
>> +++ b/stubs/meson.build
>> @@ -83,6 +83,7 @@ if have_system
>> stub_ss.add(files('qmp-i386-sgx.c'))
>> stub_ss.add(files('qmp-i386-xen.c'))
>> stub_ss.add(files('qmp-cpu.c'))
>> + stub_ss.add(files('qmp-cpu-props-info.c'))
>> stub_ss.add(files('qmp-cpu-s390x.c'))
>> stub_ss.add(files('qmp-cpu-s390x-kvm.c'))
>> stub_ss.add(files('hmp-cmd-info_mem.c'))
>> diff --git a/stubs/qmp-cpu-props-info.c b/stubs/qmp-cpu-props-info.c
>> new file mode 100644
>> index 0000000000..36b0530b98
>> --- /dev/null
>> +++ b/stubs/qmp-cpu-props-info.c
>> @@ -0,0 +1,12 @@
>> +/* SPDX-License-Identifier: GPL-2.0-or-later */
>> +
>> +#include "qemu/osdep.h"
>> +#include "qapi/error.h"
>> +#include "qapi/qapi-commands-machine.h"
>> +
>> +CpuPropertyInfoList *
>> +qmp_query_cpu_props_info(Error **errp)
>> +{
>> + error_setg(errp, "query-cpu-props-info not supported on this target");
>> + return NULL;
>> +}
>> diff --git a/tests/qtest/qmp-cmd-test.c b/tests/qtest/qmp-cmd-test.c
>> index 279a8f5614..2c25dbd8cb 100644
>> --- a/tests/qtest/qmp-cmd-test.c
>> +++ b/tests/qtest/qmp-cmd-test.c
>> @@ -100,6 +100,7 @@ static bool query_is_ignored(const char *cmd)
>> "add-fd",
>> /* Success depends on target arch: */
>> "query-cpu-definitions", /* arm, i386, ppc, s390x */
>> + "query-cpu-props-info", /* arm + kvm */
>> "query-gic-capabilities", /* arm */
>> "query-s390x-cpu-polarization", /* s390x */
>> /* Success depends on target-specific build configuration: */
> Thanks
>
> Eric
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH v4 23/25] qmp: add query-cpu-props-info command
2026-10-16 6:57 ` Khushit Shah
@ 2026-10-16 7:18 ` Eric Auger
2026-10-16 7:28 ` Khushit Shah
0 siblings, 1 reply; 66+ messages in thread
From: Eric Auger @ 2026-10-16 7:18 UTC (permalink / raw)
To: Khushit Shah
Cc: qemu-devel@nongnu.org, qemu-arm@nongnu.org,
kvmarm@lists.linux.dev, cohuck@redhat.com,
peter.maydell@linaro.org, richard.henderson@linaro.org,
maz@kernel.org, oliver.upton@linux.dev, berrange@redhat.com,
abologna@redhat.com, jdenemar@redhat.com, gshan@redhat.com,
skolothumtho@nvidia.com, sebott@redhat.com, armbru@redhat.com,
philmd@linaro.org, yangjinqian1@huawei.com, Shaju Abraham,
Mark Cave-Ayland, ping@khushitshah.com, Sandesh Patel
On 10/16/26 8:57 AM, Khushit Shah wrote:
>
>> On 15 Oct 2026, at 7:50 PM, Eric Auger <eric.auger@redhat.com> wrote:
>>
>> !-------------------------------------------------------------------|
>> CAUTION: External Email
>>
>> |-------------------------------------------------------------------!
>>
>>
>>
>> On 9/21/26 2:32 PM, Khushit Shah wrote:
>>> Introduce the 'query-cpu-props-info' QMP command. For each CPU model
>>> property, it reports the type (boolean or number) and the set of values
>>> supported under the active accelerator and host.
>>>
>>> This helps the management stack to discover which values are supported
>>> for a given CPU property. This is especially important for non-boolean
>>> properties, where knowing that the host has value 'x' does not
>>> inherently reveal the full range of valid values supported on the host.
>>> For example, an Arm host with CTR_EL0.L1Ip=3 (PIPT) also allows 2
>>> (VIPT) but a host with CTR_EL0.L1Ip=2 does not allow CTR_EL0.L1Ip=3
>>> for a guest.
>>>
>>> For numerical properties, the supported values are expressed as a list
>>> of inclusive {min, max} ranges. For boolean properties, they are
>>> represented as a list of true/false values.
>>>
>>> The command and its return types (CpuPropertyType, CpuPropertyInfo and
>>> friends) are defined in qapi/machine.json rather than an Arm-specific
>>> schema, since the concept applies to other targets (e.g. x86, RISC-V)
>>> too. Targets that do not implement it return an error.
>>> (The following commit implements the command for Arm KVM.)
>>>
>>> Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
>>> ---
>>> qapi/machine.json | 82 ++++++++++++++++++++++++++++++++++++++
>>> stubs/meson.build | 1 +
>>> stubs/qmp-cpu-props-info.c | 12 ++++++
>>> tests/qtest/qmp-cmd-test.c | 1 +
>>> 4 files changed, 96 insertions(+)
>>> create mode 100644 stubs/qmp-cpu-props-info.c
>>>
>>> diff --git a/qapi/machine.json b/qapi/machine.json
>>> index 2d63c1bac3..6e65bdad86 100644
>>> --- a/qapi/machine.json
>>> +++ b/qapi/machine.json
>>> @@ -2291,3 +2291,85 @@
>>> # Since: 1.2
>>> ##
>>> { 'command': 'query-cpu-definitions', 'returns': ['CpuDefinitionInfo'] }
>>> +
>>> +##
>>> +# @CpuPropertyType:
>>> +#
>>> +# The type of a CPU model property.
>>> +#
>>> +# @boolean: the property is of type boolean.
>>> +#
>>> +# @number: the property is of type unsigned integer.
>>> +#
>>> +# Since: 11.2
>>> +##
>>> +{ 'enum': 'CpuPropertyType',
>>> + 'data': [ 'boolean', 'number' ] }
>> why do we still need the boolean type? Can't we simplify and stick to
>> uint64_t for all SYSREG props?
> Hi Eric,
>
> Bools to support existing properties (sve, pauth, etc…) are booleans.
>>> +
>>> +##
>>> +# @CpuPropertyValueRange:
>>> +#
>>> +# An inclusive range of numeric values supported for the property.
>>> +#
>>> +# @min: the lowest supported value.
>>> +#
>>> +# @max: the highest supported value.
>>> +#
>>> +# Since: 11.2
>>> +##
>>> +{ 'struct': 'CpuPropertyValueRange',
>>> + 'data': { 'min': 'uint64', 'max': 'uint64' } }
>>> +
>>> +##
>>> +# @CpuPropertyInfoBoolean:
>>> +#
>>> +# @supported-values: list of boolean values supported for the
>>> +# property.
>>> +#
>>> +# Since: 11.2
>>> +##
>>> +{ 'struct': 'CpuPropertyInfoBoolean',
>>> + 'data': { 'supported-values': ['bool'] } }
>> why can't you model that with a range too?
> I’m sorry I didn’t get you.
I meant I don't really understand why we need to bother about boolean
props and why we don't just model everything with list of uint64 ranges.
I was puzzled by "list of boolean values supported for the property" Eric
>
> Thanks,
> Khushit
>>> +
>>> +##
>>> +# @CpuPropertyInfoNumber:
>>> +#
>>> +# @supported-values: list of numeric value ranges supported
>>> +# for the property.
>>> +#
>>> +# Since: 11.2
>>> +##
>>> +{ 'struct': 'CpuPropertyInfoNumber',
>>> + 'data': { 'supported-values': ['CpuPropertyValueRange'] } }
>>> +
>>> +##
>>> +# @CpuPropertyInfo:
>>> +#
>>> +# Information about a single CPU model property, including the values
>>> +# the host/accelerator supports for it.
>>> +#
>>> +# @name: the name of the property.
>>> +#
>>> +# @type: the type of the property, which selects the layout of
>>> +# @supported-values.
>>> +#
>>> +# Since: 11.2
>>> +##
>>> +{ 'union': 'CpuPropertyInfo',
>>> + 'base': { 'name': 'str',
>>> + 'type': 'CpuPropertyType' },
>>> + 'discriminator': 'type',
>>> + 'data': { 'boolean': 'CpuPropertyInfoBoolean',
>>> + 'number': 'CpuPropertyInfoNumber' } }
>>> +
>>> +##
>>> +# @query-cpu-props-info:
>>> +#
>>> +# Return information about the CPU model properties. For each
>>> +# property it reports the values supported under the active
>>> +# accelerator and host.
>>> +#
>>> +# Since: 11.2
>>> +##
>>> +{ 'command': 'query-cpu-props-info',
>>> + 'returns': ['CpuPropertyInfo'] }
>>> diff --git a/stubs/meson.build b/stubs/meson.build
>>> index 3b2f2680b1..3bb4028bab 100644
>>> --- a/stubs/meson.build
>>> +++ b/stubs/meson.build
>>> @@ -83,6 +83,7 @@ if have_system
>>> stub_ss.add(files('qmp-i386-sgx.c'))
>>> stub_ss.add(files('qmp-i386-xen.c'))
>>> stub_ss.add(files('qmp-cpu.c'))
>>> + stub_ss.add(files('qmp-cpu-props-info.c'))
>>> stub_ss.add(files('qmp-cpu-s390x.c'))
>>> stub_ss.add(files('qmp-cpu-s390x-kvm.c'))
>>> stub_ss.add(files('hmp-cmd-info_mem.c'))
>>> diff --git a/stubs/qmp-cpu-props-info.c b/stubs/qmp-cpu-props-info.c
>>> new file mode 100644
>>> index 0000000000..36b0530b98
>>> --- /dev/null
>>> +++ b/stubs/qmp-cpu-props-info.c
>>> @@ -0,0 +1,12 @@
>>> +/* SPDX-License-Identifier: GPL-2.0-or-later */
>>> +
>>> +#include "qemu/osdep.h"
>>> +#include "qapi/error.h"
>>> +#include "qapi/qapi-commands-machine.h"
>>> +
>>> +CpuPropertyInfoList *
>>> +qmp_query_cpu_props_info(Error **errp)
>>> +{
>>> + error_setg(errp, "query-cpu-props-info not supported on this target");
>>> + return NULL;
>>> +}
>>> diff --git a/tests/qtest/qmp-cmd-test.c b/tests/qtest/qmp-cmd-test.c
>>> index 279a8f5614..2c25dbd8cb 100644
>>> --- a/tests/qtest/qmp-cmd-test.c
>>> +++ b/tests/qtest/qmp-cmd-test.c
>>> @@ -100,6 +100,7 @@ static bool query_is_ignored(const char *cmd)
>>> "add-fd",
>>> /* Success depends on target arch: */
>>> "query-cpu-definitions", /* arm, i386, ppc, s390x */
>>> + "query-cpu-props-info", /* arm + kvm */
>>> "query-gic-capabilities", /* arm */
>>> "query-s390x-cpu-polarization", /* s390x */
>>> /* Success depends on target-specific build configuration: */
>> Thanks
>>
>> Eric
>
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH v4 23/25] qmp: add query-cpu-props-info command
2026-10-16 7:18 ` Eric Auger
@ 2026-10-16 7:28 ` Khushit Shah
0 siblings, 0 replies; 66+ messages in thread
From: Khushit Shah @ 2026-10-16 7:28 UTC (permalink / raw)
To: eric.auger@redhat.com
Cc: qemu-devel@nongnu.org, qemu-arm@nongnu.org,
kvmarm@lists.linux.dev, cohuck@redhat.com,
peter.maydell@linaro.org, richard.henderson@linaro.org,
maz@kernel.org, oliver.upton@linux.dev, berrange@redhat.com,
abologna@redhat.com, jdenemar@redhat.com, gshan@redhat.com,
skolothumtho@nvidia.com, sebott@redhat.com, armbru@redhat.com,
philmd@linaro.org, yangjinqian1@huawei.com, Shaju Abraham,
Mark Cave-Ayland, ping@khushitshah.com, Sandesh Patel
> On 16 Oct 2026, at 12:48 PM, Eric Auger <eric.auger@redhat.com> wrote:
>
> !-------------------------------------------------------------------|
> CAUTION: External Email
>
> |-------------------------------------------------------------------!
>
>
>
> On 10/16/26 8:57 AM, Khushit Shah wrote:
>>
>>> On 15 Oct 2026, at 7:50 PM, Eric Auger <eric.auger@redhat.com> wrote:
>>>
>>> !-------------------------------------------------------------------|
>>> CAUTION: External Email
>>>
>>> |-------------------------------------------------------------------!
>>>
>>>
>>>
>>> On 9/21/26 2:32 PM, Khushit Shah wrote:
>>>> Introduce the 'query-cpu-props-info' QMP command. For each CPU model
>>>> property, it reports the type (boolean or number) and the set of values
>>>> supported under the active accelerator and host.
>>>>
>>>> This helps the management stack to discover which values are supported
>>>> for a given CPU property. This is especially important for non-boolean
>>>> properties, where knowing that the host has value 'x' does not
>>>> inherently reveal the full range of valid values supported on the host.
>>>> For example, an Arm host with CTR_EL0.L1Ip=3 (PIPT) also allows 2
>>>> (VIPT) but a host with CTR_EL0.L1Ip=2 does not allow CTR_EL0.L1Ip=3
>>>> for a guest.
>>>>
>>>> For numerical properties, the supported values are expressed as a list
>>>> of inclusive {min, max} ranges. For boolean properties, they are
>>>> represented as a list of true/false values.
>>>>
>>>> The command and its return types (CpuPropertyType, CpuPropertyInfo and
>>>> friends) are defined in qapi/machine.json rather than an Arm-specific
>>>> schema, since the concept applies to other targets (e.g. x86, RISC-V)
>>>> too. Targets that do not implement it return an error.
>>>> (The following commit implements the command for Arm KVM.)
>>>>
>>>> Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
>>>> ---
>>>> qapi/machine.json | 82 ++++++++++++++++++++++++++++++++++++++
>>>> stubs/meson.build | 1 +
>>>> stubs/qmp-cpu-props-info.c | 12 ++++++
>>>> tests/qtest/qmp-cmd-test.c | 1 +
>>>> 4 files changed, 96 insertions(+)
>>>> create mode 100644 stubs/qmp-cpu-props-info.c
>>>>
>>>> diff --git a/qapi/machine.json b/qapi/machine.json
>>>> index 2d63c1bac3..6e65bdad86 100644
>>>> --- a/qapi/machine.json
>>>> +++ b/qapi/machine.json
>>>> @@ -2291,3 +2291,85 @@
>>>> # Since: 1.2
>>>> ##
>>>> { 'command': 'query-cpu-definitions', 'returns': ['CpuDefinitionInfo'] }
>>>> +
>>>> +##
>>>> +# @CpuPropertyType:
>>>> +#
>>>> +# The type of a CPU model property.
>>>> +#
>>>> +# @boolean: the property is of type boolean.
>>>> +#
>>>> +# @number: the property is of type unsigned integer.
>>>> +#
>>>> +# Since: 11.2
>>>> +##
>>>> +{ 'enum': 'CpuPropertyType',
>>>> + 'data': [ 'boolean', 'number' ] }
>>> why do we still need the boolean type? Can't we simplify and stick to
>>> uint64_t for all SYSREG props?
>> Hi Eric,
>>
>> Bools to support existing properties (sve, pauth, etc…) are booleans.
>>>> +
>>>> +##
>>>> +# @CpuPropertyValueRange:
>>>> +#
>>>> +# An inclusive range of numeric values supported for the property.
>>>> +#
>>>> +# @min: the lowest supported value.
>>>> +#
>>>> +# @max: the highest supported value.
>>>> +#
>>>> +# Since: 11.2
>>>> +##
>>>> +{ 'struct': 'CpuPropertyValueRange',
>>>> + 'data': { 'min': 'uint64', 'max': 'uint64' } }
>>>> +
>>>> +##
>>>> +# @CpuPropertyInfoBoolean:
>>>> +#
>>>> +# @supported-values: list of boolean values supported for the
>>>> +# property.
>>>> +#
>>>> +# Since: 11.2
>>>> +##
>>>> +{ 'struct': 'CpuPropertyInfoBoolean',
>>>> + 'data': { 'supported-values': ['bool'] } }
>>> why can't you model that with a range too?
>> I’m sorry I didn’t get you.
>
> I meant I don't really understand why we need to bother about boolean
> props and why we don't just model everything with list of uint64 ranges.
> I was puzzled by "list of boolean values supported for the property”
Boolean properties are for the sake of completeness.
They will cover, sve, pauth, sveNNNN, aarch64 etc…. Except aarch64,
all of them are modelled as: If hosts supports true, it also supports
false.
So the output of this qmp command for a boolean property can be:
[true], [false], [true, false]
I hope this clears the confusion.
Thanks,
Khushit
> Eric
>>
>> Thanks,
>> Khushit
>>>> +
>>>> +##
>>>> +# @CpuPropertyInfoNumber:
>>>> +#
>>>> +# @supported-values: list of numeric value ranges supported
>>>> +# for the property.
>>>> +#
>>>> +# Since: 11.2
>>>> +##
>>>> +{ 'struct': 'CpuPropertyInfoNumber',
>>>> + 'data': { 'supported-values': ['CpuPropertyValueRange'] } }
>>>> +
>>>> +##
>>>> +# @CpuPropertyInfo:
>>>> +#
>>>> +# Information about a single CPU model property, including the values
>>>> +# the host/accelerator supports for it.
>>>> +#
>>>> +# @name: the name of the property.
>>>> +#
>>>> +# @type: the type of the property, which selects the layout of
>>>> +# @supported-values.
>>>> +#
>>>> +# Since: 11.2
>>>> +##
>>>> +{ 'union': 'CpuPropertyInfo',
>>>> + 'base': { 'name': 'str',
>>>> + 'type': 'CpuPropertyType' },
>>>> + 'discriminator': 'type',
>>>> + 'data': { 'boolean': 'CpuPropertyInfoBoolean',
>>>> + 'number': 'CpuPropertyInfoNumber' } }
>>>> +
>>>> +##
>>>> +# @query-cpu-props-info:
>>>> +#
>>>> +# Return information about the CPU model properties. For each
>>>> +# property it reports the values supported under the active
>>>> +# accelerator and host.
>>>> +#
>>>> +# Since: 11.2
>>>> +##
>>>> +{ 'command': 'query-cpu-props-info',
>>>> + 'returns': ['CpuPropertyInfo'] }
>>>> diff --git a/stubs/meson.build b/stubs/meson.build
>>>> index 3b2f2680b1..3bb4028bab 100644
>>>> --- a/stubs/meson.build
>>>> +++ b/stubs/meson.build
>>>> @@ -83,6 +83,7 @@ if have_system
>>>> stub_ss.add(files('qmp-i386-sgx.c'))
>>>> stub_ss.add(files('qmp-i386-xen.c'))
>>>> stub_ss.add(files('qmp-cpu.c'))
>>>> + stub_ss.add(files('qmp-cpu-props-info.c'))
>>>> stub_ss.add(files('qmp-cpu-s390x.c'))
>>>> stub_ss.add(files('qmp-cpu-s390x-kvm.c'))
>>>> stub_ss.add(files('hmp-cmd-info_mem.c'))
>>>> diff --git a/stubs/qmp-cpu-props-info.c b/stubs/qmp-cpu-props-info.c
>>>> new file mode 100644
>>>> index 0000000000..36b0530b98
>>>> --- /dev/null
>>>> +++ b/stubs/qmp-cpu-props-info.c
>>>> @@ -0,0 +1,12 @@
>>>> +/* SPDX-License-Identifier: GPL-2.0-or-later */
>>>> +
>>>> +#include "qemu/osdep.h"
>>>> +#include "qapi/error.h"
>>>> +#include "qapi/qapi-commands-machine.h"
>>>> +
>>>> +CpuPropertyInfoList *
>>>> +qmp_query_cpu_props_info(Error **errp)
>>>> +{
>>>> + error_setg(errp, "query-cpu-props-info not supported on this target");
>>>> + return NULL;
>>>> +}
>>>> diff --git a/tests/qtest/qmp-cmd-test.c b/tests/qtest/qmp-cmd-test.c
>>>> index 279a8f5614..2c25dbd8cb 100644
>>>> --- a/tests/qtest/qmp-cmd-test.c
>>>> +++ b/tests/qtest/qmp-cmd-test.c
>>>> @@ -100,6 +100,7 @@ static bool query_is_ignored(const char *cmd)
>>>> "add-fd",
>>>> /* Success depends on target arch: */
>>>> "query-cpu-definitions", /* arm, i386, ppc, s390x */
>>>> + "query-cpu-props-info", /* arm + kvm */
>>>> "query-gic-capabilities", /* arm */
>>>> "query-s390x-cpu-polarization", /* s390x */
>>>> /* Success depends on target-specific build configuration: */
>>> Thanks
>>>
>>> Eric
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH v4 10/25] target/arm: fix SVE and PAuth finalize for named CPU models
2026-10-15 13:01 ` Eric Auger
@ 2026-10-16 7:34 ` Khushit Shah
0 siblings, 0 replies; 66+ messages in thread
From: Khushit Shah @ 2026-10-16 7:34 UTC (permalink / raw)
To: eric.auger@redhat.com
Cc: qemu-devel@nongnu.org, qemu-arm@nongnu.org,
kvmarm@lists.linux.dev, cohuck@redhat.com,
peter.maydell@linaro.org, richard.henderson@linaro.org,
maz@kernel.org, oliver.upton@linux.dev, berrange@redhat.com,
abologna@redhat.com, jdenemar@redhat.com, gshan@redhat.com,
skolothumtho@nvidia.com, sebott@redhat.com, armbru@redhat.com,
philmd@linaro.org, yangjinqian1@huawei.com, Shaju Abraham,
Mark Cave-Ayland, ping@khushitshah.com, Sandesh Patel
> On 15 Oct 2026, at 6:31 PM, Eric Auger <eric.auger@redhat.com> wrote:
>
> !-------------------------------------------------------------------|
> CAUTION: External Email
>
> |-------------------------------------------------------------------!
>
> Hi Khushit,
>
> On 9/21/26 2:32 PM, Khushit Shah wrote:
>> As named CPU models define their feature set explicitly, their SVE
>> vector lengths and PAuth fields must not be derived from the host.
>>
>> When SVE is enabled without an sve<N> setting, require the named model
>> to specify its supported vector lengths rather than inheriting them from
>> the host.
>>
>> Named models set PAuth ID register fields directly through SYSREG_
>> properties. Preserve these values in PAuth finalization.
>>
>> Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
>> ---
>> target/arm/cpu64.c | 33 +++++++++++++++++++++++++++++++++
>> 1 file changed, 33 insertions(+)
>>
>> diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
>> index 7487b48cc9..a0114b0fa2 100644
>> --- a/target/arm/cpu64.c
>> +++ b/target/arm/cpu64.c
>> @@ -38,6 +38,7 @@
>> #include "internals.h"
>> #include "cpu-features.h"
>> #include "cpu-idregs.h"
>> +#include "cpu-models.h"
>> #include "trace.h"
>>
>> /* convert between <register>_IDX and SYS_<register> */
>> @@ -134,6 +135,21 @@ void aarch64_cpu_sve_finalize(ARMCPU *cpu, Error **errp)
>> return;
>> }
>>
>> +#ifndef CONFIG_USER_ONLY
> I don't get why do you need that #ifndef?
Hi Eric,
Yeah, thanks, removed.
>> + /*
>> + * If SVE is enabled but no vector lengths are specified, we must not
>> + * default to the host's supported lengths for named CPU models.
>> + */
>> + {
>> + ARMCPUClass *acc = ARM_CPU_GET_CLASS(cpu);
>> + if (acc->info && arm_find_model(acc->info->name)) {
>> + error_setg(errp,
>> + "Named CPU models with SVE must set vector lengths");
>> + return;
>> + }
>> + }
>> +#endif
>> +
>> if (kvm_enabled()) {
>> /* Disabling a supported length disables all larger lengths. */
>> tmp = vq_init & vq_supported;
>> @@ -556,6 +572,23 @@ void aarch64_cpu_pauth_finalize(ARMCPU *cpu, Error **errp)
>> ARMISARegisters *isar = &cpu->isar;
>> uint64_t isar1, isar2;
>>
>> +#ifndef CONFIG_USER_ONLY
>> + /*
>> + * For named CPU models the model props write the authoritative
>> + * APA/API/APA3/GPA/GPI/GPA3 values directly into cpu->isar through
> all those fields ar not KVM writable currently.
Correct, but here we are letting the named model build it’s ID register view.
Later in writeback (based on v9), we error out if the KVM’s and model’s ID
register view disagree.
>> + * SYSREG_ properties, so do not override them here. Since other code
>> + * relies on cpu->prop_pauth, mirror the resulting pauth state into
>> + * cpu->prop_pauth.
>> + */
>> + {
>> + ARMCPUClass *acc = ARM_CPU_GET_CLASS(cpu);
>> + if (acc->info && arm_find_model(acc->info->name)) {
>> + cpu->prop_pauth = cpu_isar_feature(aa64_pauth, cpu);
>> + return;
>> + }
>> + }
>> +#endif
> If I understand correctly all the isar1/isar2 manipulations afterwards
> only affect TCG.
> In KVM mode, although isar1/isar2 fields are reset afterwards this does
> not impact the guest view so most probably the isa1/2 reset + finale
> update could be moved to the !hw_accel block and you put that addition
> in the hwaccel_enabled() block, or am i wrong?
For the current patch series, the QEMU idregs[] directly affects KVM’s
idregs. So, if pauth is disabled, KVM will erase _APA/_GPA, during
writeback check that KVM’s _APA/_GPA matches QEMU’s values. So, if we
do not reset these here, then the condition will fail.
I need to look at v10 in detail to understand what will happen there.
Thanks,
Khushit
> Thanks
>
> Eric
>> +
>> /*
>> * These properties enable or disable Pauth as a whole, or change
>> * the pauth algorithm, but do not change the set of features that
>
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH v4 12/25] target/arm: add arm-v9.0-a-v1 named CPU model
2026-09-21 12:32 ` [RFC PATCH v4 12/25] target/arm: add arm-v9.0-a-v1 named CPU model Khushit Shah
@ 2026-10-16 12:07 ` Eric Auger
2026-10-16 12:24 ` Peter Maydell
0 siblings, 1 reply; 66+ messages in thread
From: Eric Auger @ 2026-10-16 12:07 UTC (permalink / raw)
To: Khushit Shah, qemu-devel, qemu-arm, kvmarm
Cc: cohuck, peter.maydell, richard.henderson, maz, oliver.upton,
berrange, abologna, jdenemar, gshan, skolothumtho, sebott, armbru,
philmd, yangjinqian1, shaju.abraham, mark.caveayland, ping,
sandesh.patel
Hi Khushit,
On 9/21/26 2:32 PM, Khushit Shah wrote:
> Add a KVM-only named CPU model for the Armv9.0-A baseline, following
> DDI0487 revision M.c. The property list is the architecture-mandated
> ID-register field view.
>
> Pointer authentication is omitted because a v9.0-A core may implement
> any PAuth algorithm.
>
> Named models start from a zeroed ID-register view, so features whose
> "not implemented" encoding is non-zero (for example TGran64=0xF,
> DoubleLock=0xF) are set explicitly.
>
> The model is not realizable on its own; implementation-defined fields
> such as CTR_EL0.{CWG,ERG} and ID_AA64DFR0_EL1.CTX_CMPs still have to be
> supplied on the command line. However, this provides a useful baseline
> for upcoming reference core models.
>
> Final ID register state requested from KVM for "arm-v9.0-a-v1":
> [ 0] AIDR_EL1 = 0x0000000000000000
> [ 1] CLIDR_EL1 = 0x0000000000000000
> [ 2] CTR_EL0 = 0x0000000080008000
> [ 3] DCZID_EL0 = 0x0000000000000000
> [ 4] GMID_EL1 = 0x0000000000000000
> [ 5] ID_AA64AFR0_EL1 = 0x0000000000000000
> [ 6] ID_AA64AFR1_EL1 = 0x0000000000000000
> [ 7] ID_AA64DFR0_EL1 = 0x000000f000000009
> [ 8] ID_AA64DFR1_EL1 = 0x0000000000000000
> [ 9] ID_AA64DFR2_EL1 = 0x0000000000000000
> [ 10] ID_AA64FPFR0_EL1 = 0x0000000000000000
> [ 11] ID_AA64ISAR0_EL1 = 0x0221100010210000
> [ 12] ID_AA64ISAR1_EL1 = 0x0000011100211002
> [ 13] ID_AA64ISAR2_EL1 = 0x0000000000000000
> [ 14] ID_AA64ISAR3_EL1 = 0x0000000000000000
> [ 15] ID_AA64MMFR0_EL1 = 0x000001110f000000
> [ 16] ID_AA64MMFR1_EL1 = 0x0000000000211000
> [ 17] ID_AA64MMFR2_EL1 = 0x1001001100000011
> [ 18] ID_AA64MMFR3_EL1 = 0x0000000000000000
> [ 19] ID_AA64MMFR4_EL1 = 0x000000000f000000
> [ 20] ID_AA64PFR0_EL1 = 0x1101000010110011
> [ 21] ID_AA64PFR1_EL1 = 0x0000000000000001
> [ 22] ID_AA64PFR2_EL1 = 0x0000000000000000
> [ 23] ID_AA64SMFR0_EL1 = 0x0000000000000000
> [ 24] ID_AA64ZFR0_EL1 = 0x0000000000000000
> [ 25] ID_AFR0_EL1 = 0x0000000000000000
> [ 26] ID_DFR0_EL1 = 0x0000000000000000
> [ 27] ID_DFR1_EL1 = 0x0000000000000000
> [ 28] ID_ISAR0_EL1 = 0x0000000000000000
> [ 29] ID_ISAR1_EL1 = 0x0000000000000000
> [ 30] ID_ISAR2_EL1 = 0x0000000000000000
> [ 31] ID_ISAR3_EL1 = 0x0000000000000000
> [ 32] ID_ISAR4_EL1 = 0x0000000000000000
> [ 33] ID_ISAR5_EL1 = 0x0000000000000000
> [ 34] ID_ISAR6_EL1 = 0x0000000000000000
> [ 35] ID_MMFR0_EL1 = 0x0000000000000000
> [ 36] ID_MMFR1_EL1 = 0x0000000000000000
> [ 37] ID_MMFR2_EL1 = 0x0000000000000000
> [ 38] ID_MMFR3_EL1 = 0x0000000000000000
> [ 39] ID_MMFR4_EL1 = 0x0000000000000000
> [ 40] ID_MMFR5_EL1 = 0x0000000000000000
> [ 41] ID_PFR0_EL1 = 0x0000000000000000
> [ 42] ID_PFR1_EL1 = 0x0000000000000000
> [ 43] ID_PFR2_EL1 = 0x0000000000000000
> [ 44] MIDR_EL1 = 0x0000000000000000
> [ 45] MPIDR_EL1 = 0x0000000080000000
> [ 46] MVFR0_EL1 = 0x0000000000000000
> [ 47] MVFR1_EL1 = 0x0000000000000000
> [ 48] MVFR2_EL1 = 0x0000000000000000
> [ 49] REVIDR_EL1 = 0x0000000000000000
> [ 50] SMIDR_EL1 = 0x0000000000000000
>
> Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
> ---
> hw/arm/virt.c | 3 ++
> target/arm/cpu-models.c | 75 +++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 78 insertions(+)
>
> diff --git a/hw/arm/virt.c b/hw/arm/virt.c
> index e7a56e37f7..01381ab5e7 100644
> --- a/hw/arm/virt.c
> +++ b/hw/arm/virt.c
> @@ -4144,6 +4144,9 @@ static GPtrArray *virt_get_valid_cpu_types(const MachineState *ms)
> g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("neoverse-v1")));
> g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("neoverse-n2")));
> }
> + if (kvm_enabled() && target_aarch64()) {
> + g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("arm-v9.0-a-v1")));
> + }
> if (target_aarch64()) {
> g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("cortex-a53")));
> g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("cortex-a57")));
> diff --git a/target/arm/cpu-models.c b/target/arm/cpu-models.c
> index 153ee10ae6..7394dd358e 100644
> --- a/target/arm/cpu-models.c
> +++ b/target/arm/cpu-models.c
> @@ -39,7 +39,82 @@
> /* Maximum parent-chain depth for named CPU models. */
> #define ARM_NAMED_CPU_MODEL_MAX_DEPTH 16
>
> +/* Arm-v9.0-a mandatory features. */
> +static const ArmModelPropValue arm_v9_0_a_v1_props[] = {
> + /* ID_AA64PFR0_EL1 */
> + MODEL_PROP("SYSREG_ID_AA64PFR0_EL1_EL0", NUM, 1), /* only FEAT_AA64EL0 (Armv9.0) */
> + MODEL_PROP("SYSREG_ID_AA64PFR0_EL1_EL1", NUM, 1), /* only FEAT_AA64EL1 (Armv9.0) */
> + MODEL_PROP("SYSREG_ID_AA64PFR0_EL1_RAS", NUM, 1), /* FEAT_RAS (Armv8.2) */
> + MODEL_PROP("SYSREG_ID_AA64PFR0_EL1_DIT", NUM, 1), /* FEAT_DIT (Armv8.4) */
> + MODEL_PROP("SYSREG_ID_AA64PFR0_EL1_CSV2", NUM, 1), /* FEAT_CSV2 (Armv8.5) */
> + MODEL_PROP("SYSREG_ID_AA64PFR0_EL1_CSV3", NUM, 1), /* FEAT_CSV3 (Armv8.5) */
> + MODEL_PROP("SYSREG_ID_AA64PFR0_EL1_FP", NUM, 1), /* FEAT_FP16 */
> + MODEL_PROP("SYSREG_ID_AA64PFR0_EL1_AdvSIMD", NUM, 1), /* FEAT_FP16 */
I have not found that FP+AdvSIMD (ie FEAT_FP16) were mandated by v9.0
amybe you want this model to implement FP16 but it does not seems
strictly mandated in v9.0
so it might be distinguished from other settings that are truly mandated.
> +
> + /* ID_AA64PFR1_EL1 */
> + /* KVM zeroes out these field when MTE is not enabled. */
> + MODEL_PROP("SYSREG_ID_AA64PFR1_EL1_MTE_frac", NUM, 0),
useless as default is 0, no?
> + MODEL_PROP("SYSREG_ID_AA64PFR1_EL1_BT", NUM, 1), /* FEAT_BTI (Armv8.5) */
> +
> + /* ID_AA64MMFR0_EL1 */
> + MODEL_PROP("SYSREG_ID_AA64MMFR0_EL1_TGran64", NUM, 0xF), /* not mandatory */
> + MODEL_PROP("SYSREG_ID_AA64MMFR0_EL1_TGran4", NUM, 0), /* 4K granular support */
> + MODEL_PROP("SYSREG_ID_AA64MMFR0_EL1_TGran16_2", NUM, 1), /* not mandatory */
> + MODEL_PROP("SYSREG_ID_AA64MMFR0_EL1_TGran64_2", NUM, 1), /* not mandatory */
> + MODEL_PROP("SYSREG_ID_AA64MMFR0_EL1_TGran4_2", NUM, 1), /* not mandatory */
so the top comment, ie.
+/* Arm-v9.0-a mandatory features. */
should really be updated accordingly. None of that is mandated by v9.0
spec, right?
|
|
> +
> + /* ID_AA64DFR0_EL1 */
> + MODEL_PROP("SYSREG_ID_AA64DFR0_EL1_DebugVer", NUM, 9), /* FEAT_Debugv8p4 (Armv8.4) */
> + MODEL_PROP("SYSREG_ID_AA64DFR0_EL1_DoubleLock", NUM, 0xF), /* not implemented */
I understand this is mandated by v9.0, ie v9Ap0 ==> (!FEAT_DoubleLock)
> + /* no PMU for named models */
> + MODEL_PROP("SYSREG_ID_AA64DFR0_EL1_PMUVer", NUM, 0),
not needed?
> +
> + /* CTR_EL0 */
> + MODEL_PROP("SYSREG_CTR_EL0_L1Ip", NUM, 2), /* FEAT_IVIPT: VIPT cache impl. */
ARMv8.0
> +
> + /* ID_AA64MMFR4_EL1 */
> + MODEL_PROP("SYSREG_ID_AA64MMFR4_EL1_E2H0", NUM, 0xF), /* FEAT_E2H0 not mandatory */
not mandatory. All the non mandatory settings might rather go in the
neoverse child, no? That way it is easier to understand the role of this
parent which enforce mandatory features only
> +
> + /* ID_AA64ISAR0_EL1 */
> + MODEL_PROP("SYSREG_ID_AA64ISAR0_EL1_CRC32", NUM, 1), /* FEAT_CRC32 (Armv8.1) */
> + MODEL_PROP("SYSREG_ID_AA64ISAR0_EL1_Atomic", NUM, 2), /* FEAT_LSE (Armv8.1) */
> + MODEL_PROP("SYSREG_ID_AA64ISAR0_EL1_TS", NUM, 2), /* FEAT_FlagM2 (Armv9.0 & FP) */
this is required because FP was opt-in. Otherwise v9.0 does not require
2. As far as I understand there is no v9Ap0 ==> FEAT_FP
> + MODEL_PROP("SYSREG_ID_AA64ISAR0_EL1_TLB", NUM, 2), /* FEAT_TLBIRANGE (Armv8.4) */
> + MODEL_PROP("SYSREG_ID_AA64ISAR0_EL1_RDM", NUM, 1), /* FEAT_RDM (Armv9.0 & FP) */
> + MODEL_PROP("SYSREG_ID_AA64ISAR0_EL1_DP", NUM, 1), /* FEAT_DotProd (Armv9.0 & FP) */
> + MODEL_PROP("SYSREG_ID_AA64ISAR0_EL1_FHM", NUM, 1), /* FEAT_FHM (Armv9.0 & FP) */
> +
> + /* ID_AA64ISAR1_EL1 */
> + MODEL_PROP("SYSREG_ID_AA64ISAR1_EL1_LRCPC", NUM, 2), /* FEAT_LRCPC2 (Armv8.4) */
> + MODEL_PROP("SYSREG_ID_AA64ISAR1_EL1_FRINTTS", NUM, 1), /* FEAT_FRINTTS (v9.0 & FP) */
> + MODEL_PROP("SYSREG_ID_AA64ISAR1_EL1_FCMA", NUM, 1), /* FEAT_FCMA (Armv9.0 & FP) */
> + MODEL_PROP("SYSREG_ID_AA64ISAR1_EL1_JSCVT", NUM, 1), /* FEAT_JSCVT (Armv9.0 & FP) */
> + MODEL_PROP("SYSREG_ID_AA64ISAR1_EL1_DPB", NUM, 2), /* FEAT_DPB2 (Armv8.5) */
> + MODEL_PROP("SYSREG_ID_AA64ISAR1_EL1_SB", NUM, 1), /* FEAT_SB (Armv8.5) */
> + MODEL_PROP("SYSREG_ID_AA64ISAR1_EL1_SPECRES", NUM, 1), /* FEAT_SPECRES (Armv8.5) */
For readability please groups all fields that are mandated if v9.0 + FP
+ AdvSIMD. This is still arguable if this shall be part of this model
though
> + /*
> + * FEAT_PAuth is mandated by Armv8.3 but is excluded here as reference
> + * core can choose to implement any PAuth algorithm (APA/API/APA3).
Can you set a default value then? GPI/API <= 1 or GPA3/APA3. This mens
the child will need to override.
Without that you cannot claim this model to ve v9.0 compliant.
I guess you need to document all named vcpu models in either
docs/system/arm/cpu-features.rst
There is also docs/system/qemu-cpu-models.rst
> + */
> +
> + /* ID_AA64MMFR1_EL1 */
nit reorder after AA64_MFR0. All values below look good to me
> + MODEL_PROP("SYSREG_ID_AA64MMFR1_EL1_HPDS", NUM, 1), /* FEAT_HPDS (Armv8.1) */
> + MODEL_PROP("SYSREG_ID_AA64MMFR1_EL1_LO", NUM, 1), /* FEAT_LOR (Armv8.1) */
> + MODEL_PROP("SYSREG_ID_AA64MMFR1_EL1_PAN", NUM, 2), /* FEAT_PAN2 (Armv8.2) */
> +
> + /* ID_AA64MMFR2_EL1 */
> + MODEL_PROP("SYSREG_ID_AA64MMFR2_EL1_UAO", NUM, 1), /* FEAT_UAO (Armv8.2) */
> + MODEL_PROP("SYSREG_ID_AA64MMFR2_EL1_CnP", NUM, 1), /* FEAT_TTCNP (Armv8.2) */
> + MODEL_PROP("SYSREG_ID_AA64MMFR2_EL1_TTL", NUM, 1), /* FEAT_TTL (Armv8.4) */
> + MODEL_PROP("SYSREG_ID_AA64MMFR2_EL1_AT", NUM, 1), /* FEAT_LSE2 (Armv8.4) */
> + MODEL_PROP("SYSREG_ID_AA64MMFR2_EL1_IDS", NUM, 1), /* FEAT_IDST (Armv8.4) */
> + MODEL_PROP("SYSREG_ID_AA64MMFR2_EL1_E0PD", NUM, 1), /* FEAT_E0PD (Armv8.5) */
> +
> + MODEL_PROP_END,
> +};
> +
> static const ArmNamedCpuModel arm_cpu_models[] = {
> + {"arm-v9.0-a-v1", NULL, arm_v9_0_a_v1_props},
> {NULL, NULL, NULL}
> };
>
Thanks
Eric
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH v4 12/25] target/arm: add arm-v9.0-a-v1 named CPU model
2026-10-16 12:07 ` Eric Auger
@ 2026-10-16 12:24 ` Peter Maydell
0 siblings, 0 replies; 66+ messages in thread
From: Peter Maydell @ 2026-10-16 12:24 UTC (permalink / raw)
To: eric.auger
Cc: Khushit Shah, qemu-devel, qemu-arm, kvmarm, cohuck,
richard.henderson, maz, oliver.upton, berrange, abologna,
jdenemar, gshan, skolothumtho, sebott, armbru, philmd,
yangjinqian1, shaju.abraham, mark.caveayland, ping, sandesh.patel
On Fri, 16 Oct 2026 at 13:07, Eric Auger <eric.auger@redhat.com> wrote:
>
> Hi Khushit,
>
> On 9/21/26 2:32 PM, Khushit Shah wrote:
> > Add a KVM-only named CPU model for the Armv9.0-A baseline, following
> > DDI0487 revision M.c. The property list is the architecture-mandated
> > ID-register field view.
> > +static const ArmModelPropValue arm_v9_0_a_v1_props[] = {
> > + /* ID_AA64PFR0_EL1 */
> > + MODEL_PROP("SYSREG_ID_AA64PFR0_EL1_EL0", NUM, 1), /* only FEAT_AA64EL0 (Armv9.0) */
> > + MODEL_PROP("SYSREG_ID_AA64PFR0_EL1_EL1", NUM, 1), /* only FEAT_AA64EL1 (Armv9.0) */
> > + MODEL_PROP("SYSREG_ID_AA64PFR0_EL1_RAS", NUM, 1), /* FEAT_RAS (Armv8.2) */
> > + MODEL_PROP("SYSREG_ID_AA64PFR0_EL1_DIT", NUM, 1), /* FEAT_DIT (Armv8.4) */
> > + MODEL_PROP("SYSREG_ID_AA64PFR0_EL1_CSV2", NUM, 1), /* FEAT_CSV2 (Armv8.5) */
> > + MODEL_PROP("SYSREG_ID_AA64PFR0_EL1_CSV3", NUM, 1), /* FEAT_CSV3 (Armv8.5) */
> > + MODEL_PROP("SYSREG_ID_AA64PFR0_EL1_FP", NUM, 1), /* FEAT_FP16 */
> > + MODEL_PROP("SYSREG_ID_AA64PFR0_EL1_AdvSIMD", NUM, 1), /* FEAT_FP16 */
> I have not found that FP+AdvSIMD (ie FEAT_FP16) were mandated by v9.0
> amybe you want this model to implement FP16 but it does not seems
> strictly mandated in v9.0
> so it might be distinguished from other settings that are truly mandated.
FP/AdvSIMD is one of those things that's technically optional (because
you might have some extremely-embedded special purpose device that
doesn't want FP) but in practice is mandatory. (The Arm ARM says
"This option [no FP] is licensed only for implementations targeting
specialized markets". Anything that might be running Linux and KVM
is not that.
> > +
> > + /* ID_AA64PFR1_EL1 */
> > + /* KVM zeroes out these field when MTE is not enabled. */
> > + MODEL_PROP("SYSREG_ID_AA64PFR1_EL1_MTE_frac", NUM, 0),
> useless as default is 0, no?
> > + MODEL_PROP("SYSREG_ID_AA64PFR1_EL1_BT", NUM, 1), /* FEAT_BTI (Armv8.5) */
>
>
> > +
> > + /* ID_AA64MMFR0_EL1 */
> > + MODEL_PROP("SYSREG_ID_AA64MMFR0_EL1_TGran64", NUM, 0xF), /* not mandatory */
> > + MODEL_PROP("SYSREG_ID_AA64MMFR0_EL1_TGran4", NUM, 0), /* 4K granular support */
> > + MODEL_PROP("SYSREG_ID_AA64MMFR0_EL1_TGran16_2", NUM, 1), /* not mandatory */
> > + MODEL_PROP("SYSREG_ID_AA64MMFR0_EL1_TGran64_2", NUM, 1), /* not mandatory */
> > + MODEL_PROP("SYSREG_ID_AA64MMFR0_EL1_TGran4_2", NUM, 1), /* not mandatory */
> so the top comment, ie.
>
> +/* Arm-v9.0-a mandatory features. */
>
> should really be updated accordingly. None of that is mandated by v9.0
> spec, right?
The comments here are confusing, because what we really want to point
out here is that for these fields the "not implemented" value is not
always "0" (in some cases it's 0b1111 and in some 0b0001). Where we
set some non-0 value that is the "not implemented" value we should
say that.
Also, no particular granule size is mandatory; you just need to support
at least one, and 4K is most popular, but you can have just 16K or
just 64K if you want. So this is making an actual choice.
-- PMM
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH v4 17/25] target/arm: fail named CPU models on unknown non-zero feature ID regs
2026-09-21 12:32 ` [RFC PATCH v4 17/25] target/arm: fail named CPU models on unknown non-zero feature ID regs Khushit Shah
@ 2026-10-16 12:27 ` Eric Auger
0 siblings, 0 replies; 66+ messages in thread
From: Eric Auger @ 2026-10-16 12:27 UTC (permalink / raw)
To: Khushit Shah, qemu-devel, qemu-arm, kvmarm
Cc: cohuck, peter.maydell, richard.henderson, maz, oliver.upton,
berrange, abologna, jdenemar, gshan, skolothumtho, sebott, armbru,
philmd, yangjinqian1, shaju.abraham, mark.caveayland, ping,
sandesh.patel
Hi Khushit
On 9/21/26 2:32 PM, Khushit Shah wrote:
> Named CPU models zero the ID registers QEMU knows about and then apply
> SYSREG_ properties. However, the host and KVM might expose ID
> registers that QEMU does not know about yet. In this scenario, named
this may also happen with reserved fields becoming named, no?
> CPU models might
\n
> leak host features to the guest.
>
> Part of the problem can be addressed because the Arm Architecture
> Reference Manual specifies that unused encodings in the space (op1==0,
> CRn==0, CRm=={2-7}) may be treated as RES0. This range includes all
> ID_AA64* registers.
actually the KVM writable API covers AArch64 System register space
with op0==3, op1=={0, 1, 3}, CRn==0, CRm=={0-7}, op2=={0-7}.
so do you mean you only check part of the space. In the positive don't we need to be more precise and check for a given opcode if it is known
>
> Error out if KVM returns a non-zero value for a register in the above
> space which QEMU does not know about yet.
>
> get_sysreg_idx() now returns -1 for encodings that are not known ID
> registers, and kvm_arm_read_sys_reg64() exposes a KVM GET_ONE_REG
> read for this probe.
>
> Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
> ---
> target/arm/cpu-models.c | 74 ++++++++++++++++++++++++++++++++++++++++
> target/arm/cpu-sysregs.h | 2 +-
> target/arm/cpu64.c | 3 +-
> target/arm/kvm-stub.c | 7 ++++
> target/arm/kvm.c | 7 ++++
> target/arm/kvm_arm.h | 12 +++++++
> 6 files changed, 103 insertions(+), 2 deletions(-)
>
> diff --git a/target/arm/cpu-models.c b/target/arm/cpu-models.c
> index 4e92909755..855eb5ee6b 100644
> --- a/target/arm/cpu-models.c
> +++ b/target/arm/cpu-models.c
> @@ -362,6 +362,78 @@ static void reset_res1_fields(ARMCPU *cpu)
> }
> }
>
> +/*
> + * From ARM ARM:
> + *
> + * For unused encodings in the part of the space that has op1==0 and
> + * CRm=={2-7}, direct reads that are not trapped behave as Reserved,
> + * RES0 to ensure correct behavior if the encodings are used for ID
> + * registers in the future.
> + *
> + * It includes every ID_AA64* register.
> + *
> + * For named CPU models, we can check if any of the unknown ID registers
> + * that fall into this space is non-zero on the host. If so, the named CPU
> + * model leaks those host features. Error out in such case.
> + *
> + * We cannot do the same for the remaining Feature ID space (op1==0 and
> + * CRm==0, or op1=={1,3}). Unused encodings there are UNDEFINED. The
> + * implemented registers in that space (MIDR_EL1, CTR_EL0, DCZID_EL0,
> + * CCSIDR_EL1, ...) are identification or cache geometry.
> + */
> +static void arm_named_cpu_zero_unknown_feature_ids(ARMCPU *cpu, Error **errp)
> +{
> + uint32_t init_features0 = 0;
> + static bool checked;
> + uint32_t target;
> + int fdarray[3];
> + int crm, op2;
> + int fd;
> +
> + if (checked) {
> + return;
> + }
> +
> + if (!kvm_arm_create_scratch_max_host_vcpu(fdarray, &init_features0,
> + &target, errp)) {
can't we do that when we retrieve the host features on the 1st created
scratch vcpu. We shall avoid creating too many of them if possible
> + return;
> + }
> +
> + fd = fdarray[2];
> + for (crm = 2; crm <= 7; crm++) {
> + for (op2 = 0; op2 <= 7; op2++) {
> + uint64_t val = 0;
> + int ret;
> +
> + if (get_sysreg_idx(ENCODE_ID_REG(3, 0, 0, crm, op2)) != -1) {
> + continue;
> + }
> +
> + ret = kvm_arm_read_sys_reg64(fd, &val, 3, 0, 0, crm, op2);
> + if (ret) {
> + continue;
> + }
> +
> + /*
> + * TODO: if this encoding is writable, try to write 0?
> + */
> + if (val) {
> + error_setg(errp,
> + "unknown Feature ID register "
> + "(op0=3, op1=0, CRn=0, CRm=%d, op2=%d) "
> + "reads as 0x%" PRIx64 " on the host; named CPU "
> + "models cannot hide it",
> + crm, op2, val);
> + kvm_arm_destroy_scratch_host_vcpu(fdarray);
> + return;
> + }
> + }
> + }
> +
> + kvm_arm_destroy_scratch_host_vcpu(fdarray);
> + checked = true;
> +}
> +
> static void arm_named_cpu_initfn(Object *obj)
> {
> ARMCPU *cpu = ARM_CPU(obj);
> @@ -401,6 +473,8 @@ static void arm_named_cpu_initfn(Object *obj)
>
> /* 3. Realize the model chain. */
> arm_realize_model_chain(obj, model, &error_abort);
> +
> + arm_named_cpu_zero_unknown_feature_ids(cpu, &error_abort);
> }
>
> void arm_register_named_cpu_models(void)
> diff --git a/target/arm/cpu-sysregs.h b/target/arm/cpu-sysregs.h
> index 7877a3b06a..d48b44705f 100644
> --- a/target/arm/cpu-sysregs.h
> +++ b/target/arm/cpu-sysregs.h
> @@ -37,6 +37,6 @@ typedef enum ARMSysRegs {
>
> extern const uint32_t id_register_sysreg[NUM_ID_IDX];
>
> -int get_sysreg_idx(ARMSysRegs sysreg);
> +int get_sysreg_idx(ARMSysRegs sysreg); /* -1 if @sysreg is not a known ID register */
>
> #endif /* ARM_CPU_SYSREGS_H */
> diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
> index a0114b0fa2..3cc698d65a 100644
> --- a/target/arm/cpu64.c
> +++ b/target/arm/cpu64.c
> @@ -57,8 +57,9 @@ int get_sysreg_idx(ARMSysRegs sysreg)
> {
> switch (sysreg) {
> #include "cpu-sysregs.h.inc"
> + default:
> + return -1;
> }
> - g_assert_not_reached();
> }
>
> #undef DEF
> diff --git a/target/arm/kvm-stub.c b/target/arm/kvm-stub.c
> index eae2e1ec2c..d263adc921 100644
> --- a/target/arm/kvm-stub.c
> +++ b/target/arm/kvm-stub.c
> @@ -50,6 +50,13 @@ void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu)
> g_assert_not_reached();
> }
>
> +int kvm_arm_read_sys_reg64(int fd, uint64_t *val,
> + uint8_t op0, uint8_t op1,
> + uint8_t crn, uint8_t crm, uint8_t op2)
> +{
> + g_assert_not_reached();
> +}
> +
> void kvm_arm_add_vcpu_properties(ARMCPU *cpu)
> {
> g_assert_not_reached();
> diff --git a/target/arm/kvm.c b/target/arm/kvm.c
> index 70d9a07580..6f704c0509 100644
> --- a/target/arm/kvm.c
> +++ b/target/arm/kvm.c
> @@ -263,6 +263,13 @@ static int read_sys_reg64(int fd, uint64_t *pret, uint64_t id)
> return ioctl(fd, KVM_GET_ONE_REG, &idreg);
> }
>
> +int kvm_arm_read_sys_reg64(int fd, uint64_t *val,
> + uint8_t op0, uint8_t op1,
> + uint8_t crn, uint8_t crm, uint8_t op2)
> +{
> + return read_sys_reg64(fd, val, ARM64_SYS_REG(op0, op1, crn, crm, op2));
> +}
> +
> static uint64_t idregs_sysreg_to_kvm_reg(ARMSysRegs sysreg)
> {
> return ARM64_SYS_REG((sysreg & CP_REG_ARM64_SYSREG_OP0_MASK) >> CP_REG_ARM64_SYSREG_OP0_SHIFT,
> diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h
> index 997120966f..4e563fab96 100644
> --- a/target/arm/kvm_arm.h
> +++ b/target/arm/kvm_arm.h
> @@ -154,6 +154,18 @@ bool kvm_arm_create_scratch_max_host_vcpu(int *fdarray,
> */
> void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu);
>
> +/**
> + * kvm_arm_read_sys_reg64:
> + * @fd: vCPU fd
> + * @val: filled with the register value on success
> + * @op0/@op1/@crn/@crm/@op2: System ID register encoding
> + *
> + * Returns: 0 on success, -1 on failure.
> + */
> +int kvm_arm_read_sys_reg64(int fd, uint64_t *val,
> + uint8_t op0, uint8_t op1,
> + uint8_t crn, uint8_t crm, uint8_t op2);
> +
> /**
> * kvm_arm_add_vcpu_properties:
> * @cpu: The CPU object to add the properties to
Thanks
Eric
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH v4 19/25] target/arm/qmp: allow named CPU models on cpu-model-expansion
2026-09-21 12:32 ` [RFC PATCH v4 19/25] target/arm/qmp: allow named CPU models on cpu-model-expansion Khushit Shah
@ 2026-10-16 12:32 ` Eric Auger
0 siblings, 0 replies; 66+ messages in thread
From: Eric Auger @ 2026-10-16 12:32 UTC (permalink / raw)
To: Khushit Shah, qemu-devel, qemu-arm, kvmarm
Cc: cohuck, peter.maydell, richard.henderson, maz, oliver.upton,
berrange, abologna, jdenemar, gshan, skolothumtho, sebott, armbru,
philmd, yangjinqian1, shaju.abraham, mark.caveayland, ping,
sandesh.patel
On 9/21/26 2:32 PM, Khushit Shah wrote:
> Allow expansion of the new KVM-only named CPU models through the
> cpu-model-expansion QMP query.
>
> Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
we might need to add some new tests in tests/qtest/arm-cpu-features.c too
Eric
> ---
> target/arm/arm-qmp-cmds.c | 9 +++++++++
> 1 file changed, 9 insertions(+)
>
> diff --git a/target/arm/arm-qmp-cmds.c b/target/arm/arm-qmp-cmds.c
> index 5fbdca3253..0940285af1 100644
> --- a/target/arm/arm-qmp-cmds.c
> +++ b/target/arm/arm-qmp-cmds.c
> @@ -36,6 +36,7 @@
> #include <linux/kvm.h>
> #include "system/kvm.h"
> #include "cpu.h"
> +#include "cpu-models.h"
>
> static GICCapability *gic_cap_new(int version)
> {
> @@ -96,6 +97,7 @@ CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type,
> Object *obj;
> const char *name;
> int fdarray[3];
> + bool named_model = (arm_find_model(model->name) != NULL);
> int i;
>
> if (type != CPU_MODEL_EXPANSION_TYPE_FULL) {
> @@ -108,6 +110,11 @@ CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type,
> return NULL;
> }
>
> + if (!kvm_enabled() && named_model) {
> + error_setg(errp, "The CPU type '%s' requires KVM", model->name);
> + return NULL;
> + }
> +
> oc = cpu_class_by_name(TYPE_ARM_CPU, model->name);
> if (!oc) {
> error_setg(errp, "The CPU type '%s' is not a recognized ARM CPU type",
> @@ -121,6 +128,8 @@ CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type,
> if (!strcmp(model->name, "host") || !strcmp(model->name, "max")) {
> /* These are kvmarm's recommended cpu types */
> supported = true;
> + } else if (named_model) {
> + supported = true;
> } else if (current_machine->cpu_type) {
> const char *cpu_type = current_machine->cpu_type;
> int len = strlen(cpu_type) - strlen(ARM_CPU_TYPE_SUFFIX);
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH v4 20/25] target/arm/kvm: compute host-supported values for ID register fields
2026-09-21 12:32 ` [RFC PATCH v4 20/25] target/arm/kvm: compute host-supported values for ID register fields Khushit Shah
@ 2026-10-16 13:10 ` Eric Auger
0 siblings, 0 replies; 66+ messages in thread
From: Eric Auger @ 2026-10-16 13:10 UTC (permalink / raw)
To: Khushit Shah, qemu-devel, qemu-arm, kvmarm
Cc: cohuck, peter.maydell, richard.henderson, maz, oliver.upton,
berrange, abologna, jdenemar, gshan, skolothumtho, sebott, armbru,
philmd, yangjinqian1, shaju.abraham, mark.caveayland, ping,
sandesh.patel
Hi Khushit,
On 9/21/26 2:32 PM, Khushit Shah wrote:
> Add kvm_arm_field_get_supported_values() which, for a given ID register
> field, builds the set of values KVM allows it to take on the given host.
>
> Non-writable fields are pinned to the host value. Writable fields follow
> their per-field constraints. This function must be updated when KVM
> starts exposing a new writable field that is not lower-safe; hence the
> special handling of TGranX_2/SpecSEI/L1Ip/MIDR/REVIDR/AIDR.
This effectively advocates for having a snapshot of all the IDREGS that
are known to be writable and handled by the qemu code. Because otherwise
we may return wrong safe values for a given prop.
> signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
>
> --------
> Note:
> - We should have an authoritative static list of "writable" fields in
> QEMU.
> ---
> target/arm/kvm-stub.c | 7 +++
> target/arm/kvm.c | 99 +++++++++++++++++++++++++++++++++++++++++++
> target/arm/kvm_arm.h | 28 ++++++++++++
> 3 files changed, 134 insertions(+)
>
> diff --git a/target/arm/kvm-stub.c b/target/arm/kvm-stub.c
> index d263adc921..c9cd47bf47 100644
> --- a/target/arm/kvm-stub.c
> +++ b/target/arm/kvm-stub.c
> @@ -144,3 +144,10 @@ void kvm_arm_destroy_scratch_host_vcpu(int *fdarray)
> {
> g_assert_not_reached();
> }
> +
> +void kvm_arm_field_get_supported_values(const ARM64SysRegField *field,
> + const ARMISARegisters *host_isar,
> + ArmFieldValueSet **value_set)
> +{
> + g_assert_not_reached();
> +}
> diff --git a/target/arm/kvm.c b/target/arm/kvm.c
> index 6f704c0509..77b1bcdf55 100644
> --- a/target/arm/kvm.c
> +++ b/target/arm/kvm.c
> @@ -1324,6 +1324,105 @@ bool kvm_arm_cpu_post_load(ARMCPU *cpu)
> return true;
> }
>
> +static bool arm_field_is_signed(const ARM64SysRegField *field)
> +{
> + return field_matches(field, ID_AA64MMFR0_EL1_IDX, "TGran4") ||
> + field_matches(field, ID_AA64MMFR0_EL1_IDX, "TGran64") ||
> + field_matches(field, ID_MMFR0_EL1_IDX, "InnerShr") ||
> + field_matches(field, ID_MMFR0_EL1_IDX, "OuterShr") ||
> + field_matches(field, ID_AA64DFR0_EL1_IDX, "DoubleLock") ||
> + field_matches(field, ID_AA64DFR0_EL1_IDX, "PMUVer") ||
> + field_matches(field, ID_DFR0_EL1_IDX, "PerfMon") ||
> + field_matches(field, ID_AA64PFR1_EL1_IDX, "MTE_frac") ||
> + field_matches(field, ID_AA64MMFR4_EL1_IDX, "E2H0") ||
> + field_matches(field, ID_DFR1_EL1_IDX, "MTPMU") ||
> + field_matches(field, ID_AA64PFR0_EL1_IDX, "FP") ||
> + field_matches(field, ID_AA64PFR0_EL1_IDX, "AdvSIMD");
> +}
> +
> +static void ranges_add(GArray *ranges, uint64_t min, uint64_t max)
> +{
> + ArmFieldRange r = { .min = min, .max = max };
> + g_array_append_val(ranges, r);
> +}
> +
> +void kvm_arm_field_get_supported_values(const ARM64SysRegField *field,
> + const ARMISARegisters *host_isar,
> + ArmFieldValueSet **value_set)
> +{
> + bool is_signed = arm_field_is_signed(field);
> + uint64_t host = extract64(host_isar->idregs[field->index],
> + field->shift, field->length);
> + GArray *ranges = g_array_new(false, false, sizeof(ArmFieldRange));
> +
> + /* A non-writable field can only ever hold the host value. */
> + if (!arm_field_is_writable(field)) {
> + ranges_add(ranges, host, host);
> + goto done;
> + }
> +
> + if (field_matches(field, ID_AA64MMFR0_EL1_IDX, "TGran4_2") ||
> + field_matches(field, ID_AA64MMFR0_EL1_IDX, "TGran16_2") ||
> + field_matches(field, ID_AA64MMFR0_EL1_IDX, "TGran64_2")) {
> + /* Either support the host value or the "off" value */
> + ranges_add(ranges, host, host);
> + if (host != 1) { /* 1 = "off" */
> + ranges_add(ranges, 1, 1);
those are tagged with SAFE_EXACT policy in the kernel. Could you elaborate?
> + }
> + } else if (field_matches(field, CTR_EL0_IDX, "L1Ip")) {
> + /* Only safe to downgrade to VIPT, other values are reserved. */
> + ranges_add(ranges, host, host);
> + if (host != 2) { /* 2 = "VIPT" */
> + ranges_add(ranges, 2, 2);
*ID_AA64FPFR0_EL1_F8* hals have* EXACT policy and I don't see them
special cased here.
> + }
> + } else if (field_matches(field, ID_AA64MMFR1_EL1_IDX, "SpecSEI") ||
> + field_matches(field, ID_MMFR4_EL1_IDX, "SpecSEI")) {
> + /* It is safe to upgrade SpecSEI to 1, other values are reserved. */
> + ranges_add(ranges, host, host);
> + if (host != 1) {
> + ranges_add(ranges, 1, 1);
> + }
> + } else if (field->index == MIDR_EL1_IDX ||
> + field->index == REVIDR_EL1_IDX ||
> + field->index == AIDR_EL1_IDX) {
> + /*
> + * No restriction on value that can be set for implementation ID
> + * registers fields.
> + */
> + uint64_t max = 0;
> + if (field->length == 64) {
> + max = ~0ULL;
> + } else {
> + max = (1ULL << field->length) - 1;
> + }
> + ranges_add(ranges, 0, max);
> + } else {
> + /*
> + * After handling the special cases, other writable fields are
> + * either lower-safe or signed lower-safe.
> + */
> + if (field->arch_vals_count) {
> + for (uint32_t i = 0; i < field->arch_vals_count; i++) {
> + uint64_t av = field->arch_vals[i];
> + int64_t v = is_signed ?
> + sextract64(av, 0, field->length) : (int64_t)av;
> + int64_t hv = is_signed ?
> + sextract64(host, 0, field->length) : (int64_t)host;
> + if (v <= hv) {
> + ranges_add(ranges, av, av);
> + }
> + }
> + } else {
> + g_assert(!is_signed); /* No signed field with no arch vals */
> + ranges_add(ranges, 0, host);
> + }
> + }
> +done:
> + *value_set = g_new0(ArmFieldValueSet, 1);
> + (*value_set)->n_ranges = ranges->len;
> + (*value_set)->ranges = (ArmFieldRange *)g_array_free(ranges, false);
> +}
> +
> static bool arm_field_skip_writeback_always(const ARM64SysRegField *field)
> {
> /*
> diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h
> index 4e563fab96..9481e56412 100644
> --- a/target/arm/kvm_arm.h
> +++ b/target/arm/kvm_arm.h
> @@ -175,6 +175,34 @@ int kvm_arm_read_sys_reg64(int fd, uint64_t *val,
> */
> void kvm_arm_add_vcpu_properties(ARMCPU *cpu);
>
> +typedef struct ARM64SysReg ARM64SysReg;
> +typedef struct ARM64SysRegField ARM64SysRegField;
> +typedef struct ARMISARegisters ARMISARegisters;
> +
> +typedef struct ArmFieldRange {
> + uint64_t min;
> + uint64_t max;
> +} ArmFieldRange;
> +
> +typedef struct ArmFieldValueSet {
> + ArmFieldRange *ranges;
> + size_t n_ranges;
> +} ArmFieldValueSet;
> +
> +/**
> + * kvm_arm_field_get_supported_values:
> + * @field: The field to get the supported values for
> + * @host_isar: The host ISAR registers
> + * @value_set: The set of supported values for the @field
> + *
> + * Will be allocated and filled in with the supported values for the @field
> + * based on the host_isar and whether the field is writable or not.
> + * The caller must free the value_set.
> + */
> +void kvm_arm_field_get_supported_values(const ARM64SysRegField *field,
> + const ARMISARegisters *host_isar,
> + ArmFieldValueSet **value_set);
> +
> /**
> * kvm_arm_steal_time_finalize:
> * @cpu: ARMCPU for which to finalize kvm-steal-time
Eric
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH v4 21/25] target/arm: report 0 as supported for ID fields gated by vCPU init flags
2026-09-21 12:32 ` [RFC PATCH v4 21/25] target/arm: report 0 as supported for ID fields gated by vCPU init flags Khushit Shah
@ 2026-10-16 13:12 ` Eric Auger
0 siblings, 0 replies; 66+ messages in thread
From: Eric Auger @ 2026-10-16 13:12 UTC (permalink / raw)
To: Khushit Shah, qemu-devel, qemu-arm, kvmarm
Cc: cohuck, peter.maydell, richard.henderson, maz, oliver.upton,
berrange, abologna, jdenemar, gshan, skolothumtho, sebott, armbru,
philmd, yangjinqian1, shaju.abraham, mark.caveayland, ping,
sandesh.patel
On 9/21/26 2:32 PM, Khushit Shah wrote:
> When QEMU queries the host ISAR via KVM, it uses a scratch vCPU
> initialized with all host-supported features (like SVE and PAuth).
So I expect this patch is not needed anymore after rebase on v9/v10
Eric
>
> KVM exposes the corresponding ID register fields (e.g.,
> ID_AA64ISAR1_EL1.APA) as read-only. The supported-values list only
> shows the enabled host value (e.g., 5). This falsely flags a model as
> blocked, even though the features can be masked by omitting those flags
> during vCPU initialization. For these fields, even if KVM reports them as
> non-writable, we explicitly append "0" to the list of supported values
> if the host value is non-zero.
>
> Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
> ---
> target/arm/kvm.c | 25 +++++++++++++++++++++++++
> 1 file changed, 25 insertions(+)
>
> diff --git a/target/arm/kvm.c b/target/arm/kvm.c
> index 77b1bcdf55..0b5fb49dff 100644
> --- a/target/arm/kvm.c
> +++ b/target/arm/kvm.c
> @@ -1346,6 +1346,24 @@ static void ranges_add(GArray *ranges, uint64_t min, uint64_t max)
> g_array_append_val(ranges, r);
> }
>
> +/*
> + * Some fields are reported as non-writable by KVM but can still be
> + * disabled by not requesting the corresponding vCPU init feature flag
> + * (SVE, pauth). The supported values are derived from a scratch vCPU
> + * whose init flags may differ from the real vCPU, so for these fields
> + * "off" (0) is a supported value in addition to the host value.
> + */
> +static bool kvm_arm_field_off_via_vcpu_flags(const ARM64SysRegField *field)
> +{
> + return field_matches(field, ID_AA64PFR0_EL1_IDX, "SVE") ||
> + field_matches(field, ID_AA64ISAR1_EL1_IDX, "APA") ||
> + field_matches(field, ID_AA64ISAR1_EL1_IDX, "API") ||
> + field_matches(field, ID_AA64ISAR1_EL1_IDX, "GPA") ||
> + field_matches(field, ID_AA64ISAR1_EL1_IDX, "GPI") ||
> + field_matches(field, ID_AA64ISAR2_EL1_IDX, "APA3") ||
> + field_matches(field, ID_AA64ISAR2_EL1_IDX, "GPA3");
> +}
> +
> void kvm_arm_field_get_supported_values(const ARM64SysRegField *field,
> const ARMISARegisters *host_isar,
> ArmFieldValueSet **value_set)
> @@ -1358,6 +1376,13 @@ void kvm_arm_field_get_supported_values(const ARM64SysRegField *field,
> /* A non-writable field can only ever hold the host value. */
> if (!arm_field_is_writable(field)) {
> ranges_add(ranges, host, host);
> + /*
> + * ...unless it is one of the fields that can still be turned off
> + * via vCPU init flags, in which case "off" (0) is also supported.
> + */
> + if (host != 0 && kvm_arm_field_off_via_vcpu_flags(field)) {
> + ranges_add(ranges, 0, 0);
> + }
> goto done;
> }
>
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH v4 24/25] target/arm/qmp: implement query-cpu-props-info for KVM
2026-09-21 12:32 ` [RFC PATCH v4 24/25] target/arm/qmp: implement query-cpu-props-info for KVM Khushit Shah
@ 2026-10-16 13:21 ` Eric Auger
2026-10-16 13:23 ` Eric Auger
1 sibling, 0 replies; 66+ messages in thread
From: Eric Auger @ 2026-10-16 13:21 UTC (permalink / raw)
To: Khushit Shah, qemu-devel, qemu-arm, kvmarm
Cc: cohuck, peter.maydell, richard.henderson, maz, oliver.upton,
berrange, abologna, jdenemar, gshan, skolothumtho, sebott, armbru,
philmd, yangjinqian1, shaju.abraham, mark.caveayland, ping,
sandesh.patel
Hi Khushit,
On 9/21/26 2:32 PM, Khushit Shah wrote:
> Implement query-cpu-props-info for ARM64/KVM by creating and finalizing
> a temporary "host" CPU object and then walking its QOM properties.
>
> For numeric SYSREG_ properties, report the host-supported value ranges
> computed by kvm_arm_field_get_supported_values(). For boolean
> properties, report false as always supported and true as supported when
I am not sure false shall be always permitted. for instance iirc
aarch64=off requires a special KVM capability which is not tested here.
it is worth to emphasize those are the theoretical values that can be
easily guessed, this does not check cross feature consistency which can
only be tested when applying the values at KVM level I guess. So let's
do not pretend that this is fully reliable. I think the only way to
double check the chosen values is to do a full expansion for this models
featuring the new values
> the QOM property value is true.
>
> Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
> ---
> target/arm/arm-qmp-cmds.c | 84 +++++++++++++++++++++++++++++++++++++++
> 1 file changed, 84 insertions(+)
>
> diff --git a/target/arm/arm-qmp-cmds.c b/target/arm/arm-qmp-cmds.c
> index 0940285af1..ba488d5c01 100644
> --- a/target/arm/arm-qmp-cmds.c
> +++ b/target/arm/arm-qmp-cmds.c
> @@ -84,6 +84,90 @@ static const char *cpu_model_advertised_features[] = {
> NULL
> };
>
> +CpuPropertyInfoList *qmp_query_cpu_props_info(Error **errp)
> +{
> + CpuPropertyInfoList *head = NULL;
> + const ARMISARegisters *host_isar;
> + ObjectPropertyIterator iter;
> + ObjectProperty *prop;
> + Error *err = NULL;
> + ObjectClass *oc;
> + Object *obj;
> +
> + if (!kvm_enabled()) {
> + error_setg(errp, "query-cpu-props-info requires KVM");
> + return NULL;
> + }
> +
> + oc = cpu_class_by_name(TYPE_ARM_CPU, "host");
> + if (!oc) {
> + error_setg(errp, "The 'host' CPU type is not available");
> + return NULL;
> + }
> +
> + host_isar = kvm_arm_get_host_isar();
> +
> + /* Spin up a scratch "host" vCPU object and walk its QOM properties. */
> + obj = object_new_with_class(oc);
> + arm_cpu_finalize_features(ARM_CPU(obj), &err);
> + if (err) {
> + error_propagate(errp, err);
> + object_unref(obj);
> + return NULL;
> + }
> +
> + object_property_iter_init(&iter, obj);
> + while ((prop = object_property_iter_next(&iter))) {
> + CpuPropertyInfo *info;
> +
> + if (g_str_has_prefix(prop->name, "SYSREG_")) {
> + const ARM64SysRegField *field = prop->opaque;
> + CpuPropertyValueRangeList *ranges = NULL;
> + ArmFieldValueSet *vs = NULL;
> +
> + info = g_new0(CpuPropertyInfo, 1);
> + info->name = g_strdup(prop->name);
> + info->type = CPU_PROPERTY_TYPE_NUMBER;
> +
> + kvm_arm_field_get_supported_values(field, host_isar, &vs);
> + for (size_t k = 0; k < vs->n_ranges; k++) {
> + CpuPropertyValueRange *r = g_new0(CpuPropertyValueRange, 1);
> + r->min = vs->ranges[k].min;
> + r->max = vs->ranges[k].max;
> + QAPI_LIST_PREPEND(ranges, r);
> + }
> + info->u.number.supported_values = ranges;
> +
> + g_free(vs->ranges);
> + g_free(vs);
> + } else if (g_strv_contains(cpu_model_advertised_features, prop->name)) {
> + bool cur = object_property_get_bool(obj, prop->name, &error_abort);
> + boolList *values = NULL;
> +
> + info = g_new0(CpuPropertyInfo, 1);
> + info->name = g_strdup(prop->name);
> + info->type = CPU_PROPERTY_TYPE_BOOLEAN;
> +
> + /*
> + * "off" is always supported. "on" is only supported when the
> + * host already has the feature enabled.
> + */
> + QAPI_LIST_PREPEND(values, false);
> + if (cur) {
> + QAPI_LIST_PREPEND(values, true);
> + }
> + info->u.boolean.supported_values = values;
> + } else {
> + continue;
> + }
> +
> + QAPI_LIST_PREPEND(head, info);
> + }
> +
> + object_unref(obj);
> + return head;
> +}
> +
> CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type,
> CpuModelInfo *model,
> Error **errp)
Thanks
Eric
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH v4 24/25] target/arm/qmp: implement query-cpu-props-info for KVM
2026-09-21 12:32 ` [RFC PATCH v4 24/25] target/arm/qmp: implement query-cpu-props-info for KVM Khushit Shah
2026-10-16 13:21 ` Eric Auger
@ 2026-10-16 13:23 ` Eric Auger
1 sibling, 0 replies; 66+ messages in thread
From: Eric Auger @ 2026-10-16 13:23 UTC (permalink / raw)
To: Khushit Shah, qemu-devel, qemu-arm, kvmarm
Cc: cohuck, peter.maydell, richard.henderson, maz, oliver.upton,
berrange, abologna, jdenemar, gshan, skolothumtho, sebott, armbru,
philmd, yangjinqian1, shaju.abraham, mark.caveayland, ping,
sandesh.patel
On 9/21/26 2:32 PM, Khushit Shah wrote:
> Implement query-cpu-props-info for ARM64/KVM by creating and finalizing
> a temporary "host" CPU object and then walking its QOM properties.
side note: the new qmp command shall be documented in
docs/system/arm/cpu-features.rst
Eric
>
> For numeric SYSREG_ properties, report the host-supported value ranges
> computed by kvm_arm_field_get_supported_values(). For boolean
> properties, report false as always supported and true as supported when
> the QOM property value is true.
>
> Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
> ---
> target/arm/arm-qmp-cmds.c | 84 +++++++++++++++++++++++++++++++++++++++
> 1 file changed, 84 insertions(+)
>
> diff --git a/target/arm/arm-qmp-cmds.c b/target/arm/arm-qmp-cmds.c
> index 0940285af1..ba488d5c01 100644
> --- a/target/arm/arm-qmp-cmds.c
> +++ b/target/arm/arm-qmp-cmds.c
> @@ -84,6 +84,90 @@ static const char *cpu_model_advertised_features[] = {
> NULL
> };
>
> +CpuPropertyInfoList *qmp_query_cpu_props_info(Error **errp)
> +{
> + CpuPropertyInfoList *head = NULL;
> + const ARMISARegisters *host_isar;
> + ObjectPropertyIterator iter;
> + ObjectProperty *prop;
> + Error *err = NULL;
> + ObjectClass *oc;
> + Object *obj;
> +
> + if (!kvm_enabled()) {
> + error_setg(errp, "query-cpu-props-info requires KVM");
> + return NULL;
> + }
> +
> + oc = cpu_class_by_name(TYPE_ARM_CPU, "host");
> + if (!oc) {
> + error_setg(errp, "The 'host' CPU type is not available");
> + return NULL;
> + }
> +
> + host_isar = kvm_arm_get_host_isar();
> +
> + /* Spin up a scratch "host" vCPU object and walk its QOM properties. */
> + obj = object_new_with_class(oc);
> + arm_cpu_finalize_features(ARM_CPU(obj), &err);
> + if (err) {
> + error_propagate(errp, err);
> + object_unref(obj);
> + return NULL;
> + }
> +
> + object_property_iter_init(&iter, obj);
> + while ((prop = object_property_iter_next(&iter))) {
> + CpuPropertyInfo *info;
> +
> + if (g_str_has_prefix(prop->name, "SYSREG_")) {
> + const ARM64SysRegField *field = prop->opaque;
> + CpuPropertyValueRangeList *ranges = NULL;
> + ArmFieldValueSet *vs = NULL;
> +
> + info = g_new0(CpuPropertyInfo, 1);
> + info->name = g_strdup(prop->name);
> + info->type = CPU_PROPERTY_TYPE_NUMBER;
> +
> + kvm_arm_field_get_supported_values(field, host_isar, &vs);
> + for (size_t k = 0; k < vs->n_ranges; k++) {
> + CpuPropertyValueRange *r = g_new0(CpuPropertyValueRange, 1);
> + r->min = vs->ranges[k].min;
> + r->max = vs->ranges[k].max;
> + QAPI_LIST_PREPEND(ranges, r);
> + }
> + info->u.number.supported_values = ranges;
> +
> + g_free(vs->ranges);
> + g_free(vs);
> + } else if (g_strv_contains(cpu_model_advertised_features, prop->name)) {
> + bool cur = object_property_get_bool(obj, prop->name, &error_abort);
> + boolList *values = NULL;
> +
> + info = g_new0(CpuPropertyInfo, 1);
> + info->name = g_strdup(prop->name);
> + info->type = CPU_PROPERTY_TYPE_BOOLEAN;
> +
> + /*
> + * "off" is always supported. "on" is only supported when the
> + * host already has the feature enabled.
> + */
> + QAPI_LIST_PREPEND(values, false);
> + if (cur) {
> + QAPI_LIST_PREPEND(values, true);
> + }
> + info->u.boolean.supported_values = values;
> + } else {
> + continue;
> + }
> +
> + QAPI_LIST_PREPEND(head, info);
> + }
> +
> + object_unref(obj);
> + return head;
> +}
> +
> CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type,
> CpuModelInfo *model,
> Error **errp)
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH v4 25/25] target/arm/qmp: hook blockers in query-cpu-definitions
2026-09-21 12:32 ` [RFC PATCH v4 25/25] target/arm/qmp: hook blockers in query-cpu-definitions Khushit Shah
@ 2026-10-16 13:54 ` Eric Auger
0 siblings, 0 replies; 66+ messages in thread
From: Eric Auger @ 2026-10-16 13:54 UTC (permalink / raw)
To: Khushit Shah, qemu-devel, qemu-arm, kvmarm
Cc: cohuck, peter.maydell, richard.henderson, maz, oliver.upton,
berrange, abologna, jdenemar, gshan, skolothumtho, sebott, armbru,
philmd, yangjinqian1, shaju.abraham, mark.caveayland, ping,
sandesh.patel
Hi,
On 9/21/26 2:32 PM, Khushit Shah wrote:
> Report blockers for named CPU models in query-cpu-definitions.
>
> Efficiently do this by validating the realized ID register values
> against the host values. sveNNNN properties need special handling
> because they are not stored in ID registers.
>
> This way, we need not instantiate each model to check if it can be
> realized on the host, and we also get granular information about the ID
> register fields blocking realization.
>
> Introduce arm_cpu_class_check_missing_features() and
> kvm_arm_idregs_get_blockers() to achieve this.
I would recommend to show an excerpt of the output
>
> Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
> ---
> target/arm/arm-qmp-cmds.c | 12 +++++++++
> target/arm/cpu-models-stub.c | 5 ++++
> target/arm/cpu-models.c | 35 +++++++++++++++++++++++++
> target/arm/cpu-models.h | 2 ++
> target/arm/kvm.c | 50 ++++++++++++++++++++++++++++++++++++
> target/arm/kvm_arm.h | 13 ++++++++++
> 6 files changed, 117 insertions(+)
>
> diff --git a/target/arm/arm-qmp-cmds.c b/target/arm/arm-qmp-cmds.c
> index ba488d5c01..d837ec6653 100644
> --- a/target/arm/arm-qmp-cmds.c
> +++ b/target/arm/arm-qmp-cmds.c
> @@ -379,6 +379,18 @@ static void arm_cpu_add_definition(gpointer data, gpointer user_data)
> info->name = cpu_model_from_type(typename);
> info->q_typename = g_strdup(typename);
>
> + /* calculate blockers */
> + if (kvm_enabled()
> + && !g_str_equal(info->name, "host")
> + && !g_str_equal(info->name, "max")
> + && arm_find_model(info->name) != NULL) {
> + arm_cpu_class_check_missing_features(ARM_CPU_CLASS(oc),
> + &info->unavailable_features);
> + if (info->unavailable_features) {
> + info->has_unavailable_features = true;
> + }
> + }
> +
> QAPI_LIST_PREPEND(*cpu_list, info);
> }
>
> diff --git a/target/arm/cpu-models-stub.c b/target/arm/cpu-models-stub.c
> index 48f712d648..2d1be49e0a 100644
> --- a/target/arm/cpu-models-stub.c
> +++ b/target/arm/cpu-models-stub.c
> @@ -11,3 +11,8 @@ const ArmNamedCpuModel *arm_find_model(const char *name)
> {
> return NULL;
> }
> +
> +void arm_cpu_class_check_missing_features(ARMCPUClass *acc, strList **blockers)
> +{
> + return;
> +}
> diff --git a/target/arm/cpu-models.c b/target/arm/cpu-models.c
> index 855eb5ee6b..9591b6dbfc 100644
> --- a/target/arm/cpu-models.c
> +++ b/target/arm/cpu-models.c
> @@ -477,6 +477,41 @@ static void arm_named_cpu_initfn(Object *obj)
> arm_named_cpu_zero_unknown_feature_ids(cpu, &error_abort);
> }
>
> +void arm_cpu_class_check_missing_features(ARMCPUClass *acc, strList **blockers)
> +{
> + Error *err = NULL;
> + Object *obj = object_new_with_class(OBJECT_CLASS(acc));
> + ARMCPU *cpu = ARM_CPU(obj);
> +
> + if (!kvm_enabled() || !arm_find_model(acc->info->name)) {
> + goto out;
> + }
> +
> + if (cpu_isar_feature(aa64_sve, cpu)) {
> + aarch64_cpu_sve_finalize(cpu, &err);
> + if (err) {
> + error_free(err);
> + err = NULL;
> + uint32_t host_vq_map = cpu->sve_vq.supported;
> + uint32_t model_vq_map = cpu->sve_vq.map;
> +
> + if ((model_vq_map & host_vq_map) != model_vq_map) {
> + for (int vq = 1; vq <= ARM_MAX_VQ; vq++) {
> + uint32_t vq_bit = (1 << (vq - 1));
> + if ((model_vq_map & vq_bit) && !(host_vq_map & vq_bit)) {
> + QAPI_LIST_PREPEND(*blockers,
> + g_strdup_printf("sve%d", vq * 128));
> + }
> + }
> + }
> + }
> + }
> +
> + kvm_arm_idregs_get_blockers(cpu, kvm_arm_get_host_isar(), blockers);
> +out:
> + object_unref(obj);
> +}
> +
> void arm_register_named_cpu_models(void)
> {
> static ARMCPUInfo *arm_named_cpu_infos;
> diff --git a/target/arm/cpu-models.h b/target/arm/cpu-models.h
> index 144778744e..41bb15d928 100644
> --- a/target/arm/cpu-models.h
> +++ b/target/arm/cpu-models.h
> @@ -4,6 +4,7 @@
>
> #include "qapi/error.h"
> #include "qom/object.h"
> +#include "cpu.h"
>
> typedef enum ArmModelPropType {
> ARM_MODEL_PROP_BOOL,
> @@ -32,5 +33,6 @@ void arm_apply_model_props(Object *obj, const ArmModelPropValue *props,
> Error **errp);
> void arm_realize_model_chain(Object *obj, const ArmNamedCpuModel *model,
> Error **errp);
> +void arm_cpu_class_check_missing_features(ARMCPUClass *acc, strList **blockers);
>
> #endif /* ARM_CPU_MODELS_H */
> diff --git a/target/arm/kvm.c b/target/arm/kvm.c
> index bb74f8c274..ca3da80262 100644
> --- a/target/arm/kvm.c
> +++ b/target/arm/kvm.c
> @@ -1485,6 +1485,56 @@ arm_field_skip_writeback_if_not_writable(const ARM64SysRegField *field)
> return field_matches(field, ID_DFR0_EL1_IDX, "PerfMon");
> }
>
> +void kvm_arm_idregs_get_blockers(ARMCPU *cpu,
> + const ARMISARegisters *host_isar,
> + strList **blockers)
> +{
> + for (int i = 0; i < NUM_ID_IDX; i++) {
> + ARM64SysReg *reg = &arm64_id_regs[i];
> +
> + if (!reg->name) {
> + continue;
> + }
> +
> + for (uint32_t j = 0; j < reg->fields_count; j++) {
> + const ARM64SysRegField *field = ®->fields[j];
> + ArmFieldValueSet *vs = NULL;
> + bool supported = false;
> + uint64_t model_val;
> +
> + /* Not a blocker if the field is never written back to KVM. */
> + if (arm_field_skip_writeback_always(field) ||
> + (!arm_field_is_writable(field) &&
> + arm_field_skip_writeback_if_not_writable(field))) {
> + continue;
> + }
> +
> + model_val = extract64(cpu->isar.idregs[field->index],
> + field->shift, field->length);
nit I see you use that several times, you could introduce a helper
> +
> + /*
> + * If the field is written back, make sure a "supported" value
> + * is requested.
> + */
> + kvm_arm_field_get_supported_values(field, host_isar, &vs);
> + for (size_t k = 0; k < vs->n_ranges; k++) {
> + if (model_val >= vs->ranges[k].min &&
> + model_val <= vs->ranges[k].max) {
> + supported = true;
> + break;
> + }
> + }
> + g_free(vs->ranges);
> + g_free(vs);
> +
> + if (!supported) {
> + QAPI_LIST_PREPEND(*blockers,
> + g_strdup_printf("SYSREG_%s_%s", reg->name, field->name));
> + }
> + }
> + }
> +}
> +
> /*
> * Copy writable ID reg fields from isar.idregs[] into the KVM cpreg list,
> * so the subsequent write_list_to_kvmstate() pushes them to KVM.
> diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h
> index ab01ce8665..59832d8063 100644
> --- a/target/arm/kvm_arm.h
> +++ b/target/arm/kvm_arm.h
> @@ -205,6 +205,19 @@ void kvm_arm_field_get_supported_values(const ARM64SysRegField *field,
> const ARMISARegisters *host_isar,
> ArmFieldValueSet **value_set);
>
> +/**
> + * kvm_arm_idregs_get_blockers:
> + * @cpu: ARMCPU
> + * @host_isar: The host ISAR registers
> + * @blockers: The list of blockers
> + *
> + * Get the list of "blockers" in @cpu's idregs state for the given
> + * @host_isar.
> + */
> +void kvm_arm_idregs_get_blockers(ARMCPU *cpu,
> + const ARMISARegisters *host_isar,
> + strList **blockers);
> +
> /**
> * kvm_arm_steal_time_finalize:
> * @cpu: ARMCPU for which to finalize kvm-steal-time
Thanks
Eric
^ permalink raw reply [flat|nested] 66+ messages in thread
end of thread, other threads:[~2026-10-16 13:54 UTC | newest]
Thread overview: 66+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-21 12:32 [RFC PATCH v4 00/25] named CPU models for Arm64 on KVM Khushit Shah
2026-09-21 12:32 ` [RFC PATCH v4 01/25] target/arm: expose SYSREG_ props for REVIDR_EL1 and AIDR_EL1 Khushit Shah
2026-09-23 16:22 ` Eric Auger
2026-09-29 12:54 ` Khushit Shah
2026-09-21 12:32 ` [RFC PATCH v4 02/25] target/arm: expose all non-res ID reg fields as properties Khushit Shah
2026-09-23 16:37 ` Eric Auger
2026-09-24 6:46 ` Eric Auger
2026-09-29 12:55 ` Khushit Shah
2026-09-21 12:32 ` [RFC PATCH v4 03/25] target/arm: move SYSREG_ prop infra to cpu64.c Khushit Shah
2026-09-24 6:54 ` Eric Auger
2026-09-29 12:56 ` Khushit Shah
2026-09-21 12:32 ` [RFC PATCH v4 04/25] target/arm/kvm: enable writable implementation ID registers Khushit Shah
2026-09-21 12:32 ` [RFC PATCH v4 05/25] target/arm/kvm: read all ID registers from KVM Khushit Shah
2026-09-24 7:52 ` Eric Auger
2026-09-21 12:32 ` [RFC PATCH v4 06/25] target/arm/kvm: handle special ID registers when reading " Khushit Shah
2026-09-21 12:32 ` [RFC PATCH v4 07/25] target/arm/kvm: process ID register writeback per field Khushit Shah
2026-09-24 9:41 ` Eric Auger
2026-09-21 12:32 ` [RFC PATCH v4 08/25] target/arm/kvm: handle writeback for special ID register fields Khushit Shah
2026-09-24 9:57 ` Eric Auger
2026-09-24 10:21 ` Khushit Shah
2026-09-24 11:47 ` Eric Auger
2026-09-29 13:09 ` Khushit Shah
2026-09-21 12:32 ` [RFC PATCH v4 09/25] target/arm: introduce named CPU model infrastructure Khushit Shah
2026-09-24 13:35 ` Eric Auger
2026-09-29 13:40 ` Khushit Shah
2026-09-21 12:32 ` [RFC PATCH v4 10/25] target/arm: fix SVE and PAuth finalize for named CPU models Khushit Shah
2026-10-15 13:01 ` Eric Auger
2026-10-16 7:34 ` Khushit Shah
2026-09-21 12:32 ` [RFC PATCH v4 11/25] target/arm: disable PMU support " Khushit Shah
2026-10-15 13:12 ` Eric Auger
2026-09-21 12:32 ` [RFC PATCH v4 12/25] target/arm: add arm-v9.0-a-v1 named CPU model Khushit Shah
2026-10-16 12:07 ` Eric Auger
2026-10-16 12:24 ` Peter Maydell
2026-09-21 12:32 ` [RFC PATCH v4 13/25] target/arm: add neoverse-v2-v1 " Khushit Shah
2026-09-21 12:32 ` [RFC PATCH v4 14/25] target/arm: add neoverse-v2-v2 " Khushit Shah
2026-10-15 12:13 ` Eric Auger
2026-10-15 12:22 ` Peter Maydell
2026-10-15 14:05 ` Eric Auger
2026-10-16 6:48 ` Khushit Shah
2026-09-21 12:32 ` [RFC PATCH v4 15/25] target/arm: add graviton4-v1 " Khushit Shah
2026-09-21 12:32 ` [RFC PATCH v4 16/25] target/arm: add grace-v1 " Khushit Shah
2026-09-21 12:32 ` [RFC PATCH v4 17/25] target/arm: fail named CPU models on unknown non-zero feature ID regs Khushit Shah
2026-10-16 12:27 ` Eric Auger
2026-09-21 12:32 ` [RFC PATCH v4 18/25] target/arm: add cpu-models-stub.c Khushit Shah
2026-09-29 15:00 ` Philippe Mathieu-Daudé
2026-09-29 15:37 ` Khushit Shah
2026-09-21 12:32 ` [RFC PATCH v4 19/25] target/arm/qmp: allow named CPU models on cpu-model-expansion Khushit Shah
2026-10-16 12:32 ` Eric Auger
2026-09-21 12:32 ` [RFC PATCH v4 20/25] target/arm/kvm: compute host-supported values for ID register fields Khushit Shah
2026-10-16 13:10 ` Eric Auger
2026-09-21 12:32 ` [RFC PATCH v4 21/25] target/arm: report 0 as supported for ID fields gated by vCPU init flags Khushit Shah
2026-10-16 13:12 ` Eric Auger
2026-09-21 12:32 ` [RFC PATCH v4 22/25] target/arm/kvm: add kvm_arm_get_host_isar helper Khushit Shah
2026-09-29 15:02 ` Philippe Mathieu-Daudé
2026-09-21 12:32 ` [RFC PATCH v4 23/25] qmp: add query-cpu-props-info command Khushit Shah
2026-10-15 14:20 ` Eric Auger
2026-10-16 6:57 ` Khushit Shah
2026-10-16 7:18 ` Eric Auger
2026-10-16 7:28 ` Khushit Shah
2026-09-21 12:32 ` [RFC PATCH v4 24/25] target/arm/qmp: implement query-cpu-props-info for KVM Khushit Shah
2026-10-16 13:21 ` Eric Auger
2026-10-16 13:23 ` Eric Auger
2026-09-21 12:32 ` [RFC PATCH v4 25/25] target/arm/qmp: hook blockers in query-cpu-definitions Khushit Shah
2026-10-16 13:54 ` Eric Auger
2026-09-29 15:09 ` [RFC PATCH v4 00/25] named CPU models for Arm64 on KVM Philippe Mathieu-Daudé
2026-09-29 16:38 ` Khushit Shah
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.