aboutsummaryrefslogtreecommitdiff
path: root/payloads/libpayload/libcbfs/cbfs.c
diff options
context:
space:
mode:
Diffstat (limited to 'payloads/libpayload/libcbfs/cbfs.c')
-rw-r--r--payloads/libpayload/libcbfs/cbfs.c232
1 files changed, 187 insertions, 45 deletions
diff --git a/payloads/libpayload/libcbfs/cbfs.c b/payloads/libpayload/libcbfs/cbfs.c
index 026b73c965..35e48dda27 100644
--- a/payloads/libpayload/libcbfs/cbfs.c
+++ b/payloads/libpayload/libcbfs/cbfs.c
@@ -2,6 +2,7 @@
* This file is part of the libpayload project.
*
* Copyright (C) 2011 secunet Security Networks AG
+ * Copyright (C) 2013 Google, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -26,80 +27,221 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
+#define LIBPAYLOAD
+
+#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
+#else
+# define CBFS_CORE_WITH_LZMA
+# include <lib.h>
+#endif
-#include <endian.h>
-#include <stdio.h>
-#include <string.h>
#include <cbfs.h>
+#include <string.h>
-#ifdef CONFIG_LZMA
-#define CBFS_CORE_WITH_LZMA
-#include <lzma.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
-#define ERROR(x...) printf(x)
-#define LOG(x...)
-
-static uint32_t host_virt_to_phys(void *addr);
-static void *host_phys_to_virt(uint32_t addr);
+#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
-uint32_t romstart(void);
-uint32_t romend(void);
+#include "cbfs_core.c"
-#include <arch/virtual.h>
-static uint32_t host_virt_to_phys(void *addr)
+#ifndef __SMM__
+static inline int tohex4(unsigned int c)
{
- return virt_to_phys(addr);
+ return (c <= 9) ? (c + '0') : (c - 10 + 'a');
}
-static void *host_phys_to_virt(uint32_t addr)
+static void tohex16(unsigned int val, char* dest)
{
- return phys_to_virt(addr);
+ dest[0] = tohex4(val>>12);
+ dest[1] = tohex4((val>>8) & 0xf);
+ dest[2] = tohex4((val>>4) & 0xf);
+ dest[3] = tohex4(val & 0xf);
}
-#undef virt_to_phys
-#undef phys_to_virt
-uint32_t (*virt_to_phys)(void *) = host_virt_to_phys;
-void* (*phys_to_virt)(uint32_t) = host_phys_to_virt;
+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;
+ tohex16(vendor, name+3);
+ tohex16(device, name+8);
-uint32_t _romstart = 0xffffffff;
-uint32_t _romend = 0;
+ orom = (struct cbfs_optionrom *)
+ cbfs_get_file_content(media, name, CBFS_TYPE_OPTIONROM);
-uint32_t romstart(void)
-{
- return _romstart;
+ if (orom == 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.
+ */
+
+ /* BUG: the cbfstool is (not yet) including a cbfs_optionrom header */
+ src = (uint8_t*)orom; // + sizeof(struct cbfs_optionrom);
+
+ if (! dest)
+ return src;
+
+ if (cbfs_decompress(ntohl(orom->compression),
+ src,
+ dest,
+ ntohl(orom->len)))
+ return NULL;
+
+ return dest;
}
-uint32_t romend(void)
+void * cbfs_load_stage(struct cbfs_media *media, const char *name)
{
- return _romend;
+ struct cbfs_stage *stage = (struct cbfs_stage *)
+ cbfs_get_file_content(media, name, CBFS_TYPE_STAGE);
+ /* this is a mess. There is no ntohll. */
+ /* for now, assume compatible byte order until we solve this. */
+ uint32_t entry;
+
+ if (stage == NULL)
+ return (void *) -1;
+
+ LOG("loading stage %s @ 0x%x (%d bytes), entry @ 0x%llx\n",
+ name,
+ (uint32_t) stage->load, stage->memlen,
+ stage->entry);
+ memset((void *) (uint32_t) stage->load, 0, stage->memlen);
+
+ if (cbfs_decompress(stage->compression,
+ ((unsigned char *) stage) +
+ sizeof(struct cbfs_stage),
+ (void *) (uint32_t) stage->load,
+ stage->len))
+ return (void *) -1;
+
+ DEBUG("stage loaded.\n");
+
+ entry = stage->entry;
+ // entry = ntohll(stage->entry);
+
+ return (void *) entry;
}
-#include "cbfs_core.c"
+int cbfs_execute_stage(struct cbfs_media *media, const char *name)
+{
+ struct cbfs_stage *stage = (struct cbfs_stage *)
+ cbfs_get_file_content(media, name, CBFS_TYPE_STAGE);
-static uint32_t ram_cbfs_offset;
+ if (stage == NULL)
+ return 1;
-static uint32_t ram_virt_to_phys(void *addr)
-{
- return (uint32_t)addr - ram_cbfs_offset;
+ if (ntohl(stage->compression) != CBFS_COMPRESS_NONE) {
+ LOG("Unable to run %s: Compressed file"
+ "Not supported for in-place execution\n", name);
+ return 1;
+ }
+
+ /* FIXME: This isn't right */
+ LOG("run @ %p\n", (void *) ntohl((uint32_t) stage->entry));
+ return run_address((void *)(uintptr_t)ntohll(stage->entry));
}
-static void *ram_phys_to_virt(uint32_t addr)
+void *cbfs_load_payload(struct cbfs_media *media, const char *name)
{
- return (void*)addr + ram_cbfs_offset;
+ return (struct cbfs_payload *)cbfs_get_file_content(
+ media, name, CBFS_TYPE_PAYLOAD);
}
-void setup_cbfs_from_ram(void* start, uint32_t size)
-{
- /* assumes rollover */
- ram_cbfs_offset = (uint32_t)start + size;
- virt_to_phys = ram_virt_to_phys;
- phys_to_virt = ram_phys_to_virt;
+struct cbfs_file *cbfs_find(const char *name) {
+ return cbfs_get_file(CBFS_DEFAULT_MEDIA, name);
+}
+
+void *cbfs_find_file(const char *name, int type) {
+ return cbfs_get_file_content(CBFS_DEFAULT_MEDIA, name, type);
+}
+
+const struct cbfs_header *get_cbfs_header(void) {
+ return cbfs_get_header(CBFS_DEFAULT_MEDIA);
}
-void setup_cbfs_from_flash(void)
+/* 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=%d, count=%d): "
+ "allocated=%d, size=%d, last_allocate=%d\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=%d, size=%d, last_allocate=%d\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;
+}
+
+/**
+ * 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.
+ */
+
+int run_address(void *f)
{
- virt_to_phys = host_virt_to_phys;
- phys_to_virt = host_phys_to_virt;
+ int (*v) (void);
+ v = f;
+ return v();
}
+
+#endif