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 return -ENOMEM; 65 66 return 0; 67 } 68 69 static int efi_pstore_close(struct pstore_info *psi) 70 { 71 efivar_unlock(); 72 kfree(psi->data); 73 return 0; 74 } 75 76 static inline u64 generic_id(u64 timestamp, unsigned int part, int count) 77 { 78 return (timestamp * 100 + part) * 1000 + count; 79 } 80 81 static int efi_pstore_read_func(struct pstore_record *record, 82 efi_char16_t *varname) 83 { 84 unsigned long wlen, size = record_size; 85 char name[DUMP_NAME_LEN], data_type; 86 efi_status_t status; 87 int cnt; 88 unsigned int part; 89 u64 time; 90 91 ucs2_as_utf8(name, varname, DUMP_NAME_LEN); 92 93 if (sscanf(name, "dump-type%u-%u-%d-%llu-%c", 94 &record->type, &part, &cnt, &time, &data_type) == 5) { 95 record->id = generic_id(time, part, cnt); 96 record->part = part; 97 record->count = cnt; 98 record->time.tv_sec = time; 99 record->time.tv_nsec = 0; 100 if (data_type == 'C') 101 record->compressed = true; 102 else 103 record->compressed = false; 104 record->ecc_notice_size = 0; 105 } else if (sscanf(name, "dump-type%u-%u-%d-%llu", 106 &record->type, &part, &cnt, &time) == 4) { 107 record->id = generic_id(time, part, cnt); 108 record->part = part; 109 record->count = cnt; 110 record->time.tv_sec = time; 111 record->time.tv_nsec = 0; 112 record->compressed = false; 113 record->ecc_notice_size = 0; 114 } else if (sscanf(name, "dump-type%u-%u-%llu", 115 &record->type, &part, &time) == 3) { 116 /* 117 * Check if an old format, 118 * which doesn't support holding 119 * multiple logs, remains. 120 */ 121 record->id = generic_id(time, part, 0); 122 record->part = part; 123 record->count = 0; 124 record->time.tv_sec = time; 125 record->time.tv_nsec = 0; 126 record->compressed = false; 127 record->ecc_notice_size = 0; 128 } else 129 return 0; 130 131 record->buf = kmalloc(size, GFP_KERNEL); 132 if (!record->buf) 133 return -ENOMEM; 134 135 status = efivar_get_variable(varname, &LINUX_EFI_CRASH_GUID, NULL, 136 &size, record->buf); 137 if (status != EFI_SUCCESS) { 138 kfree(record->buf); 139 return -EIO; 140 } 141 142 /* 143 * Store the name of the variable in the pstore_record priv field, so 144 * we can reuse it later if we need to delete the EFI variable from the 145 * variable store. 146 */ 147 wlen = (ucs2_strnlen(varname, DUMP_NAME_LEN) + 1) * sizeof(efi_char16_t); 148 record->priv = kmemdup(varname, wlen, GFP_KERNEL); 149 if (!record->priv) { 150 kfree(record->buf); 151 return -ENOMEM; 152 } 153 154 return size; 155 } 156 157 static ssize_t efi_pstore_read(struct pstore_record *record) 158 { 159 efi_char16_t *varname = record->psi->data; 160 efi_guid_t guid = LINUX_EFI_CRASH_GUID; 161 unsigned long varname_size; 162 efi_status_t status; 163 164 for (;;) { 165 varname_size = 1024; 166 167 /* 168 * If this is the first read() call in the pstore enumeration, 169 * varname will be the empty string, and the GetNextVariable() 170 * runtime service call will return the first EFI variable in 171 * its own enumeration order, ignoring the guid argument. 172 * 173 * Subsequent calls to GetNextVariable() must pass the name and 174 * guid values returned by the previous call, which is why we 175 * store varname in record->psi->data. Given that we only 176 * enumerate variables with the efi-pstore GUID, there is no 177 * need to record the guid return value. 178 */ 179 status = efivar_get_next_variable(&varname_size, varname, &guid); 180 if (status == EFI_NOT_FOUND) 181 return 0; 182 183 if (status != EFI_SUCCESS) 184 return -EIO; 185 186 /* skip variables that don't concern us */ 187 if (efi_guidcmp(guid, LINUX_EFI_CRASH_GUID)) 188 continue; 189 190 return efi_pstore_read_func(record, varname); 191 } 192 } 193 194 static int efi_pstore_write(struct pstore_record *record) 195 { 196 char name[DUMP_NAME_LEN]; 197 efi_char16_t efi_name[DUMP_NAME_LEN]; 198 efi_status_t status; 199 int i; 200 201 record->id = generic_id(record->time.tv_sec, record->part, 202 record->count); 203 204 /* Since we copy the entire length of name, make sure it is wiped. */ 205 memset(name, 0, sizeof(name)); 206 207 snprintf(name, sizeof(name), "dump-type%u-%u-%d-%lld-%c", 208 record->type, record->part, record->count, 209 (long long)record->time.tv_sec, 210 record->compressed ? 'C' : 'D'); 211 212 for (i = 0; i < DUMP_NAME_LEN; i++) 213 efi_name[i] = name[i]; 214 215 if (efivar_trylock()) 216 return -EBUSY; 217 status = efivar_set_variable_locked(efi_name, &LINUX_EFI_CRASH_GUID, 218 PSTORE_EFI_ATTRIBUTES, 219 record->size, record->psi->buf, 220 true); 221 efivar_unlock(); 222 return status == EFI_SUCCESS ? 0 : -EIO; 223 }; 224 225 static int efi_pstore_erase(struct pstore_record *record) 226 { 227 efi_status_t status; 228 229 status = efivar_set_variable(record->priv, &LINUX_EFI_CRASH_GUID, 230 PSTORE_EFI_ATTRIBUTES, 0, NULL); 231 232 if (status != EFI_SUCCESS && status != EFI_NOT_FOUND) 233 return -EIO; 234 return 0; 235 } 236 237 static struct pstore_info efi_pstore_info = { 238 .owner = THIS_MODULE, 239 .name = KBUILD_MODNAME, 240 .flags = PSTORE_FLAGS_DMESG, 241 .open = efi_pstore_open, 242 .close = efi_pstore_close, 243 .read = efi_pstore_read, 244 .write = efi_pstore_write, 245 .erase = efi_pstore_erase, 246 }; 247 248 static int efivars_pstore_init(void) 249 { 250 if (!efivar_supports_writes()) 251 return 0; 252 253 if (pstore_disable) 254 return 0; 255 256 /* 257 * Notice that 1024 is the minimum here to prevent issues with 258 * decompression algorithms that were spotted during tests; 259 * even in the case of not using compression, smaller values would 260 * just pollute more the pstore FS with many small collected files. 261 */ 262 if (record_size < 1024) 263 record_size = 1024; 264 265 efi_pstore_info.buf = kmalloc(record_size, GFP_KERNEL); 266 if (!efi_pstore_info.buf) 267 return -ENOMEM; 268 269 efi_pstore_info.bufsize = record_size; 270 271 if (pstore_register(&efi_pstore_info)) { 272 kfree(efi_pstore_info.buf); 273 efi_pstore_info.buf = NULL; 274 efi_pstore_info.bufsize = 0; 275 } 276 277 return 0; 278 } 279 280 static void efivars_pstore_exit(void) 281 { 282 if (!efi_pstore_info.bufsize) 283 return; 284 285 pstore_unregister(&efi_pstore_info); 286 kfree(efi_pstore_info.buf); 287 efi_pstore_info.buf = NULL; 288 efi_pstore_info.bufsize = 0; 289 } 290 291 module_init(efivars_pstore_init); 292 module_exit(efivars_pstore_exit); 293 294 MODULE_DESCRIPTION("EFI variable backend for pstore"); 295 MODULE_LICENSE("GPL"); 296 MODULE_ALIAS("platform:efivars"); 297