powerpc/powernv: Expose OPAL firmware symbol map
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>
Thu, 11 Dec 2014 01:39:49 +0000 (12:39 +1100)
committerMichael Ellerman <mpe@ellerman.id.au>
Mon, 15 Dec 2014 02:21:44 +0000 (13:21 +1100)
Newer versions of OPAL will provide this, so let's expose it to user
space so tools like perf can use it to properly decode samples in
firmware space.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
arch/powerpc/platforms/powernv/opal.c

index aa316d820736e72aa11c133c33f6771c5d50e385..f10b9ec8c1f5c16fe9057014f5582791ee75a511 100644 (file)
@@ -9,8 +9,9 @@
  * 2 of the License, or (at your option) any later version.
  */
 
-#undef DEBUG
+#define pr_fmt(fmt)    "opal: " fmt
 
+#include <linux/printk.h>
 #include <linux/types.h>
 #include <linux/of.h>
 #include <linux/of_fdt.h>
@@ -625,6 +626,39 @@ static int opal_sysfs_init(void)
        return 0;
 }
 
+static ssize_t symbol_map_read(struct file *fp, struct kobject *kobj,
+                              struct bin_attribute *bin_attr,
+                              char *buf, loff_t off, size_t count)
+{
+       return memory_read_from_buffer(buf, count, &off, bin_attr->private,
+                                      bin_attr->size);
+}
+
+static BIN_ATTR_RO(symbol_map, 0);
+
+static void opal_export_symmap(void)
+{
+       const __be64 *syms;
+       unsigned int size;
+       struct device_node *fw;
+       int rc;
+
+       fw = of_find_node_by_path("/ibm,opal/firmware");
+       if (!fw)
+               return;
+       syms = of_get_property(fw, "symbol-map", &size);
+       if (!syms || size != 2 * sizeof(__be64))
+               return;
+
+       /* Setup attributes */
+       bin_attr_symbol_map.private = __va(be64_to_cpu(syms[0]));
+       bin_attr_symbol_map.size = be64_to_cpu(syms[1]);
+
+       rc = sysfs_create_bin_file(opal_kobj, &bin_attr_symbol_map);
+       if (rc)
+               pr_warn("Error %d creating OPAL symbols file\n", rc);
+}
+
 static void __init opal_dump_region_init(void)
 {
        void *addr;
@@ -713,6 +747,8 @@ static int __init opal_init(void)
        /* Create "opal" kobject under /sys/firmware */
        rc = opal_sysfs_init();
        if (rc == 0) {
+               /* Export symbol map to userspace */
+               opal_export_symmap();
                /* Setup dump region interface */
                opal_dump_region_init();
                /* Setup error log interface */