aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/firmware/efi/runtime-wrappers.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/firmware/efi/runtime-wrappers.c')
-rw-r--r--drivers/firmware/efi/runtime-wrappers.c164
1 files changed, 154 insertions, 10 deletions
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 */
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
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
84static efi_status_t virt_efi_get_next_variable(unsigned long *name_size, 168static 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
91static efi_status_t virt_efi_set_variable(efi_char16_t *name, 181static 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
197static efi_status_t
198virt_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
100static efi_status_t virt_efi_query_variable_info(u32 attr, 215static 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
112static efi_status_t virt_efi_get_next_high_mono_count(u32 *count) 233static 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
117static void virt_efi_reset_system(int reset_type, 244static 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
125static efi_status_t virt_efi_update_capsule(efi_capsule_header_t **capsules, 256static 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
135static efi_status_t virt_efi_query_capsule_caps(efi_capsule_header_t **capsules, 272static 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
147void efi_native_runtime_setup(void) 290void 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;