diff options
author | Michael Niewöhner <foss@mniewoehner.de> | 2019-02-20 21:09:09 +0100 |
---|---|---|
committer | Michael Niewöhner <foss@mniewoehner.de> | 2019-02-20 22:59:52 +0100 |
commit | 6247c336140fbe44479ba9e677b8e97b0431eda5 (patch) | |
tree | 8cb2470c3e0adc8ddb577eb823ded26bb024ad95 /src/boot | |
parent | Revert "Set secure_boot flag in Kernel Zero-Page (#7482)" (diff) | |
download | systemd-6247c336140fbe44479ba9e677b8e97b0431eda5.tar.xz systemd-6247c336140fbe44479ba9e677b8e97b0431eda5.zip |
Make systemd-boot compliant with the Linux Boot / EFI Handover Protocol
The current implementation copied the *complete* header to boot_params,
thus making the kernel ignore many of the fields.
As mentioned in the code comment for the sentinel variable in
bootparam.h a bootloader should only copy the setup_header, set some
fields in boot_params and zero out anything else.
This change makes systemd-boot (mostly) compliant with the Linux Boot
Protocol and the EFI Handover Protocol described in bootparam.h and
Documentation/boot.txt to fix various issues:
- Secure boot not being detected corretly by Linux (#11717)
- tboot error message / warning on boot (#11717)
- Strange purple text color when booting in qemu with OVMF
- Hopefully even more ...
Diffstat (limited to 'src/boot')
-rw-r--r-- | src/boot/efi/linux.c | 96 | ||||
-rw-r--r-- | src/boot/efi/linux.h | 80 |
2 files changed, 107 insertions, 69 deletions
diff --git a/src/boot/efi/linux.c b/src/boot/efi/linux.c index 33d51dbd72..ad26cc510e 100644 --- a/src/boot/efi/linux.c +++ b/src/boot/efi/linux.c @@ -6,66 +6,22 @@ #include "linux.h" #include "util.h" -#define SETUP_MAGIC 0x53726448 /* "HdrS" */ -struct SetupHeader { - UINT8 boot_sector[0x01f1]; - UINT8 setup_secs; - UINT16 root_flags; - UINT32 sys_size; - UINT16 ram_size; - UINT16 video_mode; - UINT16 root_dev; - UINT16 signature; - UINT16 jump; - UINT32 header; - UINT16 version; - UINT16 su_switch; - UINT16 setup_seg; - UINT16 start_sys; - UINT16 kernel_ver; - UINT8 loader_id; - UINT8 load_flags; - UINT16 movesize; - UINT32 code32_start; - UINT32 ramdisk_start; - UINT32 ramdisk_len; - UINT32 bootsect_kludge; - UINT16 heap_end; - UINT8 ext_loader_ver; - UINT8 ext_loader_type; - UINT32 cmd_line_ptr; - UINT32 ramdisk_max; - UINT32 kernel_alignment; - UINT8 relocatable_kernel; - UINT8 min_alignment; - UINT16 xloadflags; - UINT32 cmdline_size; - UINT32 hardware_subarch; - UINT64 hardware_subarch_data; - UINT32 payload_offset; - UINT32 payload_length; - UINT64 setup_data; - UINT64 pref_address; - UINT32 init_size; - UINT32 handover_offset; -} __attribute__((packed)); - #ifdef __x86_64__ -typedef VOID(*handover_f)(VOID *image, EFI_SYSTEM_TABLE *table, struct SetupHeader *setup); -static VOID linux_efi_handover(EFI_HANDLE image, struct SetupHeader *setup) { +typedef VOID(*handover_f)(VOID *image, EFI_SYSTEM_TABLE *table, struct boot_params *params); +static VOID linux_efi_handover(EFI_HANDLE image, struct boot_params *params) { handover_f handover; asm volatile ("cli"); - handover = (handover_f)((UINTN)setup->code32_start + 512 + setup->handover_offset); - handover(image, ST, setup); + handover = (handover_f)((UINTN)params->hdr.code32_start + 512 + params->hdr.handover_offset); + handover(image, ST, params); } #else -typedef VOID(*handover_f)(VOID *image, EFI_SYSTEM_TABLE *table, struct SetupHeader *setup) __attribute__((regparm(0))); -static VOID linux_efi_handover(EFI_HANDLE image, struct SetupHeader *setup) { +typedef VOID(*handover_f)(VOID *image, EFI_SYSTEM_TABLE *table, struct boot_params *params) __attribute__((regparm(0))); +static VOID linux_efi_handover(EFI_HANDLE image, struct boot_params *params) { handover_f handover; - handover = (handover_f)((UINTN)setup->code32_start + setup->handover_offset); - handover(image, ST, setup); + handover = (handover_f)((UINTN)params->hdr.code32_start + params->hdr.handover_offset); + handover(image, ST, params); } #endif @@ -73,29 +29,31 @@ EFI_STATUS linux_exec(EFI_HANDLE *image, CHAR8 *cmdline, UINTN cmdline_len, UINTN linux_addr, UINTN initrd_addr, UINTN initrd_size) { - struct SetupHeader *image_setup; - struct SetupHeader *boot_setup; + struct boot_params *image_params; + struct boot_params *boot_params; + UINT8 setup_sectors; EFI_PHYSICAL_ADDRESS addr; EFI_STATUS err; - image_setup = (struct SetupHeader *)(linux_addr); - if (image_setup->signature != 0xAA55 || image_setup->header != SETUP_MAGIC) - return EFI_LOAD_ERROR; + image_params = (struct boot_params *) linux_addr; - if (image_setup->version < 0x20b || !image_setup->relocatable_kernel) + if (image_params->hdr.boot_flag != 0xAA55 || + image_params->hdr.header != SETUP_MAGIC || + image_params->hdr.version < 0x20b || + !image_params->hdr.relocatable_kernel) return EFI_LOAD_ERROR; - addr = 0x3fffffff; + boot_params = (struct boot_params *) 0xFFFFFFFF; err = uefi_call_wrapper(BS->AllocatePages, 4, AllocateMaxAddress, EfiLoaderData, - EFI_SIZE_TO_PAGES(0x4000), &addr); + EFI_SIZE_TO_PAGES(0x4000), (UINTN *) &boot_params); if (EFI_ERROR(err)) return err; - boot_setup = (struct SetupHeader *)(UINTN)addr; - ZeroMem(boot_setup, 0x4000); - CopyMem(boot_setup, image_setup, sizeof(struct SetupHeader)); - boot_setup->loader_id = 0xff; - boot_setup->code32_start = (UINT32)linux_addr + (image_setup->setup_secs+1) * 512; + ZeroMem(boot_params, 0x4000); + CopyMem(&boot_params->hdr, &image_params->hdr, sizeof(struct setup_header)); + boot_params->hdr.type_of_loader = 0xff; + setup_sectors = image_params->hdr.setup_sects > 0 ? image_params->hdr.setup_sects : 4; + boot_params->hdr.code32_start = (UINT32)linux_addr + (setup_sectors + 1) * 512; if (cmdline) { addr = 0xA0000; @@ -105,12 +63,12 @@ EFI_STATUS linux_exec(EFI_HANDLE *image, return err; CopyMem((VOID *)(UINTN)addr, cmdline, cmdline_len); ((CHAR8 *)(UINTN)addr)[cmdline_len] = 0; - boot_setup->cmd_line_ptr = (UINT32)addr; + boot_params->hdr.cmd_line_ptr = (UINT32)addr; } - boot_setup->ramdisk_start = (UINT32)initrd_addr; - boot_setup->ramdisk_len = (UINT32)initrd_size; + boot_params->hdr.ramdisk_image = (UINT32)initrd_addr; + boot_params->hdr.ramdisk_size = (UINT32)initrd_size; - linux_efi_handover(image, boot_setup); + linux_efi_handover(image, boot_params); return EFI_LOAD_ERROR; } diff --git a/src/boot/efi/linux.h b/src/boot/efi/linux.h index 4cae99773b..ec655ce647 100644 --- a/src/boot/efi/linux.h +++ b/src/boot/efi/linux.h @@ -1,6 +1,86 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once +#define SETUP_MAGIC 0x53726448 /* "HdrS" */ + +struct setup_header { + UINT8 setup_sects; + UINT16 root_flags; + UINT32 syssize; + UINT16 ram_size; + UINT16 vid_mode; + UINT16 root_dev; + UINT16 boot_flag; + UINT16 jump; + UINT32 header; + UINT16 version; + UINT32 realmode_swtch; + UINT16 start_sys_seg; + UINT16 kernel_version; + UINT8 type_of_loader; + UINT8 loadflags; + UINT16 setup_move_size; + UINT32 code32_start; + UINT32 ramdisk_image; + UINT32 ramdisk_size; + UINT32 bootsect_kludge; + UINT16 heap_end_ptr; + UINT8 ext_loader_ver; + UINT8 ext_loader_type; + UINT32 cmd_line_ptr; + UINT32 initrd_addr_max; + UINT32 kernel_alignment; + UINT8 relocatable_kernel; + UINT8 min_alignment; + UINT16 xloadflags; + UINT32 cmdline_size; + UINT32 hardware_subarch; + UINT64 hardware_subarch_data; + UINT32 payload_offset; + UINT32 payload_length; + UINT64 setup_data; + UINT64 pref_address; + UINT32 init_size; + UINT32 handover_offset; +} __attribute__((packed)); + +/* adapted from linux' bootparam.h */ +struct boot_params { + UINT8 screen_info[64]; // was: struct screen_info + UINT8 apm_bios_info[20]; // was: struct apm_bios_info + UINT8 _pad2[4]; + UINT64 tboot_addr; + UINT8 ist_info[16]; // was: struct ist_info + UINT8 _pad3[16]; + UINT8 hd0_info[16]; + UINT8 hd1_info[16]; + UINT8 sys_desc_table[16]; // was: struct sys_desc_table + UINT8 olpc_ofw_header[16]; // was: struct olpc_ofw_header + UINT32 ext_ramdisk_image; + UINT32 ext_ramdisk_size; + UINT32 ext_cmd_line_ptr; + UINT8 _pad4[116]; + UINT8 edid_info[128]; // was: struct edid_info + UINT8 efi_info[32]; // was: struct efi_info + UINT32 alt_mem_k; + UINT32 scratch; + UINT8 e820_entries; + UINT8 eddbuf_entries; + UINT8 edd_mbr_sig_buf_entries; + UINT8 kbd_status; + UINT8 secure_boot; + UINT8 _pad5[2]; + UINT8 sentinel; + UINT8 _pad6[1]; + struct setup_header hdr; + UINT8 _pad7[0x290-0x1f1-sizeof(struct setup_header)]; + UINT32 edd_mbr_sig_buffer[16]; // was: edd_mbr_sig_buffer[EDD_MBR_SIG_MAX] + UINT8 e820_table[20*128]; // was: struct boot_e820_entry e820_table[E820_MAX_ENTRIES_ZEROPAGE] + UINT8 _pad8[48]; + UINT8 eddbuf[6*82]; // was: struct edd_info eddbuf[EDDMAXNR] + UINT8 _pad9[276]; +} __attribute__((packed)); + EFI_STATUS linux_exec(EFI_HANDLE *image, CHAR8 *cmdline, UINTN cmdline_size, UINTN linux_addr, |