1 // SPDX-License-Identifier: GPL-2.0+ 2 3 #include <linux/efi.h> 4 #include <linux/module.h> 5 #include <linux/pstore.h> 6 #include <linux/slab.h> 7 #include <linux/ucs2_string.h> 8 9 MODULE_IMPORT_NS("EFIVAR"); 10 11 #define DUMP_NAME_LEN 66 12 13 static unsigned int record_size = 1024; 14 module_param(record_size, uint, 0444); 15 MODULE_PARM_DESC(record_size, "size of each pstore UEFI var (in bytes, min/default=1024)"); 16 17 #define PSTORE_EFI_ATTRIBUTES \ 18 (EFI_VARIABLE_NON_VOLATILE | \ 19 EFI_VARIABLE_BOOTSERVICE_ACCESS | \ 20 EFI_VARIABLE_RUNTIME_ACCESS) 21 22 static bool pstore_disable = IS_ENABLED(CONFIG_EFI_VARS_PSTORE_DEFAULT_DISABLE); 23 24 static int efivars_pstore_init(void); 25 static void efivars_pstore_exit(void); 26 27 static int efi_pstore_disable_set(const char *val, const struct kernel_param *kp) 28 { 29 int err; 30 bool old_pstore_disable = pstore_disable; 31 32 err = param_set_bool(val, kp); 33 if (err) 34 return err; 35 36 if (old_pstore_disable != pstore_disable) { 37 if (pstore_disable) 38 efivars_pstore_exit(); 39 else 40 efivars_pstore_init(); 41 } 42 43 return 0; 44 } 45 46 static const struct kernel_param_ops pstore_disable_ops = { 47 .set = efi_pstore_disable_set, 48 .get = param_get_bool, 49 }; 50 51 module_param_cb(pstore_disable, &pstore_disable_ops, &pstore_disable, 0644); 52 __MODULE_PARM_TYPE(pstore_disable, "bool"); 53 54 static int efi_pstore_open(struct pstore_info *psi) 55 { 56 int err; 57 58 err = efivar_lock(); 59 if (err) 60 return err; 61 62 psi->data = kzalloc(record_size, GFP_KERNEL); 63 if (!psi->data) { 64 efivar_unlock(); 65 return -ENOMEM; 66 } 67 68 return 0; 69 } 70 71 static int efi_pstore_close(struct pstore_info *psi) 72 { 73 efivar_unlock(); 74 kfree(psi->data); 75 return 0; 76 } 77 78 static inline u64 generic_id(u64 timestamp, unsigned int part, int count) 79 { 80 return (timestamp * 100 + part) * 1000 + count; 81 } 82 83 static int efi_pstore_read_func(struct pstore_record *record, 84 efi_char16_t *varname) 85 { 86 unsigned long wlen, size = record_size; 87 char name[DUMP_NAME_LEN], data_type; 88 efi_status_t status; 89 int cnt; 90 unsigned int part; 91 u64 time; 92 93 ucs2_as_utf8(name, varname, DUMP_NAME_LEN); 94 95 if (sscanf(name, "dump-type%u-%u-%d-%llu-%c", 96 &record->type, &part, &cnt, &time, &data_type) == 5) { 97 record->id = generic_id(time, part, cnt); 98 record->part = part; 99 record->count = cnt; 100 record->time.tv_sec = time; 101 record->time.tv_nsec = 0; 102 if (data_type == 'C') 103 record->compressed = true; 104 else 105 record->compressed = false; 106 record->ecc_notice_size = 0; 107 } else if (sscanf(name, "dump-type%u-%u-%d-%llu", 108 &record->type, &part, &cnt, &time) == 4) { 109 record->id = generic_id(time, part, cnt); 110 record->part = part; 111 record->count = cnt; 112 record->time.tv_sec = time; 113 record->time.tv_nsec = 0; 114 record->compressed = false; 115 record->ecc_notice_size = 0; 116 } else if (sscanf(name, "dump-type%u-%u-%llu", 117 &record->type, &part, &time) == 3) { 118 /* 119 * Check if an old format, 120 * which doesn't support holding 121 * multiple logs, remains. 122 */ 123 record->id = generic_id(time, part, 0); 124 record->part = part; 125 record->count = 0; 126 record->time.tv_sec = time; 127 record->time.tv_nsec = 0; 128 record->compressed = false; 129 record->ecc_notice_size = 0; 130 } else 131 return 0; 132 133 record->buf = kmalloc(size, GFP_KERNEL); 134 if (!record->buf) 135 return -ENOMEM; 136 137 status = efivar_get_variable(varname, &LINUX_EFI_CRASH_GUID, NULL, 138 &size, record->buf); 139 if (status != EFI_SUCCESS) { 140 kfree(record->buf); 141 return efi_status_to_err(status); 142 } 143 144 /* 145 * Store the name of the variable in the pstore_record priv field, so 146 * we can reuse it later if we need to delete the EFI variable from the 147 * variable store. 148 */ 149 wlen = (ucs2_strnlen(varname, DUMP_NAME_LEN) + 1) * sizeof(efi_char16_t); 150 record->priv = kmemdup(varname, wlen, GFP_KERNEL); 151 if (!record->priv) { 152 kfree(record->buf); 153 return -ENOMEM; 154 } 155 156 return size; 157 } 158 159 static ssize_t efi_pstore_read(struct pstore_record *record) 160 { 161 efi_char16_t *varname = record->psi->data; 162 efi_guid_t guid = LINUX_EFI_CRASH_GUID; 163 unsigned long varname_size; 164 efi_status_t status; 165 166 for (;;) { 167 /* 168 * A small set of old UEFI implementations reject sizes 169 * above a certain threshold, the lowest seen in the wild 170 * is 512. 171 * 172 * TODO: Commonize with the iteration implementation in 173 * fs/efivarfs to keep all the quirks in one place. 174 */ 175 varname_size = 512; 176 177 /* 178 * If this is the first read() call in the pstore enumeration, 179 * varname will be the empty string, and the GetNextVariable() 180 * runtime service call will return the first EFI variable in 181 * its own enumeration order, ignoring the guid argument. 182 * 183 * Subsequent calls to GetNextVariable() must pass the name and 184 * guid values returned by the previous call, which is why we 185 * store varname in record->psi->data. Given that we only 186 * enumerate variables with the efi-pstore GUID, there is no 187 * need to record the guid return value. 188 */ 189 status = efivar_get_next_variable(&varname_size, varname, &guid); 190 if (status == EFI_NOT_FOUND) 191 return 0; 192 193 if (status != EFI_SUCCESS) 194 return efi_status_to_err(status); 195 196 /* skip variables that don't concern us */ 197 if (efi_guidcmp(guid, LINUX_EFI_CRASH_GUID)) 198 continue; 199 200 return efi_pstore_read_func(record, varname); 201 } 202 } 203 204 static int efi_pstore_write(struct pstore_record *record) 205 { 206 char name[DUMP_NAME_LEN]; 207 efi_char16_t efi_name[DUMP_NAME_LEN]; 208 efi_status_t status; 209 int i; 210 211 record->id = generic_id(record->time.tv_sec, record->part, 212 record->count); 213 214 /* Since we copy the entire length of name, make sure it is wiped. */ 215 memset(name, 0, sizeof(name)); 216 217 snprintf(name, sizeof(name), "dump-type%u-%u-%d-%lld-%c", 218 record->type, record->part, record->count, 219 (long long)record->time.tv_sec, 220 record->compressed ? 'C' : 'D'); 221 222 for (i = 0; i < DUMP_NAME_LEN; i++) 223 efi_name[i] = name[i]; 224 225 if (efivar_trylock()) 226 return -EBUSY; 227 status = efivar_set_variable_locked(efi_name, &LINUX_EFI_CRASH_GUID, 228 PSTORE_EFI_ATTRIBUTES, 229 record->size, record->psi->buf, 230 true); 231 efivar_unlock(); 232 return efi_status_to_err(status); 233 }; 234 235 static int efi_pstore_erase(struct pstore_record *record) 236 { 237 efi_status_t status; 238 239 status = efivar_set_variable(record->priv, &LINUX_EFI_CRASH_GUID, 240 PSTORE_EFI_ATTRIBUTES, 0, NULL); 241 242 if (status != EFI_SUCCESS && status != EFI_NOT_FOUND) 243 return efi_status_to_err(status); 244 return 0; 245 } 246 247 static struct pstore_info efi_pstore_info = { 248 .owner = THIS_MODULE, 249 .name = KBUILD_MODNAME, 250 .flags = PSTORE_FLAGS_DMESG, 251 .open = efi_pstore_open, 252 .close = efi_pstore_close, 253 .read = efi_pstore_read, 254 .write = efi_pstore_write, 255 .erase = efi_pstore_erase, 256 }; 257 258 static int efivars_pstore_init(void) 259 { 260 if (!efivar_supports_writes()) 261 return 0; 262 263 if (pstore_disable) 264 return 0; 265 266 /* 267 * Notice that 1024 is the minimum here to prevent issues with 268 * decompression algorithms that were spotted during tests; 269 * even in the case of not using compression, smaller values would 270 * just pollute more the pstore FS with many small collected files. 271 */ 272 if (record_size < 1024) 273 record_size = 1024; 274 275 efi_pstore_info.buf = kmalloc(record_size, GFP_KERNEL); 276 if (!efi_pstore_info.buf) 277 return -ENOMEM; 278 279 efi_pstore_info.bufsize = record_size; 280 281 if (pstore_register(&efi_pstore_info)) { 282 kfree(efi_pstore_info.buf); 283 efi_pstore_info.buf = NULL; 284 efi_pstore_info.bufsize = 0; 285 } 286 287 return 0; 288 } 289 290 static void efivars_pstore_exit(void) 291 { 292 if (!efi_pstore_info.bufsize) 293 return; 294 295 pstore_unregister(&efi_pstore_info); 296 kfree(efi_pstore_info.buf); 297 efi_pstore_info.buf = NULL; 298 efi_pstore_info.bufsize = 0; 299 } 300 301 module_init(efivars_pstore_init); 302 module_exit(efivars_pstore_exit); 303 304 MODULE_DESCRIPTION("EFI variable backend for pstore"); 305 MODULE_LICENSE("GPL"); 306 MODULE_ALIAS("platform:efivars"); 307