From 57e2cc9abf5da38f600354fe920ff20e719607b4 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 5 Sep 2024 16:12:07 +0200 Subject: [PATCH 1/7] x86/loader: only patch linux kernels If the binary loaded via -kernel is *not* a linux kernel (in which case protocol == 0), do not patch the linux kernel header fields. It's (a) pointless and (b) might break binaries by random patching and (c) changes the binary hash which in turn breaks secure boot verification. Background: OVMF happily loads and runs not only linux kernels but any efi binary via direct kernel boot. Note: Breaking the secure boot verification is a problem for linux kernels too, but fixed that is left for another day ... Signed-off-by: Gerd Hoffmann Message-ID: <20240905141211.1253307-3-kraxel@redhat.com> --- hw/i386/x86-common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/i386/x86-common.c b/hw/i386/x86-common.c index dc031af662..dadc9d99e7 100644 --- a/hw/i386/x86-common.c +++ b/hw/i386/x86-common.c @@ -945,7 +945,7 @@ void x86_load_linux(X86MachineState *x86ms, * kernel on the other side of the fw_cfg interface matches the hash of the * file the user passed in. */ - if (!sev_enabled()) { + if (!sev_enabled() && protocol > 0) { memcpy(setup, header, MIN(sizeof(header), setup_size)); } From 214191f6b57458814d279a53539d64c6e54e764b Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 5 Sep 2024 16:12:08 +0200 Subject: [PATCH 2/7] x86/loader: read complete kernel Load the complete kernel (including setup) into memory. Excluding the setup is handled later when adding the FW_CFG_KERNEL_SIZE and FW_CFG_KERNEL_DATA entries. This is a preparation for the next patch which adds a new fw_cfg file containing the complete, unpatched kernel. No functional change. Signed-off-by: Gerd Hoffmann Message-ID: <20240905141211.1253307-4-kraxel@redhat.com> --- hw/i386/x86-common.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/hw/i386/x86-common.c b/hw/i386/x86-common.c index dadc9d99e7..28341b42d9 100644 --- a/hw/i386/x86-common.c +++ b/hw/i386/x86-common.c @@ -895,7 +895,6 @@ void x86_load_linux(X86MachineState *x86ms, fprintf(stderr, "qemu: invalid kernel header\n"); exit(1); } - kernel_size -= setup_size; setup = g_malloc(setup_size); kernel = g_malloc(kernel_size); @@ -904,6 +903,7 @@ void x86_load_linux(X86MachineState *x86ms, fprintf(stderr, "fread() failed\n"); exit(1); } + fseek(f, 0, SEEK_SET); if (fread(kernel, 1, kernel_size, f) != kernel_size) { fprintf(stderr, "fread() failed\n"); exit(1); @@ -950,10 +950,11 @@ void x86_load_linux(X86MachineState *x86ms, } fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, prot_addr); - fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size); - fw_cfg_add_bytes(fw_cfg, FW_CFG_KERNEL_DATA, kernel, kernel_size); - sev_load_ctx.kernel_data = (char *)kernel; - sev_load_ctx.kernel_size = kernel_size; + fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size - setup_size); + fw_cfg_add_bytes(fw_cfg, FW_CFG_KERNEL_DATA, + kernel + setup_size, kernel_size - setup_size); + sev_load_ctx.kernel_data = (char *)kernel + setup_size; + sev_load_ctx.kernel_size = kernel_size - setup_size; fw_cfg_add_i32(fw_cfg, FW_CFG_SETUP_ADDR, real_addr); fw_cfg_add_i32(fw_cfg, FW_CFG_SETUP_SIZE, setup_size); From f2594d928444fc4d593117db2da8c9ffa26433f7 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 5 Sep 2024 16:12:09 +0200 Subject: [PATCH 3/7] x86/loader: expose unpatched kernel Add a new "etc/boot/kernel" fw_cfg file, containing the kernel without the setup header patches. Intended use is booting in UEFI with secure boot enabled, where the setup header patching breaks secure boot verification. Needs OVMF changes too to be actually useful. Signed-off-by: Gerd Hoffmann Message-ID: <20240905141211.1253307-5-kraxel@redhat.com> --- hw/i386/x86-common.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hw/i386/x86-common.c b/hw/i386/x86-common.c index 28341b42d9..1cef3045ad 100644 --- a/hw/i386/x86-common.c +++ b/hw/i386/x86-common.c @@ -962,6 +962,9 @@ void x86_load_linux(X86MachineState *x86ms, sev_load_ctx.setup_data = (char *)setup; sev_load_ctx.setup_size = setup_size; + /* kernel without setup header patches */ + fw_cfg_add_file(fw_cfg, "etc/boot/kernel", kernel, kernel_size); + if (sev_enabled()) { sev_add_kernel_loader_hashes(&sev_load_ctx, &error_fatal); } From a5bd044b15793ab041102a1e784813f54912a836 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 5 Sep 2024 16:12:10 +0200 Subject: [PATCH 4/7] x86/loader: add -shim option Add new -shim command line option, wire up for the x86 loader. When specified load shim into the new "etc/boot/shim" fw_cfg file. Needs OVMF changes too to be actually useful. Signed-off-by: Gerd Hoffmann Message-ID: <20240905141211.1253307-6-kraxel@redhat.com> --- hw/core/machine.c | 20 ++++++++++++++++++++ hw/i386/x86-common.c | 16 ++++++++++++++++ include/hw/boards.h | 1 + qemu-options.hx | 7 +++++++ system/vl.c | 9 +++++++++ 5 files changed, 53 insertions(+) diff --git a/hw/core/machine.c b/hw/core/machine.c index e6900b43ef..d970f753e3 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -305,6 +305,21 @@ static void machine_set_kernel(Object *obj, const char *value, Error **errp) ms->kernel_filename = g_strdup(value); } +static char *machine_get_shim(Object *obj, Error **errp) +{ + MachineState *ms = MACHINE(obj); + + return g_strdup(ms->shim_filename); +} + +static void machine_set_shim(Object *obj, const char *value, Error **errp) +{ + MachineState *ms = MACHINE(obj); + + g_free(ms->shim_filename); + ms->shim_filename = g_strdup(value); +} + static char *machine_get_initrd(Object *obj, Error **errp) { MachineState *ms = MACHINE(obj); @@ -1082,6 +1097,11 @@ static void machine_class_init(ObjectClass *oc, void *data) object_class_property_set_description(oc, "kernel", "Linux kernel image file"); + object_class_property_add_str(oc, "shim", + machine_get_shim, machine_set_shim); + object_class_property_set_description(oc, "shim", + "shim.efi file"); + object_class_property_add_str(oc, "initrd", machine_get_initrd, machine_set_initrd); object_class_property_set_description(oc, "initrd", diff --git a/hw/i386/x86-common.c b/hw/i386/x86-common.c index 1cef3045ad..3f78182692 100644 --- a/hw/i386/x86-common.c +++ b/hw/i386/x86-common.c @@ -965,6 +965,22 @@ void x86_load_linux(X86MachineState *x86ms, /* kernel without setup header patches */ fw_cfg_add_file(fw_cfg, "etc/boot/kernel", kernel, kernel_size); + if (machine->shim_filename) { + GMappedFile *mapped_file; + GError *gerr = NULL; + + mapped_file = g_mapped_file_new(machine->shim_filename, false, &gerr); + if (!mapped_file) { + fprintf(stderr, "qemu: error reading shim %s: %s\n", + machine->shim_filename, gerr->message); + exit(1); + } + + fw_cfg_add_file(fw_cfg, "etc/boot/shim", + g_mapped_file_get_contents(mapped_file), + g_mapped_file_get_length(mapped_file)); + } + if (sev_enabled()) { sev_add_kernel_loader_hashes(&sev_load_ctx, &error_fatal); } diff --git a/include/hw/boards.h b/include/hw/boards.h index 7456889c37..5723ee76bd 100644 --- a/include/hw/boards.h +++ b/include/hw/boards.h @@ -431,6 +431,7 @@ struct MachineState { BootConfiguration boot_config; char *kernel_filename; char *kernel_cmdline; + char *shim_filename; char *initrd_filename; const char *cpu_type; AccelState *accelerator; diff --git a/qemu-options.hx b/qemu-options.hx index dacc9790a4..cc694d3b89 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -4145,6 +4145,13 @@ SRST or in multiboot format. ERST +DEF("shim", HAS_ARG, QEMU_OPTION_shim, \ + "-shim shim.efi use 'shim.efi' to boot the kernel\n", QEMU_ARCH_ALL) +SRST +``-shim shim.efi`` + Use 'shim.efi' to boot the kernel +ERST + DEF("append", HAS_ARG, QEMU_OPTION_append, \ "-append cmdline use 'cmdline' as kernel command line\n", QEMU_ARCH_ALL) SRST diff --git a/system/vl.c b/system/vl.c index 4a370da624..09202b57e7 100644 --- a/system/vl.c +++ b/system/vl.c @@ -2427,6 +2427,7 @@ static void configure_accelerators(const char *progname) static void qemu_validate_options(const QDict *machine_opts) { const char *kernel_filename = qdict_get_try_str(machine_opts, "kernel"); + const char *shim_filename = qdict_get_try_str(machine_opts, "shim"); const char *initrd_filename = qdict_get_try_str(machine_opts, "initrd"); const char *kernel_cmdline = qdict_get_try_str(machine_opts, "append"); @@ -2436,6 +2437,11 @@ static void qemu_validate_options(const QDict *machine_opts) exit(1); } + if (shim_filename != NULL) { + error_report("-shim only allowed with -kernel option"); + exit(1); + } + if (initrd_filename != NULL) { error_report("-initrd only allowed with -kernel option"); exit(1); @@ -2912,6 +2918,9 @@ void qemu_init(int argc, char **argv) case QEMU_OPTION_kernel: qdict_put_str(machine_opts_dict, "kernel", optarg); break; + case QEMU_OPTION_shim: + qdict_put_str(machine_opts_dict, "shim", optarg); + break; case QEMU_OPTION_initrd: qdict_put_str(machine_opts_dict, "initrd", optarg); break; From d1770b5834cafff007bbe5218915f18879ff8e48 Mon Sep 17 00:00:00 2001 From: "Pratik R. Sampat" Date: Mon, 18 Nov 2024 10:14:05 -0600 Subject: [PATCH 5/7] pc-bios: Add amd-sev-es to edk2 json With the default BIOS being compatible with amd-sev-es add the feature to the json to indicate it's support Signed-off-by: Pratik R. Sampat Message-ID: <20241118161405.208437-1-pratikrajesh.sampat@amd.com> Signed-off-by: Gerd Hoffmann --- pc-bios/descriptors/60-edk2-x86_64.json | 1 + 1 file changed, 1 insertion(+) diff --git a/pc-bios/descriptors/60-edk2-x86_64.json b/pc-bios/descriptors/60-edk2-x86_64.json index 968cb65cf9..4599c63f14 100644 --- a/pc-bios/descriptors/60-edk2-x86_64.json +++ b/pc-bios/descriptors/60-edk2-x86_64.json @@ -26,6 +26,7 @@ "features": [ "acpi-s3", "amd-sev", + "amd-sev-es", "verbose-dynamic" ], "tags": [ From 74dc38d0c6c15fd57a5dee94125d13ac5b00491d Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 12 Dec 2024 10:00:59 +0100 Subject: [PATCH 6/7] pc-bios: add missing riscv64 descriptor Without descriptor libvirt cannot discover the EDK II binaries via the qemu:///system connection. Signed-off-by: Heinrich Schuchardt Message-ID: <20241212090059.94167-1-heinrich.schuchardt@canonical.com> Signed-off-by: Gerd Hoffmann --- pc-bios/descriptors/60-edk2-riscv64.json | 31 ++++++++++++++++++++++++ pc-bios/descriptors/meson.build | 3 ++- 2 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 pc-bios/descriptors/60-edk2-riscv64.json diff --git a/pc-bios/descriptors/60-edk2-riscv64.json b/pc-bios/descriptors/60-edk2-riscv64.json new file mode 100644 index 0000000000..14811ca307 --- /dev/null +++ b/pc-bios/descriptors/60-edk2-riscv64.json @@ -0,0 +1,31 @@ +{ + "description": "UEFI firmware for riscv64", + "interface-types": [ + "uefi" + ], + "mapping": { + "device": "flash", + "executable": { + "filename": "@DATADIR@/edk2-riscv-code.fd", + "format": "raw" + }, + "nvram-template": { + "filename": "@DATADIR@/edk2-riscv-vars.fd", + "format": "raw" + } + }, + "targets": [ + { + "architecture": "riscv64", + "machines": [ + "virt*" + ] + } + ], + "features": [ + + ], + "tags": [ + + ] +} diff --git a/pc-bios/descriptors/meson.build b/pc-bios/descriptors/meson.build index afb5a959cc..cdd0be01a3 100644 --- a/pc-bios/descriptors/meson.build +++ b/pc-bios/descriptors/meson.build @@ -6,7 +6,8 @@ if unpack_edk2_blobs and get_option('install_blobs') '60-edk2-arm.json', '60-edk2-i386.json', '60-edk2-x86_64.json', - '60-edk2-loongarch64.json' + '60-edk2-loongarch64.json', + '60-edk2-riscv64.json' ] configure_file(input: files(f), output: f, From 0f5715e4b5706b31b3550d8e6b88871e029c7823 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 12 Dec 2024 09:44:07 +0100 Subject: [PATCH 7/7] roms: re-add edk2-basetools target Needed to build ipxe nic roms. Reported-by: Liu Jaloo Fixes: 22e11539e167 ("edk2: replace build scripts") Signed-off-by: Gerd Hoffmann Message-ID: <20241212084408.1390728-1-kraxel@redhat.com> --- roms/Makefile | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/roms/Makefile b/roms/Makefile index dfed2b216a..31e4b97c98 100644 --- a/roms/Makefile +++ b/roms/Makefile @@ -157,6 +157,11 @@ edk2-version: edk2 touch $@; \ fi +edk2-basetools: edk2-version + $(PYTHON) edk2-build.py --config edk2-build.config \ + --silent --no-logs \ + --match none # build only basetools + efi: edk2-version $(PYTHON) edk2-build.py --config edk2-build.config \ --version-override "$(EDK2_STABLE)$(FIRMWARE_EXTRAVERSION)" \