summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
authorAaron Durbin <adurbin@chromium.org>2015-05-15 23:39:23 -0500
committerPatrick Georgi <pgeorgi@google.com>2015-06-02 14:09:31 +0200
commit899d13d0dff9e7495eb17950f19431e9bd344b2f (patch)
tree8901845fc299126a7125ff19fe1f7bde17e3f305 /src/lib
parent68bdd00799c7b2b25f265fa9e31beb709c877eb6 (diff)
cbfs: new API and better program loading
A new CBFS API is introduced to allow making CBFS access easier for providing multiple CBFS sources. That is achieved by decoupling the cbfs source from a CBFS file. A CBFS source is described by a descriptor. It contains the necessary properties for walking a CBFS to locate a file. The CBFS file is then decoupled from the CBFS descriptor in that it's no longer needed to access the contents of the file. All of this is accomplished using the regions infrastructure by repsenting CBFS sources and files as region_devices. Because region_devices can be chained together forming subregions this allows one to decouple a CBFS source from a file. This also allows one to provide CBFS files that came from other sources for payload and/or stage loading. The program loading takes advantage of those very properties by allowing multiple sources for locating a program. Because of this we can reduce the overhead of loading programs because it's all done in the common code paths. Only locating the program is per source. Change-Id: I339b84fce95f03d1dbb63a0f54a26be5eb07f7c8 Signed-off-by: Aaron Durbin <adurbin@chromium.org> Reviewed-on: http://review.coreboot.org/9134 Tested-by: build bot (Jenkins) Tested-by: Raptor Engineering Automated Test Stand <noreply@raptorengineeringinc.com> Reviewed-by: Patrick Georgi <pgeorgi@google.com>
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/Makefile.inc17
-rw-r--r--src/lib/cbfs.c334
-rw-r--r--src/lib/cbfs_boot_props.c66
-rw-r--r--src/lib/cbfs_core.c324
-rw-r--r--src/lib/cbfs_core.h47
-rw-r--r--src/lib/cbfs_spi.c72
-rw-r--r--src/lib/coreboot_table.c4
-rw-r--r--src/lib/hardwaremain.c2
-rw-r--r--src/lib/loaders/Makefile.inc27
-rw-r--r--src/lib/loaders/cbfs_payload_loader.c43
-rw-r--r--src/lib/loaders/cbfs_ramstage_loader.c56
-rw-r--r--src/lib/loaders/cbfs_romstage_loader.c31
-rw-r--r--src/lib/loaders/load_and_run_payload.c118
-rw-r--r--src/lib/loaders/load_and_run_ramstage.c109
-rw-r--r--src/lib/loaders/load_and_run_romstage.c85
-rw-r--r--src/lib/prog_loaders.c247
-rw-r--r--src/lib/rmodule.c54
-rw-r--r--src/lib/selfboot.c21
18 files changed, 565 insertions, 1092 deletions
diff --git a/src/lib/Makefile.inc b/src/lib/Makefile.inc
index 5ec9de72ed..ebb3076e63 100644
--- a/src/lib/Makefile.inc
+++ b/src/lib/Makefile.inc
@@ -18,8 +18,10 @@
#
subdirs-y += loaders
+bootblock-y += prog_loaders.c
bootblock-y += prog_ops.c
-bootblock-y += cbfs.c cbfs_core.c
+bootblock-y += cbfs.c
+bootblock-y += cbfs_boot_props.c
bootblock-$(CONFIG_COMMON_CBFS_SPI_WRAPPER) += cbfs_spi.c
bootblock-$(CONFIG_GENERIC_GPIO_LIB) += gpio.c
@@ -34,12 +36,13 @@ bootblock-y += region.c
bootblock-y += boot_device.c
bootblock-y += fmap.c
+verstage-y += prog_loaders.c
verstage-y += prog_ops.c
verstage-y += delay.c
verstage-y += cbfs.c
-verstage-y += cbfs_core.c
verstage-y += halt.c
verstage-y += fmap.c
+verstage-y += cbfs_boot_props.c
verstage-y += memcmp.c
verstage-$(CONFIG_COLLECT_TIMESTAMPS) += timestamp.c
verstage-y += region.c
@@ -57,6 +60,7 @@ verstage-$(CONFIG_GENERIC_UDELAY) += timer.c
verstage-$(CONFIG_GENERIC_GPIO_LIB) += gpio.c
verstage-y += mem_pool.c
+romstage-y += prog_loaders.c
romstage-y += prog_ops.c
romstage-y += memchr.c
romstage-y += memcmp.c
@@ -66,7 +70,8 @@ $(foreach arch,$(ARCH_SUPPORTED),\
romstage-y += fmap.c
romstage-$(CONFIG_I2C_TPM) += delay.c
-romstage-y += cbfs.c cbfs_core.c
+romstage-y += cbfs.c
+romstage-y += cbfs_boot_props.c
romstage-$(CONFIG_COMMON_CBFS_SPI_WRAPPER) += cbfs_spi.c
romstage-$(CONFIG_COMPRESS_RAMSTAGE) += lzma.c lzmadecode.c
romstage-$(CONFIG_PRIMITIVE_MEMTEST) += primitive_memtest.c
@@ -87,6 +92,7 @@ endif
romstage-$(CONFIG_GENERIC_UDELAY) += timer.c
+ramstage-y += prog_loaders.c
ramstage-y += prog_ops.c
ramstage-y += hardwaremain.c
ramstage-y += selfboot.c
@@ -100,7 +106,8 @@ smm-$(CONFIG_SMM_TSEG) += malloc.c
ramstage-y += delay.c
ramstage-y += fallback_boot.c
ramstage-y += compute_ip_checksum.c
-ramstage-y += cbfs.c cbfs_core.c
+ramstage-y += cbfs.c
+ramstage-y += cbfs_boot_props.c
ramstage-$(CONFIG_COMMON_CBFS_SPI_WRAPPER) += cbfs_spi.c
ramstage-y += lzma.c lzmadecode.c
ramstage-y += stack.c
@@ -153,7 +160,7 @@ ramstage-y += boot_device.c
smm-y += region.c
smm-y += boot_device.c
smm-y += fmap.c
-smm-y += cbfs.c cbfs_core.c memcmp.c
+smm-y += cbfs.c memcmp.c
smm-$(CONFIG_COMPILER_GCC) += gcc.c
bootblock-y += version.c
diff --git a/src/lib/cbfs.c b/src/lib/cbfs.c
index 00071f8934..23dfee70c9 100644
--- a/src/lib/cbfs.c
+++ b/src/lib/cbfs.c
@@ -1,8 +1,8 @@
/*
* This file is part of the coreboot project.
*
- * Copyright (C) 2008, Jordan Crouse <jordan@cosmicpenguin.net>
- * Copyright (C) 2013 The Chromium OS Authors. All rights reserved.
+ * Copyright (C) 2011 secunet Security Networks AG
+ * Copyright 2015 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 +18,238 @@
* Foundation, Inc.
*/
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+#include <boot_device.h>
+#include <cbfs.h>
+#include <endian.h>
+#include <lib.h>
+#include <symbols.h>
+
+#define ERROR(x...) printk(BIOS_ERR, "CBFS: " x)
+#define LOG(x...) printk(BIOS_INFO, "CBFS: " x)
+#if IS_ENABLED(CONFIG_DEBUG_CBFS)
+#define DEBUG(x...) printk(BIOS_SPEW, "CBFS: " x)
+#else
+#define DEBUG(x...)
+#endif
-#include <program_loading.h>
-#include "cbfs_core.h"
-
-#ifndef __SMM__
-static inline int tohex4(unsigned int c)
+int cbfs_boot_locate(struct region_device *fh, const char *name, uint32_t *type)
{
- return (c <= 9) ? (c + '0') : (c - 10 + 'a');
-}
+ struct cbfsd cbfs;
+ struct region_device rdev;
+ const struct region_device *boot_dev;
+ struct cbfs_props props;
-static void tohex16(unsigned int 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);
-}
+ boot_device_init();
-void *cbfs_load_optionrom(struct cbfs_media *media, uint16_t vendor,
- uint16_t device, void *dest)
-{
- char name[17] = "pciXXXX,XXXX.rom";
- struct cbfs_optionrom *orom;
- uint8_t *src;
+ if (cbfs_boot_region_properties(&props))
+ return -1;
- tohex16(vendor, name+3);
- tohex16(device, name+8);
+ /* All boot CBFS operations are performed using the RO devie. */
+ boot_dev = boot_device_ro();
- orom = (struct cbfs_optionrom *)
- cbfs_get_file_content(media, name, CBFS_TYPE_OPTIONROM, NULL);
+ if (boot_dev == NULL)
+ return -1;
- if (orom == NULL)
- return NULL;
+ if (rdev_chain(&rdev, boot_dev, props.offset, props.size))
+ return -1;
- /* 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.
- */
+ cbfs.rdev = &rdev;
+ cbfs.align = props.align;
- /* BUG: the cbfstool is (not yet) including a cbfs_optionrom header */
- src = (uint8_t *)orom; // + sizeof(struct cbfs_optionrom);
+ return cbfs_locate(fh, &cbfs, name, type);
+}
- if (! dest)
- return src;
+void *cbfs_boot_map_with_leak(const char *name, uint32_t type, size_t *size)
+{
+ struct region_device fh;
+ size_t fsize;
- if (!cbfs_decompress(ntohl(orom->compression),
- src,
- dest,
- ntohl(orom->len)))
+ if (cbfs_boot_locate(&fh, name, &type))
return NULL;
- return dest;
+ fsize = region_device_sz(&fh);
+
+ if (size != NULL)
+ *size = fsize;
+
+ return rdev_mmap(&fh, 0, fsize);
}
-int cbfs_load_prog_stage_by_offset(struct cbfs_media *media,
- struct prog *prog, ssize_t offset)
+int cbfs_locate(struct region_device *fh, const struct cbfsd *cbfs,
+ const char *name, uint32_t *type)
{
- struct cbfs_stage stage;
- struct cbfs_media backing_store;
+ size_t offset;
+ const struct region_device *rd;
+ size_t align;
+
+ offset = 0;
+ rd = cbfs->rdev;
+ align = cbfs->align;
+
+ LOG("Locating '%s'\n", name);
+
+ /* Try to scan the entire cbfs region looking for file name. */
+ while (1) {
+ struct cbfs_file file;
+ const size_t fsz = sizeof(file);
+ char *fname;
+ int name_match;
+ size_t datasz;
+
+ DEBUG("Checking offset %zx\n", offset);
+
+ /* Can't read file. Nothing else to do but bail out. */
+ if (rdev_readat(rd, &file, offset, fsz) != fsz)
+ break;
+
+ if (memcmp(file.magic, CBFS_FILE_MAGIC, sizeof(file.magic))) {
+ offset++;
+ offset = ALIGN_UP(offset, align);
+ continue;
+ }
- if (init_backing_media(&media, &backing_store))
- return -1;
+ file.len = ntohl(file.len);
+ file.type = ntohl(file.type);
+ file.offset = ntohl(file.offset);
- if (cbfs_read(media, &stage, offset, sizeof(stage)) != sizeof(stage)) {
- ERROR("ERROR: failed to read stage header\n");
- return -1;
- }
+ /* See if names match. */
+ fname = rdev_mmap(rd, offset + fsz, file.offset - fsz);
- LOG("loading stage from %#zx @ 0x%llx (%d bytes), entry @ 0x%llx\n",
- offset, stage.load, stage.memlen, stage.entry);
+ if (fname == NULL)
+ break;
- /* Stages rely the below clearing so that the bss is initialized. */
- memset((void *)(uintptr_t)stage.load, 0, stage.memlen);
+ name_match = !strcmp(fname, name);
+ rdev_munmap(rd, fname);
- if (stage.compression == CBFS_COMPRESS_NONE) {
- if (cbfs_read(media, (void *)(uintptr_t)stage.load,
- offset + sizeof(stage), stage.len) != stage.len) {
- ERROR("ERROR: Reading stage failed.\n");
- return -1;
+ if (!name_match) {
+ DEBUG(" Unmatched '%s' at %zx\n", fname, offset);
+ offset += file.offset + file.len;
+ offset = ALIGN_UP(offset, align);
+ continue;
}
- } else {
- void *data = media->map(media, offset + sizeof(stage),
- stage.len);
- if (data == CBFS_MEDIA_INVALID_MAP_ADDRESS) {
- ERROR("ERROR: Mapping stage failed.\n");
- return -1;
+
+ if (type != NULL && *type != file.type) {
+ DEBUG(" Unmatched type %x at %zx\n", file.type, offset);
+ offset += file.offset + file.len;
+ offset = ALIGN_UP(offset, align);
+ continue;
}
- if (!cbfs_decompress(stage.compression, data,
- (void *)(uintptr_t)stage.load, stage.len))
- return -1;
- media->unmap(media, data);
- }
- arch_segment_loaded(stage.load, stage.memlen, SEG_FINAL);
- DEBUG("stage loaded\n");
+ LOG("Found @ offset %zx size %x\n", offset, file.len);
+ /* File and type match. Create a chained region_device to
+ * represent the cbfs file. */
+ offset += file.offset;
+ datasz = file.len;
+ if (rdev_chain(fh, rd, offset, datasz))
+ break;
- prog_set_area(prog, (void *)(uintptr_t)stage.load, stage.memlen);
- prog_set_entry(prog, (void *)(uintptr_t)stage.entry, NULL);
+ /* Success. */
+ return 0;
+ }
- return 0;
+ LOG("'%s' not found.\n", name);
+ return -1;
}
-int cbfs_load_prog_stage(struct cbfs_media *media, struct prog *prog)
+static size_t inflate(void *src, void *dst)
{
- struct cbfs_file file;
- ssize_t offset;
- struct cbfs_media backing_store;
-
- if (init_backing_media(&media, &backing_store))
- return -1;
-
- offset = cbfs_locate_file(media, &file, prog->name);
- if (offset < 0 || file.type != CBFS_TYPE_STAGE)
- return -1;
+ if (ENV_BOOTBLOCK || ENV_VERSTAGE)
+ return 0;
+ if (ENV_ROMSTAGE && !IS_ENABLED(CONFIG_COMPRESS_RAMSTAGE))
+ return 0;
+ return ulzma(src, dst);
+}
- if (cbfs_load_prog_stage_by_offset(media, prog, offset) < 0)
- return -1;
+static inline int tohex4(unsigned int c)
+{
+ return (c <= 9) ? (c + '0') : (c - 10 + 'a');
+}
- return 0;
+static void tohex16(unsigned int 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);
}
-void *cbfs_load_stage_by_offset(struct cbfs_media *media, ssize_t offset)
+void *cbfs_boot_map_optionrom(uint16_t vendor, uint16_t device)
{
- struct prog prog = {
- .name = NULL,
- };
+ char name[17] = "pciXXXX,XXXX.rom";
- if (cbfs_load_prog_stage_by_offset(media, &prog, offset) < 0)
- return (void *)-1;
+ tohex16(vendor, name+3);
+ tohex16(device, name+8);
- return prog_entry(&prog);
+ return cbfs_boot_map_with_leak(name, CBFS_TYPE_OPTIONROM, NULL);
}
-void *cbfs_load_stage(struct cbfs_media *media, const char *name)
+void *cbfs_boot_load_stage_by_name(const char *name)
{
- struct prog prog = {
+ struct prog stage = {
.name = name,
};
+ uint32_t type = CBFS_TYPE_STAGE;
- if (cbfs_load_prog_stage(media, &prog) < 0)
- return (void *)-1;
+ if (cbfs_boot_locate(&stage.rdev, name, &type))
+ return NULL;
- return prog_entry(&prog);
-}
+ if (cbfs_prog_stage_load(&stage))
+ return NULL;
-/* Simple buffer */
-
-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) {
- ERROR("simple_buffer: no room to map %zd bytes from %#zx\n",
- count, offset);
- 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;
+ return prog_entry(&stage);
}
-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;
-}
+int cbfs_prog_stage_load(struct prog *pstage)
+{
+ struct cbfs_stage stage;
+ uint8_t *load;
+ void *entry;
+ size_t fsize;
+ size_t foffset;
+ const struct region_device *fh = &pstage->rdev;
-#endif
+ if (rdev_readat(fh, &stage, 0, sizeof(stage)) != sizeof(stage))
+ return 0;
+
+ fsize = region_device_sz(fh);
+ fsize -= sizeof(stage);
+ foffset = 0;
+ foffset += sizeof(stage);
+
+ assert(fsize == stage.len);
+
+ /* Note: cbfs_stage fields are currently in the endianness of the
+ * running processor. */
+ load = (void *)(uintptr_t)stage.load;
+ entry = (void *)(uintptr_t)stage.entry;
+
+ if (stage.compression == CBFS_COMPRESS_NONE) {
+ if (rdev_readat(fh, load, foffset, fsize) != fsize)
+ return -1;
+ } else if (stage.compression == CBFS_COMPRESS_LZMA) {
+ void *map = rdev_mmap(fh, foffset, fsize);
+
+ if (map == NULL)
+ return -1;
+
+ fsize = inflate(map, load);
+
+ rdev_munmap(fh, map);
+
+ if (!fsize)
+ return -1;
+ } else
+ return -1;
+
+ /* Clear area not covered by file. */
+ memset(&load[fsize], 0, stage.memlen - fsize);
+
+ arch_segment_loaded((uintptr_t)load, stage.memlen, SEG_FINAL);
+ prog_set_area(pstage, load, stage.memlen);
+ prog_set_entry(pstage, entry, NULL);
+
+ return 0;
+}
diff --git a/src/lib/cbfs_boot_props.c b/src/lib/cbfs_boot_props.c
new file mode 100644
index 0000000000..21e64d37a5
--- /dev/null
+++ b/src/lib/cbfs_boot_props.c
@@ -0,0 +1,66 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2015 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.
+ */
+
+#include <boot_device.h>
+#include <cbfs.h>
+#include <console/console.h>
+#include <endian.h>
+#include <region.h>
+
+/* This function is marked as weak to allow a particular platform to
+ * override the logic. This implementation should work for most devices. */
+int __attribute__((weak)) cbfs_boot_region_properties(struct cbfs_props *props)
+{
+ struct cbfs_header header;
+ const struct region_device *bdev;
+ int32_t rel_offset;
+ size_t offset;
+
+ bdev = boot_device_ro();
+
+ if (bdev == NULL)
+ return -1;
+
+ /* Find location of header using signed 32-bit offset from
+ * end of CBFS region. */
+ offset = CONFIG_CBFS_SIZE - sizeof(int32_t);
+ if (rdev_readat(bdev, &rel_offset, offset, sizeof(int32_t)) < 0)
+ return -1;
+
+ offset = CONFIG_CBFS_SIZE + rel_offset;
+ if (rdev_readat(bdev, &header, offset, sizeof(header)) < 0)
+ return -1;
+
+ header.magic = ntohl(header.magic);
+ header.romsize = ntohl(header.romsize);
+ header.align = ntohl(header.align);
+ header.offset = ntohl(header.offset);
+
+ if (header.magic != CBFS_HEADER_MAGIC)
+ return -1;
+
+ props->align = header.align;
+ props->offset = header.offset;
+ props->size = header.romsize;
+ props->size -= props->offset;
+
+ printk(BIOS_SPEW, "CBFS @ %zx size %zx\n", props->offset, props->size);
+
+ return 0;
+}
diff --git a/src/lib/cbfs_core.c b/src/lib/cbfs_core.c
deleted file mode 100644
index 9f45b3cedc..0000000000
--- a/src/lib/cbfs_core.c
+++ /dev/null
@@ -1,324 +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
- *
- * 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>
-#include <symbols.h>
-
-#if IS_ENABLED(CONFIG_MULTIPLE_CBFS_INSTANCES)
-void cbfs_set_header_offset(size_t offset)
-{
- _cbfs_header_offset[0] = offset;
- LOG("header set to: %#zx\n", offset);
-}
-
-static size_t get_header_offset(void)
-{
- return _cbfs_header_offset[0];
-}
-#else
-static size_t get_header_offset(void)
-{
- return 0;
-}
-#endif
-
-#include "cbfs_core.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)
-{
- size_t offset;
- 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);
-
- /* TODO: allow negative offsets from the end of the CBFS image at media
- * layer (like libpayload) so we can combine these two cases. */
- if (IS_ENABLED(CONFIG_ARCH_X86)) {
- offset = *(int32_t *)(uintptr_t)0xfffffffc;
- header = media->map(media, offset, sizeof(*header));
- } else {
-
- offset = get_header_offset();
-
- if (!offset) {
- int32_t rel_offset;
- size_t cbfs_top = CONFIG_CBFS_SIZE;
- DEBUG("CBFS top at offset: 0x%zx\n", cbfs_top);
- if (!media->read(media, &rel_offset, cbfs_top -
- sizeof(int32_t),
- sizeof(int32_t))) {
- ERROR("Could not read master header offset!\n");
- media->close(media);
- return CBFS_HEADER_INVALID_ADDRESS;
- }
- offset = cbfs_top + rel_offset;
- }
- header = media->map(media, offset, sizeof(*header));
- }
- DEBUG("CBFS header offset: 0x%zx/0x%x\n", offset, CONFIG_ROM_SIZE);
- media->close(media);
-
- if (header == CBFS_MEDIA_INVALID_MAP_ADDRESS) {
- ERROR("Failed to load CBFS header from 0x%zx\n", offset);
- return CBFS_HEADER_INVALID_ADDRESS;
- }
-
- if (CBFS_HEADER_MAGIC != ntohl(header->magic)) {
- ERROR("Could not find valid CBFS master header at %#zx: "
- "magic %#.8x vs %#.8x.\n", offset, 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;
-}
-
-
-int init_backing_media(struct cbfs_media **media, struct cbfs_media *backing)
-{
- if (*media == CBFS_DEFAULT_MEDIA) {
- *media = backing;
- if (init_default_cbfs_media(*media) != 0) {
- ERROR("Failed to initialize default media.\n");
- return -1;
- }
- }
- return 0;
-}
-
-/* public API starts here*/
-ssize_t cbfs_locate_file(struct cbfs_media *media, struct cbfs_file *file,
- const char *name)
-{
- const char *file_name;
- uint32_t offset, align, romsize, name_len;
- const struct cbfs_header *header;
- struct cbfs_media default_media;
-
- if (init_backing_media(&media, &default_media))
- return -1;
-
- if (CBFS_HEADER_INVALID_ADDRESS == (header = cbfs_get_header(media)))
- return -1;
-
- // 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
- // resolve actual length of ROM used for CBFS components
- // the bootblock size was not taken into account
- romsize -= ntohl(header->bootblocksize);
-
- // fine tune the length to handle alignment positioning.
- // using (bootblock size) % align, to derive the
- // number of bytes the bootblock is off from the alignment size.
- if ((ntohl(header->bootblocksize) % align))
- romsize -= (align - (ntohl(header->bootblocksize) % align));
- else
- romsize -= 1;
-#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);
- LOG("WARNING: No file header found at 0x%x - "
- "try next aligned address: 0x%x.\n", offset,
- offset + new_align);
- offset += new_align;
- continue;
- }
-
- file->len = ntohl(file->len);
- file->type= ntohl(file->type);
- file->offset = ntohl(file->offset);
-
- name_len = 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) {
- DEBUG("Found file (offset=0x%x, len=%d).\n",
- offset + file->offset, file->len);
- media->unmap(media, file_name);
- return offset + file->offset;
- } else {
- DEBUG(" (unmatched file @0x%x: %s)\n", offset,
- file_name);
- media->unmap(media, file_name);
- }
-
- // Move to next file.
- offset += file->len + file->offset;
- if (offset % align)
- offset += align - (offset % align);
- }
- media->close(media);
- LOG("WARNING: '%s' not found.\n", name);
- return -1;
-}
-
-size_t cbfs_read(struct cbfs_media *media, void *dest, size_t offset,
- size_t count)
-{
- struct cbfs_media default_media;
- size_t nread;
-
- if (init_backing_media(&media, &default_media))
- return 0;
-
- media->open(media);
- nread = media->read(media, dest, offset, count);
- media->close(media);
-
- return nread;
-}
-
-struct cbfs_file *cbfs_get_file(struct cbfs_media *media, const char *name)
-{
- struct cbfs_media default_media;
- struct cbfs_file file, *file_ptr;
- ssize_t offset;
-
- if (init_backing_media(&media, &default_media))
- return NULL;
-
- offset = cbfs_locate_file(media, &file, name);
- if (offset < 0)
- return NULL;
-
- /* Map both the metadata and the file contents. */
- media->open(media);
- offset -= file.offset;
- file_ptr = media->map(media, offset, file.offset + file.len);
- media->close(media);
-
- if (file_ptr == CBFS_MEDIA_INVALID_MAP_ADDRESS) {
- ERROR("ERROR: Mapping %s failed.\n", name);
- return NULL;
- }
-
- return file_ptr;
-}
-
-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 && ((uintptr_t)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/cbfs_core.h b/src/lib/cbfs_core.h
deleted file mode 100644
index f9aeaa8069..0000000000
--- a/src/lib/cbfs_core.h
+++ /dev/null
@@ -1,47 +0,0 @@
-#ifndef __LIB_CBFS_CORE
-#define __LIB_CBFS_CORE
-
-#include <cbfs.h>
-#include <string.h>
-
-#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(__BOOTBLOCK__)
- /* No LZMA in boot block. */
-#elif defined(__VERSTAGE__)
- /* No LZMA in verstage. */
-#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>
-#endif
-
-#include <cbfs.h>
-#include <string.h>
-#include <cbmem.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
-
-#endif /* __LIB_CBFS_CORE */
diff --git a/src/lib/cbfs_spi.c b/src/lib/cbfs_spi.c
index 6758220dfd..5b5aaff053 100644
--- a/src/lib/cbfs_spi.c
+++ b/src/lib/cbfs_spi.c
@@ -24,8 +24,6 @@
*/
#include <boot_device.h>
-#include <cbfs.h>
-#include <region.h>
#include <spi_flash.h>
#include <symbols.h>
@@ -69,73 +67,3 @@ const struct region_device *boot_device_ro(void)
return &mdev.rdev;
}
-
-static int cbfs_media_open(struct cbfs_media *media)
-{
- return 0;
-}
-
-static int cbfs_media_close(struct cbfs_media *media)
-{
- return 0;
-}
-
-static size_t cbfs_media_read(struct cbfs_media *media,
- void *dest, size_t offset,
- size_t count)
-{
- const struct region_device *boot_dev;
-
- boot_dev = media->context;
-
- if (rdev_readat(boot_dev, dest, offset, count) < 0)
- return 0;
-
- return count;
-}
-
-static void *cbfs_media_map(struct cbfs_media *media,
- size_t offset, size_t count)
-{
- const struct region_device *boot_dev;
- void *ptr;
-
- boot_dev = media->context;
-
- ptr = rdev_mmap(boot_dev, offset, count);
-
- if (ptr == NULL)
- return (void *)-1;
-
- return ptr;
-}
-
-static void *cbfs_media_unmap(struct cbfs_media *media,
- const void *address)
-{
- const struct region_device *boot_dev;
-
- boot_dev = media->context;
-
- rdev_munmap(boot_dev, (void *)address);
-
- return NULL;
-}
-
-int init_default_cbfs_media(struct cbfs_media *media)
-{
- boot_device_init();
-
- media->context = (void *)boot_device_ro();
-
- if (media->context == NULL)
- return -1;
-
- media->open = cbfs_media_open;
- media->close = cbfs_media_close;
- media->read = cbfs_media_read;
- media->map = cbfs_media_map;
- media->unmap = cbfs_media_unmap;
-
- return 0;
-}
diff --git a/src/lib/coreboot_table.c b/src/lib/coreboot_table.c
index b1fbef6026..f7fb2bb54a 100644
--- a/src/lib/coreboot_table.c
+++ b/src/lib/coreboot_table.c
@@ -396,8 +396,8 @@ unsigned long write_coreboot_table(
#if CONFIG_USE_OPTION_TABLE
{
- struct cmos_option_table *option_table = cbfs_get_file_content(
- CBFS_DEFAULT_MEDIA, "cmos_layout.bin",
+ struct cmos_option_table *option_table =
+ cbfs_boot_map_with_leak("cmos_layout.bin",
CBFS_COMPONENT_CMOS_LAYOUT, NULL);
if (option_table) {
struct lb_record *rec_dest = lb_new_record(head);
diff --git a/src/lib/hardwaremain.c b/src/lib/hardwaremain.c
index 80f677695c..56f3f29f97 100644
--- a/src/lib/hardwaremain.c
+++ b/src/lib/hardwaremain.c
@@ -228,8 +228,6 @@ static boot_state_t bs_write_tables(void *arg)
static boot_state_t bs_payload_load(void *arg)
{
- timestamp_add_now(TS_LOAD_PAYLOAD);
-
payload_load();
return BS_PAYLOAD_BOOT;
diff --git a/src/lib/loaders/Makefile.inc b/src/lib/loaders/Makefile.inc
deleted file mode 100644
index ef5af6a7aa..0000000000
--- a/src/lib/loaders/Makefile.inc
+++ /dev/null
@@ -1,27 +0,0 @@
-#
-# 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.
-#
-
-bootblock-y += load_and_run_romstage.c
-bootblock-y += cbfs_romstage_loader.c
-romstage-y += cbfs_ramstage_loader.c
-romstage-y += load_and_run_ramstage.c
-ramstage-y += cbfs_payload_loader.c
-ramstage-y += load_and_run_payload.c
-verstage-y += cbfs_romstage_loader.c
-verstage-y += load_and_run_romstage.c
diff --git a/src/lib/loaders/cbfs_payload_loader.c b/src/lib/loaders/cbfs_payload_loader.c
deleted file mode 100644
index 8e790a2952..0000000000
--- a/src/lib/loaders/cbfs_payload_loader.c
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * 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.
- */
-
-#include <cbfs.h>
-#include <program_loading.h>
-
-static int cbfs_locate_payload(struct prog *payload)
-{
- void *buffer;
- size_t size;
- const int type = CBFS_TYPE_PAYLOAD;
-
- buffer = cbfs_get_file_content(CBFS_DEFAULT_MEDIA, payload->name,
- type, &size);
-
- if (buffer == NULL)
- return -1;
-
- prog_set_area(payload, buffer, size);
-
- return 0;
-}
-
-const struct prog_loader_ops cbfs_payload_loader = {
- .name = "CBFS",
- .prepare = cbfs_locate_payload,
-};
diff --git a/src/lib/loaders/cbfs_ramstage_loader.c b/src/lib/loaders/cbfs_ramstage_loader.c
deleted file mode 100644
index acbc6c0afe..0000000000
--- a/src/lib/loaders/cbfs_ramstage_loader.c
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * This file is part of the coreboot project.
- *
- * Copyright (C) 2008-2009 coresystems GmbH
- * 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.
- */
-#include <console/console.h>
-#include <cbfs.h>
-#include <program_loading.h>
-
-#if CONFIG_RELOCATABLE_RAMSTAGE
-#include <rmodule.h>
-#include <cbmem.h>
-
-static int cbfs_load_ramstage(struct prog *ramstage)
-{
- struct rmod_stage_load rmod_ram = {
- .cbmem_id = CBMEM_ID_RAMSTAGE,
- .prog = ramstage,
- };
-
- if (rmodule_stage_load_from_cbfs(&rmod_ram)) {
- printk(BIOS_DEBUG, "Could not load ramstage.\n");
- return -1;
- }
-
- return 0;
-}
-
-#else /* CONFIG_RELOCATABLE_RAMSTAGE */
-
-static int cbfs_load_ramstage(struct prog *ramstage)
-{
- return cbfs_load_prog_stage(CBFS_DEFAULT_MEDIA, ramstage);
-
-}
-
-#endif /* CONFIG_RELOCATABLE_RAMSTAGE */
-
-const struct prog_loader_ops cbfs_ramstage_loader = {
- .name = "CBFS",
- .prepare = cbfs_load_ramstage,
-};
diff --git a/src/lib/loaders/cbfs_romstage_loader.c b/src/lib/loaders/cbfs_romstage_loader.c
deleted file mode 100644
index e5b42158f8..0000000000
--- a/src/lib/loaders/cbfs_romstage_loader.c
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * This file is part of the coreboot project.
- *
- * Copyright 2015 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.
- */
-
-#include <cbfs.h>
-#include <program_loading.h>
-
-static int cbfs_load_romstage(struct prog *romstage)
-{
- return cbfs_load_prog_stage(CBFS_DEFAULT_MEDIA, romstage);
-}
-
-const struct prog_loader_ops cbfs_romstage_loader = {
- .name = "CBFS",
- .prepare = cbfs_load_romstage,
-};
diff --git a/src/lib/loaders/load_and_run_payload.c b/src/lib/loaders/load_and_run_payload.c
deleted file mode 100644
index 6616110319..0000000000
--- a/src/lib/loaders/load_and_run_payload.c
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * 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.
- */
-
-#include <stdint.h>
-#include <stdlib.h>
-#include <cbmem.h>
-#include <console/console.h>
-#include <fallback.h>
-#include <lib.h>
-#include <program_loading.h>
-#include <symbols.h>
-#include <timestamp.h>
-
-extern const struct prog_loader_ops vboot_loader;
-extern const struct prog_loader_ops cbfs_payload_loader;
-
-static const struct prog_loader_ops *payload_ops[] = {
-#if CONFIG_VBOOT_VERIFY_FIRMWARE
- &vboot_loader,
-#endif
- &cbfs_payload_loader,
-};
-
-static struct prog global_payload = {
- .name = CONFIG_CBFS_PREFIX "/payload",
- .type = PROG_PAYLOAD,
-};
-
-void __attribute__((weak)) mirror_payload(struct prog *payload)
-{
- return;
-}
-
-void payload_load(void)
-{
- int i;
- const struct prog_loader_ops *ops;
- struct prog *payload = &global_payload;
-
- for (i = 0; i < ARRAY_SIZE(payload_ops); i++) {
- /* Default loader state is active. */
- int ret = 1;
-
- ops = payload_ops[i];
-
- if (ops->is_loader_active != NULL)
- ret = ops->is_loader_active(payload);
-
- if (ret == 0) {
- printk(BIOS_DEBUG, "%s payload loader inactive.\n",
- ops->name);
- continue;
- } else if (ret < 0) {
- printk(BIOS_DEBUG, "%s payload loader failure.\n",
- ops->name);
- continue;
- }
-
- if (ops->prepare(payload) < 0) {
- printk(BIOS_DEBUG, "%s: could not locate payload.\n",
- ops->name);
- continue;
- }
- printk(BIOS_DEBUG, "%s: located payload @ %p, %zu bytes.\n",
- ops->name, prog_start(payload), prog_size(payload));
- break;
- }
-
- if (i == ARRAY_SIZE(payload_ops))
- goto out;
-
- mirror_payload(payload);
-
- /* Pass cbtables to payload if architecture desires it. */
- prog_set_entry(payload, selfload(payload),
- cbmem_find(CBMEM_ID_CBTABLE));
-
-out:
- if (prog_entry(payload) == NULL)
- die("Payload not loaded.\n");
-}
-
-void payload_run(void)
-{
- struct prog *payload = &global_payload;
-
- /* Reset to booting from this image as late as possible */
- boot_successful();
-
- printk(BIOS_DEBUG, "Jumping to boot code at %p(%p)\n",
- prog_entry(payload), prog_entry_arg(payload));
- post_code(POST_ENTER_ELF_BOOT);
-
- timestamp_add_now(TS_SELFBOOT_JUMP);
-
- /* Before we go off to run the payload, see if
- * we stayed within our bounds.
- */
- checkstack(_estack, 0);
-
- prog_run(payload);
-}
diff --git a/src/lib/loaders/load_and_run_ramstage.c b/src/lib/loaders/load_and_run_ramstage.c
deleted file mode 100644
index 47637b85fc..0000000000
--- a/src/lib/loaders/load_and_run_ramstage.c
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * 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.
- */
-
-#include <stdlib.h>
-#include <console/console.h>
-#include <arch/stages.h>
-#include <cbfs.h>
-#include <program_loading.h>
-#include <romstage_handoff.h>
-#include <stage_cache.h>
-#include <timestamp.h>
-
-extern const struct prog_loader_ops cbfs_ramstage_loader;
-extern const struct prog_loader_ops vboot_loader;
-
-static const struct prog_loader_ops *loaders[] = {
-#if CONFIG_VBOOT_VERIFY_FIRMWARE
- &vboot_loader,
-#endif
- &cbfs_ramstage_loader,
-};
-
-void __attribute__((weak)) stage_cache_add(int stage_id, struct prog *stage) {}
-void __attribute__((weak)) stage_cache_load_stage(int stage_id,
- struct prog *stage) {}
-void __attribute__((weak)) ramstage_cache_invalid(void) {}
-
-static void load_ramstage(const struct prog_loader_ops *ops,
- struct prog *ramstage)
-{
- timestamp_add_now(TS_START_COPYRAM);
-
- if (ops->prepare(ramstage))
- return;
-
- stage_cache_add(STAGE_RAMSTAGE, ramstage);
-
- timestamp_add_now(TS_END_COPYRAM);
-
- prog_run(ramstage);
-}
-
-static void run_ramstage_from_resume(struct romstage_handoff *handoff,
- struct prog *ramstage)
-{
- if (handoff != NULL && handoff->s3_resume) {
- /* Load the cached ramstage to runtime location. */
- stage_cache_load_stage(STAGE_RAMSTAGE, ramstage);
-
- if (prog_entry(ramstage) != NULL) {
- printk(BIOS_DEBUG, "Jumping to image.\n");
- prog_run(ramstage);
- }
- ramstage_cache_invalid();
- }
-}
-
-void run_ramstage(void)
-{
- const struct prog_loader_ops *ops;
- int i;
- struct prog ramstage = {
- .name = CONFIG_CBFS_PREFIX "/ramstage",
- .type = PROG_RAMSTAGE,
- };
-
- run_ramstage_from_resume(romstage_handoff_find_or_add(), &ramstage);
-
- for (i = 0; i < ARRAY_SIZE(loaders); i++) {
- /* Default loader state is active. */
- int ret = 1;
-
- ops = loaders[i];
-
- if (ops->is_loader_active != NULL)
- ret = ops->is_loader_active(&ramstage);
-
- if (ret == 0) {
- printk(BIOS_DEBUG, "%s ramstage loader inactive.\n",
- ops->name);
- continue;
- } else if (ret < 0) {
- printk(BIOS_DEBUG, "%s ramstage loader failure.\n",
- ops->name);
- continue;
- }
-
- printk(BIOS_DEBUG, "%s ramstage loader active.\n", ops->name);
- load_ramstage(ops, &ramstage);
- }
-
- die("Ramstage was not loaded!\n");
-}
diff --git a/src/lib/loaders/load_and_run_romstage.c b/src/lib/loaders/load_and_run_romstage.c
deleted file mode 100644
index dfcb8597dc..0000000000
--- a/src/lib/loaders/load_and_run_romstage.c
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * This file is part of the coreboot project.
- *
- * Copyright 2015 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.
- */
-
-
-#include <stdlib.h>
-#include <console/console.h>
-#include <arch/stages.h>
-#include <cbfs.h>
-#include <halt.h>
-#include <program_loading.h>
-#include <rules.h>
-#include <timestamp.h>
-
-extern const struct prog_loader_ops cbfs_romstage_loader;
-extern const struct prog_loader_ops vboot_loader;
-
-static const struct prog_loader_ops *loaders[] = {
-#if CONFIG_VBOOT_VERIFY_FIRMWARE
- &vboot_loader,
-#endif
-#if !ENV_VERSTAGE || (ENV_VERSTAGE && !CONFIG_RETURN_FROM_VERSTAGE)
- &cbfs_romstage_loader,
-#endif
-};
-
-void run_romstage(void)
-{
- int i;
- struct prog romstage = {
- .name = CONFIG_CBFS_PREFIX "/romstage",
- .type = PROG_ROMSTAGE,
- };
-
- for (i = 0; i < ARRAY_SIZE(loaders); i++) {
- /* Default loader state is active. */
- int ret = 1;
- const struct prog_loader_ops *ops;
-
- ops = loaders[i];
-
- if (ops->is_loader_active != NULL)
- ret = ops->is_loader_active(&romstage);
-
- if (ret == 0) {
- printk(BIOS_DEBUG, "%s romstage loader inactive.\n",
- ops->name);
- continue;
- } else if (ret < 0) {
- printk(BIOS_DEBUG, "%s romstage loader failure.\n",
- ops->name);
- continue;
- }
-
- printk(BIOS_DEBUG, "%s romstage loader active.\n", ops->name);
-
- timestamp_add_now(TS_START_COPYROM);
-
- if (ops->prepare(&romstage))
- continue;
-
- timestamp_add_now(TS_END_COPYROM);
-
- prog_run(&romstage);
- }
-
- if (IS_ENABLED(CONFIG_BOOTBLOCK_CONSOLE))
- die("Couldn't load romstage.\n");
- halt();
-}
diff --git a/src/lib/prog_loaders.c b/src/lib/prog_loaders.c
new file mode 100644
index 0000000000..881cd99794
--- /dev/null
+++ b/src/lib/prog_loaders.c
@@ -0,0 +1,247 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2015 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.
+ */
+
+
+#include <stdlib.h>
+#include <arch/stages.h>
+#include <boot_device.h>
+#include <cbfs.h>
+#include <cbmem.h>
+#include <console/console.h>
+#include <fallback.h>
+#include <halt.h>
+#include <lib.h>
+#include <program_loading.h>
+#include <romstage_handoff.h>
+#include <rmodule.h>
+#include <rules.h>
+#include <stage_cache.h>
+#include <symbols.h>
+#include <timestamp.h>
+
+#define DEFAULT_CBFS_LOADER_PRESENT \
+ (!ENV_VERSTAGE || (ENV_VERSTAGE && !CONFIG_RETURN_FROM_VERSTAGE))
+
+#if DEFAULT_CBFS_LOADER_PRESENT
+static int cbfs_boot_prog_locate(struct prog *prog)
+{
+ return cbfs_boot_locate(&prog->rdev, prog->name, NULL);
+}
+
+static const struct prog_loader_ops cbfs_default_loader = {
+ .locate = cbfs_boot_prog_locate,
+};
+#endif
+
+extern const struct prog_loader_ops vboot_loader;
+
+static const struct prog_loader_ops *loaders[] = {
+#if CONFIG_VBOOT_VERIFY_FIRMWARE
+ &vboot_loader,
+#endif
+#if DEFAULT_CBFS_LOADER_PRESENT
+ &cbfs_default_loader,
+#endif
+};
+
+int prog_locate(struct prog *prog)
+{
+ int i;
+
+ boot_device_init();
+
+ for (i = 0; i < ARRAY_SIZE(loaders); i++) {
+ /* Default loader state is active. */
+ int ret = 1;
+ const struct prog_loader_ops *ops;
+
+ ops = loaders[i];
+
+ if (ops->is_loader_active != NULL)
+ ret = ops->is_loader_active(prog);
+
+ if (ret == 0) {
+ printk(BIOS_DEBUG, "%s loader inactive.\n",
+ ops->name);
+ continue;
+ } else if (ret < 0) {
+ printk(BIOS_DEBUG, "%s loader failure.\n",
+ ops->name);
+ continue;
+ }
+
+ printk(BIOS_DEBUG, "%s loader active.\n", ops->name);
+
+ if (ops->locate(prog))
+ continue;
+
+ printk(BIOS_DEBUG, "'%s' located at offset: %zx size: %zx\n",
+ prog->name, region_device_offset(&prog->rdev),
+ region_device_sz(&prog->rdev));
+
+ return 0;
+ }
+
+ return -1;
+}
+
+void run_romstage(void)
+{
+ struct prog romstage = {
+ .name = CONFIG_CBFS_PREFIX "/romstage",
+ .type = PROG_ROMSTAGE,
+ };
+
+ /* The only time the default CBFS loader isn't present is during
+ * VERSTAGE in which it returns back to the calling stage. */
+ if (!DEFAULT_CBFS_LOADER_PRESENT)
+ return;
+
+ if (prog_locate(&romstage))
+ goto fail;
+
+ timestamp_add_now(TS_START_COPYROM);
+
+ if (cbfs_prog_stage_load(&romstage))
+ goto fail;
+
+ timestamp_add_now(TS_END_COPYROM);
+
+ prog_run(&romstage);
+
+fail:
+ if (IS_ENABLED(CONFIG_BOOTBLOCK_CONSOLE))
+ die("Couldn't load romstage.\n");
+ halt();
+}
+
+void __attribute__((weak)) stage_cache_add(int stage_id, struct prog *stage) {}
+void __attribute__((weak)) stage_cache_load_stage(int stage_id,
+ struct prog *stage) {}
+void __attribute__((weak)) ramstage_cache_invalid(void) {}
+
+static void run_ramstage_from_resume(struct romstage_handoff *handoff,
+ struct prog *ramstage)
+{
+ if (handoff != NULL && handoff->s3_resume) {
+ /* Load the cached ramstage to runtime location. */
+ stage_cache_load_stage(STAGE_RAMSTAGE, ramstage);
+
+ if (prog_entry(ramstage) != NULL) {
+ printk(BIOS_DEBUG, "Jumping to image.\n");
+ prog_run(ramstage);
+ }
+ ramstage_cache_invalid();
+ }
+}
+
+static int load_relocatable_ramstage(struct prog *ramstage)
+{
+ struct rmod_stage_load rmod_ram = {
+ .cbmem_id = CBMEM_ID_RAMSTAGE,
+ .prog = ramstage,
+ };
+
+ return rmodule_stage_load(&rmod_ram);
+}
+
+void run_ramstage(void)
+{
+ struct prog ramstage = {
+ .name = CONFIG_CBFS_PREFIX "/ramstage",
+ .type = PROG_RAMSTAGE,
+ };
+
+ /* Only x86 systems currently take the same firmware path on resume. */
+ if (IS_ENABLED(CONFIG_ARCH_X86) && IS_ENABLED(CONFIG_EARLY_CBMEM_INIT))
+ run_ramstage_from_resume(romstage_handoff_find_or_add(),
+ &ramstage);
+
+ if (prog_locate(&ramstage))
+ goto fail;
+
+ timestamp_add_now(TS_START_COPYRAM);
+
+ if (IS_ENABLED(CONFIG_RELOCATABLE_RAMSTAGE)) {
+ if (load_relocatable_ramstage(&ramstage))
+ goto fail;
+ } else if (cbfs_prog_stage_load(&ramstage))
+ goto fail;
+
+ stage_cache_add(STAGE_RAMSTAGE, &ramstage);
+
+ timestamp_add_now(TS_END_COPYRAM);
+
+ prog_run(&ramstage);
+
+fail:
+ die("Ramstage was not loaded!\n");
+}
+
+static struct prog global_payload = {
+ .name = CONFIG_CBFS_PREFIX "/payload",
+ .type = PROG_PAYLOAD,
+};
+
+void __attribute__((weak)) mirror_payload(struct prog *payload)
+{
+ return;
+}
+
+void payload_load(void)
+{
+ struct prog *payload = &global_payload;
+
+ timestamp_add_now(TS_LOAD_PAYLOAD);
+
+ if (prog_locate(payload))
+ goto out;
+
+ mirror_payload(payload);
+
+ /* Pass cbtables to payload if architecture desires it. */
+ prog_set_entry(payload, selfload(payload),
+ cbmem_find(CBMEM_ID_CBTABLE));
+
+out:
+ if (prog_entry(payload) == NULL)
+ die("Payload not loaded.\n");
+}
+
+void payload_run(void)
+{
+ struct prog *payload = &global_payload;
+
+ /* Reset to booting from this image as late as possible */
+ boot_successful();
+
+ printk(BIOS_DEBUG, "Jumping to boot code at %p(%p)\n",
+ prog_entry(payload), prog_entry_arg(payload));
+
+ post_code(POST_ENTER_ELF_BOOT);
+
+ timestamp_add_now(TS_SELFBOOT_JUMP);
+
+ /* Before we go off to run the payload, see if
+ * we stayed within our bounds.
+ */
+ checkstack(_estack, 0);
+
+ prog_run(payload);
+}
diff --git a/src/lib/rmodule.c b/src/lib/rmodule.c
index 359272fc2b..35893d9d96 100644
--- a/src/lib/rmodule.c
+++ b/src/lib/rmodule.c
@@ -22,6 +22,7 @@
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
+#include <lib.h>
#include <console/console.h>
#include <program_loading.h>
#include <rmodule.h>
@@ -252,34 +253,60 @@ int rmodule_calc_region(unsigned int region_alignment, size_t rmodule_size,
return region_alignment - sizeof(struct rmodule_header);
}
-int rmodule_stage_load(struct rmod_stage_load *rsl, struct cbfs_stage *stage)
+int rmodule_stage_load(struct rmod_stage_load *rsl)
{
struct rmodule rmod_stage;
size_t region_size;
char *stage_region;
int rmodule_offset;
int load_offset;
+ struct cbfs_stage stage;
+ void *rmod_loc;
+ struct region_device *fh;
- if (stage == NULL || rsl->prog == NULL || rsl->prog->name == NULL)
+ if (rsl->prog == NULL || rsl->prog->name == NULL)
+ return -1;
+
+ fh = &rsl->prog->rdev;
+
+ if (rdev_readat(fh, &stage, 0, sizeof(stage)) != sizeof(stage))
return -1;
rmodule_offset =
rmodule_calc_region(DYN_CBMEM_ALIGN_SIZE,
- stage->memlen, &region_size, &load_offset);
+ stage.memlen, &region_size, &load_offset);
stage_region = cbmem_add(rsl->cbmem_id, region_size);
if (stage_region == NULL)
return -1;
+ rmod_loc = &stage_region[rmodule_offset];
+
printk(BIOS_INFO, "Decompressing stage %s @ 0x%p (%d bytes)\n",
- rsl->prog->name, &stage_region[rmodule_offset], stage->memlen);
+ rsl->prog->name, rmod_loc, stage.memlen);
+
+ if (stage.compression == CBFS_COMPRESS_NONE) {
+ if (rdev_readat(fh, rmod_loc, sizeof(stage), stage.len) !=
+ stage.len)
+ return -1;
+ } else if (stage.compression == CBFS_COMPRESS_LZMA) {
+ size_t fsize;
+ void *map = rdev_mmap(fh, sizeof(stage), stage.len);
+
+ if (map == NULL)
+ return -1;
+
+ fsize = ulzma(map, rmod_loc);
+
+ rdev_munmap(fh, map);
- if (!cbfs_decompress(stage->compression, &stage[1],
- &stage_region[rmodule_offset], stage->len))
+ if (!fsize)
+ return -1;
+ } else
return -1;
- if (rmodule_parse(&stage_region[rmodule_offset], &rmod_stage))
+ if (rmodule_parse(rmod_loc, &rmod_stage))
return -1;
if (rmodule_load(&stage_region[load_offset], &rmod_stage))
@@ -291,16 +318,3 @@ 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)
-{
- struct cbfs_stage *stage;
-
- stage = cbfs_get_file_content(CBFS_DEFAULT_MEDIA,
- rsl->prog->name, CBFS_TYPE_STAGE, NULL);
-
- if (stage == NULL)
- return -1;
-
- return rmodule_stage_load(rsl, stage);
-}
diff --git a/src/lib/selfboot.c b/src/lib/selfboot.c
index 06c0f601b4..3f8cc6fb18 100644
--- a/src/lib/selfboot.c
+++ b/src/lib/selfboot.c
@@ -211,13 +211,11 @@ static int relocate_segment(unsigned long buffer, struct segment *seg)
static int build_self_segment_list(
struct segment *head,
- struct prog *payload, uintptr_t *entry)
+ struct cbfs_payload *cbfs_payload, uintptr_t *entry)
{
struct segment *new;
struct segment *ptr;
struct cbfs_payload_segment *segment, *first_segment;
- struct cbfs_payload *cbfs_payload;
- cbfs_payload = prog_start(payload);
memset(head, 0, sizeof(*head));
head->next = head->prev = head;
first_segment = segment = &cbfs_payload->segments;
@@ -447,9 +445,6 @@ static int load_self_segments(
}
}
- /* Update the payload's area with the bounce buffer information. */
- prog_set_area(payload, (void *)(uintptr_t)bounce_buffer, bounce_size);
-
return 1;
}
@@ -457,9 +452,15 @@ void *selfload(struct prog *payload)
{
uintptr_t entry = 0;
struct segment head;
+ void *data;
+
+ data = rdev_mmap_full(&payload->rdev);
+
+ if (data == NULL)
+ return NULL;
/* Preprocess the self segments */
- if (!build_self_segment_list(&head, payload, &entry))
+ if (!build_self_segment_list(&head, data, &entry))
goto out;
/* Load the segments */
@@ -468,8 +469,14 @@ void *selfload(struct prog *payload)
printk(BIOS_SPEW, "Loaded segments\n");
+ rdev_munmap(&payload->rdev, data);
+
+ /* Update the payload's area with the bounce buffer information. */
+ prog_set_area(payload, (void *)(uintptr_t)bounce_buffer, bounce_size);
+
return (void *)entry;
out:
+ rdev_munmap(&payload->rdev, data);
return NULL;
}