[coreboot-gerrit] Patch set updated for coreboot: 3acad49 regions support
Aaron Durbin (adurbin@google.com)
gerrit at coreboot.org
Tue Mar 18 19:23:51 CET 2014
Aaron Durbin (adurbin at google.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/5394
-gerrit
commit 3acad49d6e4ba786e6adf3b7917daea59671638a
Author: Aaron Durbin <adurbin at chromium.org>
Date: Thu Mar 13 08:50:00 2014 -0500
regions support
Needs some cleanup work. Compile tested as of now.
Change-Id: I2a78278090ae928468e197ac73d1fb18596bf8cb
Signed-off-by: Aaron Durbin <adurbin at chromium.org>
---
src/Kconfig | 7 +
src/arch/x86/boot/smbios.c | 8 +-
src/arch/x86/lib/rom_media.c | 114 +++---
src/cpu/intel/microcode/microcode.c | 38 +-
src/cpu/x86/mirror_payload.c | 38 +-
src/device/pci_device.c | 7 +-
src/device/pci_rom.c | 232 +++++++-----
src/drivers/elog/elog.c | 142 +++-----
src/include/cbfs.h | 120 +++---
src/include/cbfs_core.h | 44 ---
src/include/device/pci_rom.h | 4 +-
src/include/payload_loader.h | 3 +
src/include/region.h | 145 ++++++++
src/include/rmodule.h | 7 +-
src/lib/Makefile.inc | 10 +
src/lib/bootrw_spi_flash_region.c | 119 ++++++
src/lib/cbfs.c | 501 ++++++++++++++++++--------
src/lib/cbfs_boot_region.c | 133 +++++++
src/lib/cbfs_core.c | 224 ------------
src/lib/loaders/cbfs_payload_loader.c | 18 +-
src/lib/loaders/cbfs_ramstage_loader.c | 12 +-
src/lib/loaders/load_and_run_payload.c | 5 +-
src/lib/region.c | 305 ++++++++++++++++
src/lib/rmodule.c | 46 ++-
src/lib/selfboot.c | 113 +++---
src/soc/intel/baytrail/Kconfig | 1 +
src/soc/intel/baytrail/mrc_cache.c | 20 +-
src/soc/intel/baytrail/nvm.c | 27 +-
src/soc/intel/baytrail/romstage/raminit.c | 9 +-
src/soc/intel/baytrail/romstage/romstage.c | 4 +
src/vendorcode/google/chromeos/Makefile.inc | 1 +
src/vendorcode/google/chromeos/chromeos.c | 4 +
src/vendorcode/google/chromeos/fmap.c | 177 +++++----
src/vendorcode/google/chromeos/fmap.h | 25 +-
src/vendorcode/google/chromeos/vboot_loader.c | 47 ++-
35 files changed, 1771 insertions(+), 939 deletions(-)
diff --git a/src/Kconfig b/src/Kconfig
index 531a8c8..b0b8d26 100644
--- a/src/Kconfig
+++ b/src/Kconfig
@@ -1094,3 +1094,10 @@ config REG_SCRIPT
default n
help
Internal option that controls whether we compile in register scripts.
+
+config BOOT_REGION_SPI_FLASH
+ def_bool n
+ depends on ARCH_X86
+ help
+ Use generic SPI flash boot region support. This will provide a
+ function to initialize the read-write boot region.
diff --git a/src/arch/x86/boot/smbios.c b/src/arch/x86/boot/smbios.c
index 0e84acc..0434715 100644
--- a/src/arch/x86/boot/smbios.c
+++ b/src/arch/x86/boot/smbios.c
@@ -27,7 +27,6 @@
#include <device/device.h>
#include <arch/cpu.h>
#include <cpu/x86/name.h>
-#include <cbfs_core.h>
#include <arch/byteorder.h>
#include <elog.h>
#if CONFIG_CHROMEOS
@@ -147,12 +146,7 @@ static int smbios_write_type0(unsigned long *current, int handle)
#endif
{
- const struct cbfs_header *header;
- u32 romsize = CONFIG_ROM_SIZE;
- header = cbfs_get_header(CBFS_DEFAULT_MEDIA);
- if (header != CBFS_HEADER_INVALID_ADDRESS)
- romsize = ntohl(header->romsize);
- t->bios_rom_size = (romsize / 65535) - 1;
+ t->bios_rom_size = (CONFIG_ROM_SIZE / 65535) - 1;
}
t->system_bios_major_release = 4;
diff --git a/src/arch/x86/lib/rom_media.c b/src/arch/x86/lib/rom_media.c
index ed2122c..aa17d64 100644
--- a/src/arch/x86/lib/rom_media.c
+++ b/src/arch/x86/lib/rom_media.c
@@ -18,84 +18,64 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
-#include <cbfs.h>
+#include <stdint.h>
#include <string.h>
+#include <console/console.h>
+#include <region.h>
-#ifdef LIBPAYLOAD
-# define printk(x...)
-# define init_default_cbfs_media libpayload_init_default_cbfs_media
- extern int libpayload_init_default_cbfs_media(struct cbfs_media *media);
-#else
-# include <console/console.h>
-#endif
-
-// Implementation of memory-mapped ROM media source on X86.
-
-static int x86_rom_open(struct cbfs_media *media) {
- return 0;
+static inline void *get_pointer(offset_t off)
+{
+ const uintptr_t base_address = (uintptr_t)-CONFIG_ROM_SIZE;
+ return (void *)(base_address + off);
}
-static void *x86_rom_map(struct cbfs_media *media, size_t offset, size_t count) {
- void *ptr;
- // Some address (ex, pointer to master header) may be given in memory
- // mapped location. To workaround that, we handle >0xf0000000 as real
- // memory pointer.
-
- if ((uint32_t)offset > (uint32_t)0xf0000000)
- ptr = (void*)offset;
- else
- ptr = (void*)(0 - (uint32_t)media->context + offset);
- return ptr;
+static void *
+boot_mmap(const struct region_device *rdev, offset_t off, size_t size)
+{
+ return get_pointer(off);
}
-static void *x86_rom_unmap(struct cbfs_media *media, const void *address) {
- return NULL;
+static void boot_munmap(const struct region_device *rdev, void *addr)
+{
}
-static size_t x86_rom_read(struct cbfs_media *media, void *dest, size_t offset,
- size_t count) {
- void *ptr = x86_rom_map(media, offset, count);
- memcpy(dest, ptr, count);
- x86_rom_unmap(media, ptr);
- return count;
+static ssize_t
+boot_readat(const struct region_device *rdev, void *buf,
+ offset_t off, size_t size)
+{
+ memcpy(buf, get_pointer(off), size);
+ return size;
}
-static int x86_rom_close(struct cbfs_media *media) {
- return 0;
-}
+static const struct region_device_ops boot_dev_ops = {
+ .mmap = boot_mmap,
+ .munmap = boot_munmap,
+ .readat = boot_readat,
+};
+
+static const struct region_device boot_dev = {
+ .ops = &boot_dev_ops,
+ .region = {
+ .offset = 0,
+ .size = CONFIG_ROM_SIZE,
+ },
+};
-int init_x86rom_cbfs_media(struct cbfs_media *media);
-int init_x86rom_cbfs_media(struct cbfs_media *media) {
- // On X86, we always keep a reference of pointer to CBFS header in
- // 0xfffffffc, and the pointer is still a memory-mapped address.
- // Since the CBFS core always use ROM offset, we need to figure out
- // header->romsize even before media is initialized.
- struct cbfs_header *header = (struct cbfs_header*)
- *(uint32_t*)(0xfffffffc);
- if (CBFS_HEADER_MAGIC != ntohl(header->magic)) {
-#if defined(CONFIG_ROM_SIZE)
- printk(BIOS_ERR, "Invalid CBFS master header at %p\n", header);
- media->context = (void*)CONFIG_ROM_SIZE;
-#else
- return -1;
-#endif
- } else {
- uint32_t romsize = ntohl(header->romsize);
- media->context = (void*)romsize;
-#if defined(CONFIG_ROM_SIZE)
- if (CONFIG_ROM_SIZE != romsize)
- printk(BIOS_INFO, "Warning: rom size unmatch (%d/%d)\n",
- CONFIG_ROM_SIZE, romsize);
-#endif
+void boot_media_initialize(void)
+{
+ rhandle_t rh;
+ const char *bootro_name = BOOTRO_REGION_NAME;
+
+ rh = region_locate(bootro_name);
+
+ /* Already registered. */
+ if (rhandle_valid(rh)) {
+ printk(BIOS_DEBUG, "Already Registered: '%s'\n", bootro_name);
+ return;
}
- media->open = x86_rom_open;
- media->close = x86_rom_close;
- media->map = x86_rom_map;
- media->unmap = x86_rom_unmap;
- media->read = x86_rom_read;
- return 0;
-}
-int init_default_cbfs_media(struct cbfs_media *media) {
- return init_x86rom_cbfs_media(media);
+ rh = region_register(bootro_name, &boot_dev);
+
+ if (!rhandle_valid(rh))
+ printk(BIOS_ERR, "Failed to register '%s'.\n", bootro_name);
}
diff --git a/src/cpu/intel/microcode/microcode.c b/src/cpu/intel/microcode/microcode.c
index 947dfd7..d6753c1 100644
--- a/src/cpu/intel/microcode/microcode.c
+++ b/src/cpu/intel/microcode/microcode.c
@@ -107,28 +107,48 @@ void intel_microcode_load_unlocked(const void *microcode_patch)
#endif
}
+#if !defined(__ROMCC__)
+static void *microcode_locate(u32 *len)
+{
+ const struct cbfs_file_descriptor *fd;
+ void *buf;
+
+ fd = cbfs_open_by_name(cbfs_default_descriptor(), MICROCODE_CBFS_FILE);
+ if (fd == NULL)
+ return NULL;
+
+ /*
+ * The following sequence relies on x86 having a persistent
+ * memory-mapped view of the SPI rom.
+ */
+ *len = cbfs_file_content_size(fd);
+ buf = cbfs_file_map_content(fd, 0, *len);
+ cbfs_file_close(fd);
+
+ return buf;
+}
+#endif
+
const void *intel_microcode_find(void)
{
- struct cbfs_file *microcode_file;
const struct microcode *ucode_updates;
u32 eax, microcode_len;
u32 pf, rev, sig, update_size;
unsigned int x86_model, x86_family;
msr_t msr;
+#if defined(__ROMCC__)
+ struct cbfs_file *file;
-#ifdef __PRE_RAM__
- microcode_file = walkcbfs_head((char *) MICROCODE_CBFS_FILE);
+ file = walkcbfs_head((char *) MICROCODE_CBFS_FILE);
+ microcode_len = ntohl(file->len);
+ ucode_updates = CBFS_SUBHEADER(file);
#else
- microcode_file = cbfs_get_file(CBFS_DEFAULT_MEDIA,
- MICROCODE_CBFS_FILE);
+ ucode_updates = microcode_locate(µcode_len);
#endif
- if (!microcode_file)
+ if (!ucode_updates)
return NULL;
- ucode_updates = CBFS_SUBHEADER(microcode_file);
- microcode_len = ntohl(microcode_file->len);
-
/* CPUID sets MSR 0x8B iff a microcode update has been loaded. */
msr.lo = 0;
msr.hi = 0;
diff --git a/src/cpu/x86/mirror_payload.c b/src/cpu/x86/mirror_payload.c
index edd2641..a6975e1 100644
--- a/src/cpu/x86/mirror_payload.c
+++ b/src/cpu/x86/mirror_payload.c
@@ -30,26 +30,12 @@ void mirror_payload(struct payload *payload)
size_t size;
char *src;
uintptr_t alignment_diff;
- const unsigned long cacheline_size = 64;
- const uintptr_t intra_cacheline_mask = cacheline_size - 1;
- const uintptr_t cacheline_mask = ~intra_cacheline_mask;
+ const unsigned long dword_size = sizeof(uint32_t);
+ const uintptr_t dword_mask = dword_size - 1;
src = payload->backing_store.data;
size = payload->backing_store.size;
- /*
- * Adjust size so that the start and end points are aligned to a
- * cacheline. The SPI hardware controllers on Intel machines should
- * cache full length cachelines as well as prefetch data. Once the
- * data is mirrored in memory all accesses should hit the CPU's cache.
- */
- alignment_diff = (intra_cacheline_mask & (uintptr_t)src);
- size += alignment_diff;
-
- size = ALIGN(size, cacheline_size);
-
- printk(BIOS_DEBUG, "Payload aligned size: 0x%zx\n", size);
-
buffer = bootmem_allocate_buffer(size);
if (buffer == NULL) {
@@ -57,7 +43,18 @@ void mirror_payload(struct payload *payload)
return;
}
- src = (void *)(cacheline_mask & (uintptr_t)src);
+ /*
+ * Do copies in 32-bit aligned reads from backing source.
+ * 1. Do a copy to align the source address.
+ * 2. Do remaining copy.
+ */
+ alignment_diff = dword_mask & (uintptr_t)src;
+ if (alignment_diff != 0) {
+ mempcy(buffer, src, alignment_diff);
+ src += alignment_diff;
+ buffer += alignment_diff;
+ size -= alignment_diff;
+ }
/*
* Note that if mempcy is not using 32-bit moves the performance will
@@ -66,6 +63,9 @@ void mirror_payload(struct payload *payload)
*/
memcpy(buffer, src, size);
- /* Update the payload's backing store. */
- payload->backing_store.data = &buffer[alignment_diff];
+ /*
+ * Update the payload's backing store. May leak resources depending
+ * cbfs stroage source.
+ */
+ payload->backing_store.data = buffer;
}
diff --git a/src/device/pci_device.c b/src/device/pci_device.c
index aa0d954..bcdbbe4 100644
--- a/src/device/pci_device.c
+++ b/src/device/pci_device.c
@@ -667,7 +667,7 @@ int oprom_is_loaded = 0;
void pci_dev_init(struct device *dev)
{
#if CONFIG_VGA_ROM_RUN
- struct rom_header *rom, *ram;
+ struct rom_header *ram;
/* Only execute VGA ROMs. */
if (((dev->class >> 8) != PCI_CLASS_DISPLAY_VGA))
@@ -694,11 +694,8 @@ void pci_dev_init(struct device *dev)
return;
#endif
- rom = pci_rom_probe(dev);
- if (rom == NULL)
- return;
+ ram = pci_load_vga_rom(dev);
- ram = pci_rom_load(dev, rom);
if (ram == NULL)
return;
diff --git a/src/device/pci_rom.c b/src/device/pci_rom.c
index 1bdccf0..bb17931 100644
--- a/src/device/pci_rom.c
+++ b/src/device/pci_rom.c
@@ -6,6 +6,7 @@
* (Written by Yinghai Lu <yhlu at tyan.com> for Tyan)
* Copyright (C) 2005 Ronald G. Minnich <rminnich at gmail.com>
* Copyright (C) 2005-2007 Stefan Reinauer <stepan at openbios.org>
+ * Copyright (C) 2014 Google Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -28,62 +29,15 @@
#include <device/pci_ops.h>
#include <string.h>
#include <cbfs.h>
+#include <cbfs_core.h>
-struct rom_header *pci_rom_probe(struct device *dev)
+static struct rom_header *
+pci_rom_verify_and_load(struct device *dev, struct rom_header *rom_header,
+ void *load_addr, int check_didvid)
{
- struct rom_header *rom_header;
struct pci_data *rom_data;
-
- /* If it's in FLASH, then don't check device for ROM. */
- rom_header = cbfs_load_optionrom(CBFS_DEFAULT_MEDIA, dev->vendor,
- dev->device, NULL);
-
- u32 vendev = (dev->vendor << 16) | dev->device;
- u32 mapped_vendev = vendev;
-
- if (map_oprom_vendev)
- mapped_vendev = map_oprom_vendev(vendev);
-
- if (!rom_header) {
- if (vendev != mapped_vendev) {
- rom_header = cbfs_load_optionrom(
- CBFS_DEFAULT_MEDIA,
- mapped_vendev >> 16,
- mapped_vendev & 0xffff, NULL);
- }
- }
-
- if (rom_header) {
- printk(BIOS_DEBUG, "In CBFS, ROM address for %s = %p\n",
- dev_path(dev), rom_header);
- } else {
- u32 rom_address;
-
- rom_address = pci_read_config32(dev, PCI_ROM_ADDRESS);
-
- if (rom_address == 0x00000000 || rom_address == 0xffffffff) {
-#if CONFIG_BOARD_EMULATION_QEMU_X86
- if ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA)
- rom_address = 0xc0000;
- else
-#endif
- return NULL;
- } else {
- /* Enable expansion ROM address decoding. */
- pci_write_config32(dev, PCI_ROM_ADDRESS,
- rom_address|PCI_ROM_ADDRESS_ENABLE);
- }
-
-#if CONFIG_ON_DEVICE_ROM_RUN
- printk(BIOS_DEBUG, "Option ROM address for %s = %lx\n",
- dev_path(dev), (unsigned long)rom_address);
- rom_header = (struct rom_header *)rom_address;
-#else
- printk(BIOS_DEBUG, "Option ROM execution disabled "
- "for %s\n", dev_path(dev));
- return NULL;
-#endif
- }
+ unsigned int rom_size;
+ unsigned int image_size;
printk(BIOS_SPEW, "PCI expansion ROM, signature 0x%04x, "
"INIT size 0x%04x, data ptr 0x%04x\n",
@@ -100,10 +54,11 @@ struct rom_header *pci_rom_probe(struct device *dev)
printk(BIOS_SPEW, "PCI ROM image, vendor ID %04x, device ID %04x,\n",
rom_data->vendor, rom_data->device);
+
/* If the device id is mapped, a mismatch is expected */
- if ((dev->vendor != rom_data->vendor
- || dev->device != rom_data->device)
- && (vendev == mapped_vendev)) {
+ if (check_didvid != 0 &&
+ (dev->vendor != rom_data->vendor ||
+ dev->device != rom_data->device)) {
printk(BIOS_ERR, "ID mismatch: vendor ID %04x, "
"device ID %04x\n", rom_data->vendor, rom_data->device);
return NULL;
@@ -117,29 +72,16 @@ struct rom_header *pci_rom_probe(struct device *dev)
printk(BIOS_DEBUG, "Class Code mismatch ROM %08x, dev %08x\n",
(rom_data->class_hi << 8) | rom_data->class_lo,
dev->class);
- // return NULL;
}
- return rom_header;
-}
-
-static void *pci_ram_image_start = (void *)PCI_RAM_IMAGE_START;
-
-struct rom_header *pci_rom_load(struct device *dev,
- struct rom_header *rom_header)
-{
- struct pci_data * rom_data;
- unsigned int rom_size;
- unsigned int image_size=0;
-
+ image_size = 0;
do {
/* Get next image. */
- rom_header = (struct rom_header *)((void *) rom_header
- + image_size);
-
- rom_data = (struct pci_data *)((void *) rom_header
- + le32_to_cpu(rom_header->data));
+ int data_offset;
+ rom_header = (void *)((char *)rom_header + image_size);
+ data_offset = le32_to_cpu(rom_header->data);
+ rom_data = (void *)((char *)rom_header + data_offset);
image_size = le32_to_cpu(rom_data->ilen) * 512;
} while ((rom_data->type != 0) && (rom_data->indicator != 0)); // make sure we got x86 version
@@ -148,30 +90,128 @@ struct rom_header *pci_rom_load(struct device *dev,
rom_size = rom_header->size * 512;
- /*
- * We check to see if the device thinks it is a VGA device not
- * whether the ROM image is for a VGA device because some
- * devices have a mismatch between the hardware and the ROM.
- */
- if (PCI_CLASS_DISPLAY_VGA == (dev->class >> 8)) {
+ if (load_addr != (void *)rom_header) {
+ printk(BIOS_DEBUG, "Copying ROM from %p to %p, 0x%x bytes.\n",
+ rom_header, load_addr, rom_size);
+ memcpy(load_addr, rom_header, rom_size);
+ }
+
+ return load_addr;
+}
+
+static inline int tohex4(unsigned int c)
+{
+ return (c <= 9) ? (c + '0') : (c - 10 + 'a');
+}
+
+static void tohex16(uint16_t val, char* dest)
+{
+ dest[0] = tohex4(val>>12);
+ dest[1] = tohex4((val>>8) & 0xf);
+ dest[2] = tohex4((val>>4) & 0xf);
+ dest[3] = tohex4(val & 0xf);
+}
+
+static const struct cbfs_file_descriptor *
+cbfs_open_optionrom(uint16_t vendor, uint16_t device)
+{
+ char name[17] = "pciXXXX,XXXX.rom";
+
+ tohex16(vendor, name+3);
+ tohex16(device, name+8);
+
+ return cbfs_open_by_name_type(cbfs_default_descriptor(), name,
+ CBFS_TYPE_OPTIONROM);
+}
+
+static void *cbfs_probe_and_load(struct device *dev, void *dest)
+{
+ const struct cbfs_file_descriptor *file;
+ uint32_t vendev;
+ int remapped;
+ struct rom_header *hdr;
+ void *load_addr;
+ ssize_t filesz;
+
+ load_addr = NULL;
+ remapped = 0;
+ file = cbfs_open_optionrom(dev->vendor, dev->device);
+
+ if (file == NULL && map_oprom_vendev != NULL) {
+ vendev = map_oprom_vendev((dev->vendor << 16) | dev->device);
+ file = cbfs_open_optionrom(vendev >> 16, vendev & 0xffff);
+ remapped = 1;
+ }
+
+ if (file == NULL)
+ return NULL;
+
+ filesz = cbfs_file_content_size(file);
+ hdr = cbfs_file_map_content(file, 0, filesz);
+ if (hdr == NULL)
+ goto out;
+
+ printk(BIOS_DEBUG, "In CBFS, ROM address for %s = %p\n",
+ dev_path(dev), hdr);
+
+ load_addr = pci_rom_verify_and_load(dev, hdr, dest, !remapped);
+ cbfs_file_unmap(file, hdr);
+
+out:
+ cbfs_file_close(file);
+ return load_addr;
+}
+
+#if CONFIG_ON_DEVICE_ROM_RUN
+static void *dev_probe_and_load(struct device *dev, void *dest)
+{
+ uint32_t rom_address;
+ struct rom_header *rom_header;
+
+ rom_address = pci_read_config32(dev, PCI_ROM_ADDRESS);
+
+ if (rom_address == 0x00000000 || rom_address == 0xffffffff) {
+ if (IS_ENABLED(CONFIG_BOARD_EMULATION_QEMU_X86))
+ rom_address = 0xc0000;
+ else
+ return NULL;
+ } else {
+ /* Enable expansion ROM address decoding. */
+ pci_write_config32(dev, PCI_ROM_ADDRESS,
+ rom_address|PCI_ROM_ADDRESS_ENABLE);
+ }
+ printk(BIOS_DEBUG, "Option ROM address for %s = %lx\n",
+ dev_path(dev), (unsigned long)rom_address);
+
+ rom_header = (struct rom_header *)rom_address;
+
+ return pci_rom_verify_and_load(dev, rom_header, dest, 1);
+}
+#endif
+
+struct rom_header *pci_load_vga_rom(struct device *dev)
+{
+ void *vga_load_addr = (void *)PCI_VGA_RAM_IMAGE_START;
+ void *load_addr;
+
+ if (PCI_CLASS_DISPLAY_VGA != (dev->class >> 8))
+ return NULL;
+
#if !CONFIG_MULTIPLE_VGA_ADAPTERS
- extern device_t vga_pri; /* Primary VGA device (device.c). */
- if (dev != vga_pri) return NULL; /* Only one VGA supported. */
+ extern device_t vga_pri; /* Primary VGA device (device.c). */
+ if (dev != vga_pri) return NULL; /* Only one VGA supported. */
#endif
- if ((void *)PCI_VGA_RAM_IMAGE_START != rom_header) {
- printk(BIOS_DEBUG, "Copying VGA ROM Image from %p to "
- "0x%x, 0x%x bytes\n", rom_header,
- PCI_VGA_RAM_IMAGE_START, rom_size);
- memcpy((void *)PCI_VGA_RAM_IMAGE_START, rom_header,
- rom_size);
- }
- return (struct rom_header *) (PCI_VGA_RAM_IMAGE_START);
- }
- printk(BIOS_DEBUG, "Copying non-VGA ROM image from %p to %p, 0x%x "
- "bytes\n", rom_header, pci_ram_image_start, rom_size);
+ load_addr = cbfs_probe_and_load(dev, vga_load_addr);
+
+ if (load_addr == NULL) {
+#if CONFIG_ON_DEVICE_ROM_RUN
+ load_addr = dev_probe_and_load(dev, vga_load_addr);
+#else
+ printk(BIOS_DEBUG, "Option ROM execution disabled for %s\n",
+ dev_path(dev));
+#endif
+ }
- memcpy(pci_ram_image_start, rom_header, rom_size);
- pci_ram_image_start += rom_size;
- return (struct rom_header *) (pci_ram_image_start-rom_size);
+ return load_addr;
}
diff --git a/src/drivers/elog/elog.c b/src/drivers/elog/elog.c
index de34928..597c32e 100644
--- a/src/drivers/elog/elog.c
+++ b/src/drivers/elog/elog.c
@@ -22,10 +22,9 @@
#include <console/console.h>
#include <pc80/mc146818rtc.h>
#include <smbios.h>
-#include <spi-generic.h>
-#include <spi_flash.h>
#include <stdint.h>
#include <string.h>
+#include <region.h>
#include <elog.h>
#include "elog_internal.h"
@@ -54,13 +53,15 @@
#define elog_debug(STR...)
#endif
+
+#define ELOG_REGION_NAME "elog"
+
/*
* Static variables for ELOG state
*/
static struct elog_area *elog_area;
static u16 total_size;
static u16 log_size;
-static u32 flash_base;
static elog_area_state area_state;
static elog_header_state header_state;
@@ -70,51 +71,10 @@ static u16 next_event_offset;
static u16 event_count;
static int elog_initialized;
-static struct spi_flash *elog_spi;
-
-
-static inline u32 get_rom_size(void)
-{
- u32 rom_size;
-
- /* Assume the used space of the ROM image starts from 0. The
- * physical size of the device may not be completely used. */
- rom_size = elog_spi->size;
- if (rom_size > CONFIG_ROM_SIZE)
- rom_size = CONFIG_ROM_SIZE;
-
- return rom_size;
-}
-
-/*
- * Convert a memory mapped flash address into a flash offset
- */
-static inline u32 elog_flash_address_to_offset(u8 *address)
-{
- u32 rom_size;
-
- if (!elog_spi)
- return 0;
- rom_size = get_rom_size();
-
- return (u32)address - ((u32)~0UL - rom_size + 1);
-}
-
-/*
- * Convert a flash offset into a memory mapped flash address
- */
-static inline u8* elog_flash_offset_to_address(u32 offset)
-{
- u32 rom_size;
-
- if (!elog_spi)
- return NULL;
-
- rom_size = get_rom_size();
-
- return (u8*)((u32)~0UL - rom_size + 1 + offset);
-}
+/* Region device for accessing the ELOG area. */
+static struct region_device elog_dev;
+static rhandle_t elog_rh = INVALID_RHANDLE;
/*
* Pointer to an event log header in the event data area
@@ -259,17 +219,16 @@ static void elog_flash_write(void *address, u32 size)
{
u32 offset;
- if (!address || !size || !elog_spi)
+ if (!address || !size)
return;
- offset = flash_base;
- offset += (u8 *)address - (u8 *)elog_area;
+ offset = (u8 *)address - (u8 *)elog_area;
elog_debug("elog_flash_write(address=0x%p offset=0x%08x size=%u)\n",
address, offset, size);
/* Write the data to flash */
- elog_spi->write(elog_spi, offset, size, address);
+ region_writeat(elog_rh, address, offset, size);
}
/*
@@ -280,17 +239,16 @@ static void elog_flash_erase(void *address, u32 size)
{
u32 offset;
- if (!address || !size || !elog_spi)
+ if (!address || !size)
return;
- offset = flash_base;
- offset += (u8 *)address - (u8*)elog_area;
+ offset = (u8 *)address - (u8*)elog_area;
elog_debug("elog_flash_erase(address=0x%p offset=0x%08x size=%u)\n",
address, offset, size);
/* Erase the sectors in this region */
- elog_spi->erase(elog_spi, offset, size);
+ region_eraseat(elog_rh, offset, size);
}
/*
@@ -348,7 +306,7 @@ static void elog_scan_flash(void)
event_buffer_state = ELOG_EVENT_BUFFER_OK;
/* Fill memory buffer by reading from SPI */
- elog_spi->read(elog_spi, flash_base, total_size, elog_area);
+ region_readat(elog_rh, elog_area, 0, total_size);
next_event_offset = 0;
event_count = 0;
@@ -449,13 +407,17 @@ int elog_smbios_write_type15(unsigned long *current, int handle)
{
struct smbios_type15 *t = (struct smbios_type15 *)*current;
int len = sizeof(struct smbios_type15);
+ void *backing_store;
#if CONFIG_ELOG_CBMEM
/* Save event log buffer into CBMEM for the OS to read */
- void *cbmem = cbmem_add(CBMEM_ID_ELOG, total_size);
- if (!cbmem)
+ backing_store = cbmem_add(CBMEM_ID_ELOG, total_size);
+ if (!backing_store)
return 0;
- memcpy(cbmem, elog_area, total_size);
+ memcpy(backing_store, elog_area, total_size);
+#else
+ /* This assumes x86 memory-mapped capabilities of flash. */
+ backing_store = region_mmap(elog_rh, 0, total_size);
#endif
memset(t, 0, len);
@@ -468,11 +430,7 @@ int elog_smbios_write_type15(unsigned long *current, int handle)
t->access_method = SMBIOS_EVENTLOG_ACCESS_METHOD_MMIO32;
t->log_status = SMBIOS_EVENTLOG_STATUS_VALID;
t->change_token = 0;
-#if CONFIG_ELOG_CBMEM
- t->address = (u32)cbmem;
-#else
- t->address = (u32)elog_flash_offset_to_address(flash_base);
-#endif
+ t->address = (u32)backing_store;
t->header_format = ELOG_HEADER_TYPE_OEM;
t->log_type_descriptors = 0;
t->log_type_descriptor_length = 2;
@@ -506,33 +464,46 @@ int elog_clear(void)
return 0;
}
-static void elog_find_flash(void)
+static int elog_find_flash(void)
{
-#if CONFIG_CHROMEOS
- u8 *flash_base_ptr;
-#endif
+ rhandle_t rh;
+
+ if (rhandle_valid(elog_rh))
+ return 0;
elog_debug("elog_find_flash()\n");
#if CONFIG_CHROMEOS
/* Find the ELOG base and size in FMAP */
- total_size = find_fmap_entry("RW_ELOG", (void **)&flash_base_ptr);
- if (total_size < 0) {
+ if (fmap_locate("RW_ELOG", &elog_dev.region.offset,
+ &elog_dev.region.size)) {
printk(BIOS_WARNING, "ELOG: Unable to find RW_ELOG in FMAP, "
"using CONFIG_ELOG_FLASH_BASE instead\n");
- total_size = CONFIG_ELOG_AREA_SIZE;
} else {
- flash_base = elog_flash_address_to_offset(flash_base_ptr);
-
/* Use configured size if smaller than FMAP size */
- if (total_size > CONFIG_ELOG_AREA_SIZE)
- total_size = CONFIG_ELOG_AREA_SIZE;
+ if (elog_dev.region.size > CONFIG_ELOG_AREA_SIZE)
+ elog_dev.region.size = CONFIG_ELOG_AREA_SIZE;
}
#else
- flash_base = CONFIG_ELOG_FLASH_BASE;
- total_size = CONFIG_ELOG_AREA_SIZE;
+ elog_dev.region.offset = CONFIG_ELOG_FLASH_BASE;
+ elog_dev.region.size = CONFIG_ELOG_AREA_SIZE;
#endif
+ total_size = elog_dev.region.size;
log_size = total_size - sizeof(struct elog_header);
+
+ rh = region_locate(BOOTRW_REGION_NAME);
+ if (!rhandle_valid(rh)) {
+ printk(BIOS_WARNING, "Unable to find writable boot region.\n");
+ return -1;
+ }
+ rh = region_register_subregion("elog", &elog_dev, rh);
+ if (!rhandle_valid(rh)) {
+ printk(BIOS_WARNING, "Unable to register ELOG region.\n");
+ return -1;
+ }
+
+ elog_rh = rh;
+ return 0;
}
/*
@@ -545,18 +516,9 @@ int elog_init(void)
elog_debug("elog_init()\n");
- /* Prepare SPI */
- spi_init();
- elog_spi = spi_flash_probe(0, 0, 0, 0);
- if (!elog_spi) {
- printk(BIOS_ERR, "ELOG: Unable to find SPI flash\n");
- return -1;
- }
-
/* Set up the backing store */
- elog_find_flash();
- if (flash_base == 0) {
- printk(BIOS_ERR, "ELOG: Invalid flash base\n");
+ if (elog_find_flash()) {
+ printk(BIOS_ERR, "ELOG: region not set up.\n");
return -1;
}
@@ -589,8 +551,8 @@ int elog_init(void)
elog_initialized = 1;
- printk(BIOS_INFO, "ELOG: FLASH @0x%p [SPI 0x%08x]\n",
- elog_area, flash_base);
+ printk(BIOS_INFO, "ELOG: FLASH @0x%p [SPI 0x%08zx]\n",
+ elog_area, (size_t)elog_dev.region.offset);
printk(BIOS_INFO, "ELOG: area is %d bytes, full threshold %d,"
" shrink size %d\n", total_size,
diff --git a/src/include/cbfs.h b/src/include/cbfs.h
index ebdbf43..bd000c9 100644
--- a/src/include/cbfs.h
+++ b/src/include/cbfs.h
@@ -1,14 +1,8 @@
/*
* This file is part of the coreboot project.
*
- * Copyright (C) 2008 Jordan Crouse <jordan at cosmicpenguin.net>
- * Copyright (C) 2013 The Chromium OS Authors. All rights reserved.
+ * Copyright (C) 2014 Google Inc.
*
- * This file is dual-licensed. You can choose between:
- * - The GNU GPL, version 2, as published by the Free Software Foundation
- * - The revised BSD license (without advertising clause)
- *
- * ---------------------------------------------------------------------------
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
@@ -20,62 +14,84 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
- * ---------------------------------------------------------------------------
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- * ---------------------------------------------------------------------------
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
-
#ifndef _CBFS_H_
#define _CBFS_H_
-#include <cbfs_core.h>
+#include <stdint.h>
+#include <region.h>
-void *cbfs_load_optionrom(struct cbfs_media *media, uint16_t vendor,
- uint16_t device, void * dest);
-void *cbfs_load_stage(struct cbfs_media *media, const char *name);
-
-/* Simple buffer for streaming media. */
-struct cbfs_simple_buffer {
- char *buffer;
- size_t allocated;
+/* Describe an instance of cbfs. */
+struct cbfs_descriptor {
+ rhandle_t rh;
+ size_t align;
size_t size;
- size_t last_allocate;
};
-void *cbfs_simple_buffer_map(struct cbfs_simple_buffer *buffer,
- struct cbfs_media *media,
- size_t offset, size_t count);
+struct cbfs_file_descriptor;
+
+/* Obtain the default cbfs_descriptor. */
+const struct cbfs_descriptor *cbfs_default_descriptor(void);
+
+/* Open a file by name. Return NULL on error. */
+const struct cbfs_file_descriptor *
+cbfs_open_by_name(const struct cbfs_descriptor *cbfs, const char *name);
+
+/* Open a file by name and type. */
+const struct cbfs_file_descriptor *
+cbfs_open_by_name_type(const struct cbfs_descriptor *cbfs,
+ const char *name, uint32_t type);
+
+/* Close a previously opened file. */
+void cbfs_file_close(const struct cbfs_file_descriptor *fd);
+
+/* Return the size of the file's contents. < 0 on error. */
+ssize_t cbfs_file_content_size(const struct cbfs_file_descriptor *fd);
+
+/* Return the size of the file's metadata contents. < 0 on error. */
+ssize_t cbfs_file_metadata_size(const struct cbfs_file_descriptor *fd);
+
+/*
+ * Read size bytes file contents from offset of into buffer. Returns < 0
+ * on error or bytes read.
+ */
+ssize_t cbfs_file_read_content(const struct cbfs_file_descriptor *fd,
+ void *buf, offset_t offset, size_t size);
+
+/* Attempt to map the file content. Returns NULL on error. */
+void *cbfs_file_map_content(const struct cbfs_file_descriptor *fd,
+ offset_t offset, size_t size);
+
+/*
+ * Read size bytes file metadata from offset of into buffer. Returns < 0
+ * on error or bytes read.
+ */
+ssize_t cbfs_file_read_metadata(const struct cbfs_file_descriptor *fd,
+ void *buf, offset_t offset, size_t size);
+/*
+ * Attempt to map all of the file's metadata. Depending on the file type there
+ * may be no metadata in which case NULL will be returned. File types of
+ * CBFS_TYPE_STAGE and CBFS_TYPE_PAYLOAD are currently the only files that
+ * contain metadata.
+ *
+ * Returns NULL on error.
+ */
+void *cbfs_file_map_metadata(const struct cbfs_file_descriptor *fd);
+
+/* Unmap the mapping associated with addr. No partial unmappings allowed. */
+void cbfs_file_unmap(const struct cbfs_file_descriptor *fd, void *addr);
+
-void *cbfs_simple_buffer_unmap(struct cbfs_simple_buffer *buffer,
- const void *address);
+void *cbfs_load_optionrom(const struct cbfs_descriptor *cbfs,
+ uint16_t vendor, uint16_t device, void * dest);
-// Utility functions
-int run_address(void *f);
+/* Return entry point to stage, or NULL on failure. */
+void *cbfs_load_stage(const struct cbfs_descriptor *cbfs, const char *name);
-/* Defined in individual arch / board implementation. */
-int init_default_cbfs_media(struct cbfs_media *media);
+/* Decompress range of file to destination. Returns bytes decompressed. */
+size_t cbfs_file_inflate(const struct cbfs_file_descriptor *fd,
+ offset_t offset, size_t src_sz, void *dest);
#if defined(__PRE_RAM__)
struct romstage_handoff;
diff --git a/src/include/cbfs_core.h b/src/include/cbfs_core.h
index a1d8127..6a91454 100644
--- a/src/include/cbfs_core.h
+++ b/src/include/cbfs_core.h
@@ -186,50 +186,6 @@ struct cbfs_optionrom {
uint32_t len;
} __attribute__((packed));
-#define CBFS_MEDIA_INVALID_MAP_ADDRESS ((void*)(0xffffffff))
-#define CBFS_DEFAULT_MEDIA ((void*)(0x0))
-
-/* Media for CBFS to load files. */
-struct cbfs_media {
-
- /* implementation dependent context, to hold resource references */
- void *context;
-
- /* opens media and returns 0 on success, -1 on failure */
- int (*open)(struct cbfs_media *media);
-
- /* returns number of bytes read from media into dest, starting from
- * offset for count of bytes */
- size_t (*read)(struct cbfs_media *media, void *dest, size_t offset,
- size_t count);
-
- /* returns a pointer to memory with count of bytes from media source
- * starting from offset, or CBFS_MEDIA_INVALID_MAP_ADDRESS on failure.
- * Note: mapped data can't be free unless unmap is called, even if you
- * do close first. */
- void * (*map)(struct cbfs_media *media, size_t offset, size_t count);
-
- /* returns NULL and releases the memory by address, which was allocated
- * by map */
- void * (*unmap)(struct cbfs_media *media, const void *address);
-
- /* closes media and returns 0 on success, -1 on failure. */
- int (*close)(struct cbfs_media *media);
-};
-
-/* returns pointer to a file entry inside CBFS or NULL */
-struct cbfs_file *cbfs_get_file(struct cbfs_media *media, const char *name);
-
-/* returns pointer to file content inside CBFS after if type is correct */
-void *cbfs_get_file_content(struct cbfs_media *media, const char *name,
- int type, size_t *sz);
-
-/* returns decompressed size on success, 0 on failure */
-int cbfs_decompress(int algo, void *src, void *dst, int len);
-
-/* returns a pointer to CBFS master header, or CBFS_HEADER_INVALID_ADDRESS
- * on failure */
-const struct cbfs_header *cbfs_get_header(struct cbfs_media *media);
#endif /* __ROMCC__ */
diff --git a/src/include/device/pci_rom.h b/src/include/device/pci_rom.h
index fe77276..4bd0bfd 100644
--- a/src/include/device/pci_rom.h
+++ b/src/include/device/pci_rom.h
@@ -6,7 +6,6 @@
#define PCI_ROM_HDR 0xAA55
#define PCI_DATA_HDR (uint32_t) ( ('R' << 24) | ('I' << 16) | ('C' << 8) | 'P' )
-#define PCI_RAM_IMAGE_START 0xD0000
#define PCI_VGA_RAM_IMAGE_START 0xC0000
struct rom_header {
@@ -33,8 +32,7 @@ struct pci_data {
uint16_t reserved_2;
};
-struct rom_header *pci_rom_probe(struct device *dev);
-struct rom_header *pci_rom_load(struct device *dev, struct rom_header *rom_header);
+struct rom_header *pci_load_vga_rom(struct device *dev);
u32 __attribute__((weak)) map_oprom_vendev(u32 vendev);
#endif
diff --git a/src/include/payload_loader.h b/src/include/payload_loader.h
index 7a3f045..7b6fc1c 100644
--- a/src/include/payload_loader.h
+++ b/src/include/payload_loader.h
@@ -22,6 +22,8 @@
#include <stdint.h>
#include <stddef.h>
+struct cbfs_file_descriptor;
+
struct buffer_area {
void *data;
size_t size;
@@ -29,6 +31,7 @@ struct buffer_area {
struct payload {
const char *name;
+ const struct cbfs_file_descriptor *fd;
struct buffer_area backing_store;
/* Used when payload wants memory coreboot ramstage is running at. */
struct buffer_area bounce;
diff --git a/src/include/region.h b/src/include/region.h
new file mode 100644
index 0000000..cd66bde
--- /dev/null
+++ b/src/include/region.h
@@ -0,0 +1,145 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2014 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef REGION_H
+#define REGION_H
+
+#include <stdint.h>
+#include <stddef.h>
+
+/*
+ * Region support.
+ *
+ * Regions are intended to abstract away the access mechanisms for blocks of
+ * data. This could be SPI, eMMC, or a memory region as the backing store.
+ * Subregions can be made by registering a region_device that is associated
+ * with another region. Regions can be addressed by name, but there is no
+ * hierarchy in the namespace. i.e. the operations through subregions are
+ * hierarchical but the namespace is not.
+ *
+ * There are two views to the boot media: read-only and read-write. On certain
+ * architectures the read-write availability is not available until late in
+ * ramstage. Therefore, users of each region need to be cognizant of the fact
+ * that different implementations may be backing a particular region. e.g. on
+ * x86 the read-only boot region doesn't have write and erase capabilities, but
+ * the read-write boot region would allow writes and erases but no mmap.
+ */
+
+/*
+ * Initialize the boot region. Called directly in pre-ramstage or
+ * automatically in ramstage.
+ */
+void boot_region_init(void);
+/* Initialize the boot media. Board/Arch specific code implements this. */
+void boot_media_initialize(void);
+/*
+ * A potential call for chipsets that can't bring their RW area online til
+ * after the device init in ramstage.
+ */
+void bootrw_media_initialize(void);
+/* Initialize the default CBFS region. */
+void cbfs_default_media_initialize(void);
+
+typedef uintptr_t offset_t;
+typedef long rhandle_t;
+#define INVALID_RHANDLE ((rhandle_t)~((uintptr_t)0))
+
+#define BOOTRO_REGION_NAME "bootro"
+#define BOOTRW_REGION_NAME "bootrw"
+#define DEFAULT_CBFS_REGION_NAME "cbfs"
+
+struct region_device;
+
+struct region_device_ops {
+ void *(*mmap)(const struct region_device *, offset_t, size_t);
+ void (*munmap)(const struct region_device *, void *);
+ ssize_t (*readat)(const struct region_device *, void *,
+ offset_t, size_t);
+ ssize_t (*writeat)(const struct region_device *, const void *,
+ offset_t, size_t);
+ ssize_t (*eraseat)(const struct region_device *, offset_t, size_t);
+};
+
+struct region {
+ offset_t offset;
+ size_t size;
+};
+
+struct region_device {
+ const struct region_device_ops *ops;
+ struct region region;
+};
+
+/*
+ * Requests within a region are relative to the region's size. Therefore,
+ * the requests need to be normalized to the parent's region. This routine
+ * does that normalization and checks if the request is within bounds.
+ *
+ * Returns -1 if invalid request or 0 if request is within bounds.
+ */
+int region_request_normalize(const struct region *parent,
+ struct region *request);
+
+static inline int rhandle_valid(rhandle_t rh)
+{
+ return !!(rh >= 0);
+}
+
+/* Register a region_device by name. */
+rhandle_t region_register(const char *name, const struct region_device *rdev);
+
+/* Register a subregion by name under parent. rdev->ops must be NULL. */
+rhandle_t region_register_subregion(const char *name,
+ const struct region_device *rdev,
+ rhandle_t parent);
+
+/* Locate a region of provided name. */
+rhandle_t region_locate(const char *name);
+
+/*
+ * Read subregion within provided region.
+ * Returns bytes read, < 0 on error.
+ */
+ssize_t region_readat(rhandle_t rh, void *buf, offset_t offset, size_t count);
+
+/*
+ * Write to subregion within provided region.
+ * Returns bytes written, < 0 on error.
+ */
+ssize_t region_writeat(rhandle_t rh, void *buf, offset_t offset, size_t count);
+
+/*
+ * Erase subregion within provide region.
+ * Returns bytes erased, < 0 on error.
+ */
+ssize_t region_eraseat(rhandle_t rh, offset_t offset, size_t count);
+
+/*
+ * Map subregion described by offset and size within the region provided.
+ * Returns pointer to mapped subregion or NULL on error.
+ */
+void *region_mmap(rhandle_t rh, offset_t offset, size_t count);
+
+/* Unmap previously mapped region. */
+void region_munmap(rhandle_t rh, void *addr);
+
+/* Get size of region represented by rh. < 0 on error. */
+ssize_t region_size(rhandle_t rh);
+
+#endif /* REGION_H */
diff --git a/src/include/rmodule.h b/src/include/rmodule.h
index 2147ab0..19f32e4 100644
--- a/src/include/rmodule.h
+++ b/src/include/rmodule.h
@@ -61,6 +61,7 @@ int rmodule_calc_region(unsigned int region_alignment, size_t rmodule_size,
#if CONFIG_DYNAMIC_CBMEM
struct cbfs_stage;
struct cbmem_entry;
+struct cbfs_descriptor;
struct rmod_stage_load {
/* Inputs */
@@ -72,8 +73,10 @@ struct rmod_stage_load {
};
/* Both of the following functions return 0 on success, -1 on error. */
-int rmodule_stage_load(struct rmod_stage_load *rsl, struct cbfs_stage *stage);
-int rmodule_stage_load_from_cbfs(struct rmod_stage_load *rsl);
+int rmodule_stage_load(struct rmod_stage_load *rsl, struct cbfs_stage *stage,
+ void *data);
+int rmodule_stage_load_from_cbfs(const struct cbfs_descriptor *cbfs,
+ struct rmod_stage_load *rsl);
#endif
struct rmodule {
diff --git a/src/lib/Makefile.inc b/src/lib/Makefile.inc
index acd334e..052dc9f 100644
--- a/src/lib/Makefile.inc
+++ b/src/lib/Makefile.inc
@@ -18,7 +18,9 @@
#
subdirs-y += loaders
+ifneq ($(CONFIG_ARCH_X86),y)
bootblock-y += cbfs.c
+endif
ifneq ($(CONFIG_HAVE_ARCH_MEMSET),y)
bootblock-y += memset.c
endif
@@ -109,6 +111,13 @@ ramstage-y += cbmem_info.c
ramstage-y += hexdump.c
romstage-y += hexdump.c
+ramstage-y += region.c
+romstage-y += region.c
+ramstage-y += cbfs_boot_region.c
+romstage-y += cbfs_boot_region.c
+smm-y += cbfs_boot_region.c
+ramstage-$(CONFIG_BOOT_REGION_SPI_FLASH) += bootrw_spi_flash_region.c
+smm-$(CONFIG_BOOT_REGION_SPI_FLASH) += bootrw_spi_flash_region.c
ramstage-$(CONFIG_REG_SCRIPT) += reg_script.c
@@ -125,6 +134,7 @@ smm-y += memmove.c
endif
smm-y += cbfs.c memcmp.c
smm-y += gcc.c
+smm-y += region.c
$(obj)/lib/version.ramstage.o : $(obj)/build.h
diff --git a/src/lib/bootrw_spi_flash_region.c b/src/lib/bootrw_spi_flash_region.c
new file mode 100644
index 0000000..2ef8e75
--- /dev/null
+++ b/src/lib/bootrw_spi_flash_region.c
@@ -0,0 +1,119 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2014 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+
+#include <stddef.h>
+#include <region.h>
+#include <spi-generic.h>
+#include <spi_flash.h>
+
+struct bootrw_flash_device {
+ struct spi_flash *spi;
+ struct region_device dev;
+};
+
+
+static ssize_t
+bootrw_readat(const struct region_device *rdev, void *buf,
+ offset_t offset, size_t size)
+{
+ struct bootrw_flash_device *dev;
+
+ dev = container_of(rdev, struct bootrw_flash_device, dev);
+ if (dev->spi->read(dev->spi, offset, size, buf))
+ return -1;
+ return size;
+}
+
+static ssize_t
+bootrw_writeat(const struct region_device *rdev, const void *buf,
+ offset_t offset, size_t size)
+{
+ struct bootrw_flash_device *dev;
+
+ dev = container_of(rdev, struct bootrw_flash_device, dev);
+ if (dev->spi->write(dev->spi, offset, size, buf))
+ return -1;
+ return size;
+}
+
+static ssize_t
+bootrw_eraseat(const struct region_device *rdev, offset_t offset, size_t size)
+{
+ struct bootrw_flash_device *dev;
+
+ dev = container_of(rdev, struct bootrw_flash_device, dev);
+ if (dev->spi->erase(dev->spi, offset, size))
+ return -1;
+ return size;
+}
+
+static const struct region_device_ops bootrw_ops = {
+ .readat = bootrw_readat,
+ .writeat = bootrw_writeat,
+ .eraseat = bootrw_eraseat,
+};
+
+static struct bootrw_flash_device flashdev = {
+ .dev = {
+ .ops = &bootrw_ops,
+ .region = {
+ .offset = 0,
+ .size = CONFIG_ROM_SIZE,
+ },
+ }
+};
+
+void bootrw_media_initialize(void)
+{
+ /* Reinitialize spi regs in case. */
+ spi_init();
+
+ if (flashdev.spi != NULL)
+ return;
+
+ flashdev.spi = spi_flash_probe(0, 0, 0, 0);
+ if (flashdev.spi == NULL) {
+ printk(BIOS_WARNING, "SPI probing failed for boot region.\n");
+ return;
+ }
+
+ if (flashdev.spi->size != CONFIG_ROM_SIZE) {
+ printk(BIOS_WARNING,
+ "SPI mismatch with CONFIG_ROM_SIZE: %zx vs %zx\n",
+ (size_t)CONFIG_ROM_SIZE, (size_t)flashdev.spi->size);
+ return;
+ }
+
+ if (!rhandle_valid(region_register(BOOTRW_REGION_NAME, &flashdev.dev)))
+ printk(BIOS_WARNING, "Couldn't register '%s' region.\n",
+ BOOTRW_REGION_NAME);
+}
+
+#if !defined(__PRE_RAM__)
+#include <bootstate.h>
+static void bootrw_bscb(void *unused)
+{
+ bootrw_media_initialize();
+}
+
+BOOT_STATE_INIT_ENTRIES(regions_init) = {
+ BOOT_STATE_INIT_ENTRY(BS_DEV_INIT, BS_ON_ENTRY, bootrw_bscb, NULL),
+};
+#endif
diff --git a/src/lib/cbfs.c b/src/lib/cbfs.c
index dc08937..f5dff88 100644
--- a/src/lib/cbfs.c
+++ b/src/lib/cbfs.c
@@ -1,8 +1,7 @@
/*
* This file is part of the coreboot project.
*
- * Copyright (C) 2008, Jordan Crouse <jordan at cosmicpenguin.net>
- * Copyright (C) 2013 The Chromium OS Authors. All rights reserved.
+ * Copyright (C) 2014-2014 Google Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -18,192 +17,402 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
*/
-#ifdef LIBPAYLOAD
-# include <libpayload-config.h>
-# ifdef CONFIG_LZMA
-# include <lzma.h>
-# define CBFS_CORE_WITH_LZMA
-# endif
-# define CBFS_MINI_BUILD
-#elif defined(__SMM__)
-# define CBFS_MINI_BUILD
-#elif defined(__BOOT_BLOCK__)
- /* No LZMA in boot block. */
-#elif defined(__PRE_RAM__) && !CONFIG_COMPRESS_RAMSTAGE
- /* No LZMA in romstage if ramstage is not compressed. */
-#else
-# define CBFS_CORE_WITH_LZMA
-# include <lib.h>
+#if !defined(__BOOT_BLOCK__) && !(defined(__PRE_RAM__) && !IS_ENABLED(CONFIG_COMPRESS_RAMSTAGE))
+#define CBFS_WITH_LZMA
#endif
-#include <cbfs.h>
#include <string.h>
+#include <arch/early_variables.h>
+#include <cbfs.h>
+#include <cbfs_core.h>
#include <cbmem.h>
+#include <console/console.h>
+#include <lib.h>
-#ifdef LIBPAYLOAD
-# include <stdio.h>
-# define DEBUG(x...)
-# define LOG(x...) printf(x)
-# define ERROR(x...) printf(x)
-#else
-# include <console/console.h>
-# define ERROR(x...) printk(BIOS_ERR, "CBFS: " x)
-# define LOG(x...) printk(BIOS_INFO, "CBFS: " x)
-# if CONFIG_DEBUG_CBFS
-# define DEBUG(x...) printk(BIOS_SPEW, "CBFS: " x)
-# else
-# define DEBUG(x...)
-# endif
-#endif
+struct cbfs_file_descriptor {
+ rhandle_t rh;
+ struct region metadata;
+ struct region content;
+};
-#if defined(CONFIG_CBFS_HEADER_ROM_OFFSET) && (CONFIG_CBFS_HEADER_ROM_OFFSET)
-# define CBFS_HEADER_ROM_ADDRESS (CONFIG_CBFS_HEADER_ROM_OFFSET)
-#else
-// Indirect address: only works on 32bit top-aligned systems.
-# define CBFS_HEADER_ROM_ADDRESS (*(uint32_t *)0xfffffffc)
-#endif
+#define MAX_CBFS_OPEN_FILES 4
+struct cbfs_file_cache {
+ struct cbfs_file_descriptor files[MAX_CBFS_OPEN_FILES];
+};
-#include "cbfs_core.c"
+static struct cbfs_file_cache g_cbfs_files CAR_GLOBAL;
-#ifndef __SMM__
-static inline int tohex4(unsigned int c)
+static struct cbfs_file_cache *get_cache(void)
+{
+ return car_get_var_ptr(&g_cbfs_files);
+}
+
+static int cbfs_fd_available(const struct cbfs_file_descriptor *fd)
+{
+ return !!(fd->content.size == 0 && fd->metadata.size == 0);
+}
+
+static void cbfs_fd_mark_free(const struct cbfs_file_descriptor *cfd)
{
- return (c <= 9) ? (c + '0') : (c - 10 + 'a');
+ struct cbfs_file_descriptor *fd = (struct cbfs_file_descriptor *)cfd;
+ memset(fd, 0, sizeof(*fd));
+ fd->rh = INVALID_RHANDLE;
}
-static void tohex16(unsigned int val, char* dest)
+static struct cbfs_file_descriptor *get_available_file(void)
{
- dest[0] = tohex4(val>>12);
- dest[1] = tohex4((val>>8) & 0xf);
- dest[2] = tohex4((val>>4) & 0xf);
- dest[3] = tohex4(val & 0xf);
+ int i;
+ struct cbfs_file_cache *cache = get_cache();
+
+ for (i = 0; i < MAX_CBFS_OPEN_FILES; i++) {
+ if (cbfs_fd_available(&cache->files[i]))
+ return &cache->files[i];
+ }
+
+ return NULL;
}
-void *cbfs_load_optionrom(struct cbfs_media *media, uint16_t vendor,
- uint16_t device, void *dest)
+static void cbfs_fd_add_metadata(struct cbfs_file_descriptor *fd, size_t sz)
{
- char name[17] = "pciXXXX,XXXX.rom";
- struct cbfs_optionrom *orom;
- uint8_t *src;
+ fd->metadata.size += sz;
+ fd->content.offset += sz;
+ fd->content.size -= sz;
+}
- tohex16(vendor, name+3);
- tohex16(device, name+8);
+static const struct cbfs_file_descriptor *
+allocate_file(const struct cbfs_descriptor *cbfs, const struct cbfs_file *file,
+ offset_t offset)
+{
+ struct cbfs_file_descriptor *fd;
+ offset_t file_end;
- orom = (struct cbfs_optionrom *)
- cbfs_get_file_content(media, name, CBFS_TYPE_OPTIONROM, NULL);
+ fd = get_available_file();
- if (orom == NULL)
+ if (fd == NULL) {
+ printk(BIOS_DEBUG, "No available cbfs fds!\n");
return NULL;
+ }
- /* They might have specified a dest address. If so, we can decompress.
- * If not, there's not much hope of decompressing or relocating the rom.
- * in the common case, the expansion rom is uncompressed, we
- * pass 0 in for the dest, and all we have to do is find the rom and
- * return a pointer to it.
- */
+ /* Point offset to beginning of file data. */
+ offset = file->offset + offset;
+ file_end = offset + file->len;
- /* BUG: the cbfstool is (not yet) including a cbfs_optionrom header */
- src = (uint8_t *)orom; // + sizeof(struct cbfs_optionrom);
+ fd->rh = cbfs->rh;
+ fd->metadata.offset = offset;
+ fd->metadata.size = 0;
+ fd->content.offset = offset;
+ fd->content.size = file->len;
- if (! dest)
- return src;
+ if (file->type != CBFS_TYPE_STAGE && file->type != CBFS_TYPE_PAYLOAD)
+ return fd;
+
+ if (file->type == CBFS_TYPE_STAGE) {
+ cbfs_fd_add_metadata(fd, sizeof(struct cbfs_stage));
+ return fd;
+ }
+
+ /* Parse payload segments. */
+ while (offset + sizeof(struct cbfs_payload_segment) <= file_end) {
+ struct cbfs_payload_segment segment;
+ ssize_t read_sz;
+
+ read_sz = region_readat(cbfs->rh, &segment, offset,
+ sizeof(segment));
+ if (read_sz != sizeof(segment)) {
+ printk(BIOS_DEBUG, "Couldn't read segment at 0x%zx\n",
+ (size_t)offset);
+ cbfs_fd_mark_free(fd);
+ return NULL;
+ }
+
+ switch (segment.type) {
+ case PAYLOAD_SEGMENT_CODE:
+ case PAYLOAD_SEGMENT_DATA:
+ case PAYLOAD_SEGMENT_BSS:
+ case PAYLOAD_SEGMENT_PARAMS:
+ cbfs_fd_add_metadata(fd, sizeof(segment));
+ break;
+ case PAYLOAD_SEGMENT_ENTRY:
+ cbfs_fd_add_metadata(fd, sizeof(segment));
+ return fd;
+ default:
+ cbfs_fd_mark_free(fd);
+ return NULL;
+ }
+
+ /* Next segment. */
+ offset += sizeof(segment);
+ }
- if (!cbfs_decompress(ntohl(orom->compression),
- src,
- dest,
- ntohl(orom->len)))
+ cbfs_fd_mark_free(fd);
+ return NULL;
+}
+
+static offset_t
+cbfs_next_offset(offset_t offset, size_t align, size_t increment)
+{
+ offset += increment;
+ if (offset % align)
+ offset += align - (offset % align);
+ return offset;
+}
+
+static const struct cbfs_file_descriptor *
+__cbfs_open(const struct cbfs_descriptor *cbfs, const char *name,
+ uint32_t *type)
+{
+ const struct cbfs_file_descriptor *fd;
+ struct cbfs_file file;
+ ssize_t read_sz;
+ offset_t offset;
+ size_t cbfs_sz;
+ size_t align;
+ rhandle_t rh;
+
+ if (cbfs == NULL || name == NULL)
return NULL;
- return dest;
+ offset = 0;
+ rh = cbfs->rh;
+ align = cbfs->align;
+ cbfs_sz = cbfs->size;
+ fd = NULL;
+
+ while (offset + sizeof(file) < cbfs_sz) {
+ char *file_name;
+ size_t name_sz;
+ size_t entry_sz;
+ int found;
+
+ read_sz = region_readat(rh, &file, offset, sizeof(file));
+ if (read_sz != sizeof(file))
+ return NULL;
+
+ if (memcmp(CBFS_FILE_MAGIC, file.magic, sizeof(file.magic))) {
+ offset = cbfs_next_offset(offset, align, align);
+ continue;
+ }
+
+ file.len = ntohl(file.len);
+ file.type = ntohl(file.type);
+ file.offset = ntohl(file.offset);
+ entry_sz = file.len + file.offset;
+
+ /* File type doesn't match. */
+ if (type != NULL && *type != file.type) {
+ offset = cbfs_next_offset(offset, align, entry_sz);
+ continue;
+ }
+ name_sz = file.offset - sizeof(file);
+ file_name = region_mmap(rh, offset + sizeof(file), name_sz);
+ if (file_name == NULL) {
+ offset = cbfs_next_offset(offset, align, entry_sz);
+ continue;
+ }
+
+ found = !strcmp(file_name, name);
+ region_munmap(rh, file_name);
+
+ if (found) {
+ fd = allocate_file(cbfs, &file, offset);
+ break;
+ }
+ offset = cbfs_next_offset(offset, align, entry_sz);
+ }
+
+ return fd;
}
-void * cbfs_load_stage(struct cbfs_media *media, const char *name)
+const struct cbfs_file_descriptor *
+cbfs_open_by_name(const struct cbfs_descriptor *cbfs, const char *name)
{
- struct cbfs_stage *stage = (struct cbfs_stage *)
- cbfs_get_file_content(media, name, CBFS_TYPE_STAGE, NULL);
- /* this is a mess. There is no ntohll. */
- /* for now, assume compatible byte order until we solve this. */
- uint32_t entry;
- uint32_t final_size;
+ return __cbfs_open(cbfs, name, NULL);
+}
- if (stage == NULL)
- return (void *) -1;
+const struct cbfs_file_descriptor *
+cbfs_open_by_name_type(const struct cbfs_descriptor *cbfs,
+ const char *name, uint32_t type)
+{
+ return __cbfs_open(cbfs, name, &type);
+}
- LOG("loading stage %s @ 0x%x (%d bytes), entry @ 0x%llx\n",
- name,
- (uint32_t) stage->load, stage->memlen,
- stage->entry);
+void cbfs_file_close(const struct cbfs_file_descriptor *file)
+{
+ if (file != NULL)
+ cbfs_fd_mark_free(file);
+}
- final_size = cbfs_decompress(stage->compression,
- ((unsigned char *) stage) +
- sizeof(struct cbfs_stage),
- (void *) (uint32_t) stage->load,
- stage->len);
- if (!final_size)
- return (void *) -1;
+ssize_t cbfs_file_content_size(const struct cbfs_file_descriptor *fd)
+{
+ if (fd == NULL)
+ return -1;
- /* Stages rely the below clearing so that the bss is initialized. */
- memset((void *)((uintptr_t)stage->load + final_size), 0,
- stage->memlen - final_size);
+ return fd->content.size;
+}
- DEBUG("stage loaded.\n");
+ssize_t cbfs_file_metadata_size(const struct cbfs_file_descriptor *fd)
+{
+ if (fd == NULL)
+ return -1;
- entry = stage->entry;
- // entry = ntohll(stage->entry);
+ return fd->metadata.size;
+}
- return (void *) entry;
+ssize_t cbfs_file_read_content(const struct cbfs_file_descriptor *fd,
+ void *buf, offset_t offset, size_t size)
+{
+ struct region region = {
+ .offset = offset,
+ .size = size,
+ };
+
+ if (fd == NULL)
+ return -1;
+
+ if (region_request_normalize(&fd->content, ®ion))
+ return -1;
+
+ return region_readat(fd->rh, buf, region.offset, size);
}
-/* Simple buffer */
+void *cbfs_file_map_content(const struct cbfs_file_descriptor *fd,
+ offset_t offset, size_t size)
+{
+ struct region region = {
+ .offset = offset,
+ .size = size,
+ };
-void *cbfs_simple_buffer_map(struct cbfs_simple_buffer *buffer,
- struct cbfs_media *media,
- size_t offset, size_t count) {
- void *address = buffer->buffer + buffer->allocated;
- DEBUG("simple_buffer_map(offset=%zd, count=%zd): "
- "allocated=%zd, size=%zd, last_allocate=%zd\n",
- offset, count, buffer->allocated, buffer->size,
- buffer->last_allocate);
- if (buffer->allocated + count >= buffer->size)
- return CBFS_MEDIA_INVALID_MAP_ADDRESS;
- if (media->read(media, address, offset, count) != count) {
- ERROR("simple_buffer: fail to read %zd bytes from 0x%zx\n",
- count, offset);
- return CBFS_MEDIA_INVALID_MAP_ADDRESS;
- }
- buffer->allocated += count;
- buffer->last_allocate = count;
- return address;
-}
-
-void *cbfs_simple_buffer_unmap(struct cbfs_simple_buffer *buffer,
- const void *address) {
- // TODO Add simple buffer management so we can free more than last
- // allocated one.
- DEBUG("simple_buffer_unmap(address=0x%p): "
- "allocated=%zd, size=%zd, last_allocate=%zd\n",
- address, buffer->allocated, buffer->size,
- buffer->last_allocate);
- if ((buffer->buffer + buffer->allocated - buffer->last_allocate) ==
- address) {
- buffer->allocated -= buffer->last_allocate;
- buffer->last_allocate = 0;
- }
- return NULL;
+ if (fd == NULL)
+ return NULL;
+
+ if (region_request_normalize(&fd->content, ®ion))
+ return NULL;
+
+ return region_mmap(fd->rh, region.offset, size);
}
-/**
- * run_address is passed the address of a function taking no parameters and
- * jumps to it, returning the result.
- * @param f the address to call as a function.
- * @return value returned by the function.
- */
+ssize_t cbfs_file_read_metadata(const struct cbfs_file_descriptor *fd,
+ void *buf, offset_t offset, size_t size)
+{
+ struct region region = {
+ .offset = offset,
+ .size = size,
+ };
+
+ if (fd == NULL)
+ return -1;
+
+ if (region_request_normalize(&fd->metadata, ®ion))
+ return -1;
+
+ return region_readat(fd->rh, buf, region.offset, size);
+}
+
+void *cbfs_file_map_metadata(const struct cbfs_file_descriptor *fd)
+{
+ if (fd == NULL)
+ return NULL;
+
+ return region_mmap(fd->rh, fd->metadata.offset, fd->metadata.size);
+}
+
+void cbfs_file_unmap(const struct cbfs_file_descriptor *fd, void *addr)
+{
+ if (fd == NULL)
+ return;
+
+ region_munmap(fd->rh, addr);
+}
-int run_address(void *f)
+#ifndef __SMM__
+size_t cbfs_file_inflate(const struct cbfs_file_descriptor *fd,
+ offset_t offset, size_t src_sz, void *dest)
{
- int (*v) (void);
- v = f;
- return v();
+#if defined(CBFS_WITH_LZMA)
+ void *src;
+ size_t dest_sz;
+
+ src = cbfs_file_map_content(fd, offset, src_sz);
+
+ if (src == NULL)
+ return 0;
+
+ dest_sz = ulzma(src, dest);
+
+ cbfs_file_unmap(fd, src);
+
+ return dest_sz;
+#else
+ return 0;
+#endif
}
+void *cbfs_load_stage(const struct cbfs_descriptor *cbfs, const char *name)
+{
+ struct cbfs_stage stage;
+ const struct cbfs_file_descriptor *file;
+ size_t inflated_sz;
+ ssize_t metadata_sz;
+ ssize_t file_sz;
+ uint8_t *dest;
+ void *entry;
+
+ entry = NULL;
+ file = cbfs_open_by_name_type(cbfs, name, CBFS_TYPE_STAGE);
+
+ if (file == NULL)
+ return NULL;
+
+ metadata_sz = cbfs_file_read_metadata(file, &stage, 0, sizeof(stage));
+ if (metadata_sz != sizeof(stage))
+ goto out;
+
+ file_sz = cbfs_file_content_size(file);
+ if (file_sz < 0)
+ goto out;
+
+ printk(BIOS_INFO,
+ "Loading stage '%s' 0x%llx (%d bytes), entry point 0x%llx\n",
+ name, (long long) stage.load, stage.memlen,
+ (long long)stage.entry);
+
+ dest = (void *)(uintptr_t)stage.load;
+ inflated_sz = stage.memlen;
+
+ switch (stage.compression) {
+ case CBFS_COMPRESS_NONE:
+ if (cbfs_file_read_content(file, dest, 0, file_sz) != file_sz)
+ goto out;
+ break;
+#if defined(CBFS_WITH_LZMA)
+ case CBFS_COMPRESS_LZMA:
+ inflated_sz = cbfs_file_inflate(file, 0, file_sz, dest);
+ if (inflated_sz == 0)
+ goto out;
+ break;
+#endif
+ default:
+ printk(BIOS_ERR,"Invalid compression scheme: %d\n",
+ stage.compression);
+ goto out;
+ }
+
+ if (inflated_sz > stage.memlen) {
+ printk(BIOS_ERR,"Inflated size %zu > memory size %zu.\n",
+ inflated_sz, (size_t)stage.memlen);
+ goto out;
+ }
+
+ /* Stages rely the below clearing so that the bss is initialized. */
+ memset(dest + inflated_sz, 0, stage.memlen - inflated_sz);
+
+ printk(BIOS_DEBUG,"stage loaded.\n");
+
+ entry = (void *)(uintptr_t)stage.entry;
+
+out:
+ cbfs_file_close(file);
+ return entry;
+}
#endif
diff --git a/src/lib/cbfs_boot_region.c b/src/lib/cbfs_boot_region.c
new file mode 100644
index 0000000..6ab12f7
--- /dev/null
+++ b/src/lib/cbfs_boot_region.c
@@ -0,0 +1,133 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2014 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdint.h>
+#include <arch/early_variables.h>
+#include <arch/byteorder.h>
+#include <console/console.h>
+#include <cbfs.h>
+#include <cbfs_core.h>
+#include <region.h>
+
+static struct cbfs_descriptor g_cbfs_descriptor CAR_GLOBAL;
+
+const struct cbfs_descriptor *cbfs_default_descriptor(void)
+{
+ return car_get_var_ptr(&g_cbfs_descriptor);
+}
+
+static const struct region_device cbfs_dev = {
+ .region = {
+ .offset = CONFIG_ROM_SIZE - CONFIG_CBFS_SIZE,
+ .size = CONFIG_CBFS_SIZE,
+ },
+};
+
+#if IS_ENABLED(CONFIG_ARCH_X86)
+static offset_t get_header_offset(rhandle_t rh)
+{
+ int32_t header_offset;
+ offset_t off;
+ ssize_t rsize;
+
+ rsize = region_size(rh);
+ off = rsize - sizeof(header_offset);
+ region_readat(rh, &header_offset, off, sizeof(header_offset));
+ return rsize + header_offset;
+}
+#else
+static inline offset_t get_header_offset(rhandle_t rh)
+{
+ return CONFIG_CBFS_HEADER_ROM_OFFSET;
+}
+#endif
+
+void cbfs_default_media_initialize(void)
+{
+ rhandle_t rh;
+ offset_t header_offset;
+ struct cbfs_header *hdr;
+ size_t cbfs_size;
+ struct cbfs_descriptor *cbfs_desc;
+
+ /* Already initialized. */
+ rh = region_locate(DEFAULT_CBFS_REGION_NAME);
+ if (rhandle_valid(rh))
+ return;
+
+ /* Mark region as invalid. */
+ cbfs_desc = (struct cbfs_descriptor *)cbfs_default_descriptor();
+ cbfs_desc->rh = INVALID_RHANDLE;
+
+ /* CBFS provides a readonly view of the rom. */
+ rh = region_locate(BOOTRO_REGION_NAME);
+
+ if (!rhandle_valid(rh)) {
+ printk(BIOS_ERR, "Boot region not found to register cbfs.\n");
+ return;
+ }
+
+ header_offset = get_header_offset(rh);
+ hdr = region_mmap(rh, header_offset, sizeof(*hdr));
+
+ if (hdr == NULL) {
+ printk(BIOS_ERR, "Couldn't mmap() cbfs header.\n");
+ return;
+ }
+
+ if (CBFS_HEADER_MAGIC != ntohl(hdr->magic)) {
+ printk(BIOS_ERR, "Invalid CBFS magic @ 0x%zx: %x vs %x\n",
+ (size_t)header_offset, CBFS_HEADER_MAGIC,
+ ntohl(hdr->magic));
+ goto out;
+ }
+
+ if (cbfs_dev.region.offset != ntohl(hdr->offset)) {
+ printk(BIOS_ERR, "CBFS offset doesn't match: 0x%zx vs 0x%zx\n",
+ (size_t)cbfs_dev.region.offset,
+ (size_t)ntohl(hdr->offset));
+ goto out;
+ }
+
+ cbfs_size = ntohl(hdr->romsize) - ntohl(hdr->offset);
+
+ if (cbfs_dev.region.size != cbfs_size) {
+ printk(BIOS_ERR, "CBFS size doesn't match: 0x%zx vs 0x%zx\n",
+ cbfs_dev.region.size, cbfs_size);
+ goto out;
+ }
+
+#if IS_ENABLED(CONFIG_ARCH_X86)
+ cbfs_size -= htonl(hdr->bootblocksize);
+#endif
+
+ cbfs_desc->align = ntohl(hdr->align);
+ cbfs_desc->size = cbfs_size;
+
+ printk(BIOS_DEBUG, "%s: CBFS align 0x%zx size 0x%zx\n", __func__,
+ cbfs_desc->align, cbfs_desc->size);
+
+ cbfs_desc->rh = region_register_subregion(DEFAULT_CBFS_REGION_NAME,
+ &cbfs_dev, rh);
+ if (!rhandle_valid(cbfs_desc->rh))
+ printk(BIOS_ERR, "Unable to register default CBFS region.\n");
+
+out:
+ region_munmap(rh, hdr);
+}
diff --git a/src/lib/cbfs_core.c b/src/lib/cbfs_core.c
deleted file mode 100644
index 50c037e..0000000
--- a/src/lib/cbfs_core.c
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * This file is part of the coreboot project.
- *
- * Copyright (C) 2011 secunet Security Networks AG
- * Copyright (C) 2013 The Chromium OS Authors. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-/* The CBFS core requires a couple of #defines or functions to adapt it to the
- * target environment:
- *
- * CBFS_CORE_WITH_LZMA (must be #define)
- * if defined, ulzma() must exist for decompression of data streams
- *
- * CBFS_HEADER_ROM_ADDRESS
- * ROM address (offset) of CBFS header. Underlying CBFS media may interpret
- * it in other way so we call this "address".
- *
- * ERROR(x...)
- * print an error message x (in printf format)
- *
- * LOG(x...)
- * print a message x (in printf format)
- *
- * DEBUG(x...)
- * print a debug message x (in printf format)
- *
- */
-
-#include <cbfs.h>
-#include <string.h>
-
-/* returns a pointer to CBFS master header, or CBFS_HEADER_INVALID_ADDRESS
- * on failure */
-const struct cbfs_header *cbfs_get_header(struct cbfs_media *media)
-{
- const struct cbfs_header *header;
- struct cbfs_media default_media;
-
- if (media == CBFS_DEFAULT_MEDIA) {
- media = &default_media;
- if (init_default_cbfs_media(media) != 0) {
- ERROR("Failed to initialize default media.\n");
- return CBFS_HEADER_INVALID_ADDRESS;
- }
- }
-
- media->open(media);
- DEBUG("CBFS_HEADER_ROM_ADDRESS: 0x%x/0x%x\n", CBFS_HEADER_ROM_ADDRESS,
- CONFIG_ROM_SIZE);
- header = media->map(media, CBFS_HEADER_ROM_ADDRESS, sizeof(*header));
- media->close(media);
-
- if (header == CBFS_MEDIA_INVALID_MAP_ADDRESS) {
- ERROR("Failed to load CBFS header from 0x%x\n",
- CBFS_HEADER_ROM_ADDRESS);
- return CBFS_HEADER_INVALID_ADDRESS;
- }
-
- if (CBFS_HEADER_MAGIC != ntohl(header->magic)) {
- ERROR("Could not find valid CBFS master header at %x: "
- "%x vs %x.\n", CBFS_HEADER_ROM_ADDRESS, CBFS_HEADER_MAGIC,
- ntohl(header->magic));
- if (header->magic == 0xffffffff) {
- ERROR("Maybe ROM is not mapped properly?\n");
- }
- return CBFS_HEADER_INVALID_ADDRESS;
- }
- return header;
-}
-
-/* public API starts here*/
-struct cbfs_file *cbfs_get_file(struct cbfs_media *media, const char *name)
-{
- const char *file_name;
- uint32_t offset, align, romsize, name_len;
- const struct cbfs_header *header;
- struct cbfs_file file, *file_ptr;
- struct cbfs_media default_media;
-
- if (media == CBFS_DEFAULT_MEDIA) {
- media = &default_media;
- if (init_default_cbfs_media(media) != 0) {
- ERROR("Failed to initialize default media.\n");
- return NULL;
- }
- }
-
- if (CBFS_HEADER_INVALID_ADDRESS == (header = cbfs_get_header(media)))
- return NULL;
-
- // Logical offset (for source media) of first file.
- offset = ntohl(header->offset);
- align = ntohl(header->align);
- romsize = ntohl(header->romsize);
-
- // TODO Add a "size" in CBFS header for a platform independent way to
- // determine the end of CBFS data.
-#if defined(CONFIG_ARCH_X86) && CONFIG_ARCH_X86
- romsize -= htonl(header->bootblocksize);
-#endif
- DEBUG("CBFS location: 0x%x~0x%x, align: %d\n", offset, romsize, align);
-
- DEBUG("Looking for '%s' starting from 0x%x.\n", name, offset);
- media->open(media);
- while (offset < romsize &&
- media->read(media, &file, offset, sizeof(file)) == sizeof(file)) {
- if (memcmp(CBFS_FILE_MAGIC, file.magic,
- sizeof(file.magic)) != 0) {
- uint32_t new_align = align;
- if (offset % align)
- new_align += align - (offset % align);
- ERROR("ERROR: No file header found at 0x%x - "
- "try next aligned address: 0x%x.\n", offset,
- offset + new_align);
- offset += new_align;
- continue;
- }
- name_len = ntohl(file.offset) - sizeof(file);
- DEBUG(" - load entry 0x%x file name (%d bytes)...\n", offset,
- name_len);
-
- // load file name (arbitrary length).
- file_name = (const char *)media->map(
- media, offset + sizeof(file), name_len);
- if (file_name == CBFS_MEDIA_INVALID_MAP_ADDRESS) {
- ERROR("ERROR: Failed to get filename: 0x%x.\n", offset);
- } else if (strcmp(file_name, name) == 0) {
- int file_offset = ntohl(file.offset),
- file_len = ntohl(file.len);
- DEBUG("Found file (offset=0x%x, len=%d).\n",
- offset + file_offset, file_len);
- media->unmap(media, file_name);
- file_ptr = media->map(media, offset,
- file_offset + file_len);
- media->close(media);
- return file_ptr;
- } else {
- DEBUG(" (unmatched file @0x%x: %s)\n", offset,
- file_name);
- media->unmap(media, file_name);
- }
-
- // Move to next file.
- offset += ntohl(file.len) + ntohl(file.offset);
- if (offset % align)
- offset += align - (offset % align);
- }
- media->close(media);
- LOG("WARNING: '%s' not found.\n", name);
- return NULL;
-}
-
-void *cbfs_get_file_content(struct cbfs_media *media, const char *name,
- int type, size_t *sz)
-{
- struct cbfs_file *file = cbfs_get_file(media, name);
-
- if (sz)
- *sz = 0;
-
- if (file == NULL) {
- ERROR("Could not find file '%s'.\n", name);
- return NULL;
- }
-
- if (ntohl(file->type) != type) {
- ERROR("File '%s' is of type %x, but we requested %x.\n", name,
- ntohl(file->type), type);
- return NULL;
- }
-
- if (sz)
- *sz = ntohl(file->len);
-
- return (void *)CBFS_SUBHEADER(file);
-}
-
-int cbfs_decompress(int algo, void *src, void *dst, int len)
-{
- switch (algo) {
- case CBFS_COMPRESS_NONE:
- /* Reads need to be aligned at 4 bytes to avoid
- poor flash performance. */
- while (len && ((u32)src & 3)) {
- *(u8*)dst++ = *(u8*)src++;
- len--;
- }
- memmove(dst, src, len);
- return len;
-#ifdef CBFS_CORE_WITH_LZMA
- case CBFS_COMPRESS_LZMA:
- return ulzma(src, dst);
-#endif
- default:
- ERROR("tried to decompress %d bytes with algorithm #%x,"
- "but that algorithm id is unsupported.\n", len,
- algo);
- return 0;
- }
-}
-
diff --git a/src/lib/loaders/cbfs_payload_loader.c b/src/lib/loaders/cbfs_payload_loader.c
index 2c1d179..31ad7e6 100644
--- a/src/lib/loaders/cbfs_payload_loader.c
+++ b/src/lib/loaders/cbfs_payload_loader.c
@@ -18,20 +18,30 @@
*/
#include <cbfs.h>
+#include <cbfs_core.h>
#include <payload_loader.h>
static int cbfs_locate_payload(struct payload *payload)
{
void *buffer;
size_t size;
- const int type = CBFS_TYPE_PAYLOAD;
+ const struct cbfs_file_descriptor *fd;
- buffer = cbfs_get_file_content(CBFS_DEFAULT_MEDIA, payload->name,
- type, &size);
+ fd = cbfs_open_by_name_type(cbfs_default_descriptor(), payload->name,
+ CBFS_TYPE_PAYLOAD);
- if (buffer == NULL)
+ if (fd == NULL)
return -1;
+ size = cbfs_file_content_size(fd);
+ buffer = cbfs_file_map_content(fd, 0, size);
+
+ if (buffer == NULL) {
+ cbfs_file_close(fd);
+ return -1;
+ }
+
+ payload->fd = fd;
payload->backing_store.data = buffer;
payload->backing_store.size = size;
diff --git a/src/lib/loaders/cbfs_ramstage_loader.c b/src/lib/loaders/cbfs_ramstage_loader.c
index 5d5cc0b..5d5edd8 100644
--- a/src/lib/loaders/cbfs_ramstage_loader.c
+++ b/src/lib/loaders/cbfs_ramstage_loader.c
@@ -34,7 +34,8 @@ static void *cbfs_load_ramstage(uint32_t cbmem_id, const char *name,
.name = name,
};
- if (rmodule_stage_load_from_cbfs(&rmod_ram)) {
+ if (rmodule_stage_load_from_cbfs(cbfs_default_descriptor(),
+ &rmod_ram)) {
printk(BIOS_DEBUG, "Could not load ramstage.\n");
return NULL;
}
@@ -49,14 +50,7 @@ static void *cbfs_load_ramstage(uint32_t cbmem_id, const char *name,
static void *cbfs_load_ramstage(uint32_t cbmem_id, const char *name,
const struct cbmem_entry **cbmem_entry)
{
- void *entry;
-
- entry = cbfs_load_stage(CBFS_DEFAULT_MEDIA, name);
-
- if ((void *)entry == (void *) -1)
- entry = NULL;
-
- return entry;
+ return cbfs_load_stage(cbfs_default_descriptor(), name);
}
#endif /* CONFIG_RELOCATABLE_RAMSTAGE */
diff --git a/src/lib/loaders/load_and_run_payload.c b/src/lib/loaders/load_and_run_payload.c
index 2204090..ac4e7bf 100644
--- a/src/lib/loaders/load_and_run_payload.c
+++ b/src/lib/loaders/load_and_run_payload.c
@@ -58,9 +58,8 @@ struct payload *payload_load(void)
ops->name);
continue;
}
- printk(BIOS_DEBUG, "%s: located payload @ %p, %zu bytes.\n",
- ops->name, payload->backing_store.data,
- payload->backing_store.size);
+ printk(BIOS_DEBUG, "%s: located payload, %zu bytes.\n",
+ ops->name, payload->backing_store.size);
break;
}
diff --git a/src/lib/region.c b/src/lib/region.c
new file mode 100644
index 0000000..6300b89
--- /dev/null
+++ b/src/lib/region.c
@@ -0,0 +1,305 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2014 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <string.h>
+#include <console/console.h>
+#include <arch/early_variables.h>
+#include <region.h>
+#include <vendorcode/google/chromeos/fmap.h>
+
+/* MAX_REGIONS could be configurable. */
+#define MAX_REGIONS 6
+
+struct region_registry_entry {
+ rhandle_t parent_slot;
+ const char *name;
+ const struct region_device *rdev;
+};
+
+struct region_registry {
+ struct region_registry_entry entries[MAX_REGIONS];
+};
+
+static struct region_registry g_regions CAR_GLOBAL;
+
+static inline struct region_registry *get_registry(void)
+{
+ return car_get_var_ptr(&g_regions);
+}
+
+static const struct region_registry_entry *
+registry_entry_lookup(const struct region_registry *rr, rhandle_t rh)
+{
+ if (rh < 0 || rh >= MAX_REGIONS)
+ return NULL;
+
+ return &rr->entries[rh];
+}
+
+static int region_enclosed(const struct region *parent,
+ const struct region *child)
+{
+ offset_t parent_end;
+ offset_t child_end;
+
+ child_end = child->offset + child->size;
+ parent_end = parent->offset + parent->size;
+
+ if (child->size > parent->size)
+ return -1;
+
+ if (child->offset >= parent->offset && child_end <= parent_end)
+ return 0;
+
+ return -1;
+}
+
+int region_request_normalize(const struct region *parent,
+ struct region *request)
+{
+ request->offset += parent->offset;
+ return region_enclosed(parent, request);
+}
+
+static rhandle_t __region_register(struct region_registry *rr, const char *name,
+ const struct region_device *rdev,
+ rhandle_t parent)
+{
+ rhandle_t slot;
+
+ for (slot = 0; slot < MAX_REGIONS; slot++) {
+ struct region_registry_entry *entry = &rr->entries[slot];
+
+ /* Find an empty slot. */
+ if (entry->rdev != NULL)
+ continue;
+
+ entry->parent_slot = parent;
+ entry->name = name;
+ entry->rdev = rdev;
+ printk(BIOS_DEBUG,
+ "Region '%s' registered: slot %u, %zu @ 0x%zx.\n",
+ name, (unsigned int)slot, rdev->region.size,
+ (size_t)rdev->region.offset);
+ return slot;
+ }
+
+ return INVALID_RHANDLE;
+}
+
+rhandle_t region_register(const char *name, const struct region_device *rdev)
+{
+ if (name == NULL || rdev == NULL || rdev->ops == NULL)
+ return INVALID_RHANDLE;
+
+ return __region_register(get_registry(), name, rdev, INVALID_RHANDLE);
+}
+
+rhandle_t region_register_subregion(const char *name,
+ const struct region_device *rdev,
+ rhandle_t parent)
+{
+ struct region_registry *rr;
+ const struct region_registry_entry *pentry;
+
+ /* Subregions require NULL ops. */
+ if (name == NULL || rdev == NULL || rdev->ops != NULL)
+ return INVALID_RHANDLE;
+
+ rr = get_registry();
+
+ /* Parent is invalid. */
+ pentry = registry_entry_lookup(rr, parent);
+ if (pentry == NULL)
+ return INVALID_RHANDLE;
+
+ /* Ensure subregion is within bounds. */
+ if (region_enclosed(&pentry->rdev->region, &rdev->region))
+ return INVALID_RHANDLE;
+
+ return __region_register(rr, name, rdev, parent);
+}
+
+/* Locate a region of provided name. */
+rhandle_t region_locate(const char *name)
+{
+ rhandle_t slot;
+ struct region_registry *rr;
+
+ if (name == NULL)
+ return INVALID_RHANDLE;
+
+ rr = get_registry();
+
+ for (slot = 0; slot < MAX_REGIONS; slot++) {
+ const struct region_registry_entry *entry = &rr->entries[slot];
+
+ /* No more valid entries. */
+ if (entry->rdev == NULL)
+ break;
+
+ if (!strcmp(entry->name, name))
+ return slot;
+ }
+ return INVALID_RHANDLE;
+}
+
+/*
+ * Obtain the appropriate region_device while optionally translating the
+ * region into the parent's domain.
+ */
+static const struct region_device *
+find_parent(rhandle_t rh, struct region *region)
+{
+ const struct region_registry_entry *entry;
+ struct region_registry *rr;
+
+ rr = get_registry();
+ entry = registry_entry_lookup(rr, rh);
+
+ if (entry == NULL)
+ return NULL;
+
+ if (region != NULL &&
+ region_request_normalize(&entry->rdev->region, region))
+ return NULL;
+
+ while (entry->rdev->ops == NULL) {
+ entry = &rr->entries[entry->parent_slot];
+ /* Translate the region into the parent's view. */
+ if (region != NULL)
+ region->offset += entry->rdev->region.offset;
+ }
+
+ return entry->rdev;
+}
+
+ssize_t region_readat(rhandle_t rh, void *buf, offset_t offset, size_t count)
+{
+ const struct region_device *rdev;
+ struct region region = {
+ .offset = offset,
+ .size = count,
+ };
+
+ rdev = find_parent(rh, ®ion);
+
+ if (rdev == NULL || rdev->ops->readat == NULL)
+ return -1;
+
+ return rdev->ops->readat(rdev, buf, region.offset, region.size);
+}
+
+ssize_t region_writeat(rhandle_t rh, void *buf, offset_t offset, size_t count)
+{
+ const struct region_device *rdev;
+ struct region region = {
+ .offset = offset,
+ .size = count,
+ };
+
+ rdev = find_parent(rh, ®ion);
+
+ if (rdev == NULL || rdev->ops->writeat == NULL)
+ return -1;
+
+ return rdev->ops->writeat(rdev, buf, region.offset, region.size);
+}
+
+ssize_t region_eraseat(rhandle_t rh, offset_t offset, size_t count)
+{
+ const struct region_device *rdev;
+ struct region region = {
+ .offset = offset,
+ .size = count,
+ };
+
+ rdev = find_parent(rh, ®ion);
+
+ if (rdev == NULL || rdev->ops->eraseat == NULL)
+ return -1;
+
+ return rdev->ops->eraseat(rdev, region.offset, region.size);
+}
+
+void *region_mmap(rhandle_t rh, offset_t offset, size_t count)
+{
+ const struct region_device *rdev;
+ struct region region = {
+ .offset = offset,
+ .size = count,
+ };
+
+ if (count == 0)
+ return NULL;
+
+ rdev = find_parent(rh, ®ion);
+
+ if (rdev == NULL || rdev->ops->mmap == NULL)
+ return NULL;
+
+ return rdev->ops->mmap(rdev, region.offset, region.size);
+}
+
+void region_munmap(rhandle_t rh, void *addr)
+{
+ const struct region_device *rdev;
+
+ rdev = find_parent(rh, NULL);
+
+ if (rdev == NULL || rdev->ops->munmap == NULL)
+ return;
+
+ return rdev->ops->munmap(rdev, addr);
+}
+
+ssize_t region_size(rhandle_t rh)
+{
+ const struct region_registry_entry *entry;
+
+ entry = registry_entry_lookup(get_registry(), rh);
+
+ if (entry == NULL)
+ return -1;
+
+ return entry->rdev->region.size;
+}
+
+void boot_region_init(void)
+{
+ boot_media_initialize();
+ cbfs_default_media_initialize();
+ fmap_initialize();
+}
+
+/* Provide weak default. */
+void __attribute__((weak)) bootrw_media_initialize(void) {}
+
+#if !defined(__PRE_RAM__)
+#include <bootstate.h>
+static void regions_bscb(void *unused)
+{
+ boot_region_init();
+}
+
+BOOT_STATE_INIT_ENTRIES(regions_init) = {
+ BOOT_STATE_INIT_ENTRY(BS_DEV_INIT_CHIPS, BS_ON_ENTRY,
+ regions_bscb, NULL),
+};
+#endif
diff --git a/src/lib/rmodule.c b/src/lib/rmodule.c
index 2cb70b8..33481b2 100644
--- a/src/lib/rmodule.c
+++ b/src/lib/rmodule.c
@@ -21,6 +21,9 @@
#include <stdlib.h>
#include <string.h>
#include <console/console.h>
+#include <cbfs.h>
+#include <cbfs_core.h>
+#include <lib.h>
#include <rmodule.h>
/* Change this define to get more verbose debugging for module loading. */
@@ -305,11 +308,12 @@ int rmodule_calc_region(unsigned int region_alignment, size_t rmodule_size,
#include <cbmem.h>
#include <cbfs_core.h>
-int rmodule_stage_load(struct rmod_stage_load *rsl, struct cbfs_stage *stage)
+int rmodule_stage_load(struct rmod_stage_load *rsl, struct cbfs_stage *stage,
+ void *data)
{
struct rmodule rmod_stage;
size_t region_size;
- char *stage_region;
+ unsigned char *stage_region;
int rmodule_offset;
int load_offset;
const struct cbmem_entry *cbmem_entry;
@@ -331,8 +335,12 @@ int rmodule_stage_load(struct rmod_stage_load *rsl, struct cbfs_stage *stage)
printk(BIOS_INFO, "Decompressing stage %s @ 0x%p (%d bytes)\n",
rsl->name, &stage_region[rmodule_offset], stage->memlen);
- if (!cbfs_decompress(stage->compression, &stage[1],
- &stage_region[rmodule_offset], stage->len))
+ if (stage->compression == CBFS_COMPRESS_NONE) {
+ memcpy(data, &stage_region[rmodule_offset], stage->len);
+ } else if (stage->compression == CBFS_COMPRESS_LZMA) {
+ if (!ulzma(data, &stage_region[rmodule_offset]))
+ return -1;
+ } else
return -1;
if (rmodule_parse(&stage_region[rmodule_offset], &rmod_stage))
@@ -347,17 +355,35 @@ int rmodule_stage_load(struct rmod_stage_load *rsl, struct cbfs_stage *stage)
return 0;
}
-int rmodule_stage_load_from_cbfs(struct rmod_stage_load *rsl)
+int rmodule_stage_load_from_cbfs(const struct cbfs_descriptor *cbfs,
+ struct rmod_stage_load *rsl)
{
- struct cbfs_stage *stage;
+ const struct cbfs_file_descriptor *fd;
+ struct cbfs_stage stage;
+ size_t rdsz = sizeof(stage);
+ int ret;
+ void *buf;
- stage = cbfs_get_file_content(CBFS_DEFAULT_MEDIA,
- rsl->name, CBFS_TYPE_STAGE, NULL);
+ fd = cbfs_open_by_name_type(cbfs, rsl->name, CBFS_TYPE_STAGE);
- if (stage == NULL)
+ if (fd == NULL)
return -1;
- return rmodule_stage_load(rsl, stage);
+ ret = -1;
+ if (cbfs_file_read_metadata(fd, &stage, 0, rdsz) != rdsz)
+ goto out;
+
+ buf = cbfs_file_map_content(fd, 0, cbfs_file_content_size(fd));
+ if (buf == NULL)
+ goto out;
+
+ ret = rmodule_stage_load(rsl, &stage, buf);
+
+ cbfs_file_unmap(fd, buf);
+
+out:
+ cbfs_file_close(fd);
+ return ret;
}
#endif /* DYNAMIC_CBMEM */
diff --git a/src/lib/selfboot.c b/src/lib/selfboot.c
index feff03e..b6c8797 100644
--- a/src/lib/selfboot.c
+++ b/src/lib/selfboot.c
@@ -25,6 +25,7 @@
#include <stdlib.h>
#include <string.h>
#include <cbfs.h>
+#include <cbfs_core.h>
#include <lib.h>
#include <bootmem.h>
#include <payload_loader.h>
@@ -40,7 +41,7 @@ struct segment {
struct segment *next;
struct segment *prev;
unsigned long s_dstaddr;
- unsigned long s_srcaddr;
+ unsigned long s_srcoffset;
unsigned long s_memsz;
unsigned long s_filesz;
int compression;
@@ -140,7 +141,7 @@ static int relocate_segment(unsigned long buffer, struct segment *seg)
new->s_memsz = len;
seg->s_memsz -= len;
seg->s_dstaddr += len;
- seg->s_srcaddr += len;
+ seg->s_srcoffset += len;
if (seg->s_filesz > len) {
new->s_filesz = len;
seg->s_filesz -= len;
@@ -176,7 +177,7 @@ static int relocate_segment(unsigned long buffer, struct segment *seg)
seg->s_memsz = len;
new->s_memsz -= len;
new->s_dstaddr += len;
- new->s_srcaddr += len;
+ new->s_srcoffset += len;
if (seg->s_filesz > len) {
seg->s_filesz = len;
new->s_filesz -= len;
@@ -213,17 +214,12 @@ static int relocate_segment(unsigned long buffer, struct segment *seg)
static int build_self_segment_list(
- struct segment *head,
+ struct segment *head, struct cbfs_payload_segment *segment,
struct payload *payload, uintptr_t *entry)
{
struct segment *new;
- struct segment *ptr;
- struct cbfs_payload_segment *segment, *first_segment;
- struct cbfs_payload *cbfs_payload;
- cbfs_payload = payload->backing_store.data;
memset(head, 0, sizeof(*head));
head->next = head->prev = head;
- first_segment = segment = &cbfs_payload->segments;
while(1) {
printk(BIOS_DEBUG, "Loading segment from rom address 0x%p\n", segment);
@@ -237,43 +233,39 @@ static int build_self_segment_list(
case PAYLOAD_SEGMENT_DATA:
printk(BIOS_DEBUG, " %s (compression=%x)\n",
segment->type == PAYLOAD_SEGMENT_CODE ? "code" : "data",
- ntohl(segment->compression));
+ segment->compression);
new = malloc(sizeof(*new));
- new->s_dstaddr = ntohll(segment->load_addr);
- new->s_memsz = ntohl(segment->mem_len);
- new->compression = ntohl(segment->compression);
-
- new->s_srcaddr = (uintptr_t)
- ((unsigned char *)first_segment)
- + ntohl(segment->offset);
- new->s_filesz = ntohl(segment->len);
- printk(BIOS_DEBUG, " New segment dstaddr 0x%lx memsize 0x%lx srcaddr 0x%lx filesize 0x%lx\n",
- new->s_dstaddr, new->s_memsz, new->s_srcaddr, new->s_filesz);
+ new->s_dstaddr = segment->load_addr;
+ new->s_memsz = segment->mem_len;
+ new->compression = segment->compression;
+
+ new->s_srcoffset = segment->offset;
+ new->s_filesz = segment->len;
+ printk(BIOS_DEBUG, " New segment dstaddr 0x%lx memsize 0x%lx srcoffset 0x%lx filesize 0x%lx\n",
+ new->s_dstaddr, new->s_memsz, new->s_srcoffset, new->s_filesz);
/* Clean up the values */
if (new->s_filesz > new->s_memsz) {
new->s_filesz = new->s_memsz;
}
printk(BIOS_DEBUG, " (cleaned up) New segment addr 0x%lx size 0x%lx offset 0x%lx filesize 0x%lx\n",
- new->s_dstaddr, new->s_memsz, new->s_srcaddr, new->s_filesz);
+ new->s_dstaddr, new->s_memsz, new->s_srcoffset, new->s_filesz);
break;
case PAYLOAD_SEGMENT_BSS:
- printk(BIOS_DEBUG, " BSS 0x%p (%d byte)\n", (void *)
- (intptr_t)ntohll(segment->load_addr),
- ntohl(segment->mem_len));
+ printk(BIOS_DEBUG, " BSS 0x%p (%d byte)\n",
+ (void *)(intptr_t)segment->load_addr,
+ segment->mem_len);
new = malloc(sizeof(*new));
new->s_filesz = 0;
- new->s_srcaddr = (uintptr_t)
- ((unsigned char *)first_segment)
- + ntohl(segment->offset);
- new->s_dstaddr = ntohll(segment->load_addr);
- new->s_memsz = ntohl(segment->mem_len);
+ new->s_srcoffset = segment->offset;
+ new->s_dstaddr = segment->load_addr;
+ new->s_memsz = segment->mem_len;
break;
case PAYLOAD_SEGMENT_ENTRY:
printk(BIOS_DEBUG, " Entry Point 0x%p\n",
- (void *)(intptr_t)ntohll(segment->load_addr));
- *entry = ntohll(segment->load_addr);
+ (void *)(intptr_t)segment->load_addr);
+ *entry = segment->load_addr;
/* Per definition, a payload always has the entry point
* as last segment. Thus, we use the occurrence of the
* entry point as break condition for the loop.
@@ -292,17 +284,11 @@ static int build_self_segment_list(
/* We have found another CODE, DATA or BSS segment */
segment++;
- /* Find place where to insert our segment */
- for(ptr = head->next; ptr != head; ptr = ptr->next) {
- if (new->s_srcaddr < ntohll(segment->load_addr))
- break;
- }
-
- /* Order by stream offset */
- new->next = ptr;
- new->prev = ptr->prev;
- ptr->prev->next = new;
- ptr->prev = new;
+ /* Add to end of list. */
+ new->next = head;
+ new->prev = head->prev;
+ head->prev->next = new;
+ head->prev = new;
}
return 1;
@@ -315,6 +301,7 @@ static int load_self_segments(
struct segment *ptr;
const unsigned long one_meg = (1UL << 20);
unsigned long bounce_high = lb_end;
+ unsigned char *srcaddr = payload->backing_store.data;
for(ptr = head->next; ptr != head; ptr = ptr->next) {
if (bootmem_region_targets_usable_ram(ptr->s_dstaddr,
@@ -378,7 +365,7 @@ static int load_self_segments(
/* Compute the boundaries of the segment */
dest = (unsigned char *)(ptr->s_dstaddr);
- src = (unsigned char *)(ptr->s_srcaddr);
+ src = srcaddr + ptr->s_srcoffset;
/* Copy data from the initial buffer */
if (ptr->s_filesz) {
@@ -441,13 +428,51 @@ static int load_self_segments(
return 1;
}
+static void
+parse_cbfs_segments(struct cbfs_payload_segment *segments, size_t size)
+{
+ int i;
+ int num;
+
+ num = size / sizeof(struct cbfs_payload_segment);
+
+ for (i = 0; i < num; i++) {
+ /* Note: the type field is in host order. */
+ segments[i].compression = ntohl(segments[i].compression);
+ segments[i].offset = ntohl(segments[i].offset);
+ /* Fix up the offsets to be relative to the data stream. */
+ segments[i].offset -= size;
+ segments[i].load_addr = ntohll(segments[i].load_addr);
+ segments[i].len = ntohl(segments[i].len);
+ segments[i].mem_len = ntohl(segments[i].mem_len);
+ }
+}
+
void *selfload(struct payload *payload)
{
uintptr_t entry = 0;
struct segment head;
+ ssize_t metadata_sz;
+ struct cbfs_payload_segment *segments;
+
+ metadata_sz = cbfs_file_metadata_size(payload->fd);
+
+ if (metadata_sz <= 0)
+ return NULL;
+
+ segments = malloc(sizeof(struct cbfs_payload_segment));
+
+ if (segments == NULL)
+ return NULL;
+
+ if (cbfs_file_read_metadata(payload->fd, segments, 0, metadata_sz) !=
+ metadata_sz)
+ return NULL;
+
+ parse_cbfs_segments(segments, metadata_sz);
/* Preprocess the self segments */
- if (!build_self_segment_list(&head, payload, &entry))
+ if (!build_self_segment_list(&head, segments, payload, &entry))
goto out;
/* Load the segments */
diff --git a/src/soc/intel/baytrail/Kconfig b/src/soc/intel/baytrail/Kconfig
index 2360b36..63b5c89 100644
--- a/src/soc/intel/baytrail/Kconfig
+++ b/src/soc/intel/baytrail/Kconfig
@@ -8,6 +8,7 @@ if SOC_INTEL_BAYTRAIL
config CPU_SPECIFIC_OPTIONS
def_bool y
+ select BOOT_REGION_SPI_FLASH
select CACHE_MRC_SETTINGS
select CAR_MIGRATION
select COLLECT_TIMESTAMPS
diff --git a/src/soc/intel/baytrail/mrc_cache.c b/src/soc/intel/baytrail/mrc_cache.c
index 5613761..784952d 100644
--- a/src/soc/intel/baytrail/mrc_cache.c
+++ b/src/soc/intel/baytrail/mrc_cache.c
@@ -20,6 +20,7 @@
#include <string.h>
#include <console/console.h>
#include <cbmem.h>
+#include <region.h>
#include <ip_checksum.h>
#if CONFIG_CHROMEOS
#include <vendorcode/google/chromeos/fmap.h>
@@ -40,11 +41,20 @@ struct mrc_data_region {
static int mrc_cache_get_region(struct mrc_data_region *region)
{
#if CONFIG_CHROMEOS
- int ret;
- ret = find_fmap_entry("RW_MRC_CACHE", ®ion->base);
- if (ret >= 0) {
- region->size = ret;
- return 0;
+ offset_t offset;
+ size_t size;
+ if (!fmap_locate("RW_MRC_CACHE", &offset, &size)) {
+ void *mapping;
+ rhandle_t rh;
+
+ rh = region_locate(BOOTRO_REGION_NAME);
+ mapping = region_mmap(rh, offset, size);
+
+ if (mapping != NULL) {
+ region->base = mapping;
+ region->size = size;
+ return 0;
+ }
}
#endif
region->base = (void *)CONFIG_MRC_SETTINGS_CACHE_BASE;
diff --git a/src/soc/intel/baytrail/nvm.c b/src/soc/intel/baytrail/nvm.c
index dccc801..44d67ae 100644
--- a/src/soc/intel/baytrail/nvm.c
+++ b/src/soc/intel/baytrail/nvm.c
@@ -24,26 +24,25 @@
#include <spi-generic.h>
#include <spi_flash.h>
#include <baytrail/nvm.h>
+#include <region.h>
/* This module assumes the flash is memory mapped just below 4GiB in the
* address space for reading. Also this module assumes an area it erased
* when all bytes read as all 0xff's. */
-static struct spi_flash *flash;
+static rhandle_t rwrh = INVALID_RHANDLE;
static int nvm_init(void)
{
- if (flash != NULL)
+ if (rhandle_valid(rwrh))
return 0;
- spi_init();
- flash = spi_flash_probe(0, 0, 1000000, SPI_MODE_3);
- if (!flash) {
- printk(BIOS_DEBUG, "Could not find SPI device\n");
- return -1;
- }
+ rwrh = region_locate(BOOTRW_REGION_NAME);
- return 0;
+ if (rhandle_valid(rwrh))
+ return 0;
+
+ return -1;
}
/* Convert memory mapped pointer to flash offset. */
@@ -69,7 +68,10 @@ int nvm_erase(void *start, size_t size)
{
if (nvm_init() < 0)
return -1;
- flash->erase(flash, to_flash_offset(start), size);
+
+ if (region_eraseat(rwrh, to_flash_offset(start), size) != size)
+ return -1;
+
return 0;
}
@@ -78,6 +80,9 @@ int nvm_write(void *start, const void *data, size_t size)
{
if (nvm_init() < 0)
return -1;
- flash->write(flash, to_flash_offset(start), size, data);
+
+ if (region_eraseat(rwrh, to_flash_offset(start), size) != size)
+ return -1;
+
return 0;
}
diff --git a/src/soc/intel/baytrail/romstage/raminit.c b/src/soc/intel/baytrail/romstage/raminit.c
index 7bcd54f..496e755 100644
--- a/src/soc/intel/baytrail/romstage/raminit.c
+++ b/src/soc/intel/baytrail/romstage/raminit.c
@@ -105,6 +105,7 @@ void raminit(struct mrc_params *mp, int prev_sleep_state)
int ret;
mrc_wrapper_entry_t mrc_entry;
const struct mrc_saved_data *cache;
+ const struct cbfs_file_descriptor *fd;
/* Fill in default entries. */
mp->version = MRC_PARAMS_VER;
@@ -118,10 +119,11 @@ void raminit(struct mrc_params *mp, int prev_sleep_state)
printk(BIOS_DEBUG, "No MRC cache found.\n");
}
- mrc_entry = cbfs_get_file_content(CBFS_DEFAULT_MEDIA, "mrc.bin", 0xab,
- NULL);
+ fd = cbfs_open_by_name_type(cbfs_default_descriptor(), "mrc.bin", 0xab);
+ mrc_entry = cbfs_file_map_content(fd, 0, cbfs_file_content_size(fd));
if (mrc_entry == NULL) {
+ cbfs_file_close(fd);
printk(BIOS_DEBUG, "Couldn't find mrc.bin\n");
return;
}
@@ -130,6 +132,9 @@ void raminit(struct mrc_params *mp, int prev_sleep_state)
ret = mrc_entry(mp);
+ cbfs_file_unmap(fd, mrc_entry);
+ cbfs_file_close(fd);
+
print_dram_info();
cbmem_initialize_empty();
diff --git a/src/soc/intel/baytrail/romstage/romstage.c b/src/soc/intel/baytrail/romstage/romstage.c
index 5af9bf4..37aae10 100644
--- a/src/soc/intel/baytrail/romstage/romstage.c
+++ b/src/soc/intel/baytrail/romstage/romstage.c
@@ -29,6 +29,7 @@
#include <ec/google/chromeec/ec.h>
#endif
#include <elog.h>
+#include <region.h>
#include <ramstage_cache.h>
#include <romstage_handoff.h>
#include <timestamp.h>
@@ -133,6 +134,9 @@ void * asmlinkage romstage_main(unsigned long bist,
google_chromeec_early_init();
#endif
+ /* Initialize the boot media. */
+ boot_region_init();
+
/* Call into mainboard. */
mainboard_romstage_entry(&rp);
diff --git a/src/vendorcode/google/chromeos/Makefile.inc b/src/vendorcode/google/chromeos/Makefile.inc
index 007bd57..24afb2c 100644
--- a/src/vendorcode/google/chromeos/Makefile.inc
+++ b/src/vendorcode/google/chromeos/Makefile.inc
@@ -27,6 +27,7 @@ romstage-y += fmap.c
ramstage-y += fmap.c
ramstage-$(CONFIG_CHROMEOS_RAMOOPS) += ramoops.c
smm-y += fmap.c
+smm-y += ../../../lib/region.c
ifneq ($(wildcard src/mainboard/$(MAINBOARDDIR)/chromeos.c),)
ramstage-srcs += src/mainboard/$(MAINBOARDDIR)/chromeos.c
romstage-srcs += src/mainboard/$(MAINBOARDDIR)/chromeos.c
diff --git a/src/vendorcode/google/chromeos/chromeos.c b/src/vendorcode/google/chromeos/chromeos.c
index e917ba1..6f20109 100644
--- a/src/vendorcode/google/chromeos/chromeos.c
+++ b/src/vendorcode/google/chromeos/chromeos.c
@@ -121,10 +121,14 @@ static int vboot_locate_payload(struct payload *payload)
if (buffer == NULL)
return -1;
+#if 0
payload->backing_store.data = buffer;
payload->backing_store.size = size;
return 0;
+#endif
+ /* TODO: fake a cbfs. Also need this in rmodule loading. */
+ return -1;
}
const struct payload_loader_ops vboot_payload_loader = {
diff --git a/src/vendorcode/google/chromeos/fmap.c b/src/vendorcode/google/chromeos/fmap.c
index 538b8c3..fa17e35 100644
--- a/src/vendorcode/google/chromeos/fmap.c
+++ b/src/vendorcode/google/chromeos/fmap.c
@@ -20,97 +20,134 @@
#include <stdint.h>
#include <stddef.h>
#include <string.h>
+#include <arch/early_variables.h>
#include <console/console.h>
+#include <region.h>
#include "fmap.h"
-/* Find FMAP data structure in ROM.
+/*
* See http://code.google.com/p/flashmap/ for more information on FMAP.
*/
-const struct fmap *fmap_find(void)
-{
- /* FIXME: Get rid of the hard codes. The "easy" way would be to
- * do a binary search, but since ROM accesses are slow, we don't
- * want to spend a lot of time looking for the FMAP. An elegant
- * solution would be to store a pointer to the FMAP in the CBFS
- * master header; that would require some more changes to cbfstool
- * and possibly cros_bundle_firmware.
- */
-
- /* wrapping around 0x100000000 */
- const struct fmap *fmap = (void *)
- (CONFIG_FLASHMAP_OFFSET - CONFIG_ROM_SIZE);
- if (memcmp(fmap, FMAP_SIGNATURE, sizeof(FMAP_SIGNATURE)-1)) {
- printk(BIOS_DEBUG, "No FMAP found at %p.\n", fmap);
- return NULL;
- }
+/*
+ * The reason for the global state is that FMAP needs to be available in
+ * romstage on x86 machines. This necessitates keeping some global variables
+ * around because there is no malloc or global modifiable data without being
+ * placed in BSS. This code relies on CAR globals being migrated in romstage.
+ */
- printk(BIOS_DEBUG, "FMAP: Found \"%s\" version %d.%d at %p.\n",
- fmap->name, fmap->ver_major, fmap->ver_minor, fmap);
- printk(BIOS_DEBUG, "FMAP: base = %llx size = %x #areas = %d\n",
- (unsigned long long)fmap->base, fmap->size, fmap->nareas);
+#define FMAP_REGION_NAME "fmap"
+
+struct fmap_state {
+ int registered;
+ int num_entries;
+};
+
+static struct fmap_state g_fmap_state CAR_GLOBAL;
+static const offset_t fmap_offset = CONFIG_FLASHMAP_OFFSET;
- return fmap;
+static inline struct fmap_state *get_state(void)
+{
+ return car_get_var_ptr(&g_fmap_state);
}
-const struct fmap_area *find_fmap_area(const struct fmap *fmap,
- const char name[])
+static const struct region_device fmap_rdev = {
+ .region = {
+ .offset = 0,
+ .size = CONFIG_ROM_SIZE,
+ },
+};
+
+/* Return < 0 on failure, 0 on success */
+static int fmap_init(void)
{
- const struct fmap_area *area = NULL;
-
- if (fmap) {
- int i;
- for (i = 0; i < fmap->nareas; i++) {
- if (!strcmp((const char *)fmap->areas[i].name, name)) {
- area = &fmap->areas[i];
- break;
- }
- }
- }
+ struct fmap_state *gs;
+ rhandle_t rh;
+ struct fmap *fmap;
- if (area) {
- printk(BIOS_DEBUG, "FMAP: area %s found\n", name);
- printk(BIOS_DEBUG, "FMAP: offset: %x\n", area->offset);
- printk(BIOS_DEBUG, "FMAP: size: %d bytes\n", area->size);
- } else {
- printk(BIOS_DEBUG, "FMAP: area %s not found\n", name);
+ gs = get_state();
+
+ if (gs->registered)
+ return 1;
+
+ /* Execute this function only once. Default to invalid. */
+ gs->registered = 1;
+ rh = region_locate(BOOTRO_REGION_NAME);
+
+ if (!rhandle_valid(rh))
+ return -1;
+
+ fmap = region_mmap(rh, fmap_offset, sizeof(*fmap));
+
+ if (fmap == NULL)
+ return -1;
+
+ if (memcmp(fmap, FMAP_SIGNATURE, sizeof(FMAP_SIGNATURE)-1)) {
+ printk(BIOS_DEBUG, "No FMAP found at %zx.\n", fmap_offset);
+ region_munmap(rh, fmap);
+ return -1;
}
+ printk(BIOS_DEBUG, "FMAP: Found \"%s\" version %d.%d at %zx.\n",
+ fmap->name, fmap->ver_major, fmap->ver_minor, fmap_offset);
+ printk(BIOS_DEBUG, "FMAP: base = %llx size = %x #areas = %d\n",
+ (unsigned long long)fmap->base, fmap->size, fmap->nareas);
+
+ gs->num_entries = fmap->nareas;
+ region_munmap(rh, fmap);
- return area;
+ /* Register fmap device under the boot region. */
+ if (!rhandle_valid(region_register_subregion(FMAP_REGION_NAME,
+ &fmap_rdev, rh)))
+ return -1;
+
+ return 0;
}
-int find_fmap_entry(const char name[], void **pointer)
+int fmap_locate(const char *name, offset_t *offset, size_t *size)
{
-#ifndef __PRE_RAM__
- static
-#endif
- const struct fmap *fmap = NULL;
- const struct fmap_area *area;
- void *base = NULL;
+ rhandle_t rh;
+ struct fmap_area *areas;
+ struct fmap_state * gs;
+ int i;
+ int ret = -1;
- if (!fmap)
- fmap = fmap_find();
+ rh = region_locate(FMAP_REGION_NAME);
+ gs = get_state();
- area = find_fmap_area(fmap, name);
+ if (!rhandle_valid(rh) || gs == NULL)
+ return ret;
- if (!area)
- return -1;
+ areas = region_mmap(rh, sizeof(struct fmap) + fmap_offset,
+ gs->num_entries * sizeof(*areas));
- /* Right now cros_bundle_firmware does not write a valid
- * base address into the FMAP. Hence, if base is 0, assume
- * 4GB-8MB as base address.
- */
- if (fmap->base) {
- base = (void *)(unsigned long)fmap->base;
- printk(BIOS_DEBUG, "FMAP: %s base at %p\n", name, base);
- } else {
- base = (void *)(0 - CONFIG_ROM_SIZE);
- printk(BIOS_WARNING, "FMAP: No valid base address, using"
- " 0x%p\n", base);
+ if (areas == NULL) {
+ printk(BIOS_DEBUG, "FMAP: could not map areas.\n");
+ return ret;
}
- *pointer = (void*) ((u32)base + area->offset);
- printk(BIOS_DEBUG, "FMAP: %s at %p (offset %x)\n",
- name, *pointer, area->offset);
- return area->size;
+ for (i = 0; i < gs->num_entries; i++) {
+ if (strcmp((char *)&areas[i].name[0], name))
+ continue;
+ printk(BIOS_DEBUG, "FMAP: area %s found\n", name);
+ printk(BIOS_DEBUG, "FMAP: offset: %x\n", areas[i].offset);
+ printk(BIOS_DEBUG, "FMAP: size: %d bytes\n", areas[i].size);
+
+ *offset = areas[i].offset;
+ *size = areas[i].size;
+ ret = 0;
+ break;
+ }
+
+ if (ret)
+ printk(BIOS_DEBUG, "FMAP: area '%s' not found.\n", name);
+
+ region_munmap(rh, areas);
+
+ return ret;
+}
+
+void fmap_initialize(void)
+{
+ if (fmap_init() < 0)
+ printk(BIOS_DEBUG, "FMAP region wasn't registered.\n");
}
diff --git a/src/vendorcode/google/chromeos/fmap.h b/src/vendorcode/google/chromeos/fmap.h
index a3d2abd..de935e7 100644
--- a/src/vendorcode/google/chromeos/fmap.h
+++ b/src/vendorcode/google/chromeos/fmap.h
@@ -37,6 +37,7 @@
#define FLASHMAP_LIB_FMAP_H__
#include <stdint.h>
+#include <region.h>
#define FMAP_SIGNATURE "__FMAP__"
#define FMAP_VER_MAJOR 1 /* this header's FMAP minor version */
@@ -70,10 +71,24 @@ struct fmap {
struct fmap_area areas[];
} __attribute__((packed));
+#if IS_ENABLED(CONFIG_CHROMEOS)
+/*
+ * Initialize the fmap state within coreboot.
+ */
+void fmap_initialize(void);
+
+/*
+ * Locate a region by name within the fmap. offset and size are filled in
+ * relative to the boot media the global fmap is located. Returns 0 on
+ * success, < 0 when unable to find the region.
+ */
+int fmap_locate(const char *name, offset_t *offset, size_t *size);
+#else /* IS_ENABLED(CONFIG_CHROMEOS) */
+static inline void fmap_initialize(void) {}
+static inline int fmap_locate(const char *name, offset_t *offset, size_t *size)
+{
+ return -1;
+}
+#endif /* IS_ENABLED(CONFIG_CHROMEOS) */
-/* coreboot specific function prototypes */
-const struct fmap *fmap_find(void);
-const struct fmap_area *find_fmap_area(const struct fmap *fmap,
- const char name[]);
-int find_fmap_entry(const char name[], void **pointer);
#endif /* FLASHMAP_LIB_FMAP_H__*/
diff --git a/src/vendorcode/google/chromeos/vboot_loader.c b/src/vendorcode/google/chromeos/vboot_loader.c
index 0c5220a..98bc1a5 100644
--- a/src/vendorcode/google/chromeos/vboot_loader.c
+++ b/src/vendorcode/google/chromeos/vboot_loader.c
@@ -21,6 +21,7 @@
#include <stdint.h>
#include <stddef.h>
#include <cbfs.h>
+#include <cbfs_core.h>
#include <cbmem.h>
#include <console/console.h>
#include <console/vtxprintf.h>
@@ -45,7 +46,8 @@ static void vboot_run_stub(struct vboot_context *context)
};
void (*entry)(struct vboot_context *context);
- if (rmodule_stage_load_from_cbfs(&rmod_stage)) {
+ if (rmodule_stage_load_from_cbfs(cbfs_default_descriptor(),
+ &rmod_stage)) {
printk(BIOS_DEBUG, "Could not load vboot stub.\n");
goto out;
}
@@ -74,6 +76,30 @@ static void fatal_error(void)
hard_reset();
}
+static void locate_region(const char *name, void **parea, uint32_t *psize)
+{
+ offset_t offset;
+ size_t size;
+ rhandle_t rh;
+
+ *psize = 0;
+ *parea = NULL;
+
+ if (fmap_locate(name, &offset, &size))
+ return;
+
+ rh = region_locate(BOOTRO_REGION_NAME);
+ if (!rhandle_valid(rh))
+ return;
+
+ /*
+ * This leaks the mappings on anything but x86 systems which have
+ * CBFS memory-mapped.
+ */
+ *psize = size;
+ *parea = region_mmap(rh, offset, size);
+}
+
static void vboot_invoke_wrapper(struct vboot_handoff *vboot_handoff)
{
VbCommonParams cparams;
@@ -105,20 +131,17 @@ static void vboot_invoke_wrapper(struct vboot_handoff *vboot_handoff)
context.cparams = &cparams;
context.fparams = &fparams;
- cparams.gbb_size = find_fmap_entry("GBB", &cparams.gbb_data);
+ locate_region("GBB", &cparams.gbb_data, &cparams.gbb_size);
cparams.shared_data_blob = &vboot_handoff->shared_data[0];
cparams.shared_data_size = VB_SHARED_DATA_MIN_SIZE;
cparams.caller_context = &context;
- fparams.verification_size_A =
- find_fmap_entry("VBLOCK_A", &fparams.verification_block_A);
- fparams.verification_size_B =
- find_fmap_entry("VBLOCK_B", &fparams.verification_block_B);
-
- context.fw_a_size =
- find_fmap_entry("FW_MAIN_A", (void **)&context.fw_a);
- context.fw_b_size =
- find_fmap_entry("FW_MAIN_B", (void **)&context.fw_b);
+ locate_region("VBLOCK_A", &fparams.verification_block_A,
+ &fparams.verification_size_A);
+ locate_region("VBLOCK_B", &fparams.verification_block_B,
+ &fparams.verification_size_B);
+ locate_region("FW_MAIN_A", (void **)&context.fw_a, &context.fw_a_size);
+ locate_region("FW_MAIN_B", (void **)&context.fw_b, &context.fw_b_size);
/* Check all fmap entries. */
if (context.fw_a == NULL || context.fw_b == NULL ||
@@ -195,7 +218,7 @@ static void *vboot_load_ramstage(uint32_t cbmem_id, const char *name,
stage = (void *)fwc->address;
- if (rmodule_stage_load(&rmod_load, stage)) {
+ if (rmodule_stage_load(&rmod_load, stage, &stage[1])) {
vboot_handoff->selected_firmware = VB_SELECT_FIRMWARE_READONLY;
printk(BIOS_DEBUG, "Could not load ramstage region.\n");
return NULL;
More information about the coreboot-gerrit
mailing list