aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/firmware/efi/efi-stub-helper.c
diff options
context:
space:
mode:
authorMatt Fleming <matt.fleming@intel.com>2014-01-10 10:27:14 -0500
committerMatt Fleming <matt.fleming@intel.com>2014-03-04 16:25:03 -0500
commit54b52d87268034859191d671505bb1cfce6bd74d (patch)
tree63c39b9a828e9d6dad97118cbd2e1e1210da6358 /drivers/firmware/efi/efi-stub-helper.c
parent677703cef0a148ba07d37ced649ad25b1cda2f78 (diff)
x86/efi: Build our own EFI services pointer table
It's not possible to dereference the EFI System table directly when booting a 64-bit kernel on a 32-bit EFI firmware because the size of pointers don't match. In preparation for supporting the above use case, build a list of function pointers on boot so that callers don't have to worry about converting pointer sizes through multiple levels of indirection. Signed-off-by: Matt Fleming <matt.fleming@intel.com>
Diffstat (limited to 'drivers/firmware/efi/efi-stub-helper.c')
-rw-r--r--drivers/firmware/efi/efi-stub-helper.c148
1 files changed, 38 insertions, 110 deletions
diff --git a/drivers/firmware/efi/efi-stub-helper.c b/drivers/firmware/efi/efi-stub-helper.c
index b6bffbfd3be7..a0282872d97d 100644
--- a/drivers/firmware/efi/efi-stub-helper.c
+++ b/drivers/firmware/efi/efi-stub-helper.c
@@ -16,18 +16,6 @@ struct file_info {
16 u64 size; 16 u64 size;
17}; 17};
18 18
19
20
21
22static void efi_char16_printk(efi_system_table_t *sys_table_arg,
23 efi_char16_t *str)
24{
25 struct efi_simple_text_output_protocol *out;
26
27 out = (struct efi_simple_text_output_protocol *)sys_table_arg->con_out;
28 efi_call_phys2(out->output_string, out, str);
29}
30
31static void efi_printk(efi_system_table_t *sys_table_arg, char *str) 19static void efi_printk(efi_system_table_t *sys_table_arg, char *str)
32{ 20{
33 char *s8; 21 char *s8;
@@ -65,20 +53,23 @@ again:
65 * allocation which may be in a new descriptor region. 53 * allocation which may be in a new descriptor region.
66 */ 54 */
67 *map_size += sizeof(*m); 55 *map_size += sizeof(*m);
68 status = efi_call_phys3(sys_table_arg->boottime->allocate_pool, 56 status = efi_early->call(efi_early->allocate_pool, EFI_LOADER_DATA,
69 EFI_LOADER_DATA, *map_size, (void **)&m); 57 *map_size, (void **)&m);
70 if (status != EFI_SUCCESS) 58 if (status != EFI_SUCCESS)
71 goto fail; 59 goto fail;
72 60
73 status = efi_call_phys5(sys_table_arg->boottime->get_memory_map, 61 *desc_size = 0;
74 map_size, m, &key, desc_size, &desc_version); 62 key = 0;
63 status = efi_early->call(efi_early->get_memory_map, map_size, m,
64 &key, desc_size, &desc_version);
75 if (status == EFI_BUFFER_TOO_SMALL) { 65 if (status == EFI_BUFFER_TOO_SMALL) {
76 efi_call_phys1(sys_table_arg->boottime->free_pool, m); 66 efi_early->call(efi_early->free_pool, m);
77 goto again; 67 goto again;
78 } 68 }
79 69
80 if (status != EFI_SUCCESS) 70 if (status != EFI_SUCCESS)
81 efi_call_phys1(sys_table_arg->boottime->free_pool, m); 71 efi_early->call(efi_early->free_pool, m);
72
82 if (key_ptr && status == EFI_SUCCESS) 73 if (key_ptr && status == EFI_SUCCESS)
83 *key_ptr = key; 74 *key_ptr = key;
84 if (desc_ver && status == EFI_SUCCESS) 75 if (desc_ver && status == EFI_SUCCESS)
@@ -158,9 +149,9 @@ again:
158 if (!max_addr) 149 if (!max_addr)
159 status = EFI_NOT_FOUND; 150 status = EFI_NOT_FOUND;
160 else { 151 else {
161 status = efi_call_phys4(sys_table_arg->boottime->allocate_pages, 152 status = efi_early->call(efi_early->allocate_pages,
162 EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA, 153 EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA,
163 nr_pages, &max_addr); 154 nr_pages, &max_addr);
164 if (status != EFI_SUCCESS) { 155 if (status != EFI_SUCCESS) {
165 max = max_addr; 156 max = max_addr;
166 max_addr = 0; 157 max_addr = 0;
@@ -170,8 +161,7 @@ again:
170 *addr = max_addr; 161 *addr = max_addr;
171 } 162 }
172 163
173 efi_call_phys1(sys_table_arg->boottime->free_pool, map); 164 efi_early->call(efi_early->free_pool, map);
174
175fail: 165fail:
176 return status; 166 return status;
177} 167}
@@ -231,9 +221,9 @@ static efi_status_t efi_low_alloc(efi_system_table_t *sys_table_arg,
231 if ((start + size) > end) 221 if ((start + size) > end)
232 continue; 222 continue;
233 223
234 status = efi_call_phys4(sys_table_arg->boottime->allocate_pages, 224 status = efi_early->call(efi_early->allocate_pages,
235 EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA, 225 EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA,
236 nr_pages, &start); 226 nr_pages, &start);
237 if (status == EFI_SUCCESS) { 227 if (status == EFI_SUCCESS) {
238 *addr = start; 228 *addr = start;
239 break; 229 break;
@@ -243,7 +233,7 @@ static efi_status_t efi_low_alloc(efi_system_table_t *sys_table_arg,
243 if (i == map_size / desc_size) 233 if (i == map_size / desc_size)
244 status = EFI_NOT_FOUND; 234 status = EFI_NOT_FOUND;
245 235
246 efi_call_phys1(sys_table_arg->boottime->free_pool, map); 236 efi_early->call(efi_early->free_pool, map);
247fail: 237fail:
248 return status; 238 return status;
249} 239}
@@ -257,7 +247,7 @@ static void efi_free(efi_system_table_t *sys_table_arg, unsigned long size,
257 return; 247 return;
258 248
259 nr_pages = round_up(size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE; 249 nr_pages = round_up(size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE;
260 efi_call_phys2(sys_table_arg->boottime->free_pages, addr, nr_pages); 250 efi_early->call(efi_early->free_pages, addr, nr_pages);
261} 251}
262 252
263 253
@@ -276,9 +266,7 @@ static efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg,
276{ 266{
277 struct file_info *files; 267 struct file_info *files;
278 unsigned long file_addr; 268 unsigned long file_addr;
279 efi_guid_t fs_proto = EFI_FILE_SYSTEM_GUID;
280 u64 file_size_total; 269 u64 file_size_total;
281 efi_file_io_interface_t *io;
282 efi_file_handle_t *fh; 270 efi_file_handle_t *fh;
283 efi_status_t status; 271 efi_status_t status;
284 int nr_files; 272 int nr_files;
@@ -319,10 +307,8 @@ static efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg,
319 if (!nr_files) 307 if (!nr_files)
320 return EFI_SUCCESS; 308 return EFI_SUCCESS;
321 309
322 status = efi_call_phys3(sys_table_arg->boottime->allocate_pool, 310 status = efi_early->call(efi_early->allocate_pool, EFI_LOADER_DATA,
323 EFI_LOADER_DATA, 311 nr_files * sizeof(*files), (void **)&files);
324 nr_files * sizeof(*files),
325 (void **)&files);
326 if (status != EFI_SUCCESS) { 312 if (status != EFI_SUCCESS) {
327 efi_printk(sys_table_arg, "Failed to alloc mem for file handle list\n"); 313 efi_printk(sys_table_arg, "Failed to alloc mem for file handle list\n");
328 goto fail; 314 goto fail;
@@ -331,13 +317,8 @@ static efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg,
331 str = cmd_line; 317 str = cmd_line;
332 for (i = 0; i < nr_files; i++) { 318 for (i = 0; i < nr_files; i++) {
333 struct file_info *file; 319 struct file_info *file;
334 efi_file_handle_t *h;
335 efi_file_info_t *info;
336 efi_char16_t filename_16[256]; 320 efi_char16_t filename_16[256];
337 unsigned long info_sz;
338 efi_guid_t info_guid = EFI_FILE_INFO_ID;
339 efi_char16_t *p; 321 efi_char16_t *p;
340 u64 file_sz;
341 322
342 str = strstr(str, option_string); 323 str = strstr(str, option_string);
343 if (!str) 324 if (!str)
@@ -368,71 +349,18 @@ static efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg,
368 349
369 /* Only open the volume once. */ 350 /* Only open the volume once. */
370 if (!i) { 351 if (!i) {
371 efi_boot_services_t *boottime; 352 status = efi_open_volume(sys_table_arg, image,
372 353 (void **)&fh);
373 boottime = sys_table_arg->boottime; 354 if (status != EFI_SUCCESS)
374
375 status = efi_call_phys3(boottime->handle_protocol,
376 image->device_handle, &fs_proto,
377 (void **)&io);
378 if (status != EFI_SUCCESS) {
379 efi_printk(sys_table_arg, "Failed to handle fs_proto\n");
380 goto free_files;
381 }
382
383 status = efi_call_phys2(io->open_volume, io, &fh);
384 if (status != EFI_SUCCESS) {
385 efi_printk(sys_table_arg, "Failed to open volume\n");
386 goto free_files; 355 goto free_files;
387 }
388 } 356 }
389 357
390 status = efi_call_phys5(fh->open, fh, &h, filename_16, 358 status = efi_file_size(sys_table_arg, fh, filename_16,
391 EFI_FILE_MODE_READ, (u64)0); 359 (void **)&file->handle, &file->size);
392 if (status != EFI_SUCCESS) { 360 if (status != EFI_SUCCESS)
393 efi_printk(sys_table_arg, "Failed to open file: ");
394 efi_char16_printk(sys_table_arg, filename_16);
395 efi_printk(sys_table_arg, "\n");
396 goto close_handles; 361 goto close_handles;
397 }
398 362
399 file->handle = h; 363 file_size_total += file->size;
400
401 info_sz = 0;
402 status = efi_call_phys4(h->get_info, h, &info_guid,
403 &info_sz, NULL);
404 if (status != EFI_BUFFER_TOO_SMALL) {
405 efi_printk(sys_table_arg, "Failed to get file info size\n");
406 goto close_handles;
407 }
408
409grow:
410 status = efi_call_phys3(sys_table_arg->boottime->allocate_pool,
411 EFI_LOADER_DATA, info_sz,
412 (void **)&info);
413 if (status != EFI_SUCCESS) {
414 efi_printk(sys_table_arg, "Failed to alloc mem for file info\n");
415 goto close_handles;
416 }
417
418 status = efi_call_phys4(h->get_info, h, &info_guid,
419 &info_sz, info);
420 if (status == EFI_BUFFER_TOO_SMALL) {
421 efi_call_phys1(sys_table_arg->boottime->free_pool,
422 info);
423 goto grow;
424 }
425
426 file_sz = info->file_size;
427 efi_call_phys1(sys_table_arg->boottime->free_pool, info);
428
429 if (status != EFI_SUCCESS) {
430 efi_printk(sys_table_arg, "Failed to get file info\n");
431 goto close_handles;
432 }
433
434 file->size = file_sz;
435 file_size_total += file_sz;
436 } 364 }
437 365
438 if (file_size_total) { 366 if (file_size_total) {
@@ -468,10 +396,10 @@ grow:
468 chunksize = EFI_READ_CHUNK_SIZE; 396 chunksize = EFI_READ_CHUNK_SIZE;
469 else 397 else
470 chunksize = size; 398 chunksize = size;
471 status = efi_call_phys3(fh->read, 399
472 files[j].handle, 400 status = efi_file_read(fh, files[j].handle,
473 &chunksize, 401 &chunksize,
474 (void *)addr); 402 (void *)addr);
475 if (status != EFI_SUCCESS) { 403 if (status != EFI_SUCCESS) {
476 efi_printk(sys_table_arg, "Failed to read file\n"); 404 efi_printk(sys_table_arg, "Failed to read file\n");
477 goto free_file_total; 405 goto free_file_total;
@@ -480,12 +408,12 @@ grow:
480 size -= chunksize; 408 size -= chunksize;
481 } 409 }
482 410
483 efi_call_phys1(fh->close, files[j].handle); 411 efi_file_close(fh, files[j].handle);
484 } 412 }
485 413
486 } 414 }
487 415
488 efi_call_phys1(sys_table_arg->boottime->free_pool, files); 416 efi_early->call(efi_early->free_pool, files);
489 417
490 *load_addr = file_addr; 418 *load_addr = file_addr;
491 *load_size = file_size_total; 419 *load_size = file_size_total;
@@ -497,9 +425,9 @@ free_file_total:
497 425
498close_handles: 426close_handles:
499 for (k = j; k < i; k++) 427 for (k = j; k < i; k++)
500 efi_call_phys1(fh->close, files[k].handle); 428 efi_file_close(fh, files[k].handle);
501free_files: 429free_files:
502 efi_call_phys1(sys_table_arg->boottime->free_pool, files); 430 efi_early->call(efi_early->free_pool, files);
503fail: 431fail:
504 *load_addr = 0; 432 *load_addr = 0;
505 *load_size = 0; 433 *load_size = 0;
@@ -545,9 +473,9 @@ static efi_status_t efi_relocate_kernel(efi_system_table_t *sys_table_arg,
545 * as possible while respecting the required alignment. 473 * as possible while respecting the required alignment.
546 */ 474 */
547 nr_pages = round_up(alloc_size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE; 475 nr_pages = round_up(alloc_size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE;
548 status = efi_call_phys4(sys_table_arg->boottime->allocate_pages, 476 status = efi_early->call(efi_early->allocate_pages,
549 EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA, 477 EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA,
550 nr_pages, &efi_addr); 478 nr_pages, &efi_addr);
551 new_addr = efi_addr; 479 new_addr = efi_addr;
552 /* 480 /*
553 * If preferred address allocation failed allocate as low as 481 * If preferred address allocation failed allocate as low as