Group the vCPU threads for core scheduling such that trusted siblings
share cookies and can be co-scheduled on the same core.

The grouping cannot affect isolation. Hardware checks each pairing
against the mask in the VMSA, which only the guest writes, so nothing
chosen here can bring about a pairing hardware would have refused.

It does decide whether the guest makes progress. Co-scheduling two vCPUs
whose masks disagree makes every VMRUN exit with VMEXIT_ILLSIB, which
KVM can only answer by retrying, and that never converges.

Signed-off-by: Pratik R. Sampat <[email protected]>
---
 target/i386/sev.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 47 insertions(+)

diff --git a/target/i386/sev.c b/target/i386/sev.c
index 0b5767057175..34d9851d4e94 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -18,6 +18,7 @@
 #include <linux/psp-sev.h>
 
 #include <sys/ioctl.h>
+#include <sys/prctl.h>
 
 #include "qapi/error.h"
 #include "qom/object_interfaces.h"
@@ -2031,6 +2032,47 @@ static int sev_kvm_init(ConfidentialGuestSupport *cgs, 
Error **errp)
     return 0;
 }
 
+/*
+ * Mint a cookie for the first vCPU and copy it to all the others, so that
+ * every vCPU thread of this guest ends up in one core-scheduling group.
+ */
+static void esmtp_core_sched_setup(CPUState *leader, run_on_cpu_data arg)
+{
+    CPUState *cpu;
+    int ret;
+
+    ret = prctl(PR_SCHED_CORE, PR_SCHED_CORE_CREATE, leader->thread_id,
+                PR_SCHED_CORE_SCOPE_THREAD, 0);
+    if (ret < 0) {
+        error_report("vCPU %lu: failed to create core-sched cookie: %s",
+                     kvm_arch_vcpu_id(leader), strerror(errno));
+        return;
+    }
+
+    CPU_FOREACH(cpu) {
+        if (cpu == leader) {
+            continue;
+        }
+
+        ret = prctl(PR_SCHED_CORE, PR_SCHED_CORE_SHARE_TO, cpu->thread_id,
+                    PR_SCHED_CORE_SCOPE_THREAD, 0);
+        if (ret < 0) {
+            error_report("vCPU %lu: failed to share core-sched cookie: %s",
+                         kvm_arch_vcpu_id(cpu), strerror(errno));
+            return;
+        }
+    }
+}
+
+static void esmtp_core_sched_notify(Notifier *notifier, void *data)
+{
+    run_on_cpu(first_cpu, esmtp_core_sched_setup, RUN_ON_CPU_NULL);
+}
+
+static Notifier sev_snp_esmtp_notify = {
+    .notify = esmtp_core_sched_notify,
+};
+
 static int sev_snp_kvm_init(ConfidentialGuestSupport *cgs, Error **errp)
 {
     MachineState *ms = MACHINE(qdev_get_machine());
@@ -2049,6 +2091,11 @@ static int sev_snp_kvm_init(ConfidentialGuestSupport 
*cgs, Error **errp)
     g_free(sev_snp_guest->kernel_hashes_data);
     sev_snp_guest->kernel_hashes_data = NULL;
 
+    /* Setup core scheduling cookies for esmtp after the vCPUS are all up */
+    if (is_sev_feature_set(sev_common, SVM_SEV_FEAT_ESMTP)) {
+        qemu_add_machine_init_done_notifier(&sev_snp_esmtp_notify);
+    }
+
     return 0;
 }
 
-- 
2.43.0


Reply via email to