Skip to content

Commit 7dae632

Browse files
aeglrafaeljw
authored andcommitted
ACPI / sysfs: Extend ACPI sysfs to provide access to boot error region
The ACPI sysfs interface provides a way to read each ACPI table from userspace via entries in /sys/firmware/acpi/tables/ The BERT table simply provides the size and address of the error record in BIOS reserved memory and users may want access to this record. In an earlier age we might have used /dev/mem to retrieve this error record, but many systems disable /dev/mem for security reasons. Extend this driver to provide read-only access to the data via a file in a new directory /sys/firmware/acpi/tables/data/BERT Acked-by: Punit Agrawal <[email protected]> Signed-off-by: Tony Luck <[email protected]> v4: fix typo reported by Punit Signed-off-by: Rafael J. Wysocki <[email protected]>
1 parent 14ccee7 commit 7dae632

File tree

1 file changed

+79
-0
lines changed

1 file changed

+79
-0
lines changed

drivers/acpi/sysfs.c

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,11 +306,13 @@ module_param_call(acpica_version, NULL, param_get_acpica_version, NULL, 0444);
306306
/*
307307
* ACPI table sysfs I/F:
308308
* /sys/firmware/acpi/tables/
309+
* /sys/firmware/acpi/tables/data/
309310
* /sys/firmware/acpi/tables/dynamic/
310311
*/
311312

312313
static LIST_HEAD(acpi_table_attr_list);
313314
static struct kobject *tables_kobj;
315+
static struct kobject *tables_data_kobj;
314316
static struct kobject *dynamic_tables_kobj;
315317
static struct kobject *hotplug_kobj;
316318

@@ -325,6 +327,11 @@ struct acpi_table_attr {
325327
struct list_head node;
326328
};
327329

330+
struct acpi_data_attr {
331+
struct bin_attribute attr;
332+
u64 addr;
333+
};
334+
328335
static ssize_t acpi_table_show(struct file *filp, struct kobject *kobj,
329336
struct bin_attribute *bin_attr, char *buf,
330337
loff_t offset, size_t count)
@@ -420,6 +427,70 @@ acpi_status acpi_sysfs_table_handler(u32 event, void *table, void *context)
420427
return AE_OK;
421428
}
422429

430+
static ssize_t acpi_data_show(struct file *filp, struct kobject *kobj,
431+
struct bin_attribute *bin_attr, char *buf,
432+
loff_t offset, size_t count)
433+
{
434+
struct acpi_data_attr *data_attr;
435+
void __iomem *base;
436+
ssize_t rc;
437+
438+
data_attr = container_of(bin_attr, struct acpi_data_attr, attr);
439+
440+
base = acpi_os_map_memory(data_attr->addr, data_attr->attr.size);
441+
if (!base)
442+
return -ENOMEM;
443+
rc = memory_read_from_buffer(buf, count, &offset, base,
444+
data_attr->attr.size);
445+
acpi_os_unmap_memory(base, data_attr->attr.size);
446+
447+
return rc;
448+
}
449+
450+
static int acpi_bert_data_init(void *th, struct acpi_data_attr *data_attr)
451+
{
452+
struct acpi_table_bert *bert = th;
453+
454+
if (bert->header.length < sizeof(struct acpi_table_bert) ||
455+
bert->region_length < sizeof(struct acpi_hest_generic_status)) {
456+
kfree(data_attr);
457+
return -EINVAL;
458+
}
459+
data_attr->addr = bert->address;
460+
data_attr->attr.size = bert->region_length;
461+
data_attr->attr.attr.name = "BERT";
462+
463+
return sysfs_create_bin_file(tables_data_kobj, &data_attr->attr);
464+
}
465+
466+
static struct acpi_data_obj {
467+
char *name;
468+
int (*fn)(void *, struct acpi_data_attr *);
469+
} acpi_data_objs[] = {
470+
{ ACPI_SIG_BERT, acpi_bert_data_init },
471+
};
472+
473+
#define NUM_ACPI_DATA_OBJS ARRAY_SIZE(acpi_data_objs)
474+
475+
static int acpi_table_data_init(struct acpi_table_header *th)
476+
{
477+
struct acpi_data_attr *data_attr;
478+
int i;
479+
480+
for (i = 0; i < NUM_ACPI_DATA_OBJS; i++) {
481+
if (ACPI_COMPARE_NAME(th->signature, acpi_data_objs[i].name)) {
482+
data_attr = kzalloc(sizeof(*data_attr), GFP_KERNEL);
483+
if (!data_attr)
484+
return -ENOMEM;
485+
sysfs_attr_init(&data_attr->attr.attr);
486+
data_attr->attr.read = acpi_data_show;
487+
data_attr->attr.attr.mode = 0400;
488+
return acpi_data_objs[i].fn(th, data_attr);
489+
}
490+
}
491+
return 0;
492+
}
493+
423494
static int acpi_tables_sysfs_init(void)
424495
{
425496
struct acpi_table_attr *table_attr;
@@ -432,6 +503,10 @@ static int acpi_tables_sysfs_init(void)
432503
if (!tables_kobj)
433504
goto err;
434505

506+
tables_data_kobj = kobject_create_and_add("data", tables_kobj);
507+
if (!tables_data_kobj)
508+
goto err_tables_data;
509+
435510
dynamic_tables_kobj = kobject_create_and_add("dynamic", tables_kobj);
436511
if (!dynamic_tables_kobj)
437512
goto err_dynamic_tables;
@@ -456,13 +531,17 @@ static int acpi_tables_sysfs_init(void)
456531
return ret;
457532
}
458533
list_add_tail(&table_attr->node, &acpi_table_attr_list);
534+
acpi_table_data_init(table_header);
459535
}
460536

461537
kobject_uevent(tables_kobj, KOBJ_ADD);
538+
kobject_uevent(tables_data_kobj, KOBJ_ADD);
462539
kobject_uevent(dynamic_tables_kobj, KOBJ_ADD);
463540

464541
return 0;
465542
err_dynamic_tables:
543+
kobject_put(tables_data_kobj);
544+
err_tables_data:
466545
kobject_put(tables_kobj);
467546
err:
468547
return -ENOMEM;

0 commit comments

Comments
 (0)