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 = kmemdup(entry->var.Data, size, GFP_KERNEL); 83 if (*cb_data->buf == NULL) 84 return -ENOMEM; 85 return size; 86 } 87 88 static ssize_t efi_pstore_read(u64 *id, enum pstore_type_id *type, 89 int *count, struct timespec *timespec, 90 char **buf, struct pstore_info *psi) 91 { 92 struct pstore_read_data data; 93 94 data.id = id; 95 data.type = type; 96 data.count = count; 97 data.timespec = timespec; 98 data.buf = buf; 99 100 return __efivar_entry_iter(efi_pstore_read_func, &efivar_sysfs_list, &data, 101 (struct efivar_entry **)&psi->data); 102 } 103 104 static int efi_pstore_write(enum pstore_type_id type, 105 enum kmsg_dump_reason reason, u64 *id, 106 unsigned int part, int count, size_t hsize, size_t size, 107 struct pstore_info *psi) 108 { 109 char name[DUMP_NAME_LEN]; 110 efi_char16_t efi_name[DUMP_NAME_LEN]; 111 efi_guid_t vendor = LINUX_EFI_CRASH_GUID; 112 int i, ret = 0; 113 114 sprintf(name, "dump-type%u-%u-%d-%lu", type, part, count, 115 get_seconds()); 116 117 for (i = 0; i < DUMP_NAME_LEN; i++) 118 efi_name[i] = name[i]; 119 120 efivar_entry_set_safe(efi_name, vendor, PSTORE_EFI_ATTRIBUTES, 121 !pstore_cannot_block_path(reason), 122 size, psi->buf); 123 124 if (reason == KMSG_DUMP_OOPS) 125 efivar_run_worker(); 126 127 *id = part; 128 return ret; 129 }; 130 131 struct pstore_erase_data { 132 u64 id; 133 enum pstore_type_id type; 134 int count; 135 struct timespec time; 136 efi_char16_t *name; 137 }; 138 139 /* 140 * Clean up an entry with the same name 141 */ 142 static int efi_pstore_erase_func(struct efivar_entry *entry, void *data) 143 { 144 struct pstore_erase_data *ed = data; 145 efi_guid_t vendor = LINUX_EFI_CRASH_GUID; 146 efi_char16_t efi_name_old[DUMP_NAME_LEN]; 147 efi_char16_t *efi_name = ed->name; 148 unsigned long ucs2_len = ucs2_strlen(ed->name); 149 char name_old[DUMP_NAME_LEN]; 150 int i; 151 152 if (efi_guidcmp(entry->var.VendorGuid, vendor)) 153 return 0; 154 155 if (ucs2_strncmp(entry->var.VariableName, 156 efi_name, (size_t)ucs2_len)) { 157 /* 158 * Check if an old format, which doesn't support 159 * holding multiple logs, remains. 160 */ 161 sprintf(name_old, "dump-type%u-%u-%lu", ed->type, 162 (unsigned int)ed->id, ed->time.tv_sec); 163 164 for (i = 0; i < DUMP_NAME_LEN; i++) 165 efi_name_old[i] = name_old[i]; 166 167 if (ucs2_strncmp(entry->var.VariableName, efi_name_old, 168 ucs2_strlen(efi_name_old))) 169 return 0; 170 } 171 172 /* found */ 173 __efivar_entry_delete(entry); 174 list_del(&entry->list); 175 176 return 1; 177 } 178 179 static int efi_pstore_erase(enum pstore_type_id type, u64 id, int count, 180 struct timespec time, struct pstore_info *psi) 181 { 182 struct pstore_erase_data edata; 183 struct efivar_entry *entry = NULL; 184 char name[DUMP_NAME_LEN]; 185 efi_char16_t efi_name[DUMP_NAME_LEN]; 186 int found, i; 187 188 sprintf(name, "dump-type%u-%u-%d-%lu", type, (unsigned int)id, count, 189 time.tv_sec); 190 191 for (i = 0; i < DUMP_NAME_LEN; i++) 192 efi_name[i] = name[i]; 193 194 edata.id = id; 195 edata.type = type; 196 edata.count = count; 197 edata.time = time; 198 edata.name = efi_name; 199 200 efivar_entry_iter_begin(); 201 found = __efivar_entry_iter(efi_pstore_erase_func, &efivar_sysfs_list, &edata, &entry); 202 efivar_entry_iter_end(); 203 204 if (found) 205 efivar_unregister(entry); 206 207 return 0; 208 } 209 210 static struct pstore_info efi_pstore_info = { 211 .owner = THIS_MODULE, 212 .name = "efi", 213 .open = efi_pstore_open, 214 .close = efi_pstore_close, 215 .read = efi_pstore_read, 216 .write = efi_pstore_write, 217 .erase = efi_pstore_erase, 218 }; 219 220 static __init int efivars_pstore_init(void) 221 { 222 if (!efi_enabled(EFI_RUNTIME_SERVICES)) 223 return 0; 224 225 if (!efivars_kobject()) 226 return 0; 227 228 if (efivars_pstore_disable) 229 return 0; 230 231 efi_pstore_info.buf = kmalloc(4096, GFP_KERNEL); 232 if (!efi_pstore_info.buf) 233 return -ENOMEM; 234 235 efi_pstore_info.bufsize = 1024; 236 spin_lock_init(&efi_pstore_info.buf_lock); 237 238 if (pstore_register(&efi_pstore_info)) { 239 kfree(efi_pstore_info.buf); 240 efi_pstore_info.buf = NULL; 241 efi_pstore_info.bufsize = 0; 242 } 243 244 return 0; 245 } 246 247 static __exit void efivars_pstore_exit(void) 248 { 249 } 250 251 module_init(efivars_pstore_init); 252 module_exit(efivars_pstore_exit); 253 254 MODULE_DESCRIPTION("EFI variable backend for pstore"); 255 MODULE_LICENSE("GPL"); 256