On 9/7/26 03:02, Peter Maydell wrote:
For Arm, the format we use on the wire for migration of sysregs
(cpregs on AArch32) is a set of arrays, where cpreg_indexes[] holds
the register IDs and cpreg_values[] holds the corresponding values.
The ID format we use is KVM's ID format, which is 64 bits.  This is
not quite the same as the 32-bit ID format QEMU uses internally for
things like the coprocessor register hashtable keys, and so we have
conversion functions kvm_to_cpreg_id() and cpreg_to_kvm_id() to swap
between them.

This conversion has never handled AArch32 Secure coprocessor
registers correctly: the KVM ID format has no way to indicate a
Secure register, because KVM VMs on AArch32 were always NonSecure.
The current code doesn't touch the CP_REG_AA32_NS_MASK bit when
converting from the 32-bit ID format to a KVM ID, and it forces the
NS bit to 1 when converting from a KVM ID to a cpreg.  The effect of
this on migration is that the indexes in cpreg_indexes[] have NS = 0
for the Secure banked registers and NS = 1 for the NS banked
registers, but when we read and write the values into the CPUState by
finding the register using kvm_to_cpreg_id(cpreg_indexes[i]) we
always find the NS register, and so the S register values aren't
actually migrated.

This went unnoticed most of the time because a typical Linux guest is
running only in NS and doesn't really care about the S register
state, but it breaks migration of a guest which is running in S, such
as Linux on the imx boards.

This would be more awkward to fix if KVM still supported AArch32
hosts, but luckily that was dropped some years ago, and AArch32
guests on an AArch64 host expose the sysregs as CP_REG_ARM64, not
CP_REG_ARM32.  So the only place where we use a CP_REG_ARM32 KVM
register ID is for TCG migrations.  We can therefore (continue to)
steal a bit in the KVM format for the NS bit, with the semantics
we've given it on the wire in the past.  We just need to let
kvm_to_cpreg_id() pass it through rather than forcing it to 1.

To retain compatibility with migration from older QEMU versions
without this fix, we need to add a subsection to the migration data
that tells the destination that it can trust the values for Secure
banked registers.  For incoming migrations, if we don't see this then
we ignore all the values for Secure banked registers, giving the same
behaviour as before.  This means we continue to work for migrations
where the Secure world exists but the guest is basically not using
it, such as a direct kernel boot on boards which don't set
arm_boot_info::secure_boot to true; this includes the cubieboard,
bananapi and orangepi.

Attempting migration from a new QEMU to an older QEMU version will
now fail cleanly (because the destination doesn't recognize the new
subsection) rather than silently corrupting the Secure banked
registers.

Resolves:https://gitlab.com/qemu-project/qemu/-/work_items/467
Signed-off-by: Peter Maydell<[email protected]>
---
  target/arm/cpregs.h  | 21 ++++++++----
  target/arm/cpu.h     |  6 ++++
  target/arm/machine.c | 80 ++++++++++++++++++++++++++++++++++++++++++++
  3 files changed, 100 insertions(+), 7 deletions(-)

Reviewed-by: Richard Henderson <[email protected]>

r~

Reply via email to