diff options
Diffstat (limited to '')
-rw-r--r-- | src/boot/efi/boot.c | 2 | ||||
-rw-r--r-- | src/boot/efi/linux.c | 40 | ||||
-rw-r--r-- | src/boot/efi/linux.h | 5 | ||||
-rw-r--r-- | src/boot/efi/linux_x86.c | 209 | ||||
-rw-r--r-- | src/boot/efi/meson.build | 3 | ||||
-rw-r--r-- | src/boot/efi/pe.c | 6 | ||||
-rw-r--r-- | src/boot/efi/pe.h | 2 | ||||
-rw-r--r-- | src/boot/efi/stub.c | 26 | ||||
-rw-r--r-- | src/boot/efi/util.h | 26 |
9 files changed, 179 insertions, 140 deletions
diff --git a/src/boot/efi/boot.c b/src/boot/efi/boot.c index a7ef57cb99..fdbc55b884 100644 --- a/src/boot/efi/boot.c +++ b/src/boot/efi/boot.c @@ -2415,7 +2415,7 @@ static EFI_STATUS image_start( if (err == EFI_UNSUPPORTED && entry->type == LOADER_LINUX) { uint32_t kernel_entry_address; - err = pe_alignment_info(loaded_image->ImageBase, &kernel_entry_address, NULL, NULL); + err = pe_kernel_info(loaded_image->ImageBase, &kernel_entry_address, NULL, NULL); if (err != EFI_SUCCESS) { if (err != EFI_UNSUPPORTED) return log_error_status_stall(err, L"Error finding kernel compat entry address: %r", err); diff --git a/src/boot/efi/linux.c b/src/boot/efi/linux.c index 3cbffdbbeb..7771058c3a 100644 --- a/src/boot/efi/linux.c +++ b/src/boot/efi/linux.c @@ -92,18 +92,6 @@ static inline void cleanup_loaded_image(EFI_HANDLE *loaded_image_handle) { *loaded_image_handle = NULL; } -/* struct to call cleanup_pages */ -struct pages { - EFI_PHYSICAL_ADDRESS addr; - UINTN num; -}; - -static inline void cleanup_pages(struct pages *p) { - if (p->addr == 0) - return; - (void) BS->FreePages(p->addr, p->num); -} - EFI_STATUS linux_exec( EFI_HANDLE image, const char *cmdline, UINTN cmdline_len, @@ -114,7 +102,6 @@ EFI_STATUS linux_exec( _cleanup_(cleanup_loaded_image) EFI_HANDLE loaded_image_handle = NULL; uint32_t kernel_alignment, kernel_size_of_image, kernel_entry_address; EFI_IMAGE_ENTRY_POINT kernel_entry; - _cleanup_(cleanup_pages) struct pages kernel = {}; void *new_buffer; EFI_STATUS err; @@ -124,7 +111,20 @@ EFI_STATUS linux_exec( assert(initrd_buffer || initrd_length == 0); /* get the necessary fields from the PE header */ - err = pe_alignment_info(linux_buffer, &kernel_entry_address, &kernel_size_of_image, &kernel_alignment); + err = pe_kernel_info(linux_buffer, &kernel_entry_address, &kernel_size_of_image, &kernel_alignment); +#if defined(__i386__) || defined(__x86_64__) + if (err == EFI_UNSUPPORTED) + /* Kernel is too old to support LINUX_INITRD_MEDIA_GUID, try the deprecated EFI handover + * protocol. */ + return linux_exec_efi_handover( + image, + cmdline, + cmdline_len, + linux_buffer, + linux_length, + initrd_buffer, + initrd_length); +#endif if (err != EFI_SUCCESS) return err; /* sanity check */ @@ -140,11 +140,15 @@ EFI_STATUS linux_exec( if they are not met. x86 and x86_64 kernel stubs don't do checks and fail if the BSS section is too small. */ /* allocate SizeOfImage + SectionAlignment because the new_buffer can move up to Alignment-1 bytes */ - kernel.num = EFI_SIZE_TO_PAGES(ALIGN_TO(kernel_size_of_image, kernel_alignment) + kernel_alignment); - err = BS->AllocatePages(AllocateAnyPages, EfiLoaderCode, kernel.num, &kernel.addr); - if (err != EFI_SUCCESS) - return EFI_OUT_OF_RESOURCES; + _cleanup_pages_ Pages kernel = xmalloc_pages( + AllocateAnyPages, + EfiLoaderCode, + EFI_SIZE_TO_PAGES(ALIGN_TO(kernel_size_of_image, kernel_alignment) + kernel_alignment), + 0); new_buffer = PHYSICAL_ADDRESS_TO_POINTER(ALIGN_TO(kernel.addr, kernel_alignment)); + if (!new_buffer) /* Silence gcc 11.2.0, assert(new_buffer) doesn't work. */ + return EFI_OUT_OF_RESOURCES; + memcpy(new_buffer, linux_buffer, linux_length); /* zero out rest of memory (probably not needed, but BSS section should be 0) */ memset((uint8_t *)new_buffer + linux_length, 0, kernel_size_of_image - linux_length); diff --git a/src/boot/efi/linux.h b/src/boot/efi/linux.h index 0dfe744668..eab617e579 100644 --- a/src/boot/efi/linux.h +++ b/src/boot/efi/linux.h @@ -8,3 +8,8 @@ EFI_STATUS linux_exec( const char *cmdline, UINTN cmdline_len, const void *linux_buffer, UINTN linux_length, const void *initrd_buffer, UINTN initrd_length); +EFI_STATUS linux_exec_efi_handover( + EFI_HANDLE image, + const char *cmdline, UINTN cmdline_len, + const void *linux_buffer, UINTN linux_length, + const void *initrd_buffer, UINTN initrd_length); diff --git a/src/boot/efi/linux_x86.c b/src/boot/efi/linux_x86.c index d506070926..83bd7b2c31 100644 --- a/src/boot/efi/linux_x86.c +++ b/src/boot/efi/linux_x86.c @@ -18,9 +18,27 @@ #include "macro-fundamental.h" #include "util.h" -#define SETUP_MAGIC 0x53726448 /* "HdrS" */ +#define KERNEL_SECTOR_SIZE 512u +#define BOOT_FLAG_MAGIC 0xAA55u +#define SETUP_MAGIC 0x53726448u /* "HdrS" */ +#define SETUP_VERSION_2_11 0x20bu +#define SETUP_VERSION_2_12 0x20cu +#define SETUP_VERSION_2_15 0x20fu +#define CMDLINE_PTR_MAX 0xA0000u + +enum { + XLF_KERNEL_64 = 1 << 0, + XLF_CAN_BE_LOADED_ABOVE_4G = 1 << 1, + XLF_EFI_HANDOVER_32 = 1 << 2, + XLF_EFI_HANDOVER_64 = 1 << 3, +#ifdef __x86_64__ + XLF_EFI_HANDOVER = XLF_EFI_HANDOVER_64, +#else + XLF_EFI_HANDOVER = XLF_EFI_HANDOVER_32, +#endif +}; -struct setup_header { +typedef struct { uint8_t setup_sects; uint16_t root_flags; uint32_t syssize; @@ -28,7 +46,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; @@ -59,143 +78,127 @@ 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__; - -static void linux_efi_handover(EFI_HANDLE image, struct boot_params *params) { - handover_f handover; - UINTN start = (UINTN)params->hdr.code32_start; +typedef void (*handover_f)(void *image, EFI_SYSTEM_TABLE *table, BootParams *params) __regparm0__ + __attribute__((sysv_abi)); +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. */ + #ifdef __x86_64__ - asm volatile ("cli"); - start += 512; + kernel += KERNEL_SECTOR_SIZE; /* 64bit entry address. */ #endif - handover = (handover_f)(start + params->hdr.handover_offset); + + kernel += params->hdr.handover_offset; /* 32/64bit EFI handover address. */ + + /* Note in EFI mixed mode this now points to the correct 32bit handover entry point, allowing a 64bit + * kernel to be booted from a 32bit sd-stub. */ + + handover_f handover = (handover_f) kernel; handover(image, ST, params); } -EFI_STATUS linux_exec( +EFI_STATUS linux_exec_efi_handover( EFI_HANDLE image, const char *cmdline, UINTN cmdline_len, 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; - uint8_t setup_sectors; - EFI_STATUS err; - assert(image); assert(cmdline || cmdline_len == 0); 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; + 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."); + + /* The xloadflags were added in version 2.12+ of the boot protocol but the handover support predates + * that, so we cannot safety-check this for 2.11. */ + if (image_params->hdr.version >= SETUP_VERSION_2_12 && + !FLAGS_SET(image_params->hdr.xloadflags, XLF_EFI_HANDOVER)) + return log_error_status_stall(EFI_UNSUPPORTED, u"Kernel does not support EFI handover protocol."); + + bool can_4g = image_params->hdr.version >= SETUP_VERSION_2_12 && + FLAGS_SET(image_params->hdr.xloadflags, XLF_CAN_BE_LOADED_ABOVE_4G); + + if (!can_4g && POINTER_TO_PHYSICAL_ADDRESS(linux_buffer) + linux_length > UINT32_MAX) + return log_error_status_stall( + EFI_UNSUPPORTED, + u"Unified kernel image was loaded above 4G, but kernel lacks support."); + if (!can_4g && POINTER_TO_PHYSICAL_ADDRESS(initrd_buffer) + initrd_length > UINT32_MAX) + return log_error_status_stall( + EFI_UNSUPPORTED, u"Initrd is above 4G, but kernel lacks support."); + + _cleanup_pages_ Pages boot_params_page = xmalloc_pages( + can_4g ? AllocateAnyPages : AllocateMaxAddress, + EfiLoaderData, + EFI_SIZE_TO_PAGES(sizeof(BootParams)), + UINT32_MAX /* Below the 4G boundary */); + BootParams *boot_params = PHYSICAL_ADDRESS_TO_POINTER(boot_params_page.addr); + *boot_params = (BootParams){}; - 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; + /* 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); - addr = UINT32_MAX; /* Below the 32bit boundary */ - err = BS->AllocatePages( - AllocateMaxAddress, - EfiLoaderData, - EFI_SIZE_TO_PAGES(0x4000), - &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; 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_t) POINTER_TO_PHYSICAL_ADDRESS(linux_buffer) + (setup_sectors + 1) * 512; - if (cmdline) { - addr = 0xA0000; + /* Spec says: For backwards compatibility, if the setup_sects field contains 0, the real value is 4. */ + if (boot_params->hdr.setup_sects == 0) + boot_params->hdr.setup_sects = 4; - err = BS->AllocatePages( - AllocateMaxAddress, + _cleanup_pages_ Pages cmdline_pages = {}; + if (cmdline) { + cmdline_pages = xmalloc_pages( + can_4g ? AllocateAnyPages : AllocateMaxAddress, EfiLoaderData, EFI_SIZE_TO_PAGES(cmdline_len + 1), - &addr); - if (err != EFI_SUCCESS) - return err; + CMDLINE_PTR_MAX); - memcpy(PHYSICAL_ADDRESS_TO_POINTER(addr), cmdline, cmdline_len); - ((char *) PHYSICAL_ADDRESS_TO_POINTER(addr))[cmdline_len] = 0; - boot_params->hdr.cmd_line_ptr = (uint32_t) addr; + memcpy(PHYSICAL_ADDRESS_TO_POINTER(cmdline_pages.addr), cmdline, cmdline_len); + ((char *) PHYSICAL_ADDRESS_TO_POINTER(cmdline_pages.addr))[cmdline_len] = 0; + boot_params->hdr.cmd_line_ptr = (uint32_t) cmdline_pages.addr; + boot_params->ext_cmd_line_ptr = cmdline_pages.addr >> 32; + assert(can_4g || cmdline_pages.addr <= CMDLINE_PTR_MAX); } - /* Providing the initrd via LINUX_INITRD_MEDIA_GUID is only supported by Linux 5.8+ (5.7+ on ARM64). - Until supported kernels become more established, we continue to set ramdisk in the handover struct. - This value is overridden by kernels that support LINUX_INITRD_MEDIA_GUID. - If you need to know which protocol was used by the kernel, pass "efi=debug" to the kernel, - this will print a line when InitrdMediaGuid was successfully used to load the initrd. - */ - boot_params->hdr.ramdisk_image = (uint32_t) POINTER_TO_PHYSICAL_ADDRESS(initrd_buffer); - boot_params->hdr.ramdisk_size = (uint32_t) initrd_length; - - /* register LINUX_INITRD_MEDIA_GUID */ - err = initrd_register(initrd_buffer, initrd_length, &initrd_handle); - if (err != EFI_SUCCESS) - return err; - linux_efi_handover(image, boot_params); - (void) initrd_unregister(initrd_handle); - initrd_handle = NULL; + boot_params->hdr.ramdisk_image = (uintptr_t) initrd_buffer; + boot_params->ext_ramdisk_image = POINTER_TO_PHYSICAL_ADDRESS(initrd_buffer) >> 32; + boot_params->hdr.ramdisk_size = initrd_length; + boot_params->ext_ramdisk_size = ((uint64_t) initrd_length) >> 32; + + linux_efi_handover(image, (uintptr_t) linux_buffer, boot_params); return EFI_LOAD_ERROR; } diff --git a/src/boot/efi/meson.build b/src/boot/efi/meson.build index efe056c225..b149735246 100644 --- a/src/boot/efi/meson.build +++ b/src/boot/efi/meson.build @@ -392,14 +392,13 @@ systemd_boot_sources = files( stub_sources = files( 'cpio.c', + 'linux.c', 'splash.c', 'stub.c', ) if efi_arch[1] in ['ia32', 'x86_64'] stub_sources += files('linux_x86.c') -else - stub_sources += files('linux.c') endif tests += [ diff --git a/src/boot/efi/pe.c b/src/boot/efi/pe.c index 8d7061d55b..4602827f19 100644 --- a/src/boot/efi/pe.c +++ b/src/boot/efi/pe.c @@ -209,7 +209,7 @@ static uint32_t get_compatibility_entry_address(const DosFileHeader *dos, const return 0; } -EFI_STATUS pe_alignment_info( +EFI_STATUS pe_kernel_info( const void *base, uint32_t *ret_entry_point_address, uint32_t *ret_size_of_image, @@ -229,6 +229,10 @@ EFI_STATUS pe_alignment_info( if (!verify_pe(pe, /* allow_compatibility= */ true)) return EFI_LOAD_ERROR; + /* Support for LINUX_INITRD_MEDIA_GUID was added in kernel stub 1.0. */ + if (pe->OptionalHeader.MajorImageVersion < 1) + return EFI_UNSUPPORTED; + uint32_t entry_address = pe->OptionalHeader.AddressOfEntryPoint; /* Look for a compat entry point. */ diff --git a/src/boot/efi/pe.h b/src/boot/efi/pe.h index ea4801ced5..ead2ba01cc 100644 --- a/src/boot/efi/pe.h +++ b/src/boot/efi/pe.h @@ -17,7 +17,7 @@ EFI_STATUS pe_file_locate_sections( UINTN *offsets, UINTN *sizes); -EFI_STATUS pe_alignment_info( +EFI_STATUS pe_kernel_info( const void *base, uint32_t *ret_entry_point_address, uint32_t *ret_size_of_image, diff --git a/src/boot/efi/stub.c b/src/boot/efi/stub.c index 494972fa38..2e8b4d99d2 100644 --- a/src/boot/efi/stub.c +++ b/src/boot/efi/stub.c @@ -21,14 +21,11 @@ _used_ _section_(".sdmagic") static const char magic[] = "#### LoaderInfo: syste static EFI_STATUS combine_initrd( EFI_PHYSICAL_ADDRESS initrd_base, UINTN initrd_size, const void * const extra_initrds[], const size_t extra_initrd_sizes[], size_t n_extra_initrds, - EFI_PHYSICAL_ADDRESS *ret_initrd_base, UINTN *ret_initrd_size) { + Pages *ret_initr_pages, UINTN *ret_initrd_size) { - EFI_PHYSICAL_ADDRESS base = UINT32_MAX; /* allocate an area below the 32bit boundary for this */ - EFI_STATUS err; - uint8_t *p; UINTN n; - assert(ret_initrd_base); + assert(ret_initr_pages); assert(ret_initrd_size); /* Combines four initrds into one, by simple concatenation in memory */ @@ -45,15 +42,12 @@ static EFI_STATUS combine_initrd( n += extra_initrd_sizes[i]; } - err = BS->AllocatePages( + _cleanup_pages_ Pages pages = xmalloc_pages( AllocateMaxAddress, EfiLoaderData, EFI_SIZE_TO_PAGES(n), - &base); - if (err != EFI_SUCCESS) - return log_error_status_stall(err, L"Failed to allocate space for combined initrd: %r", err); - - p = PHYSICAL_ADDRESS_TO_POINTER(base); + UINT32_MAX /* Below 4G boundary. */); + uint8_t *p = PHYSICAL_ADDRESS_TO_POINTER(pages.addr); if (initrd_base != 0) { UINTN pad; @@ -75,10 +69,11 @@ static EFI_STATUS combine_initrd( p = mempcpy(p, extra_initrds[i], extra_initrd_sizes[i]); } - assert((uint8_t*) PHYSICAL_ADDRESS_TO_POINTER(base) + n == p); + assert(PHYSICAL_ADDRESS_TO_POINTER(pages.addr + n) == p); - *ret_initrd_base = base; + *ret_initr_pages = pages; *ret_initrd_size = n; + pages.n_pages = 0; return EFI_SUCCESS; } @@ -342,6 +337,7 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) { dt_size = szs[UNIFIED_SECTION_DTB]; dt_base = dt_size != 0 ? POINTER_TO_PHYSICAL_ADDRESS(loaded_image->ImageBase) + addrs[UNIFIED_SECTION_DTB] : 0; + _cleanup_pages_ Pages initrd_pages = {}; if (credential_initrd || global_credential_initrd || sysext_initrd) { /* If we have generated initrds dynamically, let's combine them with the built-in initrd. */ err = combine_initrd( @@ -361,10 +357,12 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) { pcrpkey_initrd_size, }, 5, - &initrd_base, &initrd_size); + &initrd_pages, &initrd_size); if (err != EFI_SUCCESS) return err; + initrd_base = initrd_pages.addr; + /* Given these might be large let's free them explicitly, quickly. */ credential_initrd = mfree(credential_initrd); global_credential_initrd = mfree(global_credential_initrd); diff --git a/src/boot/efi/util.h b/src/boot/efi/util.h index 684930d5d6..be79b205a4 100644 --- a/src/boot/efi/util.h +++ b/src/boot/efi/util.h @@ -70,6 +70,32 @@ static inline void *xrealloc(void *p, size_t old_size, size_t new_size) { #define xpool_print(fmt, ...) ((char16_t *) ASSERT_SE_PTR(PoolPrint((fmt), ##__VA_ARGS__))) #define xnew(type, n) ((type *) xmalloc_multiply(sizeof(type), (n))) +typedef struct { + EFI_PHYSICAL_ADDRESS addr; + size_t n_pages; +} Pages; + +static inline void cleanup_pages(Pages *p) { + if (p->n_pages == 0) + return; +#ifdef EFI_DEBUG + assert_se(BS->FreePages(p->addr, p->n_pages) == EFI_SUCCESS); +#else + (void) BS->FreePages(p->addr, p->n_pages); +#endif +} + +#define _cleanup_pages_ _cleanup_(cleanup_pages) + +static inline Pages xmalloc_pages( + EFI_ALLOCATE_TYPE type, EFI_MEMORY_TYPE memory_type, size_t n_pages, EFI_PHYSICAL_ADDRESS addr) { + assert_se(BS->AllocatePages(type, memory_type, n_pages, &addr) == EFI_SUCCESS); + return (Pages) { + .addr = addr, + .n_pages = n_pages, + }; +} + EFI_STATUS parse_boolean(const char *v, bool *b); EFI_STATUS efivar_set(const EFI_GUID *vendor, const char16_t *name, const char16_t *value, uint32_t flags); |