* [RFC PATCH v3 01/19] target/arm/sysreg: regenerate cpu-sysregs.h.inc
2026-07-16 21:38 [RFC PATCH v3 00/19] named CPU models for Arm64 on KVM Khushit Shah
@ 2026-07-16 21:38 ` Khushit Shah
2026-07-20 12:11 ` Eric Auger
2026-07-16 21:38 ` [RFC PATCH v3 02/19] scripts: bug fixes in update-aarch64-cpu-sysreg-properties Khushit Shah
` (17 subsequent siblings)
18 siblings, 1 reply; 29+ messages in thread
From: Khushit Shah @ 2026-07-16 21:38 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, prerna.saxena
Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
---
target/arm/cpu-sysregs.h.inc | 1 +
1 file changed, 1 insertion(+)
diff --git a/target/arm/cpu-sysregs.h.inc b/target/arm/cpu-sysregs.h.inc
index 05f558610b..2188cd7be0 100644
--- a/target/arm/cpu-sysregs.h.inc
+++ b/target/arm/cpu-sysregs.h.inc
@@ -19,6 +19,7 @@ DEF(ID_AA64FPFR0_EL1, 3, 0, 0, 4, 7)
DEF(ID_AA64ISAR0_EL1, 3, 0, 0, 6, 0)
DEF(ID_AA64ISAR1_EL1, 3, 0, 0, 6, 1)
DEF(ID_AA64ISAR2_EL1, 3, 0, 0, 6, 2)
+DEF(ID_AA64ISAR3_EL1, 3, 0, 0, 6, 3)
DEF(ID_AA64MMFR0_EL1, 3, 0, 0, 7, 0)
DEF(ID_AA64MMFR1_EL1, 3, 0, 0, 7, 1)
DEF(ID_AA64MMFR2_EL1, 3, 0, 0, 7, 2)
--
2.52.0
^ permalink raw reply related [flat|nested] 29+ messages in thread* Re: [RFC PATCH v3 01/19] target/arm/sysreg: regenerate cpu-sysregs.h.inc
2026-07-16 21:38 ` [RFC PATCH v3 01/19] target/arm/sysreg: regenerate cpu-sysregs.h.inc Khushit Shah
@ 2026-07-20 12:11 ` Eric Auger
0 siblings, 0 replies; 29+ messages in thread
From: Eric Auger @ 2026-07-20 12:11 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,
prerna.saxena
Hi Khushit,
On 7/16/26 11:38 PM, Khushit Shah wrote:
> Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
> ---
> target/arm/cpu-sysregs.h.inc | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/target/arm/cpu-sysregs.h.inc b/target/arm/cpu-sysregs.h.inc
> index 05f558610b..2188cd7be0 100644
> --- a/target/arm/cpu-sysregs.h.inc
> +++ b/target/arm/cpu-sysregs.h.inc
> @@ -19,6 +19,7 @@ DEF(ID_AA64FPFR0_EL1, 3, 0, 0, 4, 7)
> DEF(ID_AA64ISAR0_EL1, 3, 0, 0, 6, 0)
> DEF(ID_AA64ISAR1_EL1, 3, 0, 0, 6, 1)
> DEF(ID_AA64ISAR2_EL1, 3, 0, 0, 6, 2)
> +DEF(ID_AA64ISAR3_EL1, 3, 0, 0, 6, 3)
Please could you send a branch. It is difficult to understand on which
code base you applied thise series as
ID_AA64ISAR3_EL1 definition is already upstream
Thanks
Eric
> DEF(ID_AA64MMFR0_EL1, 3, 0, 0, 7, 0)
> DEF(ID_AA64MMFR1_EL1, 3, 0, 0, 7, 1)
> DEF(ID_AA64MMFR2_EL1, 3, 0, 0, 7, 2)
^ permalink raw reply [flat|nested] 29+ messages in thread
* [RFC PATCH v3 02/19] scripts: bug fixes in update-aarch64-cpu-sysreg-properties
2026-07-16 21:38 [RFC PATCH v3 00/19] named CPU models for Arm64 on KVM Khushit Shah
2026-07-16 21:38 ` [RFC PATCH v3 01/19] target/arm/sysreg: regenerate cpu-sysregs.h.inc Khushit Shah
@ 2026-07-16 21:38 ` Khushit Shah
2026-07-20 14:24 ` Eric Auger
2026-07-16 21:38 ` [RFC PATCH v3 03/19] target/arm: regenerate cpu-idregs.h.inc Khushit Shah
` (16 subsequent siblings)
18 siblings, 1 reply; 29+ messages in thread
From: Khushit Shah @ 2026-07-16 21:38 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, prerna.saxena
- handle quoted bitstrings and decimal
- skip Values.ValueRange entries.
- Emit unique RESx_{lsb} names for reserved fields so no two fields in
a register share a name.
- Emit a dummy 64-bit VAL field for registers with no defined fields,
such as AIDR_EL1 and REVIDR_EL1.
Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
---
.../update-aarch64-cpu-sysreg-properties.py | 67 +++++++++++++------
1 file changed, 45 insertions(+), 22 deletions(-)
mode change 100644 => 100755 scripts/update-aarch64-cpu-sysreg-properties.py
diff --git a/scripts/update-aarch64-cpu-sysreg-properties.py b/scripts/update-aarch64-cpu-sysreg-properties.py
old mode 100644
new mode 100755
index 9e829fda2e..ecc35db528
--- a/scripts/update-aarch64-cpu-sysreg-properties.py
+++ b/scripts/update-aarch64-cpu-sysreg-properties.py
@@ -106,6 +106,29 @@ def collect_fields(item, bit_offset=0):
return fields
+def parse_value_int(raw_val):
+ if raw_val is None or isinstance(raw_val, bool):
+ return None
+
+ # may already be real number
+ if isinstance(raw_val, int):
+ return raw_val
+
+ raw_str = str(raw_val).strip()
+
+ if "'" in raw_str:
+ # quoted bitstring like "'0100'"
+ bits = raw_str.replace("'", "")
+ try:
+ return int(bits, 2)
+ except ValueError:
+ return None
+
+ # unquoted, try decimal
+ try:
+ return int(raw_str, 0)
+ except ValueError:
+ return None
def extract_field_enums(field):
enums = []
@@ -124,32 +147,23 @@ def extract_field_enums(field):
if not isinstance(val_entries, list):
return enums
+ # A Values.ValueRange field specifies start and end value for a range.
+ # Don't enumerate anything for them.
+ for val_entry in val_entries:
+ if isinstance(val_entry, dict) and \
+ val_entry.get("_type") == "Values.ValueRange":
+ return []
+
for val_entry in val_entries:
if not isinstance(val_entry, dict):
continue
-
+
if val_entry.get("_type") == "Values.Value":
- raw_val = val_entry.get("value")
- if raw_val is None:
+ int_val = parse_value_int(val_entry.get("value"))
+ if int_val is None:
continue
-
- # some of the values have ' like "'0100'"
- raw_val_str = str(raw_val).strip().replace("'", "")
-
- try:
- # convert into bin
- int_val = int(raw_val_str, 2)
- except ValueError:
- try:
- # Fallback to dec if not bin
- int_val = int(raw_val_str, 0)
- except ValueError:
- continue
-
- enums.append({
- 'value': int_val
- })
-
+ enums.append({'value': int_val})
+
return enums
def generate_sysreg_properties_from_registers_json(id_reg_names, raw_json_path):
@@ -210,7 +224,7 @@ def generate_sysreg_properties_from_registers_json(id_reg_names, raw_json_path):
msb > current_fieldset_fields[unique_key]['msb']:
enums = extract_field_enums(val)
current_fieldset_fields[unique_key] = {
- 'raw_name': name,
+ 'raw_name': unique_key,
'lsb': lsb,
'msb': msb,
'width': width,
@@ -238,6 +252,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:
+ # cases like REVIDR_EL1 and AIDR_EL1.
+ # augment a dummy fields VAL.
+ sorted_fields.append(('VAL', {
+ 'lsb': 0,
+ 'msb': 63,
+ 'width': 64,
+ 'enums': []
+ }))
for unique_key, bits in sorted_fields:
enums_list = bits.get('enums', [])
--
2.52.0
^ permalink raw reply related [flat|nested] 29+ messages in thread* Re: [RFC PATCH v3 02/19] scripts: bug fixes in update-aarch64-cpu-sysreg-properties
2026-07-16 21:38 ` [RFC PATCH v3 02/19] scripts: bug fixes in update-aarch64-cpu-sysreg-properties Khushit Shah
@ 2026-07-20 14:24 ` Eric Auger
0 siblings, 0 replies; 29+ messages in thread
From: Eric Auger @ 2026-07-20 14:24 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,
prerna.saxena
On 7/16/26 11:38 PM, Khushit Shah wrote:
> - handle quoted bitstrings and decimal
> - skip Values.ValueRange entries.
The above is the issue you reported on my v6. See my comment on the
other thread.
> - Emit unique RESx_{lsb} names for reserved fields so no two fields in
> a register share a name.
The requirement for naming RES field needs to be explained. I understand
that now you expose all fields including those which are not writable it
may be required but at this stage I still fail why this is requested.
> - Emit a dummy 64-bit VAL field for registers with no defined fields,
> such as AIDR_EL1 and REVIDR_EL1.
This is yet another functional change that could be separate.
Thanks
Eric
>
> Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
> ---
> .../update-aarch64-cpu-sysreg-properties.py | 67 +++++++++++++------
> 1 file changed, 45 insertions(+), 22 deletions(-)
> mode change 100644 => 100755 scripts/update-aarch64-cpu-sysreg-properties.py
>
> diff --git a/scripts/update-aarch64-cpu-sysreg-properties.py b/scripts/update-aarch64-cpu-sysreg-properties.py
> old mode 100644
> new mode 100755
> index 9e829fda2e..ecc35db528
> --- a/scripts/update-aarch64-cpu-sysreg-properties.py
> +++ b/scripts/update-aarch64-cpu-sysreg-properties.py
> @@ -106,6 +106,29 @@ def collect_fields(item, bit_offset=0):
>
> return fields
>
> +def parse_value_int(raw_val):
> + if raw_val is None or isinstance(raw_val, bool):
> + return None
> +
> + # may already be real number
> + if isinstance(raw_val, int):
> + return raw_val
> +
> + raw_str = str(raw_val).strip()
> +
> + if "'" in raw_str:
> + # quoted bitstring like "'0100'"
> + bits = raw_str.replace("'", "")
> + try:
> + return int(bits, 2)
> + except ValueError:
> + return None
> +
> + # unquoted, try decimal
> + try:
> + return int(raw_str, 0)
> + except ValueError:
> + return None
>
> def extract_field_enums(field):
> enums = []
> @@ -124,32 +147,23 @@ def extract_field_enums(field):
> if not isinstance(val_entries, list):
> return enums
>
> + # A Values.ValueRange field specifies start and end value for a range.
> + # Don't enumerate anything for them.
> + for val_entry in val_entries:
> + if isinstance(val_entry, dict) and \
> + val_entry.get("_type") == "Values.ValueRange":
> + return []
> +
> for val_entry in val_entries:
> if not isinstance(val_entry, dict):
> continue
> -
> +
> if val_entry.get("_type") == "Values.Value":
> - raw_val = val_entry.get("value")
> - if raw_val is None:
> + int_val = parse_value_int(val_entry.get("value"))
> + if int_val is None:
> continue
> -
> - # some of the values have ' like "'0100'"
> - raw_val_str = str(raw_val).strip().replace("'", "")
> -
> - try:
> - # convert into bin
> - int_val = int(raw_val_str, 2)
> - except ValueError:
> - try:
> - # Fallback to dec if not bin
> - int_val = int(raw_val_str, 0)
> - except ValueError:
> - continue
> -
> - enums.append({
> - 'value': int_val
> - })
> -
> + enums.append({'value': int_val})
> +
> return enums
>
> def generate_sysreg_properties_from_registers_json(id_reg_names, raw_json_path):
> @@ -210,7 +224,7 @@ def generate_sysreg_properties_from_registers_json(id_reg_names, raw_json_path):
> msb > current_fieldset_fields[unique_key]['msb']:
> enums = extract_field_enums(val)
> current_fieldset_fields[unique_key] = {
> - 'raw_name': name,
> + 'raw_name': unique_key,
> 'lsb': lsb,
> 'msb': msb,
> 'width': width,
> @@ -238,6 +252,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:
> + # cases like REVIDR_EL1 and AIDR_EL1.
> + # augment a dummy fields VAL.
> + sorted_fields.append(('VAL', {
> + 'lsb': 0,
> + 'msb': 63,
> + 'width': 64,
> + 'enums': []
> + }))
>
> for unique_key, bits in sorted_fields:
> enums_list = bits.get('enums', [])
^ permalink raw reply [flat|nested] 29+ messages in thread
* [RFC PATCH v3 03/19] target/arm: regenerate cpu-idregs.h.inc
2026-07-16 21:38 [RFC PATCH v3 00/19] named CPU models for Arm64 on KVM Khushit Shah
2026-07-16 21:38 ` [RFC PATCH v3 01/19] target/arm/sysreg: regenerate cpu-sysregs.h.inc Khushit Shah
2026-07-16 21:38 ` [RFC PATCH v3 02/19] scripts: bug fixes in update-aarch64-cpu-sysreg-properties Khushit Shah
@ 2026-07-16 21:38 ` Khushit Shah
2026-07-20 14:39 ` Eric Auger
2026-07-16 21:38 ` [RFC PATCH v3 04/19] target/arm: expose all ID regs fields as properties Khushit Shah
` (15 subsequent siblings)
18 siblings, 1 reply; 29+ messages in thread
From: Khushit Shah @ 2026-07-16 21:38 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, prerna.saxena
Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
---
target/arm/cpu-idregs.h.inc | 165 +++++++++++++++++-------------------
1 file changed, 76 insertions(+), 89 deletions(-)
diff --git a/target/arm/cpu-idregs.h.inc b/target/arm/cpu-idregs.h.inc
index 5fdc84237c..1851b37937 100644
--- a/target/arm/cpu-idregs.h.inc
+++ b/target/arm/cpu-idregs.h.inc
@@ -12,23 +12,24 @@
/* IDREG_END(REG) */
IDREG_START(AIDR_EL1)
+ IDREG_FIELD(AIDR_EL1, VAL, 0, 64)
IDREG_END(AIDR_EL1)
IDREG_START(CCSIDR2_EL1)
- IDREG_FIELD(CCSIDR2_EL1, RES0, 24, 40)
+ IDREG_FIELD(CCSIDR2_EL1, RES0_24, 24, 40)
IDREG_FIELD(CCSIDR2_EL1, NumSets, 0, 24)
IDREG_END(CCSIDR2_EL1)
IDREG_START(CCSIDR_EL1)
- IDREG_FIELD(CCSIDR_EL1, RES0, 56, 8)
+ IDREG_FIELD(CCSIDR_EL1, RES0_56, 56, 8)
IDREG_FIELD(CCSIDR_EL1, NumSets, 32, 24)
- IDREG_FIELD(CCSIDR_EL1, RES0, 24, 8)
+ IDREG_FIELD(CCSIDR_EL1, RES0_24, 24, 8)
IDREG_FIELD(CCSIDR_EL1, Associativity, 3, 21)
IDREG_FIELD(CCSIDR_EL1, LineSize, 0, 3)
IDREG_END(CCSIDR_EL1)
IDREG_START(CLIDR_EL1)
- IDREG_FIELD(CLIDR_EL1, RES0, 47, 17)
+ IDREG_FIELD(CLIDR_EL1, RES0_47, 47, 17)
IDREG_FIELD(CLIDR_EL1, Ttype7, 45, 2)
IDREG_FIELD(CLIDR_EL1, Ttype6, 43, 2)
IDREG_FIELD(CLIDR_EL1, Ttype5, 41, 2)
@@ -59,10 +60,10 @@ IDREG_START(CLIDR_EL1)
IDREG_END(CLIDR_EL1)
IDREG_START(CTR_EL0)
- IDREG_FIELD(CTR_EL0, RES0, 38, 26)
+ IDREG_FIELD(CTR_EL0, RES0_38, 38, 26)
IDREG_FIELD(CTR_EL0, TminLine, 32, 6)
- IDREG_FIELD(CTR_EL0, RES1, 31, 1)
- IDREG_FIELD(CTR_EL0, RES0, 30, 1)
+ IDREG_FIELD(CTR_EL0, RES1_31, 31, 1)
+ IDREG_FIELD(CTR_EL0, RES0_30, 30, 1)
IDREG_FIELD_START(CTR_EL0, DIC, 29, 1)
IDREG_FIELD_ARCH_VAL(0)
IDREG_FIELD_ARCH_VAL(1)
@@ -80,28 +81,28 @@ IDREG_START(CTR_EL0)
IDREG_FIELD_ARCH_VAL(2)
IDREG_FIELD_ARCH_VAL(3)
IDREG_FIELD_END(CTR_EL0, L1Ip)
- IDREG_FIELD(CTR_EL0, RES0, 4, 10)
+ IDREG_FIELD(CTR_EL0, RES0_4, 4, 10)
IDREG_FIELD(CTR_EL0, IminLine, 0, 4)
IDREG_END(CTR_EL0)
IDREG_START(DCZID_EL0)
- IDREG_FIELD(DCZID_EL0, RES0, 9, 55)
+ IDREG_FIELD(DCZID_EL0, RES0_9, 9, 55)
IDREG_FIELD(DCZID_EL0, TBS, 5, 4)
IDREG_FIELD(DCZID_EL0, DZP, 4, 1)
IDREG_FIELD(DCZID_EL0, BS, 0, 4)
IDREG_END(DCZID_EL0)
IDREG_START(GMID_EL1)
- IDREG_FIELD(GMID_EL1, RES0, 4, 60)
+ IDREG_FIELD(GMID_EL1, RES0_4, 4, 60)
IDREG_FIELD(GMID_EL1, BS, 0, 4)
IDREG_END(GMID_EL1)
IDREG_START(ID_AA64AFR0_EL1)
- IDREG_FIELD(ID_AA64AFR0_EL1, RES0, 32, 32)
+ IDREG_FIELD(ID_AA64AFR0_EL1, RES0_32, 32, 32)
IDREG_END(ID_AA64AFR0_EL1)
IDREG_START(ID_AA64AFR1_EL1)
- IDREG_FIELD(ID_AA64AFR1_EL1, RES0, 0, 64)
+ IDREG_FIELD(ID_AA64AFR1_EL1, RES0_0, 0, 64)
IDREG_END(ID_AA64AFR1_EL1)
IDREG_START(ID_AA64DFR0_EL1)
@@ -145,18 +146,14 @@ IDREG_START(ID_AA64DFR0_EL1)
IDREG_FIELD_ARCH_VAL(5)
IDREG_FIELD_ARCH_VAL(6)
IDREG_FIELD_END(ID_AA64DFR0_EL1, PMSVer)
- IDREG_FIELD_START(ID_AA64DFR0_EL1, CTX_CMPs, 28, 4)
- IDREG_FIELD_ARCH_VAL(15)
- IDREG_FIELD_END(ID_AA64DFR0_EL1, CTX_CMPs)
- IDREG_FIELD(ID_AA64DFR0_EL1, RES0, 24, 4)
+ IDREG_FIELD(ID_AA64DFR0_EL1, CTX_CMPs, 28, 4)
+ IDREG_FIELD(ID_AA64DFR0_EL1, RES0_24, 24, 4)
IDREG_FIELD(ID_AA64DFR0_EL1, WRPs, 20, 4)
IDREG_FIELD_START(ID_AA64DFR0_EL1, PMSS, 16, 4)
IDREG_FIELD_ARCH_VAL(0)
IDREG_FIELD_ARCH_VAL(1)
IDREG_FIELD_END(ID_AA64DFR0_EL1, PMSS)
- IDREG_FIELD_START(ID_AA64DFR0_EL1, BRPs, 12, 4)
- IDREG_FIELD_ARCH_VAL(15)
- IDREG_FIELD_END(ID_AA64DFR0_EL1, BRPs)
+ IDREG_FIELD(ID_AA64DFR0_EL1, BRPs, 12, 4)
IDREG_FIELD_START(ID_AA64DFR0_EL1, PMUVer, 8, 4)
IDREG_FIELD_ARCH_VAL(0)
IDREG_FIELD_ARCH_VAL(1)
@@ -209,20 +206,14 @@ IDREG_START(ID_AA64DFR1_EL1)
IDREG_FIELD_ARCH_VAL(1)
IDREG_FIELD_ARCH_VAL(2)
IDREG_FIELD_END(ID_AA64DFR1_EL1, SPMU)
- IDREG_FIELD_START(ID_AA64DFR1_EL1, CTX_CMPs, 24, 8)
- IDREG_FIELD_ARCH_VAL(0)
- IDREG_FIELD_END(ID_AA64DFR1_EL1, CTX_CMPs)
- IDREG_FIELD_START(ID_AA64DFR1_EL1, WRPs, 16, 8)
- IDREG_FIELD_ARCH_VAL(0)
- IDREG_FIELD_END(ID_AA64DFR1_EL1, WRPs)
- IDREG_FIELD_START(ID_AA64DFR1_EL1, BRPs, 8, 8)
- IDREG_FIELD_ARCH_VAL(0)
- IDREG_FIELD_END(ID_AA64DFR1_EL1, BRPs)
+ IDREG_FIELD(ID_AA64DFR1_EL1, CTX_CMPs, 24, 8)
+ IDREG_FIELD(ID_AA64DFR1_EL1, WRPs, 16, 8)
+ IDREG_FIELD(ID_AA64DFR1_EL1, BRPs, 8, 8)
IDREG_FIELD(ID_AA64DFR1_EL1, SYSPMUID, 0, 8)
IDREG_END(ID_AA64DFR1_EL1)
IDREG_START(ID_AA64DFR2_EL1)
- IDREG_FIELD(ID_AA64DFR2_EL1, RES0, 28, 36)
+ IDREG_FIELD(ID_AA64DFR2_EL1, RES0_28, 28, 36)
IDREG_FIELD_START(ID_AA64DFR2_EL1, TRBE_EXC, 24, 4)
IDREG_FIELD_ARCH_VAL(0)
IDREG_FIELD_ARCH_VAL(1)
@@ -235,7 +226,7 @@ IDREG_START(ID_AA64DFR2_EL1)
IDREG_FIELD_ARCH_VAL(0)
IDREG_FIELD_ARCH_VAL(1)
IDREG_FIELD_END(ID_AA64DFR2_EL1, SPE_EXC)
- IDREG_FIELD(ID_AA64DFR2_EL1, RES0, 8, 8)
+ IDREG_FIELD(ID_AA64DFR2_EL1, RES0_8, 8, 8)
IDREG_FIELD_START(ID_AA64DFR2_EL1, BWE, 4, 4)
IDREG_FIELD_ARCH_VAL(0)
IDREG_FIELD_ARCH_VAL(1)
@@ -248,7 +239,7 @@ IDREG_START(ID_AA64DFR2_EL1)
IDREG_END(ID_AA64DFR2_EL1)
IDREG_START(ID_AA64FPFR0_EL1)
- IDREG_FIELD(ID_AA64FPFR0_EL1, RES0, 32, 32)
+ IDREG_FIELD(ID_AA64FPFR0_EL1, RES0_32, 32, 32)
IDREG_FIELD_START(ID_AA64FPFR0_EL1, F8CVT, 31, 1)
IDREG_FIELD_ARCH_VAL(0)
IDREG_FIELD_ARCH_VAL(1)
@@ -273,13 +264,13 @@ IDREG_START(ID_AA64FPFR0_EL1)
IDREG_FIELD_ARCH_VAL(0)
IDREG_FIELD_ARCH_VAL(1)
IDREG_FIELD_END(ID_AA64FPFR0_EL1, F8MM4)
- IDREG_FIELD(ID_AA64FPFR0_EL1, RES0, 16, 10)
+ IDREG_FIELD(ID_AA64FPFR0_EL1, RES0_16, 16, 10)
IDREG_FIELD_START(ID_AA64FPFR0_EL1, F16MM2, 15, 1)
IDREG_FIELD_ARCH_VAL(0)
IDREG_FIELD_ARCH_VAL(1)
IDREG_FIELD_END(ID_AA64FPFR0_EL1, F16MM2)
- IDREG_FIELD(ID_AA64FPFR0_EL1, RES0, 8, 7)
- IDREG_FIELD(ID_AA64FPFR0_EL1, RAZ, 2, 6)
+ IDREG_FIELD(ID_AA64FPFR0_EL1, RES0_8, 8, 7)
+ IDREG_FIELD(ID_AA64FPFR0_EL1, RAZ_2, 2, 6)
IDREG_FIELD_START(ID_AA64FPFR0_EL1, F8E4M3, 1, 1)
IDREG_FIELD_ARCH_VAL(0)
IDREG_FIELD_ARCH_VAL(1)
@@ -331,7 +322,7 @@ IDREG_START(ID_AA64ISAR0_EL1)
IDREG_FIELD_ARCH_VAL(0)
IDREG_FIELD_ARCH_VAL(1)
IDREG_FIELD_END(ID_AA64ISAR0_EL1, RDM)
- IDREG_FIELD(ID_AA64ISAR0_EL1, RES0, 24, 4)
+ IDREG_FIELD(ID_AA64ISAR0_EL1, RES0_24, 24, 4)
IDREG_FIELD_START(ID_AA64ISAR0_EL1, Atomic, 20, 4)
IDREG_FIELD_ARCH_VAL(0)
IDREG_FIELD_ARCH_VAL(2)
@@ -355,7 +346,7 @@ IDREG_START(ID_AA64ISAR0_EL1)
IDREG_FIELD_ARCH_VAL(1)
IDREG_FIELD_ARCH_VAL(2)
IDREG_FIELD_END(ID_AA64ISAR0_EL1, AES)
- IDREG_FIELD(ID_AA64ISAR0_EL1, RES0, 0, 4)
+ IDREG_FIELD(ID_AA64ISAR0_EL1, RES0_0, 0, 4)
IDREG_END(ID_AA64ISAR0_EL1)
IDREG_START(ID_AA64ISAR1_EL1)
@@ -519,7 +510,7 @@ IDREG_START(ID_AA64ISAR2_EL1)
IDREG_END(ID_AA64ISAR2_EL1)
IDREG_START(ID_AA64ISAR3_EL1)
- IDREG_FIELD(ID_AA64ISAR3_EL1, RES0, 48, 16)
+ IDREG_FIELD(ID_AA64ISAR3_EL1, RES0_48, 48, 16)
IDREG_FIELD_START(ID_AA64ISAR3_EL1, LSCP, 44, 4)
IDREG_FIELD_ARCH_VAL(0)
IDREG_FIELD_ARCH_VAL(1)
@@ -583,7 +574,7 @@ IDREG_START(ID_AA64MMFR0_EL1)
IDREG_FIELD_ARCH_VAL(1)
IDREG_FIELD_ARCH_VAL(2)
IDREG_FIELD_END(ID_AA64MMFR0_EL1, FGT)
- IDREG_FIELD(ID_AA64MMFR0_EL1, RES0, 48, 8)
+ IDREG_FIELD(ID_AA64MMFR0_EL1, RES0_48, 48, 8)
IDREG_FIELD_START(ID_AA64MMFR0_EL1, ExS, 44, 4)
IDREG_FIELD_ARCH_VAL(0)
IDREG_FIELD_ARCH_VAL(1)
@@ -736,7 +727,7 @@ IDREG_START(ID_AA64MMFR2_EL1)
IDREG_FIELD_ARCH_VAL(0)
IDREG_FIELD_ARCH_VAL(1)
IDREG_FIELD_END(ID_AA64MMFR2_EL1, TTL)
- IDREG_FIELD(ID_AA64MMFR2_EL1, RES0, 44, 4)
+ IDREG_FIELD(ID_AA64MMFR2_EL1, RES0_44, 44, 4)
IDREG_FIELD_START(ID_AA64MMFR2_EL1, FWB, 40, 4)
IDREG_FIELD_ARCH_VAL(0)
IDREG_FIELD_ARCH_VAL(1)
@@ -802,7 +793,7 @@ IDREG_START(ID_AA64MMFR3_EL1)
IDREG_FIELD_ARCH_VAL(2)
IDREG_FIELD_ARCH_VAL(3)
IDREG_FIELD_END(ID_AA64MMFR3_EL1, SDERR)
- IDREG_FIELD(ID_AA64MMFR3_EL1, RES0, 48, 4)
+ IDREG_FIELD(ID_AA64MMFR3_EL1, RES0_48, 48, 4)
IDREG_FIELD_START(ID_AA64MMFR3_EL1, ANERR, 44, 4)
IDREG_FIELD_ARCH_VAL(0)
IDREG_FIELD_ARCH_VAL(1)
@@ -1056,7 +1047,7 @@ IDREG_START(ID_AA64PFR1_EL1)
IDREG_FIELD_ARCH_VAL(1)
IDREG_FIELD_ARCH_VAL(2)
IDREG_FIELD_END(ID_AA64PFR1_EL1, SME)
- IDREG_FIELD(ID_AA64PFR1_EL1, RES0, 20, 4)
+ IDREG_FIELD(ID_AA64PFR1_EL1, RES0_20, 20, 4)
IDREG_FIELD_START(ID_AA64PFR1_EL1, MPAM_frac, 16, 4)
IDREG_FIELD_ARCH_VAL(0)
IDREG_FIELD_ARCH_VAL(1)
@@ -1084,7 +1075,7 @@ IDREG_START(ID_AA64PFR1_EL1)
IDREG_END(ID_AA64PFR1_EL1)
IDREG_START(ID_AA64PFR2_EL1)
- IDREG_FIELD(ID_AA64PFR2_EL1, RES0, 48, 16)
+ IDREG_FIELD(ID_AA64PFR2_EL1, RES0_48, 48, 16)
IDREG_FIELD_START(ID_AA64PFR2_EL1, VMTETCL, 44, 4)
IDREG_FIELD_ARCH_VAL(0)
IDREG_FIELD_ARCH_VAL(1)
@@ -1144,7 +1135,7 @@ IDREG_START(ID_AA64SMFR0_EL1)
IDREG_FIELD_ARCH_VAL(0)
IDREG_FIELD_ARCH_VAL(1)
IDREG_FIELD_END(ID_AA64SMFR0_EL1, FA64)
- IDREG_FIELD(ID_AA64SMFR0_EL1, RES0, 62, 1)
+ IDREG_FIELD(ID_AA64SMFR0_EL1, RES0_62, 62, 1)
IDREG_FIELD_START(ID_AA64SMFR0_EL1, LUT6, 61, 1)
IDREG_FIELD_ARCH_VAL(0)
IDREG_FIELD_ARCH_VAL(1)
@@ -1164,7 +1155,7 @@ IDREG_START(ID_AA64SMFR0_EL1)
IDREG_FIELD_ARCH_VAL(0)
IDREG_FIELD_ARCH_VAL(15)
IDREG_FIELD_END(ID_AA64SMFR0_EL1, I16I64)
- IDREG_FIELD(ID_AA64SMFR0_EL1, RES0, 49, 3)
+ IDREG_FIELD(ID_AA64SMFR0_EL1, RES0_49, 49, 3)
IDREG_FIELD_START(ID_AA64SMFR0_EL1, F64F64, 48, 1)
IDREG_FIELD_ARCH_VAL(0)
IDREG_FIELD_ARCH_VAL(1)
@@ -1209,7 +1200,7 @@ IDREG_START(ID_AA64SMFR0_EL1)
IDREG_FIELD_ARCH_VAL(0)
IDREG_FIELD_ARCH_VAL(1)
IDREG_FIELD_END(ID_AA64SMFR0_EL1, F32F32)
- IDREG_FIELD(ID_AA64SMFR0_EL1, RES0, 31, 1)
+ IDREG_FIELD(ID_AA64SMFR0_EL1, RES0_31, 31, 1)
IDREG_FIELD_START(ID_AA64SMFR0_EL1, SF8FMA, 30, 1)
IDREG_FIELD_ARCH_VAL(0)
IDREG_FIELD_ARCH_VAL(1)
@@ -1222,7 +1213,7 @@ IDREG_START(ID_AA64SMFR0_EL1)
IDREG_FIELD_ARCH_VAL(0)
IDREG_FIELD_ARCH_VAL(1)
IDREG_FIELD_END(ID_AA64SMFR0_EL1, SF8DP2)
- IDREG_FIELD(ID_AA64SMFR0_EL1, RES0, 26, 2)
+ IDREG_FIELD(ID_AA64SMFR0_EL1, RES0_26, 26, 2)
IDREG_FIELD_START(ID_AA64SMFR0_EL1, SBitPerm, 25, 1)
IDREG_FIELD_ARCH_VAL(0)
IDREG_FIELD_ARCH_VAL(1)
@@ -1235,12 +1226,12 @@ IDREG_START(ID_AA64SMFR0_EL1)
IDREG_FIELD_ARCH_VAL(0)
IDREG_FIELD_ARCH_VAL(1)
IDREG_FIELD_END(ID_AA64SMFR0_EL1, SFEXPA)
- IDREG_FIELD(ID_AA64SMFR0_EL1, RES0, 17, 6)
+ IDREG_FIELD(ID_AA64SMFR0_EL1, RES0_17, 17, 6)
IDREG_FIELD_START(ID_AA64SMFR0_EL1, STMOP, 16, 1)
IDREG_FIELD_ARCH_VAL(0)
IDREG_FIELD_ARCH_VAL(1)
IDREG_FIELD_END(ID_AA64SMFR0_EL1, STMOP)
- IDREG_FIELD(ID_AA64SMFR0_EL1, RES0, 1, 15)
+ IDREG_FIELD(ID_AA64SMFR0_EL1, RES0_1, 1, 15)
IDREG_FIELD_START(ID_AA64SMFR0_EL1, SMOP4, 0, 1)
IDREG_FIELD_ARCH_VAL(0)
IDREG_FIELD_ARCH_VAL(1)
@@ -1248,7 +1239,7 @@ IDREG_START(ID_AA64SMFR0_EL1)
IDREG_END(ID_AA64SMFR0_EL1)
IDREG_START(ID_AA64ZFR0_EL1)
- IDREG_FIELD(ID_AA64ZFR0_EL1, RES0, 60, 4)
+ IDREG_FIELD(ID_AA64ZFR0_EL1, RES0_60, 60, 4)
IDREG_FIELD_START(ID_AA64ZFR0_EL1, F64MM, 56, 4)
IDREG_FIELD_ARCH_VAL(0)
IDREG_FIELD_ARCH_VAL(1)
@@ -1269,12 +1260,12 @@ IDREG_START(ID_AA64ZFR0_EL1)
IDREG_FIELD_ARCH_VAL(0)
IDREG_FIELD_ARCH_VAL(1)
IDREG_FIELD_END(ID_AA64ZFR0_EL1, SM4)
- IDREG_FIELD(ID_AA64ZFR0_EL1, RES0, 36, 4)
+ IDREG_FIELD(ID_AA64ZFR0_EL1, RES0_36, 36, 4)
IDREG_FIELD_START(ID_AA64ZFR0_EL1, SHA3, 32, 4)
IDREG_FIELD_ARCH_VAL(0)
IDREG_FIELD_ARCH_VAL(1)
IDREG_FIELD_END(ID_AA64ZFR0_EL1, SHA3)
- IDREG_FIELD(ID_AA64ZFR0_EL1, RES0, 28, 4)
+ IDREG_FIELD(ID_AA64ZFR0_EL1, RES0_28, 28, 4)
IDREG_FIELD_START(ID_AA64ZFR0_EL1, B16B16, 24, 4)
IDREG_FIELD_ARCH_VAL(0)
IDREG_FIELD_ARCH_VAL(1)
@@ -1294,7 +1285,7 @@ IDREG_START(ID_AA64ZFR0_EL1)
IDREG_FIELD_ARCH_VAL(0)
IDREG_FIELD_ARCH_VAL(1)
IDREG_FIELD_END(ID_AA64ZFR0_EL1, EltPerm)
- IDREG_FIELD(ID_AA64ZFR0_EL1, RES0, 8, 4)
+ IDREG_FIELD(ID_AA64ZFR0_EL1, RES0_8, 8, 4)
IDREG_FIELD_START(ID_AA64ZFR0_EL1, AES, 4, 4)
IDREG_FIELD_ARCH_VAL(0)
IDREG_FIELD_ARCH_VAL(1)
@@ -1311,11 +1302,11 @@ IDREG_START(ID_AA64ZFR0_EL1)
IDREG_END(ID_AA64ZFR0_EL1)
IDREG_START(ID_AFR0_EL1)
- IDREG_FIELD(ID_AFR0_EL1, RES0, 0, 64)
+ IDREG_FIELD(ID_AFR0_EL1, RES0_0, 0, 64)
IDREG_END(ID_AFR0_EL1)
IDREG_START(ID_DFR0_EL1)
- IDREG_FIELD(ID_DFR0_EL1, RES0, 32, 32)
+ IDREG_FIELD(ID_DFR0_EL1, RES0_32, 32, 32)
IDREG_FIELD_START(ID_DFR0_EL1, TraceFilt, 28, 4)
IDREG_FIELD_ARCH_VAL(0)
IDREG_FIELD_ARCH_VAL(1)
@@ -1367,7 +1358,7 @@ IDREG_START(ID_DFR0_EL1)
IDREG_END(ID_DFR0_EL1)
IDREG_START(ID_DFR1_EL1)
- IDREG_FIELD(ID_DFR1_EL1, RES0, 8, 56)
+ IDREG_FIELD(ID_DFR1_EL1, RES0_8, 8, 56)
IDREG_FIELD_START(ID_DFR1_EL1, HPMN0, 4, 4)
IDREG_FIELD_ARCH_VAL(0)
IDREG_FIELD_ARCH_VAL(1)
@@ -1380,7 +1371,7 @@ IDREG_START(ID_DFR1_EL1)
IDREG_END(ID_DFR1_EL1)
IDREG_START(ID_ISAR0_EL1)
- IDREG_FIELD(ID_ISAR0_EL1, RES0, 28, 36)
+ IDREG_FIELD(ID_ISAR0_EL1, RES0_28, 28, 36)
IDREG_FIELD_START(ID_ISAR0_EL1, Divide, 24, 4)
IDREG_FIELD_ARCH_VAL(0)
IDREG_FIELD_ARCH_VAL(1)
@@ -1416,7 +1407,7 @@ IDREG_START(ID_ISAR0_EL1)
IDREG_END(ID_ISAR0_EL1)
IDREG_START(ID_ISAR1_EL1)
- IDREG_FIELD(ID_ISAR1_EL1, RES0, 32, 32)
+ IDREG_FIELD(ID_ISAR1_EL1, RES0_32, 32, 32)
IDREG_FIELD_START(ID_ISAR1_EL1, Jazelle, 28, 4)
IDREG_FIELD_ARCH_VAL(0)
IDREG_FIELD_ARCH_VAL(1)
@@ -1455,7 +1446,7 @@ IDREG_START(ID_ISAR1_EL1)
IDREG_END(ID_ISAR1_EL1)
IDREG_START(ID_ISAR2_EL1)
- IDREG_FIELD(ID_ISAR2_EL1, RES0, 32, 32)
+ IDREG_FIELD(ID_ISAR2_EL1, RES0_32, 32, 32)
IDREG_FIELD_START(ID_ISAR2_EL1, Reversal, 28, 4)
IDREG_FIELD_ARCH_VAL(0)
IDREG_FIELD_ARCH_VAL(1)
@@ -1501,7 +1492,7 @@ IDREG_START(ID_ISAR2_EL1)
IDREG_END(ID_ISAR2_EL1)
IDREG_START(ID_ISAR3_EL1)
- IDREG_FIELD(ID_ISAR3_EL1, RES0, 32, 32)
+ IDREG_FIELD(ID_ISAR3_EL1, RES0_32, 32, 32)
IDREG_FIELD_START(ID_ISAR3_EL1, T32EE, 28, 4)
IDREG_FIELD_ARCH_VAL(0)
IDREG_FIELD_ARCH_VAL(1)
@@ -1539,7 +1530,7 @@ IDREG_START(ID_ISAR3_EL1)
IDREG_END(ID_ISAR3_EL1)
IDREG_START(ID_ISAR4_EL1)
- IDREG_FIELD(ID_ISAR4_EL1, RES0, 32, 32)
+ IDREG_FIELD(ID_ISAR4_EL1, RES0_32, 32, 32)
IDREG_FIELD_START(ID_ISAR4_EL1, SWP_frac, 28, 4)
IDREG_FIELD_ARCH_VAL(0)
IDREG_FIELD_ARCH_VAL(1)
@@ -1564,12 +1555,12 @@ IDREG_START(ID_ISAR4_EL1)
IDREG_FIELD_ARCH_VAL(0)
IDREG_FIELD_ARCH_VAL(1)
IDREG_FIELD_END(ID_ISAR4_EL1, Writeback)
- IDREG_FIELD_START(ID_ISAR4_EL1, WI, 4, 4)
+ IDREG_FIELD_START(ID_ISAR4_EL1, WI_4, 4, 4)
IDREG_FIELD_ARCH_VAL(0)
IDREG_FIELD_ARCH_VAL(1)
IDREG_FIELD_ARCH_VAL(3)
IDREG_FIELD_ARCH_VAL(4)
- IDREG_FIELD_END(ID_ISAR4_EL1, WI)
+ IDREG_FIELD_END(ID_ISAR4_EL1, WI_4)
IDREG_FIELD_START(ID_ISAR4_EL1, Unpriv, 0, 4)
IDREG_FIELD_ARCH_VAL(0)
IDREG_FIELD_ARCH_VAL(1)
@@ -1578,7 +1569,7 @@ IDREG_START(ID_ISAR4_EL1)
IDREG_END(ID_ISAR4_EL1)
IDREG_START(ID_ISAR5_EL1)
- IDREG_FIELD(ID_ISAR5_EL1, RES0, 32, 32)
+ IDREG_FIELD(ID_ISAR5_EL1, RES0_32, 32, 32)
IDREG_FIELD_START(ID_ISAR5_EL1, VCMA, 28, 4)
IDREG_FIELD_ARCH_VAL(0)
IDREG_FIELD_ARCH_VAL(1)
@@ -1587,7 +1578,7 @@ IDREG_START(ID_ISAR5_EL1)
IDREG_FIELD_ARCH_VAL(0)
IDREG_FIELD_ARCH_VAL(1)
IDREG_FIELD_END(ID_ISAR5_EL1, RDM)
- IDREG_FIELD(ID_ISAR5_EL1, RES0, 20, 4)
+ IDREG_FIELD(ID_ISAR5_EL1, RES0_20, 20, 4)
IDREG_FIELD_START(ID_ISAR5_EL1, CRC32, 16, 4)
IDREG_FIELD_ARCH_VAL(0)
IDREG_FIELD_ARCH_VAL(1)
@@ -1612,7 +1603,7 @@ IDREG_START(ID_ISAR5_EL1)
IDREG_END(ID_ISAR5_EL1)
IDREG_START(ID_ISAR6_EL1)
- IDREG_FIELD(ID_ISAR6_EL1, RES0, 32, 32)
+ IDREG_FIELD(ID_ISAR6_EL1, RES0_32, 32, 32)
IDREG_FIELD_START(ID_ISAR6_EL1, CLRBHB, 28, 4)
IDREG_FIELD_ARCH_VAL(0)
IDREG_FIELD_ARCH_VAL(1)
@@ -1649,7 +1640,7 @@ IDREG_START(ID_ISAR6_EL1)
IDREG_END(ID_ISAR6_EL1)
IDREG_START(ID_MMFR0_EL1)
- IDREG_FIELD(ID_MMFR0_EL1, RES0, 32, 32)
+ IDREG_FIELD(ID_MMFR0_EL1, RES0_32, 32, 32)
IDREG_FIELD_START(ID_MMFR0_EL1, InnerShr, 28, 4)
IDREG_FIELD_ARCH_VAL(0)
IDREG_FIELD_ARCH_VAL(1)
@@ -1696,7 +1687,7 @@ IDREG_START(ID_MMFR0_EL1)
IDREG_END(ID_MMFR0_EL1)
IDREG_START(ID_MMFR1_EL1)
- IDREG_FIELD(ID_MMFR1_EL1, RES0, 32, 32)
+ IDREG_FIELD(ID_MMFR1_EL1, RES0_32, 32, 32)
IDREG_FIELD_START(ID_MMFR1_EL1, BPred, 28, 4)
IDREG_FIELD_ARCH_VAL(0)
IDREG_FIELD_ARCH_VAL(1)
@@ -1745,7 +1736,7 @@ IDREG_START(ID_MMFR1_EL1)
IDREG_END(ID_MMFR1_EL1)
IDREG_START(ID_MMFR2_EL1)
- IDREG_FIELD(ID_MMFR2_EL1, RES0, 32, 32)
+ IDREG_FIELD(ID_MMFR2_EL1, RES0_32, 32, 32)
IDREG_FIELD_START(ID_MMFR2_EL1, HWAccFlg, 28, 4)
IDREG_FIELD_ARCH_VAL(0)
IDREG_FIELD_ARCH_VAL(1)
@@ -1784,7 +1775,7 @@ IDREG_START(ID_MMFR2_EL1)
IDREG_END(ID_MMFR2_EL1)
IDREG_START(ID_MMFR3_EL1)
- IDREG_FIELD(ID_MMFR3_EL1, RES0, 32, 32)
+ IDREG_FIELD(ID_MMFR3_EL1, RES0_32, 32, 32)
IDREG_FIELD_START(ID_MMFR3_EL1, Supersec, 28, 4)
IDREG_FIELD_ARCH_VAL(0)
IDREG_FIELD_ARCH_VAL(15)
@@ -1824,7 +1815,7 @@ IDREG_START(ID_MMFR3_EL1)
IDREG_END(ID_MMFR3_EL1)
IDREG_START(ID_MMFR4_EL1)
- IDREG_FIELD(ID_MMFR4_EL1, RES0, 32, 32)
+ IDREG_FIELD(ID_MMFR4_EL1, RES0_32, 32, 32)
IDREG_FIELD_START(ID_MMFR4_EL1, EVT, 28, 4)
IDREG_FIELD_ARCH_VAL(0)
IDREG_FIELD_ARCH_VAL(1)
@@ -1862,7 +1853,7 @@ IDREG_START(ID_MMFR4_EL1)
IDREG_END(ID_MMFR4_EL1)
IDREG_START(ID_MMFR5_EL1)
- IDREG_FIELD(ID_MMFR5_EL1, RES0, 8, 56)
+ IDREG_FIELD(ID_MMFR5_EL1, RES0_8, 8, 56)
IDREG_FIELD_START(ID_MMFR5_EL1, nTLBPA, 4, 4)
IDREG_FIELD_ARCH_VAL(0)
IDREG_FIELD_ARCH_VAL(1)
@@ -1876,7 +1867,7 @@ IDREG_START(ID_MMFR5_EL1)
IDREG_END(ID_MMFR5_EL1)
IDREG_START(ID_PFR0_EL1)
- IDREG_FIELD(ID_PFR0_EL1, RES0, 32, 32)
+ IDREG_FIELD(ID_PFR0_EL1, RES0_32, 32, 32)
IDREG_FIELD_START(ID_PFR0_EL1, RAS, 28, 4)
IDREG_FIELD_ARCH_VAL(0)
IDREG_FIELD_ARCH_VAL(1)
@@ -1918,7 +1909,7 @@ IDREG_START(ID_PFR0_EL1)
IDREG_END(ID_PFR0_EL1)
IDREG_START(ID_PFR1_EL1)
- IDREG_FIELD(ID_PFR1_EL1, RES0, 32, 32)
+ IDREG_FIELD(ID_PFR1_EL1, RES0_32, 32, 32)
IDREG_FIELD_START(ID_PFR1_EL1, GIC, 28, 4)
IDREG_FIELD_ARCH_VAL(0)
IDREG_FIELD_ARCH_VAL(1)
@@ -1958,7 +1949,7 @@ IDREG_START(ID_PFR1_EL1)
IDREG_END(ID_PFR1_EL1)
IDREG_START(ID_PFR2_EL1)
- IDREG_FIELD(ID_PFR2_EL1, RES0, 12, 52)
+ IDREG_FIELD(ID_PFR2_EL1, RES0_12, 12, 52)
IDREG_FIELD_START(ID_PFR2_EL1, RAS_frac, 8, 4)
IDREG_FIELD_ARCH_VAL(0)
IDREG_FIELD_ARCH_VAL(1)
@@ -2006,14 +1997,14 @@ IDREG_START(MIDR_EL1)
IDREG_END(MIDR_EL1)
IDREG_START(MPIDR_EL1)
- IDREG_FIELD(MPIDR_EL1, RES0, 40, 24)
+ IDREG_FIELD(MPIDR_EL1, RES0_40, 40, 24)
IDREG_FIELD(MPIDR_EL1, Aff3, 32, 8)
- IDREG_FIELD(MPIDR_EL1, RES1, 31, 1)
+ IDREG_FIELD(MPIDR_EL1, RES1_31, 31, 1)
IDREG_FIELD_START(MPIDR_EL1, U, 30, 1)
IDREG_FIELD_ARCH_VAL(0)
IDREG_FIELD_ARCH_VAL(1)
IDREG_FIELD_END(MPIDR_EL1, U)
- IDREG_FIELD(MPIDR_EL1, RES0, 25, 5)
+ IDREG_FIELD(MPIDR_EL1, RES0_25, 25, 5)
IDREG_FIELD_START(MPIDR_EL1, MT, 24, 1)
IDREG_FIELD_ARCH_VAL(0)
IDREG_FIELD_ARCH_VAL(1)
@@ -2024,7 +2015,7 @@ IDREG_START(MPIDR_EL1)
IDREG_END(MPIDR_EL1)
IDREG_START(MVFR0_EL1)
- IDREG_FIELD(MVFR0_EL1, RES0, 32, 32)
+ IDREG_FIELD(MVFR0_EL1, RES0_32, 32, 32)
IDREG_FIELD_START(MVFR0_EL1, FPRound, 28, 4)
IDREG_FIELD_ARCH_VAL(0)
IDREG_FIELD_ARCH_VAL(1)
@@ -2063,7 +2054,7 @@ IDREG_START(MVFR0_EL1)
IDREG_END(MVFR0_EL1)
IDREG_START(MVFR1_EL1)
- IDREG_FIELD(MVFR1_EL1, RES0, 32, 32)
+ IDREG_FIELD(MVFR1_EL1, RES0_32, 32, 32)
IDREG_FIELD_START(MVFR1_EL1, SIMDFMAC, 28, 4)
IDREG_FIELD_ARCH_VAL(0)
IDREG_FIELD_ARCH_VAL(1)
@@ -2102,7 +2093,7 @@ IDREG_START(MVFR1_EL1)
IDREG_END(MVFR1_EL1)
IDREG_START(MVFR2_EL1)
- IDREG_FIELD(MVFR2_EL1, RES0, 8, 56)
+ IDREG_FIELD(MVFR2_EL1, RES0_8, 8, 56)
IDREG_FIELD_START(MVFR2_EL1, FPMisc, 4, 4)
IDREG_FIELD_ARCH_VAL(0)
IDREG_FIELD_ARCH_VAL(1)
@@ -2119,17 +2110,13 @@ 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)
- IDREG_FIELD(SMIDR_EL1, RES0, 60, 4)
- IDREG_FIELD_START(SMIDR_EL1, NSMC, 56, 4)
- IDREG_FIELD_ARCH_VAL(0)
- IDREG_FIELD_ARCH_VAL(15)
- IDREG_FIELD_END(SMIDR_EL1, NSMC)
- IDREG_FIELD_START(SMIDR_EL1, HIP, 52, 4)
- IDREG_FIELD_ARCH_VAL(0)
- IDREG_FIELD_END(SMIDR_EL1, HIP)
+ IDREG_FIELD(SMIDR_EL1, RES0_60, 60, 4)
+ IDREG_FIELD(SMIDR_EL1, NSMC, 56, 4)
+ IDREG_FIELD(SMIDR_EL1, HIP, 52, 4)
IDREG_FIELD(SMIDR_EL1, Affinity2, 32, 20)
IDREG_FIELD_START(SMIDR_EL1, Implementer, 24, 8)
IDREG_FIELD_ARCH_VAL(0)
@@ -2158,7 +2145,7 @@ IDREG_START(SMIDR_EL1)
IDREG_FIELD_ARCH_VAL(2)
IDREG_FIELD_ARCH_VAL(3)
IDREG_FIELD_END(SMIDR_EL1, SH)
- IDREG_FIELD(SMIDR_EL1, RES0, 12, 1)
+ IDREG_FIELD(SMIDR_EL1, RES0_12, 12, 1)
IDREG_FIELD(SMIDR_EL1, Affinity, 0, 12)
IDREG_END(SMIDR_EL1)
--
2.52.0
^ permalink raw reply related [flat|nested] 29+ messages in thread* Re: [RFC PATCH v3 03/19] target/arm: regenerate cpu-idregs.h.inc
2026-07-16 21:38 ` [RFC PATCH v3 03/19] target/arm: regenerate cpu-idregs.h.inc Khushit Shah
@ 2026-07-20 14:39 ` Eric Auger
0 siblings, 0 replies; 29+ messages in thread
From: Eric Auger @ 2026-07-20 14:39 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,
prerna.saxena
On 7/16/26 11:38 PM, Khushit Shah wrote:
> Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
> ---
> target/arm/cpu-idregs.h.inc | 165 +++++++++++++++++-------------------
> 1 file changed, 76 insertions(+), 89 deletions(-)
>
> diff --git a/target/arm/cpu-idregs.h.inc b/target/arm/cpu-idregs.h.inc
> index 5fdc84237c..1851b37937 100644
> --- a/target/arm/cpu-idregs.h.inc
> +++ b/target/arm/cpu-idregs.h.inc
> @@ -12,23 +12,24 @@
> /* IDREG_END(REG) */
>
> IDREG_START(AIDR_EL1)
> + IDREG_FIELD(AIDR_EL1, VAL, 0, 64)
> IDREG_END(AIDR_EL1)
>
> IDREG_START(CCSIDR2_EL1)
> - IDREG_FIELD(CCSIDR2_EL1, RES0, 24, 40)
> + IDREG_FIELD(CCSIDR2_EL1, RES0_24, 24, 40)
> IDREG_FIELD(CCSIDR2_EL1, NumSets, 0, 24)
> IDREG_END(CCSIDR2_EL1)
>
> IDREG_START(CCSIDR_EL1)
> - IDREG_FIELD(CCSIDR_EL1, RES0, 56, 8)
> + IDREG_FIELD(CCSIDR_EL1, RES0_56, 56, 8)
> IDREG_FIELD(CCSIDR_EL1, NumSets, 32, 24)
> - IDREG_FIELD(CCSIDR_EL1, RES0, 24, 8)
> + IDREG_FIELD(CCSIDR_EL1, RES0_24, 24, 8)
> IDREG_FIELD(CCSIDR_EL1, Associativity, 3, 21)
> IDREG_FIELD(CCSIDR_EL1, LineSize, 0, 3)
> IDREG_END(CCSIDR_EL1)
>
> IDREG_START(CLIDR_EL1)
> - IDREG_FIELD(CLIDR_EL1, RES0, 47, 17)
> + IDREG_FIELD(CLIDR_EL1, RES0_47, 47, 17)
> IDREG_FIELD(CLIDR_EL1, Ttype7, 45, 2)
> IDREG_FIELD(CLIDR_EL1, Ttype6, 43, 2)
> IDREG_FIELD(CLIDR_EL1, Ttype5, 41, 2)
> @@ -59,10 +60,10 @@ IDREG_START(CLIDR_EL1)
> IDREG_END(CLIDR_EL1)
>
> IDREG_START(CTR_EL0)
> - IDREG_FIELD(CTR_EL0, RES0, 38, 26)
> + IDREG_FIELD(CTR_EL0, RES0_38, 38, 26)
> IDREG_FIELD(CTR_EL0, TminLine, 32, 6)
> - IDREG_FIELD(CTR_EL0, RES1, 31, 1)
> - IDREG_FIELD(CTR_EL0, RES0, 30, 1)
> + IDREG_FIELD(CTR_EL0, RES1_31, 31, 1)
> + IDREG_FIELD(CTR_EL0, RES0_30, 30, 1)
> IDREG_FIELD_START(CTR_EL0, DIC, 29, 1)
> IDREG_FIELD_ARCH_VAL(0)
> IDREG_FIELD_ARCH_VAL(1)
> @@ -80,28 +81,28 @@ IDREG_START(CTR_EL0)
> IDREG_FIELD_ARCH_VAL(2)
> IDREG_FIELD_ARCH_VAL(3)
> IDREG_FIELD_END(CTR_EL0, L1Ip)
> - IDREG_FIELD(CTR_EL0, RES0, 4, 10)
> + IDREG_FIELD(CTR_EL0, RES0_4, 4, 10)
> IDREG_FIELD(CTR_EL0, IminLine, 0, 4)
> IDREG_END(CTR_EL0)
>
> IDREG_START(DCZID_EL0)
> - IDREG_FIELD(DCZID_EL0, RES0, 9, 55)
> + IDREG_FIELD(DCZID_EL0, RES0_9, 9, 55)
> IDREG_FIELD(DCZID_EL0, TBS, 5, 4)
> IDREG_FIELD(DCZID_EL0, DZP, 4, 1)
> IDREG_FIELD(DCZID_EL0, BS, 0, 4)
> IDREG_END(DCZID_EL0)
>
> IDREG_START(GMID_EL1)
> - IDREG_FIELD(GMID_EL1, RES0, 4, 60)
> + IDREG_FIELD(GMID_EL1, RES0_4, 4, 60)
> IDREG_FIELD(GMID_EL1, BS, 0, 4)
> IDREG_END(GMID_EL1)
>
> IDREG_START(ID_AA64AFR0_EL1)
> - IDREG_FIELD(ID_AA64AFR0_EL1, RES0, 32, 32)
> + IDREG_FIELD(ID_AA64AFR0_EL1, RES0_32, 32, 32)
> IDREG_END(ID_AA64AFR0_EL1)
>
> IDREG_START(ID_AA64AFR1_EL1)
> - IDREG_FIELD(ID_AA64AFR1_EL1, RES0, 0, 64)
> + IDREG_FIELD(ID_AA64AFR1_EL1, RES0_0, 0, 64)
> IDREG_END(ID_AA64AFR1_EL1)
>
> IDREG_START(ID_AA64DFR0_EL1)
> @@ -145,18 +146,14 @@ IDREG_START(ID_AA64DFR0_EL1)
> IDREG_FIELD_ARCH_VAL(5)
> IDREG_FIELD_ARCH_VAL(6)
> IDREG_FIELD_END(ID_AA64DFR0_EL1, PMSVer)
> - IDREG_FIELD_START(ID_AA64DFR0_EL1, CTX_CMPs, 28, 4)
> - IDREG_FIELD_ARCH_VAL(15)
> - IDREG_FIELD_END(ID_AA64DFR0_EL1, CTX_CMPs)
> - IDREG_FIELD(ID_AA64DFR0_EL1, RES0, 24, 4)
> + IDREG_FIELD(ID_AA64DFR0_EL1, CTX_CMPs, 28, 4)
so it seems you remove all the ARCH values found in ValueRange (by the
way there were incomplete)
Eric
> + IDREG_FIELD(ID_AA64DFR0_EL1, RES0_24, 24, 4)
> IDREG_FIELD(ID_AA64DFR0_EL1, WRPs, 20, 4)
> IDREG_FIELD_START(ID_AA64DFR0_EL1, PMSS, 16, 4)
> IDREG_FIELD_ARCH_VAL(0)
> IDREG_FIELD_ARCH_VAL(1)
> IDREG_FIELD_END(ID_AA64DFR0_EL1, PMSS)
> - IDREG_FIELD_START(ID_AA64DFR0_EL1, BRPs, 12, 4)
> - IDREG_FIELD_ARCH_VAL(15)
> - IDREG_FIELD_END(ID_AA64DFR0_EL1, BRPs)
> + IDREG_FIELD(ID_AA64DFR0_EL1, BRPs, 12, 4)
> IDREG_FIELD_START(ID_AA64DFR0_EL1, PMUVer, 8, 4)
> IDREG_FIELD_ARCH_VAL(0)
> IDREG_FIELD_ARCH_VAL(1)
> @@ -209,20 +206,14 @@ IDREG_START(ID_AA64DFR1_EL1)
> IDREG_FIELD_ARCH_VAL(1)
> IDREG_FIELD_ARCH_VAL(2)
> IDREG_FIELD_END(ID_AA64DFR1_EL1, SPMU)
> - IDREG_FIELD_START(ID_AA64DFR1_EL1, CTX_CMPs, 24, 8)
> - IDREG_FIELD_ARCH_VAL(0)
> - IDREG_FIELD_END(ID_AA64DFR1_EL1, CTX_CMPs)
> - IDREG_FIELD_START(ID_AA64DFR1_EL1, WRPs, 16, 8)
> - IDREG_FIELD_ARCH_VAL(0)
> - IDREG_FIELD_END(ID_AA64DFR1_EL1, WRPs)
> - IDREG_FIELD_START(ID_AA64DFR1_EL1, BRPs, 8, 8)
> - IDREG_FIELD_ARCH_VAL(0)
> - IDREG_FIELD_END(ID_AA64DFR1_EL1, BRPs)
> + IDREG_FIELD(ID_AA64DFR1_EL1, CTX_CMPs, 24, 8)
> + IDREG_FIELD(ID_AA64DFR1_EL1, WRPs, 16, 8)
> + IDREG_FIELD(ID_AA64DFR1_EL1, BRPs, 8, 8)
> IDREG_FIELD(ID_AA64DFR1_EL1, SYSPMUID, 0, 8)
> IDREG_END(ID_AA64DFR1_EL1)
>
> IDREG_START(ID_AA64DFR2_EL1)
> - IDREG_FIELD(ID_AA64DFR2_EL1, RES0, 28, 36)
> + IDREG_FIELD(ID_AA64DFR2_EL1, RES0_28, 28, 36)
> IDREG_FIELD_START(ID_AA64DFR2_EL1, TRBE_EXC, 24, 4)
> IDREG_FIELD_ARCH_VAL(0)
> IDREG_FIELD_ARCH_VAL(1)
> @@ -235,7 +226,7 @@ IDREG_START(ID_AA64DFR2_EL1)
> IDREG_FIELD_ARCH_VAL(0)
> IDREG_FIELD_ARCH_VAL(1)
> IDREG_FIELD_END(ID_AA64DFR2_EL1, SPE_EXC)
> - IDREG_FIELD(ID_AA64DFR2_EL1, RES0, 8, 8)
> + IDREG_FIELD(ID_AA64DFR2_EL1, RES0_8, 8, 8)
> IDREG_FIELD_START(ID_AA64DFR2_EL1, BWE, 4, 4)
> IDREG_FIELD_ARCH_VAL(0)
> IDREG_FIELD_ARCH_VAL(1)
> @@ -248,7 +239,7 @@ IDREG_START(ID_AA64DFR2_EL1)
> IDREG_END(ID_AA64DFR2_EL1)
>
> IDREG_START(ID_AA64FPFR0_EL1)
> - IDREG_FIELD(ID_AA64FPFR0_EL1, RES0, 32, 32)
> + IDREG_FIELD(ID_AA64FPFR0_EL1, RES0_32, 32, 32)
> IDREG_FIELD_START(ID_AA64FPFR0_EL1, F8CVT, 31, 1)
> IDREG_FIELD_ARCH_VAL(0)
> IDREG_FIELD_ARCH_VAL(1)
> @@ -273,13 +264,13 @@ IDREG_START(ID_AA64FPFR0_EL1)
> IDREG_FIELD_ARCH_VAL(0)
> IDREG_FIELD_ARCH_VAL(1)
> IDREG_FIELD_END(ID_AA64FPFR0_EL1, F8MM4)
> - IDREG_FIELD(ID_AA64FPFR0_EL1, RES0, 16, 10)
> + IDREG_FIELD(ID_AA64FPFR0_EL1, RES0_16, 16, 10)
> IDREG_FIELD_START(ID_AA64FPFR0_EL1, F16MM2, 15, 1)
> IDREG_FIELD_ARCH_VAL(0)
> IDREG_FIELD_ARCH_VAL(1)
> IDREG_FIELD_END(ID_AA64FPFR0_EL1, F16MM2)
> - IDREG_FIELD(ID_AA64FPFR0_EL1, RES0, 8, 7)
> - IDREG_FIELD(ID_AA64FPFR0_EL1, RAZ, 2, 6)
> + IDREG_FIELD(ID_AA64FPFR0_EL1, RES0_8, 8, 7)
> + IDREG_FIELD(ID_AA64FPFR0_EL1, RAZ_2, 2, 6)
> IDREG_FIELD_START(ID_AA64FPFR0_EL1, F8E4M3, 1, 1)
> IDREG_FIELD_ARCH_VAL(0)
> IDREG_FIELD_ARCH_VAL(1)
> @@ -331,7 +322,7 @@ IDREG_START(ID_AA64ISAR0_EL1)
> IDREG_FIELD_ARCH_VAL(0)
> IDREG_FIELD_ARCH_VAL(1)
> IDREG_FIELD_END(ID_AA64ISAR0_EL1, RDM)
> - IDREG_FIELD(ID_AA64ISAR0_EL1, RES0, 24, 4)
> + IDREG_FIELD(ID_AA64ISAR0_EL1, RES0_24, 24, 4)
> IDREG_FIELD_START(ID_AA64ISAR0_EL1, Atomic, 20, 4)
> IDREG_FIELD_ARCH_VAL(0)
> IDREG_FIELD_ARCH_VAL(2)
> @@ -355,7 +346,7 @@ IDREG_START(ID_AA64ISAR0_EL1)
> IDREG_FIELD_ARCH_VAL(1)
> IDREG_FIELD_ARCH_VAL(2)
> IDREG_FIELD_END(ID_AA64ISAR0_EL1, AES)
> - IDREG_FIELD(ID_AA64ISAR0_EL1, RES0, 0, 4)
> + IDREG_FIELD(ID_AA64ISAR0_EL1, RES0_0, 0, 4)
> IDREG_END(ID_AA64ISAR0_EL1)
>
> IDREG_START(ID_AA64ISAR1_EL1)
> @@ -519,7 +510,7 @@ IDREG_START(ID_AA64ISAR2_EL1)
> IDREG_END(ID_AA64ISAR2_EL1)
>
> IDREG_START(ID_AA64ISAR3_EL1)
> - IDREG_FIELD(ID_AA64ISAR3_EL1, RES0, 48, 16)
> + IDREG_FIELD(ID_AA64ISAR3_EL1, RES0_48, 48, 16)
> IDREG_FIELD_START(ID_AA64ISAR3_EL1, LSCP, 44, 4)
> IDREG_FIELD_ARCH_VAL(0)
> IDREG_FIELD_ARCH_VAL(1)
> @@ -583,7 +574,7 @@ IDREG_START(ID_AA64MMFR0_EL1)
> IDREG_FIELD_ARCH_VAL(1)
> IDREG_FIELD_ARCH_VAL(2)
> IDREG_FIELD_END(ID_AA64MMFR0_EL1, FGT)
> - IDREG_FIELD(ID_AA64MMFR0_EL1, RES0, 48, 8)
> + IDREG_FIELD(ID_AA64MMFR0_EL1, RES0_48, 48, 8)
> IDREG_FIELD_START(ID_AA64MMFR0_EL1, ExS, 44, 4)
> IDREG_FIELD_ARCH_VAL(0)
> IDREG_FIELD_ARCH_VAL(1)
> @@ -736,7 +727,7 @@ IDREG_START(ID_AA64MMFR2_EL1)
> IDREG_FIELD_ARCH_VAL(0)
> IDREG_FIELD_ARCH_VAL(1)
> IDREG_FIELD_END(ID_AA64MMFR2_EL1, TTL)
> - IDREG_FIELD(ID_AA64MMFR2_EL1, RES0, 44, 4)
> + IDREG_FIELD(ID_AA64MMFR2_EL1, RES0_44, 44, 4)
> IDREG_FIELD_START(ID_AA64MMFR2_EL1, FWB, 40, 4)
> IDREG_FIELD_ARCH_VAL(0)
> IDREG_FIELD_ARCH_VAL(1)
> @@ -802,7 +793,7 @@ IDREG_START(ID_AA64MMFR3_EL1)
> IDREG_FIELD_ARCH_VAL(2)
> IDREG_FIELD_ARCH_VAL(3)
> IDREG_FIELD_END(ID_AA64MMFR3_EL1, SDERR)
> - IDREG_FIELD(ID_AA64MMFR3_EL1, RES0, 48, 4)
> + IDREG_FIELD(ID_AA64MMFR3_EL1, RES0_48, 48, 4)
> IDREG_FIELD_START(ID_AA64MMFR3_EL1, ANERR, 44, 4)
> IDREG_FIELD_ARCH_VAL(0)
> IDREG_FIELD_ARCH_VAL(1)
> @@ -1056,7 +1047,7 @@ IDREG_START(ID_AA64PFR1_EL1)
> IDREG_FIELD_ARCH_VAL(1)
> IDREG_FIELD_ARCH_VAL(2)
> IDREG_FIELD_END(ID_AA64PFR1_EL1, SME)
> - IDREG_FIELD(ID_AA64PFR1_EL1, RES0, 20, 4)
> + IDREG_FIELD(ID_AA64PFR1_EL1, RES0_20, 20, 4)
> IDREG_FIELD_START(ID_AA64PFR1_EL1, MPAM_frac, 16, 4)
> IDREG_FIELD_ARCH_VAL(0)
> IDREG_FIELD_ARCH_VAL(1)
> @@ -1084,7 +1075,7 @@ IDREG_START(ID_AA64PFR1_EL1)
> IDREG_END(ID_AA64PFR1_EL1)
>
> IDREG_START(ID_AA64PFR2_EL1)
> - IDREG_FIELD(ID_AA64PFR2_EL1, RES0, 48, 16)
> + IDREG_FIELD(ID_AA64PFR2_EL1, RES0_48, 48, 16)
> IDREG_FIELD_START(ID_AA64PFR2_EL1, VMTETCL, 44, 4)
> IDREG_FIELD_ARCH_VAL(0)
> IDREG_FIELD_ARCH_VAL(1)
> @@ -1144,7 +1135,7 @@ IDREG_START(ID_AA64SMFR0_EL1)
> IDREG_FIELD_ARCH_VAL(0)
> IDREG_FIELD_ARCH_VAL(1)
> IDREG_FIELD_END(ID_AA64SMFR0_EL1, FA64)
> - IDREG_FIELD(ID_AA64SMFR0_EL1, RES0, 62, 1)
> + IDREG_FIELD(ID_AA64SMFR0_EL1, RES0_62, 62, 1)
> IDREG_FIELD_START(ID_AA64SMFR0_EL1, LUT6, 61, 1)
> IDREG_FIELD_ARCH_VAL(0)
> IDREG_FIELD_ARCH_VAL(1)
> @@ -1164,7 +1155,7 @@ IDREG_START(ID_AA64SMFR0_EL1)
> IDREG_FIELD_ARCH_VAL(0)
> IDREG_FIELD_ARCH_VAL(15)
> IDREG_FIELD_END(ID_AA64SMFR0_EL1, I16I64)
> - IDREG_FIELD(ID_AA64SMFR0_EL1, RES0, 49, 3)
> + IDREG_FIELD(ID_AA64SMFR0_EL1, RES0_49, 49, 3)
> IDREG_FIELD_START(ID_AA64SMFR0_EL1, F64F64, 48, 1)
> IDREG_FIELD_ARCH_VAL(0)
> IDREG_FIELD_ARCH_VAL(1)
> @@ -1209,7 +1200,7 @@ IDREG_START(ID_AA64SMFR0_EL1)
> IDREG_FIELD_ARCH_VAL(0)
> IDREG_FIELD_ARCH_VAL(1)
> IDREG_FIELD_END(ID_AA64SMFR0_EL1, F32F32)
> - IDREG_FIELD(ID_AA64SMFR0_EL1, RES0, 31, 1)
> + IDREG_FIELD(ID_AA64SMFR0_EL1, RES0_31, 31, 1)
> IDREG_FIELD_START(ID_AA64SMFR0_EL1, SF8FMA, 30, 1)
> IDREG_FIELD_ARCH_VAL(0)
> IDREG_FIELD_ARCH_VAL(1)
> @@ -1222,7 +1213,7 @@ IDREG_START(ID_AA64SMFR0_EL1)
> IDREG_FIELD_ARCH_VAL(0)
> IDREG_FIELD_ARCH_VAL(1)
> IDREG_FIELD_END(ID_AA64SMFR0_EL1, SF8DP2)
> - IDREG_FIELD(ID_AA64SMFR0_EL1, RES0, 26, 2)
> + IDREG_FIELD(ID_AA64SMFR0_EL1, RES0_26, 26, 2)
> IDREG_FIELD_START(ID_AA64SMFR0_EL1, SBitPerm, 25, 1)
> IDREG_FIELD_ARCH_VAL(0)
> IDREG_FIELD_ARCH_VAL(1)
> @@ -1235,12 +1226,12 @@ IDREG_START(ID_AA64SMFR0_EL1)
> IDREG_FIELD_ARCH_VAL(0)
> IDREG_FIELD_ARCH_VAL(1)
> IDREG_FIELD_END(ID_AA64SMFR0_EL1, SFEXPA)
> - IDREG_FIELD(ID_AA64SMFR0_EL1, RES0, 17, 6)
> + IDREG_FIELD(ID_AA64SMFR0_EL1, RES0_17, 17, 6)
> IDREG_FIELD_START(ID_AA64SMFR0_EL1, STMOP, 16, 1)
> IDREG_FIELD_ARCH_VAL(0)
> IDREG_FIELD_ARCH_VAL(1)
> IDREG_FIELD_END(ID_AA64SMFR0_EL1, STMOP)
> - IDREG_FIELD(ID_AA64SMFR0_EL1, RES0, 1, 15)
> + IDREG_FIELD(ID_AA64SMFR0_EL1, RES0_1, 1, 15)
> IDREG_FIELD_START(ID_AA64SMFR0_EL1, SMOP4, 0, 1)
> IDREG_FIELD_ARCH_VAL(0)
> IDREG_FIELD_ARCH_VAL(1)
> @@ -1248,7 +1239,7 @@ IDREG_START(ID_AA64SMFR0_EL1)
> IDREG_END(ID_AA64SMFR0_EL1)
>
> IDREG_START(ID_AA64ZFR0_EL1)
> - IDREG_FIELD(ID_AA64ZFR0_EL1, RES0, 60, 4)
> + IDREG_FIELD(ID_AA64ZFR0_EL1, RES0_60, 60, 4)
> IDREG_FIELD_START(ID_AA64ZFR0_EL1, F64MM, 56, 4)
> IDREG_FIELD_ARCH_VAL(0)
> IDREG_FIELD_ARCH_VAL(1)
> @@ -1269,12 +1260,12 @@ IDREG_START(ID_AA64ZFR0_EL1)
> IDREG_FIELD_ARCH_VAL(0)
> IDREG_FIELD_ARCH_VAL(1)
> IDREG_FIELD_END(ID_AA64ZFR0_EL1, SM4)
> - IDREG_FIELD(ID_AA64ZFR0_EL1, RES0, 36, 4)
> + IDREG_FIELD(ID_AA64ZFR0_EL1, RES0_36, 36, 4)
> IDREG_FIELD_START(ID_AA64ZFR0_EL1, SHA3, 32, 4)
> IDREG_FIELD_ARCH_VAL(0)
> IDREG_FIELD_ARCH_VAL(1)
> IDREG_FIELD_END(ID_AA64ZFR0_EL1, SHA3)
> - IDREG_FIELD(ID_AA64ZFR0_EL1, RES0, 28, 4)
> + IDREG_FIELD(ID_AA64ZFR0_EL1, RES0_28, 28, 4)
> IDREG_FIELD_START(ID_AA64ZFR0_EL1, B16B16, 24, 4)
> IDREG_FIELD_ARCH_VAL(0)
> IDREG_FIELD_ARCH_VAL(1)
> @@ -1294,7 +1285,7 @@ IDREG_START(ID_AA64ZFR0_EL1)
> IDREG_FIELD_ARCH_VAL(0)
> IDREG_FIELD_ARCH_VAL(1)
> IDREG_FIELD_END(ID_AA64ZFR0_EL1, EltPerm)
> - IDREG_FIELD(ID_AA64ZFR0_EL1, RES0, 8, 4)
> + IDREG_FIELD(ID_AA64ZFR0_EL1, RES0_8, 8, 4)
> IDREG_FIELD_START(ID_AA64ZFR0_EL1, AES, 4, 4)
> IDREG_FIELD_ARCH_VAL(0)
> IDREG_FIELD_ARCH_VAL(1)
> @@ -1311,11 +1302,11 @@ IDREG_START(ID_AA64ZFR0_EL1)
> IDREG_END(ID_AA64ZFR0_EL1)
>
> IDREG_START(ID_AFR0_EL1)
> - IDREG_FIELD(ID_AFR0_EL1, RES0, 0, 64)
> + IDREG_FIELD(ID_AFR0_EL1, RES0_0, 0, 64)
> IDREG_END(ID_AFR0_EL1)
>
> IDREG_START(ID_DFR0_EL1)
> - IDREG_FIELD(ID_DFR0_EL1, RES0, 32, 32)
> + IDREG_FIELD(ID_DFR0_EL1, RES0_32, 32, 32)
> IDREG_FIELD_START(ID_DFR0_EL1, TraceFilt, 28, 4)
> IDREG_FIELD_ARCH_VAL(0)
> IDREG_FIELD_ARCH_VAL(1)
> @@ -1367,7 +1358,7 @@ IDREG_START(ID_DFR0_EL1)
> IDREG_END(ID_DFR0_EL1)
>
> IDREG_START(ID_DFR1_EL1)
> - IDREG_FIELD(ID_DFR1_EL1, RES0, 8, 56)
> + IDREG_FIELD(ID_DFR1_EL1, RES0_8, 8, 56)
> IDREG_FIELD_START(ID_DFR1_EL1, HPMN0, 4, 4)
> IDREG_FIELD_ARCH_VAL(0)
> IDREG_FIELD_ARCH_VAL(1)
> @@ -1380,7 +1371,7 @@ IDREG_START(ID_DFR1_EL1)
> IDREG_END(ID_DFR1_EL1)
>
> IDREG_START(ID_ISAR0_EL1)
> - IDREG_FIELD(ID_ISAR0_EL1, RES0, 28, 36)
> + IDREG_FIELD(ID_ISAR0_EL1, RES0_28, 28, 36)
> IDREG_FIELD_START(ID_ISAR0_EL1, Divide, 24, 4)
> IDREG_FIELD_ARCH_VAL(0)
> IDREG_FIELD_ARCH_VAL(1)
> @@ -1416,7 +1407,7 @@ IDREG_START(ID_ISAR0_EL1)
> IDREG_END(ID_ISAR0_EL1)
>
> IDREG_START(ID_ISAR1_EL1)
> - IDREG_FIELD(ID_ISAR1_EL1, RES0, 32, 32)
> + IDREG_FIELD(ID_ISAR1_EL1, RES0_32, 32, 32)
> IDREG_FIELD_START(ID_ISAR1_EL1, Jazelle, 28, 4)
> IDREG_FIELD_ARCH_VAL(0)
> IDREG_FIELD_ARCH_VAL(1)
> @@ -1455,7 +1446,7 @@ IDREG_START(ID_ISAR1_EL1)
> IDREG_END(ID_ISAR1_EL1)
>
> IDREG_START(ID_ISAR2_EL1)
> - IDREG_FIELD(ID_ISAR2_EL1, RES0, 32, 32)
> + IDREG_FIELD(ID_ISAR2_EL1, RES0_32, 32, 32)
> IDREG_FIELD_START(ID_ISAR2_EL1, Reversal, 28, 4)
> IDREG_FIELD_ARCH_VAL(0)
> IDREG_FIELD_ARCH_VAL(1)
> @@ -1501,7 +1492,7 @@ IDREG_START(ID_ISAR2_EL1)
> IDREG_END(ID_ISAR2_EL1)
>
> IDREG_START(ID_ISAR3_EL1)
> - IDREG_FIELD(ID_ISAR3_EL1, RES0, 32, 32)
> + IDREG_FIELD(ID_ISAR3_EL1, RES0_32, 32, 32)
> IDREG_FIELD_START(ID_ISAR3_EL1, T32EE, 28, 4)
> IDREG_FIELD_ARCH_VAL(0)
> IDREG_FIELD_ARCH_VAL(1)
> @@ -1539,7 +1530,7 @@ IDREG_START(ID_ISAR3_EL1)
> IDREG_END(ID_ISAR3_EL1)
>
> IDREG_START(ID_ISAR4_EL1)
> - IDREG_FIELD(ID_ISAR4_EL1, RES0, 32, 32)
> + IDREG_FIELD(ID_ISAR4_EL1, RES0_32, 32, 32)
> IDREG_FIELD_START(ID_ISAR4_EL1, SWP_frac, 28, 4)
> IDREG_FIELD_ARCH_VAL(0)
> IDREG_FIELD_ARCH_VAL(1)
> @@ -1564,12 +1555,12 @@ IDREG_START(ID_ISAR4_EL1)
> IDREG_FIELD_ARCH_VAL(0)
> IDREG_FIELD_ARCH_VAL(1)
> IDREG_FIELD_END(ID_ISAR4_EL1, Writeback)
> - IDREG_FIELD_START(ID_ISAR4_EL1, WI, 4, 4)
> + IDREG_FIELD_START(ID_ISAR4_EL1, WI_4, 4, 4)
> IDREG_FIELD_ARCH_VAL(0)
> IDREG_FIELD_ARCH_VAL(1)
> IDREG_FIELD_ARCH_VAL(3)
> IDREG_FIELD_ARCH_VAL(4)
> - IDREG_FIELD_END(ID_ISAR4_EL1, WI)
> + IDREG_FIELD_END(ID_ISAR4_EL1, WI_4)
> IDREG_FIELD_START(ID_ISAR4_EL1, Unpriv, 0, 4)
> IDREG_FIELD_ARCH_VAL(0)
> IDREG_FIELD_ARCH_VAL(1)
> @@ -1578,7 +1569,7 @@ IDREG_START(ID_ISAR4_EL1)
> IDREG_END(ID_ISAR4_EL1)
>
> IDREG_START(ID_ISAR5_EL1)
> - IDREG_FIELD(ID_ISAR5_EL1, RES0, 32, 32)
> + IDREG_FIELD(ID_ISAR5_EL1, RES0_32, 32, 32)
> IDREG_FIELD_START(ID_ISAR5_EL1, VCMA, 28, 4)
> IDREG_FIELD_ARCH_VAL(0)
> IDREG_FIELD_ARCH_VAL(1)
> @@ -1587,7 +1578,7 @@ IDREG_START(ID_ISAR5_EL1)
> IDREG_FIELD_ARCH_VAL(0)
> IDREG_FIELD_ARCH_VAL(1)
> IDREG_FIELD_END(ID_ISAR5_EL1, RDM)
> - IDREG_FIELD(ID_ISAR5_EL1, RES0, 20, 4)
> + IDREG_FIELD(ID_ISAR5_EL1, RES0_20, 20, 4)
> IDREG_FIELD_START(ID_ISAR5_EL1, CRC32, 16, 4)
> IDREG_FIELD_ARCH_VAL(0)
> IDREG_FIELD_ARCH_VAL(1)
> @@ -1612,7 +1603,7 @@ IDREG_START(ID_ISAR5_EL1)
> IDREG_END(ID_ISAR5_EL1)
>
> IDREG_START(ID_ISAR6_EL1)
> - IDREG_FIELD(ID_ISAR6_EL1, RES0, 32, 32)
> + IDREG_FIELD(ID_ISAR6_EL1, RES0_32, 32, 32)
> IDREG_FIELD_START(ID_ISAR6_EL1, CLRBHB, 28, 4)
> IDREG_FIELD_ARCH_VAL(0)
> IDREG_FIELD_ARCH_VAL(1)
> @@ -1649,7 +1640,7 @@ IDREG_START(ID_ISAR6_EL1)
> IDREG_END(ID_ISAR6_EL1)
>
> IDREG_START(ID_MMFR0_EL1)
> - IDREG_FIELD(ID_MMFR0_EL1, RES0, 32, 32)
> + IDREG_FIELD(ID_MMFR0_EL1, RES0_32, 32, 32)
> IDREG_FIELD_START(ID_MMFR0_EL1, InnerShr, 28, 4)
> IDREG_FIELD_ARCH_VAL(0)
> IDREG_FIELD_ARCH_VAL(1)
> @@ -1696,7 +1687,7 @@ IDREG_START(ID_MMFR0_EL1)
> IDREG_END(ID_MMFR0_EL1)
>
> IDREG_START(ID_MMFR1_EL1)
> - IDREG_FIELD(ID_MMFR1_EL1, RES0, 32, 32)
> + IDREG_FIELD(ID_MMFR1_EL1, RES0_32, 32, 32)
> IDREG_FIELD_START(ID_MMFR1_EL1, BPred, 28, 4)
> IDREG_FIELD_ARCH_VAL(0)
> IDREG_FIELD_ARCH_VAL(1)
> @@ -1745,7 +1736,7 @@ IDREG_START(ID_MMFR1_EL1)
> IDREG_END(ID_MMFR1_EL1)
>
> IDREG_START(ID_MMFR2_EL1)
> - IDREG_FIELD(ID_MMFR2_EL1, RES0, 32, 32)
> + IDREG_FIELD(ID_MMFR2_EL1, RES0_32, 32, 32)
> IDREG_FIELD_START(ID_MMFR2_EL1, HWAccFlg, 28, 4)
> IDREG_FIELD_ARCH_VAL(0)
> IDREG_FIELD_ARCH_VAL(1)
> @@ -1784,7 +1775,7 @@ IDREG_START(ID_MMFR2_EL1)
> IDREG_END(ID_MMFR2_EL1)
>
> IDREG_START(ID_MMFR3_EL1)
> - IDREG_FIELD(ID_MMFR3_EL1, RES0, 32, 32)
> + IDREG_FIELD(ID_MMFR3_EL1, RES0_32, 32, 32)
> IDREG_FIELD_START(ID_MMFR3_EL1, Supersec, 28, 4)
> IDREG_FIELD_ARCH_VAL(0)
> IDREG_FIELD_ARCH_VAL(15)
> @@ -1824,7 +1815,7 @@ IDREG_START(ID_MMFR3_EL1)
> IDREG_END(ID_MMFR3_EL1)
>
> IDREG_START(ID_MMFR4_EL1)
> - IDREG_FIELD(ID_MMFR4_EL1, RES0, 32, 32)
> + IDREG_FIELD(ID_MMFR4_EL1, RES0_32, 32, 32)
> IDREG_FIELD_START(ID_MMFR4_EL1, EVT, 28, 4)
> IDREG_FIELD_ARCH_VAL(0)
> IDREG_FIELD_ARCH_VAL(1)
> @@ -1862,7 +1853,7 @@ IDREG_START(ID_MMFR4_EL1)
> IDREG_END(ID_MMFR4_EL1)
>
> IDREG_START(ID_MMFR5_EL1)
> - IDREG_FIELD(ID_MMFR5_EL1, RES0, 8, 56)
> + IDREG_FIELD(ID_MMFR5_EL1, RES0_8, 8, 56)
> IDREG_FIELD_START(ID_MMFR5_EL1, nTLBPA, 4, 4)
> IDREG_FIELD_ARCH_VAL(0)
> IDREG_FIELD_ARCH_VAL(1)
> @@ -1876,7 +1867,7 @@ IDREG_START(ID_MMFR5_EL1)
> IDREG_END(ID_MMFR5_EL1)
>
> IDREG_START(ID_PFR0_EL1)
> - IDREG_FIELD(ID_PFR0_EL1, RES0, 32, 32)
> + IDREG_FIELD(ID_PFR0_EL1, RES0_32, 32, 32)
> IDREG_FIELD_START(ID_PFR0_EL1, RAS, 28, 4)
> IDREG_FIELD_ARCH_VAL(0)
> IDREG_FIELD_ARCH_VAL(1)
> @@ -1918,7 +1909,7 @@ IDREG_START(ID_PFR0_EL1)
> IDREG_END(ID_PFR0_EL1)
>
> IDREG_START(ID_PFR1_EL1)
> - IDREG_FIELD(ID_PFR1_EL1, RES0, 32, 32)
> + IDREG_FIELD(ID_PFR1_EL1, RES0_32, 32, 32)
> IDREG_FIELD_START(ID_PFR1_EL1, GIC, 28, 4)
> IDREG_FIELD_ARCH_VAL(0)
> IDREG_FIELD_ARCH_VAL(1)
> @@ -1958,7 +1949,7 @@ IDREG_START(ID_PFR1_EL1)
> IDREG_END(ID_PFR1_EL1)
>
> IDREG_START(ID_PFR2_EL1)
> - IDREG_FIELD(ID_PFR2_EL1, RES0, 12, 52)
> + IDREG_FIELD(ID_PFR2_EL1, RES0_12, 12, 52)
> IDREG_FIELD_START(ID_PFR2_EL1, RAS_frac, 8, 4)
> IDREG_FIELD_ARCH_VAL(0)
> IDREG_FIELD_ARCH_VAL(1)
> @@ -2006,14 +1997,14 @@ IDREG_START(MIDR_EL1)
> IDREG_END(MIDR_EL1)
>
> IDREG_START(MPIDR_EL1)
> - IDREG_FIELD(MPIDR_EL1, RES0, 40, 24)
> + IDREG_FIELD(MPIDR_EL1, RES0_40, 40, 24)
> IDREG_FIELD(MPIDR_EL1, Aff3, 32, 8)
> - IDREG_FIELD(MPIDR_EL1, RES1, 31, 1)
> + IDREG_FIELD(MPIDR_EL1, RES1_31, 31, 1)
> IDREG_FIELD_START(MPIDR_EL1, U, 30, 1)
> IDREG_FIELD_ARCH_VAL(0)
> IDREG_FIELD_ARCH_VAL(1)
> IDREG_FIELD_END(MPIDR_EL1, U)
> - IDREG_FIELD(MPIDR_EL1, RES0, 25, 5)
> + IDREG_FIELD(MPIDR_EL1, RES0_25, 25, 5)
> IDREG_FIELD_START(MPIDR_EL1, MT, 24, 1)
> IDREG_FIELD_ARCH_VAL(0)
> IDREG_FIELD_ARCH_VAL(1)
> @@ -2024,7 +2015,7 @@ IDREG_START(MPIDR_EL1)
> IDREG_END(MPIDR_EL1)
>
> IDREG_START(MVFR0_EL1)
> - IDREG_FIELD(MVFR0_EL1, RES0, 32, 32)
> + IDREG_FIELD(MVFR0_EL1, RES0_32, 32, 32)
> IDREG_FIELD_START(MVFR0_EL1, FPRound, 28, 4)
> IDREG_FIELD_ARCH_VAL(0)
> IDREG_FIELD_ARCH_VAL(1)
> @@ -2063,7 +2054,7 @@ IDREG_START(MVFR0_EL1)
> IDREG_END(MVFR0_EL1)
>
> IDREG_START(MVFR1_EL1)
> - IDREG_FIELD(MVFR1_EL1, RES0, 32, 32)
> + IDREG_FIELD(MVFR1_EL1, RES0_32, 32, 32)
> IDREG_FIELD_START(MVFR1_EL1, SIMDFMAC, 28, 4)
> IDREG_FIELD_ARCH_VAL(0)
> IDREG_FIELD_ARCH_VAL(1)
> @@ -2102,7 +2093,7 @@ IDREG_START(MVFR1_EL1)
> IDREG_END(MVFR1_EL1)
>
> IDREG_START(MVFR2_EL1)
> - IDREG_FIELD(MVFR2_EL1, RES0, 8, 56)
> + IDREG_FIELD(MVFR2_EL1, RES0_8, 8, 56)
> IDREG_FIELD_START(MVFR2_EL1, FPMisc, 4, 4)
> IDREG_FIELD_ARCH_VAL(0)
> IDREG_FIELD_ARCH_VAL(1)
> @@ -2119,17 +2110,13 @@ 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)
> - IDREG_FIELD(SMIDR_EL1, RES0, 60, 4)
> - IDREG_FIELD_START(SMIDR_EL1, NSMC, 56, 4)
> - IDREG_FIELD_ARCH_VAL(0)
> - IDREG_FIELD_ARCH_VAL(15)
> - IDREG_FIELD_END(SMIDR_EL1, NSMC)
> - IDREG_FIELD_START(SMIDR_EL1, HIP, 52, 4)
> - IDREG_FIELD_ARCH_VAL(0)
> - IDREG_FIELD_END(SMIDR_EL1, HIP)
> + IDREG_FIELD(SMIDR_EL1, RES0_60, 60, 4)
> + IDREG_FIELD(SMIDR_EL1, NSMC, 56, 4)
> + IDREG_FIELD(SMIDR_EL1, HIP, 52, 4)
so this looks wrong to me. I fixed that in v7
> IDREG_FIELD(SMIDR_EL1, Affinity2, 32, 20)
> IDREG_FIELD_START(SMIDR_EL1, Implementer, 24, 8)
> IDREG_FIELD_ARCH_VAL(0)
> @@ -2158,7 +2145,7 @@ IDREG_START(SMIDR_EL1)
> IDREG_FIELD_ARCH_VAL(2)
> IDREG_FIELD_ARCH_VAL(3)
> IDREG_FIELD_END(SMIDR_EL1, SH)
> - IDREG_FIELD(SMIDR_EL1, RES0, 12, 1)
> + IDREG_FIELD(SMIDR_EL1, RES0_12, 12, 1)
> IDREG_FIELD(SMIDR_EL1, Affinity, 0, 12)
> IDREG_END(SMIDR_EL1)
>
^ permalink raw reply [flat|nested] 29+ messages in thread
* [RFC PATCH v3 04/19] target/arm: expose all ID regs fields as properties
2026-07-16 21:38 [RFC PATCH v3 00/19] named CPU models for Arm64 on KVM Khushit Shah
` (2 preceding siblings ...)
2026-07-16 21:38 ` [RFC PATCH v3 03/19] target/arm: regenerate cpu-idregs.h.inc Khushit Shah
@ 2026-07-16 21:38 ` Khushit Shah
2026-07-21 14:44 ` Eric Auger
2026-07-16 21:38 ` [RFC PATCH v3 05/19] target/arm/kvm: enable writable implementation ID registers Khushit Shah
` (14 subsequent siblings)
18 siblings, 1 reply; 29+ messages in thread
From: Khushit Shah @ 2026-07-16 21:38 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, prerna.saxena
Upcoming named cpu models layer requires exposing all the ID register
fields as properties.
While doing so also move the code to cpu64.c to make it
accelerator-agnostic, and rename the function to
`aarch64_add_idregs_properties()`.
This makes porting this solution to other accelerators easy in future.
Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
---
target/arm/cpu64.c | 116 +++++++++++++++++++++++++++++-
target/arm/internals.h | 3 +
target/arm/kvm.c | 151 ----------------------------------------
target/arm/kvm_arm.h | 8 ---
target/arm/trace-events | 4 +-
5 files changed, 119 insertions(+), 163 deletions(-)
diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
index 92a01d4ce7..cdad0fc46d 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,113 @@ 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 > ((1ULL << 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].value) {
+ goto valid;
+ }
+ }
+ error_setg(errp,
+ "idreg %s set value (0x%lx) does not match any "
+ "arch valid enum value!", name, value);
+ return;
+ }
+
+ /* If the field is RESx or RAZ, it should not be written anything else */
+ if (strstr(field->name, "RES0") && value != 0) {
+ error_setg(errp, "idreg %s is RES0 field and cannot write %ld",
+ name, value);
+ return;
+ } else if (strstr(field->name, "RAZ") && value != 0) {
+ error_setg(errp, "idreg %s is RAZ field and cannot write %ld",
+ name, value);
+ return;
+ } else if (strstr(field->name, "RES1") && value != 1) {
+ error_setg(errp, "idreg %s is RES1 field and cannot write %ld",
+ 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 int
+aarch64_add_idreg_properties(Object *obj, ARM64SysReg *reg)
+{
+ int nb_sysreg_props = 0;
+
+ for (int i = 0; i < reg->fields_count; i++) {
+ ARM64SysRegField *field = ®->fields[i];
+ 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);
+ return 0;
+}
+
+void aarch64_add_idregs_properties(Object *obj)
+{
+ for (int i = 0; i < NUM_ID_IDX; i++) {
+ ARM64SysReg *reg = &arm64_id_regs[i];
+ aarch64_add_idreg_properties(obj, reg);
+ }
+}
+#endif
+
void aarch64_add_pauth_properties(Object *obj)
{
ARMCPU *cpu = ARM_CPU(obj);
@@ -865,8 +973,12 @@ static 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 */
- kvm_arm_expose_idreg_properties(cpu, arm64_id_regs);
+#ifndef CONFIG_USER_ONLY
+ /* generate SYSREG properties */
+ if (kvm_enabled()) {
+ aarch64_add_idregs_properties(obj);
+ }
+#endif
#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 a632584a4e..7502b6db8a 100644
--- a/target/arm/internals.h
+++ b/target/arm/internals.h
@@ -1754,6 +1754,9 @@ 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);
+#ifndef CONFIG_USER_ONLY
+void aarch64_add_idregs_properties(Object *obj);
+#endif
/* Return true if the gdbstub is presenting an AArch64 CPU */
static inline bool arm_gdbstub_is_aarch64(ARMCPU *cpu)
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index 892433a612..76583db3f0 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -327,157 +327,6 @@ static int get_host_cpu_idregs(ARMCPU *cpu, 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;
-}
-
-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].value) {
- 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);
-}
-
-/*
- * 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)
-{
- 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);
- warn_report("%s is target/arm/cpu-idregs.h.inc up-to-date?", __func__);
- 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);
- continue;
- }
- prop_name = g_strdup_printf("SYSREG_%s_%s", reg->name, field->name);
- trace_decode_idreg_writemap(field->name, lower, upper, prop_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) {
- /*
- * 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);
- }
- }
- }
-}
static void
kvm_arm_get_host_cpu_features(ARMCPU *cpu, ARMHostCPUFeatures *ahcf)
diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h
index 2b3474cc36..133a026036 100644
--- a/target/arm/kvm_arm.h
+++ b/target/arm/kvm_arm.h
@@ -143,14 +143,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:
diff --git a/target/arm/trace-events b/target/arm/trace-events
index e67730de6b..f33b0d821d 100644
--- a/target/arm/trace-events
+++ b/target/arm/trace-events
@@ -15,11 +15,11 @@ 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)"
+
+# 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"
-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 ..."
# cpu.c
arm_cpu_reset(uint64_t mp_aff) "cpu %" PRIu64
--
2.52.0
^ permalink raw reply related [flat|nested] 29+ messages in thread* Re: [RFC PATCH v3 04/19] target/arm: expose all ID regs fields as properties
2026-07-16 21:38 ` [RFC PATCH v3 04/19] target/arm: expose all ID regs fields as properties Khushit Shah
@ 2026-07-21 14:44 ` Eric Auger
0 siblings, 0 replies; 29+ messages in thread
From: Eric Auger @ 2026-07-21 14:44 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,
prerna.saxena
Hi Khushit,
On 7/16/26 11:38 PM, Khushit Shah wrote:
> Upcoming named cpu models layer requires exposing all the ID register
> fields as properties.
>
> While doing so also move the code to cpu64.c to make it
> accelerator-agnostic, and rename the function to
> `aarch64_add_idregs_properties()`.
Better to split that patch into 2 to ease the review:
1) update the code in kvm to expose all ID regs including those which
are not writable and adaptation in set_sysreg_prop to handle RAZ,
RES0/1, ...
2) Move to cpu64.c
To me it is still arguable whether it makes sense to expose settings
which cannot be really set. To me It pollutes the qmp introspection
output and I don't know whether there is any case history.
Why can't we:
- only expose writable id regs as props
- other non writable settings you need to check could be registered in a
hash table during named cpu model definition in props.
in arm_apply_model_props() when you enumerate all props you can check if
there is an existing prop for this name, in which case you really call
object_property_set_bool(), otherwise, you go through another path, which is not visible by the end user where you check the KVM value matches your "prop" value. No need to pretend this is writable.
Also I am doubtful about RES/RAZ.
+ MODEL_PROP("SYSREG_CTR_EL0_RES1_31", NUM, 1),
does not make sense to me
Why can't you enumate all ID regs and go through those fields and check the KVM value matches. Why would we need to explicitly set a RAS/RES0/1 field. Why can't that be checked transparently.
Thanks
Eric
>
> This makes porting this solution to other accelerators easy in future.
>
> Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
> ---
> target/arm/cpu64.c | 116 +++++++++++++++++++++++++++++-
> target/arm/internals.h | 3 +
> target/arm/kvm.c | 151 ----------------------------------------
> target/arm/kvm_arm.h | 8 ---
> target/arm/trace-events | 4 +-
> 5 files changed, 119 insertions(+), 163 deletions(-)
>
> diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
> index 92a01d4ce7..cdad0fc46d 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,113 @@ 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 > ((1ULL << 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].value) {
> + goto valid;
> + }
> + }
> + error_setg(errp,
> + "idreg %s set value (0x%lx) does not match any "
> + "arch valid enum value!", name, value);
> + return;
> + }
> +
> + /* If the field is RESx or RAZ, it should not be written anything else */
> + if (strstr(field->name, "RES0") && value != 0) {
> + error_setg(errp, "idreg %s is RES0 field and cannot write %ld",
> + name, value);
> + return;
> + } else if (strstr(field->name, "RAZ") && value != 0) {
> + error_setg(errp, "idreg %s is RAZ field and cannot write %ld",
> + name, value);
> + return;
> + } else if (strstr(field->name, "RES1") && value != 1) {
> + error_setg(errp, "idreg %s is RES1 field and cannot write %ld",
> + 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 int
> +aarch64_add_idreg_properties(Object *obj, ARM64SysReg *reg)
> +{
> + int nb_sysreg_props = 0;
> +
> + for (int i = 0; i < reg->fields_count; i++) {
> + ARM64SysRegField *field = ®->fields[i];
> + 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);
> + return 0;
> +}
> +
> +void aarch64_add_idregs_properties(Object *obj)
> +{
> + for (int i = 0; i < NUM_ID_IDX; i++) {
> + ARM64SysReg *reg = &arm64_id_regs[i];
> + aarch64_add_idreg_properties(obj, reg);
> + }
> +}
> +#endif
> +
> void aarch64_add_pauth_properties(Object *obj)
> {
> ARMCPU *cpu = ARM_CPU(obj);
> @@ -865,8 +973,12 @@ static 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 */
> - kvm_arm_expose_idreg_properties(cpu, arm64_id_regs);
> +#ifndef CONFIG_USER_ONLY
> + /* generate SYSREG properties */
> + if (kvm_enabled()) {
> + aarch64_add_idregs_properties(obj);
> + }
> +#endif
>
> #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 a632584a4e..7502b6db8a 100644
> --- a/target/arm/internals.h
> +++ b/target/arm/internals.h
> @@ -1754,6 +1754,9 @@ 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);
> +#ifndef CONFIG_USER_ONLY
> +void aarch64_add_idregs_properties(Object *obj);
> +#endif
>
> /* Return true if the gdbstub is presenting an AArch64 CPU */
> static inline bool arm_gdbstub_is_aarch64(ARMCPU *cpu)
> diff --git a/target/arm/kvm.c b/target/arm/kvm.c
> index 892433a612..76583db3f0 100644
> --- a/target/arm/kvm.c
> +++ b/target/arm/kvm.c
> @@ -327,157 +327,6 @@ static int get_host_cpu_idregs(ARMCPU *cpu, 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;
> -}
> -
> -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].value) {
> - 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);
> -}
> -
> -/*
> - * 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)
> -{
> - 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);
> - warn_report("%s is target/arm/cpu-idregs.h.inc up-to-date?", __func__);
> - 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);
> - continue;
> - }
> - prop_name = g_strdup_printf("SYSREG_%s_%s", reg->name, field->name);
> - trace_decode_idreg_writemap(field->name, lower, upper, prop_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) {
> - /*
> - * 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);
> - }
> - }
> - }
> -}
>
> static void
> kvm_arm_get_host_cpu_features(ARMCPU *cpu, ARMHostCPUFeatures *ahcf)
> diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h
> index 2b3474cc36..133a026036 100644
> --- a/target/arm/kvm_arm.h
> +++ b/target/arm/kvm_arm.h
> @@ -143,14 +143,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:
> diff --git a/target/arm/trace-events b/target/arm/trace-events
> index e67730de6b..f33b0d821d 100644
> --- a/target/arm/trace-events
> +++ b/target/arm/trace-events
> @@ -15,11 +15,11 @@ 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)"
> +
> +# 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"
> -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 ..."
>
> # cpu.c
> arm_cpu_reset(uint64_t mp_aff) "cpu %" PRIu64
^ permalink raw reply [flat|nested] 29+ messages in thread
* [RFC PATCH v3 05/19] target/arm/kvm: enable writable implementation ID registers
2026-07-16 21:38 [RFC PATCH v3 00/19] named CPU models for Arm64 on KVM Khushit Shah
` (3 preceding siblings ...)
2026-07-16 21:38 ` [RFC PATCH v3 04/19] target/arm: expose all ID regs fields as properties Khushit Shah
@ 2026-07-16 21:38 ` Khushit Shah
2026-07-21 15:03 ` Eric Auger
2026-07-16 21:38 ` [RFC PATCH v3 06/19] target/arm/kvm: Read all ID registers from KVM Khushit Shah
` (13 subsequent siblings)
18 siblings, 1 reply; 29+ messages in thread
From: Khushit Shah @ 2026-07-16 21:38 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, prerna.saxena
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 correct values to the
guest instead of inheriting the host's identity.
Signed-off-by: Khushit Shah <khushit.shah@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 76583db3f0..63b3727e05 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -741,6 +741,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] 29+ messages in thread* Re: [RFC PATCH v3 05/19] target/arm/kvm: enable writable implementation ID registers
2026-07-16 21:38 ` [RFC PATCH v3 05/19] target/arm/kvm: enable writable implementation ID registers Khushit Shah
@ 2026-07-21 15:03 ` Eric Auger
0 siblings, 0 replies; 29+ messages in thread
From: Eric Auger @ 2026-07-21 15:03 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,
prerna.saxena
Hi Khushit,
On 7/16/26 11:38 PM, Khushit Shah wrote:
> 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 correct values to the
> guest instead of inheriting the host's identity.
This is a subset of
[RFC PATCH RESEND 0/4] hw/arm/virt: Add support for Target
Implementation CPUs
https://lore.kernel.org/all/20250801074730.28329-1-shameerkolothum@gmail.com/
and especially 1/4
Thanks
Eric
>
> Signed-off-by: Khushit Shah <khushit.shah@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 76583db3f0..63b3727e05 100644
> --- a/target/arm/kvm.c
> +++ b/target/arm/kvm.c
> @@ -741,6 +741,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;
>
^ permalink raw reply [flat|nested] 29+ messages in thread
* [RFC PATCH v3 06/19] target/arm/kvm: Read all ID registers from KVM
2026-07-16 21:38 [RFC PATCH v3 00/19] named CPU models for Arm64 on KVM Khushit Shah
` (4 preceding siblings ...)
2026-07-16 21:38 ` [RFC PATCH v3 05/19] target/arm/kvm: enable writable implementation ID registers Khushit Shah
@ 2026-07-16 21:38 ` Khushit Shah
2026-07-22 6:54 ` Eric Auger
2026-07-16 21:38 ` [RFC PATCH v3 07/19] target/arm/kvm: handle special ID registers cases when reading " Khushit Shah
` (12 subsequent siblings)
18 siblings, 1 reply; 29+ messages in thread
From: Khushit Shah @ 2026-07-16 21:38 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, prerna.saxena
Try to read all the ID registers from KVM. KVM may return ENOENT, for
ID registers it does not support reading from userspace. Ignore those
registers. As this list is small, in future we may anyway want to
handle those register specially.
We want to do this so that we can expose more or less complete
host feature view to management stack, as for migration, we want both
writable and non-writable ID registers to match.
Also remove the unused 'cpu' args throughout the call-chain.
Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
---
target/arm/kvm.c | 38 +++++++++++++++++++-------------------
1 file changed, 19 insertions(+), 19 deletions(-)
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index 63b3727e05..42ff731f6e 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -292,14 +292,14 @@ 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(ARMCPU *cpu, int fd, ARMHostCPUFeatures *ahcf)
+static int get_host_cpu_idregs(int fd, ARMHostCPUFeatures *ahcf)
{
int err = 0;
int i;
@@ -310,26 +310,26 @@ static int get_host_cpu_idregs(ARMCPU *cpu, 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) {
+ warn_report("%s error reading value of host %s register "
+ "(ENOENT)", __func__, 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;
}
static void
-kvm_arm_get_host_cpu_features(ARMCPU *cpu, ARMHostCPUFeatures *ahcf)
+kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
{
/* Identify the feature bits corresponding to the host CPU, and
* fill out the ARMHostCPUClass fields accordingly. To do this
@@ -415,8 +415,8 @@ kvm_arm_get_host_cpu_features(ARMCPU *cpu, 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 */
- err |= get_host_cpu_idregs(cpu, fd, ahcf);
+ /* Try to read all the ID registers */
+ err |= get_host_cpu_idregs(fd, ahcf);
/*
* temporarily override the CLIDR_EL1 value since some host values
@@ -595,7 +595,7 @@ void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu)
g_free(writable_map);
if (!arm_host_cpu_features.dtb_compatible) {
- kvm_arm_get_host_cpu_features(cpu, &arm_host_cpu_features);
+ kvm_arm_get_host_cpu_features(&arm_host_cpu_features);
}
cpu->kvm_target = arm_host_cpu_features.target;
--
2.52.0
^ permalink raw reply related [flat|nested] 29+ messages in thread* Re: [RFC PATCH v3 06/19] target/arm/kvm: Read all ID registers from KVM
2026-07-16 21:38 ` [RFC PATCH v3 06/19] target/arm/kvm: Read all ID registers from KVM Khushit Shah
@ 2026-07-22 6:54 ` Eric Auger
0 siblings, 0 replies; 29+ messages in thread
From: Eric Auger @ 2026-07-22 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,
prerna.saxena
On 7/16/26 11:38 PM, Khushit Shah wrote:
> Try to read all the ID registers from KVM. KVM may return ENOENT, for
> ID registers it does not support reading from userspace. Ignore those
> registers. As this list is small, in future we may anyway want to
> handle those register specially.
>
> We want to do this so that we can expose more or less complete
> host feature view to management stack, as for migration, we want both
> writable and non-writable ID registers to match.
>
> Also remove the unused 'cpu' args throughout the call-chain.
I will integrate this fix in the parent series
>
> Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
> ---
> target/arm/kvm.c | 38 +++++++++++++++++++-------------------
> 1 file changed, 19 insertions(+), 19 deletions(-)
>
> diff --git a/target/arm/kvm.c b/target/arm/kvm.c
> index 63b3727e05..42ff731f6e 100644
> --- a/target/arm/kvm.c
> +++ b/target/arm/kvm.c
> @@ -292,14 +292,14 @@ 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(ARMCPU *cpu, int fd, ARMHostCPUFeatures *ahcf)
> +static int get_host_cpu_idregs(int fd, ARMHostCPUFeatures *ahcf)
> {
> int err = 0;
> int i;
> @@ -310,26 +310,26 @@ static int get_host_cpu_idregs(ARMCPU *cpu, 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) {
> + warn_report("%s error reading value of host %s register "
> + "(ENOENT)", __func__, sysregdesc->name);
if there are expected cases where the read is failing I don't think we
want to warn. Add a trace point instead.
> + } 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;
> }
>
>
> static void
> -kvm_arm_get_host_cpu_features(ARMCPU *cpu, ARMHostCPUFeatures *ahcf)
> +kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
> {
> /* Identify the feature bits corresponding to the host CPU, and
> * fill out the ARMHostCPUClass fields accordingly. To do this
> @@ -415,8 +415,8 @@ kvm_arm_get_host_cpu_features(ARMCPU *cpu, 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 */
> - err |= get_host_cpu_idregs(cpu, fd, ahcf);
> + /* Try to read all the ID registers */
> + err |= get_host_cpu_idregs(fd, ahcf);
>
> /*
> * temporarily override the CLIDR_EL1 value since some host values
> @@ -595,7 +595,7 @@ void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu)
> g_free(writable_map);
>
> if (!arm_host_cpu_features.dtb_compatible) {
> - kvm_arm_get_host_cpu_features(cpu, &arm_host_cpu_features);
> + kvm_arm_get_host_cpu_features(&arm_host_cpu_features);
> }
>
> cpu->kvm_target = arm_host_cpu_features.target;
Thanks
Eric
^ permalink raw reply [flat|nested] 29+ messages in thread
* [RFC PATCH v3 07/19] target/arm/kvm: handle special ID registers cases when reading from KVM
2026-07-16 21:38 [RFC PATCH v3 00/19] named CPU models for Arm64 on KVM Khushit Shah
` (5 preceding siblings ...)
2026-07-16 21:38 ` [RFC PATCH v3 06/19] target/arm/kvm: Read all ID registers from KVM Khushit Shah
@ 2026-07-16 21:38 ` Khushit Shah
2026-07-22 12:32 ` Eric Auger
2026-07-16 21:38 ` [RFC PATCH v3 08/19] target/arm/kvm: Handle writeback for special ID register fields Khushit Shah
` (11 subsequent siblings)
18 siblings, 1 reply; 29+ messages in thread
From: Khushit Shah @ 2026-07-16 21:38 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, prerna.saxena
The generic KVM_GET_ONE_REG loop cannot correctly read a handful of
ID registers, so specially handle those:
- DCZID_EL0: No fine grain trap exists, hence not tracked by KVM.
It is EL0-readable and untrapped, so read it directly with MRS.
- CCSIDR_EL1/CCSIDR2_EL1: not plain ID registers, their value is
selected by CSSELR_EL1. KVM only exposes them via the DEMUX API
(KVM_REG_ARM_DEMUX_ID_CCSIDR), so there is no single value to read
here. Skip them.
- SMIDR_EL1: KVM does not support SME, so there is no meaningful host
value. Skip it.
- GMID_EL1: not in KVM's sys_reg_descs[] and, being an EL1 register,
cannot be read from userspace via MRS 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 | 53 ++++++++++++++++++++++++++++++++++++++++--------
1 file changed, 44 insertions(+), 9 deletions(-)
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index 42ff731f6e..6974e5c551 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -311,15 +311,50 @@ 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) {
- warn_report("%s error reading value of host %s register "
- "(ENOENT)", __func__, 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 doesn't trap guest reads of it.
+ */
+ asm volatile("mrs %0, DCZID_EL0" : "=r" (*reg));
+ break;
+ case CCSIDR_EL1_IDX:
+ case CCSIDR2_EL1_IDX:
+ /*
+ * CCSIDR_EL1 is not a plain ID register: the value it
+ * returns is selected by CSSELR_EL1, so there is no single
+ * value to capture here. It is exposed to userspace only via
+ * the DEMUX API (KVM_REG_ARM_DEMUX_ID_CCSIDR), indexed by
+ * CSSELR. Skip reading it here as there is no meaningful host
+ * value to read.
+ */
+ 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) {
+ warn_report("%s error reading value of host %s register "
+ "(ENOENT)", __func__, 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] 29+ messages in thread* Re: [RFC PATCH v3 07/19] target/arm/kvm: handle special ID registers cases when reading from KVM
2026-07-16 21:38 ` [RFC PATCH v3 07/19] target/arm/kvm: handle special ID registers cases when reading " Khushit Shah
@ 2026-07-22 12:32 ` Eric Auger
0 siblings, 0 replies; 29+ messages in thread
From: Eric Auger @ 2026-07-22 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,
prerna.saxena
Hi Khushit,
On 7/16/26 11:38 PM, Khushit Shah wrote:
> The generic KVM_GET_ONE_REG loop cannot correctly read a handful of
> ID registers, so specially handle those:
>
> - DCZID_EL0: No fine grain trap exists, hence not tracked by KVM.
> It is EL0-readable and untrapped, so read it directly with MRS.
>
> - CCSIDR_EL1/CCSIDR2_EL1: not plain ID registers, their value is
> selected by CSSELR_EL1. KVM only exposes them via the DEMUX API
> (KVM_REG_ARM_DEMUX_ID_CCSIDR), so there is no single value to read
> here. Skip them.
>
> - SMIDR_EL1: KVM does not support SME, so there is no meaningful host
> value. Skip it.
>
> - GMID_EL1: not in KVM's sys_reg_descs[] and, being an EL1 register,
> cannot be read from userspace via MRS 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 | 53 ++++++++++++++++++++++++++++++++++++++++--------
> 1 file changed, 44 insertions(+), 9 deletions(-)
>
> diff --git a/target/arm/kvm.c b/target/arm/kvm.c
> index 42ff731f6e..6974e5c551 100644
> --- a/target/arm/kvm.c
> +++ b/target/arm/kvm.c
> @@ -311,15 +311,50 @@ 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) {
> - warn_report("%s error reading value of host %s register "
> - "(ENOENT)", __func__, 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 doesn't trap guest reads of it.
> + */
> + asm volatile("mrs %0, DCZID_EL0" : "=r" (*reg));
> + break;
> + case CCSIDR_EL1_IDX:
> + case CCSIDR2_EL1_IDX:
> + /*
> + * CCSIDR_EL1 is not a plain ID register: the value it
> + * returns is selected by CSSELR_EL1, so there is no single
> + * value to capture here. It is exposed to userspace only via
> + * the DEMUX API (KVM_REG_ARM_DEMUX_ID_CCSIDR), indexed by
> + * CSSELR. Skip reading it here as there is no meaningful host
> + * value to read.
> + */
I think you should rely on prerequisite
[PATCH v4 3/3] arm/kvm: get demuxed ID registers from kvm
> + 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) {
> + warn_report("%s error reading value of host %s register "
> + "(ENOENT)", __func__, sysregdesc->name);
trace point
> + } 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);
Thanks
Eric
^ permalink raw reply [flat|nested] 29+ messages in thread
* [RFC PATCH v3 08/19] target/arm/kvm: Handle writeback for special ID register fields
2026-07-16 21:38 [RFC PATCH v3 00/19] named CPU models for Arm64 on KVM Khushit Shah
` (6 preceding siblings ...)
2026-07-16 21:38 ` [RFC PATCH v3 07/19] target/arm/kvm: handle special ID registers cases when reading " Khushit Shah
@ 2026-07-16 21:38 ` Khushit Shah
2026-07-22 12:05 ` Eric Auger
2026-07-16 21:38 ` [RFC PATCH v3 09/19] target/arm: Add named cpu model infra + graviton3 named model Khushit Shah
` (10 subsequent siblings)
18 siblings, 1 reply; 29+ messages in thread
From: Khushit Shah @ 2026-07-16 21:38 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, prerna.saxena
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.
Some registers such as DCZID_EL0 are not exposed through the KVM cpreg
list at all, but guest still sees the host value, we verify that vCPU's
ID regs values match the host value.
To do this, refactor kvm_arm_writable_idregs_to_cpreg_list to
kvm_arm_write_idregs_to_cpregs_list, which operates per field and now
returns an error if a non-writable field mismatches with the host value.
Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
---
target/arm/cpu-idregs.c | 19 +++++++
target/arm/cpu-idregs.h | 4 ++
target/arm/kvm.c | 116 ++++++++++++++++++++++++++++++++++------
target/arm/trace-events | 2 +-
4 files changed, 125 insertions(+), 16 deletions(-)
diff --git a/target/arm/cpu-idregs.c b/target/arm/cpu-idregs.c
index c41d0ab0c4..6fa02af0f3 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,21 @@ 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;
+}
+
+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 245f1c8103..d866bd9e0a 100644
--- a/target/arm/cpu-idregs.h
+++ b/target/arm/cpu-idregs.h
@@ -38,4 +38,8 @@ 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);
+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 6974e5c551..c38b99cfce 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -951,6 +951,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
@@ -1252,32 +1262,105 @@ 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 number of vCPUs, 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 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; 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.
*/
-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_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,
+ 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)
@@ -2235,8 +2318,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 f33b0d821d..f042ab59b8 100644
--- a/target/arm/trace-events
+++ b/target/arm/trace-events
@@ -14,7 +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
-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
# cpu64.c
get_sysreg_prop(const char *name, uint64_t value) "%s 0x%"PRIx64
--
2.52.0
^ permalink raw reply related [flat|nested] 29+ messages in thread* Re: [RFC PATCH v3 08/19] target/arm/kvm: Handle writeback for special ID register fields
2026-07-16 21:38 ` [RFC PATCH v3 08/19] target/arm/kvm: Handle writeback for special ID register fields Khushit Shah
@ 2026-07-22 12:05 ` Eric Auger
0 siblings, 0 replies; 29+ messages in thread
From: Eric Auger @ 2026-07-22 12:05 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,
prerna.saxena
Hi Khushit,
On 7/16/26 11:38 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.
so this is part of the overall handling of legacy composite options
versus sysreg settings. To be the fact they both are consistent should
be enforced upfront.
> - 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.
Sounds this deserves a prerequisite fix. I also have this hack in my
series but this should be dealt with separately I think.
>
> Some registers such as DCZID_EL0 are not exposed through the KVM cpreg
> list at all, but guest still sees the host value, we verify that vCPU's
> ID regs values match the host value.
why isn't it cpreg then? Shouldn't we add it instead?
>
> To do this, refactor kvm_arm_writable_idregs_to_cpreg_list to
> kvm_arm_write_idregs_to_cpregs_list, which operates per field and now
> returns an error if a non-writable field mismatches with the host value.
>
> Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
> ---
> target/arm/cpu-idregs.c | 19 +++++++
> target/arm/cpu-idregs.h | 4 ++
> target/arm/kvm.c | 116 ++++++++++++++++++++++++++++++++++------
> target/arm/trace-events | 2 +-
> 4 files changed, 125 insertions(+), 16 deletions(-)
>
> diff --git a/target/arm/cpu-idregs.c b/target/arm/cpu-idregs.c
> index c41d0ab0c4..6fa02af0f3 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,21 @@ 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;
> +}
> +
> +bool field_matches(const ARM64SysRegField *field, ARMIDRegisterIdx index,
> + const char *name)
> +{
> + return field->index == index && !strcmp(field->name, name);
why do you need to check both index and name. Only checking index should
be sufficient.
> +}
> diff --git a/target/arm/cpu-idregs.h b/target/arm/cpu-idregs.h
> index 245f1c8103..d866bd9e0a 100644
> --- a/target/arm/cpu-idregs.h
> +++ b/target/arm/cpu-idregs.h
> @@ -38,4 +38,8 @@ 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);
> +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 6974e5c551..c38b99cfce 100644
> --- a/target/arm/kvm.c
> +++ b/target/arm/kvm.c
> @@ -951,6 +951,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
> @@ -1252,32 +1262,105 @@ 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 number of vCPUs, 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 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; 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.
> */
> -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;
> }
while at it you could also test all reserved fields here, RAZ, RES0/1
and make sure host value complies with the description.
>
> - 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_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,
> + 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)
> @@ -2235,8 +2318,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 f33b0d821d..f042ab59b8 100644
> --- a/target/arm/trace-events
> +++ b/target/arm/trace-events
> @@ -14,7 +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
> -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
>
> # cpu64.c
> get_sysreg_prop(const char *name, uint64_t value) "%s 0x%"PRIx64
Thanks
Eric
^ permalink raw reply [flat|nested] 29+ messages in thread
* [RFC PATCH v3 09/19] target/arm: Add named cpu model infra + graviton3 named model
2026-07-16 21:38 [RFC PATCH v3 00/19] named CPU models for Arm64 on KVM Khushit Shah
` (7 preceding siblings ...)
2026-07-16 21:38 ` [RFC PATCH v3 08/19] target/arm/kvm: Handle writeback for special ID register fields Khushit Shah
@ 2026-07-16 21:38 ` Khushit Shah
2026-07-16 21:38 ` [RFC PATCH v3 10/19] target/arm: Add Nvidia Grace " Khushit Shah
` (9 subsequent siblings)
18 siblings, 0 replies; 29+ messages in thread
From: Khushit Shah @ 2026-07-16 21:38 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, prerna.saxena
From: Shaju Abraham <shaju.abraham@nutanix.com>
Introduce a small named-CPU-model layer on top of the field-backed
property infrastructure. Each model is a flat table of (name, value)
overrides and a parent pointer. At instance-init, the parent chain is
walked root-first and every level's properties are applied via QOM,
so a child entry overrides its ancestors for the same name.
For example, the graviton3-v1 named model hierarchy is:
non-zero-defaults-v1 Known non-zero default ID regs field values
arm-v8_4-a-v1 ARMv8.4-A architectural mandate
neoverse-v1-v1 Neoverse V1
graviton3-v1 AWS Graviton3
non-zero-defaults-v1:
Field that should be populated with some non zero value by default.
arm-v8_4-a-v1:
Only features mandated by the ARM ARM.
neoverse-v1-v1:
Reference manual derived feature values for the reference core.
Values differ from TRM values based on what was exposed to the guest
with -cpu host.
graviton3-v1:
SoC integration choices (crypto pin, cache hints, PAuth alg).
The model values are figured out from ID register dump visible to
QEMU with -cpu host on Graviton3 machine.
Model realization:
1. Zero out ID regs array.
2. Add all properties to the CPU Object
3. arm_realize_model_chain: Walk the parent chain from root first and
apply all the properties.
Co-authored-by: Shaju Abraham <shaju.abraham@nutanix.com>
Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
---
hw/arm/virt.c | 5 +
target/arm/arm-cpu-models.c | 336 ++++++++++++++++++++++++++++++++++++
target/arm/arm-cpu-models.h | 35 ++++
target/arm/meson.build | 7 +-
4 files changed, 381 insertions(+), 2 deletions(-)
create mode 100644 target/arm/arm-cpu-models.c
create mode 100644 target/arm/arm-cpu-models.h
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index fe19030886..34e56dc1f1 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -3812,6 +3812,11 @@ static GPtrArray *virt_get_valid_cpu_types(const MachineState *ms)
g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("host")));
}
}
+ if (kvm_enabled() && target_aarch64()) {
+ g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("arm-v8_4-a-v1")));
+ g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("neoverse-v1-v1")));
+ g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("graviton3-v1")));
+ }
g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("max")));
return vct;
diff --git a/target/arm/arm-cpu-models.c b/target/arm/arm-cpu-models.c
new file mode 100644
index 0000000000..747e0df010
--- /dev/null
+++ b/target/arm/arm-cpu-models.c
@@ -0,0 +1,336 @@
+/*
+ * ARM named CPU model definitions.
+ *
+ * Each model is defined as an array of MODEL_PROP macro, listing only
+ * the properties that DIFFER from the parent model.
+ *
+ * At realisation the parent chain is walked root-first and
+ * every level's props are applied via QOM, so the leaf's values
+ * naturally override its ancestors.
+ *
+ * Hierarchy:
+ *
+ * non-zero-defaults-v1 Known non-zero default ID reg field values
+ * arm-v8_4-a-v1 ARMv8.4-A architectural mandate
+ * neoverse-v1-v1 Neoverse V1 (TRM 102649)
+ * graviton3-v1 AWS Graviton3
+ *
+ * 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 "arm-cpu-models.h"
+#include "cpu-idregs.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 }
+
+/*
+ * These fields should be populated with some non-zero default values.
+ */
+static const ArmModelPropValue non_zero_defaults_v1_props[] = {
+ /* ID_AA64PFR0_EL1 */
+ MODEL_PROP("SYSREG_ID_AA64PFR0_EL1_EL0", NUM, 0b0001),
+ MODEL_PROP("SYSREG_ID_AA64PFR0_EL1_EL1", NUM, 0b0001),
+ MODEL_PROP("SYSREG_ID_AA64PFR0_EL1_FP", NUM, 0b1111),
+ MODEL_PROP("SYSREG_ID_AA64PFR0_EL1_AdvSIMD", NUM, 0b1111),
+
+ /* ID_AA64PFR1_EL1 */
+ MODEL_PROP("SYSREG_ID_AA64PFR1_EL1_MTE_frac", NUM, 0b1111),
+
+ /* ID_AA64MMFR0_EL1 */
+ MODEL_PROP("SYSREG_ID_AA64MMFR0_EL1_TGran64", NUM, 0b1111),
+ MODEL_PROP("SYSREG_ID_AA64MMFR0_EL1_TGran4", NUM, 0b1111),
+ MODEL_PROP("SYSREG_ID_AA64MMFR0_EL1_TGran16_2", NUM, 0b0001),
+ MODEL_PROP("SYSREG_ID_AA64MMFR0_EL1_TGran64_2", NUM, 0b0001),
+ MODEL_PROP("SYSREG_ID_AA64MMFR0_EL1_TGran4_2", NUM, 0b0001),
+
+ /* ID_AA64DFR0_EL1 */
+ MODEL_PROP("SYSREG_ID_AA64DFR0_EL1_DebugVer", NUM, 0x6),
+ MODEL_PROP("SYSREG_ID_AA64DFR0_EL1_DoubleLock", NUM, 0b1111),
+
+ /* CTR_EL0 */
+ MODEL_PROP("SYSREG_CTR_EL0_L1Ip", NUM, 0b10),
+ MODEL_PROP("SYSREG_CTR_EL0_RES1_31", NUM, 1),
+
+ /* ID_AA64MMFR4_EL1 */
+ MODEL_PROP("SYSREG_ID_AA64MMFR4_EL1_E2H0", NUM, 0b1111),
+
+ MODEL_PROP_END,
+};
+
+static const ArmModelPropValue armv8_4_a_v1_props[] = {
+ MODEL_PROP("SYSREG_ID_AA64ISAR0_EL1_CRC32", NUM, 1),
+ MODEL_PROP("SYSREG_ID_AA64ISAR0_EL1_Atomic", NUM, 2),
+ MODEL_PROP("SYSREG_ID_AA64MMFR1_EL1_HPDS", NUM, 1),
+ MODEL_PROP("SYSREG_ID_AA64MMFR1_EL1_LO", NUM, 1),
+
+ MODEL_PROP("SYSREG_ID_AA64ISAR1_EL1_DPB", NUM, 1),
+
+ MODEL_PROP("SYSREG_ID_AA64PFR0_EL1_RAS", NUM, 1),
+ MODEL_PROP("SYSREG_ID_AA64PFR1_EL1_RAS_frac", NUM, 0),
+
+ MODEL_PROP("SYSREG_ID_AA64MMFR1_EL1_PAN", NUM, 2),
+ MODEL_PROP("SYSREG_ID_AA64MMFR2_EL1_UAO", NUM, 1),
+ MODEL_PROP("SYSREG_ID_AA64MMFR2_EL1_CnP", NUM, 1),
+ MODEL_PROP("SYSREG_ID_AA64MMFR2_EL1_IESB", NUM, 1),
+
+ MODEL_PROP("SYSREG_ID_AA64PFR0_EL1_DIT", NUM, 1),
+ MODEL_PROP("SYSREG_ID_AA64DFR0_EL1_DebugVer", NUM, 9),
+ MODEL_PROP("SYSREG_ID_AA64DFR0_EL1_PMUVer", NUM, 5),
+ MODEL_PROP("SYSREG_ID_AA64ISAR0_EL1_TS", NUM, 1),
+ MODEL_PROP("SYSREG_ID_AA64ISAR1_EL1_LRCPC", NUM, 2),
+ MODEL_PROP("SYSREG_ID_AA64MMFR2_EL1_AT", NUM, 1),
+ MODEL_PROP("SYSREG_ID_AA64MMFR2_EL1_IDS", NUM, 1),
+ /* KVM zeroes out these field when MTE is not enabled. */
+ MODEL_PROP("SYSREG_ID_AA64PFR1_EL1_MTE_frac", NUM, 0),
+ MODEL_PROP_END,
+};
+
+static const ArmModelPropValue neoverse_v1_v1_props[] = {
+ MODEL_PROP("SYSREG_MIDR_EL1_Implementer", NUM, 0x41),
+ MODEL_PROP("SYSREG_MIDR_EL1_Variant", NUM, 0x1),
+ MODEL_PROP("SYSREG_MIDR_EL1_Architecture", NUM, 0xF),
+ MODEL_PROP("SYSREG_MIDR_EL1_PartNum", NUM, 0xD40),
+ MODEL_PROP("SYSREG_MIDR_EL1_Revision", NUM, 0x1),
+
+ MODEL_PROP("SYSREG_ID_AA64DFR0_EL1_BRPs", NUM, 0x5),
+ MODEL_PROP("SYSREG_ID_AA64DFR0_EL1_WRPs", NUM, 0x3),
+ MODEL_PROP("SYSREG_ID_AA64DFR0_EL1_CTX_CMPs", NUM, 0x1),
+ MODEL_PROP("SYSREG_ID_AA64DFR0_EL1_DoubleLock", NUM, 0xF),
+
+ MODEL_PROP("SYSREG_ID_AA64ISAR0_EL1_RDM", NUM, 1),
+ MODEL_PROP("SYSREG_ID_AA64ISAR0_EL1_DP", NUM, 1),
+ MODEL_PROP("SYSREG_ID_AA64ISAR0_EL1_FHM", NUM, 1),
+
+ MODEL_PROP("SYSREG_ID_AA64ISAR1_EL1_DPB", NUM, 2),
+ MODEL_PROP("SYSREG_ID_AA64ISAR1_EL1_JSCVT", NUM, 1),
+ MODEL_PROP("SYSREG_ID_AA64ISAR1_EL1_FCMA", NUM, 1),
+ MODEL_PROP("SYSREG_ID_AA64ISAR1_EL1_BF16", NUM, 1),
+ MODEL_PROP("SYSREG_ID_AA64ISAR1_EL1_DGH", NUM, 1),
+ MODEL_PROP("SYSREG_ID_AA64ISAR1_EL1_I8MM", NUM, 1),
+
+ MODEL_PROP("SYSREG_ID_AA64PFR0_EL1_FP", NUM, 1),
+ MODEL_PROP("SYSREG_ID_AA64PFR0_EL1_AdvSIMD", NUM, 1),
+
+ MODEL_PROP("SYSREG_ID_AA64PFR0_EL1_RAS", NUM, 2),
+ MODEL_PROP("SYSREG_ID_AA64PFR1_EL1_RAS_frac", NUM, 0),
+
+ MODEL_PROP("SYSREG_ID_AA64PFR0_EL1_CSV2", NUM, 1),
+ MODEL_PROP("SYSREG_ID_AA64PFR1_EL1_CSV2_frac", NUM, 0),
+
+ MODEL_PROP("SYSREG_ID_AA64PFR0_EL1_CSV3", NUM, 1),
+
+ MODEL_PROP("SYSREG_ID_AA64PFR1_EL1_SSBS", NUM, 2),
+
+ MODEL_PROP("SYSREG_ID_AA64MMFR0_EL1_PARange", NUM, 5),
+ MODEL_PROP("SYSREG_ID_AA64MMFR0_EL1_ASIDBits", NUM, 2),
+ MODEL_PROP("SYSREG_ID_AA64MMFR0_EL1_BigEnd", NUM, 1),
+ MODEL_PROP("SYSREG_ID_AA64MMFR0_EL1_SNSMem", NUM, 1),
+ MODEL_PROP("SYSREG_ID_AA64MMFR0_EL1_TGran4", NUM, 0),
+ MODEL_PROP("SYSREG_ID_AA64MMFR0_EL1_TGran16", NUM, 1),
+ MODEL_PROP("SYSREG_ID_AA64MMFR0_EL1_TGran64", NUM, 0),
+ MODEL_PROP("SYSREG_ID_AA64MMFR0_EL1_TGran4_2", NUM, 0),
+ MODEL_PROP("SYSREG_ID_AA64MMFR0_EL1_TGran16_2", NUM, 0),
+ MODEL_PROP("SYSREG_ID_AA64MMFR0_EL1_TGran64_2", NUM, 0),
+ MODEL_PROP("SYSREG_ID_AA64MMFR1_EL1_HAFDBS", NUM, 2),
+ MODEL_PROP("SYSREG_ID_AA64MMFR1_EL1_VMIDBits", NUM, 2),
+ MODEL_PROP("SYSREG_ID_AA64MMFR1_EL1_VH", NUM, 1),
+ MODEL_PROP("SYSREG_ID_AA64MMFR1_EL1_HPDS", NUM, 2),
+ MODEL_PROP("SYSREG_ID_AA64MMFR1_EL1_XNX", NUM, 1),
+ MODEL_PROP("SYSREG_ID_AA64MMFR1_EL1_SpecSEI", NUM, 0),
+
+ MODEL_PROP("SYSREG_ID_AA64MMFR2_EL1_FWB", NUM, 1),
+ MODEL_PROP("SYSREG_ID_AA64MMFR2_EL1_BBM", NUM, 2),
+ MODEL_PROP("SYSREG_ID_AA64MMFR2_EL1_EVT", NUM, 2),
+
+ MODEL_PROP("SYSREG_ID_AA64MMFR4_EL1_E2H0", NUM, 0),
+
+ MODEL_PROP("SYSREG_CTR_EL0_IminLine", NUM, 4),
+ MODEL_PROP("SYSREG_CTR_EL0_L1Ip", NUM, 3),
+ MODEL_PROP("SYSREG_CTR_EL0_DminLine", NUM, 4),
+ MODEL_PROP("SYSREG_CTR_EL0_ERG", NUM, 4),
+ MODEL_PROP("SYSREG_CTR_EL0_CWG", NUM, 4),
+
+ MODEL_PROP("SYSREG_DCZID_EL0_BS", NUM, 0x4),
+
+ /* pauth */
+ MODEL_PROP("SYSREG_ID_AA64ISAR1_EL1_APA", NUM, 3),
+ MODEL_PROP("SYSREG_ID_AA64ISAR1_EL1_GPA", NUM, 1),
+
+ /* sve */
+ MODEL_PROP("SYSREG_ID_AA64PFR0_EL1_SVE", NUM, 1),
+ MODEL_PROP("SYSREG_ID_AA64ZFR0_EL1_BF16", NUM, 1),
+ MODEL_PROP("SYSREG_ID_AA64ZFR0_EL1_I8MM", NUM, 1),
+ MODEL_PROP("sve128", BOOL, true),
+
+ MODEL_PROP_END,
+};
+
+static const ArmModelPropValue graviton3_v1_props[] = {
+ MODEL_PROP("SYSREG_ID_AA64ISAR0_EL1_AES", NUM, 2),
+ MODEL_PROP("SYSREG_ID_AA64ISAR0_EL1_SHA1", NUM, 1),
+ MODEL_PROP("SYSREG_ID_AA64ISAR0_EL1_SHA2", NUM, 2),
+ MODEL_PROP("SYSREG_ID_AA64ISAR0_EL1_SHA3", NUM, 1),
+ MODEL_PROP("SYSREG_ID_AA64ISAR0_EL1_SM3", NUM, 1),
+ MODEL_PROP("SYSREG_ID_AA64ISAR0_EL1_SM4", NUM, 1),
+ MODEL_PROP("SYSREG_ID_AA64ISAR0_EL1_RNDR", NUM, 1),
+
+ MODEL_PROP("SYSREG_CTR_EL0_IDC", NUM, 1),
+ MODEL_PROP("SYSREG_CTR_EL0_DIC", NUM, 1),
+
+ MODEL_PROP("SYSREG_REVIDR_EL1_VAL", NUM, 1),
+
+ MODEL_PROP_END,
+};
+
+static const ArmNamedCpuModel arm_cpu_models[] = {
+ {
+ .name = "non-zero-defaults-v1",
+ .parent = NULL,
+ .props = non_zero_defaults_v1_props,
+ },
+ {
+ .name = "arm-v8_4-a-v1",
+ .parent = "non-zero-defaults-v1",
+ .props = armv8_4_a_v1_props,
+ },
+ {
+ .name = "neoverse-v1-v1",
+ .parent = "arm-v8_4-a-v1",
+ .props = neoverse_v1_v1_props,
+ },
+ {
+ .name = "graviton3-v1",
+ .parent = "neoverse-v1-v1",
+ .props = graviton3_v1_props,
+ },
+};
+
+static ARMCPUInfo arm_named_cpu_infos[ARRAY_SIZE(arm_cpu_models)];
+const ArmNamedCpuModel *arm_find_model(const char *name)
+{
+ size_t i;
+ for (i = 0; i < ARRAY_SIZE(arm_cpu_models); i++) {
+ if (g_str_equal(arm_cpu_models[i].name, name)) {
+ return &arm_cpu_models[i];
+ }
+ }
+ return NULL;
+}
+
+static 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;
+ }
+ }
+}
+
+static void arm_realize_model_chain(Object *obj, const ArmNamedCpuModel *model,
+ Error **errp)
+{
+ const ArmNamedCpuModel *cur, *parent;
+ const ArmNamedCpuModel *chain[ARRAY_SIZE(arm_cpu_models)];
+ size_t depth = 0;
+ for (cur = model; cur; ) {
+ if (depth >= ARRAY_SIZE(chain)) {
+ error_setg(errp, "model '%s': parent chain too deep "
+ "(possible cycle)", 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 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. Reset ID regs to 0 */
+ memset(cpu->isar.idregs, 0, sizeof(cpu->isar.idregs));
+
+ /* 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)
+{
+ size_t i;
+ for (i = 0; i < ARRAY_SIZE(arm_cpu_models); i++) {
+ 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/arm-cpu-models.h b/target/arm/arm-cpu-models.h
new file mode 100644
index 0000000000..ac4e510499
--- /dev/null
+++ b/target/arm/arm-cpu-models.h
@@ -0,0 +1,35 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * ARM named CPU model definitions - public API.
+ */
+#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);
+
+#endif /* ARM_CPU_MODELS_H */
diff --git a/target/arm/meson.build b/target/arm/meson.build
index 64d1ec63ab..72eed1bcc6 100644
--- a/target/arm/meson.build
+++ b/target/arm/meson.build
@@ -10,7 +10,7 @@ arm_user_ss.add(files('gdbstub.c'))
arm_ss.add(when: 'TARGET_AARCH64', if_true: files(
'cpu64.c',
- 'gdbstub64.c'
+ 'gdbstub64.c',
))
arm_common_ss.add(files(
@@ -21,7 +21,10 @@ arm_common_system_ss.add(files(
'arm-qmp-cmds.c',
'cpu-idregs.c',
))
-arm_system_ss.add(when: 'CONFIG_KVM', if_true: files('hyp_gdbstub.c', 'kvm.c'))
+arm_system_ss.add(when: 'TARGET_AARCH64', if_true: files('arm-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'))
arm_user_ss.add(files('cpu.c'))
--
2.52.0
^ permalink raw reply related [flat|nested] 29+ messages in thread* [RFC PATCH v3 10/19] target/arm: Add Nvidia Grace named model
2026-07-16 21:38 [RFC PATCH v3 00/19] named CPU models for Arm64 on KVM Khushit Shah
` (8 preceding siblings ...)
2026-07-16 21:38 ` [RFC PATCH v3 09/19] target/arm: Add named cpu model infra + graviton3 named model Khushit Shah
@ 2026-07-16 21:38 ` Khushit Shah
2026-07-16 21:38 ` [RFC PATCH v3 11/19] target/arm: fix sve and pauth finalize for named cpu models Khushit Shah
` (8 subsequent siblings)
18 siblings, 0 replies; 29+ messages in thread
From: Khushit Shah @ 2026-07-16 21:38 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, prerna.saxena
Add Nvidia Grace named model alongside its hierarchy (neoverse-v2,
armv9-a)
Field values were derived from the ID register view that KVM exposes to
QEMU with -cpu host on an Nvidia Grace system.
Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
---
hw/arm/virt.c | 3 +
target/arm/arm-cpu-models.c | 154 +++++++++++++++++++++++++++++++++++-
2 files changed, 156 insertions(+), 1 deletion(-)
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 34e56dc1f1..3b27c7a710 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -3816,6 +3816,9 @@ static GPtrArray *virt_get_valid_cpu_types(const MachineState *ms)
g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("arm-v8_4-a-v1")));
g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("neoverse-v1-v1")));
g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("graviton3-v1")));
+ 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("grace-v1")));
}
g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("max")));
diff --git a/target/arm/arm-cpu-models.c b/target/arm/arm-cpu-models.c
index 747e0df010..40e8578591 100644
--- a/target/arm/arm-cpu-models.c
+++ b/target/arm/arm-cpu-models.c
@@ -14,7 +14,9 @@
* arm-v8_4-a-v1 ARMv8.4-A architectural mandate
* neoverse-v1-v1 Neoverse V1 (TRM 102649)
* graviton3-v1 AWS Graviton3
- *
+ * arm-v9_0-a-v1 ARMv9.0-A architectural deltas
+ * neoverse-v2-v1 Neoverse V2 (TRM 102375)
+ * grace-v1 NVIDIA Grace
* SPDX-License-Identifier: GPL-2.0-or-later
*/
@@ -197,6 +199,141 @@ static const ArmModelPropValue graviton3_v1_props[] = {
MODEL_PROP_END,
};
+static const ArmModelPropValue armv9_0_a_v1_props[] = {
+ MODEL_PROP("SYSREG_ID_AA64PFR1_EL1_BT", NUM, 1),
+
+ MODEL_PROP("SYSREG_ID_AA64PFR0_EL1_CSV2", NUM, 1),
+ MODEL_PROP("SYSREG_ID_AA64PFR1_EL1_CSV2_frac", NUM, 0),
+
+ MODEL_PROP("SYSREG_ID_AA64PFR0_EL1_CSV3", NUM, 1),
+ MODEL_PROP("SYSREG_ID_AA64ISAR1_EL1_DPB", NUM, 2),
+ MODEL_PROP("SYSREG_ID_AA64MMFR2_EL1_E0PD", NUM, 1),
+ MODEL_PROP("SYSREG_ID_AA64ISAR1_EL1_SB", NUM, 1),
+ MODEL_PROP("SYSREG_ID_AA64ISAR1_EL1_SPECRES", NUM, 1),
+ MODEL_PROP("SYSREG_ID_AA64PFR1_EL1_SSBS", NUM, 2),
+
+ MODEL_PROP("SYSREG_ID_AA64DFR0_EL1_DoubleLock", NUM, 0xF),
+ MODEL_PROP("SYSREG_ID_AA64PFR0_EL1_FP", NUM, 0),
+ MODEL_PROP("SYSREG_ID_AA64PFR0_EL1_AdvSIMD", NUM, 0),
+ MODEL_PROP("SYSREG_ID_AA64ISAR0_EL1_TS", NUM, 2),
+ MODEL_PROP("SYSREG_ID_AA64ISAR1_EL1_FRINTTS", NUM, 1),
+ MODEL_PROP("SYSREG_ID_AA64ISAR0_EL1_RDM", NUM, 1),
+ MODEL_PROP("SYSREG_ID_AA64ISAR0_EL1_DP", NUM, 1),
+ MODEL_PROP("SYSREG_ID_AA64ISAR0_EL1_FHM", NUM, 1),
+ MODEL_PROP("SYSREG_ID_AA64ISAR1_EL1_FCMA", NUM, 1),
+ MODEL_PROP("SYSREG_ID_AA64ISAR1_EL1_JSCVT", NUM, 1),
+
+ MODEL_PROP("SYSREG_ID_AA64PFR0_EL1_SVE", NUM, 1),
+ MODEL_PROP("SYSREG_ID_AA64PFR0_EL1_SEL2", NUM, 1),
+ MODEL_PROP("SYSREG_ID_AA64MMFR1_EL1_VH", NUM, 1),
+ MODEL_PROP("SYSREG_ID_AA64MMFR1_EL1_XNX", NUM, 1),
+
+ MODEL_PROP_END,
+};
+
+
+static const ArmModelPropValue neoverse_v2_v1_props[] = {
+ MODEL_PROP("SYSREG_MIDR_EL1_Implementer", NUM, 0x41),
+ MODEL_PROP("SYSREG_MIDR_EL1_Variant", NUM, 0x0),
+ MODEL_PROP("SYSREG_MIDR_EL1_Architecture", NUM, 0xF),
+ MODEL_PROP("SYSREG_MIDR_EL1_PartNum", NUM, 0xD4F),
+ MODEL_PROP("SYSREG_MIDR_EL1_Revision", NUM, 0x2),
+
+ MODEL_PROP("SYSREG_ID_AA64DFR0_EL1_BRPs", NUM, 0x5),
+ MODEL_PROP("SYSREG_ID_AA64DFR0_EL1_WRPs", NUM, 0x3),
+ MODEL_PROP("SYSREG_ID_AA64DFR0_EL1_CTX_CMPs", NUM, 0x1),
+ MODEL_PROP("SYSREG_ID_AA64DFR0_EL1_PMUVer", NUM, 6),
+
+ MODEL_PROP("SYSREG_ID_AA64ISAR0_EL1_TLB", NUM, 2),
+
+ MODEL_PROP("SYSREG_ID_AA64ISAR1_EL1_BF16", NUM, 1),
+ MODEL_PROP("SYSREG_ID_AA64ISAR1_EL1_DGH", NUM, 1),
+ MODEL_PROP("SYSREG_ID_AA64ISAR1_EL1_I8MM", NUM, 1),
+
+ MODEL_PROP("SYSREG_ID_AA64PFR0_EL1_FP", NUM, 1),
+ MODEL_PROP("SYSREG_ID_AA64PFR0_EL1_AdvSIMD", NUM, 1),
+
+ MODEL_PROP("SYSREG_ID_AA64PFR0_EL1_RAS", NUM, 2),
+ MODEL_PROP("SYSREG_ID_AA64PFR1_EL1_RAS_frac", NUM, 0),
+
+ /*
+ * V2 silicon may report CSV2=2 (FEAT_CSV2_2) per TRM page 392, but
+ * KVM clamps the guest-visible limit to 1.
+ */
+ MODEL_PROP("SYSREG_ID_AA64PFR0_EL1_CSV2", NUM, 1),
+ MODEL_PROP("SYSREG_ID_AA64PFR1_EL1_CSV2_frac", NUM, 0),
+
+ MODEL_PROP("SYSREG_ID_AA64MMFR0_EL1_PARange", NUM, 5),
+ MODEL_PROP("SYSREG_ID_AA64MMFR0_EL1_ASIDBits", NUM, 2),
+ MODEL_PROP("SYSREG_ID_AA64MMFR0_EL1_BigEnd", NUM, 1),
+ MODEL_PROP("SYSREG_ID_AA64MMFR0_EL1_SNSMem", NUM, 1),
+ MODEL_PROP("SYSREG_ID_AA64MMFR0_EL1_TGran16", NUM, 1),
+ MODEL_PROP("SYSREG_ID_AA64MMFR0_EL1_TGran64", NUM, 0),
+ MODEL_PROP("SYSREG_ID_AA64MMFR0_EL1_TGran4", NUM, 0),
+ MODEL_PROP("SYSREG_ID_AA64MMFR0_EL1_TGran16_2", NUM, 2),
+ MODEL_PROP("SYSREG_ID_AA64MMFR0_EL1_TGran64_2", NUM, 2),
+ MODEL_PROP("SYSREG_ID_AA64MMFR0_EL1_TGran4_2", NUM, 2),
+
+ MODEL_PROP("SYSREG_ID_AA64MMFR1_EL1_HAFDBS", NUM, 2),
+ MODEL_PROP("SYSREG_ID_AA64MMFR1_EL1_VMIDBits", NUM, 2),
+ MODEL_PROP("SYSREG_ID_AA64MMFR1_EL1_HPDS", NUM, 2),
+ MODEL_PROP("SYSREG_ID_AA64MMFR1_EL1_PAN", NUM, 3),
+ MODEL_PROP("SYSREG_ID_AA64MMFR1_EL1_ECBHB", NUM, 0),
+ MODEL_PROP("SYSREG_ID_AA64MMFR1_EL1_SpecSEI", NUM, 0),
+
+ MODEL_PROP("SYSREG_ID_AA64MMFR2_EL1_FWB", NUM, 1),
+ MODEL_PROP("SYSREG_ID_AA64MMFR2_EL1_ST", NUM, 1),
+ MODEL_PROP("SYSREG_ID_AA64MMFR2_EL1_TTL", NUM, 1),
+ MODEL_PROP("SYSREG_ID_AA64MMFR2_EL1_BBM", NUM, 2),
+ MODEL_PROP("SYSREG_ID_AA64MMFR2_EL1_EVT", NUM, 2),
+ MODEL_PROP("SYSREG_ID_AA64MMFR4_EL1_E2H0", NUM, 0),
+
+ MODEL_PROP("SYSREG_CTR_EL0_IminLine", NUM, 4),
+ MODEL_PROP("SYSREG_CTR_EL0_L1Ip", NUM, 3),
+ MODEL_PROP("SYSREG_CTR_EL0_DminLine", NUM, 4),
+ MODEL_PROP("SYSREG_CTR_EL0_ERG", NUM, 4),
+ MODEL_PROP("SYSREG_CTR_EL0_CWG", NUM, 4),
+
+ MODEL_PROP("SYSREG_DCZID_EL0_BS", NUM, 0x4),
+
+ /* pauth */
+ MODEL_PROP("SYSREG_ID_AA64ISAR1_EL1_APA", NUM, 5),
+ MODEL_PROP("SYSREG_ID_AA64ISAR1_EL1_GPA", NUM, 1),
+
+ /* sve */
+ MODEL_PROP("SYSREG_ID_AA64ZFR0_EL1_SVEver", NUM, 1),
+ MODEL_PROP("SYSREG_ID_AA64ZFR0_EL1_BF16", NUM, 1),
+ MODEL_PROP("SYSREG_ID_AA64ZFR0_EL1_BitPerm", NUM, 1),
+ MODEL_PROP("SYSREG_ID_AA64ZFR0_EL1_I8MM", NUM, 1),
+ MODEL_PROP("sve128", BOOL, true),
+
+ MODEL_PROP_END,
+};
+
+
+static const ArmModelPropValue grace_v1_props[] = {
+ MODEL_PROP("SYSREG_MIDR_EL1_Revision", NUM, 0x0),
+
+ MODEL_PROP("SYSREG_ID_AA64ISAR0_EL1_AES", NUM, 2),
+ MODEL_PROP("SYSREG_ID_AA64ISAR0_EL1_SHA1", NUM, 1),
+ MODEL_PROP("SYSREG_ID_AA64ISAR0_EL1_SHA2", NUM, 2),
+ MODEL_PROP("SYSREG_ID_AA64ISAR0_EL1_SHA3", NUM, 1),
+ MODEL_PROP("SYSREG_ID_AA64ISAR0_EL1_SM3", NUM, 1),
+ MODEL_PROP("SYSREG_ID_AA64ISAR0_EL1_SM4", NUM, 1),
+
+ MODEL_PROP("SYSREG_CTR_EL0_IDC", NUM, 1),
+ MODEL_PROP("SYSREG_CTR_EL0_DIC", NUM, 1),
+
+ MODEL_PROP("SYSREG_REVIDR_EL1_VAL", NUM, 1),
+
+ /* sve crypto (base sve inherited from neoverse-v2) */
+ MODEL_PROP("SYSREG_ID_AA64ZFR0_EL1_AES", NUM, 2),
+ MODEL_PROP("SYSREG_ID_AA64ZFR0_EL1_SHA3", NUM, 1),
+ MODEL_PROP("SYSREG_ID_AA64ZFR0_EL1_SM4", NUM, 1),
+
+ MODEL_PROP_END,
+};
+
static const ArmNamedCpuModel arm_cpu_models[] = {
{
.name = "non-zero-defaults-v1",
@@ -218,6 +355,21 @@ static const ArmNamedCpuModel arm_cpu_models[] = {
.parent = "neoverse-v1-v1",
.props = graviton3_v1_props,
},
+ {
+ .name = "arm-v9_0-a-v1",
+ .parent = "arm-v8_4-a-v1",
+ .props = armv9_0_a_v1_props,
+ },
+ {
+ .name = "neoverse-v2-v1",
+ .parent = "arm-v9_0-a-v1",
+ .props = neoverse_v2_v1_props,
+ },
+ {
+ .name = "grace-v1",
+ .parent = "neoverse-v2-v1",
+ .props = grace_v1_props,
+ },
};
static ARMCPUInfo arm_named_cpu_infos[ARRAY_SIZE(arm_cpu_models)];
--
2.52.0
^ permalink raw reply related [flat|nested] 29+ messages in thread* [RFC PATCH v3 11/19] target/arm: fix sve and pauth finalize for named cpu models
2026-07-16 21:38 [RFC PATCH v3 00/19] named CPU models for Arm64 on KVM Khushit Shah
` (9 preceding siblings ...)
2026-07-16 21:38 ` [RFC PATCH v3 10/19] target/arm: Add Nvidia Grace " Khushit Shah
@ 2026-07-16 21:38 ` Khushit Shah
2026-07-16 21:38 ` [RFC PATCH v3 12/19] target/arm: Introduce stub files required for qmp support Khushit Shah
` (7 subsequent siblings)
18 siblings, 0 replies; 29+ messages in thread
From: Khushit Shah @ 2026-07-16 21:38 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, prerna.saxena
Named models provide authoritative ID-register values, so don't derive
SVE vector lengths or pauth fields from the host; require explicit SVE
lengths and leave the model's pauth fields intact.
Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
---
target/arm/cpu64.c | 29 +++++++++++++++++++++++++++++
1 file changed, 29 insertions(+)
diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
index cdad0fc46d..44dd9acf80 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 "arm-cpu-models.h"
#include "trace.h"
/* convert between <register>_IDX and SYS_<register> */
@@ -134,6 +135,20 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp)
return;
}
+ /*
+ * If SVE is enabled but no vector lengths are specified, we must not
+ * default to the host's supported lengths for named CPU models, as
+ * this breaks live migration.
+ */
+ {
+ 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;
+ }
+ }
+
if (kvm_enabled()) {
/* Disabling a supported length disables all larger lengths. */
tmp = vq_init & vq_supported;
@@ -556,6 +571,20 @@ void arm_cpu_pauth_finalize(ARMCPU *cpu, Error **errp)
ARMISARegisters *isar = &cpu->isar;
uint64_t isar1, isar2;
+ /*
+ * For named CPU models the model props write the authoritative
+ * APA/API/APA3/GPA/GPI/GPA3 values directly into cpu->isar, so do not
+ * override them here. Since other code relies on cpu->prop_pauth,
+ * mirror the resulting pauth state into 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;
+ }
+ }
+
/*
* 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] 29+ messages in thread* [RFC PATCH v3 12/19] target/arm: Introduce stub files required for qmp support
2026-07-16 21:38 [RFC PATCH v3 00/19] named CPU models for Arm64 on KVM Khushit Shah
` (10 preceding siblings ...)
2026-07-16 21:38 ` [RFC PATCH v3 11/19] target/arm: fix sve and pauth finalize for named cpu models Khushit Shah
@ 2026-07-16 21:38 ` Khushit Shah
2026-07-16 21:38 ` [RFC PATCH v3 13/19] target/arm/qmp: add named models and properties to cpu-model-expansion Khushit Shah
` (6 subsequent siblings)
18 siblings, 0 replies; 29+ messages in thread
From: Khushit Shah @ 2026-07-16 21:38 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, prerna.saxena
Add arm-cpu-models-stub.c, which will be required to add qmp support.
Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
---
target/arm/arm-cpu-models-stub.c | 13 +++++++++++++
target/arm/meson.build | 3 ++-
2 files changed, 15 insertions(+), 1 deletion(-)
create mode 100644 target/arm/arm-cpu-models-stub.c
diff --git a/target/arm/arm-cpu-models-stub.c b/target/arm/arm-cpu-models-stub.c
new file mode 100644
index 0000000000..0481f0f946
--- /dev/null
+++ b/target/arm/arm-cpu-models-stub.c
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * ARM named CPU model definitions - stub implementation.
+ */
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "arm-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 72eed1bcc6..d7b4cdc5c8 100644
--- a/target/arm/meson.build
+++ b/target/arm/meson.build
@@ -21,7 +21,8 @@ arm_common_system_ss.add(files(
'arm-qmp-cmds.c',
'cpu-idregs.c',
))
-arm_system_ss.add(when: 'TARGET_AARCH64', if_true: files('arm-cpu-models.c'))
+arm_system_ss.add(when: 'TARGET_AARCH64', if_true: files('arm-cpu-models.c'),
+ if_false: files('arm-cpu-models-stub.c'))
arm_system_ss.add(when: 'CONFIG_KVM',
if_true: files('hyp_gdbstub.c',
'kvm.c'))
--
2.52.0
^ permalink raw reply related [flat|nested] 29+ messages in thread* [RFC PATCH v3 13/19] target/arm/qmp: add named models and properties to cpu-model-expansion
2026-07-16 21:38 [RFC PATCH v3 00/19] named CPU models for Arm64 on KVM Khushit Shah
` (11 preceding siblings ...)
2026-07-16 21:38 ` [RFC PATCH v3 12/19] target/arm: Introduce stub files required for qmp support Khushit Shah
@ 2026-07-16 21:38 ` Khushit Shah
2026-07-16 21:38 ` [RFC PATCH v3 14/19] target/arm/kvm: compute supported values for ID register fields Khushit Shah
` (5 subsequent siblings)
18 siblings, 0 replies; 29+ messages in thread
From: Khushit Shah @ 2026-07-16 21:38 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, prerna.saxena
Allow expansion of the new named CPU models.
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 edcfc82a25..bdf46c823a 100644
--- a/target/arm/arm-qmp-cmds.c
+++ b/target/arm/arm-qmp-cmds.c
@@ -33,6 +33,7 @@
#include "qobject/qdict.h"
#include "qom/qom-qobject.h"
#include "cpu.h"
+#include "arm-cpu-models.h"
static GICCapability *gic_cap_new(int version)
{
@@ -92,6 +93,7 @@ CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type,
ObjectClass *oc;
Object *obj;
const char *name;
+ bool named_model = (arm_find_model(model->name) != NULL);
int i;
if (type != CPU_MODEL_EXPANSION_TYPE_FULL) {
@@ -104,6 +106,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",
@@ -117,6 +124,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] 29+ messages in thread* [RFC PATCH v3 14/19] target/arm/kvm: compute supported values for ID register fields
2026-07-16 21:38 [RFC PATCH v3 00/19] named CPU models for Arm64 on KVM Khushit Shah
` (12 preceding siblings ...)
2026-07-16 21:38 ` [RFC PATCH v3 13/19] target/arm/qmp: add named models and properties to cpu-model-expansion Khushit Shah
@ 2026-07-16 21:38 ` Khushit Shah
2026-07-16 21:38 ` [RFC PATCH v3 15/19] target/arm/kvm: introduce kvm_arm_get_host_isar helper Khushit Shah
` (4 subsequent siblings)
18 siblings, 0 replies; 29+ messages in thread
From: Khushit Shah @ 2026-07-16 21:38 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, prerna.saxena
Add arm_field_get_supported_values() which, for a given ID register
field, builds the set of values KVM allows it to take on the live host.
Non-writable fields are pinned to the host value. Writable fields follow
their per field constraints. This function likely needs change 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.
Cross-field constraints are not modelled; for example ID_AA64ZFR0_EL1
is gated by SVE. Reproducing every inter-field dependency in QEMU
would only duplicate KVM's logic and drift out of sync with it.
Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
---
target/arm/kvm.c | 99 ++++++++++++++++++++++++++++++++++++++++++++
target/arm/kvm_arm.h | 26 ++++++++++++
2 files changed, 125 insertions(+)
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index c38b99cfce..8f452f9570 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -1262,6 +1262,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 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].value;
+ 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 133a026036..9f15c91c4e 100644
--- a/target/arm/kvm_arm.h
+++ b/target/arm/kvm_arm.h
@@ -143,6 +143,32 @@ void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu);
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;
+
+/**
+ * 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 arm_field_get_supported_values(const ARM64SysRegField *field,
+ const ARMISARegisters *host_isar,
+ ArmFieldValueSet **value_set);
/**
* kvm_arm_steal_time_finalize:
--
2.52.0
^ permalink raw reply related [flat|nested] 29+ messages in thread* [RFC PATCH v3 15/19] target/arm/kvm: introduce kvm_arm_get_host_isar helper
2026-07-16 21:38 [RFC PATCH v3 00/19] named CPU models for Arm64 on KVM Khushit Shah
` (13 preceding siblings ...)
2026-07-16 21:38 ` [RFC PATCH v3 14/19] target/arm/kvm: compute supported values for ID register fields Khushit Shah
@ 2026-07-16 21:38 ` Khushit Shah
2026-07-16 21:38 ` [RFC PATCH v3 16/19] qmp: add query-cpu-props-info command Khushit Shah
` (3 subsequent siblings)
18 siblings, 0 replies; 29+ messages in thread
From: Khushit Shah @ 2026-07-16 21:38 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, prerna.saxena
Introduce kvm_arm_get_host_isar() to provide scratch vCPU probed host
isar. Will be used in future 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 88cbe8d85c..dd683beaaf 100644
--- a/target/arm/kvm-stub.c
+++ b/target/arm/kvm-stub.c
@@ -119,3 +119,8 @@ char *kvm_print_register_name(uint64_t regidx)
{
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 8f452f9570..042d5fe804 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -650,6 +650,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 9f15c91c4e..4a04d72e39 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)
@@ -257,6 +259,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] 29+ messages in thread* [RFC PATCH v3 16/19] qmp: add query-cpu-props-info command
2026-07-16 21:38 [RFC PATCH v3 00/19] named CPU models for Arm64 on KVM Khushit Shah
` (14 preceding siblings ...)
2026-07-16 21:38 ` [RFC PATCH v3 15/19] target/arm/kvm: introduce kvm_arm_get_host_isar helper Khushit Shah
@ 2026-07-16 21:38 ` Khushit Shah
2026-07-20 13:21 ` Markus Armbruster
2026-07-16 21:38 ` [RFC PATCH v3 17/19] target/arm: Report 0 as supported for ID fields gated by vCPU init flags Khushit Shah
` (2 subsequent siblings)
18 siblings, 1 reply; 29+ messages in thread
From: Khushit Shah @ 2026-07-16 21:38 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, prerna.saxena
Introduce the 'query-cpu-props-info' QMP command. For CPU model
properties it reports the type (boolean or number) and the set of values
supported under the active accelerator and host.
For numbers the supported values are expressed as a list of inclusive
{min, max} ranges; for booleans as the list of allowed 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, riscv)
too. Target that do not implement it return an error.
The Arm/KVM implementation spins up a scratch "host" vCPU object,
walks its QOM properties: SYSREG_ ID-register fields become 'number'
properties whose ranges come from arm_field_get_supported_values(),
and the advertised feature toggles become 'boolean' properties.
Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
---
qapi/machine.json | 87 ++++++++++++++++++++++++++++++++++++
stubs/meson.build | 1 +
stubs/qmp-cpu-props-info.c | 12 +++++
target/arm/arm-qmp-cmds.c | 90 ++++++++++++++++++++++++++++++++++++++
target/arm/kvm-stub.c | 7 +++
5 files changed, 197 insertions(+)
create mode 100644 stubs/qmp-cpu-props-info.c
diff --git a/qapi/machine.json b/qapi/machine.json
index 685e4e29b8..362efe4c50 100644
--- a/qapi/machine.json
+++ b/qapi/machine.json
@@ -2251,3 +2251,90 @@
# Since: 1.2
##
{ 'command': 'query-cpu-definitions', 'returns': ['CpuDefinitionInfo'] }
+
+##
+# @CpuPropertyType:
+#
+# The type of a CPU model property value.
+#
+# @boolean: the property is an on/off toggle.
+#
+# @number: the property is an unsigned integer.
+#
+# Since: 11.1
+##
+{ 'enum': 'CpuPropertyType',
+ 'data': [ 'boolean', 'number' ] }
+
+##
+# @CpuPropertyValueRange:
+#
+# An inclusive range of numeric values supported for a property.
+#
+# @min: the lowest supported value.
+#
+# @max: the highest supported value.
+#
+# Since: 11.1
+##
+{ 'struct': 'CpuPropertyValueRange',
+ 'data': { 'min': 'uint64', 'max': 'uint64' } }
+
+##
+# @CpuPropertyInfoBoolean:
+#
+# @supported-values: the boolean values the host supports for this
+# property (a subset of {true, false}).
+#
+# Since: 11.1
+##
+{ 'struct': 'CpuPropertyInfoBoolean',
+ 'data': { 'supported-values': ['bool'] } }
+
+##
+# @CpuPropertyInfoNumber:
+#
+# @supported-values: the set of value ranges the host supports for
+# this property.
+#
+# Since: 11.1
+##
+{ 'struct': 'CpuPropertyInfoNumber',
+ 'data': { 'supported-values': ['CpuPropertyValueRange'] } }
+
+##
+# @CpuPropertyInfo:
+#
+# Information about a single CPU model property, including the values
+# the current host supports for it.
+#
+# @name: the name of the property.
+#
+# @type: the type of the property, which selects the layout of
+# @supported-values.
+#
+# Since: 11.1
+##
+{ '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.
+#
+# .. note:: This command is currently only implemented on Arm (and
+# KVM accel); all other configurations return an error. The schema
+# is architecture-agnostic so other targets and accelerators can
+# implement it in the future.
+#
+# Since: 11.1
+##
+{ '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..f0301a1179
--- /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, "CPU model properties are not supported on this target");
+ return NULL;
+}
diff --git a/target/arm/arm-qmp-cmds.c b/target/arm/arm-qmp-cmds.c
index bdf46c823a..457cc3edf3 100644
--- a/target/arm/arm-qmp-cmds.c
+++ b/target/arm/arm-qmp-cmds.c
@@ -81,6 +81,96 @@ 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.
+ * This gives us the exact set we want to expose: the SYSREG_ ID-register
+ * properties and the advertised feature properties, along with their
+ * values for the host.
+ */
+ 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_")) {
+ /* The SYSREG_ property stashes its field descriptor as opaque. */
+ const ARM64SysRegField *field = prop->opaque;
+ ArmFieldValueSet *vs = NULL;
+ CpuPropertyValueRangeList *ranges = NULL;
+
+ info = g_new0(CpuPropertyInfo, 1);
+ info->name = g_strdup(prop->name);
+ info->type = CPU_PROPERTY_TYPE_NUMBER;
+
+ 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 achievable. "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)
diff --git a/target/arm/kvm-stub.c b/target/arm/kvm-stub.c
index dd683beaaf..d19c53927d 100644
--- a/target/arm/kvm-stub.c
+++ b/target/arm/kvm-stub.c
@@ -124,3 +124,10 @@ const ARMISARegisters *kvm_arm_get_host_isar(void)
{
return NULL;
}
+
+void arm_field_get_supported_values(const ARM64SysRegField *field,
+ const ARMISARegisters *host_isar,
+ ArmFieldValueSet **value_set)
+{
+ g_assert_not_reached();
+}
--
2.52.0
^ permalink raw reply related [flat|nested] 29+ messages in thread* Re: [RFC PATCH v3 16/19] qmp: add query-cpu-props-info command
2026-07-16 21:38 ` [RFC PATCH v3 16/19] qmp: add query-cpu-props-info command Khushit Shah
@ 2026-07-20 13:21 ` Markus Armbruster
0 siblings, 0 replies; 29+ messages in thread
From: Markus Armbruster @ 2026-07-20 13:21 UTC (permalink / raw)
To: Khushit Shah
Cc: qemu-devel, qemu-arm, kvmarm, eric.auger, cohuck, peter.maydell,
richard.henderson, maz, oliver.upton, berrange, abologna,
jdenemar, gshan, skolothumtho, sebott, philmd, yangjinqian1,
shaju.abraham, mark.caveayland, prerna.saxena
Series doesn't apply for me. I need to apply it to be able to check
rendered documentation. Could you push it somewhere I can pull?
^ permalink raw reply [flat|nested] 29+ messages in thread
* [RFC PATCH v3 17/19] target/arm: Report 0 as supported for ID fields gated by vCPU init flags
2026-07-16 21:38 [RFC PATCH v3 00/19] named CPU models for Arm64 on KVM Khushit Shah
` (15 preceding siblings ...)
2026-07-16 21:38 ` [RFC PATCH v3 16/19] qmp: add query-cpu-props-info command Khushit Shah
@ 2026-07-16 21:38 ` Khushit Shah
2026-07-16 21:38 ` [RFC PATCH v3 18/19] target/arm/qmp: hook blockers in query-cpu-definitions Khushit Shah
2026-07-16 21:38 ` [RFC PATCH v3 19/19] target/arm/kvm: fix host model writeback when kernel supports EL2 Khushit Shah
18 siblings, 0 replies; 29+ messages in thread
From: Khushit Shah @ 2026-07-16 21:38 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, prerna.saxena
When QEMU queries supported CPU properties 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 only shows the
enabled host value (e.g., 5) and omits 0. This will lead into falsely
flagging a model as blocked as the features can be masked by not
passing those flags. 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 042d5fe804..ce77758c87 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -1292,6 +1292,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 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 arm_field_get_supported_values(const ARM64SysRegField *field,
const ARMISARegisters *host_isar,
ArmFieldValueSet **value_set)
@@ -1304,6 +1322,13 @@ void 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 && arm_field_off_via_vcpu_flags(field)) {
+ ranges_add(ranges, 0, 0);
+ }
goto done;
}
--
2.52.0
^ permalink raw reply related [flat|nested] 29+ messages in thread* [RFC PATCH v3 18/19] target/arm/qmp: hook blockers in query-cpu-definitions
2026-07-16 21:38 [RFC PATCH v3 00/19] named CPU models for Arm64 on KVM Khushit Shah
` (16 preceding siblings ...)
2026-07-16 21:38 ` [RFC PATCH v3 17/19] target/arm: Report 0 as supported for ID fields gated by vCPU init flags Khushit Shah
@ 2026-07-16 21:38 ` Khushit Shah
2026-07-16 21:38 ` [RFC PATCH v3 19/19] target/arm/kvm: fix host model writeback when kernel supports EL2 Khushit Shah
18 siblings, 0 replies; 29+ messages in thread
From: Khushit Shah @ 2026-07-16 21:38 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, prerna.saxena
Now, report blocker for named cpu models in query-cpu-definitions.
Heavy handling is done by validating the realized ID registers values
against the host values. sveNNNN needs special handling as those
are not stored in any ID registers.
Introduces arm_cpu_class_check_missing_features() and
aarch64_idregs_get_blockers() to achieve this. This way we need not
instantiate each model to check if it can be realized and we also get
granular information on the ID reg fields blocking the realization.
Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
---
target/arm/arm-cpu-models-stub.c | 5 ++++
target/arm/arm-cpu-models.c | 35 ++++++++++++++++++++++
target/arm/arm-cpu-models.h | 2 ++
target/arm/arm-qmp-cmds.c | 12 ++++++++
target/arm/cpu64.c | 51 ++++++++++++++++++++++++++++++++
target/arm/internals.h | 3 ++
target/arm/kvm-stub.c | 10 +++++++
target/arm/kvm.c | 4 +--
target/arm/kvm_arm.h | 17 +++++++++++
9 files changed, 137 insertions(+), 2 deletions(-)
diff --git a/target/arm/arm-cpu-models-stub.c b/target/arm/arm-cpu-models-stub.c
index 0481f0f946..dadd3b7647 100644
--- a/target/arm/arm-cpu-models-stub.c
+++ b/target/arm/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/arm-cpu-models.c b/target/arm/arm-cpu-models.c
index 40e8578591..44e7d3cfa2 100644
--- a/target/arm/arm-cpu-models.c
+++ b/target/arm/arm-cpu-models.c
@@ -475,6 +475,41 @@ static void arm_named_cpu_initfn(Object *obj)
arm_realize_model_chain(obj, model, &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)) {
+ arm_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));
+ }
+ }
+ }
+ }
+ }
+
+ aarch64_idregs_get_blockers(cpu, kvm_arm_get_host_isar(), blockers);
+out:
+ object_unref(obj);
+}
+
void arm_register_named_cpu_models(void)
{
size_t i;
diff --git a/target/arm/arm-cpu-models.h b/target/arm/arm-cpu-models.h
index ac4e510499..6c8fba2aeb 100644
--- a/target/arm/arm-cpu-models.h
+++ b/target/arm/arm-cpu-models.h
@@ -7,6 +7,7 @@
#include "qapi/error.h"
#include "qom/object.h"
+#include "cpu.h"
typedef enum ArmModelPropType {
ARM_MODEL_PROP_BOOL,
@@ -31,5 +32,6 @@ typedef struct ArmNamedCpuModel {
void arm_register_named_cpu_models(void);
const ArmNamedCpuModel *arm_find_model(const char *name);
+void arm_cpu_class_check_missing_features(ARMCPUClass *acc, strList **blockers);
#endif /* ARM_CPU_MODELS_H */
diff --git a/target/arm/arm-qmp-cmds.c b/target/arm/arm-qmp-cmds.c
index 457cc3edf3..6f11681c87 100644
--- a/target/arm/arm-qmp-cmds.c
+++ b/target/arm/arm-qmp-cmds.c
@@ -341,6 +341,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/cpu64.c b/target/arm/cpu64.c
index 44dd9acf80..f41bcf2e81 100644
--- a/target/arm/cpu64.c
+++ b/target/arm/cpu64.c
@@ -20,6 +20,7 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
+#include "qapi/util.h"
#include "cpu.h"
#include "cpregs.h"
#include "qemu/module.h"
@@ -779,6 +780,56 @@ void aarch64_add_idregs_properties(Object *obj)
aarch64_add_idreg_properties(obj, reg);
}
}
+
+void aarch64_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.
+ */
+ 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));
+ }
+ }
+ }
+}
#endif
void aarch64_add_pauth_properties(Object *obj)
diff --git a/target/arm/internals.h b/target/arm/internals.h
index 7502b6db8a..d05e35ba83 100644
--- a/target/arm/internals.h
+++ b/target/arm/internals.h
@@ -1756,6 +1756,9 @@ void aarch64_add_sve_properties(Object *obj);
void aarch64_add_sme_properties(Object *obj);
#ifndef CONFIG_USER_ONLY
void aarch64_add_idregs_properties(Object *obj);
+void aarch64_idregs_get_blockers(ARMCPU *cpu,
+ const ARMISARegisters *host_isar,
+ strList **blockers);
#endif
/* Return true if the gdbstub is presenting an AArch64 CPU */
diff --git a/target/arm/kvm-stub.c b/target/arm/kvm-stub.c
index d19c53927d..eb8fdda236 100644
--- a/target/arm/kvm-stub.c
+++ b/target/arm/kvm-stub.c
@@ -131,3 +131,13 @@ void arm_field_get_supported_values(const ARM64SysRegField *field,
{
g_assert_not_reached();
}
+
+bool arm_field_skip_writeback_always(const ARM64SysRegField *field)
+{
+ g_assert_not_reached();
+}
+
+bool arm_field_skip_writeback_if_not_writable(const ARM64SysRegField *field)
+{
+ g_assert_not_reached();
+}
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index ce77758c87..b909a11dfd 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -1394,7 +1394,7 @@ done:
(*value_set)->ranges = (ArmFieldRange *)g_array_free(ranges, false);
}
-static bool arm_field_skip_writeback_always(const ARM64SysRegField *field)
+bool arm_field_skip_writeback_always(const ARM64SysRegField *field)
{
/*
* GIC is controlled by the gic-version property and fabricated by KVM
@@ -1412,7 +1412,7 @@ static bool arm_field_skip_writeback_always(const ARM64SysRegField *field)
|| field->index == CLIDR_EL1_IDX;
}
-static bool arm_field_skip_writeback_if_not_writable(const ARM64SysRegField *field)
+bool arm_field_skip_writeback_if_not_writable(const ARM64SysRegField *field)
{
/*
* KVM populates ID_DFR0_EL1.PerfMon even for AArch64-only guests but
diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h
index 4a04d72e39..6409bec735 100644
--- a/target/arm/kvm_arm.h
+++ b/target/arm/kvm_arm.h
@@ -172,6 +172,23 @@ void arm_field_get_supported_values(const ARM64SysRegField *field,
const ARMISARegisters *host_isar,
ArmFieldValueSet **value_set);
+/**
+ * arm_field_skip_writeback_always:
+ * @field: the ID-register field to test
+ *
+ * Returns: true if @field must never be written back to KVM (and so may
+ * legitimately differ from the host value).
+ */
+bool arm_field_skip_writeback_always(const ARM64SysRegField *field);
+
+/**
+ * arm_field_skip_writeback_if_not_writable:
+ * @field: the ID-register field to test
+ *
+ * Returns: true if @field should be skipped when it is not writable.
+ */
+bool arm_field_skip_writeback_if_not_writable(const ARM64SysRegField *field);
+
/**
* kvm_arm_steal_time_finalize:
* @cpu: ARMCPU for which to finalize kvm-steal-time
--
2.52.0
^ permalink raw reply related [flat|nested] 29+ messages in thread* [RFC PATCH v3 19/19] target/arm/kvm: fix host model writeback when kernel supports EL2
2026-07-16 21:38 [RFC PATCH v3 00/19] named CPU models for Arm64 on KVM Khushit Shah
` (17 preceding siblings ...)
2026-07-16 21:38 ` [RFC PATCH v3 18/19] target/arm/qmp: hook blockers in query-cpu-definitions Khushit Shah
@ 2026-07-16 21:38 ` Khushit Shah
18 siblings, 0 replies; 29+ messages in thread
From: Khushit Shah @ 2026-07-16 21:38 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, prerna.saxena
kvm_arm_get_host_cpu_features() probes the host by spinning up a
scratch vCPU and reading its ID registers. When the host kernel
advertises nested virtualization, the scratch is created with
KVM_ARM_VCPU_HAS_EL2, which makes the kernel run limit_nv_id_reg()
on that vCPU and force several fields (e.g. ID_AA64MMFR4_EL1.NV_frac,
parts of ID_AA64DFR0_EL1) to values that match KVM's nested-virt
capabilities rather than the raw host.
If the actual vCPU is later created without EL2 (e.g. -machine
virt,virtualization=off), the EL2-on values cached above no longer
match what the kernel exposes for the real vCPU and ID-register
writeback fails.
Fix this by caching two host views, one probed with EL2 and one
without, and selecting the appropriate view at every use site.
For -cpu host (and -cpu max) without EL2 we additionally rebase
cpu->isar.idregs[] from the EL2-on view it was initialized with
onto the EL2-off view via kvm_arm_rebase_host_idregs(), so each
field that the user has not explicitly touched picks up the value
that the real vCPU will actually see.
Corner case: the rebase compares the post-init field value against
the EL2-on host value to decide whether the user set it. If the
user directly or indirectly set field X=i and the EL2-on view also
reports feat_X=i but the EL2-off view reports feat_X=j, the rebase
cannot distinguish "user asked for i" from "inherited i from host" and
will overwrite with j. This only affects -cpu host/max without EL2
on NV enabled kernels where the user-requested value happens to match
the EL2-on host view, so we avoid the complexity of user set values
tracking and accept the loss here.
Named models are not affected with the issue as they already start
with default-zeroed view.
Signed-off-by: Khushit Shah <khushit.shah@nutanix.com>
---
target/arm/arm-cpu-models.c | 14 +++++-
target/arm/arm-qmp-cmds.c | 2 +-
target/arm/cpu64.c | 2 +-
target/arm/kvm-stub.c | 4 +-
target/arm/kvm.c | 93 ++++++++++++++++++++++++++++++-------
target/arm/kvm_arm.h | 5 +-
6 files changed, 94 insertions(+), 26 deletions(-)
diff --git a/target/arm/arm-cpu-models.c b/target/arm/arm-cpu-models.c
index 44e7d3cfa2..a41f1f1169 100644
--- a/target/arm/arm-cpu-models.c
+++ b/target/arm/arm-cpu-models.c
@@ -459,7 +459,12 @@ static void arm_named_cpu_initfn(Object *obj)
return;
}
- kvm_arm_set_cpu_features_from_host(cpu);
+ /*
+ * Start with the host view without EL2.
+ * If nested virt is needed user must provide values for all the
+ * blockers.
+ */
+ kvm_arm_set_cpu_features_from_host(cpu, false);
if (!arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) {
return;
}
@@ -481,10 +486,15 @@ void arm_cpu_class_check_missing_features(ARMCPUClass *acc, strList **blockers)
Object *obj = object_new_with_class(OBJECT_CLASS(acc));
ARMCPU *cpu = ARM_CPU(obj);
+ const ARMISARegisters *host_isar;
+
if (!kvm_enabled() || !arm_find_model(acc->info->name)) {
goto out;
}
+ /* Use the host view without EL2 to calculate blockers. */
+ host_isar = kvm_arm_get_host_isar(false);
+
if (cpu_isar_feature(aa64_sve, cpu)) {
arm_cpu_sve_finalize(cpu, &err);
if (err) {
@@ -505,7 +515,7 @@ void arm_cpu_class_check_missing_features(ARMCPUClass *acc, strList **blockers)
}
}
- aarch64_idregs_get_blockers(cpu, kvm_arm_get_host_isar(), blockers);
+ aarch64_idregs_get_blockers(cpu, host_isar, blockers);
out:
object_unref(obj);
}
diff --git a/target/arm/arm-qmp-cmds.c b/target/arm/arm-qmp-cmds.c
index 6f11681c87..8dcff6c22c 100644
--- a/target/arm/arm-qmp-cmds.c
+++ b/target/arm/arm-qmp-cmds.c
@@ -102,7 +102,7 @@ CpuPropertyInfoList *qmp_query_cpu_props_info(Error **errp)
return NULL;
}
- host_isar = kvm_arm_get_host_isar();
+ host_isar = kvm_arm_get_host_isar(false);
/*
* Spin up a scratch "host" vCPU object and walk its QOM properties.
diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
index f41bcf2e81..c7556bfd52 100644
--- a/target/arm/cpu64.c
+++ b/target/arm/cpu64.c
@@ -1050,7 +1050,7 @@ static void aarch64_host_initfn(Object *obj)
#if defined(CONFIG_KVM)
kvm_arm_set_cpreg_mig_tolerances(cpu);
- kvm_arm_set_cpu_features_from_host(cpu);
+ kvm_arm_set_cpu_features_from_host(cpu, true);
aarch64_add_sve_properties(obj);
#ifndef CONFIG_USER_ONLY
diff --git a/target/arm/kvm-stub.c b/target/arm/kvm-stub.c
index eb8fdda236..1a713cb904 100644
--- a/target/arm/kvm-stub.c
+++ b/target/arm/kvm-stub.c
@@ -45,7 +45,7 @@ bool kvm_arm_el2_supported(void)
/*
* These functions should never actually be called without KVM support.
*/
-void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu)
+void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu, bool with_el2)
{
g_assert_not_reached();
}
@@ -120,7 +120,7 @@ char *kvm_print_register_name(uint64_t regidx)
g_assert_not_reached();
}
-const ARMISARegisters *kvm_arm_get_host_isar(void)
+const ARMISARegisters *kvm_arm_get_host_isar(bool with_el2)
{
return NULL;
}
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index b909a11dfd..f2635980eb 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -67,7 +67,7 @@ typedef struct ARMHostCPUFeatures {
const char *dtb_compatible;
} ARMHostCPUFeatures;
-static ARMHostCPUFeatures arm_host_cpu_features;
+static ARMHostCPUFeatures arm_host_cpu_features[2];
/**
* kvm_arm_vcpu_init:
@@ -363,8 +363,7 @@ static int get_host_cpu_idregs(int fd, ARMHostCPUFeatures *ahcf)
}
-static void
-kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
+static void kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf, bool with_el2)
{
/* Identify the feature bits corresponding to the host CPU, and
* fill out the ARMHostCPUClass fields accordingly. To do this
@@ -404,7 +403,7 @@ kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
* Ask for EL2 if supported.
*/
el2_supported = kvm_arm_el2_supported();
- if (el2_supported) {
+ if (el2_supported && with_el2) {
init.features[0] |= 1 << KVM_ARM_VCPU_HAS_EL2;
}
@@ -553,7 +552,7 @@ kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
err |= get_host_cpu_reg(fd, ahcf, ID_AA64ZFR0_EL1_IDX);
/* Read the set of supported vector lengths. */
- arm_host_cpu_features.sve_vq_supported = kvm_arm_sve_get_vls(fd);
+ ahcf->sve_vq_supported = kvm_arm_sve_get_vls(fd);
}
}
@@ -604,7 +603,7 @@ static int kvm_arm_get_writable_id_regs(uint64_t *idregmap)
return 0;
}
-void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu)
+void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu, bool with_el2)
{
CPUARMState *env = &cpu->env;
uint64_t *writable_map;
@@ -629,11 +628,11 @@ void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu)
}
g_free(writable_map);
- if (!arm_host_cpu_features.dtb_compatible) {
- kvm_arm_get_host_cpu_features(&arm_host_cpu_features);
+ if (!arm_host_cpu_features[with_el2].dtb_compatible) {
+ kvm_arm_get_host_cpu_features(&arm_host_cpu_features[with_el2], with_el2);
}
- cpu->kvm_target = arm_host_cpu_features.target;
+ cpu->kvm_target = arm_host_cpu_features[with_el2].target;
if (cpu->kvm_target == QEMU_KVM_ARM_TARGET_NONE) {
/*
@@ -644,18 +643,18 @@ void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu)
return;
}
- cpu->dtb_compatible = arm_host_cpu_features.dtb_compatible;
- cpu->isar = arm_host_cpu_features.isar;
- cpu->sve_vq.supported = arm_host_cpu_features.sve_vq_supported;
- env->features = arm_host_cpu_features.features;
+ cpu->dtb_compatible = arm_host_cpu_features[with_el2].dtb_compatible;
+ cpu->isar = arm_host_cpu_features[with_el2].isar;
+ cpu->sve_vq.supported = arm_host_cpu_features[with_el2].sve_vq_supported;
+ env->features = arm_host_cpu_features[with_el2].features;
}
-const ARMISARegisters *kvm_arm_get_host_isar(void)
+const ARMISARegisters *kvm_arm_get_host_isar(bool with_el2)
{
- if (!arm_host_cpu_features.dtb_compatible) {
- kvm_arm_get_host_cpu_features(&arm_host_cpu_features);
+ if (!arm_host_cpu_features[with_el2].dtb_compatible) {
+ kvm_arm_get_host_cpu_features(&arm_host_cpu_features[with_el2], with_el2);
}
- return &arm_host_cpu_features.isar;
+ return &arm_host_cpu_features[with_el2].isar;
}
static bool kvm_no_adjvtime_get(Object *obj, Error **errp)
@@ -1438,6 +1437,7 @@ static int kvm_arm_write_idregs_to_cpreg_list(ARMCPU *cpu)
uint64_t writable_mask = sysregdesc->writable_mask;
uint64_t desired = cpu->isar.idregs[i];
uint64_t previous, updated;
+ bool has_el2 = cpu->has_el2;
uint64_t *cpreg;
cpreg = kvm_arm_find_cpreg_ptr(cpu, idregs_sysreg_to_kvm_reg(sysreg));
@@ -1447,7 +1447,7 @@ static int kvm_arm_write_idregs_to_cpreg_list(ARMCPU *cpu)
* 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];
+ previous = cpreg ? *cpreg : kvm_arm_get_host_isar(has_el2)->idregs[i];
if (previous == desired) {
continue;
@@ -2332,6 +2332,50 @@ bool kvm_arm_mte_supported(void)
return kvm_check_extension(kvm_state, KVM_CAP_ARM_MTE);
}
+/*
+ * Rebase cpu->isar.idregs[] on top of new_isar given the initial_isar.
+ *
+ * For fields in cpu->isar.idregs[] that are same as initial_isar, update
+ * the field with the new_isar values.
+ */
+static void kvm_arm_rebase_host_idregs(ARMCPU *cpu,
+ const ARMISARegisters *new_isar,
+ const ARMISARegisters *initial_isar)
+{
+ for (int i = 0; i < NUM_ID_IDX; i++) {
+ ARM64SysReg *sysregdesc = &arm64_id_regs[i];
+
+ for (int j = 0; j < sysregdesc->fields_count; j++) {
+ const ARM64SysRegField *field = &sysregdesc->fields[j];
+ uint64_t idreg_val = extract64(cpu->isar.idregs[i],
+ field->shift, field->length);
+ uint64_t initial_val = extract64(initial_isar->idregs[i],
+ field->shift, field->length);
+ uint64_t new_val = extract64(new_isar->idregs[i],
+ field->shift, field->length);
+
+ if (idreg_val == initial_val && new_val != idreg_val) {
+ /*
+ * The cpu->isar.idregs[]'s field val is same as
+ * initial_isar.idregs[]'s field val, which was used to
+ * initialise it. Hence, override it with the new_isar[]
+ * value. User might have explicitly asked for some value
+ * which matched the host value without EL2 in this case,
+ * that value is lost. As rebase is needed in very specific
+ * case, we avoid that complication.
+ */
+ cpu->isar.idregs[i] = deposit64(cpu->isar.idregs[i],
+ field->shift, field->length,
+ new_val);
+
+ warn_report("KVM ID %s.%s value changed from 0x%016"
+ PRIx64 " to 0x%016" PRIx64,
+ sysregdesc->name, field->name, idreg_val, new_val);
+ }
+ }
+ }
+}
+
QEMU_BUILD_BUG_ON(KVM_ARM64_SVE_VQ_MIN != 1);
static int kvm_arm_sve_set_vls(ARMCPU *cpu)
@@ -2450,11 +2494,24 @@ int kvm_arch_init_vcpu(CPUState *cs)
if (ret) {
return ret;
}
+
+ /* For -cpu host/max, rebase the idregs[] on top of cpregs[] */
+ if ((object_dynamic_cast(OBJECT(cpu), TYPE_ARM_HOST_CPU)
+ || object_dynamic_cast(OBJECT(cpu), TYPE_ARM_MAX_CPU))
+ && !cpu->has_el2
+ && kvm_arm_el2_supported()) {
+ /* scratch vCPU is created with EL2-enabled for -cpu host */
+ kvm_arm_rebase_host_idregs(cpu,
+ kvm_arm_get_host_isar(false),
+ kvm_arm_get_host_isar(true));
+ }
+
/* 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/kvm_arm.h b/target/arm/kvm_arm.h
index 6409bec735..847efb1c8d 100644
--- a/target/arm/kvm_arm.h
+++ b/target/arm/kvm_arm.h
@@ -129,11 +129,12 @@ void kvm_arm_destroy_scratch_host_vcpu(int *fdarray);
/**
* kvm_arm_set_cpu_features_from_host:
* @cpu: ARMCPU to set the features for
+ * @with_el2: probe the host with the EL2-enabled scratch vCPU view
*
* Set up the ARMCPU struct fields up to match the information probed
* from the host CPU.
*/
-void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu);
+void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu, bool with_el2);
/**
* kvm_arm_add_vcpu_properties:
@@ -276,7 +277,7 @@ 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);
+const ARMISARegisters *kvm_arm_get_host_isar(bool with_el2);
void arm_gic_cap_kvm_probe(GICCapability *v2, GICCapability *v3);
--
2.52.0
^ permalink raw reply related [flat|nested] 29+ messages in thread