diff options
author | Matt Fleming <matt.fleming@intel.com> | 2014-01-10 10:27:14 -0500 |
---|---|---|
committer | Matt Fleming <matt.fleming@intel.com> | 2014-03-04 16:25:03 -0500 |
commit | 54b52d87268034859191d671505bb1cfce6bd74d (patch) | |
tree | 63c39b9a828e9d6dad97118cbd2e1e1210da6358 /drivers/firmware/efi/efi-stub-helper.c | |
parent | 677703cef0a148ba07d37ced649ad25b1cda2f78 (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.c | 148 |
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 | |||
22 | static 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 | |||
31 | static void efi_printk(efi_system_table_t *sys_table_arg, char *str) | 19 | static 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 | |||
175 | fail: | 165 | fail: |
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); |
247 | fail: | 237 | fail: |
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 | |||
409 | grow: | ||
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 | ||
498 | close_handles: | 426 | close_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); |
501 | free_files: | 429 | free_files: |
502 | efi_call_phys1(sys_table_arg->boottime->free_pool, files); | 430 | efi_early->call(efi_early->free_pool, files); |
503 | fail: | 431 | fail: |
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 |