[coreboot-gerrit] Patch set updated for coreboot: da9a3e0 regions support

Aaron Durbin (adurbin@google.com) gerrit at coreboot.org
Tue Mar 18 16:30:11 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 da9a3e01f298f829fc5cbeefa1944d698e5b25bf
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                          | 138 ++++++++
 src/include/rmodule.h                         |   7 +-
 src/lib/Makefile.inc                          |  10 +
 src/lib/bootrw_spi_flash_region.c             | 107 ++++++
 src/lib/cbfs.c                                | 489 ++++++++++++++++++--------
 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                              | 293 +++++++++++++++
 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         | 174 +++++----
 src/vendorcode/google/chromeos/fmap.h         |  25 +-
 src/vendorcode/google/chromeos/vboot_loader.c |  47 ++-
 35 files changed, 1725 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(&microcode_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..f1b99df
--- /dev/null
+++ b/src/include/region.h
@@ -0,0 +1,138 @@
+/*
+ * 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;
+};
+
+/* Return 1 if child is contained within parent else 0. */
+int region_contained(const struct region *parent, const struct region *child);
+
+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..80b1cd1
--- /dev/null
+++ b/src/lib/bootrw_spi_flash_region.c
@@ -0,0 +1,107 @@
+/*
+ * 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);
+}
diff --git a/src/lib/cbfs.c b/src/lib/cbfs.c
index dc08937..04f4034 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,390 @@
  * 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 (c <= 9) ? (c + '0') : (c - 10 + 'a');
+	return car_get_var_ptr(&g_cbfs_files);
 }
 
-static void tohex16(unsigned int val, char* dest)
+static int cbfs_fd_available(const struct cbfs_file_descriptor *fd)
 {
-	dest[0] = tohex4(val>>12);
-	dest[1] = tohex4((val>>8) & 0xf);
-	dest[2] = tohex4((val>>4) & 0xf);
-	dest[3] = tohex4(val & 0xf);
+	return !!(fd->content.size == 0 && fd->metadata.size == 0);
 }
 
-void *cbfs_load_optionrom(struct cbfs_media *media, uint16_t vendor,
-			  uint16_t device, void *dest)
+static void cbfs_fd_mark_free(const struct cbfs_file_descriptor *cfd)
 {
-	char name[17] = "pciXXXX,XXXX.rom";
-	struct cbfs_optionrom *orom;
-	uint8_t *src;
+	struct cbfs_file_descriptor *fd = (struct cbfs_file_descriptor *)cfd;
+	memset(fd, 0, sizeof(*fd));
+	fd->rh = INVALID_RHANDLE;
+}
 
-	tohex16(vendor, name+3);
-	tohex16(device, name+8);
+static struct cbfs_file_descriptor *get_available_file(void)
+{
+	int i;
+	struct cbfs_file_cache *cache = get_cache();
 
-	orom = (struct cbfs_optionrom *)
-	  cbfs_get_file_content(media, name, CBFS_TYPE_OPTIONROM, NULL);
+	for (i = 0; i < MAX_CBFS_OPEN_FILES; i++) {
+		if (cbfs_fd_available(&cache->files[i]))
+			return &cache->files[i];
+	}
+
+	return NULL;
+}
 
-	if (orom == NULL)
+static void cbfs_fd_add_metadata(struct cbfs_file_descriptor *fd, size_t sz)
+{
+	fd->metadata.size += sz;
+	fd->content.offset += sz;
+	fd->content.size -= sz;
+}
+
+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;
+
+	fd = get_available_file();
+
+	if (fd == NULL)
 		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.
-	 */
+	fd->rh = cbfs->rh;
+	fd->metadata.offset = file->offset + offset;
+	fd->metadata.size = 0;
+	fd->content.offset = file->offset + offset;
+	fd->content.size = file->len;
 
-	/* BUG: the cbfstool is (not yet) including a cbfs_optionrom header */
-	src = (uint8_t *)orom; // + sizeof(struct cbfs_optionrom);
+	if (file->type != CBFS_TYPE_STAGE || file->type != CBFS_TYPE_PAYLOAD)
+		return fd;
 
-	if (! dest)
-		return src;
+	if (file->type == CBFS_TYPE_STAGE) {
+		cbfs_fd_add_metadata(fd, sizeof(struct cbfs_stage));
+		return fd;
+	}
 
-	if (!cbfs_decompress(ntohl(orom->compression),
-			     src,
-			     dest,
-			     ntohl(orom->len)))
+	/* Parse payload segments. */
+	while (offset + sizeof(struct cbfs_payload_segment) <= file->len) {
+		struct cbfs_payload_segment segment;
+		ssize_t read_sz;
+
+		read_sz = region_readat(cbfs->rh, &segment, offset,
+		                        sizeof(segment));
+		if (read_sz != sizeof(segment)) {
+			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;
+		}
+	}
+
+	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;
+}
+
+ssize_t cbfs_file_metadata_size(const struct cbfs_file_descriptor *fd)
+{
+	if (fd == NULL)
+		return -1;
+
+	return fd->metadata.size;
+}
+
+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,
+	};
 
-	DEBUG("stage loaded.\n");
+	if (fd == NULL)
+		return -1;
 
-	entry = stage->entry;
-	// entry = ntohll(stage->entry);
+	if (!region_contained(&fd->content, &region))
+		return -1;
 
-	return (void *) entry;
+	return region_readat(fd->rh, buf, fd->content.offset + 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_contained(&fd->content, &region))
+		return NULL;
+
+	return region_mmap(fd->rh, fd->content.offset + 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;
 
-int run_address(void *f)
+	if (!region_contained(&fd->metadata, &region))
+		return -1;
+
+	return region_readat(fd->rh, buf, fd->metadata.offset + offset, size);
+}
+
+void *cbfs_file_map_metadata(const struct cbfs_file_descriptor *fd)
 {
-	int (*v) (void);
-	v = f;
-	return v();
+	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);
+}
+
+#ifndef __SMM__
+size_t cbfs_file_inflate(const struct cbfs_file_descriptor *fd,
+                         offset_t offset, size_t src_sz, void *dest)
+{
+#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..4dadb12
--- /dev/null
+++ b/src/lib/region.c
@@ -0,0 +1,293 @@
+/*
+ * 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];
+}
+
+int region_contained(const struct region *parent, const struct region *child)
+{
+	if (child->size > parent->size)
+		return 0;
+
+	if (child->offset >= parent->size)
+		return 0;
+
+	if ((child->offset + child->size) > parent->size)
+		return 0;
+
+	return 1;
+}
+
+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_contained(&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_contained(&entry->rdev->region, region))
+		return NULL;
+
+	while (entry->rdev->ops == NULL) {
+		/* Translate the region into the parent's view. */
+		if (region != NULL)
+			region->offset += entry->rdev->region.offset;
+		entry = &rr->entries[entry->parent_slot];
+	}
+
+	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, &region);
+
+	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, &region);
+
+	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, &region);
+
+	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, &region);
+
+	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", &region->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..e0ad7c0 100644
--- a/src/vendorcode/google/chromeos/fmap.c
+++ b/src/vendorcode/google/chromeos/fmap.c
@@ -20,97 +20,131 @@
 #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);
+
+	/* Register fmap device under the boot region. */
+	if (!rhandle_valid(region_register_subregion(FMAP_REGION_NAME,
+	                   &fmap_rdev, rh)))
+		return -1;
 
-	return area;
+	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));
+
+	if (areas == NULL) {
+		printk(BIOS_DEBUG, "FMAP: could not map areas.\n");
+		return ret;
+	}
+
+	for (i = 0; i < gs->num_entries; i++) {
+		if (strncmp((char *)&areas[i].name[0], name, FMAP_STRLEN))
+			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);
 
-	/* 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);
+		*offset = areas[i].offset;
+		*size = areas[i].size;
+		ret = 0;
+		break;
 	}
 
-	*pointer = (void*) ((u32)base + area->offset);
-	printk(BIOS_DEBUG, "FMAP: %s at %p (offset %x)\n",
-	       name, *pointer, area->offset);
-	return area->size;
+	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