clearing the EFI event log and reading and writing NVRAM
          variables.
 
+config GOOGLE_COREBOOT_TABLE
+       tristate
+       depends on GOOGLE_COREBOOT_TABLE_ACPI
+
+config GOOGLE_COREBOOT_TABLE_ACPI
+       tristate "Coreboot Table Access - ACPI"
+       depends on ACPI
+       select GOOGLE_COREBOOT_TABLE
+       help
+         This option enables the coreboot_table module, which provides other
+         firmware modules to access to the coreboot table. The coreboot table
+         pointer is accessed through the ACPI "GOOGCB00" object.
+         If unsure say N.
+
 config GOOGLE_MEMCONSOLE
        tristate
-       depends on GOOGLE_MEMCONSOLE_X86_LEGACY
+       depends on GOOGLE_MEMCONSOLE_X86_LEGACY || GOOGLE_MEMCONSOLE_COREBOOT
 
 config GOOGLE_MEMCONSOLE_X86_LEGACY
        tristate "Firmware Memory Console - X86 Legacy support"
          the EBDA on Google servers.  If found, this log is exported to
          userland in the file /sys/firmware/log.
 
+config GOOGLE_MEMCONSOLE_COREBOOT
+       tristate "Firmware Memory Console"
+       depends on GOOGLE_COREBOOT_TABLE
+       select GOOGLE_MEMCONSOLE
+       help
+         This option enables the kernel to search for a firmware log in
+         the coreboot table.  If found, this log is exported to userland
+         in the file /sys/firmware/log.
+
 endif # GOOGLE_FIRMWARE
 
 
 obj-$(CONFIG_GOOGLE_SMI)               += gsmi.o
+obj-$(CONFIG_GOOGLE_COREBOOT_TABLE)        += coreboot_table.o
+obj-$(CONFIG_GOOGLE_COREBOOT_TABLE_ACPI)   += coreboot_table-acpi.o
 obj-$(CONFIG_GOOGLE_MEMCONSOLE)            += memconsole.o
+obj-$(CONFIG_GOOGLE_MEMCONSOLE_COREBOOT)   += memconsole-coreboot.o
 obj-$(CONFIG_GOOGLE_MEMCONSOLE_X86_LEGACY) += memconsole-x86-legacy.o
 
--- /dev/null
+/*
+ * coreboot_table-acpi.c
+ *
+ * Using ACPI to locate Coreboot table and provide coreboot table access.
+ *
+ * Copyright 2017 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License v2.0 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/acpi.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include "coreboot_table.h"
+
+static int coreboot_table_acpi_probe(struct platform_device *pdev)
+{
+       phys_addr_t phyaddr;
+       resource_size_t len;
+       struct coreboot_table_header __iomem *header = NULL;
+       struct resource *res;
+       void __iomem *ptr = NULL;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res)
+               return -EINVAL;
+
+       len = resource_size(res);
+       if (!res->start || !len)
+               return -EINVAL;
+
+       phyaddr = res->start;
+       header = ioremap_cache(phyaddr, sizeof(*header));
+       if (header == NULL)
+               return -ENOMEM;
+
+       ptr = ioremap_cache(phyaddr,
+                           header->header_bytes + header->table_bytes);
+       iounmap(header);
+       if (!ptr)
+               return -ENOMEM;
+
+       return coreboot_table_init(ptr);
+}
+
+static int coreboot_table_acpi_remove(struct platform_device *pdev)
+{
+       return coreboot_table_exit();
+}
+
+static const struct acpi_device_id cros_coreboot_acpi_match[] = {
+       { "GOOGCB00", 0 },
+       { "BOOT0000", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(acpi, cros_coreboot_acpi_match);
+
+static struct platform_driver coreboot_table_acpi_driver = {
+       .probe = coreboot_table_acpi_probe,
+       .remove = coreboot_table_acpi_remove,
+       .driver = {
+               .name = "coreboot_table_acpi",
+               .acpi_match_table = ACPI_PTR(cros_coreboot_acpi_match),
+       },
+};
+
+static int __init coreboot_table_acpi_init(void)
+{
+       return platform_driver_register(&coreboot_table_acpi_driver);
+}
+
+module_init(coreboot_table_acpi_init);
+
+MODULE_AUTHOR("Google, Inc.");
+MODULE_LICENSE("GPL");
 
--- /dev/null
+/*
+ * coreboot_table.c
+ *
+ * Module providing coreboot table access.
+ *
+ * Copyright 2017 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License v2.0 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include "coreboot_table.h"
+
+struct coreboot_table_entry {
+       u32 tag;
+       u32 size;
+};
+
+static struct coreboot_table_header __iomem *ptr_header;
+
+/*
+ * This function parses the coreboot table for an entry that contains the base
+ * address of the given entry tag. The coreboot table consists of a header
+ * directly followed by a number of small, variable-sized entries, which each
+ * contain an identifying tag and their length as the first two fields.
+ */
+int coreboot_table_find(int tag, void *data, size_t data_size)
+{
+       struct coreboot_table_header header;
+       struct coreboot_table_entry entry;
+       void *ptr_entry;
+       int i;
+
+       if (!ptr_header)
+               return -EPROBE_DEFER;
+
+       memcpy_fromio(&header, ptr_header, sizeof(header));
+
+       if (strncmp(header.signature, "LBIO", sizeof(header.signature))) {
+               pr_warn("coreboot_table: coreboot table missing or corrupt!\n");
+               return -ENODEV;
+       }
+
+       ptr_entry = (void *)ptr_header + header.header_bytes;
+
+       for (i = 0; i < header.table_entries; i++) {
+               memcpy_fromio(&entry, ptr_entry, sizeof(entry));
+               if (entry.tag == tag) {
+                       if (data_size < entry.size)
+                               return -EINVAL;
+
+                       memcpy_fromio(data, ptr_entry, entry.size);
+
+                       return 0;
+               }
+
+               ptr_entry += entry.size;
+       }
+
+       return -ENOENT;
+}
+EXPORT_SYMBOL(coreboot_table_find);
+
+int coreboot_table_init(void __iomem *ptr)
+{
+       ptr_header = ptr;
+
+       return 0;
+}
+EXPORT_SYMBOL(coreboot_table_init);
+
+int coreboot_table_exit(void)
+{
+       if (ptr_header)
+               iounmap(ptr_header);
+
+       return 0;
+}
+EXPORT_SYMBOL(coreboot_table_exit);
+
+MODULE_AUTHOR("Google, Inc.");
+MODULE_LICENSE("GPL");
 
--- /dev/null
+/*
+ * coreboot_table.h
+ *
+ * Internal header for coreboot table access.
+ *
+ * Copyright 2017 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License v2.0 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __COREBOOT_TABLE_H
+#define __COREBOOT_TABLE_H
+
+#include <linux/io.h>
+
+/* List of coreboot entry structures that is used */
+struct lb_cbmem_ref {
+       uint32_t tag;
+       uint32_t size;
+
+       uint64_t cbmem_addr;
+};
+
+/* Coreboot table header structure */
+struct coreboot_table_header {
+       char signature[4];
+       u32 header_bytes;
+       u32 header_checksum;
+       u32 table_bytes;
+       u32 table_checksum;
+       u32 table_entries;
+};
+
+/* Retrieve coreboot table entry with tag *tag* and copy it to data */
+int coreboot_table_find(int tag, void *data, size_t data_size);
+
+/* Initialize coreboot table module given a pointer to iomem */
+int coreboot_table_init(void __iomem *ptr);
+
+/* Cleanup coreboot table module */
+int coreboot_table_exit(void);
+
+#endif /* __COREBOOT_TABLE_H */
 
--- /dev/null
+/*
+ * memconsole-coreboot.c
+ *
+ * Memory based BIOS console accessed through coreboot table.
+ *
+ * Copyright 2017 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License v2.0 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include "memconsole.h"
+#include "coreboot_table.h"
+
+#define CB_TAG_CBMEM_CONSOLE   0x17
+
+/* CBMEM firmware console log descriptor. */
+struct cbmem_cons {
+       u32 buffer_size;
+       u32 buffer_cursor;
+       u8  buffer_body[0];
+} __packed;
+
+static struct cbmem_cons __iomem *cbmem_console;
+
+static int memconsole_coreboot_init(phys_addr_t physaddr)
+{
+       struct cbmem_cons __iomem *tmp_cbmc;
+
+       tmp_cbmc = memremap(physaddr, sizeof(*tmp_cbmc), MEMREMAP_WB);
+
+       if (!tmp_cbmc)
+               return -ENOMEM;
+
+       cbmem_console = memremap(physaddr,
+                                tmp_cbmc->buffer_size + sizeof(*cbmem_console),
+                                MEMREMAP_WB);
+       memunmap(tmp_cbmc);
+
+       if (!cbmem_console)
+               return -ENOMEM;
+
+       memconsole_setup(cbmem_console->buffer_body,
+               min(cbmem_console->buffer_cursor, cbmem_console->buffer_size));
+
+       return 0;
+}
+
+static int memconsole_probe(struct platform_device *pdev)
+{
+       int ret;
+       struct lb_cbmem_ref entry;
+
+       ret = coreboot_table_find(CB_TAG_CBMEM_CONSOLE, &entry, sizeof(entry));
+       if (ret)
+               return ret;
+
+       ret = memconsole_coreboot_init(entry.cbmem_addr);
+       if (ret)
+               return ret;
+
+       return memconsole_sysfs_init();
+}
+
+static int memconsole_remove(struct platform_device *pdev)
+{
+       memconsole_exit();
+
+       if (cbmem_console)
+               memunmap(cbmem_console);
+
+       return 0;
+}
+
+static struct platform_driver memconsole_driver = {
+       .probe = memconsole_probe,
+       .remove = memconsole_remove,
+       .driver = {
+               .name = "memconsole",
+       },
+};
+
+static int __init platform_memconsole_init(void)
+{
+       struct platform_device *pdev;
+
+       pdev = platform_device_register_simple("memconsole", -1, NULL, 0);
+       if (pdev == NULL)
+               return -ENODEV;
+
+       platform_driver_register(&memconsole_driver);
+
+       return 0;
+}
+
+module_init(platform_memconsole_init);
+
+MODULE_AUTHOR("Google, Inc.");
+MODULE_LICENSE("GPL");