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/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> 17 18 /* Private pointer to registered efivars */ 19 static struct efivars *__efivars; 20 21 static DEFINE_SEMAPHORE(efivars_lock); 22 23 efi_status_t check_var_size(u32 attributes, unsigned long size) 24 { 25 const struct efivar_operations *fops; 26 27 fops = __efivars->ops; 28 29 if (!fops->query_variable_store) 30 return EFI_UNSUPPORTED; 31 32 return fops->query_variable_store(attributes, size, false); 33 } 34 EXPORT_SYMBOL_NS_GPL(check_var_size, EFIVAR); 35 36 efi_status_t check_var_size_nonblocking(u32 attributes, unsigned long size) 37 { 38 const struct efivar_operations *fops; 39 40 fops = __efivars->ops; 41 42 if (!fops->query_variable_store) 43 return EFI_UNSUPPORTED; 44 45 return fops->query_variable_store(attributes, size, true); 46 } 47 EXPORT_SYMBOL_NS_GPL(check_var_size_nonblocking, EFIVAR); 48 49 /** 50 * efivars_kobject - get the kobject for the registered efivars 51 * 52 * If efivars_register() has not been called we return NULL, 53 * otherwise return the kobject used at registration time. 54 */ 55 struct kobject *efivars_kobject(void) 56 { 57 if (!__efivars) 58 return NULL; 59 60 return __efivars->kobject; 61 } 62 EXPORT_SYMBOL_GPL(efivars_kobject); 63 64 /** 65 * efivars_register - register an efivars 66 * @efivars: efivars to register 67 * @ops: efivars operations 68 * @kobject: @efivars-specific kobject 69 * 70 * Only a single efivars can be registered at any time. 71 */ 72 int efivars_register(struct efivars *efivars, 73 const struct efivar_operations *ops, 74 struct kobject *kobject) 75 { 76 if (down_interruptible(&efivars_lock)) 77 return -EINTR; 78 79 efivars->ops = ops; 80 efivars->kobject = kobject; 81 82 __efivars = efivars; 83 84 pr_info("Registered efivars operations\n"); 85 86 up(&efivars_lock); 87 88 return 0; 89 } 90 EXPORT_SYMBOL_GPL(efivars_register); 91 92 /** 93 * efivars_unregister - unregister an efivars 94 * @efivars: efivars to unregister 95 * 96 * The caller must have already removed every entry from the list, 97 * failure to do so is an error. 98 */ 99 int efivars_unregister(struct efivars *efivars) 100 { 101 int rv; 102 103 if (down_interruptible(&efivars_lock)) 104 return -EINTR; 105 106 if (!__efivars) { 107 printk(KERN_ERR "efivars not registered\n"); 108 rv = -EINVAL; 109 goto out; 110 } 111 112 if (__efivars != efivars) { 113 rv = -EINVAL; 114 goto out; 115 } 116 117 pr_info("Unregistered efivars operations\n"); 118 __efivars = NULL; 119 120 rv = 0; 121 out: 122 up(&efivars_lock); 123 return rv; 124 } 125 EXPORT_SYMBOL_GPL(efivars_unregister); 126 127 int efivar_supports_writes(void) 128 { 129 return __efivars && __efivars->ops->set_variable; 130 } 131 EXPORT_SYMBOL_GPL(efivar_supports_writes); 132 133 /* 134 * efivar_lock() - obtain the efivar lock, wait for it if needed 135 * @return 0 on success, error code on failure 136 */ 137 int efivar_lock(void) 138 { 139 if (down_interruptible(&efivars_lock)) 140 return -EINTR; 141 if (!__efivars->ops) { 142 up(&efivars_lock); 143 return -ENODEV; 144 } 145 return 0; 146 } 147 EXPORT_SYMBOL_NS_GPL(efivar_lock, EFIVAR); 148 149 /* 150 * efivar_lock() - obtain the efivar lock if it is free 151 * @return 0 on success, error code on failure 152 */ 153 int efivar_trylock(void) 154 { 155 if (down_trylock(&efivars_lock)) 156 return -EBUSY; 157 if (!__efivars->ops) { 158 up(&efivars_lock); 159 return -ENODEV; 160 } 161 return 0; 162 } 163 EXPORT_SYMBOL_NS_GPL(efivar_trylock, EFIVAR); 164 165 /* 166 * efivar_unlock() - release the efivar lock 167 */ 168 void efivar_unlock(void) 169 { 170 up(&efivars_lock); 171 } 172 EXPORT_SYMBOL_NS_GPL(efivar_unlock, EFIVAR); 173 174 /* 175 * efivar_get_variable() - retrieve a variable identified by name/vendor 176 * 177 * Must be called with efivars_lock held. 178 */ 179 efi_status_t efivar_get_variable(efi_char16_t *name, efi_guid_t *vendor, 180 u32 *attr, unsigned long *size, void *data) 181 { 182 return __efivars->ops->get_variable(name, vendor, attr, size, data); 183 } 184 EXPORT_SYMBOL_NS_GPL(efivar_get_variable, EFIVAR); 185 186 /* 187 * efivar_get_next_variable() - enumerate the next name/vendor pair 188 * 189 * Must be called with efivars_lock held. 190 */ 191 efi_status_t efivar_get_next_variable(unsigned long *name_size, 192 efi_char16_t *name, efi_guid_t *vendor) 193 { 194 return __efivars->ops->get_next_variable(name_size, name, vendor); 195 } 196 EXPORT_SYMBOL_NS_GPL(efivar_get_next_variable, EFIVAR); 197 198 /* 199 * efivar_set_variable_blocking() - local helper function for set_variable 200 * 201 * Must be called with efivars_lock held. 202 */ 203 static efi_status_t 204 efivar_set_variable_blocking(efi_char16_t *name, efi_guid_t *vendor, 205 u32 attr, unsigned long data_size, void *data) 206 { 207 efi_status_t status; 208 209 if (data_size > 0) { 210 status = check_var_size(attr, data_size + 211 ucs2_strsize(name, 1024)); 212 if (status != EFI_SUCCESS) 213 return status; 214 } 215 return __efivars->ops->set_variable(name, vendor, attr, data_size, data); 216 } 217 218 /* 219 * efivar_set_variable_locked() - set a variable identified by name/vendor 220 * 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. 223 */ 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) 227 { 228 efi_set_variable_t *setvar; 229 efi_status_t status; 230 231 if (!nonblocking) 232 return efivar_set_variable_blocking(name, vendor, attr, 233 data_size, data); 234 235 /* 236 * If no _nonblocking variant exists, the ordinary one 237 * is assumed to be non-blocking. 238 */ 239 setvar = __efivars->ops->set_variable_nonblocking ?: 240 __efivars->ops->set_variable; 241 242 if (data_size > 0) { 243 status = check_var_size_nonblocking(attr, data_size + 244 ucs2_strsize(name, 1024)); 245 if (status != EFI_SUCCESS) 246 return status; 247 } 248 return setvar(name, vendor, attr, data_size, data); 249 } 250 EXPORT_SYMBOL_NS_GPL(efivar_set_variable_locked, EFIVAR); 251 252 /* 253 * efivar_set_variable() - set a variable identified by name/vendor 254 * 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 257 * call. 258 */ 259 efi_status_t efivar_set_variable(efi_char16_t *name, efi_guid_t *vendor, 260 u32 attr, unsigned long data_size, void *data) 261 { 262 efi_status_t status; 263 264 if (efivar_lock()) 265 return EFI_ABORTED; 266 267 status = efivar_set_variable_blocking(name, vendor, attr, data_size, data); 268 efivar_unlock(); 269 return status; 270 } 271 EXPORT_SYMBOL_NS_GPL(efivar_set_variable, EFIVAR); 272