aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/firmware/efi/runtime-wrappers.c154
1 files changed, 144 insertions, 10 deletions
diff --git a/drivers/firmware/efi/runtime-wrappers.c b/drivers/firmware/efi/runtime-wrappers.c
index 10daa4bbb258..9694cba665c4 100644
--- a/drivers/firmware/efi/runtime-wrappers.c
+++ b/drivers/firmware/efi/runtime-wrappers.c
@@ -14,11 +14,83 @@
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 */
62static 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#ifndef efi_in_nmi
90#define efi_in_nmi() (0)
91#endif
92
93/*
22 * As per commit ef68c8f87ed1 ("x86: Serialize EFI time accesses on rtc_lock"), 94 * As per commit ef68c8f87ed1 ("x86: Serialize EFI time accesses on rtc_lock"),
23 * the EFI specification requires that callers of the time related runtime 95 * 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 96 * functions serialize with other CMOS accesses in the kernel, as the EFI time
@@ -32,7 +104,9 @@ static efi_status_t virt_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc)
32 efi_status_t status; 104 efi_status_t status;
33 105
34 spin_lock_irqsave(&rtc_lock, flags); 106 spin_lock_irqsave(&rtc_lock, flags);
107 spin_lock(&efi_runtime_lock);
35 status = efi_call_virt(get_time, tm, tc); 108 status = efi_call_virt(get_time, tm, tc);
109 spin_unlock(&efi_runtime_lock);
36 spin_unlock_irqrestore(&rtc_lock, flags); 110 spin_unlock_irqrestore(&rtc_lock, flags);
37 return status; 111 return status;
38} 112}
@@ -43,7 +117,9 @@ static efi_status_t virt_efi_set_time(efi_time_t *tm)
43 efi_status_t status; 117 efi_status_t status;
44 118
45 spin_lock_irqsave(&rtc_lock, flags); 119 spin_lock_irqsave(&rtc_lock, flags);
120 spin_lock(&efi_runtime_lock);
46 status = efi_call_virt(set_time, tm); 121 status = efi_call_virt(set_time, tm);
122 spin_unlock(&efi_runtime_lock);
47 spin_unlock_irqrestore(&rtc_lock, flags); 123 spin_unlock_irqrestore(&rtc_lock, flags);
48 return status; 124 return status;
49} 125}
@@ -56,7 +132,9 @@ static efi_status_t virt_efi_get_wakeup_time(efi_bool_t *enabled,
56 efi_status_t status; 132 efi_status_t status;
57 133
58 spin_lock_irqsave(&rtc_lock, flags); 134 spin_lock_irqsave(&rtc_lock, flags);
135 spin_lock(&efi_runtime_lock);
59 status = efi_call_virt(get_wakeup_time, enabled, pending, tm); 136 status = efi_call_virt(get_wakeup_time, enabled, pending, tm);
137 spin_unlock(&efi_runtime_lock);
60 spin_unlock_irqrestore(&rtc_lock, flags); 138 spin_unlock_irqrestore(&rtc_lock, flags);
61 return status; 139 return status;
62} 140}
@@ -67,7 +145,9 @@ static efi_status_t virt_efi_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm)
67 efi_status_t status; 145 efi_status_t status;
68 146
69 spin_lock_irqsave(&rtc_lock, flags); 147 spin_lock_irqsave(&rtc_lock, flags);
148 spin_lock(&efi_runtime_lock);
70 status = efi_call_virt(set_wakeup_time, enabled, tm); 149 status = efi_call_virt(set_wakeup_time, enabled, tm);
150 spin_unlock(&efi_runtime_lock);
71 spin_unlock_irqrestore(&rtc_lock, flags); 151 spin_unlock_irqrestore(&rtc_lock, flags);
72 return status; 152 return status;
73} 153}
@@ -78,14 +158,27 @@ static efi_status_t virt_efi_get_variable(efi_char16_t *name,
78 unsigned long *data_size, 158 unsigned long *data_size,
79 void *data) 159 void *data)
80{ 160{
81 return efi_call_virt(get_variable, name, vendor, attr, data_size, data); 161 unsigned long flags;
162 efi_status_t status;
163
164 spin_lock_irqsave(&efi_runtime_lock, flags);
165 status = efi_call_virt(get_variable, name, vendor, attr, data_size,
166 data);
167 spin_unlock_irqrestore(&efi_runtime_lock, flags);
168 return status;
82} 169}
83 170
84static efi_status_t virt_efi_get_next_variable(unsigned long *name_size, 171static efi_status_t virt_efi_get_next_variable(unsigned long *name_size,
85 efi_char16_t *name, 172 efi_char16_t *name,
86 efi_guid_t *vendor) 173 efi_guid_t *vendor)
87{ 174{
88 return efi_call_virt(get_next_variable, name_size, name, vendor); 175 unsigned long flags;
176 efi_status_t status;
177
178 spin_lock_irqsave(&efi_runtime_lock, flags);
179 status = efi_call_virt(get_next_variable, name_size, name, vendor);
180 spin_unlock_irqrestore(&efi_runtime_lock, flags);
181 return status;
89} 182}
90 183
91static efi_status_t virt_efi_set_variable(efi_char16_t *name, 184static efi_status_t virt_efi_set_variable(efi_char16_t *name,
@@ -94,7 +187,17 @@ static efi_status_t virt_efi_set_variable(efi_char16_t *name,
94 unsigned long data_size, 187 unsigned long data_size,
95 void *data) 188 void *data)
96{ 189{
97 return efi_call_virt(set_variable, name, vendor, attr, data_size, data); 190 unsigned long flags;
191 efi_status_t status;
192 bool __in_nmi = efi_in_nmi();
193
194 if (!__in_nmi)
195 spin_lock_irqsave(&efi_runtime_lock, flags);
196 status = efi_call_virt(set_variable, name, vendor, attr, data_size,
197 data);
198 if (!__in_nmi)
199 spin_unlock_irqrestore(&efi_runtime_lock, flags);
200 return status;
98} 201}
99 202
100static efi_status_t virt_efi_query_variable_info(u32 attr, 203static efi_status_t virt_efi_query_variable_info(u32 attr,
@@ -102,16 +205,31 @@ static efi_status_t virt_efi_query_variable_info(u32 attr,
102 u64 *remaining_space, 205 u64 *remaining_space,
103 u64 *max_variable_size) 206 u64 *max_variable_size)
104{ 207{
208 unsigned long flags;
209 efi_status_t status;
210 bool __in_nmi = efi_in_nmi();
211
105 if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) 212 if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION)
106 return EFI_UNSUPPORTED; 213 return EFI_UNSUPPORTED;
107 214
108 return efi_call_virt(query_variable_info, attr, storage_space, 215 if (!__in_nmi)
109 remaining_space, max_variable_size); 216 spin_lock_irqsave(&efi_runtime_lock, flags);
217 status = efi_call_virt(query_variable_info, attr, storage_space,
218 remaining_space, max_variable_size);
219 if (!__in_nmi)
220 spin_unlock_irqrestore(&efi_runtime_lock, flags);
221 return status;
110} 222}
111 223
112static efi_status_t virt_efi_get_next_high_mono_count(u32 *count) 224static efi_status_t virt_efi_get_next_high_mono_count(u32 *count)
113{ 225{
114 return efi_call_virt(get_next_high_mono_count, count); 226 unsigned long flags;
227 efi_status_t status;
228
229 spin_lock_irqsave(&efi_runtime_lock, flags);
230 status = efi_call_virt(get_next_high_mono_count, count);
231 spin_unlock_irqrestore(&efi_runtime_lock, flags);
232 return status;
115} 233}
116 234
117static void virt_efi_reset_system(int reset_type, 235static void virt_efi_reset_system(int reset_type,
@@ -119,17 +237,27 @@ static void virt_efi_reset_system(int reset_type,
119 unsigned long data_size, 237 unsigned long data_size,
120 efi_char16_t *data) 238 efi_char16_t *data)
121{ 239{
240 unsigned long flags;
241
242 spin_lock_irqsave(&efi_runtime_lock, flags);
122 __efi_call_virt(reset_system, reset_type, status, data_size, data); 243 __efi_call_virt(reset_system, reset_type, status, data_size, data);
244 spin_unlock_irqrestore(&efi_runtime_lock, flags);
123} 245}
124 246
125static efi_status_t virt_efi_update_capsule(efi_capsule_header_t **capsules, 247static efi_status_t virt_efi_update_capsule(efi_capsule_header_t **capsules,
126 unsigned long count, 248 unsigned long count,
127 unsigned long sg_list) 249 unsigned long sg_list)
128{ 250{
251 unsigned long flags;
252 efi_status_t status;
253
129 if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) 254 if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION)
130 return EFI_UNSUPPORTED; 255 return EFI_UNSUPPORTED;
131 256
132 return efi_call_virt(update_capsule, capsules, count, sg_list); 257 spin_lock_irqsave(&efi_runtime_lock, flags);
258 status = efi_call_virt(update_capsule, capsules, count, sg_list);
259 spin_unlock_irqrestore(&efi_runtime_lock, flags);
260 return status;
133} 261}
134 262
135static efi_status_t virt_efi_query_capsule_caps(efi_capsule_header_t **capsules, 263static efi_status_t virt_efi_query_capsule_caps(efi_capsule_header_t **capsules,
@@ -137,11 +265,17 @@ static efi_status_t virt_efi_query_capsule_caps(efi_capsule_header_t **capsules,
137 u64 *max_size, 265 u64 *max_size,
138 int *reset_type) 266 int *reset_type)
139{ 267{
268 unsigned long flags;
269 efi_status_t status;
270
140 if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) 271 if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION)
141 return EFI_UNSUPPORTED; 272 return EFI_UNSUPPORTED;
142 273
143 return efi_call_virt(query_capsule_caps, capsules, count, max_size, 274 spin_lock_irqsave(&efi_runtime_lock, flags);
144 reset_type); 275 status = efi_call_virt(query_capsule_caps, capsules, count, max_size,
276 reset_type);
277 spin_unlock_irqrestore(&efi_runtime_lock, flags);
278 return status;
145} 279}
146 280
147void efi_native_runtime_setup(void) 281void efi_native_runtime_setup(void)