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);			\
70ef1491e7SWaiman Long 	INIT_WORK(&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 /*
150f331e766SHedi Berriche  * Expose the EFI runtime lock to the UV platform
151f331e766SHedi Berriche  */
152f331e766SHedi Berriche #ifdef CONFIG_X86_UV
153f331e766SHedi Berriche extern struct semaphore __efi_uv_runtime_lock __alias(efi_runtime_lock);
154f331e766SHedi Berriche #endif
155f331e766SHedi Berriche 
156f331e766SHedi Berriche /*
1573eb420e7SSai Praneeth  * Calls the appropriate efi_runtime_service() with the appropriate
1583eb420e7SSai Praneeth  * arguments.
1593eb420e7SSai Praneeth  *
1603eb420e7SSai Praneeth  * Semantics followed by efi_call_rts() to understand efi_runtime_work:
1613eb420e7SSai Praneeth  * 1. If argument was a pointer, recast it from void pointer to original
1623eb420e7SSai Praneeth  * pointer type.
1633eb420e7SSai Praneeth  * 2. If argument was a value, recast it from void pointer to original
1643eb420e7SSai Praneeth  * pointer type and dereference it.
1653eb420e7SSai Praneeth  */
1663eb420e7SSai Praneeth static void efi_call_rts(struct work_struct *work)
1673eb420e7SSai Praneeth {
1683eb420e7SSai Praneeth 	void *arg1, *arg2, *arg3, *arg4, *arg5;
1693eb420e7SSai Praneeth 	efi_status_t status = EFI_NOT_FOUND;
1703eb420e7SSai Praneeth 
1719dbbedaaSSai Praneeth 	arg1 = efi_rts_work.arg1;
1729dbbedaaSSai Praneeth 	arg2 = efi_rts_work.arg2;
1739dbbedaaSSai Praneeth 	arg3 = efi_rts_work.arg3;
1749dbbedaaSSai Praneeth 	arg4 = efi_rts_work.arg4;
1759dbbedaaSSai Praneeth 	arg5 = efi_rts_work.arg5;
1763eb420e7SSai Praneeth 
1779dbbedaaSSai Praneeth 	switch (efi_rts_work.efi_rts_id) {
1783eb420e7SSai Praneeth 	case GET_TIME:
1793eb420e7SSai Praneeth 		status = efi_call_virt(get_time, (efi_time_t *)arg1,
1803eb420e7SSai Praneeth 				       (efi_time_cap_t *)arg2);
1813eb420e7SSai Praneeth 		break;
1823eb420e7SSai Praneeth 	case SET_TIME:
1833eb420e7SSai Praneeth 		status = efi_call_virt(set_time, (efi_time_t *)arg1);
1843eb420e7SSai Praneeth 		break;
1853eb420e7SSai Praneeth 	case GET_WAKEUP_TIME:
1863eb420e7SSai Praneeth 		status = efi_call_virt(get_wakeup_time, (efi_bool_t *)arg1,
1873eb420e7SSai Praneeth 				       (efi_bool_t *)arg2, (efi_time_t *)arg3);
1883eb420e7SSai Praneeth 		break;
1893eb420e7SSai Praneeth 	case SET_WAKEUP_TIME:
1903eb420e7SSai Praneeth 		status = efi_call_virt(set_wakeup_time, *(efi_bool_t *)arg1,
1913eb420e7SSai Praneeth 				       (efi_time_t *)arg2);
1923eb420e7SSai Praneeth 		break;
1933eb420e7SSai Praneeth 	case GET_VARIABLE:
1943eb420e7SSai Praneeth 		status = efi_call_virt(get_variable, (efi_char16_t *)arg1,
1953eb420e7SSai Praneeth 				       (efi_guid_t *)arg2, (u32 *)arg3,
1963eb420e7SSai Praneeth 				       (unsigned long *)arg4, (void *)arg5);
1973eb420e7SSai Praneeth 		break;
1983eb420e7SSai Praneeth 	case GET_NEXT_VARIABLE:
1993eb420e7SSai Praneeth 		status = efi_call_virt(get_next_variable, (unsigned long *)arg1,
2003eb420e7SSai Praneeth 				       (efi_char16_t *)arg2,
2013eb420e7SSai Praneeth 				       (efi_guid_t *)arg3);
2023eb420e7SSai Praneeth 		break;
2033eb420e7SSai Praneeth 	case SET_VARIABLE:
2043eb420e7SSai Praneeth 		status = efi_call_virt(set_variable, (efi_char16_t *)arg1,
2053eb420e7SSai Praneeth 				       (efi_guid_t *)arg2, *(u32 *)arg3,
2063eb420e7SSai Praneeth 				       *(unsigned long *)arg4, (void *)arg5);
2073eb420e7SSai Praneeth 		break;
2083eb420e7SSai Praneeth 	case QUERY_VARIABLE_INFO:
2093eb420e7SSai Praneeth 		status = efi_call_virt(query_variable_info, *(u32 *)arg1,
2103eb420e7SSai Praneeth 				       (u64 *)arg2, (u64 *)arg3, (u64 *)arg4);
2113eb420e7SSai Praneeth 		break;
2123eb420e7SSai Praneeth 	case GET_NEXT_HIGH_MONO_COUNT:
2133eb420e7SSai Praneeth 		status = efi_call_virt(get_next_high_mono_count, (u32 *)arg1);
2143eb420e7SSai Praneeth 		break;
2153eb420e7SSai Praneeth 	case UPDATE_CAPSULE:
2163eb420e7SSai Praneeth 		status = efi_call_virt(update_capsule,
2173eb420e7SSai Praneeth 				       (efi_capsule_header_t **)arg1,
2183eb420e7SSai Praneeth 				       *(unsigned long *)arg2,
2193eb420e7SSai Praneeth 				       *(unsigned long *)arg3);
2203eb420e7SSai Praneeth 		break;
2213eb420e7SSai Praneeth 	case QUERY_CAPSULE_CAPS:
2223eb420e7SSai Praneeth 		status = efi_call_virt(query_capsule_caps,
2233eb420e7SSai Praneeth 				       (efi_capsule_header_t **)arg1,
2243eb420e7SSai Praneeth 				       *(unsigned long *)arg2, (u64 *)arg3,
2253eb420e7SSai Praneeth 				       (int *)arg4);
2263eb420e7SSai Praneeth 		break;
2273eb420e7SSai Praneeth 	default:
2283eb420e7SSai Praneeth 		/*
2293eb420e7SSai Praneeth 		 * Ideally, we should never reach here because a caller of this
2303eb420e7SSai Praneeth 		 * function should have put the right efi_runtime_service()
2313eb420e7SSai Praneeth 		 * function identifier into efi_rts_work->efi_rts_id
2323eb420e7SSai Praneeth 		 */
2333eb420e7SSai Praneeth 		pr_err("Requested executing invalid EFI Runtime Service.\n");
2343eb420e7SSai Praneeth 	}
2359dbbedaaSSai Praneeth 	efi_rts_work.status = status;
2369dbbedaaSSai Praneeth 	complete(&efi_rts_work.efi_rts_comp);
2373eb420e7SSai Praneeth }
2383eb420e7SSai Praneeth 
239022ee6c5SArd Biesheuvel static efi_status_t virt_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc)
240022ee6c5SArd Biesheuvel {
241022ee6c5SArd Biesheuvel 	efi_status_t status;
242022ee6c5SArd Biesheuvel 
243dce48e35SArd Biesheuvel 	if (down_interruptible(&efi_runtime_lock))
244dce48e35SArd Biesheuvel 		return EFI_ABORTED;
2453eb420e7SSai Praneeth 	status = efi_queue_work(GET_TIME, tm, tc, NULL, NULL, NULL);
246dce48e35SArd Biesheuvel 	up(&efi_runtime_lock);
247022ee6c5SArd Biesheuvel 	return status;
248022ee6c5SArd Biesheuvel }
249022ee6c5SArd Biesheuvel 
250022ee6c5SArd Biesheuvel static efi_status_t virt_efi_set_time(efi_time_t *tm)
251022ee6c5SArd Biesheuvel {
252022ee6c5SArd Biesheuvel 	efi_status_t status;
253022ee6c5SArd Biesheuvel 
254dce48e35SArd Biesheuvel 	if (down_interruptible(&efi_runtime_lock))
255dce48e35SArd Biesheuvel 		return EFI_ABORTED;
2563eb420e7SSai Praneeth 	status = efi_queue_work(SET_TIME, tm, NULL, NULL, NULL, NULL);
257dce48e35SArd Biesheuvel 	up(&efi_runtime_lock);
258022ee6c5SArd Biesheuvel 	return status;
259022ee6c5SArd Biesheuvel }
260022ee6c5SArd Biesheuvel 
261022ee6c5SArd Biesheuvel static efi_status_t virt_efi_get_wakeup_time(efi_bool_t *enabled,
262022ee6c5SArd Biesheuvel 					     efi_bool_t *pending,
263022ee6c5SArd Biesheuvel 					     efi_time_t *tm)
264022ee6c5SArd Biesheuvel {
265022ee6c5SArd Biesheuvel 	efi_status_t status;
266022ee6c5SArd Biesheuvel 
267dce48e35SArd Biesheuvel 	if (down_interruptible(&efi_runtime_lock))
268dce48e35SArd Biesheuvel 		return EFI_ABORTED;
2693eb420e7SSai Praneeth 	status = efi_queue_work(GET_WAKEUP_TIME, enabled, pending, tm, NULL,
2703eb420e7SSai Praneeth 				NULL);
271dce48e35SArd Biesheuvel 	up(&efi_runtime_lock);
272022ee6c5SArd Biesheuvel 	return status;
273022ee6c5SArd Biesheuvel }
274022ee6c5SArd Biesheuvel 
275022ee6c5SArd Biesheuvel static efi_status_t virt_efi_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm)
276022ee6c5SArd Biesheuvel {
277022ee6c5SArd Biesheuvel 	efi_status_t status;
278022ee6c5SArd Biesheuvel 
279dce48e35SArd Biesheuvel 	if (down_interruptible(&efi_runtime_lock))
280dce48e35SArd Biesheuvel 		return EFI_ABORTED;
2813eb420e7SSai Praneeth 	status = efi_queue_work(SET_WAKEUP_TIME, &enabled, tm, NULL, NULL,
2823eb420e7SSai Praneeth 				NULL);
283dce48e35SArd Biesheuvel 	up(&efi_runtime_lock);
284022ee6c5SArd Biesheuvel 	return status;
285022ee6c5SArd Biesheuvel }
286022ee6c5SArd Biesheuvel 
287022ee6c5SArd Biesheuvel static efi_status_t virt_efi_get_variable(efi_char16_t *name,
288022ee6c5SArd Biesheuvel 					  efi_guid_t *vendor,
289022ee6c5SArd Biesheuvel 					  u32 *attr,
290022ee6c5SArd Biesheuvel 					  unsigned long *data_size,
291022ee6c5SArd Biesheuvel 					  void *data)
292022ee6c5SArd Biesheuvel {
293161485e8SArd Biesheuvel 	efi_status_t status;
294161485e8SArd Biesheuvel 
295dce48e35SArd Biesheuvel 	if (down_interruptible(&efi_runtime_lock))
296dce48e35SArd Biesheuvel 		return EFI_ABORTED;
2973eb420e7SSai Praneeth 	status = efi_queue_work(GET_VARIABLE, name, vendor, attr, data_size,
298161485e8SArd Biesheuvel 				data);
299dce48e35SArd Biesheuvel 	up(&efi_runtime_lock);
300161485e8SArd Biesheuvel 	return status;
301022ee6c5SArd Biesheuvel }
302022ee6c5SArd Biesheuvel 
303022ee6c5SArd Biesheuvel static efi_status_t virt_efi_get_next_variable(unsigned long *name_size,
304022ee6c5SArd Biesheuvel 					       efi_char16_t *name,
305022ee6c5SArd Biesheuvel 					       efi_guid_t *vendor)
306022ee6c5SArd Biesheuvel {
307161485e8SArd Biesheuvel 	efi_status_t status;
308161485e8SArd Biesheuvel 
309dce48e35SArd Biesheuvel 	if (down_interruptible(&efi_runtime_lock))
310dce48e35SArd Biesheuvel 		return EFI_ABORTED;
3113eb420e7SSai Praneeth 	status = efi_queue_work(GET_NEXT_VARIABLE, name_size, name, vendor,
3123eb420e7SSai Praneeth 				NULL, NULL);
313dce48e35SArd Biesheuvel 	up(&efi_runtime_lock);
314161485e8SArd Biesheuvel 	return status;
315022ee6c5SArd Biesheuvel }
316022ee6c5SArd Biesheuvel 
317022ee6c5SArd Biesheuvel static efi_status_t virt_efi_set_variable(efi_char16_t *name,
318022ee6c5SArd Biesheuvel 					  efi_guid_t *vendor,
319022ee6c5SArd Biesheuvel 					  u32 attr,
320022ee6c5SArd Biesheuvel 					  unsigned long data_size,
321022ee6c5SArd Biesheuvel 					  void *data)
322022ee6c5SArd Biesheuvel {
323161485e8SArd Biesheuvel 	efi_status_t status;
324161485e8SArd Biesheuvel 
325dce48e35SArd Biesheuvel 	if (down_interruptible(&efi_runtime_lock))
326dce48e35SArd Biesheuvel 		return EFI_ABORTED;
3273eb420e7SSai Praneeth 	status = efi_queue_work(SET_VARIABLE, name, vendor, &attr, &data_size,
328161485e8SArd Biesheuvel 				data);
329dce48e35SArd Biesheuvel 	up(&efi_runtime_lock);
330161485e8SArd Biesheuvel 	return status;
331022ee6c5SArd Biesheuvel }
332022ee6c5SArd Biesheuvel 
3336d80dba1SMatt Fleming static efi_status_t
3346d80dba1SMatt Fleming virt_efi_set_variable_nonblocking(efi_char16_t *name, efi_guid_t *vendor,
3356d80dba1SMatt Fleming 				  u32 attr, unsigned long data_size,
3366d80dba1SMatt Fleming 				  void *data)
3376d80dba1SMatt Fleming {
3386d80dba1SMatt Fleming 	efi_status_t status;
3396d80dba1SMatt Fleming 
340dce48e35SArd Biesheuvel 	if (down_trylock(&efi_runtime_lock))
3416d80dba1SMatt Fleming 		return EFI_NOT_READY;
3426d80dba1SMatt Fleming 
3436d80dba1SMatt Fleming 	status = efi_call_virt(set_variable, name, vendor, attr, data_size,
3446d80dba1SMatt Fleming 			       data);
345dce48e35SArd Biesheuvel 	up(&efi_runtime_lock);
3466d80dba1SMatt Fleming 	return status;
3476d80dba1SMatt Fleming }
3486d80dba1SMatt Fleming 
3496d80dba1SMatt Fleming 
350022ee6c5SArd Biesheuvel static efi_status_t virt_efi_query_variable_info(u32 attr,
351022ee6c5SArd Biesheuvel 						 u64 *storage_space,
352022ee6c5SArd Biesheuvel 						 u64 *remaining_space,
353022ee6c5SArd Biesheuvel 						 u64 *max_variable_size)
354022ee6c5SArd Biesheuvel {
355161485e8SArd Biesheuvel 	efi_status_t status;
356161485e8SArd Biesheuvel 
357022ee6c5SArd Biesheuvel 	if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION)
358022ee6c5SArd Biesheuvel 		return EFI_UNSUPPORTED;
359022ee6c5SArd Biesheuvel 
360dce48e35SArd Biesheuvel 	if (down_interruptible(&efi_runtime_lock))
361dce48e35SArd Biesheuvel 		return EFI_ABORTED;
3623eb420e7SSai Praneeth 	status = efi_queue_work(QUERY_VARIABLE_INFO, &attr, storage_space,
3633eb420e7SSai Praneeth 				remaining_space, max_variable_size, NULL);
364dce48e35SArd Biesheuvel 	up(&efi_runtime_lock);
365161485e8SArd Biesheuvel 	return status;
366022ee6c5SArd Biesheuvel }
367022ee6c5SArd Biesheuvel 
368d3cac1f8SArd Biesheuvel static efi_status_t
369d3cac1f8SArd Biesheuvel virt_efi_query_variable_info_nonblocking(u32 attr,
370d3cac1f8SArd Biesheuvel 					 u64 *storage_space,
371d3cac1f8SArd Biesheuvel 					 u64 *remaining_space,
372d3cac1f8SArd Biesheuvel 					 u64 *max_variable_size)
373d3cac1f8SArd Biesheuvel {
374d3cac1f8SArd Biesheuvel 	efi_status_t status;
375d3cac1f8SArd Biesheuvel 
376d3cac1f8SArd Biesheuvel 	if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION)
377d3cac1f8SArd Biesheuvel 		return EFI_UNSUPPORTED;
378d3cac1f8SArd Biesheuvel 
379dce48e35SArd Biesheuvel 	if (down_trylock(&efi_runtime_lock))
380d3cac1f8SArd Biesheuvel 		return EFI_NOT_READY;
381d3cac1f8SArd Biesheuvel 
382d3cac1f8SArd Biesheuvel 	status = efi_call_virt(query_variable_info, attr, storage_space,
383d3cac1f8SArd Biesheuvel 			       remaining_space, max_variable_size);
384dce48e35SArd Biesheuvel 	up(&efi_runtime_lock);
385d3cac1f8SArd Biesheuvel 	return status;
386d3cac1f8SArd Biesheuvel }
387d3cac1f8SArd Biesheuvel 
388022ee6c5SArd Biesheuvel static efi_status_t virt_efi_get_next_high_mono_count(u32 *count)
389022ee6c5SArd Biesheuvel {
390161485e8SArd Biesheuvel 	efi_status_t status;
391161485e8SArd Biesheuvel 
392dce48e35SArd Biesheuvel 	if (down_interruptible(&efi_runtime_lock))
393dce48e35SArd Biesheuvel 		return EFI_ABORTED;
3943eb420e7SSai Praneeth 	status = efi_queue_work(GET_NEXT_HIGH_MONO_COUNT, count, NULL, NULL,
3953eb420e7SSai Praneeth 				NULL, NULL);
396dce48e35SArd Biesheuvel 	up(&efi_runtime_lock);
397161485e8SArd Biesheuvel 	return status;
398022ee6c5SArd Biesheuvel }
399022ee6c5SArd Biesheuvel 
400022ee6c5SArd Biesheuvel static void virt_efi_reset_system(int reset_type,
401022ee6c5SArd Biesheuvel 				  efi_status_t status,
402022ee6c5SArd Biesheuvel 				  unsigned long data_size,
403022ee6c5SArd Biesheuvel 				  efi_char16_t *data)
404022ee6c5SArd Biesheuvel {
405dce48e35SArd Biesheuvel 	if (down_interruptible(&efi_runtime_lock)) {
406dce48e35SArd Biesheuvel 		pr_warn("failed to invoke the reset_system() runtime service:\n"
407dce48e35SArd Biesheuvel 			"could not get exclusive access to the firmware\n");
408dce48e35SArd Biesheuvel 		return;
409dce48e35SArd Biesheuvel 	}
4103425d934SSai Praneeth 	efi_rts_work.efi_rts_id = RESET_SYSTEM;
411022ee6c5SArd Biesheuvel 	__efi_call_virt(reset_system, reset_type, status, data_size, data);
412dce48e35SArd Biesheuvel 	up(&efi_runtime_lock);
413022ee6c5SArd Biesheuvel }
414022ee6c5SArd Biesheuvel 
415022ee6c5SArd Biesheuvel static efi_status_t virt_efi_update_capsule(efi_capsule_header_t **capsules,
416022ee6c5SArd Biesheuvel 					    unsigned long count,
417022ee6c5SArd Biesheuvel 					    unsigned long sg_list)
418022ee6c5SArd Biesheuvel {
419161485e8SArd Biesheuvel 	efi_status_t status;
420161485e8SArd Biesheuvel 
421022ee6c5SArd Biesheuvel 	if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION)
422022ee6c5SArd Biesheuvel 		return EFI_UNSUPPORTED;
423022ee6c5SArd Biesheuvel 
424dce48e35SArd Biesheuvel 	if (down_interruptible(&efi_runtime_lock))
425dce48e35SArd Biesheuvel 		return EFI_ABORTED;
4263eb420e7SSai Praneeth 	status = efi_queue_work(UPDATE_CAPSULE, capsules, &count, &sg_list,
4273eb420e7SSai Praneeth 				NULL, NULL);
428dce48e35SArd Biesheuvel 	up(&efi_runtime_lock);
429161485e8SArd Biesheuvel 	return status;
430022ee6c5SArd Biesheuvel }
431022ee6c5SArd Biesheuvel 
432022ee6c5SArd Biesheuvel static efi_status_t virt_efi_query_capsule_caps(efi_capsule_header_t **capsules,
433022ee6c5SArd Biesheuvel 						unsigned long count,
434022ee6c5SArd Biesheuvel 						u64 *max_size,
435022ee6c5SArd Biesheuvel 						int *reset_type)
436022ee6c5SArd Biesheuvel {
437161485e8SArd Biesheuvel 	efi_status_t status;
438161485e8SArd Biesheuvel 
439022ee6c5SArd Biesheuvel 	if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION)
440022ee6c5SArd Biesheuvel 		return EFI_UNSUPPORTED;
441022ee6c5SArd Biesheuvel 
442dce48e35SArd Biesheuvel 	if (down_interruptible(&efi_runtime_lock))
443dce48e35SArd Biesheuvel 		return EFI_ABORTED;
4443eb420e7SSai Praneeth 	status = efi_queue_work(QUERY_CAPSULE_CAPS, capsules, &count,
4453eb420e7SSai Praneeth 				max_size, reset_type, NULL);
446dce48e35SArd Biesheuvel 	up(&efi_runtime_lock);
447161485e8SArd Biesheuvel 	return status;
448022ee6c5SArd Biesheuvel }
449022ee6c5SArd Biesheuvel 
450022ee6c5SArd Biesheuvel void efi_native_runtime_setup(void)
451022ee6c5SArd Biesheuvel {
452022ee6c5SArd Biesheuvel 	efi.get_time = virt_efi_get_time;
453022ee6c5SArd Biesheuvel 	efi.set_time = virt_efi_set_time;
454022ee6c5SArd Biesheuvel 	efi.get_wakeup_time = virt_efi_get_wakeup_time;
455022ee6c5SArd Biesheuvel 	efi.set_wakeup_time = virt_efi_set_wakeup_time;
456022ee6c5SArd Biesheuvel 	efi.get_variable = virt_efi_get_variable;
457022ee6c5SArd Biesheuvel 	efi.get_next_variable = virt_efi_get_next_variable;
458022ee6c5SArd Biesheuvel 	efi.set_variable = virt_efi_set_variable;
4596d80dba1SMatt Fleming 	efi.set_variable_nonblocking = virt_efi_set_variable_nonblocking;
460022ee6c5SArd Biesheuvel 	efi.get_next_high_mono_count = virt_efi_get_next_high_mono_count;
461022ee6c5SArd Biesheuvel 	efi.reset_system = virt_efi_reset_system;
462022ee6c5SArd Biesheuvel 	efi.query_variable_info = virt_efi_query_variable_info;
463d3cac1f8SArd Biesheuvel 	efi.query_variable_info_nonblocking = virt_efi_query_variable_info_nonblocking;
464022ee6c5SArd Biesheuvel 	efi.update_capsule = virt_efi_update_capsule;
465022ee6c5SArd Biesheuvel 	efi.query_capsule_caps = virt_efi_query_capsule_caps;
466022ee6c5SArd Biesheuvel }
467