0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/types.h>
0010 #include <linux/errno.h>
0011 #include <linux/init.h>
0012 #include <linux/module.h>
0013 #include <linux/string.h>
0014 #include <linux/smp.h>
0015 #include <linux/efi.h>
0016 #include <linux/ucs2_string.h>
0017
0018
0019 static struct efivars *__efivars;
0020
0021 static DEFINE_SEMAPHORE(efivars_lock);
0022
0023 efi_status_t check_var_size(u32 attributes, unsigned long size)
0024 {
0025 const struct efivar_operations *fops;
0026
0027 fops = __efivars->ops;
0028
0029 if (!fops->query_variable_store)
0030 return EFI_UNSUPPORTED;
0031
0032 return fops->query_variable_store(attributes, size, false);
0033 }
0034 EXPORT_SYMBOL_NS_GPL(check_var_size, EFIVAR);
0035
0036 efi_status_t check_var_size_nonblocking(u32 attributes, unsigned long size)
0037 {
0038 const struct efivar_operations *fops;
0039
0040 fops = __efivars->ops;
0041
0042 if (!fops->query_variable_store)
0043 return EFI_UNSUPPORTED;
0044
0045 return fops->query_variable_store(attributes, size, true);
0046 }
0047 EXPORT_SYMBOL_NS_GPL(check_var_size_nonblocking, EFIVAR);
0048
0049
0050
0051
0052
0053
0054
0055 struct kobject *efivars_kobject(void)
0056 {
0057 if (!__efivars)
0058 return NULL;
0059
0060 return __efivars->kobject;
0061 }
0062 EXPORT_SYMBOL_GPL(efivars_kobject);
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072 int efivars_register(struct efivars *efivars,
0073 const struct efivar_operations *ops,
0074 struct kobject *kobject)
0075 {
0076 if (down_interruptible(&efivars_lock))
0077 return -EINTR;
0078
0079 efivars->ops = ops;
0080 efivars->kobject = kobject;
0081
0082 __efivars = efivars;
0083
0084 pr_info("Registered efivars operations\n");
0085
0086 up(&efivars_lock);
0087
0088 return 0;
0089 }
0090 EXPORT_SYMBOL_GPL(efivars_register);
0091
0092
0093
0094
0095
0096
0097
0098
0099 int efivars_unregister(struct efivars *efivars)
0100 {
0101 int rv;
0102
0103 if (down_interruptible(&efivars_lock))
0104 return -EINTR;
0105
0106 if (!__efivars) {
0107 printk(KERN_ERR "efivars not registered\n");
0108 rv = -EINVAL;
0109 goto out;
0110 }
0111
0112 if (__efivars != efivars) {
0113 rv = -EINVAL;
0114 goto out;
0115 }
0116
0117 pr_info("Unregistered efivars operations\n");
0118 __efivars = NULL;
0119
0120 rv = 0;
0121 out:
0122 up(&efivars_lock);
0123 return rv;
0124 }
0125 EXPORT_SYMBOL_GPL(efivars_unregister);
0126
0127 int efivar_supports_writes(void)
0128 {
0129 return __efivars && __efivars->ops->set_variable;
0130 }
0131 EXPORT_SYMBOL_GPL(efivar_supports_writes);
0132
0133
0134
0135
0136
0137 int efivar_lock(void)
0138 {
0139 if (down_interruptible(&efivars_lock))
0140 return -EINTR;
0141 if (!__efivars->ops) {
0142 up(&efivars_lock);
0143 return -ENODEV;
0144 }
0145 return 0;
0146 }
0147 EXPORT_SYMBOL_NS_GPL(efivar_lock, EFIVAR);
0148
0149
0150
0151
0152
0153 int efivar_trylock(void)
0154 {
0155 if (down_trylock(&efivars_lock))
0156 return -EBUSY;
0157 if (!__efivars->ops) {
0158 up(&efivars_lock);
0159 return -ENODEV;
0160 }
0161 return 0;
0162 }
0163 EXPORT_SYMBOL_NS_GPL(efivar_trylock, EFIVAR);
0164
0165
0166
0167
0168 void efivar_unlock(void)
0169 {
0170 up(&efivars_lock);
0171 }
0172 EXPORT_SYMBOL_NS_GPL(efivar_unlock, EFIVAR);
0173
0174
0175
0176
0177
0178
0179 efi_status_t efivar_get_variable(efi_char16_t *name, efi_guid_t *vendor,
0180 u32 *attr, unsigned long *size, void *data)
0181 {
0182 return __efivars->ops->get_variable(name, vendor, attr, size, data);
0183 }
0184 EXPORT_SYMBOL_NS_GPL(efivar_get_variable, EFIVAR);
0185
0186
0187
0188
0189
0190
0191 efi_status_t efivar_get_next_variable(unsigned long *name_size,
0192 efi_char16_t *name, efi_guid_t *vendor)
0193 {
0194 return __efivars->ops->get_next_variable(name_size, name, vendor);
0195 }
0196 EXPORT_SYMBOL_NS_GPL(efivar_get_next_variable, EFIVAR);
0197
0198
0199
0200
0201
0202
0203 static efi_status_t
0204 efivar_set_variable_blocking(efi_char16_t *name, efi_guid_t *vendor,
0205 u32 attr, unsigned long data_size, void *data)
0206 {
0207 efi_status_t status;
0208
0209 if (data_size > 0) {
0210 status = check_var_size(attr, data_size +
0211 ucs2_strsize(name, 1024));
0212 if (status != EFI_SUCCESS)
0213 return status;
0214 }
0215 return __efivars->ops->set_variable(name, vendor, attr, data_size, data);
0216 }
0217
0218
0219
0220
0221
0222
0223
0224 efi_status_t efivar_set_variable_locked(efi_char16_t *name, efi_guid_t *vendor,
0225 u32 attr, unsigned long data_size,
0226 void *data, bool nonblocking)
0227 {
0228 efi_set_variable_t *setvar;
0229 efi_status_t status;
0230
0231 if (!nonblocking)
0232 return efivar_set_variable_blocking(name, vendor, attr,
0233 data_size, data);
0234
0235
0236
0237
0238
0239 setvar = __efivars->ops->set_variable_nonblocking ?:
0240 __efivars->ops->set_variable;
0241
0242 if (data_size > 0) {
0243 status = check_var_size_nonblocking(attr, data_size +
0244 ucs2_strsize(name, 1024));
0245 if (status != EFI_SUCCESS)
0246 return status;
0247 }
0248 return setvar(name, vendor, attr, data_size, data);
0249 }
0250 EXPORT_SYMBOL_NS_GPL(efivar_set_variable_locked, EFIVAR);
0251
0252
0253
0254
0255
0256
0257
0258
0259 efi_status_t efivar_set_variable(efi_char16_t *name, efi_guid_t *vendor,
0260 u32 attr, unsigned long data_size, void *data)
0261 {
0262 efi_status_t status;
0263
0264 if (efivar_lock())
0265 return EFI_ABORTED;
0266
0267 status = efivar_set_variable_blocking(name, vendor, attr, data_size, data);
0268 efivar_unlock();
0269 return status;
0270 }
0271 EXPORT_SYMBOL_NS_GPL(efivar_set_variable, EFIVAR);