mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-01 08:04:22 +08:00
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>
This commit is contained in:
parent
a61962d8e7
commit
f8a31244d7
@ -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
|
||||
|
@ -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,
|
||||
|
@ -595,36 +595,63 @@ typedef struct {
|
||||
efi_char16_t filename[];
|
||||
} efi_file_info_t;
|
||||
|
||||
typedef struct efi_file_protocol efi_file_protocol_t;
|
||||
typedef union 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 *);
|
||||
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;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user