* [RFC v2 00/24] Add Realm support to QEMU-VMM
@ 2026-07-28 19:26 Mathieu Poirier
2026-07-28 19:26 ` [RFC v2 01/24] linux-headers: Add RME related definitions Mathieu Poirier
` (24 more replies)
0 siblings, 25 replies; 30+ messages in thread
From: Mathieu Poirier @ 2026-07-28 19:26 UTC (permalink / raw)
To: berrange, kchamart, pierrick.bouvier, peter.maydell, mst, cohuck,
pbonzini, eblake, armbru, lorenzo.pieralisi, gshan
Cc: qemu-devel, qemu-arm, kvm
This patchset provides minimal functionality to start a Realm VM
from an Arm RME capable host using the following command line:
qemu-system-aarch64 \
-M confidential-guest-support=rme0 -object rme-guest,id=rme0 \
-cpu host -M virt -enable-kvm -M gic-version=3,its=on -nodefaults ..
It is a refactoring of Jean-Philippe Brucker's initial work dating from a while
back. It is compatible with Steven Price's v14 revision [1] of his work adding
CCA support to KVM.
* We are currently working on rebasing the work to v15.
It was tested on the QEMU SBSA machine. For convenience, a repository is hosted
here [2], along with the TF-A [3], RMM [4] and Linux kernel [5] for the SBSA
machine (compatible with Steven's v14 patchset).
Instructions to compile and run the entire stack can be found here [6].
Device Assignment is not included.
Thanks,
Mathieu
[1]. https://lore.kernel.org/kvm/20260513131757.116630-1-steven.price@arm.com/T/#m06dd14216aaf76acab65b0a76fb84653141ea64f
[2]. https://gitlab.com/Linaro/cca-public/qemu/-/tree/upstream-v2?ref_type=heads
[3]. https://gitlab.com/Linaro/cca-public/tf-a/trusted-firmware-a/-/tree/cca/v13?ref_type=heads
[4]. https://gitlab.com/Linaro/cca-public/rmm/-/tree/cca/v14?ref_type=heads
[5]. https://gitlab.com/Linaro/cca-public/linux/-/tree/upstream-v2?ref_type=heads
[6]. https://gitlab.com/Linaro/cca-public/build-instructions
RFC v1:
https://lists.gnu.org/archive/html/qemu-devel/2026-07/msg02307.html
Changes for V2:
- Fixed linux headers to include correct bit shift for Realm VM (Gavin).
- Removed obsolete rme-guest options (Markus).
- Set ConfidentialGuestSupportClass::kvm_init() to kvm_arm_rme_init() (Gavin).
- Got rid of kvm_arm_rme_vm_type() (Gavin).
- Used kvm_vm_check_extension() instead of kvm_check_extension() to avoid
error message when starting a Realm (Gavin).
- Removed obsolete kvm_arm_rme_init_guest_ram() (Gavin).
- Collected A-B and R-B.
Jean-Philippe Brucker (23):
linux-headers: Add RME related definitions
target/arm/kvm: Return immediately on error in kvm_arch_init()
target/arm: Add confidential guest support
target/arm/kvm: Split kvm_arch_get/put_registers
target/arm/kvm-rme: Initialize vCPU
target/arm/kvm: Create scratch Realm VM when requested
target/arm/kvm: Use kvm_vm_check_extension() where necessary
hw/core/loader: Add a ROM loader notifier
target/arm/kvm-rme: Keep track of images loaded in Realm memory
target/arm/kvm-rme: Populate Realm with runtime images
target/arm/cpu: Set number of breakpoints and watchpoints in KVM
target/arm/cpu: Set number of PMU counters in KVM
target/arm/cpu: Don't read Realm registers
hw/arm/virt: Set proper conduit method for Realms
hw/arm/virt: Embed Realm VM type with IPA address space
hw/arm/virt: Reserve one bit of guest physical address for RME
hw/arm/virt: Disable DTB randomness for confidential VMs
hw/arm/virt: Move virt_flash_create() to machvirt_init()
hw/arm/virt: Use RAM instead of flash for confidential guest firmware
target/arm/kvm-rme: Add DMA remapping for the shared memory region
docs/interop/firmware.json: Add arm-rme firmware feature
hw/arm/boot: Load DTB as is for confidential VMs
hw/arm/boot: Skip bootloader for confidential guests
Mathieu Poirier (1):
target/arm/kvm-rme: Add mechanic to initialize realms
docs/interop/firmware.json | 5 +-
docs/system/arm/virt.rst | 9 +-
docs/system/confidential-guest-support.rst | 1 +
hw/arm/boot.c | 70 ++++-
hw/arm/virt.c | 142 ++++++++--
hw/core/loader.c | 15 +
include/hw/arm/boot.h | 9 +
include/hw/arm/virt.h | 2 +-
include/hw/core/loader.h | 17 ++
linux-headers/asm-arm64/kvm.h | 9 +
linux-headers/linux/kvm.h | 10 +-
qapi/qom.json | 1 +
target/arm/arm-qmp-cmds.c | 1 +
target/arm/cpu.c | 5 +
target/arm/cpu.h | 10 +
target/arm/cpu64.c | 122 ++++++++
target/arm/kvm-rme.c | 313 +++++++++++++++++++++
target/arm/kvm-stub.c | 9 +
target/arm/kvm.c | 202 ++++++++++++-
target/arm/kvm_arm.h | 20 ++
target/arm/meson.build | 5 +-
21 files changed, 927 insertions(+), 50 deletions(-)
create mode 100644 target/arm/kvm-rme.c
--
2.43.0
^ permalink raw reply [flat|nested] 30+ messages in thread
* [RFC v2 01/24] linux-headers: Add RME related definitions
2026-07-28 19:26 [RFC v2 00/24] Add Realm support to QEMU-VMM Mathieu Poirier
@ 2026-07-28 19:26 ` Mathieu Poirier
2026-07-30 5:41 ` Kohei Enju
2026-07-28 19:26 ` [RFC v2 02/24] target/arm/kvm: Return immediately on error in kvm_arch_init() Mathieu Poirier
` (23 subsequent siblings)
24 siblings, 1 reply; 30+ messages in thread
From: Mathieu Poirier @ 2026-07-28 19:26 UTC (permalink / raw)
To: berrange, kchamart, pierrick.bouvier, peter.maydell, mst, cohuck,
pbonzini, eblake, armbru, lorenzo.pieralisi, gshan
Cc: qemu-devel, qemu-arm, kvm
From: Jean-Philippe Brucker <jean-philippe@linaro.org>
This is a temporary patch intended for testing purposes only. It provides
definitions related to supporting Realms by the QEMU-VMM.
Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org>
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
| 9 +++++++++
| 10 +++++++++-
2 files changed, 18 insertions(+), 1 deletion(-)
--git a/linux-headers/asm-arm64/kvm.h b/linux-headers/asm-arm64/kvm.h
index 6aefe7973814..4c08631ec7d2 100644
--- a/linux-headers/asm-arm64/kvm.h
+++ b/linux-headers/asm-arm64/kvm.h
@@ -208,6 +208,15 @@ struct kvm_arm_counter_offset {
__u64 reserved;
};
+#define KVM_ARM_RMI_POPULATE_FLAGS_MEASURE (1 << 0)
+struct kvm_arm_rmi_populate {
+ __u64 base;
+ __u64 size;
+ __u64 source_uaddr;
+ __u32 flags;
+ __u32 reserved;
+};
+
#define KVM_ARM_TAGS_TO_GUEST 0
#define KVM_ARM_TAGS_FROM_GUEST 1
--git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h
index dd52e2a65bfd..cdd5ad11f85a 100644
--- a/linux-headers/linux/kvm.h
+++ b/linux-headers/linux/kvm.h
@@ -689,14 +689,19 @@ struct kvm_enable_cap {
* address size for the VM. Bits[7-0] are reserved for the guest
* PA size shift (i.e, log2(PA_Size)). For backward compatibility,
* value 0 implies the default IPA size, 40bits.
+ *
+ * Bits[30-31] are reserved for the VM type
*/
#define KVM_VM_TYPE_ARM_IPA_SIZE_MASK 0xffULL
#define KVM_VM_TYPE_ARM_IPA_SIZE(x) \
((x) & KVM_VM_TYPE_ARM_IPA_SIZE_MASK)
+#define KVM_VM_TYPE_ARM_NORMAL 0
+#define KVM_VM_TYPE_ARM_REALM (1UL << 30)
#define KVM_VM_TYPE_ARM_PROTECTED (1UL << 31)
#define KVM_VM_TYPE_ARM_MASK (KVM_VM_TYPE_ARM_IPA_SIZE_MASK | \
- KVM_VM_TYPE_ARM_PROTECTED)
+ KVM_VM_TYPE_ARM_PROTECTED | \
+ KVM_VM_TYPE_ARM_REALM)
/*
* ioctls for /dev/kvm fds:
@@ -719,6 +724,8 @@ struct kvm_enable_cap {
#define KVM_GET_EMULATED_CPUID _IOWR(KVMIO, 0x09, struct kvm_cpuid2)
#define KVM_GET_MSR_FEATURE_INDEX_LIST _IOWR(KVMIO, 0x0a, struct kvm_msr_list)
+#define KVM_ARM_RMI_POPULATE _IOWR(KVMIO, 0xd7, struct kvm_arm_rmi_populate)
+
/*
* Extension capability list.
*/
@@ -986,6 +993,7 @@ struct kvm_enable_cap {
#define KVM_CAP_S390_KEYOP 247
#define KVM_CAP_S390_VSIE_ESAMODE 248
#define KVM_CAP_S390_HPAGE_2G 249
+#define KVM_CAP_ARM_RMI 250
struct kvm_irq_routing_irqchip {
__u32 irqchip;
--
2.43.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [RFC v2 02/24] target/arm/kvm: Return immediately on error in kvm_arch_init()
2026-07-28 19:26 [RFC v2 00/24] Add Realm support to QEMU-VMM Mathieu Poirier
2026-07-28 19:26 ` [RFC v2 01/24] linux-headers: Add RME related definitions Mathieu Poirier
@ 2026-07-28 19:26 ` Mathieu Poirier
2026-07-28 19:26 ` [RFC v2 03/24] target/arm: Add confidential guest support Mathieu Poirier
` (22 subsequent siblings)
24 siblings, 0 replies; 30+ messages in thread
From: Mathieu Poirier @ 2026-07-28 19:26 UTC (permalink / raw)
To: berrange, kchamart, pierrick.bouvier, peter.maydell, mst, cohuck,
pbonzini, eblake, armbru, lorenzo.pieralisi, gshan
Cc: qemu-devel, qemu-arm, kvm
From: Jean-Philippe Brucker <jean-philippe@linaro.org>
Returning an error to kvm_init() is fatal anyway, no need to continue
the initialization.
Leave the `ret` variable in the function scope because it will be reused
when adding RME support.
Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
target/arm/kvm.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index d40a6a985914..ed99be7fd80c 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -596,7 +596,7 @@ int kvm_arch_get_default_type(MachineState *ms)
int kvm_arch_init(MachineState *ms, KVMState *s)
{
- int ret = 0;
+ int ret;
/* For ARM interrupt delivery is always asynchronous,
* whether we are using an in-kernel VGIC or not.
*/
@@ -618,7 +618,7 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
!kvm_check_extension(s, KVM_CAP_ARM_IRQ_LINE_LAYOUT_2)) {
error_report("Using more than 256 vcpus requires a host kernel "
"with KVM_CAP_ARM_IRQ_LINE_LAYOUT_2");
- ret = -EINVAL;
+ return -EINVAL;
}
if (kvm_check_extension(s, KVM_CAP_ARM_NISV_TO_USER)) {
@@ -640,13 +640,14 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
warn_report("Eager Page Split support not available");
} else if (!(s->kvm_eager_split_size & sizes)) {
error_report("Eager Page Split requested chunk size not valid");
- ret = -EINVAL;
+ return -EINVAL;
} else {
ret = kvm_vm_enable_cap(s, KVM_CAP_ARM_EAGER_SPLIT_CHUNK_SIZE, 0,
s->kvm_eager_split_size);
if (ret < 0) {
error_report("Enabling of Eager Page Split failed: %s",
strerror(-ret));
+ return ret;
}
}
}
@@ -659,7 +660,7 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
hw_breakpoints = g_array_sized_new(true, true,
sizeof(HWBreakpoint), max_hw_bps);
- return ret;
+ return 0;
}
unsigned long kvm_arch_vcpu_id(CPUState *cpu)
--
2.43.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [RFC v2 03/24] target/arm: Add confidential guest support
2026-07-28 19:26 [RFC v2 00/24] Add Realm support to QEMU-VMM Mathieu Poirier
2026-07-28 19:26 ` [RFC v2 01/24] linux-headers: Add RME related definitions Mathieu Poirier
2026-07-28 19:26 ` [RFC v2 02/24] target/arm/kvm: Return immediately on error in kvm_arch_init() Mathieu Poirier
@ 2026-07-28 19:26 ` Mathieu Poirier
2026-07-28 19:26 ` [RFC v2 04/24] target/arm/kvm-rme: Add mechanic to initialize realms Mathieu Poirier
` (21 subsequent siblings)
24 siblings, 0 replies; 30+ messages in thread
From: Mathieu Poirier @ 2026-07-28 19:26 UTC (permalink / raw)
To: berrange, kchamart, pierrick.bouvier, peter.maydell, mst, cohuck,
pbonzini, eblake, armbru, lorenzo.pieralisi, gshan
Cc: qemu-devel, qemu-arm, kvm
From: Jean-Philippe Brucker <jean-philippe@linaro.org>
Add a new RmeGuest object, inheriting from ConfidentialGuestSupport, to
support the Arm Realm Management Extension (RME). It is instantiated by
passing on the command-line:
-M virt,confidential-guest-support=<id>
-object rme-guest,id=<id>
This is only the skeleton. Support will be added in following patches.
Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org>
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
docs/system/confidential-guest-support.rst | 1 +
qapi/qom.json | 1 +
target/arm/kvm-rme.c | 42 ++++++++++++++++++++++
target/arm/meson.build | 5 ++-
4 files changed, 48 insertions(+), 1 deletion(-)
create mode 100644 target/arm/kvm-rme.c
diff --git a/docs/system/confidential-guest-support.rst b/docs/system/confidential-guest-support.rst
index 562a7c3c2852..abb56923ad13 100644
--- a/docs/system/confidential-guest-support.rst
+++ b/docs/system/confidential-guest-support.rst
@@ -42,5 +42,6 @@ Currently supported confidential guest mechanisms are:
* POWER Protected Execution Facility (PEF) (see :ref:`power-papr-protected-execution-facility-pef`)
* s390x Protected Virtualization (PV) (see :doc:`s390x/protvirt`)
* AWS Nitro Enclaves (see :doc:`nitro`)
+* Arm Realm Management Extension (RME)
Other mechanisms may be supported in future.
diff --git a/qapi/qom.json b/qapi/qom.json
index c55776af7d35..68de12c37c01 100644
--- a/qapi/qom.json
+++ b/qapi/qom.json
@@ -1302,6 +1302,7 @@
{ 'name': 'pr-manager-helper',
'if': 'CONFIG_LINUX' },
'qtest',
+ 'rme-guest',
'rng-builtin',
'rng-egd',
{ 'name': 'rng-random',
diff --git a/target/arm/kvm-rme.c b/target/arm/kvm-rme.c
new file mode 100644
index 000000000000..42e1d1e7b859
--- /dev/null
+++ b/target/arm/kvm-rme.c
@@ -0,0 +1,42 @@
+/*
+ * QEMU Arm RME support
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * Copyright Linaro 2026
+ */
+
+#include "qemu/osdep.h"
+
+#include "hw/core/boards.h"
+#include "hw/core/cpu.h"
+#include "kvm_arm.h"
+#include "migration/blocker.h"
+#include "qapi/error.h"
+#include "qom/object_interfaces.h"
+#include "system/confidential-guest-support.h"
+#include "system/kvm.h"
+#include "system/runstate.h"
+
+#define TYPE_RME_GUEST "rme-guest"
+OBJECT_DECLARE_SIMPLE_TYPE(RmeGuest, RME_GUEST)
+
+struct RmeGuest {
+ ConfidentialGuestSupport parent_obj;
+};
+
+OBJECT_DEFINE_SIMPLE_TYPE_WITH_INTERFACES(RmeGuest, rme_guest, RME_GUEST,
+ CONFIDENTIAL_GUEST_SUPPORT,
+ { TYPE_USER_CREATABLE }, { })
+
+static void rme_guest_class_init(ObjectClass *oc, const void *data)
+{
+}
+
+static void rme_guest_init(Object *obj)
+{
+}
+
+static void rme_guest_finalize(Object *obj)
+{
+}
diff --git a/target/arm/meson.build b/target/arm/meson.build
index 4412fde065f2..aff52a3f6eeb 100644
--- a/target/arm/meson.build
+++ b/target/arm/meson.build
@@ -31,7 +31,10 @@ arm_common_user_system_ss.add(when: 'TARGET_AARCH64', if_true: files(
arm_common_system_ss.add(files(
'arm-qmp-cmds.c',
))
-arm_system_ss.add(when: 'CONFIG_KVM', if_true: files('hyp_gdbstub.c', 'kvm.c'))
+arm_system_ss.add(when: 'CONFIG_KVM', if_true: files(
+ 'hyp_gdbstub.c',
+ 'kvm.c',
+ 'kvm-rme.c'))
arm_system_ss.add(when: 'CONFIG_HVF', if_true: files('hyp_gdbstub.c'))
arm_user_ss.add(files('cpu.c'))
--
2.43.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [RFC v2 04/24] target/arm/kvm-rme: Add mechanic to initialize realms
2026-07-28 19:26 [RFC v2 00/24] Add Realm support to QEMU-VMM Mathieu Poirier
` (2 preceding siblings ...)
2026-07-28 19:26 ` [RFC v2 03/24] target/arm: Add confidential guest support Mathieu Poirier
@ 2026-07-28 19:26 ` Mathieu Poirier
2026-07-28 19:26 ` [RFC v2 05/24] target/arm/kvm: Split kvm_arch_get/put_registers Mathieu Poirier
` (20 subsequent siblings)
24 siblings, 0 replies; 30+ messages in thread
From: Mathieu Poirier @ 2026-07-28 19:26 UTC (permalink / raw)
To: berrange, kchamart, pierrick.bouvier, peter.maydell, mst, cohuck,
pbonzini, eblake, armbru, lorenzo.pieralisi, gshan
Cc: qemu-devel, qemu-arm, kvm
Initialise an @rme_guest object and install a handler to get notified
when the Realm is ready to start. That way we can finish reading the
Realm once we know everything is in place.
Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org>
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
target/arm/kvm-rme.c | 48 ++++++++++++++++++++++++++++++++++++++++++++
target/arm/kvm.c | 15 ++++++++++++--
2 files changed, 61 insertions(+), 2 deletions(-)
diff --git a/target/arm/kvm-rme.c b/target/arm/kvm-rme.c
index 42e1d1e7b859..eb8e65ba438f 100644
--- a/target/arm/kvm-rme.c
+++ b/target/arm/kvm-rme.c
@@ -13,6 +13,7 @@
#include "kvm_arm.h"
#include "migration/blocker.h"
#include "qapi/error.h"
+#include "qemu/error-report.h"
#include "qom/object_interfaces.h"
#include "system/confidential-guest-support.h"
#include "system/kvm.h"
@@ -29,12 +30,59 @@ OBJECT_DEFINE_SIMPLE_TYPE_WITH_INTERFACES(RmeGuest, rme_guest, RME_GUEST,
CONFIDENTIAL_GUEST_SUPPORT,
{ TYPE_USER_CREATABLE }, { })
+static RmeGuest *rme_guest;
+
+static void rme_vm_state_change(void *opaque, bool running, RunState state)
+{
+ if (!running) {
+ return;
+ }
+
+ kvm_mark_guest_state_protected();
+}
+
+static int kvm_arm_rme_init(ConfidentialGuestSupport *cgs, Error **errp)
+{
+ KVMState *s = KVM_STATE(current_accel());
+ static Error *rme_mig_blocker;
+
+ if (!rme_guest) {
+ return 0;
+ }
+
+ if (!kvm_vm_check_extension(s, KVM_CAP_ARM_RMI)) {
+ error_setg(errp, "VM doesn't support Realms");
+ return -ENODEV;
+ }
+
+ error_setg(&rme_mig_blocker, "RME: migration is not implemented");
+ migrate_add_blocker(&rme_mig_blocker, &error_fatal);
+
+ /*
+ * The realm activation is done last, when the VM starts, after all images
+ * have been loaded and all vcpus finalized.
+ */
+ qemu_add_vm_change_state_handler(rme_vm_state_change, NULL);
+
+ cgs->require_guest_memfd = true;
+ cgs->ready = true;
+ return 0;
+}
+
static void rme_guest_class_init(ObjectClass *oc, const void *data)
{
+ ConfidentialGuestSupportClass *klass = CONFIDENTIAL_GUEST_SUPPORT_CLASS(oc);
+
+ klass->kvm_init = kvm_arm_rme_init;
}
static void rme_guest_init(Object *obj)
{
+ if (rme_guest) {
+ error_report("a single instance of RmeGuest is supported");
+ exit(1);
+ }
+ rme_guest = RME_GUEST(obj);
}
static void rme_guest_finalize(Object *obj)
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index ed99be7fd80c..401a6f669cbb 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -33,6 +33,7 @@
#include "hw/pci/pci.h"
#include "exec/memattrs.h"
#include "system/address-spaces.h"
+#include "system/confidential-guest-support.h"
#include "gdbstub/enums.h"
#include "hw/core/boards.h"
#include "hw/core/irq.h"
@@ -596,7 +597,8 @@ int kvm_arch_get_default_type(MachineState *ms)
int kvm_arch_init(MachineState *ms, KVMState *s)
{
- int ret;
+ Error *local_err = NULL;
+ int ret = 0;
/* For ARM interrupt delivery is always asynchronous,
* whether we are using an in-kernel VGIC or not.
*/
@@ -610,6 +612,15 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
cap_has_mp_state = kvm_check_extension(s, KVM_CAP_MP_STATE);
+ /* Initialize confidential guest (Realm) if needed */
+ if (ms->cgs) {
+ ret = confidential_guest_kvm_init(ms->cgs, &local_err);
+ if (ret < 0) {
+ error_report_err(local_err);
+ return ret;
+ }
+ }
+
/* Check whether user space can specify guest syndrome value */
cap_has_inject_serror_esr =
kvm_check_extension(s, KVM_CAP_ARM_INJECT_SERROR_ESR);
@@ -660,7 +671,7 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
hw_breakpoints = g_array_sized_new(true, true,
sizeof(HWBreakpoint), max_hw_bps);
- return 0;
+ return ret;
}
unsigned long kvm_arch_vcpu_id(CPUState *cpu)
--
2.43.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [RFC v2 05/24] target/arm/kvm: Split kvm_arch_get/put_registers
2026-07-28 19:26 [RFC v2 00/24] Add Realm support to QEMU-VMM Mathieu Poirier
` (3 preceding siblings ...)
2026-07-28 19:26 ` [RFC v2 04/24] target/arm/kvm-rme: Add mechanic to initialize realms Mathieu Poirier
@ 2026-07-28 19:26 ` Mathieu Poirier
2026-07-28 19:26 ` [RFC v2 06/24] target/arm/kvm-rme: Initialize vCPU Mathieu Poirier
` (19 subsequent siblings)
24 siblings, 0 replies; 30+ messages in thread
From: Mathieu Poirier @ 2026-07-28 19:26 UTC (permalink / raw)
To: berrange, kchamart, pierrick.bouvier, peter.maydell, mst, cohuck,
pbonzini, eblake, armbru, lorenzo.pieralisi, gshan
Cc: qemu-devel, qemu-arm, kvm
From: Jean-Philippe Brucker <jean-philippe@linaro.org>
For a Realm, KVM is much more restrictive on the registers a VMM can
initialize. To prepare for Realm VM initialization, split the get/put
register functions for a non-secure VM in their own function.
Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org>
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
target/arm/kvm.c | 30 ++++++++++++++++++++++++++++--
1 file changed, 28 insertions(+), 2 deletions(-)
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index 401a6f669cbb..33c3763aebfa 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -2169,7 +2169,7 @@ static int kvm_arch_put_sve(CPUState *cs, uint32_t vq, bool have_ffr)
return 0;
}
-int kvm_arch_put_registers(CPUState *cs, KvmPutState level, Error **errp)
+static int kvm_arm_put_core_regs(CPUState *cs, Error **errp)
{
uint64_t val;
uint32_t fpr;
@@ -2272,6 +2272,19 @@ int kvm_arch_put_registers(CPUState *cs, KvmPutState level, Error **errp)
return ret;
}
+ return 0;
+}
+
+int kvm_arch_put_registers(CPUState *cs, KvmPutState level, Error **errp)
+{
+ int ret;
+ ARMCPU *cpu = ARM_CPU(cs);
+
+ ret = kvm_arm_put_core_regs(cs, errp);
+ if (ret) {
+ return ret;
+ }
+
write_cpustate_to_list(cpu, true);
if (!write_list_to_kvmstate(cpu, level)) {
@@ -2354,7 +2367,7 @@ static int kvm_arch_get_sve(CPUState *cs, uint32_t vq, bool have_ffr)
return 0;
}
-int kvm_arch_get_registers(CPUState *cs, Error **errp)
+static int kvm_arm_get_core_regs(CPUState *cs, Error **errp)
{
uint64_t val;
unsigned int el;
@@ -2457,6 +2470,19 @@ int kvm_arch_get_registers(CPUState *cs, Error **errp)
}
vfp_set_fpcr(env, fpr);
+ return 0;
+}
+
+int kvm_arch_get_registers(CPUState *cs, Error **errp)
+{
+ int ret;
+ ARMCPU *cpu = ARM_CPU(cs);
+
+ ret = kvm_arm_get_core_regs(cs, errp);
+ if (ret) {
+ return ret;
+ }
+
ret = kvm_get_vcpu_events(cpu);
if (ret) {
return ret;
--
2.43.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [RFC v2 06/24] target/arm/kvm-rme: Initialize vCPU
2026-07-28 19:26 [RFC v2 00/24] Add Realm support to QEMU-VMM Mathieu Poirier
` (4 preceding siblings ...)
2026-07-28 19:26 ` [RFC v2 05/24] target/arm/kvm: Split kvm_arch_get/put_registers Mathieu Poirier
@ 2026-07-28 19:26 ` Mathieu Poirier
2026-07-28 19:26 ` [RFC v2 07/24] target/arm/kvm: Create scratch Realm VM when requested Mathieu Poirier
` (18 subsequent siblings)
24 siblings, 0 replies; 30+ messages in thread
From: Mathieu Poirier @ 2026-07-28 19:26 UTC (permalink / raw)
To: berrange, kchamart, pierrick.bouvier, peter.maydell, mst, cohuck,
pbonzini, eblake, armbru, lorenzo.pieralisi, gshan
Cc: qemu-devel, qemu-arm, kvm
From: Jean-Philippe Brucker <jean-philippe@linaro.org>
The target code calls kvm_arm_vcpu_init() to mark the vCPU as part of a
Realm. For a Realm vCPU, only x0-x7 can be set at runtime. Before boot,
the PC can also be set, and is ignored at runtime. KVM also accepts a
few system register changes during initial configuration, as returned by
KVM_GET_REG_LIST.
Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org>
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
target/arm/cpu.h | 3 +++
target/arm/kvm-rme.c | 9 ++++++++
target/arm/kvm-stub.c | 5 ++++
target/arm/kvm.c | 54 +++++++++++++++++++++++++++++++++++++++++--
target/arm/kvm_arm.h | 10 ++++++++
5 files changed, 79 insertions(+), 2 deletions(-)
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 03a30afcbed1..c7927036360c 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -1055,6 +1055,9 @@ struct ArchCPU {
/* KVM steal time */
OnOffAuto kvm_steal_time;
+ /* Realm Management Extension */
+ bool kvm_rme;
+
/* Uniprocessor system with MP extensions */
bool mp_is_up;
diff --git a/target/arm/kvm-rme.c b/target/arm/kvm-rme.c
index eb8e65ba438f..5d6814fcf9e5 100644
--- a/target/arm/kvm-rme.c
+++ b/target/arm/kvm-rme.c
@@ -69,6 +69,15 @@ static int kvm_arm_rme_init(ConfidentialGuestSupport *cgs, Error **errp)
return 0;
}
+void kvm_arm_rme_vcpu_init(ARMCPU *cpu)
+{
+ if (!rme_guest) {
+ return;
+ }
+
+ cpu->kvm_rme = true;
+}
+
static void rme_guest_class_init(ObjectClass *oc, const void *data)
{
ConfidentialGuestSupportClass *klass = CONFIDENTIAL_GUEST_SUPPORT_CLASS(oc);
diff --git a/target/arm/kvm-stub.c b/target/arm/kvm-stub.c
index 88cbe8d85c41..5fde96f9b281 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();
}
+
+void kvm_arm_rme_vcpu_init(ARMCPU *cpu)
+{
+ g_assert_not_reached();
+}
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index 33c3763aebfa..b4c6da1fb9f3 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -2015,6 +2015,8 @@ int kvm_arch_init_vcpu(CPUState *cs)
cpu->kvm_init_features[0] |= 1 << KVM_ARM_VCPU_HAS_EL2;
}
+ kvm_arm_rme_vcpu_init(cpu);
+
/* Do KVM_ARM_VCPU_INIT ioctl */
ret = kvm_arm_vcpu_init(cpu);
if (ret) {
@@ -2169,6 +2171,29 @@ static int kvm_arch_put_sve(CPUState *cs, uint32_t vq, bool have_ffr)
return 0;
}
+static int kvm_arm_rme_put_core_regs(CPUState *cs, Error **errp)
+{
+ int i, ret;
+ ARMCPU *cpu = ARM_CPU(cs);
+ CPUARMState *env = &cpu->env;
+
+ /* The RME ABI only allows us to set 8 GPRs and the PC */
+ for (i = 0; i < 8; i++) {
+ ret = kvm_set_one_reg(cs, AARCH64_CORE_REG(regs.regs[i]),
+ &env->xregs[i]);
+ if (ret) {
+ return ret;
+ }
+ }
+
+ ret = kvm_set_one_reg(cs, AARCH64_CORE_REG(regs.pc), &env->pc);
+ if (ret) {
+ return ret;
+ }
+
+ return 0;
+}
+
static int kvm_arm_put_core_regs(CPUState *cs, Error **errp)
{
uint64_t val;
@@ -2280,7 +2305,11 @@ int kvm_arch_put_registers(CPUState *cs, KvmPutState level, Error **errp)
int ret;
ARMCPU *cpu = ARM_CPU(cs);
- ret = kvm_arm_put_core_regs(cs, errp);
+ if (cpu->kvm_rme) {
+ ret = kvm_arm_rme_put_core_regs(cs, errp);
+ } else {
+ ret = kvm_arm_put_core_regs(cs, errp);
+ }
if (ret) {
return ret;
}
@@ -2367,6 +2396,23 @@ static int kvm_arch_get_sve(CPUState *cs, uint32_t vq, bool have_ffr)
return 0;
}
+static int kvm_arm_rme_get_core_regs(CPUState *cs, Error **errp)
+{
+ int i, ret;
+ ARMCPU *cpu = ARM_CPU(cs);
+ CPUARMState *env = &cpu->env;
+
+ for (i = 0; i < 8; i++) {
+ ret = kvm_get_one_reg(cs, AARCH64_CORE_REG(regs.regs[i]),
+ &env->xregs[i]);
+ if (ret) {
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
static int kvm_arm_get_core_regs(CPUState *cs, Error **errp)
{
uint64_t val;
@@ -2478,7 +2524,11 @@ int kvm_arch_get_registers(CPUState *cs, Error **errp)
int ret;
ARMCPU *cpu = ARM_CPU(cs);
- ret = kvm_arm_get_core_regs(cs, errp);
+ if (cpu->kvm_rme) {
+ ret = kvm_arm_rme_get_core_regs(cs, errp);
+ } else {
+ ret = kvm_arm_get_core_regs(cs, errp);
+ }
if (ret) {
return ret;
}
diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h
index e7c40fb003e4..d95381c13afa 100644
--- a/target/arm/kvm_arm.h
+++ b/target/arm/kvm_arm.h
@@ -240,4 +240,14 @@ void arm_gic_cap_kvm_probe(GICCapability *v2, GICCapability *v3);
*/
char *kvm_print_register_name(uint64_t regidx);
+/**
+ * kvm_arm_rme_vcpu_init
+ * @cs: the CPU
+ *
+ * If the user requested a Realm, setup the given vCPU accordingly. Realm vCPUs
+ * behave a little differently, for example most of their register state is
+ * hidden from the host.
+ */
+void kvm_arm_rme_vcpu_init(ARMCPU *cpu);
+
#endif
--
2.43.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [RFC v2 07/24] target/arm/kvm: Create scratch Realm VM when requested
2026-07-28 19:26 [RFC v2 00/24] Add Realm support to QEMU-VMM Mathieu Poirier
` (5 preceding siblings ...)
2026-07-28 19:26 ` [RFC v2 06/24] target/arm/kvm-rme: Initialize vCPU Mathieu Poirier
@ 2026-07-28 19:26 ` Mathieu Poirier
2026-07-28 19:26 ` [RFC v2 08/24] target/arm/kvm: Use kvm_vm_check_extension() where necessary Mathieu Poirier
` (17 subsequent siblings)
24 siblings, 0 replies; 30+ messages in thread
From: Mathieu Poirier @ 2026-07-28 19:26 UTC (permalink / raw)
To: berrange, kchamart, pierrick.bouvier, peter.maydell, mst, cohuck,
pbonzini, eblake, armbru, lorenzo.pieralisi, gshan
Cc: qemu-devel, qemu-arm, kvm
From: Jean-Philippe Brucker <jean-philippe@linaro.org>
When a Realm is requested, create a scratch Realm VM by setting bit 8
of the argument given to the KVM_CREATE_VM ioctl(). Bit 7-0 are reserved
for the guest PA size.
Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org>
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
target/arm/kvm.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index b4c6da1fb9f3..d86e66e056b9 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -108,7 +108,9 @@ bool kvm_arm_create_scratch_host_vcpu(int *fdarray,
struct kvm_vcpu_init *init)
{
int ret = 0, kvmfd = -1, vmfd = -1, cpufd = -1;
+ MachineState *ms = MACHINE(qdev_get_machine());
int max_vm_pa_size;
+ int vm_type;
kvmfd = qemu_open_old("/dev/kvm", O_RDWR);
if (kvmfd < 0) {
@@ -118,8 +120,10 @@ bool kvm_arm_create_scratch_host_vcpu(int *fdarray,
if (max_vm_pa_size < 0) {
max_vm_pa_size = 0;
}
+
+ vm_type = (ms->cgs ? KVM_VM_TYPE_ARM_REALM : KVM_VM_TYPE_ARM_NORMAL);
do {
- vmfd = ioctl(kvmfd, KVM_CREATE_VM, max_vm_pa_size);
+ vmfd = ioctl(kvmfd, KVM_CREATE_VM, max_vm_pa_size | vm_type);
} while (vmfd == -1 && errno == EINTR);
if (vmfd < 0) {
goto err;
--
2.43.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [RFC v2 08/24] target/arm/kvm: Use kvm_vm_check_extension() where necessary
2026-07-28 19:26 [RFC v2 00/24] Add Realm support to QEMU-VMM Mathieu Poirier
` (6 preceding siblings ...)
2026-07-28 19:26 ` [RFC v2 07/24] target/arm/kvm: Create scratch Realm VM when requested Mathieu Poirier
@ 2026-07-28 19:26 ` Mathieu Poirier
2026-07-28 19:26 ` [RFC v2 09/24] hw/core/loader: Add a ROM loader notifier Mathieu Poirier
` (16 subsequent siblings)
24 siblings, 0 replies; 30+ messages in thread
From: Mathieu Poirier @ 2026-07-28 19:26 UTC (permalink / raw)
To: berrange, kchamart, pierrick.bouvier, peter.maydell, mst, cohuck,
pbonzini, eblake, armbru, lorenzo.pieralisi, gshan
Cc: qemu-devel, qemu-arm, kvm
From: Jean-Philippe Brucker <jean-philippe@linaro.org>
The Arm KVM code can return different values from KVM_CHECK_EXTENSION
depending on the VM type. Use kvm_vm_check_extension() where necessary
to ensure we get the right response from KVM.
Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org>
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
target/arm/kvm.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index d86e66e056b9..ca25b707a0a8 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -331,7 +331,7 @@ static void kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
1 << KVM_ARM_VCPU_PTRAUTH_GENERIC);
}
- if (kvm_check_extension(kvm_state, KVM_CAP_ARM_PMU_V3)) {
+ if (kvm_vm_check_extension(kvm_state, KVM_CAP_ARM_PMU_V3)) {
init.features[0] |= 1 << KVM_ARM_VCPU_PMU_V3;
pmu_supported = true;
features |= 1ULL << ARM_FEATURE_PMU;
@@ -636,7 +636,7 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
return -EINVAL;
}
- if (kvm_check_extension(s, KVM_CAP_ARM_NISV_TO_USER)) {
+ if (kvm_vm_check_extension(s, KVM_CAP_ARM_NISV_TO_USER)) {
if (kvm_vm_enable_cap(s, KVM_CAP_ARM_NISV_TO_USER, 0)) {
error_report("Failed to enable KVM_CAP_ARM_NISV_TO_USER cap");
} else {
@@ -667,11 +667,11 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
}
}
- max_hw_wps = kvm_check_extension(s, KVM_CAP_GUEST_DEBUG_HW_WPS);
+ max_hw_wps = kvm_vm_check_extension(s, KVM_CAP_GUEST_DEBUG_HW_WPS);
hw_watchpoints = g_array_sized_new(true, true,
sizeof(HWWatchpoint), max_hw_wps);
- max_hw_bps = kvm_check_extension(s, KVM_CAP_GUEST_DEBUG_HW_BPS);
+ max_hw_bps = kvm_vm_check_extension(s, KVM_CAP_GUEST_DEBUG_HW_BPS);
hw_breakpoints = g_array_sized_new(true, true,
sizeof(HWBreakpoint), max_hw_bps);
@@ -1913,7 +1913,7 @@ void kvm_arm_pvtime_init(ARMCPU *cpu, uint64_t ipa)
void kvm_arm_steal_time_finalize(ARMCPU *cpu, Error **errp)
{
- bool has_steal_time = kvm_check_extension(kvm_state, KVM_CAP_STEAL_TIME);
+ bool has_steal_time = kvm_vm_check_extension(kvm_state, KVM_CAP_STEAL_TIME);
if (cpu->kvm_steal_time == ON_OFF_AUTO_AUTO) {
if (!has_steal_time || !arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) {
--
2.43.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [RFC v2 09/24] hw/core/loader: Add a ROM loader notifier
2026-07-28 19:26 [RFC v2 00/24] Add Realm support to QEMU-VMM Mathieu Poirier
` (7 preceding siblings ...)
2026-07-28 19:26 ` [RFC v2 08/24] target/arm/kvm: Use kvm_vm_check_extension() where necessary Mathieu Poirier
@ 2026-07-28 19:26 ` Mathieu Poirier
2026-07-28 19:26 ` [RFC v2 10/24] target/arm/kvm-rme: Keep track of images loaded in Realm memory Mathieu Poirier
` (15 subsequent siblings)
24 siblings, 0 replies; 30+ messages in thread
From: Mathieu Poirier @ 2026-07-28 19:26 UTC (permalink / raw)
To: berrange, kchamart, pierrick.bouvier, peter.maydell, mst, cohuck,
pbonzini, eblake, armbru, lorenzo.pieralisi, gshan
Cc: qemu-devel, qemu-arm, kvm
From: Jean-Philippe Brucker <jean-philippe@linaro.org>
Add a function to register a notifier that is invoked when ROMs get
loaded into guest memory.
It will be used by Arm confidential guest support, in order to register
all blobs loaded into memory with KVM, so that their content is moved
into Realm state and measured into the initial VM state.
Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org>
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
hw/core/loader.c | 15 +++++++++++++++
include/hw/core/loader.h | 17 +++++++++++++++++
2 files changed, 32 insertions(+)
diff --git a/hw/core/loader.c b/hw/core/loader.c
index 5cbfba0a86d2..b3d769bec5cb 100644
--- a/hw/core/loader.c
+++ b/hw/core/loader.c
@@ -74,6 +74,8 @@
#endif
static int roms_loaded;
+static NotifierList rom_loader_notifier =
+ NOTIFIER_LIST_INITIALIZER(rom_loader_notifier);
/* return the size or -1 if error */
int64_t get_image_size(const char *filename, Error **errp)
@@ -1201,6 +1203,11 @@ MemoryRegion *rom_add_blob(const char *name, const void *blob, size_t len,
return mr;
}
+void rom_add_load_notifier(Notifier *notifier)
+{
+ notifier_list_add(&rom_loader_notifier, notifier);
+}
+
/* This function is specific for elf program because we don't need to allocate
* all the rom. We just allocate the first part and the rest is just zeros. This
* is why romsize and datasize are different. Also, this function takes its own
@@ -1242,6 +1249,7 @@ ssize_t rom_add_option(const char *file, int32_t bootindex)
static void rom_reset(void *unused)
{
Rom *rom;
+ RomLoaderNotifyData notify;
QTAILQ_FOREACH(rom, &roms, next) {
if (rom->fw_file) {
@@ -1290,6 +1298,13 @@ static void rom_reset(void *unused)
address_space_flush_icache_range(rom->as, rom->addr, rom->datasize);
trace_loader_write_rom(rom->name, rom->addr, rom->datasize, rom->isrom);
+
+ notify = (RomLoaderNotifyData) {
+ .addr = rom->addr,
+ .len = rom->datasize,
+ .as = rom->as,
+ };
+ notifier_list_notify(&rom_loader_notifier, ¬ify);
}
}
diff --git a/include/hw/core/loader.h b/include/hw/core/loader.h
index d9431e8a8d12..94cf6ad2e26b 100644
--- a/include/hw/core/loader.h
+++ b/include/hw/core/loader.h
@@ -342,6 +342,23 @@ void *rom_ptr_for_as(AddressSpace *as, hwaddr addr, size_t size);
ssize_t rom_add_vga(const char *file);
ssize_t rom_add_option(const char *file, int32_t bootindex);
+typedef struct RomLoaderNotifyData {
+ /* Address of the blob in guest memory */
+ hwaddr addr;
+ /* Length of the blob */
+ size_t len;
+ /* Address space of the blob */
+ AddressSpace *as;
+} RomLoaderNotifyData;
+
+/**
+ * rom_add_load_notifier - Add a notifier for loaded images
+ *
+ * Add a notifier that will be invoked with a RomLoaderNotifyData structure for
+ * each blob loaded into guest memory, after the blob is loaded.
+ */
+void rom_add_load_notifier(Notifier *notifier);
+
/* This is the usual maximum in uboot, so if a uImage overflows this, it would
* overflow on real hardware too. */
#define UBOOT_MAX_DECOMPRESSED_BYTES (64 << 20)
--
2.43.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [RFC v2 10/24] target/arm/kvm-rme: Keep track of images loaded in Realm memory
2026-07-28 19:26 [RFC v2 00/24] Add Realm support to QEMU-VMM Mathieu Poirier
` (8 preceding siblings ...)
2026-07-28 19:26 ` [RFC v2 09/24] hw/core/loader: Add a ROM loader notifier Mathieu Poirier
@ 2026-07-28 19:26 ` Mathieu Poirier
2026-07-28 19:26 ` [RFC v2 11/24] target/arm/kvm-rme: Populate Realm with runtime images Mathieu Poirier
` (14 subsequent siblings)
24 siblings, 0 replies; 30+ messages in thread
From: Mathieu Poirier @ 2026-07-28 19:26 UTC (permalink / raw)
To: berrange, kchamart, pierrick.bouvier, peter.maydell, mst, cohuck,
pbonzini, eblake, armbru, lorenzo.pieralisi, gshan
Cc: qemu-devel, qemu-arm, kvm
From: Jean-Philippe Brucker <jean-philippe@linaro.org>
Add a Rom notifier to keep track of binary blobs loaded in Realm memory.
That way we can deterministically calculate the Realm Initial Measurement (RIM).
Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org>
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
target/arm/kvm-rme.c | 52 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 52 insertions(+)
diff --git a/target/arm/kvm-rme.c b/target/arm/kvm-rme.c
index 5d6814fcf9e5..10bca9a944ba 100644
--- a/target/arm/kvm-rme.c
+++ b/target/arm/kvm-rme.c
@@ -10,6 +10,7 @@
#include "hw/core/boards.h"
#include "hw/core/cpu.h"
+#include "hw/core/loader.h"
#include "kvm_arm.h"
#include "migration/blocker.h"
#include "qapi/error.h"
@@ -22,8 +23,18 @@
#define TYPE_RME_GUEST "rme-guest"
OBJECT_DECLARE_SIMPLE_TYPE(RmeGuest, RME_GUEST)
+#define RME_PAGE_SIZE qemu_real_host_page_size()
+
+typedef struct {
+ hwaddr base;
+ hwaddr size;
+ AddressSpace *as;
+} RmeRamRegion;
+
struct RmeGuest {
ConfidentialGuestSupport parent_obj;
+ Notifier rom_load_notifier;
+ GSList *ram_regions;
};
OBJECT_DEFINE_SIMPLE_TYPE_WITH_INTERFACES(RmeGuest, rme_guest, RME_GUEST,
@@ -41,6 +52,44 @@ static void rme_vm_state_change(void *opaque, bool running, RunState state)
kvm_mark_guest_state_protected();
}
+static gint rme_compare_ram_regions(gconstpointer a, gconstpointer b)
+{
+ const RmeRamRegion *ra = a;
+ const RmeRamRegion *rb = b;
+
+ g_assert(ra->base != rb->base);
+ return ra->base < rb->base ? -1 : 1;
+}
+
+static void rme_rom_load_notify(Notifier *notifier, void *data)
+{
+ RmeRamRegion *region;
+ RomLoaderNotifyData *rom = data;
+
+ if (rom->addr == -1) {
+ /*
+ * These blobs (ACPI tables) are not loaded into guest RAM at reset.
+ * Instead the firmware will load them via fw_cfg and measure them
+ * itself.
+ */
+ return;
+ }
+
+ region = g_new0(RmeRamRegion, 1);
+ region->base = rom->addr;
+ region->size = rom->len;
+ region->as = rom->as;
+
+ /*
+ * The Realm Initial Measurement (RIM) depends on the order in which we
+ * initialize and populate the RAM regions. To help a verifier
+ * independently calculate the RIM, sort regions by GPA.
+ */
+ rme_guest->ram_regions = g_slist_insert_sorted(rme_guest->ram_regions,
+ region,
+ rme_compare_ram_regions);
+}
+
static int kvm_arm_rme_init(ConfidentialGuestSupport *cgs, Error **errp)
{
KVMState *s = KVM_STATE(current_accel());
@@ -58,6 +107,9 @@ static int kvm_arm_rme_init(ConfidentialGuestSupport *cgs, Error **errp)
error_setg(&rme_mig_blocker, "RME: migration is not implemented");
migrate_add_blocker(&rme_mig_blocker, &error_fatal);
+ rme_guest->rom_load_notifier.notify = rme_rom_load_notify;
+ rom_add_load_notifier(&rme_guest->rom_load_notifier);
+
/*
* The realm activation is done last, when the VM starts, after all images
* have been loaded and all vcpus finalized.
--
2.43.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [RFC v2 11/24] target/arm/kvm-rme: Populate Realm with runtime images
2026-07-28 19:26 [RFC v2 00/24] Add Realm support to QEMU-VMM Mathieu Poirier
` (9 preceding siblings ...)
2026-07-28 19:26 ` [RFC v2 10/24] target/arm/kvm-rme: Keep track of images loaded in Realm memory Mathieu Poirier
@ 2026-07-28 19:26 ` Mathieu Poirier
2026-07-28 19:26 ` [RFC v2 12/24] target/arm/cpu: Set number of breakpoints and watchpoints in KVM Mathieu Poirier
` (13 subsequent siblings)
24 siblings, 0 replies; 30+ messages in thread
From: Mathieu Poirier @ 2026-07-28 19:26 UTC (permalink / raw)
To: berrange, kchamart, pierrick.bouvier, peter.maydell, mst, cohuck,
pbonzini, eblake, armbru, lorenzo.pieralisi, gshan
Cc: qemu-devel, qemu-arm, kvm
From: Jean-Philippe Brucker <jean-philippe@linaro.org>
Once the Realm descriptor has been created, tell KVM to transfer runtime
images (kernel, DT, and rootfs) from guest memory to Realm memory.
Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org>
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
target/arm/kvm-rme.c | 56 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 56 insertions(+)
diff --git a/target/arm/kvm-rme.c b/target/arm/kvm-rme.c
index 10bca9a944ba..335ad60d0f3b 100644
--- a/target/arm/kvm-rme.c
+++ b/target/arm/kvm-rme.c
@@ -43,12 +43,68 @@ OBJECT_DEFINE_SIMPLE_TYPE_WITH_INTERFACES(RmeGuest, rme_guest, RME_GUEST,
static RmeGuest *rme_guest;
+static int rme_populate_range(const RmeRamRegion *region, bool measure,
+ Error **errp)
+{
+ int ret;
+ void *host_ua;
+ hwaddr size = region->size;
+ hwaddr base = region->base;
+ hwaddr start = QEMU_ALIGN_DOWN(base, RME_PAGE_SIZE);
+ hwaddr end = QEMU_ALIGN_UP(base + size, RME_PAGE_SIZE);
+ struct kvm_arm_rmi_populate populate_args;
+
+ host_ua = address_space_map(region->as, base, &size, false,
+ MEMTXATTRS_UNSPECIFIED);
+
+ populate_args = (struct kvm_arm_rmi_populate) {
+ .base = start,
+ .size = end - start,
+ .source_uaddr = (uintptr_t)host_ua,
+ .flags = measure ? KVM_ARM_RMI_POPULATE_FLAGS_MEASURE : 0,
+ };
+
+ while (populate_args.size > 0) {
+ ret = kvm_vm_ioctl(kvm_state, KVM_ARM_RMI_POPULATE, &populate_args, 0);
+ if (ret) {
+ error_setg_errno(errp, -ret,
+ "failed to populate realm [0x%"HWADDR_PRIx", 0x%"HWADDR_PRIx")",
+ start, end);
+ break;
+ }
+ }
+
+ address_space_unmap(region->as, host_ua, size, false, 0);
+
+ return ret;
+}
+
+static void rme_populate_ram_region(gpointer data, gpointer err)
+{
+ Error **errp = err;
+ const RmeRamRegion *region = data;
+
+ if (*errp) {
+ return;
+ }
+
+ rme_populate_range(region, /* measure */ true, errp);
+}
+
static void rme_vm_state_change(void *opaque, bool running, RunState state)
{
+ Error *errp = NULL;
+
if (!running) {
return;
}
+ g_slist_foreach(rme_guest->ram_regions, rme_populate_ram_region, &errp);
+ g_slist_free_full(g_steal_pointer(&rme_guest->ram_regions), g_free);
+ if (errp) {
+ return;
+ }
+
kvm_mark_guest_state_protected();
}
--
2.43.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [RFC v2 12/24] target/arm/cpu: Set number of breakpoints and watchpoints in KVM
2026-07-28 19:26 [RFC v2 00/24] Add Realm support to QEMU-VMM Mathieu Poirier
` (10 preceding siblings ...)
2026-07-28 19:26 ` [RFC v2 11/24] target/arm/kvm-rme: Populate Realm with runtime images Mathieu Poirier
@ 2026-07-28 19:26 ` Mathieu Poirier
2026-07-28 19:26 ` [RFC v2 13/24] target/arm/cpu: Set number of PMU counters " Mathieu Poirier
` (12 subsequent siblings)
24 siblings, 0 replies; 30+ messages in thread
From: Mathieu Poirier @ 2026-07-28 19:26 UTC (permalink / raw)
To: berrange, kchamart, pierrick.bouvier, peter.maydell, mst, cohuck,
pbonzini, eblake, armbru, lorenzo.pieralisi, gshan
Cc: qemu-devel, qemu-arm, kvm
From: Jean-Philippe Brucker <jean-philippe@linaro.org>
Add "num-breakpoints" and "num-watchpoints" CPU parameters to configure
the debug features that KVM presents to the guest. The KVM vCPU
configuration is modified by calling SET_ONE_REG on the ID register.
This is needed for Realm VMs, whose parameters include breakpoints and
watchpoints, and influence the Realm Initial Measurement.
Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org>
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
target/arm/arm-qmp-cmds.c | 1 +
target/arm/cpu.h | 4 ++
target/arm/cpu64.c | 81 +++++++++++++++++++++++++++++++++++++++
target/arm/kvm.c | 56 +++++++++++++++++++++++++++
4 files changed, 142 insertions(+)
diff --git a/target/arm/arm-qmp-cmds.c b/target/arm/arm-qmp-cmds.c
index 83ec95c290f6..9ed65eb090d7 100644
--- a/target/arm/arm-qmp-cmds.c
+++ b/target/arm/arm-qmp-cmds.c
@@ -76,6 +76,7 @@ static const char *cpu_model_advertised_features[] = {
"sve1408", "sve1536", "sve1664", "sve1792", "sve1920", "sve2048",
"kvm-no-adjvtime", "kvm-steal-time",
"pauth", "pauth-impdef", "pauth-qarma3", "pauth-qarma5",
+ "num-breakpoints", "num-watchpoints",
NULL
};
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index c7927036360c..d6f64daec2a3 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -1174,6 +1174,10 @@ struct ArchCPU {
/* Generic timer counter frequency, in Hz */
uint64_t gt_cntfrq_hz;
+
+ /* Allows to override the default configuration */
+ uint8_t num_bps;
+ uint8_t num_wps;
};
typedef struct ARMCPUInfo {
diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
index 28167355773b..3f12009befa8 100644
--- a/target/arm/cpu64.c
+++ b/target/arm/cpu64.c
@@ -666,6 +666,86 @@ void aarch64_add_pauth_properties(Object *obj)
}
}
+#if defined(CONFIG_KVM)
+static void arm_cpu_get_num_wps(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ uint8_t val;
+ ARMCPU *cpu = ARM_CPU(obj);
+
+ val = cpu->num_wps;
+ if (val == 0) {
+ val = FIELD_EX64(cpu->isar.idregs[ID_AA64DFR0_EL1_IDX],
+ ID_AA64DFR0, WRPS) + 1;
+ }
+
+ visit_type_uint8(v, name, &val, errp);
+}
+
+static void arm_cpu_set_num_wps(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ uint8_t val;
+ ARMCPU *cpu = ARM_CPU(obj);
+ uint8_t max_wps = FIELD_EX64(cpu->isar.idregs[ID_AA64DFR0_EL1_IDX],
+ ID_AA64DFR0, WRPS) + 1;
+
+ if (!visit_type_uint8(v, name, &val, errp)) {
+ return;
+ }
+
+ if (val < 2 || val > max_wps) {
+ error_setg(errp, "invalid number of watchpoints");
+ return;
+ }
+
+ cpu->num_wps = val;
+}
+
+static void arm_cpu_get_num_bps(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ uint8_t val;
+ ARMCPU *cpu = ARM_CPU(obj);
+
+ val = cpu->num_bps;
+ if (val == 0) {
+ val = FIELD_EX64(cpu->isar.idregs[ID_AA64DFR0_EL1_IDX],
+ ID_AA64DFR0, BRPS) + 1;
+ }
+
+ visit_type_uint8(v, name, &val, errp);
+}
+
+static void arm_cpu_set_num_bps(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ uint8_t val;
+ ARMCPU *cpu = ARM_CPU(obj);
+ uint8_t max_bps = FIELD_EX64(cpu->isar.idregs[ID_AA64DFR0_EL1_IDX],
+ ID_AA64DFR0, BRPS) + 1;
+
+ if (!visit_type_uint8(v, name, &val, errp)) {
+ return;
+ }
+
+ if (val < 2 || val > max_bps) {
+ error_setg(errp, "invalid number of breakpoints");
+ return;
+ }
+
+ cpu->num_bps = val;
+}
+
+static void aarch64_add_kvm_writable_properties(Object *obj)
+{
+ object_property_add(obj, "num-breakpoints", "uint8", arm_cpu_get_num_bps,
+ arm_cpu_set_num_bps, NULL, NULL);
+ object_property_add(obj, "num-watchpoints", "uint8", arm_cpu_get_num_wps,
+ arm_cpu_set_num_wps, NULL, NULL);
+}
+#endif /* CONFIG_KVM */
+
void aarch64_cpu_lpa2_finalize(ARMCPU *cpu, Error **errp)
{
uint64_t t;
@@ -806,6 +886,7 @@ void aarch64_host_initfn(Object *obj)
kvm_arm_set_cpreg_mig_tolerances(cpu);
kvm_arm_set_cpu_features_from_host(cpu);
aarch64_add_sve_properties(obj);
+ aarch64_add_kvm_writable_properties(obj);
#elif defined(CONFIG_HVF)
hvf_arm_set_cpu_features_from_host(cpu);
#elif defined(CONFIG_WHPX)
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index ca25b707a0a8..93686b038263 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -912,6 +912,56 @@ out:
return ret;
}
+#define KVM_REG_ARM_ID_AA64DFR0_EL1 ARM64_SYS_REG(3, 0, 0, 5, 0)
+
+static void kvm_arm_configure_aa64dfr0(ARMCPU *cpu)
+{
+ int ret;
+ uint64_t val, newval;
+ CPUState *cs = CPU(cpu);
+
+ if (!cpu->num_bps && !cpu->num_wps) {
+ return;
+ }
+
+ newval = cpu->isar.idregs[ID_AA64DFR0_EL1_IDX];
+ if (cpu->num_bps) {
+ uint64_t ctx_cmps = FIELD_EX64(newval, ID_AA64DFR0, CTX_CMPS);
+
+ /* CTX_CMPs is never greater than BRPs */
+ ctx_cmps = MIN(ctx_cmps, cpu->num_bps - 1);
+ newval = FIELD_DP64(newval, ID_AA64DFR0, BRPS, cpu->num_bps - 1);
+ newval = FIELD_DP64(newval, ID_AA64DFR0, CTX_CMPS, ctx_cmps);
+ }
+ if (cpu->num_wps) {
+ newval = FIELD_DP64(newval, ID_AA64DFR0, WRPS, cpu->num_wps - 1);
+ }
+ ret = kvm_set_one_reg(cs, KVM_REG_ARM_ID_AA64DFR0_EL1, &newval);
+ if (ret) {
+ error_report("Failed to set KVM_REG_ARM_ID_AA64DFR0_EL1");
+ return;
+ }
+
+ /*
+ * Check if the write succeeded. KVM does offer the writable mask for this
+ * register, but this way we also check if the value we wrote was sane.
+ */
+ ret = kvm_get_one_reg(cs, KVM_REG_ARM_ID_AA64DFR0_EL1, &val);
+ if (ret) {
+ error_report("Failed to get KVM_REG_ARM_ID_AA64DFR0_EL1");
+ return;
+ }
+
+ if (val != newval) {
+ error_report("Failed to update KVM_REG_ARM_ID_AA64DFR0_EL1");
+ }
+}
+
+static void kvm_arm_configure_vcpu_regs(ARMCPU *cpu)
+{
+ kvm_arm_configure_aa64dfr0(cpu);
+}
+
/**
* kvm_arm_cpreg_level:
* @regidx: KVM register index
@@ -1128,6 +1178,12 @@ void kvm_arm_reset_vcpu(ARMCPU *cpu)
fprintf(stderr, "kvm_arm_vcpu_init failed: %s\n", strerror(-ret));
abort();
}
+
+ /*
+ * Before loading the KVM values into CPUState, update the KVM configuration
+ */
+ kvm_arm_configure_vcpu_regs(cpu);
+
if (!write_kvmstate_to_list(cpu)) {
fprintf(stderr, "write_kvmstate_to_list failed\n");
abort();
--
2.43.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [RFC v2 13/24] target/arm/cpu: Set number of PMU counters in KVM
2026-07-28 19:26 [RFC v2 00/24] Add Realm support to QEMU-VMM Mathieu Poirier
` (11 preceding siblings ...)
2026-07-28 19:26 ` [RFC v2 12/24] target/arm/cpu: Set number of breakpoints and watchpoints in KVM Mathieu Poirier
@ 2026-07-28 19:26 ` Mathieu Poirier
2026-07-28 19:26 ` [RFC v2 14/24] target/arm/cpu: Don't read Realm registers Mathieu Poirier
` (11 subsequent siblings)
24 siblings, 0 replies; 30+ messages in thread
From: Mathieu Poirier @ 2026-07-28 19:26 UTC (permalink / raw)
To: berrange, kchamart, pierrick.bouvier, peter.maydell, mst, cohuck,
pbonzini, eblake, armbru, lorenzo.pieralisi, gshan
Cc: qemu-devel, qemu-arm, kvm
From: Jean-Philippe Brucker <jean-philippe@linaro.org>
Add a "num-pmu-counters" CPU parameter to configure the number of
counters that KVM presents to the guest. This is needed for Realm VMs,
whose parameters include the number of PMU counters and influence the
Realm Initial Measurement.
Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org>
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
target/arm/arm-qmp-cmds.c | 2 +-
target/arm/cpu.h | 3 +++
target/arm/cpu64.c | 41 +++++++++++++++++++++++++++++++++++++++
target/arm/kvm.c | 34 ++++++++++++++++++++++++++++++++
4 files changed, 79 insertions(+), 1 deletion(-)
diff --git a/target/arm/arm-qmp-cmds.c b/target/arm/arm-qmp-cmds.c
index 9ed65eb090d7..9350dc30d12f 100644
--- a/target/arm/arm-qmp-cmds.c
+++ b/target/arm/arm-qmp-cmds.c
@@ -76,7 +76,7 @@ static const char *cpu_model_advertised_features[] = {
"sve1408", "sve1536", "sve1664", "sve1792", "sve1920", "sve2048",
"kvm-no-adjvtime", "kvm-steal-time",
"pauth", "pauth-impdef", "pauth-qarma3", "pauth-qarma5",
- "num-breakpoints", "num-watchpoints",
+ "num-breakpoints", "num-watchpoints", "num-pmu-counters",
NULL
};
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index d6f64daec2a3..50d482b09b0d 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -1178,6 +1178,7 @@ struct ArchCPU {
/* Allows to override the default configuration */
uint8_t num_bps;
uint8_t num_wps;
+ int8_t num_pmu_ctrs;
};
typedef struct ARMCPUInfo {
@@ -2134,6 +2135,8 @@ FIELD(MFAR, FPA, 12, 40)
FIELD(MFAR, NSE, 62, 1)
FIELD(MFAR, NS, 63, 1)
+FIELD(PMCR, N, 11, 5)
+
QEMU_BUILD_BUG_ON(ARRAY_SIZE(((ARMCPU *)0)->ccsidr) <= R_V7M_CSSELR_INDEX_MASK);
/* If adding a feature bit which corresponds to a Linux ELF
diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
index 3f12009befa8..00b3511dcbc3 100644
--- a/target/arm/cpu64.c
+++ b/target/arm/cpu64.c
@@ -737,12 +737,53 @@ static void arm_cpu_set_num_bps(Object *obj, Visitor *v, const char *name,
cpu->num_bps = val;
}
+static void arm_cpu_get_num_pmu_ctrs(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ uint8_t val;
+ ARMCPU *cpu = ARM_CPU(obj);
+
+ if (cpu->num_pmu_ctrs == -1) {
+ val = FIELD_EX64(cpu->isar.reset_pmcr_el0, PMCR, N);
+ } else {
+ val = cpu->num_pmu_ctrs;
+ }
+
+ visit_type_uint8(v, name, &val, errp);
+}
+
+static void arm_cpu_set_num_pmu_ctrs(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ uint8_t val;
+ ARMCPU *cpu = ARM_CPU(obj);
+ uint8_t max_ctrs = FIELD_EX64(cpu->isar.reset_pmcr_el0, PMCR, N);
+
+ if (!visit_type_uint8(v, name, &val, errp)) {
+ return;
+ }
+
+ if (val > max_ctrs) {
+ error_setg(errp, "invalid number of PMU counters");
+ return;
+ }
+
+ cpu->num_pmu_ctrs = val;
+}
+
static void aarch64_add_kvm_writable_properties(Object *obj)
{
+ ARMCPU *cpu = ARM_CPU(obj);
+
object_property_add(obj, "num-breakpoints", "uint8", arm_cpu_get_num_bps,
arm_cpu_set_num_bps, NULL, NULL);
object_property_add(obj, "num-watchpoints", "uint8", arm_cpu_get_num_wps,
arm_cpu_set_num_wps, NULL, NULL);
+
+ cpu->num_pmu_ctrs = -1;
+ object_property_add(obj, "num-pmu-counters", "uint8",
+ arm_cpu_get_num_pmu_ctrs, arm_cpu_set_num_pmu_ctrs,
+ NULL, NULL);
}
#endif /* CONFIG_KVM */
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index 93686b038263..b8cb04f7eeb1 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -957,9 +957,43 @@ static void kvm_arm_configure_aa64dfr0(ARMCPU *cpu)
}
}
+#define KVM_REG_ARM_PMCR_EL0 ARM64_SYS_REG(3, 3, 9, 12, 0)
+
+static void kvm_arm_configure_pmcr(ARMCPU *cpu)
+{
+ int ret;
+ uint64_t val, newval;
+ CPUState *cs = CPU(cpu);
+
+ if (cpu->num_pmu_ctrs == -1) {
+ return;
+ }
+
+ newval = FIELD_DP64(cpu->isar.reset_pmcr_el0, PMCR, N, cpu->num_pmu_ctrs);
+ ret = kvm_set_one_reg(cs, KVM_REG_ARM_PMCR_EL0, &newval);
+ if (ret) {
+ error_report("Failed to set KVM_REG_ARM_PMCR_EL0");
+ return;
+ }
+
+ /*
+ * Check if the write succeeded, since older versions of KVM ignore it.
+ */
+ ret = kvm_get_one_reg(cs, KVM_REG_ARM_PMCR_EL0, &val);
+ if (ret) {
+ error_report("Failed to get KVM_REG_ARM_PMCR_EL0");
+ return;
+ }
+
+ if (val != newval) {
+ error_report("Failed to update KVM_REG_ARM_PMCR_EL0");
+ }
+}
+
static void kvm_arm_configure_vcpu_regs(ARMCPU *cpu)
{
kvm_arm_configure_aa64dfr0(cpu);
+ kvm_arm_configure_pmcr(cpu);
}
/**
--
2.43.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [RFC v2 14/24] target/arm/cpu: Don't read Realm registers
2026-07-28 19:26 [RFC v2 00/24] Add Realm support to QEMU-VMM Mathieu Poirier
` (12 preceding siblings ...)
2026-07-28 19:26 ` [RFC v2 13/24] target/arm/cpu: Set number of PMU counters " Mathieu Poirier
@ 2026-07-28 19:26 ` Mathieu Poirier
2026-07-28 19:26 ` [RFC v2 15/24] hw/arm/virt: Set proper conduit method for Realms Mathieu Poirier
` (10 subsequent siblings)
24 siblings, 0 replies; 30+ messages in thread
From: Mathieu Poirier @ 2026-07-28 19:26 UTC (permalink / raw)
To: berrange, kchamart, pierrick.bouvier, peter.maydell, mst, cohuck,
pbonzini, eblake, armbru, lorenzo.pieralisi, gshan
Cc: qemu-devel, qemu-arm, kvm
From: Jean-Philippe Brucker <jean-philippe@linaro.org>
The host cannot access registers of a Realm. Instead of showing all
registers as zero in "info registers", display a message about this
restriction.
Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org>
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
target/arm/cpu.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index 787e4dc7ab23..7679b8758262 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -965,6 +965,11 @@ static void aarch64_cpu_dump_state(CPUState *cs, FILE *f, int flags)
const char *ns_status;
bool sve;
+ if (cpu->kvm_rme) {
+ qemu_fprintf(f, "the CPU registers are confidential to the realm\n");
+ return;
+ }
+
qemu_fprintf(f, " PC=%016" PRIx64 " ", env->pc);
for (i = 0; i < 32; i++) {
if (i == 31) {
--
2.43.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [RFC v2 15/24] hw/arm/virt: Set proper conduit method for Realms
2026-07-28 19:26 [RFC v2 00/24] Add Realm support to QEMU-VMM Mathieu Poirier
` (13 preceding siblings ...)
2026-07-28 19:26 ` [RFC v2 14/24] target/arm/cpu: Don't read Realm registers Mathieu Poirier
@ 2026-07-28 19:26 ` Mathieu Poirier
2026-07-28 19:26 ` [RFC v2 16/24] hw/arm/virt: Embed Realm VM type with IPA address space Mathieu Poirier
` (9 subsequent siblings)
24 siblings, 0 replies; 30+ messages in thread
From: Mathieu Poirier @ 2026-07-28 19:26 UTC (permalink / raw)
To: berrange, kchamart, pierrick.bouvier, peter.maydell, mst, cohuck,
pbonzini, eblake, armbru, lorenzo.pieralisi, gshan
Cc: qemu-devel, qemu-arm, kvm
From: Jean-Philippe Brucker <jean-philippe@linaro.org>
The HVC conduit for PSCI is not supported for Realms, so default
to SMC.
Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
hw/arm/virt.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 219597cabd0b..27bed9755320 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -274,6 +274,11 @@ static const int a15irqmap[] = {
[VIRT_PLATFORM_BUS] = 112, /* ...to 112 + PLATFORM_BUS_NUM_IRQS -1 */
};
+static bool virt_machine_is_confidential(VirtMachineState *vms)
+{
+ return MACHINE(vms)->cgs;
+}
+
static void create_randomness(MachineState *ms, const char *node)
{
struct {
@@ -2952,10 +2957,11 @@ static void machvirt_init(MachineState *machine)
* if the guest has EL2 then we will use SMC as the conduit,
* and otherwise we will use HVC (for backwards compatibility and
* because if we're using KVM then we must use HVC).
+ * Realm guests must also use SMC.
*/
if (vms->secure && firmware_loaded) {
vms->psci_conduit = QEMU_PSCI_CONDUIT_DISABLED;
- } else if (vms->virt) {
+ } else if (vms->virt || virt_machine_is_confidential(vms)) {
vms->psci_conduit = QEMU_PSCI_CONDUIT_SMC;
} else {
vms->psci_conduit = QEMU_PSCI_CONDUIT_HVC;
--
2.43.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [RFC v2 16/24] hw/arm/virt: Embed Realm VM type with IPA address space
2026-07-28 19:26 [RFC v2 00/24] Add Realm support to QEMU-VMM Mathieu Poirier
` (14 preceding siblings ...)
2026-07-28 19:26 ` [RFC v2 15/24] hw/arm/virt: Set proper conduit method for Realms Mathieu Poirier
@ 2026-07-28 19:26 ` Mathieu Poirier
2026-07-28 19:26 ` [RFC v2 17/24] hw/arm/virt: Reserve one bit of guest physical address for RME Mathieu Poirier
` (8 subsequent siblings)
24 siblings, 0 replies; 30+ messages in thread
From: Mathieu Poirier @ 2026-07-28 19:26 UTC (permalink / raw)
To: berrange, kchamart, pierrick.bouvier, peter.maydell, mst, cohuck,
pbonzini, eblake, armbru, lorenzo.pieralisi, gshan
Cc: qemu-devel, qemu-arm, kvm
From: Jean-Philippe Brucker <jean-philippe@linaro.org>
Set the Ream VM bit in the IPA address space size when needed.
Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org>
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
hw/arm/virt.c | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 27bed9755320..9123f46fae4a 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -97,6 +97,8 @@
#include "qemu/guest-random.h"
#include "hw/watchdog/sbsa_gwdt.h"
+#include <linux/kvm.h>
+
static GlobalProperty arm_virt_compat_defaults[] = {
{ TYPE_VIRTIO_IOMMU_PCI, "aw-bits", "48" },
};
@@ -4053,9 +4055,12 @@ static int virt_kvm_type(MachineState *ms, const char *type_str)
VirtMachineState *vms = VIRT_MACHINE(ms);
int max_vm_pa_size, requested_pa_size;
bool fixed_ipa;
+ int vm_type;
max_vm_pa_size = kvm_arm_get_max_vm_ipa_size(ms, &fixed_ipa);
+ vm_type = (ms->cgs ? KVM_VM_TYPE_ARM_REALM : KVM_VM_TYPE_ARM_NORMAL);
+
/* we freeze the memory map to compute the highest gpa */
virt_set_memmap(vms, max_vm_pa_size);
@@ -4080,7 +4085,11 @@ static int virt_kvm_type(MachineState *ms, const char *type_str)
* the implicit legacy 40b IPA setting, in which case the kvm_type
* must be 0.
*/
- return fixed_ipa ? 0 : requested_pa_size;
+ if (fixed_ipa) {
+ return 0;
+ }
+
+ return requested_pa_size | vm_type;
}
static int virt_get_physical_address_range(MachineState *ms,
--
2.43.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [RFC v2 17/24] hw/arm/virt: Reserve one bit of guest physical address for RME
2026-07-28 19:26 [RFC v2 00/24] Add Realm support to QEMU-VMM Mathieu Poirier
` (15 preceding siblings ...)
2026-07-28 19:26 ` [RFC v2 16/24] hw/arm/virt: Embed Realm VM type with IPA address space Mathieu Poirier
@ 2026-07-28 19:26 ` Mathieu Poirier
2026-07-28 19:26 ` [RFC v2 18/24] hw/arm/virt: Disable DTB randomness for confidential VMs Mathieu Poirier
` (7 subsequent siblings)
24 siblings, 0 replies; 30+ messages in thread
From: Mathieu Poirier @ 2026-07-28 19:26 UTC (permalink / raw)
To: berrange, kchamart, pierrick.bouvier, peter.maydell, mst, cohuck,
pbonzini, eblake, armbru, lorenzo.pieralisi, gshan
Cc: qemu-devel, qemu-arm, kvm
From: Jean-Philippe Brucker <jean-philippe@linaro.org>
When RME is enabled, the upper GPA bit is used to distinguish protected
from unprotected addresses. Reserve it when setting up the guest memory
map.
Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org>
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
hw/arm/virt.c | 20 +++++++++++++++-----
1 file changed, 15 insertions(+), 5 deletions(-)
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 9123f46fae4a..fa6cd62a335c 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -4054,17 +4054,27 @@ static int virt_kvm_type(MachineState *ms, const char *type_str)
{
VirtMachineState *vms = VIRT_MACHINE(ms);
int max_vm_pa_size, requested_pa_size;
+ int rme_reserve_bit = 0;
bool fixed_ipa;
int vm_type;
- max_vm_pa_size = kvm_arm_get_max_vm_ipa_size(ms, &fixed_ipa);
-
vm_type = (ms->cgs ? KVM_VM_TYPE_ARM_REALM : KVM_VM_TYPE_ARM_NORMAL);
+ if (vm_type) {
+ /*
+ * With RME, the upper GPA bit differentiates Realm from NS memory.
+ * Reserve the upper bit to ensure that highmem devices will fit.
+ */
+ rme_reserve_bit = 1;
+ }
+
+ max_vm_pa_size = kvm_arm_get_max_vm_ipa_size(ms, &fixed_ipa) -
+ rme_reserve_bit;
+
/* we freeze the memory map to compute the highest gpa */
virt_set_memmap(vms, max_vm_pa_size);
- requested_pa_size = 64 - clz64(vms->highest_gpa);
+ requested_pa_size = 64 - clz64(vms->highest_gpa) + rme_reserve_bit;
/*
* KVM requires the IPA size to be at least 32 bits.
@@ -4073,11 +4083,11 @@ static int virt_kvm_type(MachineState *ms, const char *type_str)
requested_pa_size = 32;
}
- if (requested_pa_size > max_vm_pa_size) {
+ if (requested_pa_size > max_vm_pa_size + rme_reserve_bit) {
error_report("-m and ,maxmem option values "
"require an IPA range (%d bits) larger than "
"the one supported by the host (%d bits)",
- requested_pa_size, max_vm_pa_size);
+ requested_pa_size, max_vm_pa_size + rme_reserve_bit);
return -1;
}
/*
--
2.43.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [RFC v2 18/24] hw/arm/virt: Disable DTB randomness for confidential VMs
2026-07-28 19:26 [RFC v2 00/24] Add Realm support to QEMU-VMM Mathieu Poirier
` (16 preceding siblings ...)
2026-07-28 19:26 ` [RFC v2 17/24] hw/arm/virt: Reserve one bit of guest physical address for RME Mathieu Poirier
@ 2026-07-28 19:26 ` Mathieu Poirier
2026-07-28 19:26 ` [RFC v2 19/24] hw/arm/virt: Move virt_flash_create() to machvirt_init() Mathieu Poirier
` (6 subsequent siblings)
24 siblings, 0 replies; 30+ messages in thread
From: Mathieu Poirier @ 2026-07-28 19:26 UTC (permalink / raw)
To: berrange, kchamart, pierrick.bouvier, peter.maydell, mst, cohuck,
pbonzini, eblake, armbru, lorenzo.pieralisi, gshan
Cc: qemu-devel, qemu-arm, kvm
From: Jean-Philippe Brucker <jean-philippe@linaro.org>
The dtb-randomness feature, which adds random seeds to the DTB, isn't
really compatible with confidential VMs since it randomizes the Realm
Initial Measurement. Enabling it is not an error, but it prevents
attestation. It also isn't useful to a Realm, which doesn't trust host
input.
Currently the feature is automatically enabled, unless the user disables
it on the command-line. Change it to OnOffAuto, and automatically
disable it for confidential VMs, unless the user explicitly enables it.
Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org>
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
docs/system/arm/virt.rst | 9 +++++----
hw/arm/virt.c | 41 +++++++++++++++++++++++++---------------
include/hw/arm/virt.h | 2 +-
3 files changed, 32 insertions(+), 20 deletions(-)
diff --git a/docs/system/arm/virt.rst b/docs/system/arm/virt.rst
index 5f6dd1797862..9882b842ddd5 100644
--- a/docs/system/arm/virt.rst
+++ b/docs/system/arm/virt.rst
@@ -238,10 +238,11 @@ dtb-randomness
rng-seed and kaslr-seed nodes (in both "/chosen" and
"/secure-chosen") to use for features like the random number
generator and address space randomisation. The default is
- ``on``. You will want to disable it if your trusted boot chain
- will verify the DTB it is passed, since this option causes the
- DTB to be non-deterministic. It would be the responsibility of
- the firmware to come up with a seed and pass it on if it wants to.
+ ``off`` for confidential VMs, and ``on`` otherwise. You will want
+ to disable it if your trusted boot chain will verify the DTB it is
+ passed, since this option causes the DTB to be non-deterministic.
+ It would be the responsibility of the firmware to come up with a
+ seed and pass it on if it wants to.
dtb-kaslr-seed
A deprecated synonym for dtb-randomness.
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index fa6cd62a335c..65ed8573f8b1 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -401,6 +401,7 @@ static int gic_fdt_irq_type_spi(const VirtMachineState *vms)
static void create_fdt(VirtMachineState *vms)
{
+ bool dtb_randomness = true;
MachineState *ms = MACHINE(vms);
int nb_numa_nodes = ms->numa_state->num_nodes;
void *fdt = create_device_tree(&vms->fdt_size);
@@ -410,6 +411,16 @@ static void create_fdt(VirtMachineState *vms)
exit(1);
}
+ /*
+ * Including random data in the DTB causes random intial measurement on CCA,
+ * so disable it for confidential VMs.
+ */
+ if (vms->dtb_randomness == ON_OFF_AUTO_OFF ||
+ (vms->dtb_randomness == ON_OFF_AUTO_AUTO &&
+ virt_machine_is_confidential(vms))) {
+ dtb_randomness = false;
+ }
+
ms->fdt = fdt;
/* Header */
@@ -431,13 +442,13 @@ static void create_fdt(VirtMachineState *vms)
/* /chosen must exist for load_dtb to fill in necessary properties later */
qemu_fdt_add_subnode(fdt, "/chosen");
- if (vms->dtb_randomness) {
+ if (dtb_randomness) {
create_randomness(ms, "/chosen");
}
if (vms->secure) {
qemu_fdt_add_subnode(fdt, "/secure-chosen");
- if (vms->dtb_randomness) {
+ if (dtb_randomness) {
create_randomness(ms, "/secure-chosen");
}
}
@@ -3512,18 +3523,21 @@ static void virt_set_virtio_transports(Object *obj, Visitor *v,
vms->virtio_transports = transports;
}
-static bool virt_get_dtb_randomness(Object *obj, Error **errp)
+static void virt_get_dtb_randomness(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
{
VirtMachineState *vms = VIRT_MACHINE(obj);
+ OnOffAuto dtb_randomness = vms->dtb_randomness;
- return vms->dtb_randomness;
+ visit_type_OnOffAuto(v, name, &dtb_randomness, errp);
}
-static void virt_set_dtb_randomness(Object *obj, bool value, Error **errp)
+static void virt_set_dtb_randomness(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
{
VirtMachineState *vms = VIRT_MACHINE(obj);
- vms->dtb_randomness = value;
+ visit_type_OnOffAuto(v, name, &vms->dtb_randomness, errp);
}
static char *virt_get_oem_id(Object *obj, Error **errp)
@@ -4343,16 +4357,16 @@ static void virt_machine_class_init(ObjectClass *oc, const void *data)
"Set MSI settings. "
"Valid values are auto, gicv2m, its and off");
- object_class_property_add_bool(oc, "dtb-randomness",
- virt_get_dtb_randomness,
- virt_set_dtb_randomness);
+ object_class_property_add(oc, "dtb-randomness", "OnOffAuto",
+ virt_get_dtb_randomness, virt_set_dtb_randomness,
+ NULL, NULL);
object_class_property_set_description(oc, "dtb-randomness",
"Set off to disable passing random or "
"non-deterministic dtb nodes to guest");
- object_class_property_add_bool(oc, "dtb-kaslr-seed",
- virt_get_dtb_randomness,
- virt_set_dtb_randomness);
+ object_class_property_add(oc, "dtb-kaslr-seed", "OnOffAuto",
+ virt_get_dtb_randomness, virt_set_dtb_randomness,
+ NULL, NULL);
object_class_property_set_description(oc, "dtb-kaslr-seed",
"Deprecated synonym of dtb-randomness");
@@ -4415,9 +4429,6 @@ static void virt_instance_init(Object *obj)
/* MTE is disabled by default. */
vms->mte = false;
- /* Supply kaslr-seed and rng-seed by default */
- vms->dtb_randomness = true;
-
vms->irqmap = a15irqmap;
vms->virtio_transports = NUM_VIRTIO_TRANSPORTS;
diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h
index 22e66d1a113c..d4c1aa04f664 100644
--- a/include/hw/arm/virt.h
+++ b/include/hw/arm/virt.h
@@ -176,7 +176,7 @@ struct VirtMachineState {
bool virt;
bool ras;
bool mte;
- bool dtb_randomness;
+ OnOffAuto dtb_randomness;
bool second_ns_uart_present;
OnOffAuto acpi;
VirtGICType gic_version;
--
2.43.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [RFC v2 19/24] hw/arm/virt: Move virt_flash_create() to machvirt_init()
2026-07-28 19:26 [RFC v2 00/24] Add Realm support to QEMU-VMM Mathieu Poirier
` (17 preceding siblings ...)
2026-07-28 19:26 ` [RFC v2 18/24] hw/arm/virt: Disable DTB randomness for confidential VMs Mathieu Poirier
@ 2026-07-28 19:26 ` Mathieu Poirier
2026-07-28 19:26 ` [RFC v2 20/24] hw/arm/virt: Use RAM instead of flash for confidential guest firmware Mathieu Poirier
` (5 subsequent siblings)
24 siblings, 0 replies; 30+ messages in thread
From: Mathieu Poirier @ 2026-07-28 19:26 UTC (permalink / raw)
To: berrange, kchamart, pierrick.bouvier, peter.maydell, mst, cohuck,
pbonzini, eblake, armbru, lorenzo.pieralisi, gshan
Cc: qemu-devel, qemu-arm, kvm
From: Jean-Philippe Brucker <jean-philippe@linaro.org>
For confidential VMs we'll want to skip flash device creation.
Unfortunately, in virt_instance_init() the machine->cgs member has not
yet been initialized, so we cannot check whether confidential guest is
enabled. Move virt_flash_create() to machvirt_init(), where we can
access the machine->cgs member.
Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
hw/arm/virt.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 65ed8573f8b1..74fe21712d4f 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -2911,6 +2911,8 @@ static void machvirt_init(MachineState *machine)
unsigned int smp_cpus = machine->smp.cpus;
unsigned int max_cpus = machine->smp.max_cpus;
+ virt_flash_create(vms);
+
possible_cpus = mc->possible_cpu_arch_ids(machine);
/*
@@ -4433,8 +4435,6 @@ static void virt_instance_init(Object *obj)
vms->virtio_transports = NUM_VIRTIO_TRANSPORTS;
- virt_flash_create(vms);
-
vms->oem_id = g_strndup(ACPI_BUILD_APPNAME6, 6);
vms->oem_table_id = g_strndup(ACPI_BUILD_APPNAME8, 8);
cxl_machine_init(obj, &vms->cxl_devices_state);
--
2.43.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [RFC v2 20/24] hw/arm/virt: Use RAM instead of flash for confidential guest firmware
2026-07-28 19:26 [RFC v2 00/24] Add Realm support to QEMU-VMM Mathieu Poirier
` (18 preceding siblings ...)
2026-07-28 19:26 ` [RFC v2 19/24] hw/arm/virt: Move virt_flash_create() to machvirt_init() Mathieu Poirier
@ 2026-07-28 19:26 ` Mathieu Poirier
2026-07-28 19:26 ` [RFC v2 21/24] target/arm/kvm-rme: Add DMA remapping for the shared memory region Mathieu Poirier
` (4 subsequent siblings)
24 siblings, 0 replies; 30+ messages in thread
From: Mathieu Poirier @ 2026-07-28 19:26 UTC (permalink / raw)
To: berrange, kchamart, pierrick.bouvier, peter.maydell, mst, cohuck,
pbonzini, eblake, armbru, lorenzo.pieralisi, gshan
Cc: qemu-devel, qemu-arm, kvm
From: Jean-Philippe Brucker <jean-philippe@linaro.org>
Use RAM instead of flash to store firmware image and boot information,
including UEFI variables. That way the firmware can be measured and
included in the Realm's initial measurements. It also prevents
variable stored in flash and modified as part of the boot process to
be leaked outside the Realm.
Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org>
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
hw/arm/boot.c | 37 +++++++++++++++++++++++++--
hw/arm/virt.c | 58 +++++++++++++++++++++++++++++++++++++++++++
include/hw/arm/boot.h | 9 +++++++
3 files changed, 102 insertions(+), 2 deletions(-)
diff --git a/hw/arm/boot.c b/hw/arm/boot.c
index 9b7553dde5e1..1e8efada209f 100644
--- a/hw/arm/boot.c
+++ b/hw/arm/boot.c
@@ -1112,7 +1112,36 @@ static void arm_setup_direct_kernel_boot(ARMCPU *cpu,
}
}
-static void arm_setup_firmware_boot(ARMCPU *cpu, struct arm_boot_info *info)
+static void arm_setup_confidential_firmware_boot(ARMCPU *cpu,
+ struct arm_boot_info *info,
+ const char *firmware_filename)
+{
+ ssize_t fw_size;
+ const char *fname;
+ AddressSpace *as = arm_boot_address_space(cpu, info);
+
+ fname = qemu_find_file(QEMU_FILE_TYPE_BIOS, firmware_filename);
+ if (!fname) {
+ error_report("Could not find firmware image '%s'", firmware_filename);
+ exit(1);
+ }
+
+ /*
+ * Load the firmware image in the Realm's address space. Mapping of the
+ * firmware area in the Realm's address space is done in function
+ * virt_confidential_firmware_init().
+ */
+ fw_size = load_image_targphys_as(firmware_filename,
+ info->firmware_base,
+ info->firmware_max_size, as, NULL);
+ if (fw_size <= 0) {
+ error_report("could not load firmware '%s'", firmware_filename);
+ exit(1);
+ }
+}
+
+static void arm_setup_firmware_boot(ARMCPU *cpu, struct arm_boot_info *info,
+ const char *firmware_filename)
{
/* Set up for booting firmware (which might load a kernel via fw_cfg) */
@@ -1168,6 +1197,10 @@ static void arm_setup_firmware_boot(ARMCPU *cpu, struct arm_boot_info *info)
}
}
+ if (info->confidential) {
+ arm_setup_confidential_firmware_boot(cpu, info, firmware_filename);
+ }
+
/*
* We will start from address 0 (typically a boot ROM image) in the
* same way as hardware. Leave env->boot_info NULL, so that
@@ -1212,7 +1245,7 @@ void arm_load_kernel(ARMCPU *cpu, MachineState *ms, struct arm_boot_info *info)
/* Load the kernel. */
if (!info->kernel_filename || info->firmware_loaded) {
- arm_setup_firmware_boot(cpu, info);
+ arm_setup_firmware_boot(cpu, info, ms->firmware);
} else {
arm_setup_direct_kernel_boot(cpu, info);
}
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 74fe21712d4f..ae663d051ac3 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -1823,6 +1823,16 @@ static PFlashCFI01 *virt_flash_create1(VirtMachineState *vms,
static void virt_flash_create(VirtMachineState *vms)
{
+ /*
+ * For Realms, the firmware image is placed directly in the guest's
+ * RAM area. The association between the final location in the
+ * guest's RAM and the system memory is done in function
+ * virt_confidential_firmware_init().
+ */
+ if (virt_machine_is_confidential(vms)) {
+ return;
+ }
+
vms->flash[0] = virt_flash_create1(vms, "virt.flash0", "pflash0");
vms->flash[1] = virt_flash_create1(vms, "virt.flash1", "pflash1");
}
@@ -1873,6 +1883,16 @@ static void virt_flash_fdt(VirtMachineState *vms,
MachineState *ms = MACHINE(vms);
char *nodename;
+ /*
+ * For Realms the firmware images are stored in the guest's address
+ * space. As such there is no need for flash configuration in the FDT.
+ * See function virt_confidential_firmware_init() and
+ * arm_setup_confidential_firmware_boot() for details.
+ */
+ if (virt_machine_is_confidential(vms)) {
+ return;
+ }
+
if (sysmem == secure_sysmem) {
/* Report both flash devices as a single node in the DT */
nodename = g_strdup_printf("/flash@%" PRIx64, flashbase);
@@ -1908,6 +1928,32 @@ static void virt_flash_fdt(VirtMachineState *vms,
}
}
+static bool virt_confidential_firmware_init(VirtMachineState *vms,
+ MemoryRegion *sysmem)
+{
+ MemoryRegion *fw_ram;
+ hwaddr fw_base = vms->memmap[VIRT_FLASH].base;
+ hwaddr fw_size = vms->memmap[VIRT_FLASH].size;
+
+ if (!MACHINE(vms)->firmware) {
+ return false;
+ }
+
+ assert(machine_require_guest_memfd(MACHINE(vms)));
+
+ fw_ram = g_new(MemoryRegion, 1);
+ memory_region_init_ram_guest_memfd(fw_ram, NULL, "fw_ram", fw_size,
+ &error_fatal);
+ /*
+ * Map the guest's firmware image directly in its address space.
+ * Copying of the firmware image itself is done in function
+ * arm_setup_confidential_firmware_boot().
+ */
+ memory_region_add_subregion(sysmem, fw_base, fw_ram);
+
+ return true;
+}
+
static bool virt_firmware_init(VirtMachineState *vms,
MemoryRegion *sysmem,
MemoryRegion *secure_sysmem)
@@ -1916,6 +1962,15 @@ static bool virt_firmware_init(VirtMachineState *vms,
const char *bios_name;
BlockBackend *pflash_blk0;
+ /*
+ * For a confidential VM, the firmware image and any boot information,
+ * including EFI variables, are stored in RAM in order to be measurable and
+ * private. Create a RAM region and load the firmware image there.
+ */
+ if (virt_machine_is_confidential(vms)) {
+ return virt_confidential_firmware_init(vms, sysmem);
+ }
+
/* Map legacy -drive if=pflash to machine properties */
for (i = 0; i < ARRAY_SIZE(vms->flash); i++) {
pflash_cfi01_legacy_drive(vms->flash[i],
@@ -3278,7 +3333,10 @@ static void machvirt_init(MachineState *machine)
vms->bootinfo.get_dtb = machvirt_dtb;
vms->bootinfo.skip_dtb_autoload = true;
vms->bootinfo.firmware_loaded = firmware_loaded;
+ vms->bootinfo.firmware_base = vms->memmap[VIRT_FLASH].base;
+ vms->bootinfo.firmware_max_size = vms->memmap[VIRT_FLASH].size;
vms->bootinfo.psci_conduit = vms->psci_conduit;
+ vms->bootinfo.confidential = virt_machine_is_confidential(vms);
arm_load_kernel(ARM_CPU(first_cpu), machine, &vms->bootinfo);
vms->machine_done.notify = virt_machine_done;
diff --git a/include/hw/arm/boot.h b/include/hw/arm/boot.h
index 94386fdbea6c..fe7e14e94651 100644
--- a/include/hw/arm/boot.h
+++ b/include/hw/arm/boot.h
@@ -113,6 +113,10 @@ struct arm_boot_info {
*/
bool firmware_loaded;
+ /* Used when loading firmware into RAM */
+ hwaddr firmware_base;
+ hwaddr firmware_max_size;
+
/* Address at which board specific loader/setup code exists. If enabled,
* this code-blob will run before anything else. It must return to the
* caller via the link register. There is no stack set up. Enabled by
@@ -136,6 +140,11 @@ struct arm_boot_info {
/* CPU having load the kernel and that should be the first to boot. */
ARMCPU *primary_cpu;
+
+ /*
+ * Confidential guest boot loads everything into RAM so it can be measured.
+ */
+ bool confidential;
};
/**
--
2.43.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [RFC v2 21/24] target/arm/kvm-rme: Add DMA remapping for the shared memory region
2026-07-28 19:26 [RFC v2 00/24] Add Realm support to QEMU-VMM Mathieu Poirier
` (19 preceding siblings ...)
2026-07-28 19:26 ` [RFC v2 20/24] hw/arm/virt: Use RAM instead of flash for confidential guest firmware Mathieu Poirier
@ 2026-07-28 19:26 ` Mathieu Poirier
2026-07-28 19:26 ` [RFC v2 22/24] docs/interop/firmware.json: Add arm-rme firmware feature Mathieu Poirier
` (3 subsequent siblings)
24 siblings, 0 replies; 30+ messages in thread
From: Mathieu Poirier @ 2026-07-28 19:26 UTC (permalink / raw)
To: berrange, kchamart, pierrick.bouvier, peter.maydell, mst, cohuck,
pbonzini, eblake, armbru, lorenzo.pieralisi, gshan
Cc: qemu-devel, qemu-arm, kvm
From: Jean-Philippe Brucker <jean-philippe@linaro.org>
In Arm CCA, the guest-physical address space is split in half. The top
half represents memory shared between guest and host, and the bottom
half is private to the guest. From QEMU's point of view, the two halves
are merged into a single region, and pages within this region are either
shared or private.
Virtual devices implemented by the host are only allowed to access the
top half. For emulated MMIO, KVM strips the GPA before returning to
QEMU, so the GPA already belongs to QEMU's merged view of guest memory.
However DMA addresses cannot be stripped this way and need special
handling by the VMM.
When emulating DMA the VMM needs to translate the addresses into its
merged view. Add an IOMMU memory region on the top half, that
retargets DMA accesses to the merged sysmem.
Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org>
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
hw/arm/virt.c | 2 +
target/arm/kvm-rme.c | 106 ++++++++++++++++++++++++++++++++++++++++++
target/arm/kvm-stub.c | 4 ++
target/arm/kvm_arm.h | 10 ++++
4 files changed, 122 insertions(+)
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index ae663d051ac3..5b1608c23462 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -3327,6 +3327,8 @@ static void machvirt_init(MachineState *machine)
vms->fw_cfg, OBJECT(vms));
}
+ kvm_arm_rme_init_gpa_space(vms->highest_gpa, vms->bus);
+
vms->bootinfo.ram_size = machine->ram_size;
vms->bootinfo.board_id = -1;
vms->bootinfo.loader_start = vms->memmap[VIRT_MEM].base;
diff --git a/target/arm/kvm-rme.c b/target/arm/kvm-rme.c
index 335ad60d0f3b..7b83de2f956b 100644
--- a/target/arm/kvm-rme.c
+++ b/target/arm/kvm-rme.c
@@ -11,10 +11,12 @@
#include "hw/core/boards.h"
#include "hw/core/cpu.h"
#include "hw/core/loader.h"
+#include "hw/pci/pci.h"
#include "kvm_arm.h"
#include "migration/blocker.h"
#include "qapi/error.h"
#include "qemu/error-report.h"
+#include "qemu/units.h"
#include "qom/object_interfaces.h"
#include "system/confidential-guest-support.h"
#include "system/kvm.h"
@@ -25,6 +27,23 @@ OBJECT_DECLARE_SIMPLE_TYPE(RmeGuest, RME_GUEST)
#define RME_PAGE_SIZE qemu_real_host_page_size()
+/*
+ * Realms have a split guest-physical address space: the bottom half is private
+ * to the realm, and the top half is shared with the host. Within QEMU, we use a
+ * merged view of both halves. Most of RAM is private to the guest and not
+ * accessible to us, but the guest shares some pages with us.
+ *
+ * RealmDmaRegion performs remapping of top-half accesses to system memory.
+ */
+struct RealmDmaRegion {
+ IOMMUMemoryRegion parent_obj;
+};
+
+#define TYPE_REALM_DMA_REGION "realm-dma-region"
+OBJECT_DECLARE_SIMPLE_TYPE(RealmDmaRegion, REALM_DMA_REGION)
+OBJECT_DEFINE_SIMPLE_TYPE(RealmDmaRegion, realm_dma_region,
+ REALM_DMA_REGION, IOMMU_MEMORY_REGION);
+
typedef struct {
hwaddr base;
hwaddr size;
@@ -35,6 +54,10 @@ struct RmeGuest {
ConfidentialGuestSupport parent_obj;
Notifier rom_load_notifier;
GSList *ram_regions;
+ uint8_t ipa_bits;
+
+ RealmDmaRegion *dma_region;
+ AddressSpace dma_as;
};
OBJECT_DEFINE_SIMPLE_TYPE_WITH_INTERFACES(RmeGuest, rme_guest, RME_GUEST,
@@ -205,3 +228,86 @@ static void rme_guest_init(Object *obj)
static void rme_guest_finalize(Object *obj)
{
}
+
+static AddressSpace *rme_dma_get_address_space(PCIBus *bus, void *opaque,
+ int devfn)
+{
+ return &rme_guest->dma_as;
+}
+
+static const PCIIOMMUOps rme_dma_ops = {
+ .get_address_space = rme_dma_get_address_space,
+};
+
+void kvm_arm_rme_init_gpa_space(hwaddr highest_gpa, PCIBus *pci_bus)
+{
+ RealmDmaRegion *dma_region;
+ const unsigned int ipa_bits = 64 - clz64(highest_gpa) + 1;
+
+ if (!rme_guest) {
+ return;
+ }
+
+ assert(ipa_bits < 64);
+
+ /*
+ * Setup a DMA translation from the shared top half of the guest-physical
+ * address space to our merged view of RAM.
+ */
+ dma_region = g_new0(RealmDmaRegion, 1);
+
+ memory_region_init_iommu(dma_region, sizeof(*dma_region),
+ TYPE_REALM_DMA_REGION, OBJECT(rme_guest),
+ "realm-dma-region", 1ULL << ipa_bits);
+ address_space_init(&rme_guest->dma_as, MEMORY_REGION(dma_region),
+ TYPE_REALM_DMA_REGION);
+ rme_guest->dma_region = dma_region;
+ rme_guest->ipa_bits = ipa_bits;
+
+ pci_setup_iommu(pci_bus, &rme_dma_ops, NULL);
+}
+
+static void realm_dma_region_init(Object *obj)
+{
+}
+
+static IOMMUTLBEntry realm_dma_region_translate(IOMMUMemoryRegion *mr,
+ hwaddr addr,
+ IOMMUAccessFlags flag,
+ int iommu_idx)
+{
+ const hwaddr address_mask = MAKE_64BIT_MASK(0, rme_guest->ipa_bits - 1);
+ IOMMUTLBEntry entry = {
+ .target_as = &address_space_memory,
+ .iova = addr,
+ .translated_addr = addr & address_mask,
+ /*
+ * Somewhat arbitrary granule for users that need one, such as
+ * address_space_get_iotlb_entry(). Should be relatively large to
+ * avoid frequent TLB misses. It can't be larger than memory region
+ * alignment (eg. address_mask) because that would mask the whole
+ * address, preventing vhost from finding the correct memory region.
+ */
+ .addr_mask = 4 * KiB - 1,
+ .perm = IOMMU_RW,
+ };
+
+ return entry;
+}
+
+static void realm_dma_region_replay(IOMMUMemoryRegion *mr, IOMMUNotifier *n)
+{
+ /* Nothing is shared at boot */
+}
+
+static void realm_dma_region_finalize(Object *obj)
+{
+}
+
+static void realm_dma_region_class_init(ObjectClass *oc, const void *data)
+{
+ IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(oc);
+
+ imrc->translate = realm_dma_region_translate;
+ imrc->replay = realm_dma_region_replay;
+}
diff --git a/target/arm/kvm-stub.c b/target/arm/kvm-stub.c
index 5fde96f9b281..e5af5d20367f 100644
--- a/target/arm/kvm-stub.c
+++ b/target/arm/kvm-stub.c
@@ -42,6 +42,10 @@ bool kvm_arm_el2_supported(void)
return false;
}
+void kvm_arm_rme_init_gpa_space(hwaddr highest_gpa, PCIBus *pci_bus)
+{
+}
+
/*
* These functions should never actually be called without KVM support.
*/
diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h
index d95381c13afa..b4a293911f71 100644
--- a/target/arm/kvm_arm.h
+++ b/target/arm/kvm_arm.h
@@ -250,4 +250,14 @@ char *kvm_print_register_name(uint64_t regidx);
*/
void kvm_arm_rme_vcpu_init(ARMCPU *cpu);
+/**
+ * kvm_arm_rme_setup_gpa
+ * @highest_gpa: highest address of the lower half of the guest address space
+ * @pci_bus: The main PCI bus, for which PCI queries DMA address spaces
+ *
+ * Setup the guest-physical address space for a Realm. Install a memory region
+ * and notifier to manage the shared upper half of the address space.
+ */
+void kvm_arm_rme_init_gpa_space(hwaddr highest_gpa, PCIBus *pci_bus);
+
#endif
--
2.43.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [RFC v2 22/24] docs/interop/firmware.json: Add arm-rme firmware feature
2026-07-28 19:26 [RFC v2 00/24] Add Realm support to QEMU-VMM Mathieu Poirier
` (20 preceding siblings ...)
2026-07-28 19:26 ` [RFC v2 21/24] target/arm/kvm-rme: Add DMA remapping for the shared memory region Mathieu Poirier
@ 2026-07-28 19:26 ` Mathieu Poirier
2026-07-28 19:26 ` [RFC v2 23/24] hw/arm/boot: Load DTB as is for confidential VMs Mathieu Poirier
` (2 subsequent siblings)
24 siblings, 0 replies; 30+ messages in thread
From: Mathieu Poirier @ 2026-07-28 19:26 UTC (permalink / raw)
To: berrange, kchamart, pierrick.bouvier, peter.maydell, mst, cohuck,
pbonzini, eblake, armbru, lorenzo.pieralisi, gshan
Cc: qemu-devel, qemu-arm, kvm
From: Jean-Philippe Brucker <jean-philippe@linaro.org>
Some distributions provide packages continaing firmware to be run under
QEMU, such as "qemu-efi-aarch64" or "edk2-aarch64". Those packages also
contain descriptors in /usr/share/qemu/firmware/*.json listing the
firmware features, so that environments like libvirt can figure out
which firmware they can load.
Define an optional feature for arm64 firmware to indicate that a
firmware supports running in a Realm. Firmware implementations need
extra support for running in a Realm, in particular to distinguish
shared from private guest memory.
Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org>
Acked-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
docs/interop/firmware.json | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/docs/interop/firmware.json b/docs/interop/firmware.json
index 421bee0e5ed4..2850b91078d9 100644
--- a/docs/interop/firmware.json
+++ b/docs/interop/firmware.json
@@ -161,6 +161,9 @@
# options related to this feature are documented in
# "docs/system/i386/amd-memory-encryption.rst".
#
+# @arm-rme: The firmware supports running in a Realm, under the Arm Realm
+# Management Extension (RME).
+#
# @intel-tdx: The firmware supports running under Intel Trust Domain
# Extensions (TDX).
#
@@ -229,7 +232,7 @@
{ 'enum' : 'FirmwareFeature',
'data' : [ 'acpi-s3', 'acpi-s4',
'amd-sev', 'amd-sev-es', 'amd-sev-snp',
- 'intel-tdx',
+ 'arm-rme', 'intel-tdx',
'enrolled-keys', 'requires-smm',
'secure-boot', 'host-uefi-vars',
'verbose-dynamic', 'verbose-static' ] }
--
2.43.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [RFC v2 23/24] hw/arm/boot: Load DTB as is for confidential VMs
2026-07-28 19:26 [RFC v2 00/24] Add Realm support to QEMU-VMM Mathieu Poirier
` (21 preceding siblings ...)
2026-07-28 19:26 ` [RFC v2 22/24] docs/interop/firmware.json: Add arm-rme firmware feature Mathieu Poirier
@ 2026-07-28 19:26 ` Mathieu Poirier
2026-07-28 19:26 ` [RFC v2 24/24] hw/arm/boot: Skip bootloader for confidential guests Mathieu Poirier
2026-07-30 5:11 ` [RFC v2 00/24] Add Realm support to QEMU-VMM Kohei Enju
24 siblings, 0 replies; 30+ messages in thread
From: Mathieu Poirier @ 2026-07-28 19:26 UTC (permalink / raw)
To: berrange, kchamart, pierrick.bouvier, peter.maydell, mst, cohuck,
pbonzini, eblake, armbru, lorenzo.pieralisi, gshan
Cc: qemu-devel, qemu-arm, kvm
From: Jean-Philippe Brucker <jean-philippe@linaro.org>
Load DTB without modifications when provided. That way it is possible
for a verification entity to reconstruct the Realm's initial measurement.
Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org>
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
hw/arm/boot.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/hw/arm/boot.c b/hw/arm/boot.c
index 1e8efada209f..9b3d3558bcbc 100644
--- a/hw/arm/boot.c
+++ b/hw/arm/boot.c
@@ -477,7 +477,14 @@ int arm_load_dtb(hwaddr addr, const struct arm_boot_info *binfo,
g_autoptr(MemoryDeviceInfoList) md_list = NULL;
Error *err = NULL;
- if (binfo->dtb_filename) {
+ if (binfo->dtb_filename && binfo->confidential) {
+ /*
+ * If the user is providing a DTB for a confidential VM, it is already
+ * tailored to this configuration and measured. Load it as is, without
+ * any modification.
+ */
+ return rom_add_file_fixed_as(binfo->dtb_filename, addr, -1, as);
+ } else if (binfo->dtb_filename) {
char *filename;
filename = qemu_find_file(QEMU_FILE_TYPE_DTB, binfo->dtb_filename);
if (!filename) {
--
2.43.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [RFC v2 24/24] hw/arm/boot: Skip bootloader for confidential guests
2026-07-28 19:26 [RFC v2 00/24] Add Realm support to QEMU-VMM Mathieu Poirier
` (22 preceding siblings ...)
2026-07-28 19:26 ` [RFC v2 23/24] hw/arm/boot: Load DTB as is for confidential VMs Mathieu Poirier
@ 2026-07-28 19:26 ` Mathieu Poirier
2026-07-30 5:11 ` [RFC v2 00/24] Add Realm support to QEMU-VMM Kohei Enju
24 siblings, 0 replies; 30+ messages in thread
From: Mathieu Poirier @ 2026-07-28 19:26 UTC (permalink / raw)
To: berrange, kchamart, pierrick.bouvier, peter.maydell, mst, cohuck,
pbonzini, eblake, armbru, lorenzo.pieralisi, gshan
Cc: qemu-devel, qemu-arm, kvm
From: Jean-Philippe Brucker <jean-philippe@linaro.org>
An independent verifier needs to reconstruct the content of guest memory
in order to attest that it is running trusted code. To avoid having to
reconstruct the bootloader generated by QEMU, skip this step and jump
directly to the kernel, with the DTB address in x0 as specified by the
Linux boot protocol [1].
[1] https://docs.kernel.org/arch/arm64/booting.html
Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org>
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
hw/arm/boot.c | 24 ++++++++++++++++++------
1 file changed, 18 insertions(+), 6 deletions(-)
diff --git a/hw/arm/boot.c b/hw/arm/boot.c
index 9b3d3558bcbc..da4f399a3026 100644
--- a/hw/arm/boot.c
+++ b/hw/arm/boot.c
@@ -731,7 +731,13 @@ static void do_cpu_reset(void *opaque)
if (cpu == info->primary_cpu) {
AddressSpace *as = arm_boot_address_space(cpu, info);
- cpu_set_pc(cs, info->loader_start);
+ if (info->confidential) {
+ assert(is_a64(env));
+ env->xregs[0] = info->dtb_start;
+ cpu_set_pc(cs, info->entry);
+ } else {
+ cpu_set_pc(cs, info->loader_start);
+ }
if (!have_dtb(info)) {
set_kernel_args(info, as);
@@ -821,7 +827,8 @@ static ssize_t arm_load_elf(struct arm_boot_info *info, uint64_t *pentry,
}
static uint64_t load_aarch64_image(const char *filename, hwaddr mem_base,
- hwaddr *entry, AddressSpace *as)
+ hwaddr *entry, AddressSpace *as,
+ bool confidential)
{
const size_t max_bytes = LOAD_IMAGE_MAX_DECOMPRESSED_BYTES;
hwaddr kernel_load_offset = KERNEL64_LOAD_ADDR;
@@ -873,7 +880,8 @@ static uint64_t load_aarch64_image(const char *filename, hwaddr mem_base,
* bootloader, we can just load it starting at 2MB+offset rather
* than 0MB + offset.
*/
- if (kernel_load_offset < BOOTLOADER_MAX_SIZE) {
+ if (kernel_load_offset < BOOTLOADER_MAX_SIZE &&
+ !confidential) {
kernel_load_offset += 2 * MiB;
}
}
@@ -957,7 +965,8 @@ static void arm_setup_direct_kernel_boot(ARMCPU *cpu,
}
if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64) && kernel_size < 0) {
kernel_size = load_aarch64_image(info->kernel_filename,
- info->loader_start, &entry, as);
+ info->loader_start, &entry, as,
+ info->confidential);
is_linux = 1;
if (kernel_size >= 0) {
image_low_addr = entry;
@@ -1098,8 +1107,11 @@ static void arm_setup_direct_kernel_boot(ARMCPU *cpu,
fixupcontext[FIXUP_ENTRYPOINT_LO] = entry;
fixupcontext[FIXUP_ENTRYPOINT_HI] = entry >> 32;
- arm_write_bootloader("bootloader", as, info->loader_start,
- primary_loader, fixupcontext);
+ /* Immediately jump to the kernel when guest is a Realm */
+ if (!info->confidential) {
+ arm_write_bootloader("bootloader", as, info->loader_start,
+ primary_loader, fixupcontext);
+ }
if (info->write_board_setup) {
info->write_board_setup(cpu, info);
--
2.43.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* Re: [RFC v2 00/24] Add Realm support to QEMU-VMM
2026-07-28 19:26 [RFC v2 00/24] Add Realm support to QEMU-VMM Mathieu Poirier
` (23 preceding siblings ...)
2026-07-28 19:26 ` [RFC v2 24/24] hw/arm/boot: Skip bootloader for confidential guests Mathieu Poirier
@ 2026-07-30 5:11 ` Kohei Enju
2026-08-09 13:06 ` Mathieu Poirier
24 siblings, 1 reply; 30+ messages in thread
From: Kohei Enju @ 2026-07-30 5:11 UTC (permalink / raw)
To: Mathieu Poirier
Cc: berrange, kchamart, pierrick.bouvier, peter.maydell, mst, cohuck,
pbonzini, eblake, armbru, lorenzo.pieralisi, gshan, qemu-devel,
qemu-arm, kvm
On 07/28 13:26, Mathieu Poirier wrote:
> This patchset provides minimal functionality to start a Realm VM
> from an Arm RME capable host using the following command line:
>
> qemu-system-aarch64 \
> -M confidential-guest-support=rme0 -object rme-guest,id=rme0 \
> -cpu host -M virt -enable-kvm -M gic-version=3,its=on -nodefaults ..
>
> It is a refactoring of Jean-Philippe Brucker's initial work dating from a while
> back. It is compatible with Steven Price's v14 revision [1] of his work adding
> CCA support to KVM.
>
> * We are currently working on rebasing the work to v15.
>
> It was tested on the QEMU SBSA machine. For convenience, a repository is hosted
> here [2], along with the TF-A [3], RMM [4] and Linux kernel [5] for the SBSA
> machine (compatible with Steven's v14 patchset).
>
> Instructions to compile and run the entire stack can be found here [6].
>
> Device Assignment is not included.
>
> Thanks,
> Mathieu
Hi Mathieu, thank you for your work on upstreaming CCA support. I've
tested this series in QEMU-TCG(x-rme=on) environments and confirmed
that the basic functionality works well.
I have a question about a QMP command for querying CCA capabilities.
Jean's tree contains the following commit adding such a QMP command. Was
this functionality intentionally omitted from this series?
https://git.codelinaro.org/linaro/dcap/qemu/-/commit/41f7852cc8590a38c47299a35a7238da09ff9a12
We are interested in adding this functionality because we are also
planning to upstream CCA support for libvirt, which will need a QMP
interface to query the CCA capabilities exposed by QEMU.
Since the Linux kernel dropped some configuration parameters such as the
hash algorithm, I need to rework the implementation of that QMP command
a bit. If it's okay with you, I'd be happy to send out the reworked
patch based on this series.
Thanks,
Kohei
>
> [1]. https://lore.kernel.org/kvm/20260513131757.116630-1-steven.price@arm.com/T/#m06dd14216aaf76acab65b0a76fb84653141ea64f
> [2]. https://gitlab.com/Linaro/cca-public/qemu/-/tree/upstream-v2?ref_type=heads
> [3]. https://gitlab.com/Linaro/cca-public/tf-a/trusted-firmware-a/-/tree/cca/v13?ref_type=heads
> [4]. https://gitlab.com/Linaro/cca-public/rmm/-/tree/cca/v14?ref_type=heads
> [5]. https://gitlab.com/Linaro/cca-public/linux/-/tree/upstream-v2?ref_type=heads
> [6]. https://gitlab.com/Linaro/cca-public/build-instructions
>
> RFC v1:
> https://lists.gnu.org/archive/html/qemu-devel/2026-07/msg02307.html
>
> Changes for V2:
> - Fixed linux headers to include correct bit shift for Realm VM (Gavin).
> - Removed obsolete rme-guest options (Markus).
> - Set ConfidentialGuestSupportClass::kvm_init() to kvm_arm_rme_init() (Gavin).
> - Got rid of kvm_arm_rme_vm_type() (Gavin).
> - Used kvm_vm_check_extension() instead of kvm_check_extension() to avoid
> error message when starting a Realm (Gavin).
> - Removed obsolete kvm_arm_rme_init_guest_ram() (Gavin).
> - Collected A-B and R-B.
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [RFC v2 01/24] linux-headers: Add RME related definitions
2026-07-28 19:26 ` [RFC v2 01/24] linux-headers: Add RME related definitions Mathieu Poirier
@ 2026-07-30 5:41 ` Kohei Enju
2026-07-30 6:08 ` Gavin Shan
0 siblings, 1 reply; 30+ messages in thread
From: Kohei Enju @ 2026-07-30 5:41 UTC (permalink / raw)
To: Mathieu Poirier
Cc: berrange, kchamart, pierrick.bouvier, peter.maydell, mst, cohuck,
pbonzini, eblake, armbru, lorenzo.pieralisi, gshan, qemu-devel,
qemu-arm, kvm
On 07/28 13:26, Mathieu Poirier wrote:
> From: Jean-Philippe Brucker <jean-philippe@linaro.org>
>
> This is a temporary patch intended for testing purposes only. It provides
> definitions related to supporting Realms by the QEMU-VMM.
>
> Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org>
> Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
> ---
> linux-headers/asm-arm64/kvm.h | 9 +++++++++
> linux-headers/linux/kvm.h | 10 +++++++++-
> 2 files changed, 18 insertions(+), 1 deletion(-)
>
> diff --git a/linux-headers/asm-arm64/kvm.h b/linux-headers/asm-arm64/kvm.h
> index 6aefe7973814..4c08631ec7d2 100644
> --- a/linux-headers/asm-arm64/kvm.h
> +++ b/linux-headers/asm-arm64/kvm.h
> @@ -208,6 +208,15 @@ struct kvm_arm_counter_offset {
> __u64 reserved;
> };
>
> +#define KVM_ARM_RMI_POPULATE_FLAGS_MEASURE (1 << 0)
> +struct kvm_arm_rmi_populate {
> + __u64 base;
> + __u64 size;
> + __u64 source_uaddr;
> + __u32 flags;
> + __u32 reserved;
> +};
> +
> #define KVM_ARM_TAGS_TO_GUEST 0
> #define KVM_ARM_TAGS_FROM_GUEST 1
>
> diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h
> index dd52e2a65bfd..cdd5ad11f85a 100644
> --- a/linux-headers/linux/kvm.h
> +++ b/linux-headers/linux/kvm.h
> @@ -689,14 +689,19 @@ struct kvm_enable_cap {
> * address size for the VM. Bits[7-0] are reserved for the guest
> * PA size shift (i.e, log2(PA_Size)). For backward compatibility,
> * value 0 implies the default IPA size, 40bits.
> + *
> + * Bits[30-31] are reserved for the VM type
> */
> #define KVM_VM_TYPE_ARM_IPA_SIZE_MASK 0xffULL
> #define KVM_VM_TYPE_ARM_IPA_SIZE(x) \
> ((x) & KVM_VM_TYPE_ARM_IPA_SIZE_MASK)
>
> +#define KVM_VM_TYPE_ARM_NORMAL 0
> +#define KVM_VM_TYPE_ARM_REALM (1UL << 30)
> #define KVM_VM_TYPE_ARM_PROTECTED (1UL << 31)
> #define KVM_VM_TYPE_ARM_MASK (KVM_VM_TYPE_ARM_IPA_SIZE_MASK | \
> - KVM_VM_TYPE_ARM_PROTECTED)
> + KVM_VM_TYPE_ARM_PROTECTED | \
> + KVM_VM_TYPE_ARM_REALM)
>
> /*
> * ioctls for /dev/kvm fds:
> @@ -719,6 +724,8 @@ struct kvm_enable_cap {
> #define KVM_GET_EMULATED_CPUID _IOWR(KVMIO, 0x09, struct kvm_cpuid2)
> #define KVM_GET_MSR_FEATURE_INDEX_LIST _IOWR(KVMIO, 0x0a, struct kvm_msr_list)
>
> +#define KVM_ARM_RMI_POPULATE _IOWR(KVMIO, 0xd7, struct kvm_arm_rmi_populate)
> +
> /*
> * Extension capability list.
> */
> @@ -986,6 +993,7 @@ struct kvm_enable_cap {
> #define KVM_CAP_S390_KEYOP 247
> #define KVM_CAP_S390_VSIE_ESAMODE 248
> #define KVM_CAP_S390_HPAGE_2G 249
> +#define KVM_CAP_ARM_RMI 250
Not a big deal, but a note for anyone testing this series:
Use Linaro's Linux kernel tree, as mentioned in the cover letter:
https://gitlab.com/Linaro/cca-public/linux/-/tree/upstream-v2?ref_type=heads
Alternetively, if you're using Arm's tree or other trees with Steven
Price's v14 series as I am:
You'll need to adjust the definition of KVM_CAP_ARM_RMI, since it uses a
differenct capability number.
>
> struct kvm_irq_routing_irqchip {
> __u32 irqchip;
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [RFC v2 01/24] linux-headers: Add RME related definitions
2026-07-30 5:41 ` Kohei Enju
@ 2026-07-30 6:08 ` Gavin Shan
2026-07-30 6:13 ` Kohei Enju
0 siblings, 1 reply; 30+ messages in thread
From: Gavin Shan @ 2026-07-30 6:08 UTC (permalink / raw)
To: Kohei Enju, Mathieu Poirier
Cc: berrange, kchamart, pierrick.bouvier, peter.maydell, mst, cohuck,
pbonzini, eblake, armbru, lorenzo.pieralisi, qemu-devel, qemu-arm,
kvm
On 7/30/26 3:41 PM, Kohei Enju wrote:
> On 07/28 13:26, Mathieu Poirier wrote:
>> From: Jean-Philippe Brucker <jean-philippe@linaro.org>
>>
>> This is a temporary patch intended for testing purposes only. It provides
>> definitions related to supporting Realms by the QEMU-VMM.
>>
>> Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org>
>> Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
>> ---
>> linux-headers/asm-arm64/kvm.h | 9 +++++++++
>> linux-headers/linux/kvm.h | 10 +++++++++-
>> 2 files changed, 18 insertions(+), 1 deletion(-)
>>
>> diff --git a/linux-headers/asm-arm64/kvm.h b/linux-headers/asm-arm64/kvm.h
>> index 6aefe7973814..4c08631ec7d2 100644
>> --- a/linux-headers/asm-arm64/kvm.h
>> +++ b/linux-headers/asm-arm64/kvm.h
>> @@ -208,6 +208,15 @@ struct kvm_arm_counter_offset {
>> __u64 reserved;
>> };
>>
>> +#define KVM_ARM_RMI_POPULATE_FLAGS_MEASURE (1 << 0)
>> +struct kvm_arm_rmi_populate {
>> + __u64 base;
>> + __u64 size;
>> + __u64 source_uaddr;
>> + __u32 flags;
>> + __u32 reserved;
>> +};
>> +
>> #define KVM_ARM_TAGS_TO_GUEST 0
>> #define KVM_ARM_TAGS_FROM_GUEST 1
>>
>> diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h
>> index dd52e2a65bfd..cdd5ad11f85a 100644
>> --- a/linux-headers/linux/kvm.h
>> +++ b/linux-headers/linux/kvm.h
>> @@ -689,14 +689,19 @@ struct kvm_enable_cap {
>> * address size for the VM. Bits[7-0] are reserved for the guest
>> * PA size shift (i.e, log2(PA_Size)). For backward compatibility,
>> * value 0 implies the default IPA size, 40bits.
>> + *
>> + * Bits[30-31] are reserved for the VM type
>> */
>> #define KVM_VM_TYPE_ARM_IPA_SIZE_MASK 0xffULL
>> #define KVM_VM_TYPE_ARM_IPA_SIZE(x) \
>> ((x) & KVM_VM_TYPE_ARM_IPA_SIZE_MASK)
>>
>> +#define KVM_VM_TYPE_ARM_NORMAL 0
>> +#define KVM_VM_TYPE_ARM_REALM (1UL << 30)
>> #define KVM_VM_TYPE_ARM_PROTECTED (1UL << 31)
>> #define KVM_VM_TYPE_ARM_MASK (KVM_VM_TYPE_ARM_IPA_SIZE_MASK | \
>> - KVM_VM_TYPE_ARM_PROTECTED)
>> + KVM_VM_TYPE_ARM_PROTECTED | \
>> + KVM_VM_TYPE_ARM_REALM)
>>
>> /*
>> * ioctls for /dev/kvm fds:
>> @@ -719,6 +724,8 @@ struct kvm_enable_cap {
>> #define KVM_GET_EMULATED_CPUID _IOWR(KVMIO, 0x09, struct kvm_cpuid2)
>> #define KVM_GET_MSR_FEATURE_INDEX_LIST _IOWR(KVMIO, 0x0a, struct kvm_msr_list)
>>
>> +#define KVM_ARM_RMI_POPULATE _IOWR(KVMIO, 0xd7, struct kvm_arm_rmi_populate)
>> +
>> /*
>> * Extension capability list.
>> */
>> @@ -986,6 +993,7 @@ struct kvm_enable_cap {
>> #define KVM_CAP_S390_KEYOP 247
>> #define KVM_CAP_S390_VSIE_ESAMODE 248
>> #define KVM_CAP_S390_HPAGE_2G 249
>> +#define KVM_CAP_ARM_RMI 250
>
> Not a big deal, but a note for anyone testing this series:
>
> Use Linaro's Linux kernel tree, as mentioned in the cover letter:
> https://gitlab.com/Linaro/cca-public/linux/-/tree/upstream-v2?ref_type=heads
>
It seems the capability values get an extra leap on KVM_CAP_ARM_AMI in
"upstream-v2" host kernel.
include/uapi/linux/kvm.h
#define KVM_CAP_S390_KEYOP 247
#define KVM_CAP_S390_VSIE_ESAMODE 248
#define KVM_CAP_ARM_RMI 250
> Alternetively, if you're using Arm's tree or other trees with Steven
> Price's v14 series as I am:
>
> You'll need to adjust the definition of KVM_CAP_ARM_RMI, since it uses a
> differenct capability number.
>
>>
>> struct kvm_irq_routing_irqchip {
>> __u32 irqchip;
>> --
>> 2.43.0
>>
Thanks,
Gavin
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [RFC v2 01/24] linux-headers: Add RME related definitions
2026-07-30 6:08 ` Gavin Shan
@ 2026-07-30 6:13 ` Kohei Enju
0 siblings, 0 replies; 30+ messages in thread
From: Kohei Enju @ 2026-07-30 6:13 UTC (permalink / raw)
To: Gavin Shan
Cc: Mathieu Poirier, berrange, kchamart, pierrick.bouvier,
peter.maydell, mst, cohuck, pbonzini, eblake, armbru,
lorenzo.pieralisi, qemu-devel, qemu-arm, kvm
On 07/30 16:08, Gavin Shan wrote:
> On 7/30/26 3:41 PM, Kohei Enju wrote:
> > On 07/28 13:26, Mathieu Poirier wrote:
> > > From: Jean-Philippe Brucker <jean-philippe@linaro.org>
> > >
> > > This is a temporary patch intended for testing purposes only. It provides
> > > definitions related to supporting Realms by the QEMU-VMM.
> > >
> > > Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org>
> > > Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
> > > ---
> > > linux-headers/asm-arm64/kvm.h | 9 +++++++++
> > > linux-headers/linux/kvm.h | 10 +++++++++-
> > > 2 files changed, 18 insertions(+), 1 deletion(-)
> > >
> > > diff --git a/linux-headers/asm-arm64/kvm.h b/linux-headers/asm-arm64/kvm.h
> > > index 6aefe7973814..4c08631ec7d2 100644
> > > --- a/linux-headers/asm-arm64/kvm.h
> > > +++ b/linux-headers/asm-arm64/kvm.h
> > > @@ -208,6 +208,15 @@ struct kvm_arm_counter_offset {
> > > __u64 reserved;
> > > };
> > > +#define KVM_ARM_RMI_POPULATE_FLAGS_MEASURE (1 << 0)
> > > +struct kvm_arm_rmi_populate {
> > > + __u64 base;
> > > + __u64 size;
> > > + __u64 source_uaddr;
> > > + __u32 flags;
> > > + __u32 reserved;
> > > +};
> > > +
> > > #define KVM_ARM_TAGS_TO_GUEST 0
> > > #define KVM_ARM_TAGS_FROM_GUEST 1
> > > diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h
> > > index dd52e2a65bfd..cdd5ad11f85a 100644
> > > --- a/linux-headers/linux/kvm.h
> > > +++ b/linux-headers/linux/kvm.h
> > > @@ -689,14 +689,19 @@ struct kvm_enable_cap {
> > > * address size for the VM. Bits[7-0] are reserved for the guest
> > > * PA size shift (i.e, log2(PA_Size)). For backward compatibility,
> > > * value 0 implies the default IPA size, 40bits.
> > > + *
> > > + * Bits[30-31] are reserved for the VM type
> > > */
> > > #define KVM_VM_TYPE_ARM_IPA_SIZE_MASK 0xffULL
> > > #define KVM_VM_TYPE_ARM_IPA_SIZE(x) \
> > > ((x) & KVM_VM_TYPE_ARM_IPA_SIZE_MASK)
> > > +#define KVM_VM_TYPE_ARM_NORMAL 0
> > > +#define KVM_VM_TYPE_ARM_REALM (1UL << 30)
> > > #define KVM_VM_TYPE_ARM_PROTECTED (1UL << 31)
> > > #define KVM_VM_TYPE_ARM_MASK (KVM_VM_TYPE_ARM_IPA_SIZE_MASK | \
> > > - KVM_VM_TYPE_ARM_PROTECTED)
> > > + KVM_VM_TYPE_ARM_PROTECTED | \
> > > + KVM_VM_TYPE_ARM_REALM)
> > > /*
> > > * ioctls for /dev/kvm fds:
> > > @@ -719,6 +724,8 @@ struct kvm_enable_cap {
> > > #define KVM_GET_EMULATED_CPUID _IOWR(KVMIO, 0x09, struct kvm_cpuid2)
> > > #define KVM_GET_MSR_FEATURE_INDEX_LIST _IOWR(KVMIO, 0x0a, struct kvm_msr_list)
> > > +#define KVM_ARM_RMI_POPULATE _IOWR(KVMIO, 0xd7, struct kvm_arm_rmi_populate)
> > > +
> > > /*
> > > * Extension capability list.
> > > */
> > > @@ -986,6 +993,7 @@ struct kvm_enable_cap {
> > > #define KVM_CAP_S390_KEYOP 247
> > > #define KVM_CAP_S390_VSIE_ESAMODE 248
> > > #define KVM_CAP_S390_HPAGE_2G 249
> > > +#define KVM_CAP_ARM_RMI 250
> >
> > Not a big deal, but a note for anyone testing this series:
> >
> > Use Linaro's Linux kernel tree, as mentioned in the cover letter:
> > https://gitlab.com/Linaro/cca-public/linux/-/tree/upstream-v2?ref_type=heads
> >
>
> It seems the capability values get an extra leap on KVM_CAP_ARM_AMI in
> "upstream-v2" host kernel.
>
> include/uapi/linux/kvm.h
>
> #define KVM_CAP_S390_KEYOP 247
> #define KVM_CAP_S390_VSIE_ESAMODE 248
> #define KVM_CAP_ARM_RMI 250
Yes. The following commit changed it in "upstream-v2".
https://gitlab.com/Linaro/cca-public/linux/-/commit/1558aa1d9b8a49283d69c15889cb2df98183d7d0
>
> > Alternetively, if you're using Arm's tree or other trees with Steven
> > Price's v14 series as I am:
> >
> > You'll need to adjust the definition of KVM_CAP_ARM_RMI, since it uses a
> > differenct capability number.
> >
> > > struct kvm_irq_routing_irqchip {
> > > __u32 irqchip;
> > > --
> > > 2.43.0
> > >
>
> Thanks,
> Gavin
>
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [RFC v2 00/24] Add Realm support to QEMU-VMM
2026-07-30 5:11 ` [RFC v2 00/24] Add Realm support to QEMU-VMM Kohei Enju
@ 2026-08-09 13:06 ` Mathieu Poirier
0 siblings, 0 replies; 30+ messages in thread
From: Mathieu Poirier @ 2026-08-09 13:06 UTC (permalink / raw)
To: Kohei Enju
Cc: berrange, kchamart, pierrick.bouvier, peter.maydell, mst, cohuck,
pbonzini, eblake, armbru, lorenzo.pieralisi, gshan, qemu-devel,
qemu-arm, kvm
On Thu, Jul 30, 2026 at 02:11:57PM +0900, Kohei Enju wrote:
> On 07/28 13:26, Mathieu Poirier wrote:
> > This patchset provides minimal functionality to start a Realm VM
> > from an Arm RME capable host using the following command line:
> >
> > qemu-system-aarch64 \
> > -M confidential-guest-support=rme0 -object rme-guest,id=rme0 \
> > -cpu host -M virt -enable-kvm -M gic-version=3,its=on -nodefaults ..
> >
> > It is a refactoring of Jean-Philippe Brucker's initial work dating from a while
> > back. It is compatible with Steven Price's v14 revision [1] of his work adding
> > CCA support to KVM.
> >
> > * We are currently working on rebasing the work to v15.
> >
> > It was tested on the QEMU SBSA machine. For convenience, a repository is hosted
> > here [2], along with the TF-A [3], RMM [4] and Linux kernel [5] for the SBSA
> > machine (compatible with Steven's v14 patchset).
> >
> > Instructions to compile and run the entire stack can be found here [6].
> >
> > Device Assignment is not included.
> >
> > Thanks,
> > Mathieu
>
> Hi Mathieu, thank you for your work on upstreaming CCA support. I've
> tested this series in QEMU-TCG(x-rme=on) environments and confirmed
> that the basic functionality works well.
>
> I have a question about a QMP command for querying CCA capabilities.
>
> Jean's tree contains the following commit adding such a QMP command. Was
> this functionality intentionally omitted from this series?
> https://git.codelinaro.org/linaro/dcap/qemu/-/commit/41f7852cc8590a38c47299a35a7238da09ff9a12
>
> We are interested in adding this functionality because we are also
> planning to upstream CCA support for libvirt, which will need a QMP
> interface to query the CCA capabilities exposed by QEMU.
>
> Since the Linux kernel dropped some configuration parameters such as the
> hash algorithm, I need to rework the implementation of that QMP command
> a bit. If it's okay with you, I'd be happy to send out the reworked
> patch based on this series.
I am currently away from the office - I will get back to you after August 17th.
>
> Thanks,
> Kohei
>
> >
> > [1]. https://lore.kernel.org/kvm/20260513131757.116630-1-steven.price@arm.com/T/#m06dd14216aaf76acab65b0a76fb84653141ea64f
> > [2]. https://gitlab.com/Linaro/cca-public/qemu/-/tree/upstream-v2?ref_type=heads
> > [3]. https://gitlab.com/Linaro/cca-public/tf-a/trusted-firmware-a/-/tree/cca/v13?ref_type=heads
> > [4]. https://gitlab.com/Linaro/cca-public/rmm/-/tree/cca/v14?ref_type=heads
> > [5]. https://gitlab.com/Linaro/cca-public/linux/-/tree/upstream-v2?ref_type=heads
> > [6]. https://gitlab.com/Linaro/cca-public/build-instructions
> >
> > RFC v1:
> > https://lists.gnu.org/archive/html/qemu-devel/2026-07/msg02307.html
> >
> > Changes for V2:
> > - Fixed linux headers to include correct bit shift for Realm VM (Gavin).
> > - Removed obsolete rme-guest options (Markus).
> > - Set ConfidentialGuestSupportClass::kvm_init() to kvm_arm_rme_init() (Gavin).
> > - Got rid of kvm_arm_rme_vm_type() (Gavin).
> > - Used kvm_vm_check_extension() instead of kvm_check_extension() to avoid
> > error message when starting a Realm (Gavin).
> > - Removed obsolete kvm_arm_rme_init_guest_ram() (Gavin).
> > - Collected A-B and R-B.
^ permalink raw reply [flat|nested] 30+ messages in thread
end of thread, other threads:[~2026-08-09 13:06 UTC | newest]
Thread overview: 30+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-28 19:26 [RFC v2 00/24] Add Realm support to QEMU-VMM Mathieu Poirier
2026-07-28 19:26 ` [RFC v2 01/24] linux-headers: Add RME related definitions Mathieu Poirier
2026-07-30 5:41 ` Kohei Enju
2026-07-30 6:08 ` Gavin Shan
2026-07-30 6:13 ` Kohei Enju
2026-07-28 19:26 ` [RFC v2 02/24] target/arm/kvm: Return immediately on error in kvm_arch_init() Mathieu Poirier
2026-07-28 19:26 ` [RFC v2 03/24] target/arm: Add confidential guest support Mathieu Poirier
2026-07-28 19:26 ` [RFC v2 04/24] target/arm/kvm-rme: Add mechanic to initialize realms Mathieu Poirier
2026-07-28 19:26 ` [RFC v2 05/24] target/arm/kvm: Split kvm_arch_get/put_registers Mathieu Poirier
2026-07-28 19:26 ` [RFC v2 06/24] target/arm/kvm-rme: Initialize vCPU Mathieu Poirier
2026-07-28 19:26 ` [RFC v2 07/24] target/arm/kvm: Create scratch Realm VM when requested Mathieu Poirier
2026-07-28 19:26 ` [RFC v2 08/24] target/arm/kvm: Use kvm_vm_check_extension() where necessary Mathieu Poirier
2026-07-28 19:26 ` [RFC v2 09/24] hw/core/loader: Add a ROM loader notifier Mathieu Poirier
2026-07-28 19:26 ` [RFC v2 10/24] target/arm/kvm-rme: Keep track of images loaded in Realm memory Mathieu Poirier
2026-07-28 19:26 ` [RFC v2 11/24] target/arm/kvm-rme: Populate Realm with runtime images Mathieu Poirier
2026-07-28 19:26 ` [RFC v2 12/24] target/arm/cpu: Set number of breakpoints and watchpoints in KVM Mathieu Poirier
2026-07-28 19:26 ` [RFC v2 13/24] target/arm/cpu: Set number of PMU counters " Mathieu Poirier
2026-07-28 19:26 ` [RFC v2 14/24] target/arm/cpu: Don't read Realm registers Mathieu Poirier
2026-07-28 19:26 ` [RFC v2 15/24] hw/arm/virt: Set proper conduit method for Realms Mathieu Poirier
2026-07-28 19:26 ` [RFC v2 16/24] hw/arm/virt: Embed Realm VM type with IPA address space Mathieu Poirier
2026-07-28 19:26 ` [RFC v2 17/24] hw/arm/virt: Reserve one bit of guest physical address for RME Mathieu Poirier
2026-07-28 19:26 ` [RFC v2 18/24] hw/arm/virt: Disable DTB randomness for confidential VMs Mathieu Poirier
2026-07-28 19:26 ` [RFC v2 19/24] hw/arm/virt: Move virt_flash_create() to machvirt_init() Mathieu Poirier
2026-07-28 19:26 ` [RFC v2 20/24] hw/arm/virt: Use RAM instead of flash for confidential guest firmware Mathieu Poirier
2026-07-28 19:26 ` [RFC v2 21/24] target/arm/kvm-rme: Add DMA remapping for the shared memory region Mathieu Poirier
2026-07-28 19:26 ` [RFC v2 22/24] docs/interop/firmware.json: Add arm-rme firmware feature Mathieu Poirier
2026-07-28 19:26 ` [RFC v2 23/24] hw/arm/boot: Load DTB as is for confidential VMs Mathieu Poirier
2026-07-28 19:26 ` [RFC v2 24/24] hw/arm/boot: Skip bootloader for confidential guests Mathieu Poirier
2026-07-30 5:11 ` [RFC v2 00/24] Add Realm support to QEMU-VMM Kohei Enju
2026-08-09 13:06 ` Mathieu Poirier
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox