vmmcp: Rework coreboot tables support
authorRonald G. Minnich <rminnich@gmail.com>
Thu, 18 Jun 2015 15:00:38 +0000 (08:00 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Mon, 22 Jun 2015 23:37:08 +0000 (16:37 -0700)
Adds the user header and makes coreboot_table compile.

Signed-off-by: Ronald G. Minnich <rminnich@gmail.com>
Git-fu'd-by: brho
Commended-by: brho and Ronald G. Minnich <rminnich@gmail.com>
tests/vmm/vmrunkernel.c
user/vmm/coreboot_table.c
user/vmm/include/coreboot_tables.h [new file with mode: 0644]

index c8e6e54..a9f752a 100644 (file)
@@ -11,7 +11,7 @@
 #include <string.h>
 #include <ros/syscall.h>
 #include <sys/mman.h>
-
+#include <vmm/coreboot_tables.h>
 /* this test will run the "kernel" in the negative address space. We hope. */
 int *mmap_blob;
 unsigned long long stack[1024];
@@ -50,6 +50,7 @@ int main(int argc, char **argv)
        void * x;
        int kfd = -1;
        static char cmd[512];
+       void *coreboot_tables;
        /* kernel has to be in the range 16M to 64M for now. */
        // mmap is not working for us at present.
        if ((uint64_t)_kernel > 16*1048576) {
@@ -64,13 +65,14 @@ int main(int argc, char **argv)
        }
        argc--,argv++;
        if (argc < 1) {
-               fprintf(stderr, "Usage: %s vmimage [loadaddress [entrypoint]]\n", argv[0]);
+               fprintf(stderr, "Usage: %s vmimage coreboot_tables [loadaddress [entrypoint]]\n", argv[0]);
                exit(1);
        }
-       if (argc > 1)
-               kerneladdress = strtoull(argv[1], 0, 0);
+       coreboot_tables = (void *) strtoull(argv[1], 0, 0);
        if (argc > 2)
-               entry = strtoull(argv[2], 0, 0);
+               kerneladdress = strtoull(argv[2], 0, 0);
+       if (argc > 3)
+               entry = strtoull(argv[3], 0, 0);
        kfd = open(argv[0], O_RDONLY);
        if (kfd < 0) {
                perror(argv[0]);
@@ -165,8 +167,8 @@ int main(int argc, char **argv)
        kernbase >>= (0+12);
        kernbase <<= (0 + 12);
        uint8_t *kernel = (void *)(16*1048576);
-       uint8_t program[] = {0x0f, 0x1, 0xc1, 0xeb, 0xfe};
-       memmove(kernel, program, sizeof(program));
+       write_coreboot_table(coreboot_tables, kernel, 16*1048576);
+       hexdump(stdout, coreboot_tables, 128);
        printf("kernbase for pml4 is 0x%llx and entry is %llx\n", kernbase, entry);
        printf("p512 %p p512[0] is 0x%lx p1 %p p1[0] is 0x%x\n", p512, p512[0], p1, p1[0]);
        sprintf(cmd, "V 0x%llx 0x%llx 0x%llx", entry, (unsigned long long) &stack[1024], (unsigned long long) p512);
index 4af50ed..b6ccc4b 100644 (file)
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
  * MA 02110-1301 USA
  */
+#include <ros/common.h>
 
-#include <console/console.h>
-#include <console/uart.h>
-#include <ip_checksum.h>
-#include <boot/coreboot_tables.h>
+#include <stdio.h>
+#include <stdarg.h>
 #include <string.h>
-#include <version.h>
-#include <boardid.h>
-#include <device/device.h>
-#include <stdlib.h>
-#include <cbfs.h>
-#include <cbmem.h>
-#include <bootmem.h>
-#include <spi_flash.h>
-#if CONFIG_CHROMEOS
-#if CONFIG_HAVE_ACPI_TABLES
-#include <arch/acpi.h>
-#endif
-#include <vendorcode/google/chromeos/chromeos.h>
-#include <vendorcode/google/chromeos/gnvs.h>
-#endif
-#if CONFIG_ARCH_X86
-#include <cpu/x86/mtrr.h>
-#endif
+#include <vmm/coreboot_tables.h>
 
-static struct lb_header *lb_table_init(unsigned long addr)
+static struct lb_header *lb_table_init(void *addr)
 {
        struct lb_header *header;
 
        /* 16 byte align the address */
-       addr += 15;
-       addr &= ~15;
-
-       header = (void *)addr;
+       header = (void *)(((unsigned long)addr + 15) & ~15);
        header->signature[0] = 'L';
        header->signature[1] = 'B';
        header->signature[2] = 'I';
@@ -131,7 +110,7 @@ void lb_add_console(uint16_t consoletype, void *data)
 
 static void lb_framebuffer(struct lb_header *header)
 {
-#if CONFIG_FRAMEBUFFER_KEEP_VESA_MODE || CONFIG_MAINBOARD_DO_NATIVE_VGA_INIT
+#if 0 //CONFIG_FRAMEBUFFER_KEEP_VESA_MODE || CONFIG_MAINBOARD_DO_NATIVE_VGA_INIT
        void fill_lb_framebuffer(struct lb_framebuffer *framebuffer);
        int vbe_mode_info_valid(void);
 
@@ -218,7 +197,7 @@ static inline void lb_vboot_handoff(struct lb_header *header) {}
 
 static void lb_board_id(struct lb_header *header)
 {
-#if CONFIG_BOARD_ID_AUTO || CONFIG_BOARD_ID_MANUAL
+#if 0 // CONFIG_BOARD_ID_AUTO || CONFIG_BOARD_ID_MANUAL
        struct lb_board_id  *bid;
 
        bid = (struct lb_board_id *)lb_new_record(header);
@@ -229,92 +208,16 @@ static void lb_board_id(struct lb_header *header)
 #endif
 }
 
-static void lb_ram_code(struct lb_header *header)
-{
-#if IS_ENABLED(CONFIG_RAM_CODE_SUPPORT)
-       struct lb_ram_code *code;
-
-       code = (struct lb_ram_code *)lb_new_record(header);
-
-       code->tag = LB_TAG_RAM_CODE;
-       code->size = sizeof(*code);
-       code->ram_code = ram_code();
-#endif
-}
-
-static void add_cbmem_pointers(struct lb_header *header)
-{
-       /*
-        * These CBMEM sections' addresses are included in the coreboot table
-        * with the appropriate tags.
-        */
-       const struct section_id {
-               int cbmem_id;
-               int table_tag;
-       } section_ids[] = {
-               {CBMEM_ID_TIMESTAMP, LB_TAG_TIMESTAMPS},
-               {CBMEM_ID_CONSOLE, LB_TAG_CBMEM_CONSOLE},
-               {CBMEM_ID_ACPI_GNVS, LB_TAG_ACPI_GNVS},
-               {CBMEM_ID_WIFI_CALIBRATION, LB_TAG_WIFI_CALIBRATION}
-       };
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(section_ids); i++) {
-               const struct section_id *sid = section_ids + i;
-               struct lb_cbmem_ref *cbmem_ref;
-               void *cbmem_addr = cbmem_find(sid->cbmem_id);
-
-               if (!cbmem_addr)
-                       continue;  /* This section is not present */
-
-               cbmem_ref = (struct lb_cbmem_ref *)lb_new_record(header);
-               if (!cbmem_ref) {
-                       printk(BIOS_ERR, "No more room in coreboot table!\n");
-                       break;
-               }
-               cbmem_ref->tag = sid->table_tag;
-               cbmem_ref->size = sizeof(*cbmem_ref);
-               cbmem_ref->cbmem_addr = (unsigned long)cbmem_addr;
-       }
-}
-
-static struct lb_mainboard *lb_mainboard(struct lb_header *header)
-{
-       struct lb_record *rec;
-       struct lb_mainboard *mainboard;
-       rec = lb_new_record(header);
-       mainboard = (struct lb_mainboard *)rec;
-       mainboard->tag = LB_TAG_MAINBOARD;
-
-       mainboard->size = (sizeof(*mainboard) +
-               strlen(mainboard_vendor) + 1 +
-               strlen(mainboard_part_number) + 1 +
-               3) & ~3;
-
-       mainboard->vendor_idx = 0;
-       mainboard->part_number_idx = strlen(mainboard_vendor) + 1;
-
-       memcpy(mainboard->strings + mainboard->vendor_idx,
-               mainboard_vendor,      strlen(mainboard_vendor) + 1);
-       memcpy(mainboard->strings + mainboard->part_number_idx,
-               mainboard_part_number, strlen(mainboard_part_number) + 1);
-
-       return mainboard;
-}
-
 static void lb_strings(struct lb_header *header)
 {
        static const struct {
                uint32_t tag;
                const char *string;
        } strings[] = {
-               { LB_TAG_VERSION,        coreboot_version,        },
-               { LB_TAG_EXTRA_VERSION,  coreboot_extra_version,  },
-               { LB_TAG_BUILD,          coreboot_build,          },
-               { LB_TAG_COMPILE_TIME,   coreboot_compile_time,   },
+               // we may want this at some point.
        };
        unsigned int i;
-       for(i = 0; i < ARRAY_SIZE(strings); i++) {
+       for(i = 0; i < sizeof(strings)/sizeof(strings[0]); i++) {
                struct lb_string *rec;
                size_t len;
                rec = (struct lb_string *)lb_new_record(header);
@@ -332,7 +235,8 @@ static void lb_record_version_timestamp(struct lb_header *header)
        rec = (struct lb_timestamp *)lb_new_record(header);
        rec->tag = LB_TAG_VERSION_TIMESTAMP;
        rec->size = sizeof(*rec);
-       rec->timestamp = coreboot_version_timestamp;
+       // TODO
+       //rec->timestamp = coreboot_version_timestamp;
 }
 
 void __attribute__((weak)) lb_board(struct lb_header *header) { /* NOOP */ }
@@ -349,7 +253,27 @@ static struct lb_forward *lb_forward(struct lb_header *header, struct lb_header
        return forward;
 }
 
-static unsigned long lb_table_fini(struct lb_header *head)
+/* enough with the ip dependency already. This is a trivial checksum. */
+static inline uint16_t cb_checksum(const void *ptr, unsigned len)
+{
+       uint32_t sum;
+       const uint8_t *addr = ptr;
+
+       sum = 0;
+
+       while(len > 0) {
+               sum += addr[0]<<8 | addr[1] ;
+               len -= 2;
+               addr += 2;
+       }
+
+       sum = (sum & 0xffff) + (sum >> 16);
+       sum = (sum & 0xffff) + (sum >> 16);
+
+       return (sum^0xffff);
+}
+
+static void *lb_table_fini(struct lb_header *head)
 {
        struct lb_record *rec, *first_rec;
        rec = lb_last_record(head);
@@ -358,132 +282,31 @@ static unsigned long lb_table_fini(struct lb_header *head)
        }
 
        first_rec = lb_first_record(head);
-       head->table_checksum = compute_ip_checksum(first_rec, head->table_bytes);
+       head->table_checksum = cb_checksum((void *)first_rec, head->table_bytes);
        head->header_checksum = 0;
-       head->header_checksum = compute_ip_checksum(head, sizeof(*head));
-       printk(BIOS_DEBUG,
-              "Wrote coreboot table at: %p, 0x%x bytes, checksum %x\n",
+       head->header_checksum = cb_checksum((void *)head, sizeof(*head));
+       printf("Wrote coreboot table at: %p, 0x%x bytes, checksum %x\n",
               head, head->table_bytes, head->table_checksum);
-       return (unsigned long)rec + rec->size;
+       printf("header checksum (not worth using in a kernel) 0x%x\n", head->header_checksum);
+       return rec + rec->size;
 }
 
-unsigned long write_coreboot_table(
-       unsigned long low_table_start, unsigned long low_table_end,
-       unsigned long rom_table_start, unsigned long rom_table_end)
+void * write_coreboot_table(void *where, void *base, uint64_t len)
 {
        struct lb_header *head;
-
-       if (low_table_start || low_table_end) {
-               printk(BIOS_DEBUG, "Writing table forward entry at 0x%08lx\n",
-                               low_table_end);
-               head = lb_table_init(low_table_end);
-               lb_forward(head, (struct lb_header*)rom_table_end);
-
-               low_table_end = (unsigned long) lb_table_fini(head);
-               printk(BIOS_DEBUG, "Table forward entry ends at 0x%08lx.\n",
-                       low_table_end);
-               low_table_end = ALIGN(low_table_end, 4096);
-               printk(BIOS_DEBUG, "... aligned to 0x%08lx\n", low_table_end);
-       }
-
-       printk(BIOS_DEBUG, "Writing coreboot table at 0x%08lx\n",
-               rom_table_end);
-
-       head = lb_table_init(rom_table_end);
-       rom_table_end = (unsigned long)head;
-       printk(BIOS_DEBUG, "rom_table_end = 0x%08lx\n", rom_table_end);
-       rom_table_end = ALIGN(rom_table_end, (64 * 1024));
-       printk(BIOS_DEBUG, "... aligned to 0x%08lx\n", rom_table_end);
-
-#if CONFIG_USE_OPTION_TABLE
-       {
-               struct cmos_option_table *option_table = cbfs_get_file_content(
-                               CBFS_DEFAULT_MEDIA, "cmos_layout.bin",
-                               CBFS_COMPONENT_CMOS_LAYOUT, NULL);
-               if (option_table) {
-                       struct lb_record *rec_dest = lb_new_record(head);
-                       /* Copy the option config table, it's already a lb_record... */
-                       memcpy(rec_dest,  option_table, option_table->size);
-               } else {
-                       printk(BIOS_ERR, "cmos_layout.bin could not be found!\n");
-               }
-       }
-#endif
-
-       /* Initialize the memory map at boot time. */
-       bootmem_init();
-
-       if (low_table_start || low_table_end) {
-               uint64_t size = low_table_end - low_table_start;
-               /* Record the mptable and the the lb_table.
-                * (This will be adjusted later)  */
-               bootmem_add_range(low_table_start, size, LB_MEM_TABLE);
-       }
-
-       /* Record the pirq table, acpi tables, and maybe the mptable. However,
-        * these only need to be added when the rom_table is sitting below
-        * 1MiB. If it isn't that means high tables are being written.
-        * The code below handles high tables correctly. */
-       if (rom_table_end <= (1 << 20)) {
-               uint64_t size = rom_table_end - rom_table_start;
-               bootmem_add_range(rom_table_start, size, LB_MEM_TABLE);
-       }
-
-       /* No other memory areas can be added after the memory table has been
-        * committed as the entries won't show up in the serialize mem table. */
-       bootmem_write_memory_table(lb_memory(head));
-
-       /* Record our motherboard */
-       lb_mainboard(head);
-
-       /* Record the serial ports and consoles */
-#if CONFIG_CONSOLE_SERIAL
-       uart_fill_lb(head);
-#endif
-#if CONFIG_CONSOLE_USB
-       lb_add_console(LB_TAG_CONSOLE_EHCI, head);
-#endif
-
-       /* Record our various random string information */
-       lb_strings(head);
-       lb_record_version_timestamp(head);
-       /* Record our framebuffer */
-       lb_framebuffer(head);
-
-#if CONFIG_CHROMEOS
-       /* Record our GPIO settings (ChromeOS specific) */
-       lb_gpios(head);
-
-       /* pass along the VDAT buffer address */
-       lb_vdat(head);
-
-       /* pass along VBNV offsets in CMOS */
-       lb_vbnv(head);
-
-       /* pass along the vboot_handoff address. */
-       lb_vboot_handoff(head);
-#endif
-
-       /* Add board ID if available */
-       lb_board_id(head);
-
-       /* Add RAM config if available */
-       lb_ram_code(head);
-
-#if IS_ENABLED(CONFIG_SPI_FLASH)
-       /* Add SPI flash description if available */
-       lb_spi_flash(head);
-#endif
-
-       add_cbmem_pointers(head);
-
-       /* Add board-specific table entries, if any. */
-       lb_board(head);
-
-#if IS_ENABLED(CONFIG_CHROMEOS_RAMOOPS)
-       lb_ramoops(head);
-#endif
-
-       /* Remember where my valid memory ranges are */
+       struct lb_memory *m;
+       struct lb_memory_range *mem;
+
+       printf("Writing coreboot table at %p with mem %p len 0x%lx\n", where, base, len);
+
+       head = lb_table_init(where);
+       m = lb_memory(head);
+       mem = (void *)(&m[1]);
+       mem->start = pack_lb64((uint64_t) base);
+       mem->size = pack_lb64((uint64_t) len);
+       mem->type = LB_MEM_RAM;
+       m->size += sizeof(*mem);
+       printf("Head is %p, mem is %p, m is %p, m->size is %d, mem->size is %d\n",
+               head, mem, m, m->size, mem->size);
        return lb_table_fini(head);
 }
diff --git a/user/vmm/include/coreboot_tables.h b/user/vmm/include/coreboot_tables.h
new file mode 100644 (file)
index 0000000..73490a0
--- /dev/null
@@ -0,0 +1,405 @@
+#ifndef COREBOOT_TABLES_H
+#define COREBOOT_TABLES_H
+
+#include <stdint.h>
+#include <ros/common.h>
+
+// NOTE: the first part of this file is for producers of tables.
+// It is used when we are starting a guest. 
+// The second part is for CONSUMERS of tables, e.g. running
+// on a coreboot-based system. 
+
+/* The coreboot table information is for conveying information
+ * from the firmware to the loaded OS image.  Primarily this
+ * is expected to be information that cannot be discovered by
+ * other means, such as querying the hardware directly.
+ *
+ * All of the information should be Position Independent Data.
+ * That is it should be safe to relocated any of the information
+ * without it's meaning/correctness changing.   For table that
+ * can reasonably be used on multiple architectures the data
+ * size should be fixed.  This should ease the transition between
+ * 32 bit and 64 bit architectures etc.
+ *
+ * The completeness test for the information in this table is:
+ * - Can all of the hardware be detected?
+ * - Are the per motherboard constants available?
+ * - Is there enough to allow a kernel to run that was written before
+ *   a particular motherboard is constructed? (Assuming the kernel
+ *   has drivers for all of the hardware but it does not have
+ *   assumptions on how the hardware is connected together).
+ *
+ * With this test it should be straight forward to determine if a
+ * table entry is required or not.  This should remove much of the
+ * long term compatibility burden as table entries which are
+ * irrelevant or have been replaced by better alternatives may be
+ * dropped.  Of course it is polite and expedite to include extra
+ * table entries and be backwards compatible, but it is not required.
+ */
+
+/* Since coreboot is usually compiled 32bit, gcc will align 64bit
+ * types to 32bit boundaries. If the coreboot table is dumped on a
+ * 64bit system, a uint64_t would be aligned to 64bit boundaries,
+ * breaking the table format.
+ *
+ * lb_uint64 will keep 64bit coreboot table values aligned to 32bit
+ * to ensure compatibility. They can be accessed with the two functions
+ * below: unpack_lb64() and pack_lb64()
+ *
+ * See also: util/lbtdump/lbtdump.c
+ */
+
+struct lb_uint64 {
+       uint32_t lo;
+       uint32_t hi;
+};
+
+static inline uint64_t unpack_lb64(struct lb_uint64 value)
+{
+       uint64_t result;
+       result = value.hi;
+       result = (result << 32) + value.lo;
+       return result;
+}
+
+static inline struct lb_uint64 pack_lb64(uint64_t value)
+{
+       struct lb_uint64 result;
+       result.lo = (value >> 0) & 0xffffffff;
+       result.hi = (value >> 32) & 0xffffffff;
+       return result;
+}
+
+struct lb_header
+{
+       uint8_t  signature[4]; /* LBIO */
+       uint32_t header_bytes;
+       uint32_t header_checksum;
+       uint32_t table_bytes;
+       uint32_t table_checksum;
+       uint32_t table_entries;
+};
+
+/* Every entry in the boot environment list will correspond to a boot
+ * info record.  Encoding both type and size.  The type is obviously
+ * so you can tell what it is.  The size allows you to skip that
+ * boot environment record if you don't know what it is.  This allows
+ * forward compatibility with records not yet defined.
+ */
+struct lb_record {
+       uint32_t tag;           /* tag ID */
+       uint32_t size;          /* size of record (in bytes) */
+};
+
+#define LB_TAG_UNUSED          0x0000
+
+#define LB_TAG_MEMORY          0x0001
+
+struct lb_memory_range {
+       struct lb_uint64 start;
+       struct lb_uint64 size;
+       uint32_t type;
+#define LB_MEM_RAM              1      /* Memory anyone can use */
+#define LB_MEM_RESERVED                 2      /* Don't use this memory region */
+#define LB_MEM_ACPI             3      /* ACPI Tables */
+#define LB_MEM_NVS              4      /* ACPI NVS Memory */
+#define LB_MEM_UNUSABLE                 5      /* Unusable address space */
+#define LB_MEM_VENDOR_RSVD      6      /* Vendor Reserved */
+#define LB_MEM_TABLE           16      /* Ram configuration tables are kept in */
+};
+
+struct lb_memory {
+       uint32_t tag;
+       uint32_t size;
+       struct lb_memory_range map[0];
+};
+
+#define LB_TAG_HWRPB           0x0002
+struct lb_hwrpb {
+       uint32_t tag;
+       uint32_t size;
+       uint64_t hwrpb;
+};
+
+#define LB_TAG_MAINBOARD       0x0003
+struct lb_mainboard {
+       uint32_t tag;
+       uint32_t size;
+       uint8_t  vendor_idx;
+       uint8_t  part_number_idx;
+       uint8_t  strings[0];
+};
+
+#define LB_TAG_VERSION         0x0004
+#define LB_TAG_EXTRA_VERSION   0x0005
+#define LB_TAG_BUILD           0x0006
+#define LB_TAG_COMPILE_TIME    0x0007
+#define LB_TAG_COMPILE_BY      0x0008
+#define LB_TAG_COMPILE_HOST    0x0009
+#define LB_TAG_COMPILE_DOMAIN  0x000a
+#define LB_TAG_COMPILER                0x000b
+#define LB_TAG_LINKER          0x000c
+#define LB_TAG_ASSEMBLER       0x000d
+struct lb_string {
+       uint32_t tag;
+       uint32_t size;
+       uint8_t  string[0];
+};
+
+#define LB_TAG_VERSION_TIMESTAMP       0x0026
+struct lb_timestamp {
+       uint32_t tag;
+       uint32_t size;
+       uint32_t timestamp;
+};
+
+
+/* 0xe is taken by v3 */
+
+#define LB_TAG_SERIAL          0x000f
+struct lb_serial {
+       uint32_t tag;
+       uint32_t size;
+#define LB_SERIAL_TYPE_IO_MAPPED     1
+#define LB_SERIAL_TYPE_MEMORY_MAPPED 2
+       uint32_t type;
+       uint32_t baseaddr;
+       uint32_t baud;
+       uint32_t regwidth;
+};
+
+#define LB_TAG_CONSOLE         0x0010
+struct lb_console {
+       uint32_t tag;
+       uint32_t size;
+       uint16_t type;
+};
+
+#define LB_TAG_CONSOLE_SERIAL8250      0
+#define LB_TAG_CONSOLE_VGA             1 // OBSOLETE
+#define LB_TAG_CONSOLE_BTEXT           2 // OBSOLETE
+#define LB_TAG_CONSOLE_LOGBUF          3 // OBSOLETE
+#define LB_TAG_CONSOLE_SROM            4 // OBSOLETE
+#define LB_TAG_CONSOLE_EHCI            5
+#define LB_TAG_CONSOLE_SERIAL8250MEM   6
+
+#define LB_TAG_FORWARD         0x0011
+struct lb_forward {
+       uint32_t tag;
+       uint32_t size;
+       uint64_t forward;
+};
+
+#define LB_TAG_FRAMEBUFFER     0x0012
+struct lb_framebuffer {
+       uint32_t tag;
+       uint32_t size;
+
+       uint64_t physical_address;
+       uint32_t x_resolution;
+       uint32_t y_resolution;
+       uint32_t bytes_per_line;
+       uint8_t bits_per_pixel;
+       uint8_t red_mask_pos;
+       uint8_t red_mask_size;
+       uint8_t green_mask_pos;
+       uint8_t green_mask_size;
+       uint8_t blue_mask_pos;
+       uint8_t blue_mask_size;
+       uint8_t reserved_mask_pos;
+       uint8_t reserved_mask_size;
+};
+
+#define LB_TAG_GPIO    0x0013
+
+struct lb_gpio {
+       uint32_t port;
+       uint32_t polarity;
+#define ACTIVE_LOW     0
+#define ACTIVE_HIGH    1
+       uint32_t value;
+#define GPIO_MAX_NAME_LENGTH 16
+        uint8_t name[GPIO_MAX_NAME_LENGTH];
+};
+
+struct lb_gpios {
+       uint32_t tag;
+       uint32_t size;
+
+       uint32_t count;
+       struct lb_gpio gpios[0];
+};
+
+#define LB_TAG_VDAT            0x0015
+#define LB_TAG_VBNV            0x0019
+#define LB_TAB_VBOOT_HANDOFF   0x0020
+#define LB_TAB_DMA             0x0022
+#define LB_TAG_RAM_OOPS                0x0023
+struct lb_range {
+       uint32_t tag;
+       uint32_t size;
+
+       uint64_t range_start;
+       uint32_t range_size;
+};
+
+void lb_ramoops(struct lb_header *header);
+
+#define LB_TAG_TIMESTAMPS      0x0016
+#define LB_TAG_CBMEM_CONSOLE   0x0017
+#define LB_TAG_MRC_CACHE       0x0018
+#define LB_TAG_ACPI_GNVS       0x0024
+#define LB_TAG_WIFI_CALIBRATION        0x0027
+struct lb_cbmem_ref {
+       uint32_t tag;
+       uint32_t size;
+
+       uint64_t cbmem_addr;
+};
+
+#define LB_TAG_X86_ROM_MTRR    0x0021
+struct lb_x86_rom_mtrr {
+       uint32_t tag;
+       uint32_t size;
+       /* The variable range MTRR index covering the ROM. */
+       uint32_t index;
+};
+
+#define LB_TAG_BOARD_ID                0x0025
+struct lb_board_id {
+       uint32_t tag;
+       uint32_t size;
+       /* Board ID as retrieved from the board revision GPIOs. */
+       uint32_t board_id;
+};
+
+#define LB_TAG_MAC_ADDRS       0x0026
+struct mac_address {
+       uint8_t mac_addr[6];
+       uint8_t pad[2];         /* Pad it to 8 bytes to keep it simple. */
+};
+
+struct lb_macs {
+       uint32_t tag;
+       uint32_t size;
+       uint32_t count;
+       struct mac_address mac_addrs[0];
+};
+
+#define LB_TAG_RAM_CODE                0x0028
+struct lb_ram_code {
+       uint32_t tag;
+       uint32_t size;
+       uint32_t ram_code;
+};
+
+#define LB_TAG_SPI_FLASH       0x0029
+struct lb_spi_flash {
+       uint32_t tag;
+       uint32_t size;
+       uint32_t flash_size;
+       uint32_t sector_size;
+       uint32_t erase_cmd;
+};
+
+#define LB_TAG_SERIALNO                0x002a
+#define MAX_SERIALNO_LENGTH    32
+
+/* The following structures are for the cmos definitions table */
+#define LB_TAG_CMOS_OPTION_TABLE 200
+/* cmos header record */
+struct cmos_option_table {
+       uint32_t tag;               /* CMOS definitions table type */
+       uint32_t size;               /* size of the entire table */
+       uint32_t header_length;      /* length of header */
+};
+
+/* cmos entry record
+        This record is variable length.  The name field may be
+        shorter than CMOS_MAX_NAME_LENGTH. The entry may start
+        anywhere in the byte, but can not span bytes unless it
+        starts at the beginning of the byte and the length is
+        fills complete bytes.
+*/
+#define LB_TAG_OPTION 201
+struct cmos_entries {
+       uint32_t tag;                /* entry type */
+       uint32_t size;               /* length of this record */
+       uint32_t bit;                /* starting bit from start of image */
+       uint32_t length;             /* length of field in bits */
+       uint32_t config;             /* e=enumeration, h=hex, r=reserved */
+       uint32_t config_id;          /* a number linking to an enumeration record */
+#define CMOS_MAX_NAME_LENGTH 32
+       uint8_t name[CMOS_MAX_NAME_LENGTH]; /* name of entry in ascii,
+                                              variable length int aligned */
+};
+
+
+/* cmos enumerations record
+        This record is variable length.  The text field may be
+        shorter than CMOS_MAX_TEXT_LENGTH.
+*/
+#define LB_TAG_OPTION_ENUM 202
+struct cmos_enums {
+       uint32_t tag;                /* enumeration type */
+       uint32_t size;               /* length of this record */
+       uint32_t config_id;          /* a number identifying the config id */
+       uint32_t value;              /* the value associated with the text */
+#define CMOS_MAX_TEXT_LENGTH 32
+       uint8_t text[CMOS_MAX_TEXT_LENGTH]; /* enum description in ascii,
+                                               variable length int aligned */
+};
+
+/* cmos defaults record
+        This record contains default settings for the cmos ram.
+*/
+#define LB_TAG_OPTION_DEFAULTS 203
+struct cmos_defaults {
+       uint32_t tag;                /* default type */
+       uint32_t size;               /* length of this record */
+       uint32_t name_length;        /* length of the following name field */
+       uint8_t name[CMOS_MAX_NAME_LENGTH]; /* name identifying the default */
+#define CMOS_IMAGE_BUFFER_SIZE 256
+       uint8_t default_set[CMOS_IMAGE_BUFFER_SIZE]; /* default settings */
+};
+
+#define LB_TAG_OPTION_CHECKSUM 204
+struct cmos_checksum {
+       uint32_t tag;
+       uint32_t size;
+       /* In practice everything is byte aligned, but things are measured
+        * in bits to be consistent.
+        */
+       uint32_t range_start;   /* First bit that is checksummed (byte aligned) */
+       uint32_t range_end;     /* Last bit that is checksummed (byte aligned) */
+       uint32_t location;      /* First bit of the checksum (byte aligned) */
+       uint32_t type;          /* Checksum algorithm that is used */
+#define CHECKSUM_NONE  0
+#define CHECKSUM_PCBIOS        1
+};
+
+/* function prototypes for building the coreboot table */
+
+void *write_coreboot_table(void *where, void *base, uint64_t len);
+
+void fill_lb_gpios(struct lb_gpios *gpios);
+void fill_lb_gpio(struct lb_gpio *gpio, int num,
+                        int polarity, const char *name, int value);
+
+void uart_fill_lb(void *data);
+void lb_add_serial(struct lb_serial *serial, void *data);
+void lb_add_console(uint16_t consoletype, void *data);
+
+/* Define this in mainboard.c to add board-specific table entries. */
+void lb_board(struct lb_header *header);
+
+/*
+ * Function to retrieve MAC address(es) from the VPD and store them in the
+ * coreboot table.
+ */
+void lb_table_add_macs_from_vpd(struct lb_header *header);
+
+void lb_table_add_serialno_from_vpd(struct lb_header *header);
+
+struct lb_record *lb_new_record(struct lb_header *header);
+#endif