@@ -325,6 +325,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
@@ -682,7 +682,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,
@@ -593,36 +593,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
@@ -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;
}
@@ -73,7 +74,7 @@ static efi_status_t efi_open_file(efi_file_protocol_t *volume,
static efi_status_t efi_open_volume(efi_loaded_image_t *image,
efi_file_protocol_t **fh)
{
- struct efi_vendor_dev_path *dp = image->file_path;
+ struct efi_vendor_dev_path *dp = efi_table_attr(image, file_path);
efi_guid_t li_proto = LOADED_IMAGE_PROTOCOL_GUID;
efi_guid_t fs_proto = EFI_FILE_SYSTEM_GUID;
efi_simple_file_system_protocol_t *io;
@@ -95,14 +96,14 @@ static efi_status_t efi_open_volume(efi_loaded_image_t *image,
}
}
- 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");
@@ -162,7 +163,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) ?:
@@ -184,7 +186,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");
@@ -205,8 +207,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;
@@ -294,7 +296,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;
@@ -302,8 +304,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;
@@ -312,10 +314,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);
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 | 11 +++ drivers/firmware/efi/libstub/efi-stub-helper.c | 2 +- drivers/firmware/efi/libstub/efistub.h | 81 +++++++++++++------- drivers/firmware/efi/libstub/file.c | 34 ++++---- 4 files changed, 84 insertions(+), 44 deletions(-)