diff options
Diffstat (limited to 'drivers/firmware')
-rw-r--r-- | drivers/firmware/efi/efi.c | 79 | ||||
-rw-r--r-- | drivers/firmware/efi/libstub/arm-stub.c | 4 | ||||
-rw-r--r-- | drivers/firmware/efi/libstub/efi-stub-helper.c | 62 | ||||
-rw-r--r-- | drivers/firmware/efi/runtime-wrappers.c | 164 | ||||
-rw-r--r-- | drivers/firmware/efi/vars.c | 61 |
5 files changed, 351 insertions, 19 deletions
diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index 64ecbb501c50..8590099ac148 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c | |||
@@ -41,6 +41,28 @@ struct efi __read_mostly efi = { | |||
41 | }; | 41 | }; |
42 | EXPORT_SYMBOL(efi); | 42 | EXPORT_SYMBOL(efi); |
43 | 43 | ||
44 | static bool disable_runtime; | ||
45 | static int __init setup_noefi(char *arg) | ||
46 | { | ||
47 | disable_runtime = true; | ||
48 | return 0; | ||
49 | } | ||
50 | early_param("noefi", setup_noefi); | ||
51 | |||
52 | bool efi_runtime_disabled(void) | ||
53 | { | ||
54 | return disable_runtime; | ||
55 | } | ||
56 | |||
57 | static int __init parse_efi_cmdline(char *str) | ||
58 | { | ||
59 | if (parse_option_str(str, "noruntime")) | ||
60 | disable_runtime = true; | ||
61 | |||
62 | return 0; | ||
63 | } | ||
64 | early_param("efi", parse_efi_cmdline); | ||
65 | |||
44 | static struct kobject *efi_kobj; | 66 | static struct kobject *efi_kobj; |
45 | static struct kobject *efivars_kobj; | 67 | static struct kobject *efivars_kobj; |
46 | 68 | ||
@@ -423,3 +445,60 @@ int __init efi_get_fdt_params(struct efi_fdt_params *params, int verbose) | |||
423 | return ret; | 445 | return ret; |
424 | } | 446 | } |
425 | #endif /* CONFIG_EFI_PARAMS_FROM_FDT */ | 447 | #endif /* CONFIG_EFI_PARAMS_FROM_FDT */ |
448 | |||
449 | static __initdata char memory_type_name[][20] = { | ||
450 | "Reserved", | ||
451 | "Loader Code", | ||
452 | "Loader Data", | ||
453 | "Boot Code", | ||
454 | "Boot Data", | ||
455 | "Runtime Code", | ||
456 | "Runtime Data", | ||
457 | "Conventional Memory", | ||
458 | "Unusable Memory", | ||
459 | "ACPI Reclaim Memory", | ||
460 | "ACPI Memory NVS", | ||
461 | "Memory Mapped I/O", | ||
462 | "MMIO Port Space", | ||
463 | "PAL Code" | ||
464 | }; | ||
465 | |||
466 | char * __init efi_md_typeattr_format(char *buf, size_t size, | ||
467 | const efi_memory_desc_t *md) | ||
468 | { | ||
469 | char *pos; | ||
470 | int type_len; | ||
471 | u64 attr; | ||
472 | |||
473 | pos = buf; | ||
474 | if (md->type >= ARRAY_SIZE(memory_type_name)) | ||
475 | type_len = snprintf(pos, size, "[type=%u", md->type); | ||
476 | else | ||
477 | type_len = snprintf(pos, size, "[%-*s", | ||
478 | (int)(sizeof(memory_type_name[0]) - 1), | ||
479 | memory_type_name[md->type]); | ||
480 | if (type_len >= size) | ||
481 | return buf; | ||
482 | |||
483 | pos += type_len; | ||
484 | size -= type_len; | ||
485 | |||
486 | attr = md->attribute; | ||
487 | if (attr & ~(EFI_MEMORY_UC | EFI_MEMORY_WC | EFI_MEMORY_WT | | ||
488 | EFI_MEMORY_WB | EFI_MEMORY_UCE | EFI_MEMORY_WP | | ||
489 | EFI_MEMORY_RP | EFI_MEMORY_XP | EFI_MEMORY_RUNTIME)) | ||
490 | snprintf(pos, size, "|attr=0x%016llx]", | ||
491 | (unsigned long long)attr); | ||
492 | else | ||
493 | snprintf(pos, size, "|%3s|%2s|%2s|%2s|%3s|%2s|%2s|%2s|%2s]", | ||
494 | attr & EFI_MEMORY_RUNTIME ? "RUN" : "", | ||
495 | attr & EFI_MEMORY_XP ? "XP" : "", | ||
496 | attr & EFI_MEMORY_RP ? "RP" : "", | ||
497 | attr & EFI_MEMORY_WP ? "WP" : "", | ||
498 | attr & EFI_MEMORY_UCE ? "UCE" : "", | ||
499 | attr & EFI_MEMORY_WB ? "WB" : "", | ||
500 | attr & EFI_MEMORY_WT ? "WT" : "", | ||
501 | attr & EFI_MEMORY_WC ? "WC" : "", | ||
502 | attr & EFI_MEMORY_UC ? "UC" : ""); | ||
503 | return buf; | ||
504 | } | ||
diff --git a/drivers/firmware/efi/libstub/arm-stub.c b/drivers/firmware/efi/libstub/arm-stub.c index 480339b6b110..75ee05964cbc 100644 --- a/drivers/firmware/efi/libstub/arm-stub.c +++ b/drivers/firmware/efi/libstub/arm-stub.c | |||
@@ -226,6 +226,10 @@ unsigned long __init efi_entry(void *handle, efi_system_table_t *sys_table, | |||
226 | goto fail_free_image; | 226 | goto fail_free_image; |
227 | } | 227 | } |
228 | 228 | ||
229 | status = efi_parse_options(cmdline_ptr); | ||
230 | if (status != EFI_SUCCESS) | ||
231 | pr_efi_err(sys_table, "Failed to parse EFI cmdline options\n"); | ||
232 | |||
229 | /* | 233 | /* |
230 | * Unauthenticated device tree data is a security hazard, so | 234 | * Unauthenticated device tree data is a security hazard, so |
231 | * ignore 'dtb=' unless UEFI Secure Boot is disabled. | 235 | * ignore 'dtb=' unless UEFI Secure Boot is disabled. |
diff --git a/drivers/firmware/efi/libstub/efi-stub-helper.c b/drivers/firmware/efi/libstub/efi-stub-helper.c index 32d5cca30f49..a920fec8fe88 100644 --- a/drivers/firmware/efi/libstub/efi-stub-helper.c +++ b/drivers/firmware/efi/libstub/efi-stub-helper.c | |||
@@ -15,8 +15,23 @@ | |||
15 | 15 | ||
16 | #include "efistub.h" | 16 | #include "efistub.h" |
17 | 17 | ||
18 | /* | ||
19 | * Some firmware implementations have problems reading files in one go. | ||
20 | * A read chunk size of 1MB seems to work for most platforms. | ||
21 | * | ||
22 | * Unfortunately, reading files in chunks triggers *other* bugs on some | ||
23 | * platforms, so we provide a way to disable this workaround, which can | ||
24 | * be done by passing "efi=nochunk" on the EFI boot stub command line. | ||
25 | * | ||
26 | * If you experience issues with initrd images being corrupt it's worth | ||
27 | * trying efi=nochunk, but chunking is enabled by default because there | ||
28 | * are far more machines that require the workaround than those that | ||
29 | * break with it enabled. | ||
30 | */ | ||
18 | #define EFI_READ_CHUNK_SIZE (1024 * 1024) | 31 | #define EFI_READ_CHUNK_SIZE (1024 * 1024) |
19 | 32 | ||
33 | static unsigned long __chunk_size = EFI_READ_CHUNK_SIZE; | ||
34 | |||
20 | struct file_info { | 35 | struct file_info { |
21 | efi_file_handle_t *handle; | 36 | efi_file_handle_t *handle; |
22 | u64 size; | 37 | u64 size; |
@@ -281,6 +296,49 @@ void efi_free(efi_system_table_t *sys_table_arg, unsigned long size, | |||
281 | efi_call_early(free_pages, addr, nr_pages); | 296 | efi_call_early(free_pages, addr, nr_pages); |
282 | } | 297 | } |
283 | 298 | ||
299 | /* | ||
300 | * Parse the ASCII string 'cmdline' for EFI options, denoted by the efi= | ||
301 | * option, e.g. efi=nochunk. | ||
302 | * | ||
303 | * It should be noted that efi= is parsed in two very different | ||
304 | * environments, first in the early boot environment of the EFI boot | ||
305 | * stub, and subsequently during the kernel boot. | ||
306 | */ | ||
307 | efi_status_t efi_parse_options(char *cmdline) | ||
308 | { | ||
309 | char *str; | ||
310 | |||
311 | /* | ||
312 | * If no EFI parameters were specified on the cmdline we've got | ||
313 | * nothing to do. | ||
314 | */ | ||
315 | str = strstr(cmdline, "efi="); | ||
316 | if (!str) | ||
317 | return EFI_SUCCESS; | ||
318 | |||
319 | /* Skip ahead to first argument */ | ||
320 | str += strlen("efi="); | ||
321 | |||
322 | /* | ||
323 | * Remember, because efi= is also used by the kernel we need to | ||
324 | * skip over arguments we don't understand. | ||
325 | */ | ||
326 | while (*str) { | ||
327 | if (!strncmp(str, "nochunk", 7)) { | ||
328 | str += strlen("nochunk"); | ||
329 | __chunk_size = -1UL; | ||
330 | } | ||
331 | |||
332 | /* Group words together, delimited by "," */ | ||
333 | while (*str && *str != ',') | ||
334 | str++; | ||
335 | |||
336 | if (*str == ',') | ||
337 | str++; | ||
338 | } | ||
339 | |||
340 | return EFI_SUCCESS; | ||
341 | } | ||
284 | 342 | ||
285 | /* | 343 | /* |
286 | * Check the cmdline for a LILO-style file= arguments. | 344 | * Check the cmdline for a LILO-style file= arguments. |
@@ -423,8 +481,8 @@ efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg, | |||
423 | size = files[j].size; | 481 | size = files[j].size; |
424 | while (size) { | 482 | while (size) { |
425 | unsigned long chunksize; | 483 | unsigned long chunksize; |
426 | if (size > EFI_READ_CHUNK_SIZE) | 484 | if (size > __chunk_size) |
427 | chunksize = EFI_READ_CHUNK_SIZE; | 485 | chunksize = __chunk_size; |
428 | else | 486 | else |
429 | chunksize = size; | 487 | chunksize = size; |
430 | 488 | ||
diff --git a/drivers/firmware/efi/runtime-wrappers.c b/drivers/firmware/efi/runtime-wrappers.c index 10daa4bbb258..228bbf910461 100644 --- a/drivers/firmware/efi/runtime-wrappers.c +++ b/drivers/firmware/efi/runtime-wrappers.c | |||
@@ -14,11 +14,80 @@ | |||
14 | * This file is released under the GPLv2. | 14 | * This file is released under the GPLv2. |
15 | */ | 15 | */ |
16 | 16 | ||
17 | #include <linux/bug.h> | ||
17 | #include <linux/efi.h> | 18 | #include <linux/efi.h> |
18 | #include <linux/spinlock.h> /* spinlock_t */ | 19 | #include <linux/mutex.h> |
20 | #include <linux/spinlock.h> | ||
19 | #include <asm/efi.h> | 21 | #include <asm/efi.h> |
20 | 22 | ||
21 | /* | 23 | /* |
24 | * According to section 7.1 of the UEFI spec, Runtime Services are not fully | ||
25 | * reentrant, and there are particular combinations of calls that need to be | ||
26 | * serialized. (source: UEFI Specification v2.4A) | ||
27 | * | ||
28 | * Table 31. Rules for Reentry Into Runtime Services | ||
29 | * +------------------------------------+-------------------------------+ | ||
30 | * | If previous call is busy in | Forbidden to call | | ||
31 | * +------------------------------------+-------------------------------+ | ||
32 | * | Any | SetVirtualAddressMap() | | ||
33 | * +------------------------------------+-------------------------------+ | ||
34 | * | ConvertPointer() | ConvertPointer() | | ||
35 | * +------------------------------------+-------------------------------+ | ||
36 | * | SetVariable() | ResetSystem() | | ||
37 | * | UpdateCapsule() | | | ||
38 | * | SetTime() | | | ||
39 | * | SetWakeupTime() | | | ||
40 | * | GetNextHighMonotonicCount() | | | ||
41 | * +------------------------------------+-------------------------------+ | ||
42 | * | GetVariable() | GetVariable() | | ||
43 | * | GetNextVariableName() | GetNextVariableName() | | ||
44 | * | SetVariable() | SetVariable() | | ||
45 | * | QueryVariableInfo() | QueryVariableInfo() | | ||
46 | * | UpdateCapsule() | UpdateCapsule() | | ||
47 | * | QueryCapsuleCapabilities() | QueryCapsuleCapabilities() | | ||
48 | * | GetNextHighMonotonicCount() | GetNextHighMonotonicCount() | | ||
49 | * +------------------------------------+-------------------------------+ | ||
50 | * | GetTime() | GetTime() | | ||
51 | * | SetTime() | SetTime() | | ||
52 | * | GetWakeupTime() | GetWakeupTime() | | ||
53 | * | SetWakeupTime() | SetWakeupTime() | | ||
54 | * +------------------------------------+-------------------------------+ | ||
55 | * | ||
56 | * Due to the fact that the EFI pstore may write to the variable store in | ||
57 | * interrupt context, we need to use a spinlock for at least the groups that | ||
58 | * contain SetVariable() and QueryVariableInfo(). That leaves little else, as | ||
59 | * none of the remaining functions are actually ever called at runtime. | ||
60 | * So let's just use a single spinlock to serialize all Runtime Services calls. | ||
61 | */ | ||
62 | static DEFINE_SPINLOCK(efi_runtime_lock); | ||
63 | |||
64 | /* | ||
65 | * Some runtime services calls can be reentrant under NMI, even if the table | ||
66 | * above says they are not. (source: UEFI Specification v2.4A) | ||
67 | * | ||
68 | * Table 32. Functions that may be called after Machine Check, INIT and NMI | ||
69 | * +----------------------------+------------------------------------------+ | ||
70 | * | Function | Called after Machine Check, INIT and NMI | | ||
71 | * +----------------------------+------------------------------------------+ | ||
72 | * | GetTime() | Yes, even if previously busy. | | ||
73 | * | GetVariable() | Yes, even if previously busy | | ||
74 | * | GetNextVariableName() | Yes, even if previously busy | | ||
75 | * | QueryVariableInfo() | Yes, even if previously busy | | ||
76 | * | SetVariable() | Yes, even if previously busy | | ||
77 | * | UpdateCapsule() | Yes, even if previously busy | | ||
78 | * | QueryCapsuleCapabilities() | Yes, even if previously busy | | ||
79 | * | ResetSystem() | Yes, even if previously busy | | ||
80 | * +----------------------------+------------------------------------------+ | ||
81 | * | ||
82 | * In order to prevent deadlocks under NMI, the wrappers for these functions | ||
83 | * may only grab the efi_runtime_lock or rtc_lock spinlocks if !efi_in_nmi(). | ||
84 | * However, not all of the services listed are reachable through NMI code paths, | ||
85 | * so the the special handling as suggested by the UEFI spec is only implemented | ||
86 | * for QueryVariableInfo() and SetVariable(), as these can be reached in NMI | ||
87 | * context through efi_pstore_write(). | ||
88 | */ | ||
89 | |||
90 | /* | ||
22 | * As per commit ef68c8f87ed1 ("x86: Serialize EFI time accesses on rtc_lock"), | 91 | * As per commit ef68c8f87ed1 ("x86: Serialize EFI time accesses on rtc_lock"), |
23 | * the EFI specification requires that callers of the time related runtime | 92 | * the EFI specification requires that callers of the time related runtime |
24 | * functions serialize with other CMOS accesses in the kernel, as the EFI time | 93 | * functions serialize with other CMOS accesses in the kernel, as the EFI time |
@@ -32,7 +101,9 @@ static efi_status_t virt_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc) | |||
32 | efi_status_t status; | 101 | efi_status_t status; |
33 | 102 | ||
34 | spin_lock_irqsave(&rtc_lock, flags); | 103 | spin_lock_irqsave(&rtc_lock, flags); |
104 | spin_lock(&efi_runtime_lock); | ||
35 | status = efi_call_virt(get_time, tm, tc); | 105 | status = efi_call_virt(get_time, tm, tc); |
106 | spin_unlock(&efi_runtime_lock); | ||
36 | spin_unlock_irqrestore(&rtc_lock, flags); | 107 | spin_unlock_irqrestore(&rtc_lock, flags); |
37 | return status; | 108 | return status; |
38 | } | 109 | } |
@@ -43,7 +114,9 @@ static efi_status_t virt_efi_set_time(efi_time_t *tm) | |||
43 | efi_status_t status; | 114 | efi_status_t status; |
44 | 115 | ||
45 | spin_lock_irqsave(&rtc_lock, flags); | 116 | spin_lock_irqsave(&rtc_lock, flags); |
117 | spin_lock(&efi_runtime_lock); | ||
46 | status = efi_call_virt(set_time, tm); | 118 | status = efi_call_virt(set_time, tm); |
119 | spin_unlock(&efi_runtime_lock); | ||
47 | spin_unlock_irqrestore(&rtc_lock, flags); | 120 | spin_unlock_irqrestore(&rtc_lock, flags); |
48 | return status; | 121 | return status; |
49 | } | 122 | } |
@@ -56,7 +129,9 @@ static efi_status_t virt_efi_get_wakeup_time(efi_bool_t *enabled, | |||
56 | efi_status_t status; | 129 | efi_status_t status; |
57 | 130 | ||
58 | spin_lock_irqsave(&rtc_lock, flags); | 131 | spin_lock_irqsave(&rtc_lock, flags); |
132 | spin_lock(&efi_runtime_lock); | ||
59 | status = efi_call_virt(get_wakeup_time, enabled, pending, tm); | 133 | status = efi_call_virt(get_wakeup_time, enabled, pending, tm); |
134 | spin_unlock(&efi_runtime_lock); | ||
60 | spin_unlock_irqrestore(&rtc_lock, flags); | 135 | spin_unlock_irqrestore(&rtc_lock, flags); |
61 | return status; | 136 | return status; |
62 | } | 137 | } |
@@ -67,7 +142,9 @@ static efi_status_t virt_efi_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm) | |||
67 | efi_status_t status; | 142 | efi_status_t status; |
68 | 143 | ||
69 | spin_lock_irqsave(&rtc_lock, flags); | 144 | spin_lock_irqsave(&rtc_lock, flags); |
145 | spin_lock(&efi_runtime_lock); | ||
70 | status = efi_call_virt(set_wakeup_time, enabled, tm); | 146 | status = efi_call_virt(set_wakeup_time, enabled, tm); |
147 | spin_unlock(&efi_runtime_lock); | ||
71 | spin_unlock_irqrestore(&rtc_lock, flags); | 148 | spin_unlock_irqrestore(&rtc_lock, flags); |
72 | return status; | 149 | return status; |
73 | } | 150 | } |
@@ -78,14 +155,27 @@ static efi_status_t virt_efi_get_variable(efi_char16_t *name, | |||
78 | unsigned long *data_size, | 155 | unsigned long *data_size, |
79 | void *data) | 156 | void *data) |
80 | { | 157 | { |
81 | return efi_call_virt(get_variable, name, vendor, attr, data_size, data); | 158 | unsigned long flags; |
159 | efi_status_t status; | ||
160 | |||
161 | spin_lock_irqsave(&efi_runtime_lock, flags); | ||
162 | status = efi_call_virt(get_variable, name, vendor, attr, data_size, | ||
163 | data); | ||
164 | spin_unlock_irqrestore(&efi_runtime_lock, flags); | ||
165 | return status; | ||
82 | } | 166 | } |
83 | 167 | ||
84 | static efi_status_t virt_efi_get_next_variable(unsigned long *name_size, | 168 | static efi_status_t virt_efi_get_next_variable(unsigned long *name_size, |
85 | efi_char16_t *name, | 169 | efi_char16_t *name, |
86 | efi_guid_t *vendor) | 170 | efi_guid_t *vendor) |
87 | { | 171 | { |
88 | return efi_call_virt(get_next_variable, name_size, name, vendor); | 172 | unsigned long flags; |
173 | efi_status_t status; | ||
174 | |||
175 | spin_lock_irqsave(&efi_runtime_lock, flags); | ||
176 | status = efi_call_virt(get_next_variable, name_size, name, vendor); | ||
177 | spin_unlock_irqrestore(&efi_runtime_lock, flags); | ||
178 | return status; | ||
89 | } | 179 | } |
90 | 180 | ||
91 | static efi_status_t virt_efi_set_variable(efi_char16_t *name, | 181 | static efi_status_t virt_efi_set_variable(efi_char16_t *name, |
@@ -94,24 +184,61 @@ static efi_status_t virt_efi_set_variable(efi_char16_t *name, | |||
94 | unsigned long data_size, | 184 | unsigned long data_size, |
95 | void *data) | 185 | void *data) |
96 | { | 186 | { |
97 | return efi_call_virt(set_variable, name, vendor, attr, data_size, data); | 187 | unsigned long flags; |
188 | efi_status_t status; | ||
189 | |||
190 | spin_lock_irqsave(&efi_runtime_lock, flags); | ||
191 | status = efi_call_virt(set_variable, name, vendor, attr, data_size, | ||
192 | data); | ||
193 | spin_unlock_irqrestore(&efi_runtime_lock, flags); | ||
194 | return status; | ||
98 | } | 195 | } |
99 | 196 | ||
197 | static efi_status_t | ||
198 | virt_efi_set_variable_nonblocking(efi_char16_t *name, efi_guid_t *vendor, | ||
199 | u32 attr, unsigned long data_size, | ||
200 | void *data) | ||
201 | { | ||
202 | unsigned long flags; | ||
203 | efi_status_t status; | ||
204 | |||
205 | if (!spin_trylock_irqsave(&efi_runtime_lock, flags)) | ||
206 | return EFI_NOT_READY; | ||
207 | |||
208 | status = efi_call_virt(set_variable, name, vendor, attr, data_size, | ||
209 | data); | ||
210 | spin_unlock_irqrestore(&efi_runtime_lock, flags); | ||
211 | return status; | ||
212 | } | ||
213 | |||
214 | |||
100 | static efi_status_t virt_efi_query_variable_info(u32 attr, | 215 | static efi_status_t virt_efi_query_variable_info(u32 attr, |
101 | u64 *storage_space, | 216 | u64 *storage_space, |
102 | u64 *remaining_space, | 217 | u64 *remaining_space, |
103 | u64 *max_variable_size) | 218 | u64 *max_variable_size) |
104 | { | 219 | { |
220 | unsigned long flags; | ||
221 | efi_status_t status; | ||
222 | |||
105 | if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) | 223 | if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) |
106 | return EFI_UNSUPPORTED; | 224 | return EFI_UNSUPPORTED; |
107 | 225 | ||
108 | return efi_call_virt(query_variable_info, attr, storage_space, | 226 | spin_lock_irqsave(&efi_runtime_lock, flags); |
109 | remaining_space, max_variable_size); | 227 | status = efi_call_virt(query_variable_info, attr, storage_space, |
228 | remaining_space, max_variable_size); | ||
229 | spin_unlock_irqrestore(&efi_runtime_lock, flags); | ||
230 | return status; | ||
110 | } | 231 | } |
111 | 232 | ||
112 | static efi_status_t virt_efi_get_next_high_mono_count(u32 *count) | 233 | static efi_status_t virt_efi_get_next_high_mono_count(u32 *count) |
113 | { | 234 | { |
114 | return efi_call_virt(get_next_high_mono_count, count); | 235 | unsigned long flags; |
236 | efi_status_t status; | ||
237 | |||
238 | spin_lock_irqsave(&efi_runtime_lock, flags); | ||
239 | status = efi_call_virt(get_next_high_mono_count, count); | ||
240 | spin_unlock_irqrestore(&efi_runtime_lock, flags); | ||
241 | return status; | ||
115 | } | 242 | } |
116 | 243 | ||
117 | static void virt_efi_reset_system(int reset_type, | 244 | static void virt_efi_reset_system(int reset_type, |
@@ -119,17 +246,27 @@ static void virt_efi_reset_system(int reset_type, | |||
119 | unsigned long data_size, | 246 | unsigned long data_size, |
120 | efi_char16_t *data) | 247 | efi_char16_t *data) |
121 | { | 248 | { |
249 | unsigned long flags; | ||
250 | |||
251 | spin_lock_irqsave(&efi_runtime_lock, flags); | ||
122 | __efi_call_virt(reset_system, reset_type, status, data_size, data); | 252 | __efi_call_virt(reset_system, reset_type, status, data_size, data); |
253 | spin_unlock_irqrestore(&efi_runtime_lock, flags); | ||
123 | } | 254 | } |
124 | 255 | ||
125 | static efi_status_t virt_efi_update_capsule(efi_capsule_header_t **capsules, | 256 | static efi_status_t virt_efi_update_capsule(efi_capsule_header_t **capsules, |
126 | unsigned long count, | 257 | unsigned long count, |
127 | unsigned long sg_list) | 258 | unsigned long sg_list) |
128 | { | 259 | { |
260 | unsigned long flags; | ||
261 | efi_status_t status; | ||
262 | |||
129 | if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) | 263 | if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) |
130 | return EFI_UNSUPPORTED; | 264 | return EFI_UNSUPPORTED; |
131 | 265 | ||
132 | return efi_call_virt(update_capsule, capsules, count, sg_list); | 266 | spin_lock_irqsave(&efi_runtime_lock, flags); |
267 | status = efi_call_virt(update_capsule, capsules, count, sg_list); | ||
268 | spin_unlock_irqrestore(&efi_runtime_lock, flags); | ||
269 | return status; | ||
133 | } | 270 | } |
134 | 271 | ||
135 | static efi_status_t virt_efi_query_capsule_caps(efi_capsule_header_t **capsules, | 272 | static efi_status_t virt_efi_query_capsule_caps(efi_capsule_header_t **capsules, |
@@ -137,11 +274,17 @@ static efi_status_t virt_efi_query_capsule_caps(efi_capsule_header_t **capsules, | |||
137 | u64 *max_size, | 274 | u64 *max_size, |
138 | int *reset_type) | 275 | int *reset_type) |
139 | { | 276 | { |
277 | unsigned long flags; | ||
278 | efi_status_t status; | ||
279 | |||
140 | if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) | 280 | if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) |
141 | return EFI_UNSUPPORTED; | 281 | return EFI_UNSUPPORTED; |
142 | 282 | ||
143 | return efi_call_virt(query_capsule_caps, capsules, count, max_size, | 283 | spin_lock_irqsave(&efi_runtime_lock, flags); |
144 | reset_type); | 284 | status = efi_call_virt(query_capsule_caps, capsules, count, max_size, |
285 | reset_type); | ||
286 | spin_unlock_irqrestore(&efi_runtime_lock, flags); | ||
287 | return status; | ||
145 | } | 288 | } |
146 | 289 | ||
147 | void efi_native_runtime_setup(void) | 290 | void efi_native_runtime_setup(void) |
@@ -153,6 +296,7 @@ void efi_native_runtime_setup(void) | |||
153 | efi.get_variable = virt_efi_get_variable; | 296 | efi.get_variable = virt_efi_get_variable; |
154 | efi.get_next_variable = virt_efi_get_next_variable; | 297 | efi.get_next_variable = virt_efi_get_next_variable; |
155 | efi.set_variable = virt_efi_set_variable; | 298 | efi.set_variable = virt_efi_set_variable; |
299 | efi.set_variable_nonblocking = virt_efi_set_variable_nonblocking; | ||
156 | efi.get_next_high_mono_count = virt_efi_get_next_high_mono_count; | 300 | efi.get_next_high_mono_count = virt_efi_get_next_high_mono_count; |
157 | efi.reset_system = virt_efi_reset_system; | 301 | efi.reset_system = virt_efi_reset_system; |
158 | efi.query_variable_info = virt_efi_query_variable_info; | 302 | efi.query_variable_info = virt_efi_query_variable_info; |
diff --git a/drivers/firmware/efi/vars.c b/drivers/firmware/efi/vars.c index 5abe943e3404..70a0fb10517f 100644 --- a/drivers/firmware/efi/vars.c +++ b/drivers/firmware/efi/vars.c | |||
@@ -321,11 +321,11 @@ static unsigned long var_name_strnsize(efi_char16_t *variable_name, | |||
321 | * Print a warning when duplicate EFI variables are encountered and | 321 | * Print a warning when duplicate EFI variables are encountered and |
322 | * disable the sysfs workqueue since the firmware is buggy. | 322 | * disable the sysfs workqueue since the firmware is buggy. |
323 | */ | 323 | */ |
324 | static void dup_variable_bug(efi_char16_t *s16, efi_guid_t *vendor_guid, | 324 | static void dup_variable_bug(efi_char16_t *str16, efi_guid_t *vendor_guid, |
325 | unsigned long len16) | 325 | unsigned long len16) |
326 | { | 326 | { |
327 | size_t i, len8 = len16 / sizeof(efi_char16_t); | 327 | size_t i, len8 = len16 / sizeof(efi_char16_t); |
328 | char *s8; | 328 | char *str8; |
329 | 329 | ||
330 | /* | 330 | /* |
331 | * Disable the workqueue since the algorithm it uses for | 331 | * Disable the workqueue since the algorithm it uses for |
@@ -334,16 +334,16 @@ static void dup_variable_bug(efi_char16_t *s16, efi_guid_t *vendor_guid, | |||
334 | */ | 334 | */ |
335 | efivar_wq_enabled = false; | 335 | efivar_wq_enabled = false; |
336 | 336 | ||
337 | s8 = kzalloc(len8, GFP_KERNEL); | 337 | str8 = kzalloc(len8, GFP_KERNEL); |
338 | if (!s8) | 338 | if (!str8) |
339 | return; | 339 | return; |
340 | 340 | ||
341 | for (i = 0; i < len8; i++) | 341 | for (i = 0; i < len8; i++) |
342 | s8[i] = s16[i]; | 342 | str8[i] = str16[i]; |
343 | 343 | ||
344 | printk(KERN_WARNING "efivars: duplicate variable: %s-%pUl\n", | 344 | printk(KERN_WARNING "efivars: duplicate variable: %s-%pUl\n", |
345 | s8, vendor_guid); | 345 | str8, vendor_guid); |
346 | kfree(s8); | 346 | kfree(str8); |
347 | } | 347 | } |
348 | 348 | ||
349 | /** | 349 | /** |
@@ -595,6 +595,39 @@ int efivar_entry_set(struct efivar_entry *entry, u32 attributes, | |||
595 | } | 595 | } |
596 | EXPORT_SYMBOL_GPL(efivar_entry_set); | 596 | EXPORT_SYMBOL_GPL(efivar_entry_set); |
597 | 597 | ||
598 | /* | ||
599 | * efivar_entry_set_nonblocking - call set_variable_nonblocking() | ||
600 | * | ||
601 | * This function is guaranteed to not block and is suitable for calling | ||
602 | * from crash/panic handlers. | ||
603 | * | ||
604 | * Crucially, this function will not block if it cannot acquire | ||
605 | * __efivars->lock. Instead, it returns -EBUSY. | ||
606 | */ | ||
607 | static int | ||
608 | efivar_entry_set_nonblocking(efi_char16_t *name, efi_guid_t vendor, | ||
609 | u32 attributes, unsigned long size, void *data) | ||
610 | { | ||
611 | const struct efivar_operations *ops = __efivars->ops; | ||
612 | unsigned long flags; | ||
613 | efi_status_t status; | ||
614 | |||
615 | if (!spin_trylock_irqsave(&__efivars->lock, flags)) | ||
616 | return -EBUSY; | ||
617 | |||
618 | status = check_var_size(attributes, size + ucs2_strsize(name, 1024)); | ||
619 | if (status != EFI_SUCCESS) { | ||
620 | spin_unlock_irqrestore(&__efivars->lock, flags); | ||
621 | return -ENOSPC; | ||
622 | } | ||
623 | |||
624 | status = ops->set_variable_nonblocking(name, &vendor, attributes, | ||
625 | size, data); | ||
626 | |||
627 | spin_unlock_irqrestore(&__efivars->lock, flags); | ||
628 | return efi_status_to_err(status); | ||
629 | } | ||
630 | |||
598 | /** | 631 | /** |
599 | * efivar_entry_set_safe - call set_variable() if enough space in firmware | 632 | * efivar_entry_set_safe - call set_variable() if enough space in firmware |
600 | * @name: buffer containing the variable name | 633 | * @name: buffer containing the variable name |
@@ -622,6 +655,20 @@ int efivar_entry_set_safe(efi_char16_t *name, efi_guid_t vendor, u32 attributes, | |||
622 | if (!ops->query_variable_store) | 655 | if (!ops->query_variable_store) |
623 | return -ENOSYS; | 656 | return -ENOSYS; |
624 | 657 | ||
658 | /* | ||
659 | * If the EFI variable backend provides a non-blocking | ||
660 | * ->set_variable() operation and we're in a context where we | ||
661 | * cannot block, then we need to use it to avoid live-locks, | ||
662 | * since the implication is that the regular ->set_variable() | ||
663 | * will block. | ||
664 | * | ||
665 | * If no ->set_variable_nonblocking() is provided then | ||
666 | * ->set_variable() is assumed to be non-blocking. | ||
667 | */ | ||
668 | if (!block && ops->set_variable_nonblocking) | ||
669 | return efivar_entry_set_nonblocking(name, vendor, attributes, | ||
670 | size, data); | ||
671 | |||
625 | if (!block) { | 672 | if (!block) { |
626 | if (!spin_trylock_irqsave(&__efivars->lock, flags)) | 673 | if (!spin_trylock_irqsave(&__efivars->lock, flags)) |
627 | return -EBUSY; | 674 | return -EBUSY; |