1 // SPDX-License-Identifier: GPL-2.0+
3 * Originally from efivars.c
5 * Copyright (C) 2001,2003,2004 Dell <Matt_Domsch@dell.com>
6 * Copyright (C) 2004 Intel Corporation <matthew.e.tolentino@intel.com>
9 #define pr_fmt(fmt) "efivars: " fmt
11 #include <linux/types.h>
12 #include <linux/sizes.h>
13 #include <linux/errno.h>
14 #include <linux/init.h>
15 #include <linux/module.h>
16 #include <linux/string.h>
17 #include <linux/smp.h>
18 #include <linux/efi.h>
19 #include <linux/ucs2_string.h>
21 /* Private pointer to registered efivars */
22 static struct efivars
*__efivars
;
24 static DEFINE_SEMAPHORE(efivars_lock
, 1);
26 static efi_status_t
check_var_size(bool nonblocking
, u32 attributes
,
29 const struct efivar_operations
*fops
;
32 fops
= __efivars
->ops
;
34 if (!fops
->query_variable_store
)
35 status
= EFI_UNSUPPORTED
;
37 status
= fops
->query_variable_store(attributes
, size
,
39 if (status
== EFI_UNSUPPORTED
)
40 return (size
<= SZ_64K
) ? EFI_SUCCESS
: EFI_OUT_OF_RESOURCES
;
45 * efivar_is_available - check if efivars is available
47 * @return true iff evivars is currently registered
49 bool efivar_is_available(void)
51 return __efivars
!= NULL
;
53 EXPORT_SYMBOL_GPL(efivar_is_available
);
56 * efivars_register - register an efivars
57 * @efivars: efivars to register
58 * @ops: efivars operations
60 * Only a single efivars can be registered at any time.
62 int efivars_register(struct efivars
*efivars
,
63 const struct efivar_operations
*ops
)
68 if (down_interruptible(&efivars_lock
))
72 pr_warn("efivars already registered\n");
81 if (efivar_supports_writes())
82 event
= EFIVAR_OPS_RDWR
;
84 event
= EFIVAR_OPS_RDONLY
;
86 blocking_notifier_call_chain(&efivar_ops_nh
, event
, NULL
);
88 pr_info("Registered efivars operations\n");
95 EXPORT_SYMBOL_GPL(efivars_register
);
98 * efivars_unregister - unregister an efivars
99 * @efivars: efivars to unregister
101 * The caller must have already removed every entry from the list,
102 * failure to do so is an error.
104 int efivars_unregister(struct efivars
*efivars
)
108 if (down_interruptible(&efivars_lock
))
112 pr_err("efivars not registered\n");
117 if (__efivars
!= efivars
) {
122 pr_info("Unregistered efivars operations\n");
130 EXPORT_SYMBOL_GPL(efivars_unregister
);
132 bool efivar_supports_writes(void)
134 return __efivars
&& __efivars
->ops
->set_variable
;
136 EXPORT_SYMBOL_GPL(efivar_supports_writes
);
139 * efivar_lock() - obtain the efivar lock, wait for it if needed
140 * @return 0 on success, error code on failure
142 int efivar_lock(void)
144 if (down_interruptible(&efivars_lock
))
146 if (!__efivars
->ops
) {
152 EXPORT_SYMBOL_NS_GPL(efivar_lock
, "EFIVAR");
155 * efivar_lock() - obtain the efivar lock if it is free
156 * @return 0 on success, error code on failure
158 int efivar_trylock(void)
160 if (down_trylock(&efivars_lock
))
162 if (!__efivars
->ops
) {
168 EXPORT_SYMBOL_NS_GPL(efivar_trylock
, "EFIVAR");
171 * efivar_unlock() - release the efivar lock
173 void efivar_unlock(void)
177 EXPORT_SYMBOL_NS_GPL(efivar_unlock
, "EFIVAR");
180 * efivar_get_variable() - retrieve a variable identified by name/vendor
182 * Must be called with efivars_lock held.
184 efi_status_t
efivar_get_variable(efi_char16_t
*name
, efi_guid_t
*vendor
,
185 u32
*attr
, unsigned long *size
, void *data
)
187 return __efivars
->ops
->get_variable(name
, vendor
, attr
, size
, data
);
189 EXPORT_SYMBOL_NS_GPL(efivar_get_variable
, "EFIVAR");
192 * efivar_get_next_variable() - enumerate the next name/vendor pair
194 * Must be called with efivars_lock held.
196 efi_status_t
efivar_get_next_variable(unsigned long *name_size
,
197 efi_char16_t
*name
, efi_guid_t
*vendor
)
199 return __efivars
->ops
->get_next_variable(name_size
, name
, vendor
);
201 EXPORT_SYMBOL_NS_GPL(efivar_get_next_variable
, "EFIVAR");
204 * efivar_set_variable_locked() - set a variable identified by name/vendor
206 * Must be called with efivars_lock held. If @nonblocking is set, it will use
207 * non-blocking primitives so it is guaranteed not to sleep.
209 efi_status_t
efivar_set_variable_locked(efi_char16_t
*name
, efi_guid_t
*vendor
,
210 u32 attr
, unsigned long data_size
,
211 void *data
, bool nonblocking
)
213 efi_set_variable_t
*setvar
;
217 status
= check_var_size(nonblocking
, attr
,
218 data_size
+ ucs2_strsize(name
, EFI_VAR_NAME_LEN
));
219 if (status
!= EFI_SUCCESS
)
224 * If no _nonblocking variant exists, the ordinary one
225 * is assumed to be non-blocking.
227 setvar
= __efivars
->ops
->set_variable_nonblocking
;
228 if (!setvar
|| !nonblocking
)
229 setvar
= __efivars
->ops
->set_variable
;
231 return setvar(name
, vendor
, attr
, data_size
, data
);
233 EXPORT_SYMBOL_NS_GPL(efivar_set_variable_locked
, "EFIVAR");
236 * efivar_set_variable() - set a variable identified by name/vendor
238 * Can be called without holding the efivars_lock. Will sleep on obtaining the
239 * lock, or on obtaining other locks that are needed in order to complete the
242 efi_status_t
efivar_set_variable(efi_char16_t
*name
, efi_guid_t
*vendor
,
243 u32 attr
, unsigned long data_size
, void *data
)
250 status
= efivar_set_variable_locked(name
, vendor
, attr
, data_size
,
255 EXPORT_SYMBOL_NS_GPL(efivar_set_variable
, "EFIVAR");
257 efi_status_t
efivar_query_variable_info(u32 attr
,
259 u64
*remaining_space
,
260 u64
*max_variable_size
)
262 if (!__efivars
->ops
->query_variable_info
)
263 return EFI_UNSUPPORTED
;
264 return __efivars
->ops
->query_variable_info(attr
, storage_space
,
265 remaining_space
, max_variable_size
);
267 EXPORT_SYMBOL_NS_GPL(efivar_query_variable_info
, "EFIVAR");