aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTony Luck <tony.luck@intel.com>2017-08-18 19:19:00 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2017-08-23 21:35:37 -0400
commit7dae6326ed76431653793df0388b3a404de1217e (patch)
tree403fa2fdab3b5291cdd0390d570a56aa4df05c4f
parent14ccee78fc82f5512908f4424f541549a5705b89 (diff)
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 <punit.agrawal@arm.com> Signed-off-by: Tony Luck <tony.luck@intel.com> v4: fix typo reported by Punit Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rw-r--r--drivers/acpi/sysfs.c79
1 files changed, 79 insertions, 0 deletions
diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c
index e414fabf7315..faa1aa3ed0e1 100644
--- a/drivers/acpi/sysfs.c
+++ b/drivers/acpi/sysfs.c
@@ -306,11 +306,13 @@ module_param_call(acpica_version, NULL, param_get_acpica_version, NULL, 0444);
306/* 306/*
307 * ACPI table sysfs I/F: 307 * ACPI table sysfs I/F:
308 * /sys/firmware/acpi/tables/ 308 * /sys/firmware/acpi/tables/
309 * /sys/firmware/acpi/tables/data/
309 * /sys/firmware/acpi/tables/dynamic/ 310 * /sys/firmware/acpi/tables/dynamic/
310 */ 311 */
311 312
312static LIST_HEAD(acpi_table_attr_list); 313static LIST_HEAD(acpi_table_attr_list);
313static struct kobject *tables_kobj; 314static struct kobject *tables_kobj;
315static struct kobject *tables_data_kobj;
314static struct kobject *dynamic_tables_kobj; 316static struct kobject *dynamic_tables_kobj;
315static struct kobject *hotplug_kobj; 317static struct kobject *hotplug_kobj;
316 318
@@ -325,6 +327,11 @@ struct acpi_table_attr {
325 struct list_head node; 327 struct list_head node;
326}; 328};
327 329
330struct acpi_data_attr {
331 struct bin_attribute attr;
332 u64 addr;
333};
334
328static ssize_t acpi_table_show(struct file *filp, struct kobject *kobj, 335static ssize_t acpi_table_show(struct file *filp, struct kobject *kobj,
329 struct bin_attribute *bin_attr, char *buf, 336 struct bin_attribute *bin_attr, char *buf,
330 loff_t offset, size_t count) 337 loff_t offset, size_t count)
@@ -420,6 +427,70 @@ acpi_status acpi_sysfs_table_handler(u32 event, void *table, void *context)
420 return AE_OK; 427 return AE_OK;
421} 428}
422 429
430static 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
450static 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
466static 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
475static 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
423static int acpi_tables_sysfs_init(void) 494static int acpi_tables_sysfs_init(void)
424{ 495{
425 struct acpi_table_attr *table_attr; 496 struct acpi_table_attr *table_attr;
@@ -432,6 +503,10 @@ static int acpi_tables_sysfs_init(void)
432 if (!tables_kobj) 503 if (!tables_kobj)
433 goto err; 504 goto err;
434 505
506 tables_data_kobj = kobject_create_and_add("data", tables_kobj);
507 if (!tables_data_kobj)
508 goto err_tables_data;
509
435 dynamic_tables_kobj = kobject_create_and_add("dynamic", tables_kobj); 510 dynamic_tables_kobj = kobject_create_and_add("dynamic", tables_kobj);
436 if (!dynamic_tables_kobj) 511 if (!dynamic_tables_kobj)
437 goto err_dynamic_tables; 512 goto err_dynamic_tables;
@@ -456,13 +531,17 @@ static int acpi_tables_sysfs_init(void)
456 return ret; 531 return ret;
457 } 532 }
458 list_add_tail(&table_attr->node, &acpi_table_attr_list); 533 list_add_tail(&table_attr->node, &acpi_table_attr_list);
534 acpi_table_data_init(table_header);
459 } 535 }
460 536
461 kobject_uevent(tables_kobj, KOBJ_ADD); 537 kobject_uevent(tables_kobj, KOBJ_ADD);
538 kobject_uevent(tables_data_kobj, KOBJ_ADD);
462 kobject_uevent(dynamic_tables_kobj, KOBJ_ADD); 539 kobject_uevent(dynamic_tables_kobj, KOBJ_ADD);
463 540
464 return 0; 541 return 0;
465err_dynamic_tables: 542err_dynamic_tables:
543 kobject_put(tables_data_kobj);
544err_tables_data:
466 kobject_put(tables_kobj); 545 kobject_put(tables_kobj);
467err: 546err:
468 return -ENOMEM; 547 return -ENOMEM;