0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/efi.h>
0011 #include <asm/efi.h>
0012
0013 #include "efistub.h"
0014
0015 #define MAX_FILENAME_SIZE 256
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030 #define EFI_READ_CHUNK_SIZE SZ_1M
0031
0032 struct finfo {
0033 efi_file_info_t info;
0034 efi_char16_t filename[MAX_FILENAME_SIZE];
0035 };
0036
0037 static efi_status_t efi_open_file(efi_file_protocol_t *volume,
0038 struct finfo *fi,
0039 efi_file_protocol_t **handle,
0040 unsigned long *file_size)
0041 {
0042 efi_guid_t info_guid = EFI_FILE_INFO_ID;
0043 efi_file_protocol_t *fh;
0044 unsigned long info_sz;
0045 efi_status_t status;
0046
0047 status = volume->open(volume, &fh, fi->filename, EFI_FILE_MODE_READ, 0);
0048 if (status != EFI_SUCCESS) {
0049 efi_err("Failed to open file: %ls\n", fi->filename);
0050 return status;
0051 }
0052
0053 info_sz = sizeof(struct finfo);
0054 status = fh->get_info(fh, &info_guid, &info_sz, fi);
0055 if (status != EFI_SUCCESS) {
0056 efi_err("Failed to get file info\n");
0057 fh->close(fh);
0058 return status;
0059 }
0060
0061 *handle = fh;
0062 *file_size = fi->info.file_size;
0063 return EFI_SUCCESS;
0064 }
0065
0066 static efi_status_t efi_open_volume(efi_loaded_image_t *image,
0067 efi_file_protocol_t **fh)
0068 {
0069 efi_guid_t fs_proto = EFI_FILE_SYSTEM_GUID;
0070 efi_simple_file_system_protocol_t *io;
0071 efi_status_t status;
0072
0073 status = efi_bs_call(handle_protocol, image->device_handle, &fs_proto,
0074 (void **)&io);
0075 if (status != EFI_SUCCESS) {
0076 efi_err("Failed to handle fs_proto\n");
0077 return status;
0078 }
0079
0080 status = io->open_volume(io, fh);
0081 if (status != EFI_SUCCESS)
0082 efi_err("Failed to open volume\n");
0083
0084 return status;
0085 }
0086
0087 static int find_file_option(const efi_char16_t *cmdline, int cmdline_len,
0088 const efi_char16_t *prefix, int prefix_size,
0089 efi_char16_t *result, int result_len)
0090 {
0091 int prefix_len = prefix_size / 2;
0092 bool found = false;
0093 int i;
0094
0095 for (i = prefix_len; i < cmdline_len; i++) {
0096 if (!memcmp(&cmdline[i - prefix_len], prefix, prefix_size)) {
0097 found = true;
0098 break;
0099 }
0100 }
0101
0102 if (!found)
0103 return 0;
0104
0105
0106 while (i < cmdline_len && (cmdline[i] == L'/' || cmdline[i] == L'\\'))
0107 i++;
0108
0109 while (--result_len > 0 && i < cmdline_len) {
0110 efi_char16_t c = cmdline[i++];
0111
0112 if (c == L'\0' || c == L'\n' || c == L' ')
0113 break;
0114 else if (c == L'/')
0115
0116 *result++ = L'\\';
0117 else
0118 *result++ = c;
0119 }
0120 *result = L'\0';
0121 return i;
0122 }
0123
0124
0125
0126
0127
0128
0129
0130 efi_status_t handle_cmdline_files(efi_loaded_image_t *image,
0131 const efi_char16_t *optstr,
0132 int optstr_size,
0133 unsigned long soft_limit,
0134 unsigned long hard_limit,
0135 unsigned long *load_addr,
0136 unsigned long *load_size)
0137 {
0138 const efi_char16_t *cmdline = image->load_options;
0139 int cmdline_len = image->load_options_size;
0140 unsigned long efi_chunk_size = ULONG_MAX;
0141 efi_file_protocol_t *volume = NULL;
0142 efi_file_protocol_t *file;
0143 unsigned long alloc_addr;
0144 unsigned long alloc_size;
0145 efi_status_t status;
0146 int offset;
0147
0148 if (!load_addr || !load_size)
0149 return EFI_INVALID_PARAMETER;
0150
0151 efi_apply_loadoptions_quirk((const void **)&cmdline, &cmdline_len);
0152 cmdline_len /= sizeof(*cmdline);
0153
0154 if (IS_ENABLED(CONFIG_X86) && !efi_nochunk)
0155 efi_chunk_size = EFI_READ_CHUNK_SIZE;
0156
0157 alloc_addr = alloc_size = 0;
0158 do {
0159 struct finfo fi;
0160 unsigned long size;
0161 void *addr;
0162
0163 offset = find_file_option(cmdline, cmdline_len,
0164 optstr, optstr_size,
0165 fi.filename, ARRAY_SIZE(fi.filename));
0166
0167 if (!offset)
0168 break;
0169
0170 cmdline += offset;
0171 cmdline_len -= offset;
0172
0173 if (!volume) {
0174 status = efi_open_volume(image, &volume);
0175 if (status != EFI_SUCCESS)
0176 return status;
0177 }
0178
0179 status = efi_open_file(volume, &fi, &file, &size);
0180 if (status != EFI_SUCCESS)
0181 goto err_close_volume;
0182
0183
0184
0185
0186
0187
0188
0189 if (round_up(alloc_size + size, EFI_ALLOC_ALIGN) >
0190 round_up(alloc_size, EFI_ALLOC_ALIGN)) {
0191 unsigned long old_addr = alloc_addr;
0192
0193 status = EFI_OUT_OF_RESOURCES;
0194 if (soft_limit < hard_limit)
0195 status = efi_allocate_pages(alloc_size + size,
0196 &alloc_addr,
0197 soft_limit);
0198 if (status == EFI_OUT_OF_RESOURCES)
0199 status = efi_allocate_pages(alloc_size + size,
0200 &alloc_addr,
0201 hard_limit);
0202 if (status != EFI_SUCCESS) {
0203 efi_err("Failed to allocate memory for files\n");
0204 goto err_close_file;
0205 }
0206
0207 if (old_addr != 0) {
0208
0209
0210
0211
0212
0213
0214 memcpy((void *)alloc_addr, (void *)old_addr, alloc_size);
0215 efi_free(alloc_size, old_addr);
0216 }
0217 }
0218
0219 addr = (void *)alloc_addr + alloc_size;
0220 alloc_size += size;
0221
0222 while (size) {
0223 unsigned long chunksize = min(size, efi_chunk_size);
0224
0225 status = file->read(file, &chunksize, addr);
0226 if (status != EFI_SUCCESS) {
0227 efi_err("Failed to read file\n");
0228 goto err_close_file;
0229 }
0230 addr += chunksize;
0231 size -= chunksize;
0232 }
0233 file->close(file);
0234 } while (offset > 0);
0235
0236 *load_addr = alloc_addr;
0237 *load_size = alloc_size;
0238
0239 if (volume)
0240 volume->close(volume);
0241 return EFI_SUCCESS;
0242
0243 err_close_file:
0244 file->close(file);
0245
0246 err_close_volume:
0247 volume->close(volume);
0248 efi_free(alloc_size, alloc_addr);
0249 return status;
0250 }