firmware: google: memconsole: Make memconsole interface more flexible
authorJulius Werner <jwerner@chromium.org>
Tue, 2 May 2017 22:16:29 +0000 (15:16 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 18 May 2017 14:59:06 +0000 (16:59 +0200)
This patch redesigns the interface between the generic memconsole driver
and its implementations to become more flexible than a flat memory
buffer with unchanging bounds. This allows memconsoles like coreboot's
to include lines that were added by runtime firmware after the driver
was initialized. Since the console log size is thus no longer static,
this means that the /sys/firmware/log file has to become unseekable.

Signed-off-by: Julius Werner <jwerner@chromium.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/firmware/google/memconsole-coreboot.c
drivers/firmware/google/memconsole-x86-legacy.c
drivers/firmware/google/memconsole.c
drivers/firmware/google/memconsole.h

index 02711114deceb68277305d897a99a55f64d588b9..d48a80c3042dbdfb9c1a773e9228fdb67633d0cf 100644 (file)
@@ -33,6 +33,14 @@ struct cbmem_cons {
 
 static struct cbmem_cons __iomem *cbmem_console;
 
+static ssize_t memconsole_coreboot_read(char *buf, loff_t pos, size_t count)
+{
+       return memory_read_from_buffer(buf, count, &pos,
+                                      cbmem_console->buffer_body,
+                                      min(cbmem_console->buffer_cursor,
+                                          cbmem_console->buffer_size));
+}
+
 static int memconsole_coreboot_init(phys_addr_t physaddr)
 {
        struct cbmem_cons __iomem *tmp_cbmc;
@@ -50,9 +58,7 @@ static int memconsole_coreboot_init(phys_addr_t physaddr)
        if (!cbmem_console)
                return -ENOMEM;
 
-       memconsole_setup(cbmem_console->buffer_body,
-               min(cbmem_console->buffer_cursor, cbmem_console->buffer_size));
-
+       memconsole_setup(memconsole_coreboot_read);
        return 0;
 }
 
index 1f279ee883b9ae26812813a8fdc74ee338161b5f..8c1bf6dbdaa643dc89636dbccf3300c6f6a63828 100644 (file)
@@ -48,6 +48,15 @@ struct biosmemcon_ebda {
        };
 } __packed;
 
+static char *memconsole_baseaddr;
+static size_t memconsole_length;
+
+static ssize_t memconsole_read(char *buf, loff_t pos, size_t count)
+{
+       return memory_read_from_buffer(buf, count, &pos, memconsole_baseaddr,
+                                      memconsole_length);
+}
+
 static void found_v1_header(struct biosmemcon_ebda *hdr)
 {
        pr_info("memconsole: BIOS console v1 EBDA structure found at %p\n",
@@ -56,7 +65,9 @@ static void found_v1_header(struct biosmemcon_ebda *hdr)
                hdr->v1.buffer_addr, hdr->v1.start,
                hdr->v1.end, hdr->v1.num_chars);
 
-       memconsole_setup(phys_to_virt(hdr->v1.buffer_addr), hdr->v1.num_chars);
+       memconsole_baseaddr = phys_to_virt(hdr->v1.buffer_addr);
+       memconsole_length = hdr->v1.num_chars;
+       memconsole_setup(memconsole_read);
 }
 
 static void found_v2_header(struct biosmemcon_ebda *hdr)
@@ -67,8 +78,9 @@ static void found_v2_header(struct biosmemcon_ebda *hdr)
                hdr->v2.buffer_addr, hdr->v2.start,
                hdr->v2.end, hdr->v2.num_bytes);
 
-       memconsole_setup(phys_to_virt(hdr->v2.buffer_addr + hdr->v2.start),
-                        hdr->v2.end - hdr->v2.start);
+       memconsole_baseaddr = phys_to_virt(hdr->v2.buffer_addr + hdr->v2.start);
+       memconsole_length = hdr->v2.end - hdr->v2.start;
+       memconsole_setup(memconsole_read);
 }
 
 /*
index 94e200ddb4faf870d6d35f81313771ba90d5d70b..166f07c68c02c895b93a8bd881516c3afcc92329 100644 (file)
 
 #include "memconsole.h"
 
-static char *memconsole_baseaddr;
-static size_t memconsole_length;
+static ssize_t (*memconsole_read_func)(char *, loff_t, size_t);
 
 static ssize_t memconsole_read(struct file *filp, struct kobject *kobp,
                               struct bin_attribute *bin_attr, char *buf,
                               loff_t pos, size_t count)
 {
-       return memory_read_from_buffer(buf, count, &pos, memconsole_baseaddr,
-                                      memconsole_length);
+       if (WARN_ON_ONCE(!memconsole_read_func))
+               return -EIO;
+       return memconsole_read_func(buf, pos, count);
 }
 
 static struct bin_attribute memconsole_bin_attr = {
@@ -38,16 +38,14 @@ static struct bin_attribute memconsole_bin_attr = {
        .read = memconsole_read,
 };
 
-void memconsole_setup(void *baseaddr, size_t length)
+void memconsole_setup(ssize_t (*read_func)(char *, loff_t, size_t))
 {
-       memconsole_baseaddr = baseaddr;
-       memconsole_length = length;
+       memconsole_read_func = read_func;
 }
 EXPORT_SYMBOL(memconsole_setup);
 
 int memconsole_sysfs_init(void)
 {
-       memconsole_bin_attr.size = memconsole_length;
        return sysfs_create_bin_file(firmware_kobj, &memconsole_bin_attr);
 }
 EXPORT_SYMBOL(memconsole_sysfs_init);
index 190fc03a51aee0ebd3db2ddc2ed580b5c714bebb..ff1592dc7d1a4bf4886446c31f0d376356945c19 100644 (file)
 #ifndef __FIRMWARE_GOOGLE_MEMCONSOLE_H
 #define __FIRMWARE_GOOGLE_MEMCONSOLE_H
 
+#include <linux/types.h>
+
 /*
  * memconsole_setup
  *
- * Initialize the memory console from raw (virtual) base
- * address and length.
+ * Initialize the memory console, passing the function to handle read accesses.
  */
-void memconsole_setup(void *baseaddr, size_t length);
+void memconsole_setup(ssize_t (*read_func)(char *, loff_t, size_t));
 
 /*
  * memconsole_sysfs_init