efi: libstub: Add mixed mode support to command line initrd loader
authorArd Biesheuvel <ardb@kernel.org>
Mon, 26 Sep 2022 20:17:21 +0000 (22:17 +0200)
committerArd Biesheuvel <ardb@kernel.org>
Fri, 18 Nov 2022 08:14:08 +0000 (09:14 +0100)
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>
arch/x86/include/asm/efi.h
drivers/firmware/efi/libstub/efi-stub-helper.c
drivers/firmware/efi/libstub/efistub.h
drivers/firmware/efi/libstub/file.c

index f76f15f634bc37cebfcc2ef8c129e843148598a5..aaed31e640e5646e414f31734271dfb76f3f8c92 100644 (file)
@@ -324,6 +324,17 @@ static inline u32 efi64_convert_status(efi_status_t status)
 #define __efi64_argmap_set_memory_space_attributes(phys, size, flags) \
        (__efi64_split(phys), __efi64_split(size), __efi64_split(flags))
 
+/* file protocol */
+#define __efi64_argmap_open(prot, newh, fname, mode, attr) \
+       ((prot), efi64_zero_upper(newh), (fname), __efi64_split(mode), \
+        __efi64_split(attr))
+
+#define __efi64_argmap_set_position(pos) (__efi64_split(pos))
+
+/* file system protocol */
+#define __efi64_argmap_open_volume(prot, file) \
+       ((prot), efi64_zero_upper(file))
+
 /*
  * The macros below handle the plumbing for the argument mapping. To add a
  * mapping for a specific EFI method, simply define a macro
index 2184f3f153ef6a0074d9ca2d55d1eeb946347464..01680b11d46dfc0f065427581149c2bb21b5f1d0 100644 (file)
@@ -539,7 +539,7 @@ efi_status_t efi_load_initrd_cmdline(efi_loaded_image_t *image,
                                     unsigned long hard_limit)
 {
        if (!IS_ENABLED(CONFIG_EFI_GENERIC_STUB_INITRD_CMDLINE_LOADER) ||
-           (IS_ENABLED(CONFIG_X86) && (!efi_is_native() || image == NULL)))
+           (IS_ENABLED(CONFIG_X86) && image == NULL))
                return EFI_UNSUPPORTED;
 
        return handle_cmdline_files(image, L"initrd=", sizeof(L"initrd=") - 2,
index 8bb11fb309c3d3f4af060fac70ff00ac450356ae..5615ad6f29582ec7d53288f49f1bf70f04001127 100644 (file)
@@ -595,36 +595,63 @@ typedef struct {
        efi_char16_t            filename[];
 } efi_file_info_t;
 
-typedef struct efi_file_protocol efi_file_protocol_t;
-
-struct efi_file_protocol {
-       u64             revision;
-       efi_status_t    (__efiapi *open)        (efi_file_protocol_t *,
-                                                efi_file_protocol_t **,
-                                                efi_char16_t *, u64, u64);
-       efi_status_t    (__efiapi *close)       (efi_file_protocol_t *);
-       efi_status_t    (__efiapi *delete)      (efi_file_protocol_t *);
-       efi_status_t    (__efiapi *read)        (efi_file_protocol_t *,
-                                                unsigned long *, void *);
-       efi_status_t    (__efiapi *write)       (efi_file_protocol_t *,
-                                                unsigned long, void *);
-       efi_status_t    (__efiapi *get_position)(efi_file_protocol_t *, u64 *);
-       efi_status_t    (__efiapi *set_position)(efi_file_protocol_t *, u64);
-       efi_status_t    (__efiapi *get_info)    (efi_file_protocol_t *,
-                                                efi_guid_t *, unsigned long *,
-                                                void *);
-       efi_status_t    (__efiapi *set_info)    (efi_file_protocol_t *,
-                                                efi_guid_t *, unsigned long,
-                                                void *);
-       efi_status_t    (__efiapi *flush)       (efi_file_protocol_t *);
+typedef union efi_file_protocol efi_file_protocol_t;
+
+union efi_file_protocol {
+       struct {
+               u64             revision;
+               efi_status_t    (__efiapi *open)        (efi_file_protocol_t *,
+                                                        efi_file_protocol_t **,
+                                                        efi_char16_t *, u64,
+                                                        u64);
+               efi_status_t    (__efiapi *close)       (efi_file_protocol_t *);
+               efi_status_t    (__efiapi *delete)      (efi_file_protocol_t *);
+               efi_status_t    (__efiapi *read)        (efi_file_protocol_t *,
+                                                        unsigned long *,
+                                                        void *);
+               efi_status_t    (__efiapi *write)       (efi_file_protocol_t *,
+                                                        unsigned long, void *);
+               efi_status_t    (__efiapi *get_position)(efi_file_protocol_t *,
+                                                        u64 *);
+               efi_status_t    (__efiapi *set_position)(efi_file_protocol_t *,
+                                                        u64);
+               efi_status_t    (__efiapi *get_info)    (efi_file_protocol_t *,
+                                                        efi_guid_t *,
+                                                        unsigned long *,
+                                                        void *);
+               efi_status_t    (__efiapi *set_info)    (efi_file_protocol_t *,
+                                                        efi_guid_t *,
+                                                        unsigned long,
+                                                        void *);
+               efi_status_t    (__efiapi *flush)       (efi_file_protocol_t *);
+       };
+       struct {
+               u64 revision;
+               u32 open;
+               u32 close;
+               u32 delete;
+               u32 read;
+               u32 write;
+               u32 get_position;
+               u32 set_position;
+               u32 get_info;
+               u32 set_info;
+               u32 flush;
+       } mixed_mode;
 };
 
-typedef struct efi_simple_file_system_protocol efi_simple_file_system_protocol_t;
+typedef union efi_simple_file_system_protocol efi_simple_file_system_protocol_t;
 
-struct efi_simple_file_system_protocol {
-       u64     revision;
-       int     (__efiapi *open_volume)(efi_simple_file_system_protocol_t *,
-                                       efi_file_protocol_t **);
+union efi_simple_file_system_protocol {
+       struct {
+               u64             revision;
+               efi_status_t    (__efiapi *open_volume)(efi_simple_file_system_protocol_t *,
+                                                       efi_file_protocol_t **);
+       };
+       struct {
+               u64 revision;
+               u32 open_volume;
+       } mixed_mode;
 };
 
 #define EFI_FILE_MODE_READ     0x0000000000000001
index 20d3530ca9c57d2f37aee4e62c38e31d86108478..d6a025df07dcf9efd02ec503427c7072bfb7292f 100644 (file)
@@ -51,17 +51,18 @@ static efi_status_t efi_open_file(efi_file_protocol_t *volume,
                        *c = L'\\';
        }
 
-       status = volume->open(volume, &fh, fi->filename, EFI_FILE_MODE_READ, 0);
+       status = efi_call_proto(volume, open, &fh, fi->filename,
+                               EFI_FILE_MODE_READ, 0);
        if (status != EFI_SUCCESS) {
                efi_err("Failed to open file: %ls\n", fi->filename);
                return status;
        }
 
        info_sz = sizeof(struct finfo);
-       status = fh->get_info(fh, &info_guid, &info_sz, fi);
+       status = efi_call_proto(fh, get_info, &info_guid, &info_sz, fi);
        if (status != EFI_SUCCESS) {
                efi_err("Failed to get file info\n");
-               fh->close(fh);
+               efi_call_proto(fh, close);
                return status;
        }
 
@@ -77,14 +78,14 @@ static efi_status_t efi_open_volume(efi_loaded_image_t *image,
        efi_simple_file_system_protocol_t *io;
        efi_status_t status;
 
-       status = efi_bs_call(handle_protocol, image->device_handle, &fs_proto,
-                            (void **)&io);
+       status = efi_bs_call(handle_protocol, efi_table_attr(image, device_handle),
+                            &fs_proto, (void **)&io);
        if (status != EFI_SUCCESS) {
                efi_err("Failed to handle fs_proto\n");
                return status;
        }
 
-       status = io->open_volume(io, fh);
+       status = efi_call_proto(io, open_volume, fh);
        if (status != EFI_SUCCESS)
                efi_err("Failed to open volume\n");
 
@@ -144,7 +145,8 @@ static efi_status_t efi_open_device_path(efi_file_protocol_t **volume,
 
 
        /* Convert the filename wide string into a device path */
-       initrd_dp = text_to_dp->convert_text_to_device_path(fi->filename);
+       initrd_dp = efi_fn_call(text_to_dp, convert_text_to_device_path,
+                               fi->filename);
 
        /* Check whether the device path in question implements simple FS */
        if ((efi_bs_call(locate_device_path, &fs_proto, &initrd_dp, &handle) ?:
@@ -166,7 +168,7 @@ static efi_status_t efi_open_device_path(efi_file_protocol_t **volume,
               min(sizeof(fi->filename),
                   fpath->header.length - sizeof(fpath->header)));
 
-       status = io->open_volume(io, volume);
+       status = efi_call_proto(io, open_volume, volume);
        if (status != EFI_SUCCESS)
                efi_err("Failed to open volume\n");
 
@@ -187,8 +189,8 @@ efi_status_t handle_cmdline_files(efi_loaded_image_t *image,
                                  unsigned long *load_addr,
                                  unsigned long *load_size)
 {
-       const efi_char16_t *cmdline = image->load_options;
-       u32 cmdline_len = image->load_options_size;
+       const efi_char16_t *cmdline = efi_table_attr(image, load_options);
+       u32 cmdline_len = efi_table_attr(image, load_options_size);
        unsigned long efi_chunk_size = ULONG_MAX;
        efi_file_protocol_t *volume = NULL;
        efi_file_protocol_t *file;
@@ -276,7 +278,7 @@ efi_status_t handle_cmdline_files(efi_loaded_image_t *image,
                while (size) {
                        unsigned long chunksize = min(size, efi_chunk_size);
 
-                       status = file->read(file, &chunksize, addr);
+                       status = efi_call_proto(file, read, &chunksize, addr);
                        if (status != EFI_SUCCESS) {
                                efi_err("Failed to read file\n");
                                goto err_close_file;
@@ -284,8 +286,8 @@ efi_status_t handle_cmdline_files(efi_loaded_image_t *image,
                        addr += chunksize;
                        size -= chunksize;
                }
-               file->close(file);
-               volume->close(volume);
+               efi_call_proto(file, close);
+               efi_call_proto(volume, close);
        } while (offset > 0);
 
        *load_addr = alloc_addr;
@@ -296,10 +298,10 @@ efi_status_t handle_cmdline_files(efi_loaded_image_t *image,
        return EFI_SUCCESS;
 
 err_close_file:
-       file->close(file);
+       efi_call_proto(file, close);
 
 err_close_volume:
-       volume->close(volume);
+       efi_call_proto(volume, close);
 
 err_free_alloc:
        efi_free(alloc_size, alloc_addr);