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 #define EFIVARS_DATA_SIZE_MAX 1024 14 15 static bool efivars_pstore_disable = 16 IS_ENABLED(CONFIG_EFI_VARS_PSTORE_DEFAULT_DISABLE); 17 18 module_param_named(pstore_disable, efivars_pstore_disable, bool, 0644); 19 20 #define PSTORE_EFI_ATTRIBUTES \ 21 (EFI_VARIABLE_NON_VOLATILE | \ 22 EFI_VARIABLE_BOOTSERVICE_ACCESS | \ 23 EFI_VARIABLE_RUNTIME_ACCESS) 24 25 static int efi_pstore_open(struct pstore_info *psi) 26 { 27 int err; 28 29 err = efivar_lock(); 30 if (err) 31 return err; 32 33 psi->data = kzalloc(EFIVARS_DATA_SIZE_MAX, GFP_KERNEL); 34 if (!psi->data) 35 return -ENOMEM; 36 37 return 0; 38 } 39 40 static int efi_pstore_close(struct pstore_info *psi) 41 { 42 efivar_unlock(); 43 kfree(psi->data); 44 return 0; 45 } 46 47 static inline u64 generic_id(u64 timestamp, unsigned int part, int count) 48 { 49 return (timestamp * 100 + part) * 1000 + count; 50 } 51 52 static int efi_pstore_read_func(struct pstore_record *record, 53 efi_char16_t *varname) 54 { 55 unsigned long wlen, size = EFIVARS_DATA_SIZE_MAX; 56 char name[DUMP_NAME_LEN], data_type; 57 efi_status_t status; 58 int cnt; 59 unsigned int part; 60 u64 time; 61 62 ucs2_as_utf8(name, varname, DUMP_NAME_LEN); 63 64 if (sscanf(name, "dump-type%u-%u-%d-%llu-%c", 65 &record->type, &part, &cnt, &time, &data_type) == 5) { 66 record->id = generic_id(time, part, cnt); 67 record->part = part; 68 record->count = cnt; 69 record->time.tv_sec = time; 70 record->time.tv_nsec = 0; 71 if (data_type == 'C') 72 record->compressed = true; 73 else 74 record->compressed = false; 75 record->ecc_notice_size = 0; 76 } else if (sscanf(name, "dump-type%u-%u-%d-%llu", 77 &record->type, &part, &cnt, &time) == 4) { 78 record->id = generic_id(time, part, cnt); 79 record->part = part; 80 record->count = cnt; 81 record->time.tv_sec = time; 82 record->time.tv_nsec = 0; 83 record->compressed = false; 84 record->ecc_notice_size = 0; 85 } else if (sscanf(name, "dump-type%u-%u-%llu", 86 &record->type, &part, &time) == 3) { 87 /* 88 * Check if an old format, 89 * which doesn't support holding 90 * multiple logs, remains. 91 */ 92 record->id = generic_id(time, part, 0); 93 record->part = part; 94 record->count = 0; 95 record->time.tv_sec = time; 96 record->time.tv_nsec = 0; 97 record->compressed = false; 98 record->ecc_notice_size = 0; 99 } else 100 return 0; 101 102 record->buf = kmalloc(size, GFP_KERNEL); 103 if (!record->buf) 104 return -ENOMEM; 105 106 status = efivar_get_variable(varname, &LINUX_EFI_CRASH_GUID, NULL, 107 &size, record->buf); 108 if (status != EFI_SUCCESS) { 109 kfree(record->buf); 110 return -EIO; 111 } 112 113 /* 114 * Store the name of the variable in the pstore_record priv field, so 115 * we can reuse it later if we need to delete the EFI variable from the 116 * variable store. 117 */ 118 wlen = (ucs2_strnlen(varname, DUMP_NAME_LEN) + 1) * sizeof(efi_char16_t); 119 record->priv = kmemdup(varname, wlen, GFP_KERNEL); 120 if (!record->priv) { 121 kfree(record->buf); 122 return -ENOMEM; 123 } 124 125 return size; 126 } 127 128 static ssize_t efi_pstore_read(struct pstore_record *record) 129 { 130 efi_char16_t *varname = record->psi->data; 131 efi_guid_t guid = LINUX_EFI_CRASH_GUID; 132 unsigned long varname_size; 133 efi_status_t status; 134 135 for (;;) { 136 varname_size = EFIVARS_DATA_SIZE_MAX; 137 138 /* 139 * If this is the first read() call in the pstore enumeration, 140 * varname will be the empty string, and the GetNextVariable() 141 * runtime service call will return the first EFI variable in 142 * its own enumeration order, ignoring the guid argument. 143 * 144 * Subsequent calls to GetNextVariable() must pass the name and 145 * guid values returned by the previous call, which is why we 146 * store varname in record->psi->data. Given that we only 147 * enumerate variables with the efi-pstore GUID, there is no 148 * need to record the guid return value. 149 */ 150 status = efivar_get_next_variable(&varname_size, varname, &guid); 151 if (status == EFI_NOT_FOUND) 152 return 0; 153 154 if (status != EFI_SUCCESS) 155 return -EIO; 156 157 /* skip variables that don't concern us */ 158 if (efi_guidcmp(guid, LINUX_EFI_CRASH_GUID)) 159 continue; 160 161 return efi_pstore_read_func(record, varname); 162 } 163 } 164 165 static int efi_pstore_write(struct pstore_record *record) 166 { 167 char name[DUMP_NAME_LEN]; 168 efi_char16_t efi_name[DUMP_NAME_LEN]; 169 efi_status_t status; 170 int i; 171 172 record->id = generic_id(record->time.tv_sec, record->part, 173 record->count); 174 175 /* Since we copy the entire length of name, make sure it is wiped. */ 176 memset(name, 0, sizeof(name)); 177 178 snprintf(name, sizeof(name), "dump-type%u-%u-%d-%lld-%c", 179 record->type, record->part, record->count, 180 (long long)record->time.tv_sec, 181 record->compressed ? 'C' : 'D'); 182 183 for (i = 0; i < DUMP_NAME_LEN; i++) 184 efi_name[i] = name[i]; 185 186 if (efivar_trylock()) 187 return -EBUSY; 188 status = efivar_set_variable_locked(efi_name, &LINUX_EFI_CRASH_GUID, 189 PSTORE_EFI_ATTRIBUTES, 190 record->size, record->psi->buf, 191 true); 192 efivar_unlock(); 193 return status == EFI_SUCCESS ? 0 : -EIO; 194 }; 195 196 static int efi_pstore_erase(struct pstore_record *record) 197 { 198 efi_status_t status; 199 200 status = efivar_set_variable(record->priv, &LINUX_EFI_CRASH_GUID, 201 PSTORE_EFI_ATTRIBUTES, 0, NULL); 202 203 if (status != EFI_SUCCESS && status != EFI_NOT_FOUND) 204 return -EIO; 205 return 0; 206 } 207 208 static struct pstore_info efi_pstore_info = { 209 .owner = THIS_MODULE, 210 .name = "efi", 211 .flags = PSTORE_FLAGS_DMESG, 212 .open = efi_pstore_open, 213 .close = efi_pstore_close, 214 .read = efi_pstore_read, 215 .write = efi_pstore_write, 216 .erase = efi_pstore_erase, 217 }; 218 219 static __init int efivars_pstore_init(void) 220 { 221 if (!efivar_supports_writes()) 222 return 0; 223 224 if (efivars_pstore_disable) 225 return 0; 226 227 efi_pstore_info.buf = kmalloc(4096, GFP_KERNEL); 228 if (!efi_pstore_info.buf) 229 return -ENOMEM; 230 231 efi_pstore_info.bufsize = 1024; 232 233 if (pstore_register(&efi_pstore_info)) { 234 kfree(efi_pstore_info.buf); 235 efi_pstore_info.buf = NULL; 236 efi_pstore_info.bufsize = 0; 237 } 238 239 return 0; 240 } 241 242 static __exit void efivars_pstore_exit(void) 243 { 244 if (!efi_pstore_info.bufsize) 245 return; 246 247 pstore_unregister(&efi_pstore_info); 248 kfree(efi_pstore_info.buf); 249 efi_pstore_info.buf = NULL; 250 efi_pstore_info.bufsize = 0; 251 } 252 253 module_init(efivars_pstore_init); 254 module_exit(efivars_pstore_exit); 255 256 MODULE_DESCRIPTION("EFI variable backend for pstore"); 257 MODULE_LICENSE("GPL"); 258 MODULE_ALIAS("platform:efivars"); 259