Commit | Line | Data |
---|---|---|
022ee6c5 AB |
1 | /* |
2 | * runtime-wrappers.c - Runtime Services function call wrappers | |
3 | * | |
4 | * Copyright (C) 2014 Linaro Ltd. <ard.biesheuvel@linaro.org> | |
5 | * | |
6 | * Split off from arch/x86/platform/efi/efi.c | |
7 | * | |
8 | * Copyright (C) 1999 VA Linux Systems | |
9 | * Copyright (C) 1999 Walt Drummond <drummond@valinux.com> | |
10 | * Copyright (C) 1999-2002 Hewlett-Packard Co. | |
11 | * Copyright (C) 2005-2008 Intel Co. | |
12 | * Copyright (C) 2013 SuSE Labs | |
13 | * | |
14 | * This file is released under the GPLv2. | |
15 | */ | |
16 | ||
161485e8 | 17 | #include <linux/bug.h> |
022ee6c5 | 18 | #include <linux/efi.h> |
1d04ba17 | 19 | #include <linux/irqflags.h> |
161485e8 AB |
20 | #include <linux/mutex.h> |
21 | #include <linux/spinlock.h> | |
1d04ba17 | 22 | #include <linux/stringify.h> |
022ee6c5 AB |
23 | #include <asm/efi.h> |
24 | ||
1d04ba17 MR |
25 | static void efi_call_virt_check_flags(unsigned long flags, const char *call) |
26 | { | |
27 | unsigned long cur_flags, mismatch; | |
28 | ||
29 | local_save_flags(cur_flags); | |
30 | ||
31 | mismatch = flags ^ cur_flags; | |
32 | if (!WARN_ON_ONCE(mismatch & ARCH_EFI_IRQ_FLAGS_MASK)) | |
33 | return; | |
34 | ||
35 | add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_NOW_UNRELIABLE); | |
36 | pr_err_ratelimited(FW_BUG "IRQ flags corrupted (0x%08lx=>0x%08lx) by EFI %s\n", | |
37 | flags, cur_flags, call); | |
38 | local_irq_restore(flags); | |
39 | } | |
1d04ba17 | 40 | |
f51c35f2 MR |
41 | /* |
42 | * Arch code can implement the following three template macros, avoiding | |
43 | * reptition for the void/non-void return cases of {__,}efi_call_virt: | |
44 | * | |
45 | * * arch_efi_call_virt_setup | |
46 | * | |
47 | * Sets up the environment for the call (e.g. switching page tables, | |
48 | * allowing kernel-mode use of floating point, if required). | |
49 | * | |
50 | * * arch_efi_call_virt | |
51 | * | |
52 | * Performs the call. The last expression in the macro must be the call | |
53 | * itself, allowing the logic to be shared by the void and non-void | |
54 | * cases. | |
55 | * | |
56 | * * arch_efi_call_virt_teardown | |
57 | * | |
58 | * Restores the usual kernel environment once the call has returned. | |
59 | */ | |
60 | ||
f51c35f2 MR |
61 | #define efi_call_virt(f, args...) \ |
62 | ({ \ | |
63 | efi_status_t __s; \ | |
1d04ba17 | 64 | unsigned long flags; \ |
f51c35f2 | 65 | arch_efi_call_virt_setup(); \ |
1d04ba17 | 66 | local_save_flags(flags); \ |
f51c35f2 | 67 | __s = arch_efi_call_virt(f, args); \ |
1d04ba17 | 68 | efi_call_virt_check_flags(flags, __stringify(f)); \ |
f51c35f2 MR |
69 | arch_efi_call_virt_teardown(); \ |
70 | __s; \ | |
71 | }) | |
f51c35f2 | 72 | |
f51c35f2 MR |
73 | #define __efi_call_virt(f, args...) \ |
74 | ({ \ | |
1d04ba17 | 75 | unsigned long flags; \ |
f51c35f2 | 76 | arch_efi_call_virt_setup(); \ |
1d04ba17 | 77 | local_save_flags(flags); \ |
f51c35f2 | 78 | arch_efi_call_virt(f, args); \ |
1d04ba17 | 79 | efi_call_virt_check_flags(flags, __stringify(f)); \ |
f51c35f2 MR |
80 | arch_efi_call_virt_teardown(); \ |
81 | }) | |
f51c35f2 | 82 | |
161485e8 AB |
83 | /* |
84 | * According to section 7.1 of the UEFI spec, Runtime Services are not fully | |
85 | * reentrant, and there are particular combinations of calls that need to be | |
86 | * serialized. (source: UEFI Specification v2.4A) | |
87 | * | |
88 | * Table 31. Rules for Reentry Into Runtime Services | |
89 | * +------------------------------------+-------------------------------+ | |
90 | * | If previous call is busy in | Forbidden to call | | |
91 | * +------------------------------------+-------------------------------+ | |
92 | * | Any | SetVirtualAddressMap() | | |
93 | * +------------------------------------+-------------------------------+ | |
94 | * | ConvertPointer() | ConvertPointer() | | |
95 | * +------------------------------------+-------------------------------+ | |
96 | * | SetVariable() | ResetSystem() | | |
97 | * | UpdateCapsule() | | | |
98 | * | SetTime() | | | |
99 | * | SetWakeupTime() | | | |
100 | * | GetNextHighMonotonicCount() | | | |
101 | * +------------------------------------+-------------------------------+ | |
102 | * | GetVariable() | GetVariable() | | |
103 | * | GetNextVariableName() | GetNextVariableName() | | |
104 | * | SetVariable() | SetVariable() | | |
105 | * | QueryVariableInfo() | QueryVariableInfo() | | |
106 | * | UpdateCapsule() | UpdateCapsule() | | |
107 | * | QueryCapsuleCapabilities() | QueryCapsuleCapabilities() | | |
108 | * | GetNextHighMonotonicCount() | GetNextHighMonotonicCount() | | |
109 | * +------------------------------------+-------------------------------+ | |
110 | * | GetTime() | GetTime() | | |
111 | * | SetTime() | SetTime() | | |
112 | * | GetWakeupTime() | GetWakeupTime() | | |
113 | * | SetWakeupTime() | SetWakeupTime() | | |
114 | * +------------------------------------+-------------------------------+ | |
115 | * | |
116 | * Due to the fact that the EFI pstore may write to the variable store in | |
117 | * interrupt context, we need to use a spinlock for at least the groups that | |
118 | * contain SetVariable() and QueryVariableInfo(). That leaves little else, as | |
119 | * none of the remaining functions are actually ever called at runtime. | |
120 | * So let's just use a single spinlock to serialize all Runtime Services calls. | |
121 | */ | |
122 | static DEFINE_SPINLOCK(efi_runtime_lock); | |
123 | ||
022ee6c5 AB |
124 | static efi_status_t virt_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc) |
125 | { | |
022ee6c5 AB |
126 | efi_status_t status; |
127 | ||
fe324494 | 128 | spin_lock(&efi_runtime_lock); |
022ee6c5 | 129 | status = efi_call_virt(get_time, tm, tc); |
fe324494 | 130 | spin_unlock(&efi_runtime_lock); |
022ee6c5 AB |
131 | return status; |
132 | } | |
133 | ||
134 | static efi_status_t virt_efi_set_time(efi_time_t *tm) | |
135 | { | |
022ee6c5 AB |
136 | efi_status_t status; |
137 | ||
fe324494 | 138 | spin_lock(&efi_runtime_lock); |
022ee6c5 | 139 | status = efi_call_virt(set_time, tm); |
fe324494 | 140 | spin_unlock(&efi_runtime_lock); |
022ee6c5 AB |
141 | return status; |
142 | } | |
143 | ||
144 | static efi_status_t virt_efi_get_wakeup_time(efi_bool_t *enabled, | |
145 | efi_bool_t *pending, | |
146 | efi_time_t *tm) | |
147 | { | |
022ee6c5 AB |
148 | efi_status_t status; |
149 | ||
fe324494 | 150 | spin_lock(&efi_runtime_lock); |
022ee6c5 | 151 | status = efi_call_virt(get_wakeup_time, enabled, pending, tm); |
fe324494 | 152 | spin_unlock(&efi_runtime_lock); |
022ee6c5 AB |
153 | return status; |
154 | } | |
155 | ||
156 | static efi_status_t virt_efi_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm) | |
157 | { | |
022ee6c5 AB |
158 | efi_status_t status; |
159 | ||
fe324494 | 160 | spin_lock(&efi_runtime_lock); |
022ee6c5 | 161 | status = efi_call_virt(set_wakeup_time, enabled, tm); |
fe324494 | 162 | spin_unlock(&efi_runtime_lock); |
022ee6c5 AB |
163 | return status; |
164 | } | |
165 | ||
166 | static efi_status_t virt_efi_get_variable(efi_char16_t *name, | |
167 | efi_guid_t *vendor, | |
168 | u32 *attr, | |
169 | unsigned long *data_size, | |
170 | void *data) | |
171 | { | |
161485e8 AB |
172 | efi_status_t status; |
173 | ||
fe324494 | 174 | spin_lock(&efi_runtime_lock); |
161485e8 AB |
175 | status = efi_call_virt(get_variable, name, vendor, attr, data_size, |
176 | data); | |
fe324494 | 177 | spin_unlock(&efi_runtime_lock); |
161485e8 | 178 | return status; |
022ee6c5 AB |
179 | } |
180 | ||
181 | static efi_status_t virt_efi_get_next_variable(unsigned long *name_size, | |
182 | efi_char16_t *name, | |
183 | efi_guid_t *vendor) | |
184 | { | |
161485e8 AB |
185 | efi_status_t status; |
186 | ||
fe324494 | 187 | spin_lock(&efi_runtime_lock); |
161485e8 | 188 | status = efi_call_virt(get_next_variable, name_size, name, vendor); |
fe324494 | 189 | spin_unlock(&efi_runtime_lock); |
161485e8 | 190 | return status; |
022ee6c5 AB |
191 | } |
192 | ||
193 | static efi_status_t virt_efi_set_variable(efi_char16_t *name, | |
194 | efi_guid_t *vendor, | |
195 | u32 attr, | |
196 | unsigned long data_size, | |
197 | void *data) | |
198 | { | |
161485e8 | 199 | efi_status_t status; |
161485e8 | 200 | |
fe324494 | 201 | spin_lock(&efi_runtime_lock); |
161485e8 AB |
202 | status = efi_call_virt(set_variable, name, vendor, attr, data_size, |
203 | data); | |
fe324494 | 204 | spin_unlock(&efi_runtime_lock); |
161485e8 | 205 | return status; |
022ee6c5 AB |
206 | } |
207 | ||
6d80dba1 MF |
208 | static efi_status_t |
209 | virt_efi_set_variable_nonblocking(efi_char16_t *name, efi_guid_t *vendor, | |
210 | u32 attr, unsigned long data_size, | |
211 | void *data) | |
212 | { | |
6d80dba1 MF |
213 | efi_status_t status; |
214 | ||
fe324494 | 215 | if (!spin_trylock(&efi_runtime_lock)) |
6d80dba1 MF |
216 | return EFI_NOT_READY; |
217 | ||
218 | status = efi_call_virt(set_variable, name, vendor, attr, data_size, | |
219 | data); | |
fe324494 | 220 | spin_unlock(&efi_runtime_lock); |
6d80dba1 MF |
221 | return status; |
222 | } | |
223 | ||
224 | ||
022ee6c5 AB |
225 | static efi_status_t virt_efi_query_variable_info(u32 attr, |
226 | u64 *storage_space, | |
227 | u64 *remaining_space, | |
228 | u64 *max_variable_size) | |
229 | { | |
161485e8 | 230 | efi_status_t status; |
161485e8 | 231 | |
022ee6c5 AB |
232 | if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) |
233 | return EFI_UNSUPPORTED; | |
234 | ||
fe324494 | 235 | spin_lock(&efi_runtime_lock); |
161485e8 AB |
236 | status = efi_call_virt(query_variable_info, attr, storage_space, |
237 | remaining_space, max_variable_size); | |
fe324494 | 238 | spin_unlock(&efi_runtime_lock); |
161485e8 | 239 | return status; |
022ee6c5 AB |
240 | } |
241 | ||
d3cac1f8 AB |
242 | static efi_status_t |
243 | virt_efi_query_variable_info_nonblocking(u32 attr, | |
244 | u64 *storage_space, | |
245 | u64 *remaining_space, | |
246 | u64 *max_variable_size) | |
247 | { | |
d3cac1f8 AB |
248 | efi_status_t status; |
249 | ||
250 | if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) | |
251 | return EFI_UNSUPPORTED; | |
252 | ||
fe324494 | 253 | if (!spin_trylock(&efi_runtime_lock)) |
d3cac1f8 AB |
254 | return EFI_NOT_READY; |
255 | ||
256 | status = efi_call_virt(query_variable_info, attr, storage_space, | |
257 | remaining_space, max_variable_size); | |
fe324494 | 258 | spin_unlock(&efi_runtime_lock); |
d3cac1f8 AB |
259 | return status; |
260 | } | |
261 | ||
022ee6c5 AB |
262 | static efi_status_t virt_efi_get_next_high_mono_count(u32 *count) |
263 | { | |
161485e8 AB |
264 | efi_status_t status; |
265 | ||
fe324494 | 266 | spin_lock(&efi_runtime_lock); |
161485e8 | 267 | status = efi_call_virt(get_next_high_mono_count, count); |
fe324494 | 268 | spin_unlock(&efi_runtime_lock); |
161485e8 | 269 | return status; |
022ee6c5 AB |
270 | } |
271 | ||
272 | static void virt_efi_reset_system(int reset_type, | |
273 | efi_status_t status, | |
274 | unsigned long data_size, | |
275 | efi_char16_t *data) | |
276 | { | |
fe324494 | 277 | spin_lock(&efi_runtime_lock); |
022ee6c5 | 278 | __efi_call_virt(reset_system, reset_type, status, data_size, data); |
fe324494 | 279 | spin_unlock(&efi_runtime_lock); |
022ee6c5 AB |
280 | } |
281 | ||
282 | static efi_status_t virt_efi_update_capsule(efi_capsule_header_t **capsules, | |
283 | unsigned long count, | |
284 | unsigned long sg_list) | |
285 | { | |
161485e8 AB |
286 | efi_status_t status; |
287 | ||
022ee6c5 AB |
288 | if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) |
289 | return EFI_UNSUPPORTED; | |
290 | ||
fe324494 | 291 | spin_lock(&efi_runtime_lock); |
161485e8 | 292 | status = efi_call_virt(update_capsule, capsules, count, sg_list); |
fe324494 | 293 | spin_unlock(&efi_runtime_lock); |
161485e8 | 294 | return status; |
022ee6c5 AB |
295 | } |
296 | ||
297 | static efi_status_t virt_efi_query_capsule_caps(efi_capsule_header_t **capsules, | |
298 | unsigned long count, | |
299 | u64 *max_size, | |
300 | int *reset_type) | |
301 | { | |
161485e8 AB |
302 | efi_status_t status; |
303 | ||
022ee6c5 AB |
304 | if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) |
305 | return EFI_UNSUPPORTED; | |
306 | ||
fe324494 | 307 | spin_lock(&efi_runtime_lock); |
161485e8 AB |
308 | status = efi_call_virt(query_capsule_caps, capsules, count, max_size, |
309 | reset_type); | |
fe324494 | 310 | spin_unlock(&efi_runtime_lock); |
161485e8 | 311 | return status; |
022ee6c5 AB |
312 | } |
313 | ||
314 | void efi_native_runtime_setup(void) | |
315 | { | |
316 | efi.get_time = virt_efi_get_time; | |
317 | efi.set_time = virt_efi_set_time; | |
318 | efi.get_wakeup_time = virt_efi_get_wakeup_time; | |
319 | efi.set_wakeup_time = virt_efi_set_wakeup_time; | |
320 | efi.get_variable = virt_efi_get_variable; | |
321 | efi.get_next_variable = virt_efi_get_next_variable; | |
322 | efi.set_variable = virt_efi_set_variable; | |
6d80dba1 | 323 | efi.set_variable_nonblocking = virt_efi_set_variable_nonblocking; |
022ee6c5 AB |
324 | efi.get_next_high_mono_count = virt_efi_get_next_high_mono_count; |
325 | efi.reset_system = virt_efi_reset_system; | |
326 | efi.query_variable_info = virt_efi_query_variable_info; | |
d3cac1f8 | 327 | efi.query_variable_info_nonblocking = virt_efi_query_variable_info_nonblocking; |
022ee6c5 AB |
328 | efi.update_capsule = virt_efi_update_capsule; |
329 | efi.query_capsule_caps = virt_efi_query_capsule_caps; | |
330 | } |