Commit c160d2f5ec9298d545a6e0fab0a68cc1a3e93759
Committed by
Alexander Graf
1 parent
a095aadffa
Exists in
smarc_8mq_lf_v2020.04
and in
17 other branches
efi_loader: add checking for incorrect use of EFI_ENTRY/EXIT
Missing an EFI_ENTRY() or doubling up EFI_EXIT() leads to non-obvious crashes. Let's add some error checking. Signed-off-by: Rob Clark <robdclark@gmail.com> [agraf: fix bogus assert() and fix app_gd breakage] Signed-off-by: Alexander Graf <agraf@suse.de>
Showing 2 changed files with 41 additions and 21 deletions Side-by-side Diff
include/efi_loader.h
... | ... | @@ -15,11 +15,14 @@ |
15 | 15 | |
16 | 16 | #include <linux/list.h> |
17 | 17 | |
18 | +int __efi_entry_check(void); | |
19 | +int __efi_exit_check(void); | |
20 | + | |
18 | 21 | /* |
19 | 22 | * Enter the u-boot world from UEFI: |
20 | 23 | */ |
21 | 24 | #define EFI_ENTRY(format, ...) do { \ |
22 | - efi_restore_gd(); \ | |
25 | + assert(__efi_entry_check()); \ | |
23 | 26 | debug("EFI: Entry %s(" format ")\n", __func__, ##__VA_ARGS__); \ |
24 | 27 | } while(0) |
25 | 28 | |
... | ... | @@ -29,7 +32,8 @@ |
29 | 32 | #define EFI_EXIT(ret) ({ \ |
30 | 33 | efi_status_t _r = ret; \ |
31 | 34 | debug("EFI: Exit: %s: %u\n", __func__, (u32)(_r & ~EFI_ERROR_MASK)); \ |
32 | - efi_exit_func(_r); \ | |
35 | + assert(__efi_exit_check()); \ | |
36 | + _r; \ | |
33 | 37 | }) |
34 | 38 | |
35 | 39 | /* |
36 | 40 | |
... | ... | @@ -37,9 +41,9 @@ |
37 | 41 | */ |
38 | 42 | #define EFI_CALL(exp) do { \ |
39 | 43 | debug("EFI: Call: %s\n", #exp); \ |
40 | - efi_exit_func(EFI_SUCCESS); \ | |
44 | + assert(__efi_exit_check()); \ | |
41 | 45 | exp; \ |
42 | - efi_restore_gd(); \ | |
46 | + assert(__efi_entry_check()); \ | |
43 | 47 | debug("EFI: Return From: %s\n", #exp); \ |
44 | 48 | } while(0) |
45 | 49 | |
46 | 50 | |
... | ... | @@ -139,10 +143,9 @@ |
139 | 143 | void *efi_load_pe(void *efi, struct efi_loaded_image *loaded_image_info); |
140 | 144 | /* Called once to store the pristine gd pointer */ |
141 | 145 | void efi_save_gd(void); |
142 | -/* Called from EFI_ENTRY on callback entry to put gd into the gd register */ | |
146 | +/* Special case handler for error/abort that just tries to dtrt to get | |
147 | + * back to u-boot world */ | |
143 | 148 | void efi_restore_gd(void); |
144 | -/* Called from EFI_EXIT on callback exit to restore the gd register */ | |
145 | -efi_status_t efi_exit_func(efi_status_t ret); | |
146 | 149 | /* Call this to relocate the runtime section to an address space */ |
147 | 150 | void efi_runtime_relocate(ulong offset, struct efi_mem_desc *map); |
148 | 151 | /* Call this to set the current device name */ |
lib/efi_loader/efi_boottime.c
... | ... | @@ -49,6 +49,30 @@ |
49 | 49 | static volatile void *efi_gd, *app_gd; |
50 | 50 | #endif |
51 | 51 | |
52 | +static int entry_count; | |
53 | + | |
54 | +/* Called on every callback entry */ | |
55 | +int __efi_entry_check(void) | |
56 | +{ | |
57 | + int ret = entry_count++ == 0; | |
58 | +#ifdef CONFIG_ARM | |
59 | + assert(efi_gd); | |
60 | + app_gd = gd; | |
61 | + gd = efi_gd; | |
62 | +#endif | |
63 | + return ret; | |
64 | +} | |
65 | + | |
66 | +/* Called on every callback exit */ | |
67 | +int __efi_exit_check(void) | |
68 | +{ | |
69 | + int ret = --entry_count == 0; | |
70 | +#ifdef CONFIG_ARM | |
71 | + gd = app_gd; | |
72 | +#endif | |
73 | + return ret; | |
74 | +} | |
75 | + | |
52 | 76 | /* Called from do_bootefi_exec() */ |
53 | 77 | void efi_save_gd(void) |
54 | 78 | { |
55 | 79 | |
56 | 80 | |
... | ... | @@ -57,30 +81,21 @@ |
57 | 81 | #endif |
58 | 82 | } |
59 | 83 | |
60 | -/* Called on every callback entry */ | |
84 | +/* | |
85 | + * Special case handler for error/abort that just forces things back | |
86 | + * to u-boot world so we can dump out an abort msg, without any care | |
87 | + * about returning back to UEFI world. | |
88 | + */ | |
61 | 89 | void efi_restore_gd(void) |
62 | 90 | { |
63 | 91 | #ifdef CONFIG_ARM |
64 | 92 | /* Only restore if we're already in EFI context */ |
65 | 93 | if (!efi_gd) |
66 | 94 | return; |
67 | - | |
68 | - if (gd != efi_gd) | |
69 | - app_gd = gd; | |
70 | 95 | gd = efi_gd; |
71 | 96 | #endif |
72 | 97 | } |
73 | 98 | |
74 | -/* Called on every callback exit */ | |
75 | -efi_status_t efi_exit_func(efi_status_t ret) | |
76 | -{ | |
77 | -#ifdef CONFIG_ARM | |
78 | - gd = app_gd; | |
79 | -#endif | |
80 | - | |
81 | - return ret; | |
82 | -} | |
83 | - | |
84 | 99 | /* Low 32 bit */ |
85 | 100 | #define EFI_LOW32(a) (a & 0xFFFFFFFFULL) |
86 | 101 | /* High 32 bit */ |
87 | 102 | |
... | ... | @@ -733,7 +748,9 @@ |
733 | 748 | return EFI_EXIT(info->exit_status); |
734 | 749 | } |
735 | 750 | |
751 | + __efi_exit_check(); | |
736 | 752 | entry(image_handle, &systab); |
753 | + __efi_entry_check(); | |
737 | 754 | |
738 | 755 | /* Should usually never get here */ |
739 | 756 | return EFI_EXIT(EFI_SUCCESS); |