On Thu, Feb 26, 2026 at 4:09 AM Alexander Graf <[email protected]> wrote:
>
> 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 <[email protected]>
> ---
>  hw/core/eif.h        |   3 ++
>  hw/nitro/machine.c   | 116 +++++++++++++++++++++++++++++++++++++++++++
>  hw/nitro/meson.build |   2 +-
>  3 files changed, 120 insertions(+), 1 deletion(-)
>

Reviewed-by: Dorjoy Chowdhury <[email protected]>

> 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
>
>  #define MAX_SECTIONS 32
> +#define EIF_HDR_ARCH_ARM64 0x1
>
>  /* members are ordered according to field order in .eif file */
>  typedef struct EifHeader {
> @@ -49,6 +50,8 @@ enum EifSectionTypes {
>      EIF_SECTION_MAX = 6,
>  };
>
> +#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 <zlib.h> /* for crc32 */
>
>  #define EIF_LOAD_ADDR   (8 * 1024 * 1024)
>
> +static bool is_eif(char *eif, gsize len)
> +{
> +    const char eif_magic[] = EIF_MAGIC;
> +
> +    return len >= sizeof(eif_magic) &&
> +           !memcmp(eif, eif_magic, sizeof(eif_magic));
> +}
> +
> +static void build_eif_section(EifHeader *hdr, GByteArray *buf, uint16_t type,
> +                              const char *data, uint64_t size)
> +{
> +    uint16_t section = be16_to_cpu(hdr->section_cnt);
> +    EifSectionHeader shdr = {
> +        .section_type = cpu_to_be16(type),
> +        .flags = 0,
> +        .section_size = cpu_to_be64(size),
> +    };
> +
> +    hdr->section_offsets[section] = cpu_to_be64(buf->len);
> +    hdr->section_sizes[section] = 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 = 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 = NULL;
> +    static const char metadata[] = "{}";
> +    size_t metadata_len = sizeof(metadata) - 1;
> +    gsize initrd_size = 0;
> +    GByteArray *buf;
> +    EifHeader hdr;
> +    uint32_t crc = 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 = g_byte_array_new();
> +
> +    cmdline_len = cmdline ? strlen(cmdline) : 0;
> +
> +    hdr = (EifHeader) {
> +        .magic = EIF_MAGIC,
> +        .version = cpu_to_be16(4),
> +        .flags = 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_size);
> +
> +    /* 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 = crc32(crc, buf->data, offsetof(EifHeader, eif_crc32));
> +    crc = crc32(crc, &buf->data[sizeof(hdr)], buf->len - sizeof(hdr));
> +
> +    /* Finally write the CRC into the in-buffer header */
> +    ((EifHeader *)buf->data)->eif_crc32 = cpu_to_be32(crc);
> +
> +    *out_size = buf->len;
> +    return (char *)g_byte_array_free(buf, false);
> +}
> +
>  static void nitro_machine_init(MachineState *machine)
>  {
>      const char *eif_path = 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 = eif_data;
> +        gsize kernel_size = eif_size;
> +        Error *err = 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 
> arguments,
> +         * so that users can perform a natural direct kernel boot.
> +         */
> +        eif_data = build_eif(kernel_data, kernel_size, 
> machine->initrd_filename,
> +                             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);
>
> 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-vsock.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])
> --
> 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
>

Reply via email to