On 24.02.26 11:22, Paolo Bonzini wrote:
On 2/18/26 02:51, Alexander Graf wrote:
+/*
+ * Start the Enclave. This gets called when the first vCPU 0 enters its main + * loop. At this point memory is set up and the EIF is loaded. This function
+ * donates memory, adds vCPUs, and starts the enclave.
+ */
+static void nitro_do_start(NitroAccelState *s)
+{
+    MachineState *ms = MACHINE(qdev_get_machine());
+    int nr_cpus = ms->smp.cpus;
+    int i, ret;
+    struct ne_enclave_start_info start_info = {
+        .flags = s->debug_mode ? NE_ENCLAVE_DEBUG_MODE : 0,
+        .enclave_cid = s->enclave_cid,
+    };
+
+    ret = qemu_ram_foreach_block(nitro_donate_ram_block, s);
+    if (ret < 0) {
+        error_report("nitro: failed to donate memory");
+        exit(1);
+    }
+
+    for (i = 0; i < nr_cpus; i++) {
+        uint32_t cpu_id = 0;
+        if (ioctl(s->enclave_fd, NE_ADD_VCPU, &cpu_id) < 0) {
+            error_report("nitro: NE_ADD_VCPU failed: %s", strerror(errno));
+            exit(1);
+        }
+    }
+
+    ret = ioctl(s->enclave_fd, NE_START_ENCLAVE, &start_info);
+    if (ret < 0) {
+        switch (errno) {
+        case NE_ERR_NO_MEM_REGIONS_ADDED:
+            error_report("nitro: no memory regions added");
+            break;
+        case NE_ERR_NO_VCPUS_ADDED:
+            error_report("nitro: no vCPUs added");
+            break;
+        case NE_ERR_ENCLAVE_MEM_MIN_SIZE:
+            error_report("nitro: memory is below the minimum "
+                         "required size. Try increasing -m");
+            break;
+        case NE_ERR_FULL_CORES_NOT_USED:
+            error_report("nitro: requires full CPU cores. "
+                         "Try increasing -smp to a multiple of threads "
+                         "per core on this host (e.g. -smp 2)");
+            break;
+        case NE_ERR_NOT_IN_INIT_STATE:
+            error_report("nitro: not in init state");
+            break;
+        case NE_ERR_INVALID_FLAG_VALUE:
+            error_report("nitro: invalid flag value for NE_START_ENCLAVE");
+            break;
+        case NE_ERR_INVALID_ENCLAVE_CID:
+            error_report("nitro: invalid enclave CID");
+            break;
+        default:
+            error_report("nitro: NE_START_ENCLAVE failed: %s (errno %d)",
+                         strerror(errno), errno);
+            break;
+        }
+        exit(1);
+    }
+
+    s->enclave_cid = start_info.enclave_cid;
+    trace_nitro_enclave_started(s->enclave_cid);
+
+    /*
+     * Push enclave CID to all devices that need it.
+     * Each device handles its own connection (console, heartbeat).
+     */
+    {
+        BusState *sysbus = sysbus_get_default();
+        BusChild *kid;
+
+        QTAILQ_FOREACH(kid, &sysbus->children, sibling) {
+            DeviceState *dev = kid->child;
+            if (object_property_find(OBJECT(dev), "enclave-cid")) {
+                object_property_set_uint(OBJECT(dev), "enclave-cid",
+                                         s->enclave_cid, NULL);
+            }
+        }

I think it makes more sense to have a "nitro bus" with its own subclass and an enclave_started(NitroDevice *dev, int enclave_cid, Error **errp) method.  Properties can be set with -device and that gets either awkward or buggy pretty quickly.


I tend to agree. Maybe even a "nitro vsock bus". Let me cook on that a bit.



+    }
+}
+
+/*
+ * vCPU dummy thread function. The real vCPUs run inside the enclave.
+ *
+ * Based on dummy_cpu_thread_fn() from accel/dummy-cpus.c.
+ */
+static void *nitro_vcpu_thread_fn(void *arg)
+{
+    CPUState *cpu = arg;
+    NitroAccelState *s = NITRO_ACCEL(current_accel());
+    sigset_t waitset;
+
+    rcu_register_thread();
+
+    bql_lock();
+    qemu_thread_get_self(cpu->thread);
+    cpu->thread_id = qemu_get_thread_id();
+    current_cpu = cpu;
+
+    sigemptyset(&waitset);
+    sigaddset(&waitset, SIG_IPI);
+
+    cpu_thread_signal_created(cpu);
+    qemu_guest_random_seed_thread_part2(cpu->random_seed);
+
+    /* vCPU 0 starts the enclave on first entry */
+    if (cpu->cpu_index == 0) {
+        nitro_do_start(s);
+    }

Can you replace this with an async_run_on_cpu() call when vCPU 0 is created (in nitro_start_vcpu_thread) and just reuse dummy_cpu_thread_fn()?

Or alternatively with a machine ready notifier.


I moved it into setup_post() which is a more natural place anyway. That way I can also exclusively use the dummy cpu thread. Definitely much cleaner, thank you :).



diff --git a/accel/stubs/nitro-stub.c b/accel/stubs/nitro-stub.c
new file mode 100644
index 0000000000..186c8444f8
--- /dev/null
+++ b/accel/stubs/nitro-stub.c
@@ -0,0 +1,11 @@
+/*
+ * Nitro accel stubs for QEMU
+ *
+ * Copyright © 2026 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+
+bool nitro_allowed;

Maybe all these *_allowed variables should be in a .c file in accel/.


Hm, maybe. But I'd like to leave that for a different patch set so I don't end up boiling the ocean :)


Alex




Amazon Web Services Development Center Germany GmbH
Tamara-Danz-Str. 13
10243 Berlin
Geschaeftsfuehrung: Christof Hellmis, Andreas Stieger
Eingetragen am Amtsgericht Charlottenburg unter HRB 257764 B
Sitz: Berlin
Ust-ID: DE 365 538 597

Reply via email to