Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

efi: libstub: Add mixed mode support to command line initrd loader

Now that we have support for calling protocols that need additional
marshalling for mixed mode, wire up the initrd command line loader.

Signed-off-by: Ard Biesheuvel <ardb@kernel.org>

+82 -42
+11
arch/x86/include/asm/efi.h
··· 324 324 #define __efi64_argmap_set_memory_space_attributes(phys, size, flags) \ 325 325 (__efi64_split(phys), __efi64_split(size), __efi64_split(flags)) 326 326 327 + /* file protocol */ 328 + #define __efi64_argmap_open(prot, newh, fname, mode, attr) \ 329 + ((prot), efi64_zero_upper(newh), (fname), __efi64_split(mode), \ 330 + __efi64_split(attr)) 331 + 332 + #define __efi64_argmap_set_position(pos) (__efi64_split(pos)) 333 + 334 + /* file system protocol */ 335 + #define __efi64_argmap_open_volume(prot, file) \ 336 + ((prot), efi64_zero_upper(file)) 337 + 327 338 /* 328 339 * The macros below handle the plumbing for the argument mapping. To add a 329 340 * mapping for a specific EFI method, simply define a macro
+1 -1
drivers/firmware/efi/libstub/efi-stub-helper.c
··· 539 539 unsigned long hard_limit) 540 540 { 541 541 if (!IS_ENABLED(CONFIG_EFI_GENERIC_STUB_INITRD_CMDLINE_LOADER) || 542 - (IS_ENABLED(CONFIG_X86) && (!efi_is_native() || image == NULL))) 542 + (IS_ENABLED(CONFIG_X86) && image == NULL)) 543 543 return EFI_UNSUPPORTED; 544 544 545 545 return handle_cmdline_files(image, L"initrd=", sizeof(L"initrd=") - 2,
+53 -26
drivers/firmware/efi/libstub/efistub.h
··· 595 595 efi_char16_t filename[]; 596 596 } efi_file_info_t; 597 597 598 - typedef struct efi_file_protocol efi_file_protocol_t; 598 + typedef union efi_file_protocol efi_file_protocol_t; 599 599 600 - struct efi_file_protocol { 601 - u64 revision; 602 - efi_status_t (__efiapi *open) (efi_file_protocol_t *, 603 - efi_file_protocol_t **, 604 - efi_char16_t *, u64, u64); 605 - efi_status_t (__efiapi *close) (efi_file_protocol_t *); 606 - efi_status_t (__efiapi *delete) (efi_file_protocol_t *); 607 - efi_status_t (__efiapi *read) (efi_file_protocol_t *, 608 - unsigned long *, void *); 609 - efi_status_t (__efiapi *write) (efi_file_protocol_t *, 610 - unsigned long, void *); 611 - efi_status_t (__efiapi *get_position)(efi_file_protocol_t *, u64 *); 612 - efi_status_t (__efiapi *set_position)(efi_file_protocol_t *, u64); 613 - efi_status_t (__efiapi *get_info) (efi_file_protocol_t *, 614 - efi_guid_t *, unsigned long *, 615 - void *); 616 - efi_status_t (__efiapi *set_info) (efi_file_protocol_t *, 617 - efi_guid_t *, unsigned long, 618 - void *); 619 - efi_status_t (__efiapi *flush) (efi_file_protocol_t *); 600 + union efi_file_protocol { 601 + struct { 602 + u64 revision; 603 + efi_status_t (__efiapi *open) (efi_file_protocol_t *, 604 + efi_file_protocol_t **, 605 + efi_char16_t *, u64, 606 + u64); 607 + efi_status_t (__efiapi *close) (efi_file_protocol_t *); 608 + efi_status_t (__efiapi *delete) (efi_file_protocol_t *); 609 + efi_status_t (__efiapi *read) (efi_file_protocol_t *, 610 + unsigned long *, 611 + void *); 612 + efi_status_t (__efiapi *write) (efi_file_protocol_t *, 613 + unsigned long, void *); 614 + efi_status_t (__efiapi *get_position)(efi_file_protocol_t *, 615 + u64 *); 616 + efi_status_t (__efiapi *set_position)(efi_file_protocol_t *, 617 + u64); 618 + efi_status_t (__efiapi *get_info) (efi_file_protocol_t *, 619 + efi_guid_t *, 620 + unsigned long *, 621 + void *); 622 + efi_status_t (__efiapi *set_info) (efi_file_protocol_t *, 623 + efi_guid_t *, 624 + unsigned long, 625 + void *); 626 + efi_status_t (__efiapi *flush) (efi_file_protocol_t *); 627 + }; 628 + struct { 629 + u64 revision; 630 + u32 open; 631 + u32 close; 632 + u32 delete; 633 + u32 read; 634 + u32 write; 635 + u32 get_position; 636 + u32 set_position; 637 + u32 get_info; 638 + u32 set_info; 639 + u32 flush; 640 + } mixed_mode; 620 641 }; 621 642 622 - typedef struct efi_simple_file_system_protocol efi_simple_file_system_protocol_t; 643 + typedef union efi_simple_file_system_protocol efi_simple_file_system_protocol_t; 623 644 624 - struct efi_simple_file_system_protocol { 625 - u64 revision; 626 - int (__efiapi *open_volume)(efi_simple_file_system_protocol_t *, 627 - efi_file_protocol_t **); 645 + union efi_simple_file_system_protocol { 646 + struct { 647 + u64 revision; 648 + efi_status_t (__efiapi *open_volume)(efi_simple_file_system_protocol_t *, 649 + efi_file_protocol_t **); 650 + }; 651 + struct { 652 + u64 revision; 653 + u32 open_volume; 654 + } mixed_mode; 628 655 }; 629 656 630 657 #define EFI_FILE_MODE_READ 0x0000000000000001
+17 -15
drivers/firmware/efi/libstub/file.c
··· 51 51 *c = L'\\'; 52 52 } 53 53 54 - status = volume->open(volume, &fh, fi->filename, EFI_FILE_MODE_READ, 0); 54 + status = efi_call_proto(volume, open, &fh, fi->filename, 55 + EFI_FILE_MODE_READ, 0); 55 56 if (status != EFI_SUCCESS) { 56 57 efi_err("Failed to open file: %ls\n", fi->filename); 57 58 return status; 58 59 } 59 60 60 61 info_sz = sizeof(struct finfo); 61 - status = fh->get_info(fh, &info_guid, &info_sz, fi); 62 + status = efi_call_proto(fh, get_info, &info_guid, &info_sz, fi); 62 63 if (status != EFI_SUCCESS) { 63 64 efi_err("Failed to get file info\n"); 64 - fh->close(fh); 65 + efi_call_proto(fh, close); 65 66 return status; 66 67 } 67 68 ··· 78 77 efi_simple_file_system_protocol_t *io; 79 78 efi_status_t status; 80 79 81 - status = efi_bs_call(handle_protocol, image->device_handle, &fs_proto, 82 - (void **)&io); 80 + status = efi_bs_call(handle_protocol, efi_table_attr(image, device_handle), 81 + &fs_proto, (void **)&io); 83 82 if (status != EFI_SUCCESS) { 84 83 efi_err("Failed to handle fs_proto\n"); 85 84 return status; 86 85 } 87 86 88 - status = io->open_volume(io, fh); 87 + status = efi_call_proto(io, open_volume, fh); 89 88 if (status != EFI_SUCCESS) 90 89 efi_err("Failed to open volume\n"); 91 90 ··· 145 144 146 145 147 146 /* Convert the filename wide string into a device path */ 148 - initrd_dp = text_to_dp->convert_text_to_device_path(fi->filename); 147 + initrd_dp = efi_fn_call(text_to_dp, convert_text_to_device_path, 148 + fi->filename); 149 149 150 150 /* Check whether the device path in question implements simple FS */ 151 151 if ((efi_bs_call(locate_device_path, &fs_proto, &initrd_dp, &handle) ?: ··· 168 166 min(sizeof(fi->filename), 169 167 fpath->header.length - sizeof(fpath->header))); 170 168 171 - status = io->open_volume(io, volume); 169 + status = efi_call_proto(io, open_volume, volume); 172 170 if (status != EFI_SUCCESS) 173 171 efi_err("Failed to open volume\n"); 174 172 ··· 189 187 unsigned long *load_addr, 190 188 unsigned long *load_size) 191 189 { 192 - const efi_char16_t *cmdline = image->load_options; 193 - u32 cmdline_len = image->load_options_size; 190 + const efi_char16_t *cmdline = efi_table_attr(image, load_options); 191 + u32 cmdline_len = efi_table_attr(image, load_options_size); 194 192 unsigned long efi_chunk_size = ULONG_MAX; 195 193 efi_file_protocol_t *volume = NULL; 196 194 efi_file_protocol_t *file; ··· 278 276 while (size) { 279 277 unsigned long chunksize = min(size, efi_chunk_size); 280 278 281 - status = file->read(file, &chunksize, addr); 279 + status = efi_call_proto(file, read, &chunksize, addr); 282 280 if (status != EFI_SUCCESS) { 283 281 efi_err("Failed to read file\n"); 284 282 goto err_close_file; ··· 286 284 addr += chunksize; 287 285 size -= chunksize; 288 286 } 289 - file->close(file); 290 - volume->close(volume); 287 + efi_call_proto(file, close); 288 + efi_call_proto(volume, close); 291 289 } while (offset > 0); 292 290 293 291 *load_addr = alloc_addr; ··· 298 296 return EFI_SUCCESS; 299 297 300 298 err_close_file: 301 - file->close(file); 299 + efi_call_proto(file, close); 302 300 303 301 err_close_volume: 304 - volume->close(volume); 302 + efi_call_proto(volume, close); 305 303 306 304 err_free_alloc: 307 305 efi_free(alloc_size, alloc_addr);