hw/nitro/nitro-serial-vsock: Nitro Enclaves vsock console
Nitro Enclaves support a special "debug" mode. When in debug mode, the Nitro Hypervisor provides a vsock port that the parent can connect to to receive serial console output of the Enclave. Add a new nitro-serial-vsock driver that implements short-circuit logic to establish the vsock connection to that port and feed its data into a chardev, so that a machine model can use it as serial device. Signed-off-by: Alexander Graf <graf@amazon.com> Link: https://lore.kernel.org/r/20260225220807.33092-6-graf@amazon.com Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Alexander Graf committed
Feb 25, 2026 at 22:07 UTC
00c83607206c0d98e40fc71f78713276e03489db
5 files changed
+154
hw/nitro/Kconfig
+4
@@ -1,2 +1,6 @@
1
config NITRO_VSOCK_BUS
2
bool
3
+
4
+config NITRO_SERIAL_VSOCK
5
+ bool
6
+ depends on NITRO_VSOCK_BUS
hw/nitro/meson.build
+1
@@ -1 +1,2 @@
1
system_ss.add(when: 'CONFIG_NITRO_VSOCK_BUS', if_true: files('nitro-vsock-bus.c'))
2
+system_ss.add(when: 'CONFIG_NITRO_SERIAL_VSOCK', if_true: files('serial-vsock.c'))
hw/nitro/serial-vsock.c
new
+123
@@ -0,0 +1,123 @@
1
+/*
2
+ * Nitro Enclave Vsock Serial
3
+ *
4
+ * Copyright © 2026 Amazon.com, Inc. or its affiliates. All Rights Reserved.
5
+ *
6
+ * Authors:
7
+ * Alexander Graf <graf@amazon.com>
8
+ *
9
+ * With Nitro Enclaves in debug mode, the Nitro Hypervisor provides a vsock
10
+ * port that the parent can connect to to receive serial console output of
11
+ * the Enclave. This driver implements short-circuit logic to establish the
12
+ * vsock connection to that port and feed its data into a chardev, so that
13
+ * a machine model can use it as serial device.
14
+ *
15
+ * SPDX-License-Identifier: GPL-2.0-or-later
16
+ */
17
+
18
+#include "qemu/osdep.h"
19
+#include "qemu/error-report.h"
20
+#include "qapi/error.h"
21
+#include "chardev/char.h"
22
+#include "chardev/char-fe.h"
23
+#include "hw/core/qdev-properties.h"
24
+#include "hw/core/qdev-properties-system.h"
25
+#include "hw/nitro/serial-vsock.h"
26
+#include "trace.h"
27
+
28
+#define CONSOLE_PORT_START 10000
29
+#define VMADDR_CID_HYPERVISOR_STR "0"
30
+
31
+static int nitro_serial_vsock_can_read(void *opaque)
32
+{
33
+ NitroSerialVsockState *s = opaque;
34
+
35
+ /* Refuse vsock input until the output backend is ready */
36
+ return qemu_chr_fe_backend_open(&s->output) ? 4096 : 0;
37
+}
38
+
39
+static void nitro_serial_vsock_read(void *opaque, const uint8_t *buf, int size)
40
+{
41
+ NitroSerialVsockState *s = opaque;
42
+
43
+ /* Forward all vsock data to the output chardev */
44
+ qemu_chr_fe_write_all(&s->output, buf, size);
45
+}
46
+
47
+static void nitro_serial_vsock_event(void *opaque, QEMUChrEvent event)
48
+{
49
+ /* No need to action on connect/disconnect events, but trace for debug */
50
+ trace_nitro_serial_vsock_event(event);
51
+}
52
+
53
+static void nitro_serial_vsock_enclave_started(NitroVsockDevice *dev,
54
+ uint32_t enclave_cid,
55
+ Error **errp)
56
+{
57
+ NitroSerialVsockState *s = NITRO_SERIAL_VSOCK(dev);
58
+ uint32_t port = enclave_cid + CONSOLE_PORT_START;
59
+ g_autofree char *chardev_id = NULL;
60
+ Chardev *chr;
61
+ ChardevBackend *backend;
62
+ ChardevSocket *sock;
63
+
64
+ /*
65
+ * We know the Enclave CID to connect to now. Create a vsock
66
+ * client chardev that connects to the Enclave's console.
67
+ */
68
+ chardev_id = g_strdup_printf("nitro-console-%u", enclave_cid);
69
+
70
+ backend = g_new0(ChardevBackend, 1);
71
+ backend->type = CHARDEV_BACKEND_KIND_SOCKET;
72
+ sock = backend->u.socket.data = g_new0(ChardevSocket, 1);
73
+ sock->addr = g_new0(SocketAddressLegacy, 1);
74
+ sock->addr->type = SOCKET_ADDRESS_TYPE_VSOCK;
75
+ sock->addr->u.vsock.data = g_new0(VsockSocketAddress, 1);
76
+ sock->addr->u.vsock.data->cid = g_strdup(VMADDR_CID_HYPERVISOR_STR);
77
+ sock->addr->u.vsock.data->port = g_strdup_printf("%u", port);
78
+ sock->server = false;
79
+ sock->has_server = true;
80
+
81
+ chr = qemu_chardev_new(chardev_id, TYPE_CHARDEV_SOCKET,
82
+ backend, NULL, errp);
83
+ if (!chr) {
84
+ return;
85
+ }
86
+
87
+ if (!qemu_chr_fe_init(&s->vsock, chr, errp)) {
88
+ return;
89
+ }
90
+
91
+ qemu_chr_fe_set_handlers(&s->vsock,
92
+ nitro_serial_vsock_can_read,
93
+ nitro_serial_vsock_read,
94
+ nitro_serial_vsock_event,
95
+ NULL, s, NULL, true);
96
+}
97
+
98
+static const Property nitro_serial_vsock_props[] = {
99
+ DEFINE_PROP_CHR("chardev", NitroSerialVsockState, output),
100
+};
101
+
102
+static void nitro_serial_vsock_class_init(ObjectClass *oc, const void *data)
103
+{
104
+ DeviceClass *dc = DEVICE_CLASS(oc);
105
+ NitroVsockDeviceClass *ndc = NITRO_VSOCK_DEVICE_CLASS(oc);
106
+
107
+ device_class_set_props(dc, nitro_serial_vsock_props);
108
+ ndc->enclave_started = nitro_serial_vsock_enclave_started;
109
+}
110
+
111
+static const TypeInfo nitro_serial_vsock_info = {
112
+ .name = TYPE_NITRO_SERIAL_VSOCK,
113
+ .parent = TYPE_NITRO_VSOCK_DEVICE,
114
+ .instance_size = sizeof(NitroSerialVsockState),
115
+ .class_init = nitro_serial_vsock_class_init,
116
+};
117
+
118
+static void nitro_serial_vsock_register(void)
119
+{
120
+ type_register_static(&nitro_serial_vsock_info);
121
+}
122
+
123
+type_init(nitro_serial_vsock_register);
hw/nitro/trace-events
+2
@@ -1,2 +1,4 @@
1
# See docs/devel/tracing.rst for syntax documentation.
2
3
+# serial-vsock.c
4
+nitro_serial_vsock_event(int event) "event %d"
include/hw/nitro/serial-vsock.h
new
+24
@@ -0,0 +1,24 @@
1
+/*
2
+ * Nitro Enclave Serial (vsock)
3
+ *
4
+ * SPDX-License-Identifier: GPL-2.0-or-later
5
+ */
6
+
7
+#ifndef HW_CHAR_NITRO_SERIAL_VSOCK_H
8
+#define HW_CHAR_NITRO_SERIAL_VSOCK_H
9
+
10
+#include "hw/nitro/nitro-vsock-bus.h"
11
+#include "chardev/char-fe.h"
12
+#include "qom/object.h"
13
+
14
+#define TYPE_NITRO_SERIAL_VSOCK "nitro-serial-vsock"
15
+OBJECT_DECLARE_SIMPLE_TYPE(NitroSerialVsockState, NITRO_SERIAL_VSOCK)
16
+
17
+struct NitroSerialVsockState {
18
+ NitroVsockDevice parent_obj;
19
+
20
+ CharFrontend output; /* chardev to write console output to */
21
+ CharFrontend vsock; /* vsock chardev to enclave console */
22
+};
23
+
24
+#endif /* HW_CHAR_NITRO_SERIAL_VSOCK_H */