@@ -153,6 +153,14 @@ void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu);
*/
void kvm_arm_add_vcpu_properties(ARMCPU *cpu);
+/**
+ * @cpu: The CPU object to finalize
+ * @feature: a KVM_ARM_VCPU_* feature
+ *
+ * Finalize the configuration of the given vcpu feature.
+ */
+int kvm_arm_vcpu_finalize(ARMCPU *cpu, int feature);
+
/**
* kvm_arm_steal_time_finalize:
* @cpu: ARMCPU for which to finalize kvm-steal-time
@@ -221,6 +229,22 @@ int kvm_arm_set_irq(int cpu, int irqtype, int irq, int level);
void kvm_arm_enable_mte(Object *cpuobj, Error **errp);
+/**
+ * kvm_arm_rme_init
+ * @ms: the machine state
+ *
+ * Prepare the machine to be a Realm, if the user enabled it.
+ */
+int kvm_arm_rme_init(MachineState *ms);
+
+/**
+ * kvm_arm_rme_vm_type
+ * @ms: the machine state
+ *
+ * Returns the Realm KVM VM type if the user requested a Realm, 0 otherwise.
+ */
+int kvm_arm_rme_vm_type(MachineState *ms);
+
#else
/*
@@ -260,6 +284,11 @@ static inline void kvm_arm_add_vcpu_properties(ARMCPU *cpu)
g_assert_not_reached();
}
+static inline int kvm_arm_vcpu_finalize(ARMCPU *cpu, int feature)
+{
+ g_assert_not_reached();
+}
+
static inline int kvm_arm_get_max_vm_ipa_size(MachineState *ms, bool *fixed_ipa)
{
g_assert_not_reached();
@@ -300,6 +329,16 @@ static inline void kvm_arm_enable_mte(Object *cpuobj, Error **errp)
g_assert_not_reached();
}
+static inline int kvm_arm_rme_init(MachineState *ms)
+{
+ g_assert_not_reached();
+}
+
+static inline int kvm_arm_rme_vm_type(MachineState *ms)
+{
+ g_assert_not_reached();
+}
+
#endif
#endif
@@ -12,6 +12,7 @@
#include "kvm_arm.h"
#include "migration/blocker.h"
#include "qapi/error.h"
+#include "qemu/error-report.h"
#include "qom/object_interfaces.h"
#include "sysemu/kvm.h"
#include "sysemu/runstate.h"
@@ -27,14 +28,119 @@ OBJECT_DEFINE_SIMPLE_TYPE_WITH_INTERFACES(RmeGuest, rme_guest, RME_GUEST,
CONFIDENTIAL_GUEST_SUPPORT,
{ TYPE_USER_CREATABLE }, { })
+static RmeGuest *rme_guest;
+
+static int rme_init_cpus(Error **errp)
+{
+ int ret;
+ CPUState *cs;
+
+ /*
+ * Now that do_cpu_reset() initialized the boot PC and
+ * kvm_cpu_synchronize_post_reset() registered it, we can finalize the REC.
+ */
+ CPU_FOREACH(cs) {
+ ret = kvm_arm_vcpu_finalize(ARM_CPU(cs), KVM_ARM_VCPU_REC);
+ if (ret) {
+ error_setg_errno(errp, -ret, "failed to finalize vCPU");
+ return ret;
+ }
+ }
+ return 0;
+}
+
+static int rme_create_realm(Error **errp)
+{
+ int ret;
+
+ ret = kvm_vm_enable_cap(kvm_state, KVM_CAP_ARM_RME, 0,
+ KVM_CAP_ARM_RME_CREATE_RD);
+ if (ret) {
+ error_setg_errno(errp, -ret, "failed to create Realm Descriptor");
+ return -1;
+ }
+
+ if (rme_init_cpus(errp)) {
+ return -1;
+ }
+
+ ret = kvm_vm_enable_cap(kvm_state, KVM_CAP_ARM_RME, 0,
+ KVM_CAP_ARM_RME_ACTIVATE_REALM);
+ if (ret) {
+ error_setg_errno(errp, -ret, "failed to activate realm");
+ return -1;
+ }
+
+ kvm_mark_guest_state_protected();
+ return 0;
+}
+
+static void rme_vm_state_change(void *opaque, bool running, RunState state)
+{
+ Error *err = NULL;
+
+ if (!running) {
+ return;
+ }
+
+ if (rme_create_realm(&err)) {
+ error_propagate_prepend(&error_fatal, err, "RME: ");
+ }
+}
+
static void rme_guest_class_init(ObjectClass *oc, void *data)
{
}
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)
{
}
+
+int kvm_arm_rme_init(MachineState *ms)
+{
+ static Error *rme_mig_blocker;
+ ConfidentialGuestSupport *cgs = ms->cgs;
+
+ if (!rme_guest) {
+ return 0;
+ }
+
+ if (!cgs) {
+ error_report("missing -machine confidential-guest-support parameter");
+ return -EINVAL;
+ }
+
+ if (!kvm_check_extension(kvm_state, KVM_CAP_ARM_RME)) {
+ 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;
+}
+
+int kvm_arm_rme_vm_type(MachineState *ms)
+{
+ if (rme_guest) {
+ return KVM_VM_TYPE_ARM_REALM;
+ }
+ return 0;
+}
@@ -95,7 +95,7 @@ static int kvm_arm_vcpu_init(ARMCPU *cpu)
*
* Returns: 0 if success else < 0 error code
*/
-static int kvm_arm_vcpu_finalize(ARMCPU *cpu, int feature)
+int kvm_arm_vcpu_finalize(ARMCPU *cpu, int feature)
{
return kvm_vcpu_ioctl(CPU(cpu), KVM_ARM_VCPU_FINALIZE, &feature);
}
@@ -627,7 +627,12 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
hw_breakpoints = g_array_sized_new(true, true,
sizeof(HWBreakpoint), max_hw_bps);
- return 0;
+ ret = kvm_arm_rme_init(ms);
+ if (ret) {
+ error_report("Failed to enable RME: %s", strerror(-ret));
+ }
+
+ return ret;
}
unsigned long kvm_arch_vcpu_id(CPUState *cpu)
The machine code calls kvm_arm_rme_vm_type() to get the VM flag and KVM calls kvm_arm_rme_init() to prepare for launching a Realm. Once VM creation is complete, create the Realm: * Create the realm descriptor, * load images into Realm RAM (in another patch), * finalize the REC (vCPU) after the registers are reset, * activate the realm, at which point the realm is sealed. Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org> --- v2->v3: * Cleaner error handling --- target/arm/kvm_arm.h | 39 ++++++++++++++++ target/arm/kvm-rme.c | 106 +++++++++++++++++++++++++++++++++++++++++++ target/arm/kvm.c | 9 +++- 3 files changed, 152 insertions(+), 2 deletions(-)