1 #include <linux/efi.h> 2 #include <linux/module.h> 3 #include <linux/pstore.h> 4 #include <linux/slab.h> 5 #include <linux/ucs2_string.h> 6 7 #define DUMP_NAME_LEN 52 8 9 static bool efivars_pstore_disable = 10 IS_ENABLED(CONFIG_EFI_VARS_PSTORE_DEFAULT_DISABLE); 11 12 module_param_named(pstore_disable, efivars_pstore_disable, bool, 0644); 13 14 #define PSTORE_EFI_ATTRIBUTES \ 15 (EFI_VARIABLE_NON_VOLATILE | \ 16 EFI_VARIABLE_BOOTSERVICE_ACCESS | \ 17 EFI_VARIABLE_RUNTIME_ACCESS) 18 19 static int efi_pstore_open(struct pstore_info *psi) 20 { 21 efivar_entry_iter_begin(); 22 psi->data = NULL; 23 return 0; 24 } 25 26 static int efi_pstore_close(struct pstore_info *psi) 27 { 28 efivar_entry_iter_end(); 29 psi->data = NULL; 30 return 0; 31 } 32 33 struct pstore_read_data { 34 u64 *id; 35 enum pstore_type_id *type; 36 int *count; 37 struct timespec *timespec; 38 char **buf; 39 }; 40 41 static int efi_pstore_read_func(struct efivar_entry *entry, void *data) 42 { 43 efi_guid_t vendor = LINUX_EFI_CRASH_GUID; 44 struct pstore_read_data *cb_data = data; 45 char name[DUMP_NAME_LEN]; 46 int i; 47 int cnt; 48 unsigned int part; 49 unsigned long time, size; 50 51 if (efi_guidcmp(entry->var.VendorGuid, vendor)) 52 return 0; 53 54 for (i = 0; i < DUMP_NAME_LEN; i++) 55 name[i] = entry->var.VariableName[i]; 56 57 if (sscanf(name, "dump-type%u-%u-%d-%lu", 58 cb_data->type, &part, &cnt, &time) == 4) { 59 *cb_data->id = part; 60 *cb_data->count = cnt; 61 cb_data->timespec->tv_sec = time; 62 cb_data->timespec->tv_nsec = 0; 63 } else if (sscanf(name, "dump-type%u-%u-%lu", 64 cb_data->type, &part, &time) == 3) { 65 /* 66 * Check if an old format, 67 * which doesn't support holding 68 * multiple logs, remains. 69 */ 70 *cb_data->id = part; 71 *cb_data->count = 0; 72 cb_data->timespec->tv_sec = time; 73 cb_data->timespec->tv_nsec = 0; 74 } else 75 return 0; 76 77 entry->var.DataSize = 1024; 78 __efivar_entry_get(entry, &entry->var.Attributes, 79 &entry->var.DataSize, entry->var.Data); 80 size = entry->var.DataSize; 81 82 *cb_data->buf = kmalloc(size, GFP_KERNEL); 83 if (*cb_data->buf == NULL) 84 return -ENOMEM; 85 memcpy(*cb_data->buf, entry->var.Data, size); 86 return size; 87 } 88 89 static ssize_t efi_pstore_read(u64 *id, enum pstore_type_id *type, 90 int *count, struct timespec *timespec, 91 char **buf, struct pstore_info *psi) 92 { 93 struct pstore_read_data data; 94 95 data.id = id; 96 data.type = type; 97 data.count = count; 98 data.timespec = timespec; 99 data.buf = buf; 100 101 return __efivar_entry_iter(efi_pstore_read_func, &efivar_sysfs_list, &data, 102 (struct efivar_entry **)&psi->data); 103 } 104 105 static int efi_pstore_write(enum pstore_type_id type, 106 enum kmsg_dump_reason reason, u64 *id, 107 unsigned int part, int count, size_t size, 108 struct pstore_info *psi) 109 { 110 char name[DUMP_NAME_LEN]; 111 efi_char16_t efi_name[DUMP_NAME_LEN]; 112 efi_guid_t vendor = LINUX_EFI_CRASH_GUID; 113 int i, ret = 0; 114 115 sprintf(name, "dump-type%u-%u-%d-%lu", type, part, count, 116 get_seconds()); 117 118 for (i = 0; i < DUMP_NAME_LEN; i++) 119 efi_name[i] = name[i]; 120 121 efivar_entry_set_safe(efi_name, vendor, PSTORE_EFI_ATTRIBUTES, 122 !pstore_cannot_block_path(reason), 123 size, psi->buf); 124 125 if (reason == KMSG_DUMP_OOPS) 126 efivar_run_worker(); 127 128 *id = part; 129 return ret; 130 }; 131 132 struct pstore_erase_data { 133 u64 id; 134 enum pstore_type_id type; 135 int count; 136 struct timespec time; 137 efi_char16_t *name; 138 }; 139 140 /* 141 * Clean up an entry with the same name 142 */ 143 static int efi_pstore_erase_func(struct efivar_entry *entry, void *data) 144 { 145 struct pstore_erase_data *ed = data; 146 efi_guid_t vendor = LINUX_EFI_CRASH_GUID; 147 efi_char16_t efi_name_old[DUMP_NAME_LEN]; 148 efi_char16_t *efi_name = ed->name; 149 unsigned long ucs2_len = ucs2_strlen(ed->name); 150 char name_old[DUMP_NAME_LEN]; 151 int i; 152 153 if (efi_guidcmp(entry->var.VendorGuid, vendor)) 154 return 0; 155 156 if (ucs2_strncmp(entry->var.VariableName, 157 efi_name, (size_t)ucs2_len)) { 158 /* 159 * Check if an old format, which doesn't support 160 * holding multiple logs, remains. 161 */ 162 sprintf(name_old, "dump-type%u-%u-%lu", ed->type, 163 (unsigned int)ed->id, ed->time.tv_sec); 164 165 for (i = 0; i < DUMP_NAME_LEN; i++) 166 efi_name_old[i] = name_old[i]; 167 168 if (ucs2_strncmp(entry->var.VariableName, efi_name_old, 169 ucs2_strlen(efi_name_old))) 170 return 0; 171 } 172 173 /* found */ 174 __efivar_entry_delete(entry); 175 list_del(&entry->list); 176 177 return 1; 178 } 179 180 static int efi_pstore_erase(enum pstore_type_id type, u64 id, int count, 181 struct timespec time, struct pstore_info *psi) 182 { 183 struct pstore_erase_data edata; 184 struct efivar_entry *entry = NULL; 185 char name[DUMP_NAME_LEN]; 186 efi_char16_t efi_name[DUMP_NAME_LEN]; 187 int found, i; 188 189 sprintf(name, "dump-type%u-%u-%d-%lu", type, (unsigned int)id, count, 190 time.tv_sec); 191 192 for (i = 0; i < DUMP_NAME_LEN; i++) 193 efi_name[i] = name[i]; 194 195 edata.id = id; 196 edata.type = type; 197 edata.count = count; 198 edata.time = time; 199 edata.name = efi_name; 200 201 efivar_entry_iter_begin(); 202 found = __efivar_entry_iter(efi_pstore_erase_func, &efivar_sysfs_list, &edata, &entry); 203 efivar_entry_iter_end(); 204 205 if (found) 206 efivar_unregister(entry); 207 208 return 0; 209 } 210 211 static struct pstore_info efi_pstore_info = { 212 .owner = THIS_MODULE, 213 .name = "efi", 214 .open = efi_pstore_open, 215 .close = efi_pstore_close, 216 .read = efi_pstore_read, 217 .write = efi_pstore_write, 218 .erase = efi_pstore_erase, 219 }; 220 221 static __init int efivars_pstore_init(void) 222 { 223 if (!efi_enabled(EFI_RUNTIME_SERVICES)) 224 return 0; 225 226 if (!efivars_kobject()) 227 return 0; 228 229 if (efivars_pstore_disable) 230 return 0; 231 232 efi_pstore_info.buf = kmalloc(4096, GFP_KERNEL); 233 if (!efi_pstore_info.buf) 234 return -ENOMEM; 235 236 efi_pstore_info.bufsize = 1024; 237 spin_lock_init(&efi_pstore_info.buf_lock); 238 239 pstore_register(&efi_pstore_info); 240 241 return 0; 242 } 243 244 static __exit void efivars_pstore_exit(void) 245 { 246 } 247 248 module_init(efivars_pstore_init); 249 module_exit(efivars_pstore_exit); 250 251 MODULE_DESCRIPTION("EFI variable backend for pstore"); 252 MODULE_LICENSE("GPL"); 253