From nobody Sun Apr 12 06:07:42 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=1771379628; cv=none; d=zohomail.com; s=zohoarc; b=Ek2xVhYQL/2MGMzH6cqTvWPs4HZAYT1yxFoLhe5tpCOSEuFAejotYL/IA2k9rn2UIpnXDilj0jpS5zY58TTcoS4b09i71Lt8gJYPnMXMTTm/Y1+5IVUGPWZ3IayHPYfa3Bb1ebHHW4BY/029wmZ+SmVhmpVOtkZcX/wEwXUn9zE= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1771379628; 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=vGUcozSGDe3LdA51buWeDnWuA1XOyLH+O+KdKgLB5Pc=; b=RPkp6dBCKwjYO/l5r13oayAHz0XGS+7TY65FAv6svKEANDciOn9GzpxmZYDLEMH4AEIgN2M4RHZ89gi9lHFVwc8+TS/MtyA4j/qtUVK3h98z5uPU1rHKk2gNUO2OVwrlwxhPybwA/6q36MWEUEVJGa3Hlr56pkqlfvff/ghL6N0= 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 1771379628899566.2979973577532; Tue, 17 Feb 2026 17:53:48 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1vsWku-0000W1-Me; Tue, 17 Feb 2026 20:53:32 -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 1vsWks-0000RL-GX; Tue, 17 Feb 2026 20:53:30 -0500 Received: from pdx-out-014.esa.us-west-2.outbound.mail-perimeter.amazon.com ([35.83.148.184]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1vsWkq-0005hY-Mq; Tue, 17 Feb 2026 20:53:30 -0500 Received: from ip-10-5-6-203.us-west-2.compute.internal (HELO smtpout.naws.us-west-2.prod.farcaster.email.amazon.dev) ([10.5.6.203]) by internal-pdx-out-014.esa.us-west-2.outbound.mail-perimeter.amazon.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 18 Feb 2026 01:53:24 +0000 Received: from EX19MTAUWC001.ant.amazon.com [205.251.233.105:30148] by smtpin.naws.us-west-2.prod.farcaster.email.amazon.dev [10.0.45.241:2525] with esmtp (Farcaster) id 0c8131c5-47b6-420c-ad7d-5afbafb4ae0e; Wed, 18 Feb 2026 01:53:23 +0000 (UTC) Received: from EX19D020UWC004.ant.amazon.com (10.13.138.149) by EX19MTAUWC001.ant.amazon.com (10.250.64.174) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA) id 15.2.2562.35; Wed, 18 Feb 2026 01:53:23 +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.35; Wed, 18 Feb 2026 01:53:20 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amazon.com; i=@amazon.com; q=dns/txt; s=amazoncorp2; t=1771379608; x=1802915608; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=vGUcozSGDe3LdA51buWeDnWuA1XOyLH+O+KdKgLB5Pc=; b=S1elGRZYfYi6eeLSA2ZbHPAvKxbrFZUe9HNijDZ+AIxE006rvcw8K3uG +uqZ6gwrUU975KYvUQJjyMoetT518uGs0q5kdZeAo90dZYNsj1ZjeRHVq r95HXvOcn3QQX+vibiL7QFEKZSgt6wkRprT1YG42cDztl8e349KrU6B8V K5xwQdjIT5eWpgCNt9E5CEBt6UQ/8MYJsZpK66CqkTlm7wVMHZM84N6ew O1Pwtpw6pnh5uKmgpH0G7JquvUStob4qQ9ZOG3SwSRyKWeoBihajB8oVv JIej/CwTp+xVwwvWvojxoChlNKOHuzr3QZAXFbxaXVMZzluuDE2QGgyUi A==; X-CSE-ConnectionGUID: 6RaYNiU/T8y49rRrUjpGMA== X-CSE-MsgGUID: Pxs3kH1ESw2hw1KvXZzSRg== X-IronPort-AV: E=Sophos;i="6.21,297,1763424000"; d="scan'208";a="13037688" X-Farcaster-Flow-ID: 0c8131c5-47b6-420c-ad7d-5afbafb4ae0e From: Alexander Graf To: CC: , Peter Maydell , "Thomas Huth" , , , , , Cornelia Huck , , Dorjoy Chowdhury , Pierrick Bouvier , Paolo Bonzini , Tyler Fanelli , , Subject: [PATCH 09/10] hw/nitro: Enable direct kernel boot Date: Wed, 18 Feb 2026 01:51:49 +0000 Message-ID: <20260218015151.4052-10-graf@amazon.com> X-Mailer: git-send-email 2.47.1 In-Reply-To: <20260218015151.4052-1-graf@amazon.com> References: <20260218015151.4052-1-graf@amazon.com> MIME-Version: 1.0 X-Originating-IP: [172.19.99.218] X-ClientProxiedBy: EX19D032UWA004.ant.amazon.com (10.13.139.56) 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=35.83.148.184; envelope-from=prvs=502105d20=graf@amazon.de; helo=pdx-out-014.esa.us-west-2.outbound.mail-perimeter.amazon.com X-Spam_score_int: -19 X-Spam_score: -2.0 X-Spam_bar: -- X-Spam_report: (-2.0 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.043, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, HEADER_FROM_DIFFERENT_DOMAINS=0.001, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_NONE=0.001, T_SPF_PERMERROR=0.01, UNPARSEABLE_RELAY=0.001 autolearn=ham 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: 1771379630948154100 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 197adfbdb5..33b0749288 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_create_cpu(const char *cpu_type, int index) { Object *obj =3D object_new(cpu_type); @@ -87,6 +182,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 813f5a9c87..7b23f71d5a 100644 --- a/hw/nitro/meson.build +++ b/hw/nitro/meson.build @@ -1,3 +1,3 @@ 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