Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 
0003 #include <linux/efi.h>
0004 #include <linux/module.h>
0005 #include <linux/pstore.h>
0006 #include <linux/slab.h>
0007 #include <linux/ucs2_string.h>
0008 
0009 MODULE_IMPORT_NS(EFIVAR);
0010 
0011 #define DUMP_NAME_LEN 66
0012 
0013 #define EFIVARS_DATA_SIZE_MAX 1024
0014 
0015 static bool efivars_pstore_disable =
0016     IS_ENABLED(CONFIG_EFI_VARS_PSTORE_DEFAULT_DISABLE);
0017 
0018 module_param_named(pstore_disable, efivars_pstore_disable, bool, 0644);
0019 
0020 #define PSTORE_EFI_ATTRIBUTES \
0021     (EFI_VARIABLE_NON_VOLATILE | \
0022      EFI_VARIABLE_BOOTSERVICE_ACCESS | \
0023      EFI_VARIABLE_RUNTIME_ACCESS)
0024 
0025 static int efi_pstore_open(struct pstore_info *psi)
0026 {
0027     int err;
0028 
0029     err = efivar_lock();
0030     if (err)
0031         return err;
0032 
0033     psi->data = kzalloc(EFIVARS_DATA_SIZE_MAX, GFP_KERNEL);
0034     if (!psi->data)
0035         return -ENOMEM;
0036 
0037     return 0;
0038 }
0039 
0040 static int efi_pstore_close(struct pstore_info *psi)
0041 {
0042     efivar_unlock();
0043     kfree(psi->data);
0044     return 0;
0045 }
0046 
0047 static inline u64 generic_id(u64 timestamp, unsigned int part, int count)
0048 {
0049     return (timestamp * 100 + part) * 1000 + count;
0050 }
0051 
0052 static int efi_pstore_read_func(struct pstore_record *record,
0053                 efi_char16_t *varname)
0054 {
0055     unsigned long wlen, size = EFIVARS_DATA_SIZE_MAX;
0056     char name[DUMP_NAME_LEN], data_type;
0057     efi_status_t status;
0058     int cnt;
0059     unsigned int part;
0060     u64 time;
0061 
0062     ucs2_as_utf8(name, varname, DUMP_NAME_LEN);
0063 
0064     if (sscanf(name, "dump-type%u-%u-%d-%llu-%c",
0065            &record->type, &part, &cnt, &time, &data_type) == 5) {
0066         record->id = generic_id(time, part, cnt);
0067         record->part = part;
0068         record->count = cnt;
0069         record->time.tv_sec = time;
0070         record->time.tv_nsec = 0;
0071         if (data_type == 'C')
0072             record->compressed = true;
0073         else
0074             record->compressed = false;
0075         record->ecc_notice_size = 0;
0076     } else if (sscanf(name, "dump-type%u-%u-%d-%llu",
0077            &record->type, &part, &cnt, &time) == 4) {
0078         record->id = generic_id(time, part, cnt);
0079         record->part = part;
0080         record->count = cnt;
0081         record->time.tv_sec = time;
0082         record->time.tv_nsec = 0;
0083         record->compressed = false;
0084         record->ecc_notice_size = 0;
0085     } else if (sscanf(name, "dump-type%u-%u-%llu",
0086               &record->type, &part, &time) == 3) {
0087         /*
0088          * Check if an old format,
0089          * which doesn't support holding
0090          * multiple logs, remains.
0091          */
0092         record->id = generic_id(time, part, 0);
0093         record->part = part;
0094         record->count = 0;
0095         record->time.tv_sec = time;
0096         record->time.tv_nsec = 0;
0097         record->compressed = false;
0098         record->ecc_notice_size = 0;
0099     } else
0100         return 0;
0101 
0102     record->buf = kmalloc(size, GFP_KERNEL);
0103     if (!record->buf)
0104         return -ENOMEM;
0105 
0106     status = efivar_get_variable(varname, &LINUX_EFI_CRASH_GUID, NULL,
0107                      &size, record->buf);
0108     if (status != EFI_SUCCESS) {
0109         kfree(record->buf);
0110         return -EIO;
0111     }
0112 
0113     /*
0114      * Store the name of the variable in the pstore_record priv field, so
0115      * we can reuse it later if we need to delete the EFI variable from the
0116      * variable store.
0117      */
0118     wlen = (ucs2_strnlen(varname, DUMP_NAME_LEN) + 1) * sizeof(efi_char16_t);
0119     record->priv = kmemdup(varname, wlen, GFP_KERNEL);
0120     if (!record->priv) {
0121         kfree(record->buf);
0122         return -ENOMEM;
0123     }
0124 
0125     return size;
0126 }
0127 
0128 static ssize_t efi_pstore_read(struct pstore_record *record)
0129 {
0130     efi_char16_t *varname = record->psi->data;
0131     efi_guid_t guid = LINUX_EFI_CRASH_GUID;
0132     unsigned long varname_size;
0133     efi_status_t status;
0134 
0135     for (;;) {
0136         varname_size = EFIVARS_DATA_SIZE_MAX;
0137 
0138         /*
0139          * If this is the first read() call in the pstore enumeration,
0140          * varname will be the empty string, and the GetNextVariable()
0141          * runtime service call will return the first EFI variable in
0142          * its own enumeration order, ignoring the guid argument.
0143          *
0144          * Subsequent calls to GetNextVariable() must pass the name and
0145          * guid values returned by the previous call, which is why we
0146          * store varname in record->psi->data. Given that we only
0147          * enumerate variables with the efi-pstore GUID, there is no
0148          * need to record the guid return value.
0149          */
0150         status = efivar_get_next_variable(&varname_size, varname, &guid);
0151         if (status == EFI_NOT_FOUND)
0152             return 0;
0153 
0154         if (status != EFI_SUCCESS)
0155             return -EIO;
0156 
0157         /* skip variables that don't concern us */
0158         if (efi_guidcmp(guid, LINUX_EFI_CRASH_GUID))
0159             continue;
0160 
0161         return efi_pstore_read_func(record, varname);
0162     }
0163 }
0164 
0165 static int efi_pstore_write(struct pstore_record *record)
0166 {
0167     char name[DUMP_NAME_LEN];
0168     efi_char16_t efi_name[DUMP_NAME_LEN];
0169     efi_status_t status;
0170     int i;
0171 
0172     record->id = generic_id(record->time.tv_sec, record->part,
0173                 record->count);
0174 
0175     /* Since we copy the entire length of name, make sure it is wiped. */
0176     memset(name, 0, sizeof(name));
0177 
0178     snprintf(name, sizeof(name), "dump-type%u-%u-%d-%lld-%c",
0179          record->type, record->part, record->count,
0180          (long long)record->time.tv_sec,
0181          record->compressed ? 'C' : 'D');
0182 
0183     for (i = 0; i < DUMP_NAME_LEN; i++)
0184         efi_name[i] = name[i];
0185 
0186     if (efivar_trylock())
0187         return -EBUSY;
0188     status = efivar_set_variable_locked(efi_name, &LINUX_EFI_CRASH_GUID,
0189                         PSTORE_EFI_ATTRIBUTES,
0190                         record->size, record->psi->buf,
0191                         true);
0192     efivar_unlock();
0193     return status == EFI_SUCCESS ? 0 : -EIO;
0194 };
0195 
0196 static int efi_pstore_erase(struct pstore_record *record)
0197 {
0198     efi_status_t status;
0199 
0200     status = efivar_set_variable(record->priv, &LINUX_EFI_CRASH_GUID,
0201                      PSTORE_EFI_ATTRIBUTES, 0, NULL);
0202 
0203     if (status != EFI_SUCCESS && status != EFI_NOT_FOUND)
0204         return -EIO;
0205     return 0;
0206 }
0207 
0208 static struct pstore_info efi_pstore_info = {
0209     .owner      = THIS_MODULE,
0210     .name       = "efi",
0211     .flags      = PSTORE_FLAGS_DMESG,
0212     .open       = efi_pstore_open,
0213     .close      = efi_pstore_close,
0214     .read       = efi_pstore_read,
0215     .write      = efi_pstore_write,
0216     .erase      = efi_pstore_erase,
0217 };
0218 
0219 static __init int efivars_pstore_init(void)
0220 {
0221     if (!efivar_supports_writes())
0222         return 0;
0223 
0224     if (efivars_pstore_disable)
0225         return 0;
0226 
0227     efi_pstore_info.buf = kmalloc(4096, GFP_KERNEL);
0228     if (!efi_pstore_info.buf)
0229         return -ENOMEM;
0230 
0231     efi_pstore_info.bufsize = 1024;
0232 
0233     if (pstore_register(&efi_pstore_info)) {
0234         kfree(efi_pstore_info.buf);
0235         efi_pstore_info.buf = NULL;
0236         efi_pstore_info.bufsize = 0;
0237     }
0238 
0239     return 0;
0240 }
0241 
0242 static __exit void efivars_pstore_exit(void)
0243 {
0244     if (!efi_pstore_info.bufsize)
0245         return;
0246 
0247     pstore_unregister(&efi_pstore_info);
0248     kfree(efi_pstore_info.buf);
0249     efi_pstore_info.buf = NULL;
0250     efi_pstore_info.bufsize = 0;
0251 }
0252 
0253 module_init(efivars_pstore_init);
0254 module_exit(efivars_pstore_exit);
0255 
0256 MODULE_DESCRIPTION("EFI variable backend for pstore");
0257 MODULE_LICENSE("GPL");
0258 MODULE_ALIAS("platform:efivars");