Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.15-rc4 564 lines 13 kB view raw
1/* 2 * Helper functions used by the EFI stub on multiple 3 * architectures. This should be #included by the EFI stub 4 * implementation files. 5 * 6 * Copyright 2011 Intel Corporation; author Matt Fleming 7 * 8 * This file is part of the Linux kernel, and is made available 9 * under the terms of the GNU General Public License version 2. 10 * 11 */ 12#define EFI_READ_CHUNK_SIZE (1024 * 1024) 13 14struct file_info { 15 efi_file_handle_t *handle; 16 u64 size; 17}; 18 19static void efi_printk(efi_system_table_t *sys_table_arg, char *str) 20{ 21 char *s8; 22 23 for (s8 = str; *s8; s8++) { 24 efi_char16_t ch[2] = { 0 }; 25 26 ch[0] = *s8; 27 if (*s8 == '\n') { 28 efi_char16_t nl[2] = { '\r', 0 }; 29 efi_char16_printk(sys_table_arg, nl); 30 } 31 32 efi_char16_printk(sys_table_arg, ch); 33 } 34} 35 36 37static efi_status_t efi_get_memory_map(efi_system_table_t *sys_table_arg, 38 efi_memory_desc_t **map, 39 unsigned long *map_size, 40 unsigned long *desc_size, 41 u32 *desc_ver, 42 unsigned long *key_ptr) 43{ 44 efi_memory_desc_t *m = NULL; 45 efi_status_t status; 46 unsigned long key; 47 u32 desc_version; 48 49 *map_size = sizeof(*m) * 32; 50again: 51 /* 52 * Add an additional efi_memory_desc_t because we're doing an 53 * allocation which may be in a new descriptor region. 54 */ 55 *map_size += sizeof(*m); 56 status = efi_call_early(allocate_pool, EFI_LOADER_DATA, 57 *map_size, (void **)&m); 58 if (status != EFI_SUCCESS) 59 goto fail; 60 61 *desc_size = 0; 62 key = 0; 63 status = efi_call_early(get_memory_map, map_size, m, 64 &key, desc_size, &desc_version); 65 if (status == EFI_BUFFER_TOO_SMALL) { 66 efi_call_early(free_pool, m); 67 goto again; 68 } 69 70 if (status != EFI_SUCCESS) 71 efi_call_early(free_pool, m); 72 73 if (key_ptr && status == EFI_SUCCESS) 74 *key_ptr = key; 75 if (desc_ver && status == EFI_SUCCESS) 76 *desc_ver = desc_version; 77 78fail: 79 *map = m; 80 return status; 81} 82 83/* 84 * Allocate at the highest possible address that is not above 'max'. 85 */ 86static efi_status_t efi_high_alloc(efi_system_table_t *sys_table_arg, 87 unsigned long size, unsigned long align, 88 unsigned long *addr, unsigned long max) 89{ 90 unsigned long map_size, desc_size; 91 efi_memory_desc_t *map; 92 efi_status_t status; 93 unsigned long nr_pages; 94 u64 max_addr = 0; 95 int i; 96 97 status = efi_get_memory_map(sys_table_arg, &map, &map_size, &desc_size, 98 NULL, NULL); 99 if (status != EFI_SUCCESS) 100 goto fail; 101 102 /* 103 * Enforce minimum alignment that EFI requires when requesting 104 * a specific address. We are doing page-based allocations, 105 * so we must be aligned to a page. 106 */ 107 if (align < EFI_PAGE_SIZE) 108 align = EFI_PAGE_SIZE; 109 110 nr_pages = round_up(size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE; 111again: 112 for (i = 0; i < map_size / desc_size; i++) { 113 efi_memory_desc_t *desc; 114 unsigned long m = (unsigned long)map; 115 u64 start, end; 116 117 desc = (efi_memory_desc_t *)(m + (i * desc_size)); 118 if (desc->type != EFI_CONVENTIONAL_MEMORY) 119 continue; 120 121 if (desc->num_pages < nr_pages) 122 continue; 123 124 start = desc->phys_addr; 125 end = start + desc->num_pages * (1UL << EFI_PAGE_SHIFT); 126 127 if ((start + size) > end || (start + size) > max) 128 continue; 129 130 if (end - size > max) 131 end = max; 132 133 if (round_down(end - size, align) < start) 134 continue; 135 136 start = round_down(end - size, align); 137 138 /* 139 * Don't allocate at 0x0. It will confuse code that 140 * checks pointers against NULL. 141 */ 142 if (start == 0x0) 143 continue; 144 145 if (start > max_addr) 146 max_addr = start; 147 } 148 149 if (!max_addr) 150 status = EFI_NOT_FOUND; 151 else { 152 status = efi_call_early(allocate_pages, 153 EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA, 154 nr_pages, &max_addr); 155 if (status != EFI_SUCCESS) { 156 max = max_addr; 157 max_addr = 0; 158 goto again; 159 } 160 161 *addr = max_addr; 162 } 163 164 efi_call_early(free_pool, map); 165fail: 166 return status; 167} 168 169/* 170 * Allocate at the lowest possible address. 171 */ 172static efi_status_t efi_low_alloc(efi_system_table_t *sys_table_arg, 173 unsigned long size, unsigned long align, 174 unsigned long *addr) 175{ 176 unsigned long map_size, desc_size; 177 efi_memory_desc_t *map; 178 efi_status_t status; 179 unsigned long nr_pages; 180 int i; 181 182 status = efi_get_memory_map(sys_table_arg, &map, &map_size, &desc_size, 183 NULL, NULL); 184 if (status != EFI_SUCCESS) 185 goto fail; 186 187 /* 188 * Enforce minimum alignment that EFI requires when requesting 189 * a specific address. We are doing page-based allocations, 190 * so we must be aligned to a page. 191 */ 192 if (align < EFI_PAGE_SIZE) 193 align = EFI_PAGE_SIZE; 194 195 nr_pages = round_up(size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE; 196 for (i = 0; i < map_size / desc_size; i++) { 197 efi_memory_desc_t *desc; 198 unsigned long m = (unsigned long)map; 199 u64 start, end; 200 201 desc = (efi_memory_desc_t *)(m + (i * desc_size)); 202 203 if (desc->type != EFI_CONVENTIONAL_MEMORY) 204 continue; 205 206 if (desc->num_pages < nr_pages) 207 continue; 208 209 start = desc->phys_addr; 210 end = start + desc->num_pages * (1UL << EFI_PAGE_SHIFT); 211 212 /* 213 * Don't allocate at 0x0. It will confuse code that 214 * checks pointers against NULL. Skip the first 8 215 * bytes so we start at a nice even number. 216 */ 217 if (start == 0x0) 218 start += 8; 219 220 start = round_up(start, align); 221 if ((start + size) > end) 222 continue; 223 224 status = efi_call_early(allocate_pages, 225 EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA, 226 nr_pages, &start); 227 if (status == EFI_SUCCESS) { 228 *addr = start; 229 break; 230 } 231 } 232 233 if (i == map_size / desc_size) 234 status = EFI_NOT_FOUND; 235 236 efi_call_early(free_pool, map); 237fail: 238 return status; 239} 240 241static void efi_free(efi_system_table_t *sys_table_arg, unsigned long size, 242 unsigned long addr) 243{ 244 unsigned long nr_pages; 245 246 if (!size) 247 return; 248 249 nr_pages = round_up(size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE; 250 efi_call_early(free_pages, addr, nr_pages); 251} 252 253 254/* 255 * Check the cmdline for a LILO-style file= arguments. 256 * 257 * We only support loading a file from the same filesystem as 258 * the kernel image. 259 */ 260static efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg, 261 efi_loaded_image_t *image, 262 char *cmd_line, char *option_string, 263 unsigned long max_addr, 264 unsigned long *load_addr, 265 unsigned long *load_size) 266{ 267 struct file_info *files; 268 unsigned long file_addr; 269 u64 file_size_total; 270 efi_file_handle_t *fh; 271 efi_status_t status; 272 int nr_files; 273 char *str; 274 int i, j, k; 275 276 file_addr = 0; 277 file_size_total = 0; 278 279 str = cmd_line; 280 281 j = 0; /* See close_handles */ 282 283 if (!load_addr || !load_size) 284 return EFI_INVALID_PARAMETER; 285 286 *load_addr = 0; 287 *load_size = 0; 288 289 if (!str || !*str) 290 return EFI_SUCCESS; 291 292 for (nr_files = 0; *str; nr_files++) { 293 str = strstr(str, option_string); 294 if (!str) 295 break; 296 297 str += strlen(option_string); 298 299 /* Skip any leading slashes */ 300 while (*str == '/' || *str == '\\') 301 str++; 302 303 while (*str && *str != ' ' && *str != '\n') 304 str++; 305 } 306 307 if (!nr_files) 308 return EFI_SUCCESS; 309 310 status = efi_call_early(allocate_pool, EFI_LOADER_DATA, 311 nr_files * sizeof(*files), (void **)&files); 312 if (status != EFI_SUCCESS) { 313 efi_printk(sys_table_arg, "Failed to alloc mem for file handle list\n"); 314 goto fail; 315 } 316 317 str = cmd_line; 318 for (i = 0; i < nr_files; i++) { 319 struct file_info *file; 320 efi_char16_t filename_16[256]; 321 efi_char16_t *p; 322 323 str = strstr(str, option_string); 324 if (!str) 325 break; 326 327 str += strlen(option_string); 328 329 file = &files[i]; 330 p = filename_16; 331 332 /* Skip any leading slashes */ 333 while (*str == '/' || *str == '\\') 334 str++; 335 336 while (*str && *str != ' ' && *str != '\n') { 337 if ((u8 *)p >= (u8 *)filename_16 + sizeof(filename_16)) 338 break; 339 340 if (*str == '/') { 341 *p++ = '\\'; 342 str++; 343 } else { 344 *p++ = *str++; 345 } 346 } 347 348 *p = '\0'; 349 350 /* Only open the volume once. */ 351 if (!i) { 352 status = efi_open_volume(sys_table_arg, image, 353 (void **)&fh); 354 if (status != EFI_SUCCESS) 355 goto free_files; 356 } 357 358 status = efi_file_size(sys_table_arg, fh, filename_16, 359 (void **)&file->handle, &file->size); 360 if (status != EFI_SUCCESS) 361 goto close_handles; 362 363 file_size_total += file->size; 364 } 365 366 if (file_size_total) { 367 unsigned long addr; 368 369 /* 370 * Multiple files need to be at consecutive addresses in memory, 371 * so allocate enough memory for all the files. This is used 372 * for loading multiple files. 373 */ 374 status = efi_high_alloc(sys_table_arg, file_size_total, 0x1000, 375 &file_addr, max_addr); 376 if (status != EFI_SUCCESS) { 377 efi_printk(sys_table_arg, "Failed to alloc highmem for files\n"); 378 goto close_handles; 379 } 380 381 /* We've run out of free low memory. */ 382 if (file_addr > max_addr) { 383 efi_printk(sys_table_arg, "We've run out of free low memory\n"); 384 status = EFI_INVALID_PARAMETER; 385 goto free_file_total; 386 } 387 388 addr = file_addr; 389 for (j = 0; j < nr_files; j++) { 390 unsigned long size; 391 392 size = files[j].size; 393 while (size) { 394 unsigned long chunksize; 395 if (size > EFI_READ_CHUNK_SIZE) 396 chunksize = EFI_READ_CHUNK_SIZE; 397 else 398 chunksize = size; 399 400 status = efi_file_read(files[j].handle, 401 &chunksize, 402 (void *)addr); 403 if (status != EFI_SUCCESS) { 404 efi_printk(sys_table_arg, "Failed to read file\n"); 405 goto free_file_total; 406 } 407 addr += chunksize; 408 size -= chunksize; 409 } 410 411 efi_file_close(files[j].handle); 412 } 413 414 } 415 416 efi_call_early(free_pool, files); 417 418 *load_addr = file_addr; 419 *load_size = file_size_total; 420 421 return status; 422 423free_file_total: 424 efi_free(sys_table_arg, file_size_total, file_addr); 425 426close_handles: 427 for (k = j; k < i; k++) 428 efi_file_close(files[k].handle); 429free_files: 430 efi_call_early(free_pool, files); 431fail: 432 *load_addr = 0; 433 *load_size = 0; 434 435 return status; 436} 437/* 438 * Relocate a kernel image, either compressed or uncompressed. 439 * In the ARM64 case, all kernel images are currently 440 * uncompressed, and as such when we relocate it we need to 441 * allocate additional space for the BSS segment. Any low 442 * memory that this function should avoid needs to be 443 * unavailable in the EFI memory map, as if the preferred 444 * address is not available the lowest available address will 445 * be used. 446 */ 447static efi_status_t efi_relocate_kernel(efi_system_table_t *sys_table_arg, 448 unsigned long *image_addr, 449 unsigned long image_size, 450 unsigned long alloc_size, 451 unsigned long preferred_addr, 452 unsigned long alignment) 453{ 454 unsigned long cur_image_addr; 455 unsigned long new_addr = 0; 456 efi_status_t status; 457 unsigned long nr_pages; 458 efi_physical_addr_t efi_addr = preferred_addr; 459 460 if (!image_addr || !image_size || !alloc_size) 461 return EFI_INVALID_PARAMETER; 462 if (alloc_size < image_size) 463 return EFI_INVALID_PARAMETER; 464 465 cur_image_addr = *image_addr; 466 467 /* 468 * The EFI firmware loader could have placed the kernel image 469 * anywhere in memory, but the kernel has restrictions on the 470 * max physical address it can run at. Some architectures 471 * also have a prefered address, so first try to relocate 472 * to the preferred address. If that fails, allocate as low 473 * as possible while respecting the required alignment. 474 */ 475 nr_pages = round_up(alloc_size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE; 476 status = efi_call_early(allocate_pages, 477 EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA, 478 nr_pages, &efi_addr); 479 new_addr = efi_addr; 480 /* 481 * If preferred address allocation failed allocate as low as 482 * possible. 483 */ 484 if (status != EFI_SUCCESS) { 485 status = efi_low_alloc(sys_table_arg, alloc_size, alignment, 486 &new_addr); 487 } 488 if (status != EFI_SUCCESS) { 489 efi_printk(sys_table_arg, "ERROR: Failed to allocate usable memory for kernel.\n"); 490 return status; 491 } 492 493 /* 494 * We know source/dest won't overlap since both memory ranges 495 * have been allocated by UEFI, so we can safely use memcpy. 496 */ 497 memcpy((void *)new_addr, (void *)cur_image_addr, image_size); 498 499 /* Return the new address of the relocated image. */ 500 *image_addr = new_addr; 501 502 return status; 503} 504 505/* 506 * Convert the unicode UEFI command line to ASCII to pass to kernel. 507 * Size of memory allocated return in *cmd_line_len. 508 * Returns NULL on error. 509 */ 510static char *efi_convert_cmdline_to_ascii(efi_system_table_t *sys_table_arg, 511 efi_loaded_image_t *image, 512 int *cmd_line_len) 513{ 514 u16 *s2; 515 u8 *s1 = NULL; 516 unsigned long cmdline_addr = 0; 517 int load_options_size = image->load_options_size / 2; /* ASCII */ 518 void *options = image->load_options; 519 int options_size = 0; 520 efi_status_t status; 521 int i; 522 u16 zero = 0; 523 524 if (options) { 525 s2 = options; 526 while (*s2 && *s2 != '\n' && options_size < load_options_size) { 527 s2++; 528 options_size++; 529 } 530 } 531 532 if (options_size == 0) { 533 /* No command line options, so return empty string*/ 534 options_size = 1; 535 options = &zero; 536 } 537 538 options_size++; /* NUL termination */ 539#ifdef CONFIG_ARM 540 /* 541 * For ARM, allocate at a high address to avoid reserved 542 * regions at low addresses that we don't know the specfics of 543 * at the time we are processing the command line. 544 */ 545 status = efi_high_alloc(sys_table_arg, options_size, 0, 546 &cmdline_addr, 0xfffff000); 547#else 548 status = efi_low_alloc(sys_table_arg, options_size, 0, 549 &cmdline_addr); 550#endif 551 if (status != EFI_SUCCESS) 552 return NULL; 553 554 s1 = (u8 *)cmdline_addr; 555 s2 = (u16 *)options; 556 557 for (i = 0; i < options_size - 1; i++) 558 *s1++ = *s2++; 559 560 *s1 = '\0'; 561 562 *cmd_line_len = options_size; 563 return (char *)cmdline_addr; 564}