1 // SPDX-License-Identifier: GPL-2.0+
3 * Originally from efivars.c
9 #include <linux/types.h>
10 #include <linux/errno.h>
11 #include <linux/init.h>
12 #include <linux/module.h>
13 #include <linux/string.h>
14 #include <linux/smp.h>
15 #include <linux/efi.h>
16 #include <linux/ucs2_string.h>
18 /* Private pointer to registered efivars */
19 static struct efivars *__efivars;
21 static DEFINE_SEMAPHORE(efivars_lock);
23 efi_status_t check_var_size(u32 attributes, unsigned long size)
25 const struct efivar_operations *fops;
27 fops = __efivars->ops;
29 if (!fops->query_variable_store)
30 return EFI_UNSUPPORTED;
32 return fops->query_variable_store(attributes, size, false);
34 EXPORT_SYMBOL_NS_GPL(check_var_size, EFIVAR);
36 efi_status_t check_var_size_nonblocking(u32 attributes, unsigned long size)
38 const struct efivar_operations *fops;
40 fops = __efivars->ops;
42 if (!fops->query_variable_store)
43 return EFI_UNSUPPORTED;
45 return fops->query_variable_store(attributes, size, true);
47 EXPORT_SYMBOL_NS_GPL(check_var_size_nonblocking, EFIVAR);
50 * efivars_kobject - get the kobject for the registered efivars
52 * If efivars_register() has not been called we return NULL,
53 * otherwise return the kobject used at registration time.
55 struct kobject *efivars_kobject(void)
60 return __efivars->kobject;
62 EXPORT_SYMBOL_GPL(efivars_kobject);
65 * efivars_register - register an efivars
66 * @efivars: efivars to register
67 * @ops: efivars operations
68 * @kobject: @efivars-specific kobject
70 * Only a single efivars can be registered at any time.
72 int efivars_register(struct efivars *efivars,
73 const struct efivar_operations *ops,
74 struct kobject *kobject)
76 if (down_interruptible(&efivars_lock))
80 efivars->kobject = kobject;
84 pr_info("Registered efivars operations\n");
90 EXPORT_SYMBOL_GPL(efivars_register);
93 * efivars_unregister - unregister an efivars
94 * @efivars: efivars to unregister
96 * The caller must have already removed every entry from the list,
97 * failure to do so is an error.
99 int efivars_unregister(struct efivars *efivars)
103 if (down_interruptible(&efivars_lock))
107 printk(KERN_ERR "efivars not registered\n");
112 if (__efivars != efivars) {
117 pr_info("Unregistered efivars operations\n");
125 EXPORT_SYMBOL_GPL(efivars_unregister);
127 int efivar_supports_writes(void)
129 return __efivars && __efivars->ops->set_variable;
131 EXPORT_SYMBOL_GPL(efivar_supports_writes);
134 * efivar_lock() - obtain the efivar lock, wait for it if needed
135 * @return 0 on success, error code on failure
137 int efivar_lock(void)
139 if (down_interruptible(&efivars_lock))
141 if (!__efivars->ops) {
147 EXPORT_SYMBOL_NS_GPL(efivar_lock, EFIVAR);
150 * efivar_lock() - obtain the efivar lock if it is free
151 * @return 0 on success, error code on failure
153 int efivar_trylock(void)
155 if (down_trylock(&efivars_lock))
157 if (!__efivars->ops) {
163 EXPORT_SYMBOL_NS_GPL(efivar_trylock, EFIVAR);
166 * efivar_unlock() - release the efivar lock
168 void efivar_unlock(void)
172 EXPORT_SYMBOL_NS_GPL(efivar_unlock, EFIVAR);
175 * efivar_get_variable() - retrieve a variable identified by name/vendor
177 * Must be called with efivars_lock held.
179 efi_status_t efivar_get_variable(efi_char16_t *name, efi_guid_t *vendor,
180 u32 *attr, unsigned long *size, void *data)
182 return __efivars->ops->get_variable(name, vendor, attr, size, data);
184 EXPORT_SYMBOL_NS_GPL(efivar_get_variable, EFIVAR);
187 * efivar_get_next_variable() - enumerate the next name/vendor pair
189 * Must be called with efivars_lock held.
191 efi_status_t efivar_get_next_variable(unsigned long *name_size,
192 efi_char16_t *name, efi_guid_t *vendor)
194 return __efivars->ops->get_next_variable(name_size, name, vendor);
196 EXPORT_SYMBOL_NS_GPL(efivar_get_next_variable, EFIVAR);
199 * efivar_set_variable_blocking() - local helper function for set_variable
201 * Must be called with efivars_lock held.
204 efivar_set_variable_blocking(efi_char16_t *name, efi_guid_t *vendor,
205 u32 attr, unsigned long data_size, void *data)
210 status = check_var_size(attr, data_size +
211 ucs2_strsize(name, 1024));
212 if (status != EFI_SUCCESS)
215 return __efivars->ops->set_variable(name, vendor, attr, data_size, data);
219 * efivar_set_variable_locked() - set a variable identified by name/vendor
221 * Must be called with efivars_lock held. If @nonblocking is set, it will use
222 * non-blocking primitives so it is guaranteed not to sleep.
224 efi_status_t efivar_set_variable_locked(efi_char16_t *name, efi_guid_t *vendor,
225 u32 attr, unsigned long data_size,
226 void *data, bool nonblocking)
228 efi_set_variable_t *setvar;
232 return efivar_set_variable_blocking(name, vendor, attr,
236 * If no _nonblocking variant exists, the ordinary one
237 * is assumed to be non-blocking.
239 setvar = __efivars->ops->set_variable_nonblocking ?:
240 __efivars->ops->set_variable;
243 status = check_var_size_nonblocking(attr, data_size +
244 ucs2_strsize(name, 1024));
245 if (status != EFI_SUCCESS)
248 return setvar(name, vendor, attr, data_size, data);
250 EXPORT_SYMBOL_NS_GPL(efivar_set_variable_locked, EFIVAR);
253 * efivar_set_variable() - set a variable identified by name/vendor
255 * Can be called without holding the efivars_lock. Will sleep on obtaining the
256 * lock, or on obtaining other locks that are needed in order to complete the
259 efi_status_t efivar_set_variable(efi_char16_t *name, efi_guid_t *vendor,
260 u32 attr, unsigned long data_size, void *data)
267 status = efivar_set_variable_blocking(name, vendor, attr, data_size, data);
271 EXPORT_SYMBOL_NS_GPL(efivar_set_variable, EFIVAR);