1 // SPDX-License-Identifier: GPL-2.0+
3 * Originally from efivars.c
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)
67 if (down_interruptible(&efivars_lock))
71 pr_warn("efivars already registered\n");
80 pr_info("Registered efivars operations\n");
87 EXPORT_SYMBOL_GPL(efivars_register);
90 * efivars_unregister - unregister an efivars
91 * @efivars: efivars to unregister
93 * The caller must have already removed every entry from the list,
94 * failure to do so is an error.
96 int efivars_unregister(struct efivars *efivars)
100 if (down_interruptible(&efivars_lock))
104 pr_err("efivars not registered\n");
109 if (__efivars != efivars) {
114 pr_info("Unregistered efivars operations\n");
122 EXPORT_SYMBOL_GPL(efivars_unregister);
124 bool efivar_supports_writes(void)
126 return __efivars && __efivars->ops->set_variable;
128 EXPORT_SYMBOL_GPL(efivar_supports_writes);
131 * efivar_lock() - obtain the efivar lock, wait for it if needed
132 * @return 0 on success, error code on failure
134 int efivar_lock(void)
136 if (down_interruptible(&efivars_lock))
138 if (!__efivars->ops) {
144 EXPORT_SYMBOL_NS_GPL(efivar_lock, EFIVAR);
147 * efivar_lock() - obtain the efivar lock if it is free
148 * @return 0 on success, error code on failure
150 int efivar_trylock(void)
152 if (down_trylock(&efivars_lock))
154 if (!__efivars->ops) {
160 EXPORT_SYMBOL_NS_GPL(efivar_trylock, EFIVAR);
163 * efivar_unlock() - release the efivar lock
165 void efivar_unlock(void)
169 EXPORT_SYMBOL_NS_GPL(efivar_unlock, EFIVAR);
172 * efivar_get_variable() - retrieve a variable identified by name/vendor
174 * Must be called with efivars_lock held.
176 efi_status_t efivar_get_variable(efi_char16_t *name, efi_guid_t *vendor,
177 u32 *attr, unsigned long *size, void *data)
179 return __efivars->ops->get_variable(name, vendor, attr, size, data);
181 EXPORT_SYMBOL_NS_GPL(efivar_get_variable, EFIVAR);
184 * efivar_get_next_variable() - enumerate the next name/vendor pair
186 * Must be called with efivars_lock held.
188 efi_status_t efivar_get_next_variable(unsigned long *name_size,
189 efi_char16_t *name, efi_guid_t *vendor)
191 return __efivars->ops->get_next_variable(name_size, name, vendor);
193 EXPORT_SYMBOL_NS_GPL(efivar_get_next_variable, EFIVAR);
196 * efivar_set_variable_locked() - set a variable identified by name/vendor
198 * Must be called with efivars_lock held. If @nonblocking is set, it will use
199 * non-blocking primitives so it is guaranteed not to sleep.
201 efi_status_t efivar_set_variable_locked(efi_char16_t *name, efi_guid_t *vendor,
202 u32 attr, unsigned long data_size,
203 void *data, bool nonblocking)
205 efi_set_variable_t *setvar;
209 status = check_var_size(nonblocking, attr,
210 data_size + ucs2_strsize(name, 1024));
211 if (status != EFI_SUCCESS)
216 * If no _nonblocking variant exists, the ordinary one
217 * is assumed to be non-blocking.
219 setvar = __efivars->ops->set_variable_nonblocking;
220 if (!setvar || !nonblocking)
221 setvar = __efivars->ops->set_variable;
223 return setvar(name, vendor, attr, data_size, data);
225 EXPORT_SYMBOL_NS_GPL(efivar_set_variable_locked, EFIVAR);
228 * efivar_set_variable() - set a variable identified by name/vendor
230 * Can be called without holding the efivars_lock. Will sleep on obtaining the
231 * lock, or on obtaining other locks that are needed in order to complete the
234 efi_status_t efivar_set_variable(efi_char16_t *name, efi_guid_t *vendor,
235 u32 attr, unsigned long data_size, void *data)
242 status = efivar_set_variable_locked(name, vendor, attr, data_size,
247 EXPORT_SYMBOL_NS_GPL(efivar_set_variable, EFIVAR);
249 efi_status_t efivar_query_variable_info(u32 attr,
251 u64 *remaining_space,
252 u64 *max_variable_size)
254 if (!__efivars->ops->query_variable_info)
255 return EFI_UNSUPPORTED;
256 return __efivars->ops->query_variable_info(attr, storage_space,
257 remaining_space, max_variable_size);
259 EXPORT_SYMBOL_NS_GPL(efivar_query_variable_info, EFIVAR);