From: Jan Janssen Date: Sat, 17 Sep 2022 20:02:42 +0000 (+0200) Subject: stub: Provide a proper boot params page X-Git-Tag: v252-rc1~124^2~6 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=d62c1777568ff69034fd5b5d582a2889229f7e20;p=thirdparty%2Fsystemd.git stub: Provide a proper boot params page The boot params passed to the kernel only has to be one page in size and the size of the setup header has to be calculated as it depends on the boot protocol version supported by the kernel. --- diff --git a/src/boot/efi/linux_x86.c b/src/boot/efi/linux_x86.c index 756494b9c7c..e8231de2c5c 100644 --- a/src/boot/efi/linux_x86.c +++ b/src/boot/efi/linux_x86.c @@ -19,9 +19,11 @@ #include "util.h" #define KERNEL_SECTOR_SIZE 512u -#define SETUP_MAGIC 0x53726448 /* "HdrS" */ +#define BOOT_FLAG_MAGIC 0xAA55u +#define SETUP_MAGIC 0x53726448u /* "HdrS" */ +#define SETUP_VERSION_2_11 0x20bu -struct setup_header { +typedef struct { uint8_t setup_sects; uint16_t root_flags; uint32_t syssize; @@ -29,7 +31,8 @@ struct setup_header { uint16_t vid_mode; uint16_t root_dev; uint16_t boot_flag; - uint16_t jump; + uint8_t jump; /* We split the 2-byte jump field from the spec in two for convenience. */ + uint8_t setup_size; uint32_t header; uint16_t version; uint32_t realmode_swtch; @@ -60,54 +63,30 @@ struct setup_header { uint64_t pref_address; uint32_t init_size; uint32_t handover_offset; -} _packed_; - -/* adapted from linux' bootparam.h */ -struct boot_params { - uint8_t screen_info[64]; // was: struct screen_info - uint8_t apm_bios_info[20]; // was: struct apm_bios_info - uint8_t _pad2[4]; - uint64_t tboot_addr; - uint8_t ist_info[16]; // was: struct ist_info - uint8_t _pad3[16]; - uint8_t hd0_info[16]; - uint8_t hd1_info[16]; - uint8_t sys_desc_table[16]; // was: struct sys_desc_table - uint8_t olpc_ofw_header[16]; // was: struct olpc_ofw_header +} _packed_ SetupHeader; + +/* We really only care about a few fields, but we still have to provide a full page otherwise. */ +typedef struct { + uint8_t pad[192]; uint32_t ext_ramdisk_image; uint32_t ext_ramdisk_size; uint32_t ext_cmd_line_ptr; - uint8_t _pad4[116]; - uint8_t edid_info[128]; // was: struct edid_info - uint8_t efi_info[32]; // was: struct efi_info - uint32_t alt_mem_k; - uint32_t scratch; - uint8_t e820_entries; - uint8_t eddbuf_entries; - uint8_t edd_mbr_sig_buf_entries; - uint8_t kbd_status; - uint8_t secure_boot; - uint8_t _pad5[2]; - uint8_t sentinel; - uint8_t _pad6[1]; - struct setup_header hdr; - uint8_t _pad7[0x290-0x1f1-sizeof(struct setup_header)]; - uint32_t edd_mbr_sig_buffer[16]; // was: edd_mbr_sig_buffer[EDD_MBR_SIG_MAX] - uint8_t e820_table[20*128]; // was: struct boot_e820_entry e820_table[E820_MAX_ENTRIES_ZEROPAGE] - uint8_t _pad8[48]; - uint8_t eddbuf[6*82]; // was: struct edd_info eddbuf[EDDMAXNR] - uint8_t _pad9[276]; -} _packed_; + uint8_t pad2[293]; + SetupHeader hdr; + uint8_t pad3[3480]; +} _packed_ BootParams; +assert_cc(offsetof(BootParams, ext_ramdisk_image) == 0x0C0); +assert_cc(sizeof(BootParams) == 4096); #ifdef __i386__ -#define __regparm0__ __attribute__((regparm(0))) +# define __regparm0__ __attribute__((regparm(0))) #else -#define __regparm0__ +# define __regparm0__ #endif -typedef void(*handover_f)(void *image, EFI_SYSTEM_TABLE *table, struct boot_params *params) __regparm0__; +typedef void (*handover_f)(void *image, EFI_SYSTEM_TABLE *table, BootParams *params) __regparm0__; -static void linux_efi_handover(EFI_HANDLE image, uintptr_t kernel, struct boot_params *params) { +static void linux_efi_handover(EFI_HANDLE image, uintptr_t kernel, BootParams *params) { assert(params); kernel += (params->hdr.setup_sects + 1) * KERNEL_SECTOR_SIZE; /* 32bit entry address. */ @@ -132,8 +111,6 @@ EFI_STATUS linux_exec( const void *linux_buffer, UINTN linux_length, const void *initrd_buffer, UINTN initrd_length) { - const struct boot_params *image_params; - struct boot_params *boot_params; EFI_HANDLE initrd_handle = NULL; EFI_PHYSICAL_ADDRESS addr; EFI_STATUS err; @@ -143,29 +120,35 @@ EFI_STATUS linux_exec( assert(linux_buffer); assert(initrd_buffer || initrd_length == 0); - if (linux_length < sizeof(struct boot_params)) + if (linux_length < sizeof(BootParams)) return EFI_LOAD_ERROR; - image_params = (const struct boot_params *) linux_buffer; - - 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; + const BootParams *image_params = (const BootParams *) linux_buffer; + if (image_params->hdr.header != SETUP_MAGIC || image_params->hdr.boot_flag != BOOT_FLAG_MAGIC) + return log_error_status_stall(EFI_UNSUPPORTED, u"Unsupported kernel image."); + if (image_params->hdr.version < SETUP_VERSION_2_11) + return log_error_status_stall(EFI_UNSUPPORTED, u"Kernel too old."); + if (!image_params->hdr.relocatable_kernel) + return log_error_status_stall(EFI_UNSUPPORTED, u"Kernel is not relocatable."); addr = UINT32_MAX; /* Below the 32bit boundary */ err = BS->AllocatePages( AllocateMaxAddress, EfiLoaderData, - EFI_SIZE_TO_PAGES(0x4000), + EFI_SIZE_TO_PAGES(sizeof(BootParams)), &addr); if (err != EFI_SUCCESS) return err; - boot_params = (struct boot_params *) PHYSICAL_ADDRESS_TO_POINTER(addr); - memset(boot_params, 0, 0x4000); - boot_params->hdr = image_params->hdr; + BootParams *boot_params = PHYSICAL_ADDRESS_TO_POINTER(addr); + *boot_params = (BootParams){}; + + /* Setup size is determined by offset 0x0202 + byte value at offset 0x0201, which is the same as + * offset of the header field and the target from the jump field (which we split for this reason). */ + memcpy(&boot_params->hdr, + &image_params->hdr, + offsetof(SetupHeader, header) + image_params->hdr.setup_size); + boot_params->hdr.type_of_loader = 0xff; /* Spec says: For backwards compatibility, if the setup_sects field contains 0, the real value is 4. */