Linux Audio

Check our new training course

Embedded Linux training

Mar 31-Apr 8, 2025
Register
Loading...
Note: File does not exist in v3.1.
  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
 17#define pr_fmt(fmt)	"efi: " fmt
 18
 19#include <linux/bug.h>
 20#include <linux/efi.h>
 21#include <linux/irqflags.h>
 22#include <linux/mutex.h>
 23#include <linux/semaphore.h>
 24#include <linux/stringify.h>
 25#include <asm/efi.h>
 26
 27/*
 28 * Wrap around the new efi_call_virt_generic() macros so that the
 29 * code doesn't get too cluttered:
 30 */
 31#define efi_call_virt(f, args...)   \
 32	efi_call_virt_pointer(efi.systab->runtime, f, args)
 33#define __efi_call_virt(f, args...) \
 34	__efi_call_virt_pointer(efi.systab->runtime, f, args)
 35
 36void efi_call_virt_check_flags(unsigned long flags, const char *call)
 37{
 38	unsigned long cur_flags, mismatch;
 39
 40	local_save_flags(cur_flags);
 41
 42	mismatch = flags ^ cur_flags;
 43	if (!WARN_ON_ONCE(mismatch & ARCH_EFI_IRQ_FLAGS_MASK))
 44		return;
 45
 46	add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_NOW_UNRELIABLE);
 47	pr_err_ratelimited(FW_BUG "IRQ flags corrupted (0x%08lx=>0x%08lx) by EFI %s\n",
 48			   flags, cur_flags, call);
 49	local_irq_restore(flags);
 50}
 51
 52/*
 53 * According to section 7.1 of the UEFI spec, Runtime Services are not fully
 54 * reentrant, and there are particular combinations of calls that need to be
 55 * serialized. (source: UEFI Specification v2.4A)
 56 *
 57 * Table 31. Rules for Reentry Into Runtime Services
 58 * +------------------------------------+-------------------------------+
 59 * | If previous call is busy in	| Forbidden to call		|
 60 * +------------------------------------+-------------------------------+
 61 * | Any				| SetVirtualAddressMap()	|
 62 * +------------------------------------+-------------------------------+
 63 * | ConvertPointer()			| ConvertPointer()		|
 64 * +------------------------------------+-------------------------------+
 65 * | SetVariable()			| ResetSystem()			|
 66 * | UpdateCapsule()			|				|
 67 * | SetTime()				|				|
 68 * | SetWakeupTime()			|				|
 69 * | GetNextHighMonotonicCount()	|				|
 70 * +------------------------------------+-------------------------------+
 71 * | GetVariable()			| GetVariable()			|
 72 * | GetNextVariableName()		| GetNextVariableName()		|
 73 * | SetVariable()			| SetVariable()			|
 74 * | QueryVariableInfo()		| QueryVariableInfo()		|
 75 * | UpdateCapsule()			| UpdateCapsule()		|
 76 * | QueryCapsuleCapabilities()		| QueryCapsuleCapabilities()	|
 77 * | GetNextHighMonotonicCount()	| GetNextHighMonotonicCount()	|
 78 * +------------------------------------+-------------------------------+
 79 * | GetTime()				| GetTime()			|
 80 * | SetTime()				| SetTime()			|
 81 * | GetWakeupTime()			| GetWakeupTime()		|
 82 * | SetWakeupTime()			| SetWakeupTime()		|
 83 * +------------------------------------+-------------------------------+
 84 *
 85 * Due to the fact that the EFI pstore may write to the variable store in
 86 * interrupt context, we need to use a lock for at least the groups that
 87 * contain SetVariable() and QueryVariableInfo(). That leaves little else, as
 88 * none of the remaining functions are actually ever called at runtime.
 89 * So let's just use a single lock to serialize all Runtime Services calls.
 90 */
 91static DEFINE_SEMAPHORE(efi_runtime_lock);
 92
 93static efi_status_t virt_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc)
 94{
 95	efi_status_t status;
 96
 97	if (down_interruptible(&efi_runtime_lock))
 98		return EFI_ABORTED;
 99	status = efi_call_virt(get_time, tm, tc);
100	up(&efi_runtime_lock);
101	return status;
102}
103
104static efi_status_t virt_efi_set_time(efi_time_t *tm)
105{
106	efi_status_t status;
107
108	if (down_interruptible(&efi_runtime_lock))
109		return EFI_ABORTED;
110	status = efi_call_virt(set_time, tm);
111	up(&efi_runtime_lock);
112	return status;
113}
114
115static efi_status_t virt_efi_get_wakeup_time(efi_bool_t *enabled,
116					     efi_bool_t *pending,
117					     efi_time_t *tm)
118{
119	efi_status_t status;
120
121	if (down_interruptible(&efi_runtime_lock))
122		return EFI_ABORTED;
123	status = efi_call_virt(get_wakeup_time, enabled, pending, tm);
124	up(&efi_runtime_lock);
125	return status;
126}
127
128static efi_status_t virt_efi_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm)
129{
130	efi_status_t status;
131
132	if (down_interruptible(&efi_runtime_lock))
133		return EFI_ABORTED;
134	status = efi_call_virt(set_wakeup_time, enabled, tm);
135	up(&efi_runtime_lock);
136	return status;
137}
138
139static efi_status_t virt_efi_get_variable(efi_char16_t *name,
140					  efi_guid_t *vendor,
141					  u32 *attr,
142					  unsigned long *data_size,
143					  void *data)
144{
145	efi_status_t status;
146
147	if (down_interruptible(&efi_runtime_lock))
148		return EFI_ABORTED;
149	status = efi_call_virt(get_variable, name, vendor, attr, data_size,
150			       data);
151	up(&efi_runtime_lock);
152	return status;
153}
154
155static efi_status_t virt_efi_get_next_variable(unsigned long *name_size,
156					       efi_char16_t *name,
157					       efi_guid_t *vendor)
158{
159	efi_status_t status;
160
161	if (down_interruptible(&efi_runtime_lock))
162		return EFI_ABORTED;
163	status = efi_call_virt(get_next_variable, name_size, name, vendor);
164	up(&efi_runtime_lock);
165	return status;
166}
167
168static efi_status_t virt_efi_set_variable(efi_char16_t *name,
169					  efi_guid_t *vendor,
170					  u32 attr,
171					  unsigned long data_size,
172					  void *data)
173{
174	efi_status_t status;
175
176	if (down_interruptible(&efi_runtime_lock))
177		return EFI_ABORTED;
178	status = efi_call_virt(set_variable, name, vendor, attr, data_size,
179			       data);
180	up(&efi_runtime_lock);
181	return status;
182}
183
184static efi_status_t
185virt_efi_set_variable_nonblocking(efi_char16_t *name, efi_guid_t *vendor,
186				  u32 attr, unsigned long data_size,
187				  void *data)
188{
189	efi_status_t status;
190
191	if (down_trylock(&efi_runtime_lock))
192		return EFI_NOT_READY;
193
194	status = efi_call_virt(set_variable, name, vendor, attr, data_size,
195			       data);
196	up(&efi_runtime_lock);
197	return status;
198}
199
200
201static efi_status_t virt_efi_query_variable_info(u32 attr,
202						 u64 *storage_space,
203						 u64 *remaining_space,
204						 u64 *max_variable_size)
205{
206	efi_status_t status;
207
208	if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION)
209		return EFI_UNSUPPORTED;
210
211	if (down_interruptible(&efi_runtime_lock))
212		return EFI_ABORTED;
213	status = efi_call_virt(query_variable_info, attr, storage_space,
214			       remaining_space, max_variable_size);
215	up(&efi_runtime_lock);
216	return status;
217}
218
219static efi_status_t
220virt_efi_query_variable_info_nonblocking(u32 attr,
221					 u64 *storage_space,
222					 u64 *remaining_space,
223					 u64 *max_variable_size)
224{
225	efi_status_t status;
226
227	if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION)
228		return EFI_UNSUPPORTED;
229
230	if (down_trylock(&efi_runtime_lock))
231		return EFI_NOT_READY;
232
233	status = efi_call_virt(query_variable_info, attr, storage_space,
234			       remaining_space, max_variable_size);
235	up(&efi_runtime_lock);
236	return status;
237}
238
239static efi_status_t virt_efi_get_next_high_mono_count(u32 *count)
240{
241	efi_status_t status;
242
243	if (down_interruptible(&efi_runtime_lock))
244		return EFI_ABORTED;
245	status = efi_call_virt(get_next_high_mono_count, count);
246	up(&efi_runtime_lock);
247	return status;
248}
249
250static void virt_efi_reset_system(int reset_type,
251				  efi_status_t status,
252				  unsigned long data_size,
253				  efi_char16_t *data)
254{
255	if (down_interruptible(&efi_runtime_lock)) {
256		pr_warn("failed to invoke the reset_system() runtime service:\n"
257			"could not get exclusive access to the firmware\n");
258		return;
259	}
260	__efi_call_virt(reset_system, reset_type, status, data_size, data);
261	up(&efi_runtime_lock);
262}
263
264static efi_status_t virt_efi_update_capsule(efi_capsule_header_t **capsules,
265					    unsigned long count,
266					    unsigned long sg_list)
267{
268	efi_status_t status;
269
270	if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION)
271		return EFI_UNSUPPORTED;
272
273	if (down_interruptible(&efi_runtime_lock))
274		return EFI_ABORTED;
275	status = efi_call_virt(update_capsule, capsules, count, sg_list);
276	up(&efi_runtime_lock);
277	return status;
278}
279
280static efi_status_t virt_efi_query_capsule_caps(efi_capsule_header_t **capsules,
281						unsigned long count,
282						u64 *max_size,
283						int *reset_type)
284{
285	efi_status_t status;
286
287	if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION)
288		return EFI_UNSUPPORTED;
289
290	if (down_interruptible(&efi_runtime_lock))
291		return EFI_ABORTED;
292	status = efi_call_virt(query_capsule_caps, capsules, count, max_size,
293			       reset_type);
294	up(&efi_runtime_lock);
295	return status;
296}
297
298void efi_native_runtime_setup(void)
299{
300	efi.get_time = virt_efi_get_time;
301	efi.set_time = virt_efi_set_time;
302	efi.get_wakeup_time = virt_efi_get_wakeup_time;
303	efi.set_wakeup_time = virt_efi_set_wakeup_time;
304	efi.get_variable = virt_efi_get_variable;
305	efi.get_next_variable = virt_efi_get_next_variable;
306	efi.set_variable = virt_efi_set_variable;
307	efi.set_variable_nonblocking = virt_efi_set_variable_nonblocking;
308	efi.get_next_high_mono_count = virt_efi_get_next_high_mono_count;
309	efi.reset_system = virt_efi_reset_system;
310	efi.query_variable_info = virt_efi_query_variable_info;
311	efi.query_variable_info_nonblocking = virt_efi_query_variable_info_nonblocking;
312	efi.update_capsule = virt_efi_update_capsule;
313	efi.query_capsule_caps = virt_efi_query_capsule_caps;
314}