Linux Audio

Check our new training course

Loading...
v6.9.4
  1// SPDX-License-Identifier: GPL-2.0+
  2/*
  3 * Originally from efivars.c
  4 *
  5 * Copyright (C) 2001,2003,2004 Dell <Matt_Domsch@dell.com>
  6 * Copyright (C) 2004 Intel Corporation <matthew.e.tolentino@intel.com>
  7 */
  8
  9#define pr_fmt(fmt) "efivars: " fmt
 10
 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>
 20
 21/* Private pointer to registered efivars */
 22static struct efivars *__efivars;
 23
 24static DEFINE_SEMAPHORE(efivars_lock, 1);
 25
 26static efi_status_t check_var_size(bool nonblocking, u32 attributes,
 27				   unsigned long size)
 28{
 29	const struct efivar_operations *fops;
 30	efi_status_t status;
 31
 32	fops = __efivars->ops;
 33
 34	if (!fops->query_variable_store)
 35		status = EFI_UNSUPPORTED;
 36	else
 37		status = fops->query_variable_store(attributes, size,
 38						    nonblocking);
 39	if (status == EFI_UNSUPPORTED)
 40		return (size <= SZ_64K) ? EFI_SUCCESS : EFI_OUT_OF_RESOURCES;
 41	return status;
 42}
 43
 44/**
 45 * efivar_is_available - check if efivars is available
 46 *
 47 * @return true iff evivars is currently registered
 
 48 */
 49bool efivar_is_available(void)
 50{
 51	return __efivars != NULL;
 
 
 
 52}
 53EXPORT_SYMBOL_GPL(efivar_is_available);
 54
 55/**
 56 * efivars_register - register an efivars
 57 * @efivars: efivars to register
 58 * @ops: efivars operations
 
 59 *
 60 * Only a single efivars can be registered at any time.
 61 */
 62int efivars_register(struct efivars *efivars,
 63		     const struct efivar_operations *ops)
 
 64{
 65	int rv;
 66	int event;
 67
 68	if (down_interruptible(&efivars_lock))
 69		return -EINTR;
 70
 71	if (__efivars) {
 72		pr_warn("efivars already registered\n");
 73		rv = -EBUSY;
 74		goto out;
 75	}
 76
 77	efivars->ops = ops;
 
 78
 79	__efivars = efivars;
 80
 81	if (efivar_supports_writes())
 82		event = EFIVAR_OPS_RDWR;
 83	else
 84		event = EFIVAR_OPS_RDONLY;
 85
 86	blocking_notifier_call_chain(&efivar_ops_nh, event, NULL);
 87
 88	pr_info("Registered efivars operations\n");
 89	rv = 0;
 90out:
 91	up(&efivars_lock);
 92
 93	return rv;
 94}
 95EXPORT_SYMBOL_GPL(efivars_register);
 96
 97/**
 98 * efivars_unregister - unregister an efivars
 99 * @efivars: efivars to unregister
100 *
101 * The caller must have already removed every entry from the list,
102 * failure to do so is an error.
103 */
104int efivars_unregister(struct efivars *efivars)
105{
106	int rv;
107
108	if (down_interruptible(&efivars_lock))
109		return -EINTR;
110
111	if (!__efivars) {
112		pr_err("efivars not registered\n");
113		rv = -EINVAL;
114		goto out;
115	}
116
117	if (__efivars != efivars) {
118		rv = -EINVAL;
119		goto out;
120	}
121
122	pr_info("Unregistered efivars operations\n");
123	__efivars = NULL;
124
125	rv = 0;
126out:
127	up(&efivars_lock);
128	return rv;
129}
130EXPORT_SYMBOL_GPL(efivars_unregister);
131
132bool efivar_supports_writes(void)
133{
134	return __efivars && __efivars->ops->set_variable;
135}
136EXPORT_SYMBOL_GPL(efivar_supports_writes);
137
138/*
139 * efivar_lock() - obtain the efivar lock, wait for it if needed
140 * @return 0 on success, error code on failure
141 */
142int efivar_lock(void)
143{
144	if (down_interruptible(&efivars_lock))
145		return -EINTR;
146	if (!__efivars->ops) {
147		up(&efivars_lock);
148		return -ENODEV;
149	}
150	return 0;
151}
152EXPORT_SYMBOL_NS_GPL(efivar_lock, EFIVAR);
153
154/*
155 * efivar_lock() - obtain the efivar lock if it is free
156 * @return 0 on success, error code on failure
157 */
158int efivar_trylock(void)
159{
160	if (down_trylock(&efivars_lock))
161		 return -EBUSY;
162	if (!__efivars->ops) {
163		up(&efivars_lock);
164		return -ENODEV;
165	}
166	return 0;
167}
168EXPORT_SYMBOL_NS_GPL(efivar_trylock, EFIVAR);
169
170/*
171 * efivar_unlock() - release the efivar lock
172 */
173void efivar_unlock(void)
174{
175	up(&efivars_lock);
176}
177EXPORT_SYMBOL_NS_GPL(efivar_unlock, EFIVAR);
178
179/*
180 * efivar_get_variable() - retrieve a variable identified by name/vendor
181 *
182 * Must be called with efivars_lock held.
183 */
184efi_status_t efivar_get_variable(efi_char16_t *name, efi_guid_t *vendor,
185				 u32 *attr, unsigned long *size, void *data)
186{
187	return __efivars->ops->get_variable(name, vendor, attr, size, data);
188}
189EXPORT_SYMBOL_NS_GPL(efivar_get_variable, EFIVAR);
190
191/*
192 * efivar_get_next_variable() - enumerate the next name/vendor pair
193 *
194 * Must be called with efivars_lock held.
195 */
196efi_status_t efivar_get_next_variable(unsigned long *name_size,
197				      efi_char16_t *name, efi_guid_t *vendor)
198{
199	return __efivars->ops->get_next_variable(name_size, name, vendor);
200}
201EXPORT_SYMBOL_NS_GPL(efivar_get_next_variable, EFIVAR);
202
203/*
204 * efivar_set_variable_locked() - set a variable identified by name/vendor
205 *
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.
208 */
209efi_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)
212{
213	efi_set_variable_t *setvar;
214	efi_status_t status;
215
216	if (data_size > 0) {
217		status = check_var_size(nonblocking, attr,
218					data_size + ucs2_strsize(name, 1024));
219		if (status != EFI_SUCCESS)
220			return status;
221	}
222
223	/*
224	 * If no _nonblocking variant exists, the ordinary one
225	 * is assumed to be non-blocking.
226	 */
227	setvar = __efivars->ops->set_variable_nonblocking;
228	if (!setvar || !nonblocking)
229		 setvar = __efivars->ops->set_variable;
230
231	return setvar(name, vendor, attr, data_size, data);
232}
233EXPORT_SYMBOL_NS_GPL(efivar_set_variable_locked, EFIVAR);
234
235/*
236 * efivar_set_variable() - set a variable identified by name/vendor
237 *
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
240 * call.
241 */
242efi_status_t efivar_set_variable(efi_char16_t *name, efi_guid_t *vendor,
243				 u32 attr, unsigned long data_size, void *data)
244{
245	efi_status_t status;
246
247	if (efivar_lock())
248		return EFI_ABORTED;
249
250	status = efivar_set_variable_locked(name, vendor, attr, data_size,
251					    data, false);
252	efivar_unlock();
253	return status;
254}
255EXPORT_SYMBOL_NS_GPL(efivar_set_variable, EFIVAR);
256
257efi_status_t efivar_query_variable_info(u32 attr,
258					u64 *storage_space,
259					u64 *remaining_space,
260					u64 *max_variable_size)
261{
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);
266}
267EXPORT_SYMBOL_NS_GPL(efivar_query_variable_info, EFIVAR);
v6.2
  1// SPDX-License-Identifier: GPL-2.0+
  2/*
  3 * Originally from efivars.c
  4 *
  5 * Copyright (C) 2001,2003,2004 Dell <Matt_Domsch@dell.com>
  6 * Copyright (C) 2004 Intel Corporation <matthew.e.tolentino@intel.com>
  7 */
  8
 
 
  9#include <linux/types.h>
 10#include <linux/sizes.h>
 11#include <linux/errno.h>
 12#include <linux/init.h>
 13#include <linux/module.h>
 14#include <linux/string.h>
 15#include <linux/smp.h>
 16#include <linux/efi.h>
 17#include <linux/ucs2_string.h>
 18
 19/* Private pointer to registered efivars */
 20static struct efivars *__efivars;
 21
 22static DEFINE_SEMAPHORE(efivars_lock);
 23
 24static efi_status_t check_var_size(bool nonblocking, u32 attributes,
 25				   unsigned long size)
 26{
 27	const struct efivar_operations *fops;
 28	efi_status_t status;
 29
 30	fops = __efivars->ops;
 31
 32	if (!fops->query_variable_store)
 33		status = EFI_UNSUPPORTED;
 34	else
 35		status = fops->query_variable_store(attributes, size,
 36						    nonblocking);
 37	if (status == EFI_UNSUPPORTED)
 38		return (size <= SZ_64K) ? EFI_SUCCESS : EFI_OUT_OF_RESOURCES;
 39	return status;
 40}
 41
 42/**
 43 * efivars_kobject - get the kobject for the registered efivars
 44 *
 45 * If efivars_register() has not been called we return NULL,
 46 * otherwise return the kobject used at registration time.
 47 */
 48struct kobject *efivars_kobject(void)
 49{
 50	if (!__efivars)
 51		return NULL;
 52
 53	return __efivars->kobject;
 54}
 55EXPORT_SYMBOL_GPL(efivars_kobject);
 56
 57/**
 58 * efivars_register - register an efivars
 59 * @efivars: efivars to register
 60 * @ops: efivars operations
 61 * @kobject: @efivars-specific kobject
 62 *
 63 * Only a single efivars can be registered at any time.
 64 */
 65int efivars_register(struct efivars *efivars,
 66		     const struct efivar_operations *ops,
 67		     struct kobject *kobject)
 68{
 
 
 
 69	if (down_interruptible(&efivars_lock))
 70		return -EINTR;
 71
 
 
 
 
 
 
 72	efivars->ops = ops;
 73	efivars->kobject = kobject;
 74
 75	__efivars = efivars;
 76
 
 
 
 
 
 
 
 77	pr_info("Registered efivars operations\n");
 78
 
 79	up(&efivars_lock);
 80
 81	return 0;
 82}
 83EXPORT_SYMBOL_GPL(efivars_register);
 84
 85/**
 86 * efivars_unregister - unregister an efivars
 87 * @efivars: efivars to unregister
 88 *
 89 * The caller must have already removed every entry from the list,
 90 * failure to do so is an error.
 91 */
 92int efivars_unregister(struct efivars *efivars)
 93{
 94	int rv;
 95
 96	if (down_interruptible(&efivars_lock))
 97		return -EINTR;
 98
 99	if (!__efivars) {
100		printk(KERN_ERR "efivars not registered\n");
101		rv = -EINVAL;
102		goto out;
103	}
104
105	if (__efivars != efivars) {
106		rv = -EINVAL;
107		goto out;
108	}
109
110	pr_info("Unregistered efivars operations\n");
111	__efivars = NULL;
112
113	rv = 0;
114out:
115	up(&efivars_lock);
116	return rv;
117}
118EXPORT_SYMBOL_GPL(efivars_unregister);
119
120int efivar_supports_writes(void)
121{
122	return __efivars && __efivars->ops->set_variable;
123}
124EXPORT_SYMBOL_GPL(efivar_supports_writes);
125
126/*
127 * efivar_lock() - obtain the efivar lock, wait for it if needed
128 * @return 0 on success, error code on failure
129 */
130int efivar_lock(void)
131{
132	if (down_interruptible(&efivars_lock))
133		return -EINTR;
134	if (!__efivars->ops) {
135		up(&efivars_lock);
136		return -ENODEV;
137	}
138	return 0;
139}
140EXPORT_SYMBOL_NS_GPL(efivar_lock, EFIVAR);
141
142/*
143 * efivar_lock() - obtain the efivar lock if it is free
144 * @return 0 on success, error code on failure
145 */
146int efivar_trylock(void)
147{
148	if (down_trylock(&efivars_lock))
149		 return -EBUSY;
150	if (!__efivars->ops) {
151		up(&efivars_lock);
152		return -ENODEV;
153	}
154	return 0;
155}
156EXPORT_SYMBOL_NS_GPL(efivar_trylock, EFIVAR);
157
158/*
159 * efivar_unlock() - release the efivar lock
160 */
161void efivar_unlock(void)
162{
163	up(&efivars_lock);
164}
165EXPORT_SYMBOL_NS_GPL(efivar_unlock, EFIVAR);
166
167/*
168 * efivar_get_variable() - retrieve a variable identified by name/vendor
169 *
170 * Must be called with efivars_lock held.
171 */
172efi_status_t efivar_get_variable(efi_char16_t *name, efi_guid_t *vendor,
173				 u32 *attr, unsigned long *size, void *data)
174{
175	return __efivars->ops->get_variable(name, vendor, attr, size, data);
176}
177EXPORT_SYMBOL_NS_GPL(efivar_get_variable, EFIVAR);
178
179/*
180 * efivar_get_next_variable() - enumerate the next name/vendor pair
181 *
182 * Must be called with efivars_lock held.
183 */
184efi_status_t efivar_get_next_variable(unsigned long *name_size,
185				      efi_char16_t *name, efi_guid_t *vendor)
186{
187	return __efivars->ops->get_next_variable(name_size, name, vendor);
188}
189EXPORT_SYMBOL_NS_GPL(efivar_get_next_variable, EFIVAR);
190
191/*
192 * efivar_set_variable_locked() - set a variable identified by name/vendor
193 *
194 * Must be called with efivars_lock held. If @nonblocking is set, it will use
195 * non-blocking primitives so it is guaranteed not to sleep.
196 */
197efi_status_t efivar_set_variable_locked(efi_char16_t *name, efi_guid_t *vendor,
198					u32 attr, unsigned long data_size,
199					void *data, bool nonblocking)
200{
201	efi_set_variable_t *setvar;
202	efi_status_t status;
203
204	if (data_size > 0) {
205		status = check_var_size(nonblocking, attr,
206					data_size + ucs2_strsize(name, 1024));
207		if (status != EFI_SUCCESS)
208			return status;
209	}
210
211	/*
212	 * If no _nonblocking variant exists, the ordinary one
213	 * is assumed to be non-blocking.
214	 */
215	setvar = __efivars->ops->set_variable_nonblocking;
216	if (!setvar || !nonblocking)
217		 setvar = __efivars->ops->set_variable;
218
219	return setvar(name, vendor, attr, data_size, data);
220}
221EXPORT_SYMBOL_NS_GPL(efivar_set_variable_locked, EFIVAR);
222
223/*
224 * efivar_set_variable() - set a variable identified by name/vendor
225 *
226 * Can be called without holding the efivars_lock. Will sleep on obtaining the
227 * lock, or on obtaining other locks that are needed in order to complete the
228 * call.
229 */
230efi_status_t efivar_set_variable(efi_char16_t *name, efi_guid_t *vendor,
231				 u32 attr, unsigned long data_size, void *data)
232{
233	efi_status_t status;
234
235	if (efivar_lock())
236		return EFI_ABORTED;
237
238	status = efivar_set_variable_locked(name, vendor, attr, data_size,
239					    data, false);
240	efivar_unlock();
241	return status;
242}
243EXPORT_SYMBOL_NS_GPL(efivar_set_variable, EFIVAR);