From nobody Sun Apr 12 05:57:50 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass header.i=@amazon.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=amazon.com ARC-Seal: i=1; a=rsa-sha256; t=1772030921; cv=none; d=zohomail.com; s=zohoarc; b=Ztdad74qW/D961fME3vHhtb5jL8awRUKyeYT1f1/g+I3HDHN+T+RG2Rr3+4J2VPEFW5329+1X+aoqz5MArC4yqSsuzuluZXZ7lbyAvV1XWbCaSPhUYpqPgCT7CKAe9s4LegfEXzth+R8SOiv4O9nb4h1soAEZQI5uC0tiTKsNzM= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1772030921; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=wiFxVcGuOOQDsn9n6nHZt2xgOoJ7CV0tZ9+LBptze6g=; b=jqR+SFAbuGaJwT6dxX6TpVlf+RBprLVHYzK6682QzHgRtMqa1H/qJ2PKWPpihjp/mDrP17Q9F/LXC6zQpzXmswWsw4JBSt7ZGtIYSNVPfZorUvNW6HQye82Kgb8aV6XTCCRPfIwkV7slF7Gg6Nke32FUUfJUBPjqFEYrxTjZinw= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass header.i=@amazon.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1772030921528184.20287232090345; Wed, 25 Feb 2026 06:48:41 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1vvGB7-0001Je-Si; Wed, 25 Feb 2026 09:47:56 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1vvGAX-00018J-Lz; Wed, 25 Feb 2026 09:47:19 -0500 Received: from pdx-out-003.esa.us-west-2.outbound.mail-perimeter.amazon.com ([44.246.68.102]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1vvGAV-00079X-OA; Wed, 25 Feb 2026 09:47:17 -0500 Received: from ip-10-5-12-219.us-west-2.compute.internal (HELO smtpout.naws.us-west-2.prod.farcaster.email.amazon.dev) ([10.5.12.219]) by internal-pdx-out-003.esa.us-west-2.outbound.mail-perimeter.amazon.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 25 Feb 2026 14:47:10 +0000 Received: from EX19MTAUWC002.ant.amazon.com [205.251.233.51:9661] by smtpin.naws.us-west-2.prod.farcaster.email.amazon.dev [10.0.36.66:2525] with esmtp (Farcaster) id 9d510a1e-b7dd-487e-a911-877d9d388bcf; Wed, 25 Feb 2026 14:47:10 +0000 (UTC) Received: from EX19D020UWC004.ant.amazon.com (10.13.138.149) by EX19MTAUWC002.ant.amazon.com (10.250.64.143) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA) id 15.2.2562.37; Wed, 25 Feb 2026 14:47:09 +0000 Received: from ip-10-253-83-51.amazon.com (172.19.99.218) by EX19D020UWC004.ant.amazon.com (10.13.138.149) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA) id 15.2.2562.37; Wed, 25 Feb 2026 14:47:07 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amazon.com; i=@amazon.com; q=dns/txt; s=amazoncorp2; t=1772030835; x=1803566835; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=wiFxVcGuOOQDsn9n6nHZt2xgOoJ7CV0tZ9+LBptze6g=; b=mgoSjPM2swBxN8gQViDe/yUQKTiU0tqWoeaPH2JUayCgOmiEGKSmBK3G xP4fvDYy9AuMCd9amFkhnGi1rIPixPIAEAFMTdRMWdaQVGGx4jUoSZyWy LWXy/YEoUy+H1i6gKgkSoSoU5gLqT50rKKnevHxuN5/YoA6HtfzVSZEwO Lju/anljdbcF+1PAwt11fTRTmEDV9CN+IIhw+VPoTCt6sLYhdSiIw6lof bkW8J1jVtCWoUeSpBZJ4VY9K+3Vq1GcsOnUkRgYAT1ZkENe3Yyyn4l5Zh VPQalriCXmqoNwRNS8MwpqXgQ7hHpmwmZk1xpH3RinAUywl3CRkyUaacm w==; X-CSE-ConnectionGUID: 5HL1FQWfQnCEQg3ym/1eWw== X-CSE-MsgGUID: 4zLpn9AATy24kFVMBqsTTw== X-IronPort-AV: E=Sophos;i="6.21,310,1763424000"; d="scan'208";a="13779701" X-Farcaster-Flow-ID: 9d510a1e-b7dd-487e-a911-877d9d388bcf From: Alexander Graf To: CC: , Peter Maydell , "Thomas Huth" , , , , , Cornelia Huck , , Dorjoy Chowdhury , Pierrick Bouvier , Paolo Bonzini , Tyler Fanelli , , Subject: [PATCH v2 10/11] hw/nitro: Enable direct kernel boot Date: Wed, 25 Feb 2026 14:45:29 +0000 Message-ID: <20260225144532.84673-11-graf@amazon.com> X-Mailer: git-send-email 2.47.1 In-Reply-To: <20260225144532.84673-1-graf@amazon.com> References: <20260225144532.84673-1-graf@amazon.com> MIME-Version: 1.0 X-Originating-IP: [172.19.99.218] X-ClientProxiedBy: EX19D039UWB003.ant.amazon.com (10.13.138.93) To EX19D020UWC004.ant.amazon.com (10.13.138.149) Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=44.246.68.102; envelope-from=prvs=509822c20=graf@amazon.de; helo=pdx-out-003.esa.us-west-2.outbound.mail-perimeter.amazon.com X-Spam_score_int: -1 X-Spam_score: -0.2 X-Spam_bar: / X-Spam_report: (-0.2 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, HEADER_FROM_DIFFERENT_DOMAINS=0.249, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.734, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.78, SPF_HELO_NONE=0.001, T_SPF_PERMERROR=0.01, UNPARSEABLE_RELAY=0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @amazon.com) X-ZM-MESSAGEID: 1772030923623158500 Content-Type: text/plain; charset="utf-8" Nitro Enclaves can only boot EIF files which are a combination of kernel, initramfs and cmdline in a single file. When the kernel image is not an EIF, treat it like a kernel image and assemble an EIF image on the fly. This way, users can call QEMU with a direct kernel/initrd/cmdline combination and everything "just works". Signed-off-by: Alexander Graf --- hw/core/eif.h | 3 ++ hw/nitro/machine.c | 116 +++++++++++++++++++++++++++++++++++++++++++ hw/nitro/meson.build | 2 +- 3 files changed, 120 insertions(+), 1 deletion(-) diff --git a/hw/core/eif.h b/hw/core/eif.h index a3412377a9..0c432dbc2d 100644 --- a/hw/core/eif.h +++ b/hw/core/eif.h @@ -12,6 +12,7 @@ #define HW_CORE_EIF_H =20 #define MAX_SECTIONS 32 +#define EIF_HDR_ARCH_ARM64 0x1 =20 /* members are ordered according to field order in .eif file */ typedef struct EifHeader { @@ -49,6 +50,8 @@ enum EifSectionTypes { EIF_SECTION_MAX =3D 6, }; =20 +#define EIF_MAGIC { '.', 'e', 'i', 'f' } + bool read_eif_file(const char *eif_path, const char *machine_initrd, char **kernel_path, char **initrd_path, char **kernel_cmdline, uint8_t *image_sha384, diff --git a/hw/nitro/machine.c b/hw/nitro/machine.c index e28c8e9bf5..8849959359 100644 --- a/hw/nitro/machine.c +++ b/hw/nitro/machine.c @@ -32,9 +32,104 @@ #include "system/nitro-accel.h" #include "qemu/accel.h" #include "hw/arm/machines-qom.h" +#include "hw/core/eif.h" +#include /* for crc32 */ =20 #define EIF_LOAD_ADDR (8 * 1024 * 1024) =20 +static bool is_eif(char *eif, gsize len) +{ + const char eif_magic[] =3D EIF_MAGIC; + + return len >=3D sizeof(eif_magic) && + !memcmp(eif, eif_magic, sizeof(eif_magic)); +} + +static void build_eif_section(EifHeader *hdr, GByteArray *buf, uint16_t ty= pe, + const char *data, uint64_t size) +{ + uint16_t section =3D be16_to_cpu(hdr->section_cnt); + EifSectionHeader shdr =3D { + .section_type =3D cpu_to_be16(type), + .flags =3D 0, + .section_size =3D cpu_to_be64(size), + }; + + hdr->section_offsets[section] =3D cpu_to_be64(buf->len); + hdr->section_sizes[section] =3D cpu_to_be64(size); + + g_byte_array_append(buf, (const uint8_t *)&shdr, sizeof(shdr)); + if (size) { + g_byte_array_append(buf, (const uint8_t *)data, size); + } + + hdr->section_cnt =3D cpu_to_be16(section + 1); +} + +/* + * Nitro Enclaves only support loading EIF files. When the user provides + * a Linux kernel, initrd and cmdline, convert them into EIF format. + */ +static char *build_eif(const char *kernel_data, gsize kernel_size, + const char *initrd_path, const char *cmdline, + gsize *out_size, Error **errp) +{ + g_autofree char *initrd_data =3D NULL; + static const char metadata[] =3D "{}"; + size_t metadata_len =3D sizeof(metadata) - 1; + gsize initrd_size =3D 0; + GByteArray *buf; + EifHeader hdr; + uint32_t crc =3D 0; + size_t cmdline_len; + + if (initrd_path) { + if (!g_file_get_contents(initrd_path, &initrd_data, + &initrd_size, NULL)) { + error_setg(errp, "Failed to read initrd '%s'", initrd_path); + return NULL; + } + } + + buf =3D g_byte_array_new(); + + cmdline_len =3D cmdline ? strlen(cmdline) : 0; + + hdr =3D (EifHeader) { + .magic =3D EIF_MAGIC, + .version =3D cpu_to_be16(4), + .flags =3D cpu_to_be16(target_aarch64() ? EIF_HDR_ARCH_ARM64 : 0), + }; + + g_byte_array_append(buf, (const uint8_t *)&hdr, sizeof(hdr)); + + /* Kernel */ + build_eif_section(&hdr, buf, EIF_SECTION_KERNEL, kernel_data, kernel_s= ize); + + /* Command line */ + build_eif_section(&hdr, buf, EIF_SECTION_CMDLINE, cmdline, cmdline_len= ); + + /* Initramfs */ + build_eif_section(&hdr, buf, EIF_SECTION_RAMDISK, initrd_data, initrd_= size); + + /* Metadata */ + build_eif_section(&hdr, buf, EIF_SECTION_METADATA, metadata, metadata_= len); + + /* + * Patch the header into the buffer first (with real section offsets + * and sizes), then compute CRC over everything except the CRC field. + */ + memcpy(buf->data, &hdr, sizeof(hdr)); + crc =3D crc32(crc, buf->data, offsetof(EifHeader, eif_crc32)); + crc =3D crc32(crc, &buf->data[sizeof(hdr)], buf->len - sizeof(hdr)); + + /* Finally write the CRC into the in-buffer header */ + ((EifHeader *)buf->data)->eif_crc32 =3D cpu_to_be32(crc); + + *out_size =3D buf->len; + return (char *)g_byte_array_free(buf, false); +} + static void nitro_machine_init(MachineState *machine) { const char *eif_path =3D machine->kernel_filename; @@ -74,6 +169,27 @@ static void nitro_machine_init(MachineState *machine) error_report("nitro: failed to read EIF '%s'", eif_path); exit(1); } + + if (!is_eif(eif_data, eif_size)) { + char *kernel_data =3D eif_data; + gsize kernel_size =3D eif_size; + Error *err =3D NULL; + + /* + * The user gave us a non-EIF kernel, likely a Linux kernel image. + * Assemble an EIF file from it, the -initrd and the -append argum= ents, + * so that users can perform a natural direct kernel boot. + */ + eif_data =3D build_eif(kernel_data, kernel_size, machine->initrd_f= ilename, + machine->kernel_cmdline, &eif_size, &err); + if (!eif_data) { + error_report_err(err); + exit(1); + } + + g_free(kernel_data); + } + address_space_write(&address_space_memory, EIF_LOAD_ADDR, MEMTXATTRS_UNSPECIFIED, eif_data, eif_size); =20 diff --git a/hw/nitro/meson.build b/hw/nitro/meson.build index e3f1895890..b9bd0d4300 100644 --- a/hw/nitro/meson.build +++ b/hw/nitro/meson.build @@ -1,4 +1,4 @@ system_ss.add(when: 'CONFIG_NITRO_VSOCK_BUS', if_true: files('nitro-vsock-= bus.c')) system_ss.add(when: 'CONFIG_NITRO_SERIAL_VSOCK', if_true: files('serial-vs= ock.c')) system_ss.add(when: 'CONFIG_NITRO_HEARTBEAT', if_true: files('heartbeat.c'= )) -system_ss.add(when: 'CONFIG_NITRO_MACHINE', if_true: files('machine.c')) +system_ss.add(when: 'CONFIG_NITRO_MACHINE', if_true: [files('machine.c'), = zlib]) --=20 2.47.1 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