2 #include <linux/module.h>
3 #include <linux/pstore.h>
4 #include <linux/ucs2_string.h>
6 #define DUMP_NAME_LEN 52
8 static bool efivars_pstore_disable
=
9 IS_ENABLED(CONFIG_EFI_VARS_PSTORE_DEFAULT_DISABLE
);
11 module_param_named(pstore_disable
, efivars_pstore_disable
, bool, 0644);
13 #define PSTORE_EFI_ATTRIBUTES \
14 (EFI_VARIABLE_NON_VOLATILE | \
15 EFI_VARIABLE_BOOTSERVICE_ACCESS | \
16 EFI_VARIABLE_RUNTIME_ACCESS)
18 static int efi_pstore_open(struct pstore_info
*psi
)
20 efivar_entry_iter_begin();
25 static int efi_pstore_close(struct pstore_info
*psi
)
27 efivar_entry_iter_end();
32 struct pstore_read_data
{
34 enum pstore_type_id
*type
;
36 struct timespec
*timespec
;
40 static int efi_pstore_read_func(struct efivar_entry
*entry
, void *data
)
42 efi_guid_t vendor
= LINUX_EFI_CRASH_GUID
;
43 struct pstore_read_data
*cb_data
= data
;
44 char name
[DUMP_NAME_LEN
];
48 unsigned long time
, size
;
50 if (efi_guidcmp(entry
->var
.VendorGuid
, vendor
))
53 for (i
= 0; i
< DUMP_NAME_LEN
; i
++)
54 name
[i
] = entry
->var
.VariableName
[i
];
56 if (sscanf(name
, "dump-type%u-%u-%d-%lu",
57 cb_data
->type
, &part
, &cnt
, &time
) == 4) {
59 *cb_data
->count
= cnt
;
60 cb_data
->timespec
->tv_sec
= time
;
61 cb_data
->timespec
->tv_nsec
= 0;
62 } else if (sscanf(name
, "dump-type%u-%u-%lu",
63 cb_data
->type
, &part
, &time
) == 3) {
65 * Check if an old format,
66 * which doesn't support holding
67 * multiple logs, remains.
71 cb_data
->timespec
->tv_sec
= time
;
72 cb_data
->timespec
->tv_nsec
= 0;
76 entry
->var
.DataSize
= 1024;
77 __efivar_entry_get(entry
, &entry
->var
.Attributes
,
78 &entry
->var
.DataSize
, entry
->var
.Data
);
79 size
= entry
->var
.DataSize
;
81 *cb_data
->buf
= kmalloc(size
, GFP_KERNEL
);
82 if (*cb_data
->buf
== NULL
)
84 memcpy(*cb_data
->buf
, entry
->var
.Data
, size
);
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
)
92 struct pstore_read_data data
;
97 data
.timespec
= timespec
;
100 return __efivar_entry_iter(efi_pstore_read_func
, &efivar_sysfs_list
, &data
,
101 (struct efivar_entry
**)&psi
->data
);
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 size
,
107 struct pstore_info
*psi
)
109 char name
[DUMP_NAME_LEN
];
110 efi_char16_t efi_name
[DUMP_NAME_LEN
];
111 efi_guid_t vendor
= LINUX_EFI_CRASH_GUID
;
114 sprintf(name
, "dump-type%u-%u-%d-%lu", type
, part
, count
,
117 for (i
= 0; i
< DUMP_NAME_LEN
; i
++)
118 efi_name
[i
] = name
[i
];
120 efivar_entry_set_safe(efi_name
, vendor
, PSTORE_EFI_ATTRIBUTES
,
121 !pstore_cannot_block_path(reason
),
124 if (reason
== KMSG_DUMP_OOPS
)
131 struct pstore_erase_data
{
133 enum pstore_type_id type
;
135 struct timespec time
;
140 * Clean up an entry with the same name
142 static int efi_pstore_erase_func(struct efivar_entry
*entry
, void *data
)
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
];
152 if (efi_guidcmp(entry
->var
.VendorGuid
, vendor
))
155 if (ucs2_strncmp(entry
->var
.VariableName
,
156 efi_name
, (size_t)ucs2_len
)) {
158 * Check if an old format, which doesn't support
159 * holding multiple logs, remains.
161 sprintf(name_old
, "dump-type%u-%u-%lu", ed
->type
,
162 (unsigned int)ed
->id
, ed
->time
.tv_sec
);
164 for (i
= 0; i
< DUMP_NAME_LEN
; i
++)
165 efi_name_old
[i
] = name_old
[i
];
167 if (ucs2_strncmp(entry
->var
.VariableName
, efi_name_old
,
168 ucs2_strlen(efi_name_old
)))
173 __efivar_entry_delete(entry
);
174 list_del(&entry
->list
);
179 static int efi_pstore_erase(enum pstore_type_id type
, u64 id
, int count
,
180 struct timespec time
, struct pstore_info
*psi
)
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
];
188 sprintf(name
, "dump-type%u-%u-%d-%lu", type
, (unsigned int)id
, count
,
191 for (i
= 0; i
< DUMP_NAME_LEN
; i
++)
192 efi_name
[i
] = name
[i
];
198 edata
.name
= efi_name
;
200 efivar_entry_iter_begin();
201 found
= __efivar_entry_iter(efi_pstore_erase_func
, &efivar_sysfs_list
, &edata
, &entry
);
202 efivar_entry_iter_end();
205 efivar_unregister(entry
);
210 static struct pstore_info efi_pstore_info
= {
211 .owner
= THIS_MODULE
,
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
,
220 static __init
int efivars_pstore_init(void)
222 if (!efi_enabled(EFI_RUNTIME_SERVICES
))
225 if (!efivars_kobject())
228 if (efivars_pstore_disable
)
231 efi_pstore_info
.buf
= kmalloc(4096, GFP_KERNEL
);
232 if (!efi_pstore_info
.buf
)
235 efi_pstore_info
.bufsize
= 1024;
236 spin_lock_init(&efi_pstore_info
.buf_lock
);
238 pstore_register(&efi_pstore_info
);
243 static __exit
void efivars_pstore_exit(void)
247 module_init(efivars_pstore_init
);
248 module_exit(efivars_pstore_exit
);
250 MODULE_DESCRIPTION("EFI variable backend for pstore");
251 MODULE_LICENSE("GPL");