aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/firmware/efivars.c
diff options
context:
space:
mode:
authorMatt Fleming <matt.fleming@intel.com>2013-02-08 10:48:51 -0500
committerMatt Fleming <matt.fleming@intel.com>2013-04-17 08:24:01 -0400
commit048517722cde2595a7366d0c3c72b8b1ec142a9c (patch)
tree1f54a4009c3f418285473e56bc930d606116bd11 /drivers/firmware/efivars.c
parente14ab23dde12b80db4c94b684a2e485b72b16af3 (diff)
efivars: Move pstore code into the new EFI directory
efivars.c has grown far too large and needs to be divided up. Create a new directory and move the persistence storage code to efi-pstore.c now that it uses the new efivar API. This helps us to greatly reduce the size of efivars.c and paves the way for moving other code out of efivars.c. Note that because CONFIG_EFI_VARS can be built as a module efi-pstore must also include support for building as a module. Reviewed-by: Tom Gundersen <teg@jklm.no> Tested-by: Tom Gundersen <teg@jklm.no> Cc: Seiji Aguchi <seiji.aguchi@hds.com> Cc: Anton Vorontsov <cbouatmailru@gmail.com> Cc: Colin Cross <ccross@android.com> Cc: Kees Cook <keescook@chromium.org> Cc: Matthew Garrett <mjg59@srcf.ucam.org> Cc: Tony Luck <tony.luck@intel.com> Signed-off-by: Matt Fleming <matt.fleming@intel.com>
Diffstat (limited to 'drivers/firmware/efivars.c')
-rw-r--r--drivers/firmware/efivars.c277
1 files changed, 12 insertions, 265 deletions
diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c
index 82fd145ead3b..5e7c3b1acde9 100644
--- a/drivers/firmware/efivars.c
+++ b/drivers/firmware/efivars.c
@@ -78,7 +78,6 @@
78#include <linux/kobject.h> 78#include <linux/kobject.h>
79#include <linux/device.h> 79#include <linux/device.h>
80#include <linux/slab.h> 80#include <linux/slab.h>
81#include <linux/pstore.h>
82#include <linux/ctype.h> 81#include <linux/ctype.h>
83 82
84#include <linux/fs.h> 83#include <linux/fs.h>
@@ -95,15 +94,9 @@ MODULE_DESCRIPTION("sysfs interface to EFI Variables");
95MODULE_LICENSE("GPL"); 94MODULE_LICENSE("GPL");
96MODULE_VERSION(EFIVARS_VERSION); 95MODULE_VERSION(EFIVARS_VERSION);
97 96
98#define DUMP_NAME_LEN 52
99
100static LIST_HEAD(efivarfs_list); 97static LIST_HEAD(efivarfs_list);
101static LIST_HEAD(efivar_sysfs_list); 98LIST_HEAD(efivar_sysfs_list);
102 99EXPORT_SYMBOL_GPL(efivar_sysfs_list);
103static bool efivars_pstore_disable =
104 IS_ENABLED(CONFIG_EFI_VARS_PSTORE_DEFAULT_DISABLE);
105
106module_param_named(pstore_disable, efivars_pstore_disable, bool, 0644);
107 100
108struct efivar_attribute { 101struct efivar_attribute {
109 struct attribute attr; 102 struct attribute attr;
@@ -114,11 +107,6 @@ struct efivar_attribute {
114/* Private pointer to registered efivars */ 107/* Private pointer to registered efivars */
115static struct efivars *__efivars; 108static struct efivars *__efivars;
116 109
117#define PSTORE_EFI_ATTRIBUTES \
118 (EFI_VARIABLE_NON_VOLATILE | \
119 EFI_VARIABLE_BOOTSERVICE_ACCESS | \
120 EFI_VARIABLE_RUNTIME_ACCESS)
121
122static struct kset *efivars_kset; 110static struct kset *efivars_kset;
123 111
124static struct bin_attribute *efivars_new_var; 112static struct bin_attribute *efivars_new_var;
@@ -148,34 +136,6 @@ static void efivar_update_sysfs_entries(struct work_struct *);
148static DECLARE_WORK(efivar_work, efivar_update_sysfs_entries); 136static DECLARE_WORK(efivar_work, efivar_update_sysfs_entries);
149static bool efivar_wq_enabled = true; 137static bool efivar_wq_enabled = true;
150 138
151/*
152 * Return the number of bytes is the length of this string
153 * Note: this is NOT the same as the number of unicode characters
154 */
155static inline unsigned long
156utf16_strsize(efi_char16_t *data, unsigned long maxlength)
157{
158 return utf16_strnlen(data, maxlength/sizeof(efi_char16_t)) * sizeof(efi_char16_t);
159}
160
161static inline int
162utf16_strncmp(const efi_char16_t *a, const efi_char16_t *b, size_t len)
163{
164 while (1) {
165 if (len == 0)
166 return 0;
167 if (*a < *b)
168 return -1;
169 if (*a > *b)
170 return 1;
171 if (*a == 0) /* implies *b == 0 */
172 return 0;
173 a++;
174 b++;
175 len--;
176 }
177}
178
179static bool 139static bool
180validate_device_path(struct efi_variable *var, int match, u8 *buffer, 140validate_device_path(struct efi_variable *var, int match, u8 *buffer,
181 unsigned long len) 141 unsigned long len)
@@ -598,12 +558,6 @@ static struct kobj_type efivar_ktype = {
598 .default_attrs = def_attrs, 558 .default_attrs = def_attrs,
599}; 559};
600 560
601static inline void
602efivar_unregister(struct efivar_entry *var)
603{
604 kobject_put(&var->kobj);
605}
606
607static int efivarfs_file_open(struct inode *inode, struct file *file) 561static int efivarfs_file_open(struct inode *inode, struct file *file)
608{ 562{
609 file->private_data = inode->i_private; 563 file->private_data = inode->i_private;
@@ -1130,220 +1084,6 @@ static const struct inode_operations efivarfs_dir_inode_operations = {
1130 .create = efivarfs_create, 1084 .create = efivarfs_create,
1131}; 1085};
1132 1086
1133#ifdef CONFIG_EFI_VARS_PSTORE
1134
1135static int efi_pstore_open(struct pstore_info *psi)
1136{
1137 efivar_entry_iter_begin();
1138 psi->data = NULL;
1139 return 0;
1140}
1141
1142static int efi_pstore_close(struct pstore_info *psi)
1143{
1144 efivar_entry_iter_end();
1145 psi->data = NULL;
1146 return 0;
1147}
1148
1149struct pstore_read_data {
1150 u64 *id;
1151 enum pstore_type_id *type;
1152 int *count;
1153 struct timespec *timespec;
1154 char **buf;
1155};
1156
1157static int efi_pstore_read_func(struct efivar_entry *entry, void *data)
1158{
1159 efi_guid_t vendor = LINUX_EFI_CRASH_GUID;
1160 struct pstore_read_data *cb_data = data;
1161 char name[DUMP_NAME_LEN];
1162 int i;
1163 int cnt;
1164 unsigned int part;
1165 unsigned long time, size;
1166
1167 if (efi_guidcmp(entry->var.VendorGuid, vendor))
1168 return 0;
1169
1170 for (i = 0; i < DUMP_NAME_LEN; i++)
1171 name[i] = entry->var.VariableName[i];
1172
1173 if (sscanf(name, "dump-type%u-%u-%d-%lu",
1174 cb_data->type, &part, &cnt, &time) == 4) {
1175 *cb_data->id = part;
1176 *cb_data->count = cnt;
1177 cb_data->timespec->tv_sec = time;
1178 cb_data->timespec->tv_nsec = 0;
1179 } else if (sscanf(name, "dump-type%u-%u-%lu",
1180 cb_data->type, &part, &time) == 3) {
1181 /*
1182 * Check if an old format,
1183 * which doesn't support holding
1184 * multiple logs, remains.
1185 */
1186 *cb_data->id = part;
1187 *cb_data->count = 0;
1188 cb_data->timespec->tv_sec = time;
1189 cb_data->timespec->tv_nsec = 0;
1190 } else
1191 return 0;
1192
1193 __efivar_entry_size(entry, &size);
1194 *cb_data->buf = kmalloc(size, GFP_KERNEL);
1195 if (*cb_data->buf == NULL)
1196 return -ENOMEM;
1197 memcpy(*cb_data->buf, entry->var.Data, size);
1198 return size;
1199}
1200
1201static ssize_t efi_pstore_read(u64 *id, enum pstore_type_id *type,
1202 int *count, struct timespec *timespec,
1203 char **buf, struct pstore_info *psi)
1204{
1205 struct pstore_read_data data;
1206
1207 data.id = id;
1208 data.type = type;
1209 data.count = count;
1210 data.timespec = timespec;
1211 data.buf = buf;
1212
1213 return __efivar_entry_iter(efi_pstore_read_func, &efivar_sysfs_list, &data,
1214 (struct efivar_entry **)&psi->data);
1215}
1216
1217static int efi_pstore_write(enum pstore_type_id type,
1218 enum kmsg_dump_reason reason, u64 *id,
1219 unsigned int part, int count, size_t size,
1220 struct pstore_info *psi)
1221{
1222 char name[DUMP_NAME_LEN];
1223 efi_char16_t efi_name[DUMP_NAME_LEN];
1224 efi_guid_t vendor = LINUX_EFI_CRASH_GUID;
1225 int i, ret = 0;
1226
1227 sprintf(name, "dump-type%u-%u-%d-%lu", type, part, count,
1228 get_seconds());
1229
1230 for (i = 0; i < DUMP_NAME_LEN; i++)
1231 efi_name[i] = name[i];
1232
1233 ret = efivar_entry_set_safe(efi_name, vendor, PSTORE_EFI_ATTRIBUTES,
1234 !pstore_cannot_block_path(reason),
1235 size, psi->buf);
1236
1237 if (reason == KMSG_DUMP_OOPS && efivar_wq_enabled)
1238 schedule_work(&efivar_work);
1239
1240 *id = part;
1241 return ret;
1242};
1243
1244struct pstore_erase_data {
1245 u64 id;
1246 enum pstore_type_id type;
1247 int count;
1248 struct timespec time;
1249 efi_char16_t *name;
1250};
1251
1252/*
1253 * Clean up an entry with the same name
1254 */
1255static int efi_pstore_erase_func(struct efivar_entry *entry, void *data)
1256{
1257 struct pstore_erase_data *ed = data;
1258 efi_guid_t vendor = LINUX_EFI_CRASH_GUID;
1259 efi_char16_t efi_name_old[DUMP_NAME_LEN];
1260 efi_char16_t *efi_name = ed->name;
1261 unsigned long utf16_len = utf16_strlen(ed->name);
1262 char name_old[DUMP_NAME_LEN];
1263 int i;
1264
1265 if (efi_guidcmp(entry->var.VendorGuid, vendor))
1266 return 0;
1267
1268 if (utf16_strncmp(entry->var.VariableName,
1269 efi_name, (size_t)utf16_len)) {
1270 /*
1271 * Check if an old format, which doesn't support
1272 * holding multiple logs, remains.
1273 */
1274 sprintf(name_old, "dump-type%u-%u-%lu", ed->type,
1275 (unsigned int)ed->id, ed->time.tv_sec);
1276
1277 for (i = 0; i < DUMP_NAME_LEN; i++)
1278 efi_name_old[i] = name_old[i];
1279
1280 if (utf16_strncmp(entry->var.VariableName, efi_name_old,
1281 utf16_strlen(efi_name_old)))
1282 return 0;
1283 }
1284
1285 /* found */
1286 __efivar_entry_delete(entry);
1287 return 1;
1288}
1289
1290static int efi_pstore_erase(enum pstore_type_id type, u64 id, int count,
1291 struct timespec time, struct pstore_info *psi)
1292{
1293 struct pstore_erase_data edata;
1294 struct efivar_entry *entry;
1295 char name[DUMP_NAME_LEN];
1296 efi_char16_t efi_name[DUMP_NAME_LEN];
1297 int found, i;
1298
1299 sprintf(name, "dump-type%u-%u-%d-%lu", type, (unsigned int)id, count,
1300 time.tv_sec);
1301
1302 for (i = 0; i < DUMP_NAME_LEN; i++)
1303 efi_name[i] = name[i];
1304
1305 edata.id = id;
1306 edata.type = type;
1307 edata.count = count;
1308 edata.time = time;
1309 edata.name = efi_name;
1310
1311 efivar_entry_iter_begin();
1312 found = __efivar_entry_iter(efi_pstore_erase_func, &efivar_sysfs_list, &edata, &entry);
1313 efivar_entry_iter_end();
1314
1315 if (found)
1316 efivar_unregister(entry);
1317
1318 return 0;
1319}
1320
1321static struct pstore_info efi_pstore_info = {
1322 .owner = THIS_MODULE,
1323 .name = "efi",
1324 .open = efi_pstore_open,
1325 .close = efi_pstore_close,
1326 .read = efi_pstore_read,
1327 .write = efi_pstore_write,
1328 .erase = efi_pstore_erase,
1329};
1330
1331static void efivar_pstore_register(void)
1332{
1333 efi_pstore_info.buf = kmalloc(4096, GFP_KERNEL);
1334 if (efi_pstore_info.buf) {
1335 efi_pstore_info.bufsize = 1024;
1336 spin_lock_init(&efi_pstore_info.buf_lock);
1337 pstore_register(&efi_pstore_info);
1338 }
1339}
1340#else
1341static void efivar_pstore_register(void)
1342{
1343 return;
1344}
1345#endif
1346
1347static ssize_t efivar_create(struct file *filp, struct kobject *kobj, 1087static ssize_t efivar_create(struct file *filp, struct kobject *kobj,
1348 struct bin_attribute *bin_attr, 1088 struct bin_attribute *bin_attr,
1349 char *buf, loff_t pos, size_t count) 1089 char *buf, loff_t pos, size_t count)
@@ -2397,6 +2137,16 @@ struct kobject *efivars_kobject(void)
2397EXPORT_SYMBOL_GPL(efivars_kobject); 2137EXPORT_SYMBOL_GPL(efivars_kobject);
2398 2138
2399/** 2139/**
2140 * efivar_run_worker - schedule the efivar worker thread
2141 */
2142void efivar_run_worker(void)
2143{
2144 if (efivar_wq_enabled)
2145 schedule_work(&efivar_work);
2146}
2147EXPORT_SYMBOL_GPL(efivar_run_worker);
2148
2149/**
2400 * efivars_register - register an efivars 2150 * efivars_register - register an efivars
2401 * @efivars: efivars to register 2151 * @efivars: efivars to register
2402 * @ops: efivars operations 2152 * @ops: efivars operations
@@ -2414,9 +2164,6 @@ int efivars_register(struct efivars *efivars,
2414 2164
2415 __efivars = efivars; 2165 __efivars = efivars;
2416 2166
2417 if (!efivars_pstore_disable)
2418 efivar_pstore_register();
2419
2420 register_filesystem(&efivarfs_type); 2167 register_filesystem(&efivarfs_type);
2421 2168
2422 return 0; 2169 return 0;