1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Helper functions used by the EFI stub on multiple 4 * architectures. This should be #included by the EFI stub 5 * implementation files. 6 * 7 * Copyright 2011 Intel Corporation; author Matt Fleming 8 */ 9 10 #include <linux/efi.h> 11 #include <asm/efi.h> 12 13 #include "efistub.h" 14 15 /* 16 * Some firmware implementations have problems reading files in one go. 17 * A read chunk size of 1MB seems to work for most platforms. 18 * 19 * Unfortunately, reading files in chunks triggers *other* bugs on some 20 * platforms, so we provide a way to disable this workaround, which can 21 * be done by passing "efi=nochunk" on the EFI boot stub command line. 22 * 23 * If you experience issues with initrd images being corrupt it's worth 24 * trying efi=nochunk, but chunking is enabled by default on x86 because 25 * there are far more machines that require the workaround than those that 26 * break with it enabled. 27 */ 28 #define EFI_READ_CHUNK_SIZE SZ_1M 29 30 struct file_info { 31 efi_file_protocol_t *handle; 32 u64 size; 33 }; 34 35 static efi_status_t efi_file_size(void *__fh, efi_char16_t *filename_16, 36 void **handle, u64 *file_sz) 37 { 38 efi_file_protocol_t *h, *fh = __fh; 39 efi_file_info_t *info; 40 efi_status_t status; 41 efi_guid_t info_guid = EFI_FILE_INFO_ID; 42 unsigned long info_sz; 43 44 status = fh->open(fh, &h, filename_16, EFI_FILE_MODE_READ, 0); 45 if (status != EFI_SUCCESS) { 46 efi_printk("Failed to open file: "); 47 efi_char16_printk(filename_16); 48 efi_printk("\n"); 49 return status; 50 } 51 52 *handle = h; 53 54 info_sz = 0; 55 status = h->get_info(h, &info_guid, &info_sz, NULL); 56 if (status != EFI_BUFFER_TOO_SMALL) { 57 efi_printk("Failed to get file info size\n"); 58 return status; 59 } 60 61 grow: 62 status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, info_sz, 63 (void **)&info); 64 if (status != EFI_SUCCESS) { 65 efi_printk("Failed to alloc mem for file info\n"); 66 return status; 67 } 68 69 status = h->get_info(h, &info_guid, &info_sz, info); 70 if (status == EFI_BUFFER_TOO_SMALL) { 71 efi_bs_call(free_pool, info); 72 goto grow; 73 } 74 75 *file_sz = info->file_size; 76 efi_bs_call(free_pool, info); 77 78 if (status != EFI_SUCCESS) 79 efi_printk("Failed to get initrd info\n"); 80 81 return status; 82 } 83 84 static efi_status_t efi_file_read(efi_file_protocol_t *handle, 85 unsigned long *size, void *addr) 86 { 87 return handle->read(handle, size, addr); 88 } 89 90 static efi_status_t efi_file_close(efi_file_protocol_t *handle) 91 { 92 return handle->close(handle); 93 } 94 95 static efi_status_t efi_open_volume(efi_loaded_image_t *image, 96 efi_file_protocol_t **__fh) 97 { 98 efi_simple_file_system_protocol_t *io; 99 efi_file_protocol_t *fh; 100 efi_guid_t fs_proto = EFI_FILE_SYSTEM_GUID; 101 efi_status_t status; 102 efi_handle_t handle = image->device_handle; 103 104 status = efi_bs_call(handle_protocol, handle, &fs_proto, (void **)&io); 105 if (status != EFI_SUCCESS) { 106 efi_printk("Failed to handle fs_proto\n"); 107 return status; 108 } 109 110 status = io->open_volume(io, &fh); 111 if (status != EFI_SUCCESS) 112 efi_printk("Failed to open volume\n"); 113 else 114 *__fh = fh; 115 116 return status; 117 } 118 119 /* 120 * Check the cmdline for a LILO-style file= arguments. 121 * 122 * We only support loading a file from the same filesystem as 123 * the kernel image. 124 */ 125 efi_status_t handle_cmdline_files(efi_loaded_image_t *image, 126 char *cmd_line, char *option_string, 127 unsigned long max_addr, 128 unsigned long *load_addr, 129 unsigned long *load_size) 130 { 131 unsigned long efi_chunk_size = ULONG_MAX; 132 struct file_info *files; 133 unsigned long file_addr; 134 u64 file_size_total; 135 efi_file_protocol_t *fh = NULL; 136 efi_status_t status; 137 int nr_files; 138 char *str; 139 int i, j, k; 140 141 if (IS_ENABLED(CONFIG_X86) && !nochunk()) 142 efi_chunk_size = EFI_READ_CHUNK_SIZE; 143 144 file_addr = 0; 145 file_size_total = 0; 146 147 str = cmd_line; 148 149 j = 0; /* See close_handles */ 150 151 if (!load_addr || !load_size) 152 return EFI_INVALID_PARAMETER; 153 154 *load_addr = 0; 155 *load_size = 0; 156 157 if (!str || !*str) 158 return EFI_SUCCESS; 159 160 for (nr_files = 0; *str; nr_files++) { 161 str = strstr(str, option_string); 162 if (!str) 163 break; 164 165 str += strlen(option_string); 166 167 /* Skip any leading slashes */ 168 while (*str == '/' || *str == '\\') 169 str++; 170 171 while (*str && *str != ' ' && *str != '\n') 172 str++; 173 } 174 175 if (!nr_files) 176 return EFI_SUCCESS; 177 178 status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, 179 nr_files * sizeof(*files), (void **)&files); 180 if (status != EFI_SUCCESS) { 181 pr_efi_err("Failed to alloc mem for file handle list\n"); 182 goto fail; 183 } 184 185 str = cmd_line; 186 for (i = 0; i < nr_files; i++) { 187 struct file_info *file; 188 efi_char16_t filename_16[256]; 189 efi_char16_t *p; 190 191 str = strstr(str, option_string); 192 if (!str) 193 break; 194 195 str += strlen(option_string); 196 197 file = &files[i]; 198 p = filename_16; 199 200 /* Skip any leading slashes */ 201 while (*str == '/' || *str == '\\') 202 str++; 203 204 while (*str && *str != ' ' && *str != '\n') { 205 if ((u8 *)p >= (u8 *)filename_16 + sizeof(filename_16)) 206 break; 207 208 if (*str == '/') { 209 *p++ = '\\'; 210 str++; 211 } else { 212 *p++ = *str++; 213 } 214 } 215 216 *p = '\0'; 217 218 /* Only open the volume once. */ 219 if (!i) { 220 status = efi_open_volume(image, &fh); 221 if (status != EFI_SUCCESS) 222 goto free_files; 223 } 224 225 status = efi_file_size(fh, filename_16, (void **)&file->handle, 226 &file->size); 227 if (status != EFI_SUCCESS) 228 goto close_handles; 229 230 file_size_total += file->size; 231 } 232 233 if (file_size_total) { 234 unsigned long addr; 235 236 /* 237 * Multiple files need to be at consecutive addresses in memory, 238 * so allocate enough memory for all the files. This is used 239 * for loading multiple files. 240 */ 241 status = efi_allocate_pages(file_size_total, &file_addr, max_addr); 242 if (status != EFI_SUCCESS) { 243 pr_efi_err("Failed to alloc highmem for files\n"); 244 goto close_handles; 245 } 246 247 /* We've run out of free low memory. */ 248 if (file_addr > max_addr) { 249 pr_efi_err("We've run out of free low memory\n"); 250 status = EFI_INVALID_PARAMETER; 251 goto free_file_total; 252 } 253 254 addr = file_addr; 255 for (j = 0; j < nr_files; j++) { 256 unsigned long size; 257 258 size = files[j].size; 259 while (size) { 260 unsigned long chunksize; 261 262 if (size > efi_chunk_size) 263 chunksize = efi_chunk_size; 264 else 265 chunksize = size; 266 267 status = efi_file_read(files[j].handle, 268 &chunksize, 269 (void *)addr); 270 if (status != EFI_SUCCESS) { 271 pr_efi_err("Failed to read file\n"); 272 goto free_file_total; 273 } 274 addr += chunksize; 275 size -= chunksize; 276 } 277 278 efi_file_close(files[j].handle); 279 } 280 281 } 282 283 efi_bs_call(free_pool, files); 284 285 *load_addr = file_addr; 286 *load_size = file_size_total; 287 288 return status; 289 290 free_file_total: 291 efi_free(file_size_total, file_addr); 292 293 close_handles: 294 for (k = j; k < i; k++) 295 efi_file_close(files[k].handle); 296 free_files: 297 efi_bs_call(free_pool, files); 298 fail: 299 *load_addr = 0; 300 *load_size = 0; 301 302 return status; 303 } 304