On 7/27/25 1:02 AM, Richard Henderson wrote:
The ARM now defines 36 bits in SPSR_ELx in aarch64 mode, so
it's time to bite the bullet and extend PSTATE to match.
Most changes are straightforward, adjusting printf formats,
changing local variable types. More complex is migration,
where to maintain backward compatibility a new pstate64
record is introduced, and only when one of the extensions
that sets bits 32-35 are active.
The fate of gdbstub is left undecided for the moment.
Signed-off-by: Richard Henderson <richard.hender...@linaro.org>
---
target/arm/cpu.h | 8 +++---
target/arm/tcg/translate.h | 20 ++++++-------
target/arm/cpu.c | 6 ++--
target/arm/gdbstub64.c | 1 +
target/arm/helper.c | 11 ++++----
target/arm/machine.c | 56 +++++++++++++++++++++++++++++++++++++
target/arm/tcg/helper-a64.c | 2 +-
7 files changed, 81 insertions(+), 23 deletions(-)
...
diff --git a/target/arm/gdbstub64.c b/target/arm/gdbstub64.c
index 64ee9b3b56..3cef47281a 100644
--- a/target/arm/gdbstub64.c
+++ b/target/arm/gdbstub64.c
@@ -47,6 +47,7 @@ int aarch64_cpu_gdb_read_register(CPUState *cs, GByteArray
*mem_buf, int n)
case 32:
return gdb_get_reg64(mem_buf, env->pc);
case 33:
+ /* pstate is now a 64-bit value; can we simply adjust the xml? */
return gdb_get_reg32(mem_buf, pstate_read(env));
}
If I'm correct, we currently don't expose PSTATE through gdbstub, but
only CPSR. This was a bit confusing for me, considering that CPSR is not
even supposed to exist in Aarch64.
Maybe it's a good opportunity to expose PSTATE instead, which could have
a 64 bits size. This way, we don't break any workflow.
...
diff --git a/target/arm/machine.c b/target/arm/machine.c
index 8dbeca2867..9b00c14b4a 100644
--- a/target/arm/machine.c
+++ b/target/arm/machine.c
@@ -836,6 +836,61 @@ static const VMStateInfo vmstate_cpsr = {
.put = put_cpsr,
};
+static int get_pstate64_1(QEMUFile *f, void *opaque, size_t size,
+ const VMStateField *field)
+{
+ ARMCPU *cpu = opaque;
+ CPUARMState *env = &cpu->env;
+ uint64_t val = qemu_get_be64(f);
+
+ env->aarch64 = ((val & PSTATE_nRW) == 0);
+ pstate_write(env, val);
+ return 0;
+}
+
+static int put_pstate64_1(QEMUFile *f, void *opaque, size_t size,
+ const VMStateField *field, JSONWriter *vmdesc)
+{
+ ARMCPU *cpu = opaque;
+ CPUARMState *env = &cpu->env;
+ uint64_t val = pstate_read(env);
+
+ qemu_put_be64(f, val);
+ return 0;
+}
+
+static const VMStateInfo vmstate_pstate64_1 = {
+ .name = "pstate64",
+ .get = get_pstate64_1,
+ .put = put_pstate64_1,
+};
+
+static bool pstate64_needed(void *opaque)
+{
+ ARMCPU *cpu = opaque;
+ CPUARMState *env = &cpu->env;
+
+ return is_a64(env) && pstate_read(env) > UINT32_MAX;
+}
+
+static const VMStateDescription vmstate_pstate64 = {
+ .name = "cpu/pstate64",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = pstate64_needed,
+ .fields = (const VMStateField[]) {
+ {
+ .name = "pstate64",
+ .version_id = 0,
+ .size = sizeof(uint64_t),
+ .info = &vmstate_pstate64_1,
+ .flags = VMS_SINGLE,
+ .offset = 0,
+ },
+ VMSTATE_END_OF_LIST()
+ },
+};
+
static int get_power(QEMUFile *f, void *opaque, size_t size,
const VMStateField *field)
{
@@ -1119,6 +1174,7 @@ const VMStateDescription vmstate_arm_cpu = {
&vmstate_serror,
&vmstate_irq_line_state,
&vmstate_wfxt_timer,
+ &vmstate_pstate64,
NULL
}
};
diff --git a/target/arm/tcg/helper-a64.c b/target/arm/tcg/helper-a64.c
index 71c6c44ee8..f61adf1f80 100644
--- a/target/arm/tcg/helper-a64.c
+++ b/target/arm/tcg/helper-a64.c
@@ -639,7 +639,7 @@ void HELPER(exception_return)(CPUARMState *env, uint64_t
new_pc)
ARMCPU *cpu = env_archcpu(env);
int cur_el = arm_current_el(env);
unsigned int spsr_idx = aarch64_banked_spsr_index(cur_el);
- uint32_t spsr = env->banked_spsr[spsr_idx];
+ uint64_t spsr = env->banked_spsr[spsr_idx];
int new_el;
bool return_to_aa64 = (spsr & PSTATE_nRW) == 0;
Would that be better or worse to simply save the upper 32 bits,
considering that cpsr already holds the lower ones in Aarch64 mode?