1022ee6c5SArd Biesheuvel /*
2022ee6c5SArd Biesheuvel  * runtime-wrappers.c - Runtime Services function call wrappers
3022ee6c5SArd Biesheuvel  *
43eb420e7SSai Praneeth  * Implementation summary:
53eb420e7SSai Praneeth  * -----------------------
63eb420e7SSai Praneeth  * 1. When user/kernel thread requests to execute efi_runtime_service(),
73eb420e7SSai Praneeth  * enqueue work to efi_rts_wq.
83eb420e7SSai Praneeth  * 2. Caller thread waits for completion until the work is finished
93eb420e7SSai Praneeth  * because it's dependent on the return status and execution of
103eb420e7SSai Praneeth  * efi_runtime_service().
113eb420e7SSai Praneeth  * For instance, get_variable() and get_next_variable().
123eb420e7SSai Praneeth  *
13022ee6c5SArd Biesheuvel  * Copyright (C) 2014 Linaro Ltd. <ard.biesheuvel@linaro.org>
14022ee6c5SArd Biesheuvel  *
15022ee6c5SArd Biesheuvel  * Split off from arch/x86/platform/efi/efi.c
16022ee6c5SArd Biesheuvel  *
17022ee6c5SArd Biesheuvel  * Copyright (C) 1999 VA Linux Systems
18022ee6c5SArd Biesheuvel  * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
19022ee6c5SArd Biesheuvel  * Copyright (C) 1999-2002 Hewlett-Packard Co.
20022ee6c5SArd Biesheuvel  * Copyright (C) 2005-2008 Intel Co.
21022ee6c5SArd Biesheuvel  * Copyright (C) 2013 SuSE Labs
22022ee6c5SArd Biesheuvel  *
23022ee6c5SArd Biesheuvel  * This file is released under the GPLv2.
24022ee6c5SArd Biesheuvel  */
25022ee6c5SArd Biesheuvel 
26dce48e35SArd Biesheuvel #define pr_fmt(fmt)	"efi: " fmt
27dce48e35SArd Biesheuvel 
28161485e8SArd Biesheuvel #include <linux/bug.h>
29022ee6c5SArd Biesheuvel #include <linux/efi.h>
301d04ba17SMark Rutland #include <linux/irqflags.h>
31161485e8SArd Biesheuvel #include <linux/mutex.h>
32dce48e35SArd Biesheuvel #include <linux/semaphore.h>
331d04ba17SMark Rutland #include <linux/stringify.h>
343eb420e7SSai Praneeth #include <linux/workqueue.h>
353eb420e7SSai Praneeth #include <linux/completion.h>
363eb420e7SSai Praneeth 
37022ee6c5SArd Biesheuvel #include <asm/efi.h>
38022ee6c5SArd Biesheuvel 
3980e75596SAlex Thorlton /*
4080e75596SAlex Thorlton  * Wrap around the new efi_call_virt_generic() macros so that the
4180e75596SAlex Thorlton  * code doesn't get too cluttered:
4280e75596SAlex Thorlton  */
4380e75596SAlex Thorlton #define efi_call_virt(f, args...)   \
4480e75596SAlex Thorlton 	efi_call_virt_pointer(efi.systab->runtime, f, args)
4580e75596SAlex Thorlton #define __efi_call_virt(f, args...) \
4680e75596SAlex Thorlton 	__efi_call_virt_pointer(efi.systab->runtime, f, args)
4780e75596SAlex Thorlton 
489dbbedaaSSai Praneeth struct efi_runtime_work efi_rts_work;
493eb420e7SSai Praneeth 
503eb420e7SSai Praneeth /*
513eb420e7SSai Praneeth  * efi_queue_work:	Queue efi_runtime_service() and wait until it's done
523eb420e7SSai Praneeth  * @rts:		efi_runtime_service() function identifier
533eb420e7SSai Praneeth  * @rts_arg<1-5>:	efi_runtime_service() function arguments
543eb420e7SSai Praneeth  *
553eb420e7SSai Praneeth  * Accesses to efi_runtime_services() are serialized by a binary
563eb420e7SSai Praneeth  * semaphore (efi_runtime_lock) and caller waits until the work is
573eb420e7SSai Praneeth  * finished, hence _only_ one work is queued at a time and the caller
583eb420e7SSai Praneeth  * thread waits for completion.
593eb420e7SSai Praneeth  */
603eb420e7SSai Praneeth #define efi_queue_work(_rts, _arg1, _arg2, _arg3, _arg4, _arg5)		\
613eb420e7SSai Praneeth ({									\
623eb420e7SSai Praneeth 	efi_rts_work.status = EFI_ABORTED;				\
633eb420e7SSai Praneeth 									\
643425d934SSai Praneeth 	if (!efi_enabled(EFI_RUNTIME_SERVICES)) {			\
653425d934SSai Praneeth 		pr_warn_once("EFI Runtime Services are disabled!\n");	\
663425d934SSai Praneeth 		goto exit;						\
673425d934SSai Praneeth 	}								\
683425d934SSai Praneeth 									\
693eb420e7SSai Praneeth 	init_completion(&efi_rts_work.efi_rts_comp);			\
703eb420e7SSai Praneeth 	INIT_WORK_ONSTACK(&efi_rts_work.work, efi_call_rts);		\
713eb420e7SSai Praneeth 	efi_rts_work.arg1 = _arg1;					\
723eb420e7SSai Praneeth 	efi_rts_work.arg2 = _arg2;					\
733eb420e7SSai Praneeth 	efi_rts_work.arg3 = _arg3;					\
743eb420e7SSai Praneeth 	efi_rts_work.arg4 = _arg4;					\
753eb420e7SSai Praneeth 	efi_rts_work.arg5 = _arg5;					\
763eb420e7SSai Praneeth 	efi_rts_work.efi_rts_id = _rts;					\
773eb420e7SSai Praneeth 									\
783eb420e7SSai Praneeth 	/*								\
793eb420e7SSai Praneeth 	 * queue_work() returns 0 if work was already on queue,         \
803eb420e7SSai Praneeth 	 * _ideally_ this should never happen.                          \
813eb420e7SSai Praneeth 	 */								\
823eb420e7SSai Praneeth 	if (queue_work(efi_rts_wq, &efi_rts_work.work))			\
833eb420e7SSai Praneeth 		wait_for_completion(&efi_rts_work.efi_rts_comp);	\
843eb420e7SSai Praneeth 	else								\
853eb420e7SSai Praneeth 		pr_err("Failed to queue work to efi_rts_wq.\n");	\
863eb420e7SSai Praneeth 									\
873425d934SSai Praneeth exit:									\
883425d934SSai Praneeth 	efi_rts_work.efi_rts_id = NONE;					\
893eb420e7SSai Praneeth 	efi_rts_work.status;						\
903eb420e7SSai Praneeth })
913eb420e7SSai Praneeth 
9280e75596SAlex Thorlton void efi_call_virt_check_flags(unsigned long flags, const char *call)
931d04ba17SMark Rutland {
941d04ba17SMark Rutland 	unsigned long cur_flags, mismatch;
951d04ba17SMark Rutland 
961d04ba17SMark Rutland 	local_save_flags(cur_flags);
971d04ba17SMark Rutland 
981d04ba17SMark Rutland 	mismatch = flags ^ cur_flags;
991d04ba17SMark Rutland 	if (!WARN_ON_ONCE(mismatch & ARCH_EFI_IRQ_FLAGS_MASK))
1001d04ba17SMark Rutland 		return;
1011d04ba17SMark Rutland 
1021d04ba17SMark Rutland 	add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_NOW_UNRELIABLE);
1031d04ba17SMark Rutland 	pr_err_ratelimited(FW_BUG "IRQ flags corrupted (0x%08lx=>0x%08lx) by EFI %s\n",
1041d04ba17SMark Rutland 			   flags, cur_flags, call);
1051d04ba17SMark Rutland 	local_irq_restore(flags);
1061d04ba17SMark Rutland }
1071d04ba17SMark Rutland 
1081d04ba17SMark Rutland /*
109161485e8SArd Biesheuvel  * According to section 7.1 of the UEFI spec, Runtime Services are not fully
110161485e8SArd Biesheuvel  * reentrant, and there are particular combinations of calls that need to be
111161485e8SArd Biesheuvel  * serialized. (source: UEFI Specification v2.4A)
112161485e8SArd Biesheuvel  *
113161485e8SArd Biesheuvel  * Table 31. Rules for Reentry Into Runtime Services
114161485e8SArd Biesheuvel  * +------------------------------------+-------------------------------+
115161485e8SArd Biesheuvel  * | If previous call is busy in	| Forbidden to call		|
116161485e8SArd Biesheuvel  * +------------------------------------+-------------------------------+
117161485e8SArd Biesheuvel  * | Any				| SetVirtualAddressMap()	|
118161485e8SArd Biesheuvel  * +------------------------------------+-------------------------------+
119161485e8SArd Biesheuvel  * | ConvertPointer()			| ConvertPointer()		|
120161485e8SArd Biesheuvel  * +------------------------------------+-------------------------------+
121161485e8SArd Biesheuvel  * | SetVariable()			| ResetSystem()			|
122161485e8SArd Biesheuvel  * | UpdateCapsule()			|				|
123161485e8SArd Biesheuvel  * | SetTime()				|				|
124161485e8SArd Biesheuvel  * | SetWakeupTime()			|				|
125161485e8SArd Biesheuvel  * | GetNextHighMonotonicCount()	|				|
126161485e8SArd Biesheuvel  * +------------------------------------+-------------------------------+
127161485e8SArd Biesheuvel  * | GetVariable()			| GetVariable()			|
128161485e8SArd Biesheuvel  * | GetNextVariableName()		| GetNextVariableName()		|
129161485e8SArd Biesheuvel  * | SetVariable()			| SetVariable()			|
130161485e8SArd Biesheuvel  * | QueryVariableInfo()		| QueryVariableInfo()		|
131161485e8SArd Biesheuvel  * | UpdateCapsule()			| UpdateCapsule()		|
132161485e8SArd Biesheuvel  * | QueryCapsuleCapabilities()		| QueryCapsuleCapabilities()	|
133161485e8SArd Biesheuvel  * | GetNextHighMonotonicCount()	| GetNextHighMonotonicCount()	|
134161485e8SArd Biesheuvel  * +------------------------------------+-------------------------------+
135161485e8SArd Biesheuvel  * | GetTime()				| GetTime()			|
136161485e8SArd Biesheuvel  * | SetTime()				| SetTime()			|
137161485e8SArd Biesheuvel  * | GetWakeupTime()			| GetWakeupTime()		|
138161485e8SArd Biesheuvel  * | SetWakeupTime()			| SetWakeupTime()		|
139161485e8SArd Biesheuvel  * +------------------------------------+-------------------------------+
140161485e8SArd Biesheuvel  *
141161485e8SArd Biesheuvel  * Due to the fact that the EFI pstore may write to the variable store in
142dce48e35SArd Biesheuvel  * interrupt context, we need to use a lock for at least the groups that
143161485e8SArd Biesheuvel  * contain SetVariable() and QueryVariableInfo(). That leaves little else, as
144161485e8SArd Biesheuvel  * none of the remaining functions are actually ever called at runtime.
145dce48e35SArd Biesheuvel  * So let's just use a single lock to serialize all Runtime Services calls.
146161485e8SArd Biesheuvel  */
147dce48e35SArd Biesheuvel static DEFINE_SEMAPHORE(efi_runtime_lock);
148161485e8SArd Biesheuvel 
1493eb420e7SSai Praneeth /*
1503eb420e7SSai Praneeth  * Calls the appropriate efi_runtime_service() with the appropriate
1513eb420e7SSai Praneeth  * arguments.
1523eb420e7SSai Praneeth  *
1533eb420e7SSai Praneeth  * Semantics followed by efi_call_rts() to understand efi_runtime_work:
1543eb420e7SSai Praneeth  * 1. If argument was a pointer, recast it from void pointer to original
1553eb420e7SSai Praneeth  * pointer type.
1563eb420e7SSai Praneeth  * 2. If argument was a value, recast it from void pointer to original
1573eb420e7SSai Praneeth  * pointer type and dereference it.
1583eb420e7SSai Praneeth  */
1593eb420e7SSai Praneeth static void efi_call_rts(struct work_struct *work)
1603eb420e7SSai Praneeth {
1613eb420e7SSai Praneeth 	void *arg1, *arg2, *arg3, *arg4, *arg5;
1623eb420e7SSai Praneeth 	efi_status_t status = EFI_NOT_FOUND;
1633eb420e7SSai Praneeth 
1649dbbedaaSSai Praneeth 	arg1 = efi_rts_work.arg1;
1659dbbedaaSSai Praneeth 	arg2 = efi_rts_work.arg2;
1669dbbedaaSSai Praneeth 	arg3 = efi_rts_work.arg3;
1679dbbedaaSSai Praneeth 	arg4 = efi_rts_work.arg4;
1689dbbedaaSSai Praneeth 	arg5 = efi_rts_work.arg5;
1693eb420e7SSai Praneeth 
1709dbbedaaSSai Praneeth 	switch (efi_rts_work.efi_rts_id) {
1713eb420e7SSai Praneeth 	case GET_TIME:
1723eb420e7SSai Praneeth 		status = efi_call_virt(get_time, (efi_time_t *)arg1,
1733eb420e7SSai Praneeth 				       (efi_time_cap_t *)arg2);
1743eb420e7SSai Praneeth 		break;
1753eb420e7SSai Praneeth 	case SET_TIME:
1763eb420e7SSai Praneeth 		status = efi_call_virt(set_time, (efi_time_t *)arg1);
1773eb420e7SSai Praneeth 		break;
1783eb420e7SSai Praneeth 	case GET_WAKEUP_TIME:
1793eb420e7SSai Praneeth 		status = efi_call_virt(get_wakeup_time, (efi_bool_t *)arg1,
1803eb420e7SSai Praneeth 				       (efi_bool_t *)arg2, (efi_time_t *)arg3);
1813eb420e7SSai Praneeth 		break;
1823eb420e7SSai Praneeth 	case SET_WAKEUP_TIME:
1833eb420e7SSai Praneeth 		status = efi_call_virt(set_wakeup_time, *(efi_bool_t *)arg1,
1843eb420e7SSai Praneeth 				       (efi_time_t *)arg2);
1853eb420e7SSai Praneeth 		break;
1863eb420e7SSai Praneeth 	case GET_VARIABLE:
1873eb420e7SSai Praneeth 		status = efi_call_virt(get_variable, (efi_char16_t *)arg1,
1883eb420e7SSai Praneeth 				       (efi_guid_t *)arg2, (u32 *)arg3,
1893eb420e7SSai Praneeth 				       (unsigned long *)arg4, (void *)arg5);
1903eb420e7SSai Praneeth 		break;
1913eb420e7SSai Praneeth 	case GET_NEXT_VARIABLE:
1923eb420e7SSai Praneeth 		status = efi_call_virt(get_next_variable, (unsigned long *)arg1,
1933eb420e7SSai Praneeth 				       (efi_char16_t *)arg2,
1943eb420e7SSai Praneeth 				       (efi_guid_t *)arg3);
1953eb420e7SSai Praneeth 		break;
1963eb420e7SSai Praneeth 	case SET_VARIABLE:
1973eb420e7SSai Praneeth 		status = efi_call_virt(set_variable, (efi_char16_t *)arg1,
1983eb420e7SSai Praneeth 				       (efi_guid_t *)arg2, *(u32 *)arg3,
1993eb420e7SSai Praneeth 				       *(unsigned long *)arg4, (void *)arg5);
2003eb420e7SSai Praneeth 		break;
2013eb420e7SSai Praneeth 	case QUERY_VARIABLE_INFO:
2023eb420e7SSai Praneeth 		status = efi_call_virt(query_variable_info, *(u32 *)arg1,
2033eb420e7SSai Praneeth 				       (u64 *)arg2, (u64 *)arg3, (u64 *)arg4);
2043eb420e7SSai Praneeth 		break;
2053eb420e7SSai Praneeth 	case GET_NEXT_HIGH_MONO_COUNT:
2063eb420e7SSai Praneeth 		status = efi_call_virt(get_next_high_mono_count, (u32 *)arg1);
2073eb420e7SSai Praneeth 		break;
2083eb420e7SSai Praneeth 	case UPDATE_CAPSULE:
2093eb420e7SSai Praneeth 		status = efi_call_virt(update_capsule,
2103eb420e7SSai Praneeth 				       (efi_capsule_header_t **)arg1,
2113eb420e7SSai Praneeth 				       *(unsigned long *)arg2,
2123eb420e7SSai Praneeth 				       *(unsigned long *)arg3);
2133eb420e7SSai Praneeth 		break;
2143eb420e7SSai Praneeth 	case QUERY_CAPSULE_CAPS:
2153eb420e7SSai Praneeth 		status = efi_call_virt(query_capsule_caps,
2163eb420e7SSai Praneeth 				       (efi_capsule_header_t **)arg1,
2173eb420e7SSai Praneeth 				       *(unsigned long *)arg2, (u64 *)arg3,
2183eb420e7SSai Praneeth 				       (int *)arg4);
2193eb420e7SSai Praneeth 		break;
2203eb420e7SSai Praneeth 	default:
2213eb420e7SSai Praneeth 		/*
2223eb420e7SSai Praneeth 		 * Ideally, we should never reach here because a caller of this
2233eb420e7SSai Praneeth 		 * function should have put the right efi_runtime_service()
2243eb420e7SSai Praneeth 		 * function identifier into efi_rts_work->efi_rts_id
2253eb420e7SSai Praneeth 		 */
2263eb420e7SSai Praneeth 		pr_err("Requested executing invalid EFI Runtime Service.\n");
2273eb420e7SSai Praneeth 	}
2289dbbedaaSSai Praneeth 	efi_rts_work.status = status;
2299dbbedaaSSai Praneeth 	complete(&efi_rts_work.efi_rts_comp);
2303eb420e7SSai Praneeth }
2313eb420e7SSai Praneeth 
232022ee6c5SArd Biesheuvel static efi_status_t virt_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc)
233022ee6c5SArd Biesheuvel {
234022ee6c5SArd Biesheuvel 	efi_status_t status;
235022ee6c5SArd Biesheuvel 
236dce48e35SArd Biesheuvel 	if (down_interruptible(&efi_runtime_lock))
237dce48e35SArd Biesheuvel 		return EFI_ABORTED;
2383eb420e7SSai Praneeth 	status = efi_queue_work(GET_TIME, tm, tc, NULL, NULL, NULL);
239dce48e35SArd Biesheuvel 	up(&efi_runtime_lock);
240022ee6c5SArd Biesheuvel 	return status;
241022ee6c5SArd Biesheuvel }
242022ee6c5SArd Biesheuvel 
243022ee6c5SArd Biesheuvel static efi_status_t virt_efi_set_time(efi_time_t *tm)
244022ee6c5SArd Biesheuvel {
245022ee6c5SArd Biesheuvel 	efi_status_t status;
246022ee6c5SArd Biesheuvel 
247dce48e35SArd Biesheuvel 	if (down_interruptible(&efi_runtime_lock))
248dce48e35SArd Biesheuvel 		return EFI_ABORTED;
2493eb420e7SSai Praneeth 	status = efi_queue_work(SET_TIME, tm, NULL, NULL, NULL, NULL);
250dce48e35SArd Biesheuvel 	up(&efi_runtime_lock);
251022ee6c5SArd Biesheuvel 	return status;
252022ee6c5SArd Biesheuvel }
253022ee6c5SArd Biesheuvel 
254022ee6c5SArd Biesheuvel static efi_status_t virt_efi_get_wakeup_time(efi_bool_t *enabled,
255022ee6c5SArd Biesheuvel 					     efi_bool_t *pending,
256022ee6c5SArd Biesheuvel 					     efi_time_t *tm)
257022ee6c5SArd Biesheuvel {
258022ee6c5SArd Biesheuvel 	efi_status_t status;
259022ee6c5SArd Biesheuvel 
260dce48e35SArd Biesheuvel 	if (down_interruptible(&efi_runtime_lock))
261dce48e35SArd Biesheuvel 		return EFI_ABORTED;
2623eb420e7SSai Praneeth 	status = efi_queue_work(GET_WAKEUP_TIME, enabled, pending, tm, NULL,
2633eb420e7SSai Praneeth 				NULL);
264dce48e35SArd Biesheuvel 	up(&efi_runtime_lock);
265022ee6c5SArd Biesheuvel 	return status;
266022ee6c5SArd Biesheuvel }
267022ee6c5SArd Biesheuvel 
268022ee6c5SArd Biesheuvel static efi_status_t virt_efi_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm)
269022ee6c5SArd Biesheuvel {
270022ee6c5SArd Biesheuvel 	efi_status_t status;
271022ee6c5SArd Biesheuvel 
272dce48e35SArd Biesheuvel 	if (down_interruptible(&efi_runtime_lock))
273dce48e35SArd Biesheuvel 		return EFI_ABORTED;
2743eb420e7SSai Praneeth 	status = efi_queue_work(SET_WAKEUP_TIME, &enabled, tm, NULL, NULL,
2753eb420e7SSai Praneeth 				NULL);
276dce48e35SArd Biesheuvel 	up(&efi_runtime_lock);
277022ee6c5SArd Biesheuvel 	return status;
278022ee6c5SArd Biesheuvel }
279022ee6c5SArd Biesheuvel 
280022ee6c5SArd Biesheuvel static efi_status_t virt_efi_get_variable(efi_char16_t *name,
281022ee6c5SArd Biesheuvel 					  efi_guid_t *vendor,
282022ee6c5SArd Biesheuvel 					  u32 *attr,
283022ee6c5SArd Biesheuvel 					  unsigned long *data_size,
284022ee6c5SArd Biesheuvel 					  void *data)
285022ee6c5SArd Biesheuvel {
286161485e8SArd Biesheuvel 	efi_status_t status;
287161485e8SArd Biesheuvel 
288dce48e35SArd Biesheuvel 	if (down_interruptible(&efi_runtime_lock))
289dce48e35SArd Biesheuvel 		return EFI_ABORTED;
2903eb420e7SSai Praneeth 	status = efi_queue_work(GET_VARIABLE, name, vendor, attr, data_size,
291161485e8SArd Biesheuvel 				data);
292dce48e35SArd Biesheuvel 	up(&efi_runtime_lock);
293161485e8SArd Biesheuvel 	return status;
294022ee6c5SArd Biesheuvel }
295022ee6c5SArd Biesheuvel 
296022ee6c5SArd Biesheuvel static efi_status_t virt_efi_get_next_variable(unsigned long *name_size,
297022ee6c5SArd Biesheuvel 					       efi_char16_t *name,
298022ee6c5SArd Biesheuvel 					       efi_guid_t *vendor)
299022ee6c5SArd Biesheuvel {
300161485e8SArd Biesheuvel 	efi_status_t status;
301161485e8SArd Biesheuvel 
302dce48e35SArd Biesheuvel 	if (down_interruptible(&efi_runtime_lock))
303dce48e35SArd Biesheuvel 		return EFI_ABORTED;
3043eb420e7SSai Praneeth 	status = efi_queue_work(GET_NEXT_VARIABLE, name_size, name, vendor,
3053eb420e7SSai Praneeth 				NULL, NULL);
306dce48e35SArd Biesheuvel 	up(&efi_runtime_lock);
307161485e8SArd Biesheuvel 	return status;
308022ee6c5SArd Biesheuvel }
309022ee6c5SArd Biesheuvel 
310022ee6c5SArd Biesheuvel static efi_status_t virt_efi_set_variable(efi_char16_t *name,
311022ee6c5SArd Biesheuvel 					  efi_guid_t *vendor,
312022ee6c5SArd Biesheuvel 					  u32 attr,
313022ee6c5SArd Biesheuvel 					  unsigned long data_size,
314022ee6c5SArd Biesheuvel 					  void *data)
315022ee6c5SArd Biesheuvel {
316161485e8SArd Biesheuvel 	efi_status_t status;
317161485e8SArd Biesheuvel 
318dce48e35SArd Biesheuvel 	if (down_interruptible(&efi_runtime_lock))
319dce48e35SArd Biesheuvel 		return EFI_ABORTED;
3203eb420e7SSai Praneeth 	status = efi_queue_work(SET_VARIABLE, name, vendor, &attr, &data_size,
321161485e8SArd Biesheuvel 				data);
322dce48e35SArd Biesheuvel 	up(&efi_runtime_lock);
323161485e8SArd Biesheuvel 	return status;
324022ee6c5SArd Biesheuvel }
325022ee6c5SArd Biesheuvel 
3266d80dba1SMatt Fleming static efi_status_t
3276d80dba1SMatt Fleming virt_efi_set_variable_nonblocking(efi_char16_t *name, efi_guid_t *vendor,
3286d80dba1SMatt Fleming 				  u32 attr, unsigned long data_size,
3296d80dba1SMatt Fleming 				  void *data)
3306d80dba1SMatt Fleming {
3316d80dba1SMatt Fleming 	efi_status_t status;
3326d80dba1SMatt Fleming 
333dce48e35SArd Biesheuvel 	if (down_trylock(&efi_runtime_lock))
3346d80dba1SMatt Fleming 		return EFI_NOT_READY;
3356d80dba1SMatt Fleming 
3366d80dba1SMatt Fleming 	status = efi_call_virt(set_variable, name, vendor, attr, data_size,
3376d80dba1SMatt Fleming 			       data);
338dce48e35SArd Biesheuvel 	up(&efi_runtime_lock);
3396d80dba1SMatt Fleming 	return status;
3406d80dba1SMatt Fleming }
3416d80dba1SMatt Fleming 
3426d80dba1SMatt Fleming 
343022ee6c5SArd Biesheuvel static efi_status_t virt_efi_query_variable_info(u32 attr,
344022ee6c5SArd Biesheuvel 						 u64 *storage_space,
345022ee6c5SArd Biesheuvel 						 u64 *remaining_space,
346022ee6c5SArd Biesheuvel 						 u64 *max_variable_size)
347022ee6c5SArd Biesheuvel {
348161485e8SArd Biesheuvel 	efi_status_t status;
349161485e8SArd Biesheuvel 
350022ee6c5SArd Biesheuvel 	if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION)
351022ee6c5SArd Biesheuvel 		return EFI_UNSUPPORTED;
352022ee6c5SArd Biesheuvel 
353dce48e35SArd Biesheuvel 	if (down_interruptible(&efi_runtime_lock))
354dce48e35SArd Biesheuvel 		return EFI_ABORTED;
3553eb420e7SSai Praneeth 	status = efi_queue_work(QUERY_VARIABLE_INFO, &attr, storage_space,
3563eb420e7SSai Praneeth 				remaining_space, max_variable_size, NULL);
357dce48e35SArd Biesheuvel 	up(&efi_runtime_lock);
358161485e8SArd Biesheuvel 	return status;
359022ee6c5SArd Biesheuvel }
360022ee6c5SArd Biesheuvel 
361d3cac1f8SArd Biesheuvel static efi_status_t
362d3cac1f8SArd Biesheuvel virt_efi_query_variable_info_nonblocking(u32 attr,
363d3cac1f8SArd Biesheuvel 					 u64 *storage_space,
364d3cac1f8SArd Biesheuvel 					 u64 *remaining_space,
365d3cac1f8SArd Biesheuvel 					 u64 *max_variable_size)
366d3cac1f8SArd Biesheuvel {
367d3cac1f8SArd Biesheuvel 	efi_status_t status;
368d3cac1f8SArd Biesheuvel 
369d3cac1f8SArd Biesheuvel 	if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION)
370d3cac1f8SArd Biesheuvel 		return EFI_UNSUPPORTED;
371d3cac1f8SArd Biesheuvel 
372dce48e35SArd Biesheuvel 	if (down_trylock(&efi_runtime_lock))
373d3cac1f8SArd Biesheuvel 		return EFI_NOT_READY;
374d3cac1f8SArd Biesheuvel 
375d3cac1f8SArd Biesheuvel 	status = efi_call_virt(query_variable_info, attr, storage_space,
376d3cac1f8SArd Biesheuvel 			       remaining_space, max_variable_size);
377dce48e35SArd Biesheuvel 	up(&efi_runtime_lock);
378d3cac1f8SArd Biesheuvel 	return status;
379d3cac1f8SArd Biesheuvel }
380d3cac1f8SArd Biesheuvel 
381022ee6c5SArd Biesheuvel static efi_status_t virt_efi_get_next_high_mono_count(u32 *count)
382022ee6c5SArd Biesheuvel {
383161485e8SArd Biesheuvel 	efi_status_t status;
384161485e8SArd Biesheuvel 
385dce48e35SArd Biesheuvel 	if (down_interruptible(&efi_runtime_lock))
386dce48e35SArd Biesheuvel 		return EFI_ABORTED;
3873eb420e7SSai Praneeth 	status = efi_queue_work(GET_NEXT_HIGH_MONO_COUNT, count, NULL, NULL,
3883eb420e7SSai Praneeth 				NULL, NULL);
389dce48e35SArd Biesheuvel 	up(&efi_runtime_lock);
390161485e8SArd Biesheuvel 	return status;
391022ee6c5SArd Biesheuvel }
392022ee6c5SArd Biesheuvel 
393022ee6c5SArd Biesheuvel static void virt_efi_reset_system(int reset_type,
394022ee6c5SArd Biesheuvel 				  efi_status_t status,
395022ee6c5SArd Biesheuvel 				  unsigned long data_size,
396022ee6c5SArd Biesheuvel 				  efi_char16_t *data)
397022ee6c5SArd Biesheuvel {
398dce48e35SArd Biesheuvel 	if (down_interruptible(&efi_runtime_lock)) {
399dce48e35SArd Biesheuvel 		pr_warn("failed to invoke the reset_system() runtime service:\n"
400dce48e35SArd Biesheuvel 			"could not get exclusive access to the firmware\n");
401dce48e35SArd Biesheuvel 		return;
402dce48e35SArd Biesheuvel 	}
4033425d934SSai Praneeth 	efi_rts_work.efi_rts_id = RESET_SYSTEM;
404022ee6c5SArd Biesheuvel 	__efi_call_virt(reset_system, reset_type, status, data_size, data);
405dce48e35SArd Biesheuvel 	up(&efi_runtime_lock);
406022ee6c5SArd Biesheuvel }
407022ee6c5SArd Biesheuvel 
408022ee6c5SArd Biesheuvel static efi_status_t virt_efi_update_capsule(efi_capsule_header_t **capsules,
409022ee6c5SArd Biesheuvel 					    unsigned long count,
410022ee6c5SArd Biesheuvel 					    unsigned long sg_list)
411022ee6c5SArd Biesheuvel {
412161485e8SArd Biesheuvel 	efi_status_t status;
413161485e8SArd Biesheuvel 
414022ee6c5SArd Biesheuvel 	if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION)
415022ee6c5SArd Biesheuvel 		return EFI_UNSUPPORTED;
416022ee6c5SArd Biesheuvel 
417dce48e35SArd Biesheuvel 	if (down_interruptible(&efi_runtime_lock))
418dce48e35SArd Biesheuvel 		return EFI_ABORTED;
4193eb420e7SSai Praneeth 	status = efi_queue_work(UPDATE_CAPSULE, capsules, &count, &sg_list,
4203eb420e7SSai Praneeth 				NULL, NULL);
421dce48e35SArd Biesheuvel 	up(&efi_runtime_lock);
422161485e8SArd Biesheuvel 	return status;
423022ee6c5SArd Biesheuvel }
424022ee6c5SArd Biesheuvel 
425022ee6c5SArd Biesheuvel static efi_status_t virt_efi_query_capsule_caps(efi_capsule_header_t **capsules,
426022ee6c5SArd Biesheuvel 						unsigned long count,
427022ee6c5SArd Biesheuvel 						u64 *max_size,
428022ee6c5SArd Biesheuvel 						int *reset_type)
429022ee6c5SArd Biesheuvel {
430161485e8SArd Biesheuvel 	efi_status_t status;
431161485e8SArd Biesheuvel 
432022ee6c5SArd Biesheuvel 	if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION)
433022ee6c5SArd Biesheuvel 		return EFI_UNSUPPORTED;
434022ee6c5SArd Biesheuvel 
435dce48e35SArd Biesheuvel 	if (down_interruptible(&efi_runtime_lock))
436dce48e35SArd Biesheuvel 		return EFI_ABORTED;
4373eb420e7SSai Praneeth 	status = efi_queue_work(QUERY_CAPSULE_CAPS, capsules, &count,
4383eb420e7SSai Praneeth 				max_size, reset_type, NULL);
439dce48e35SArd Biesheuvel 	up(&efi_runtime_lock);
440161485e8SArd Biesheuvel 	return status;
441022ee6c5SArd Biesheuvel }
442022ee6c5SArd Biesheuvel 
443022ee6c5SArd Biesheuvel void efi_native_runtime_setup(void)
444022ee6c5SArd Biesheuvel {
445022ee6c5SArd Biesheuvel 	efi.get_time = virt_efi_get_time;
446022ee6c5SArd Biesheuvel 	efi.set_time = virt_efi_set_time;
447022ee6c5SArd Biesheuvel 	efi.get_wakeup_time = virt_efi_get_wakeup_time;
448022ee6c5SArd Biesheuvel 	efi.set_wakeup_time = virt_efi_set_wakeup_time;
449022ee6c5SArd Biesheuvel 	efi.get_variable = virt_efi_get_variable;
450022ee6c5SArd Biesheuvel 	efi.get_next_variable = virt_efi_get_next_variable;
451022ee6c5SArd Biesheuvel 	efi.set_variable = virt_efi_set_variable;
4526d80dba1SMatt Fleming 	efi.set_variable_nonblocking = virt_efi_set_variable_nonblocking;
453022ee6c5SArd Biesheuvel 	efi.get_next_high_mono_count = virt_efi_get_next_high_mono_count;
454022ee6c5SArd Biesheuvel 	efi.reset_system = virt_efi_reset_system;
455022ee6c5SArd Biesheuvel 	efi.query_variable_info = virt_efi_query_variable_info;
456d3cac1f8SArd Biesheuvel 	efi.query_variable_info_nonblocking = virt_efi_query_variable_info_nonblocking;
457022ee6c5SArd Biesheuvel 	efi.update_capsule = virt_efi_update_capsule;
458022ee6c5SArd Biesheuvel 	efi.query_capsule_caps = virt_efi_query_capsule_caps;
459022ee6c5SArd Biesheuvel }
460