summaryrefslogtreecommitdiffstats
path: root/drivers/firmware
diff options
context:
space:
mode:
authorArd Biesheuvel <ardb@kernel.org>2022-09-26 22:17:21 +0200
committerArd Biesheuvel <ardb@kernel.org>2022-11-18 09:14:08 +0100
commitf8a31244d73288bd623a0247512f6c0b81844a92 (patch)
tree6c8e8f4246417672cdcf65406de12157f040715b /drivers/firmware
parenta61962d8e7d3f11f68cbaebd477fbd8e1f7b9f6d (diff)
downloadlinux-stable-f8a31244d73288bd623a0247512f6c0b81844a92.tar.gz
linux-stable-f8a31244d73288bd623a0247512f6c0b81844a92.tar.bz2
linux-stable-f8a31244d73288bd623a0247512f6c0b81844a92.zip
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>
Diffstat (limited to 'drivers/firmware')
-rw-r--r--drivers/firmware/efi/libstub/efi-stub-helper.c2
-rw-r--r--drivers/firmware/efi/libstub/efistub.h81
-rw-r--r--drivers/firmware/efi/libstub/file.c32
3 files changed, 72 insertions, 43 deletions
diff --git a/drivers/firmware/efi/libstub/efi-stub-helper.c b/drivers/firmware/efi/libstub/efi-stub-helper.c
index 2184f3f153ef..01680b11d46d 100644
--- a/drivers/firmware/efi/libstub/efi-stub-helper.c
+++ b/drivers/firmware/efi/libstub/efi-stub-helper.c
@@ -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,
diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h
index 8bb11fb309c3..5615ad6f2958 100644
--- a/drivers/firmware/efi/libstub/efistub.h
+++ b/drivers/firmware/efi/libstub/efistub.h
@@ -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
diff --git a/drivers/firmware/efi/libstub/file.c b/drivers/firmware/efi/libstub/file.c
index 20d3530ca9c5..d6a025df07dc 100644
--- a/drivers/firmware/efi/libstub/file.c
+++ b/drivers/firmware/efi/libstub/file.c
@@ -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);