blob: 9ad706c7fd26ecfe723b3aae8b7554d039813af4 [file] [log] [blame]
/*
* This file was originally part of the libpayload project, which is part
* of coreboot.
*
* Copyright (C) 2011 secunet Security Networks AG
* Portions Copyright (C) 2012 Google Inc.
*
* 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.
*
* Note: This is a modified version of the original cbfs_core.c file from
* Coreboot. The major changes are intended to remove certain Coreboot-specific
* dependencies and assumptions, such as callbacks used by Coreboot at runtime,
* using a supplied memory buffer rather than looking at physical memory,
* virtual/physical address handling, error/logging macros, and certain constants.
*/
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include "mosys/log.h"
#include "lib/cbfs_core.h"
#include "lib/math.h"
struct cbfs_header *get_cbfs_header(const uint8_t *buf, size_t size)
{
struct cbfs_header *header = NULL;
uint32_t *header_ptr = NULL;
/*
* Header pointer would usually be at offset -4 from end of ROM
* (0xfffffffc on normal x86 systems) and point to an absolute address
* somewhere in the Coreboot bootblock section between 0xFFFFB000
* and 0xFFFFFFF0.
*/
header_ptr = (uint32_t *)((buf + size) - 4);
header = (struct cbfs_header *)((*header_ptr - (0xffffffff - size + 1)) + buf);
/* find header */
if (CBFS_HEADER_MAGIC != ntohl(header->magic)) {
lprintf(LOG_DEBUG, "Could not find valid CBFS master header at "
"%p: %x vs %x.\n", header, CBFS_HEADER_MAGIC,
ntohl(header->magic));
if (header->magic == 0xffffffff) {
lprintf(LOG_DEBUG, "Maybe ROM is not mapped properly?\n");
}
return (void*)0xffffffff;
}
return header;
}
// by must be power-of-two
#define CBFS_ALIGN(val, by) (typeof(val))((unsigned long long)(val + by - 1) & \
(unsigned long long)~(by - 1))
#define CBFS_ALIGN_UP(val, by) CBFS_ALIGN(val + 1, by)
/* public API starts here*/
struct cbfs_file *cbfs_find(const char *name, const uint8_t *buf, size_t size)
{
struct cbfs_header *header = get_cbfs_header(buf, size);
void *data, *dataend;
int align;
off_t offset = 0;
if (header == (void*)0xffffffff) return NULL;
lprintf(LOG_DEBUG, "Searching for %s\n", name);
/*
* Find first entry.
* Note: romsize and offset refer to the coreboot image which may
* occupy only a small portion of the physical ROM.
*/
data = (void *)buf + size - ntohl(header->romsize) + ntohl(header->offset);
dataend = (void *)buf + size - ntohl(header->bootblocksize);
align = ntohl(header->align);
/*
* Physical ROM addresses and virtual addresses have different
* alignment. Thus, we'll increment by the aligned physical ROM offset
* on each iteration rather than working with addresses directly.
*/
while ((data + offset < dataend - 1)) {
struct cbfs_file *file = data + offset;
if (memcmp(CBFS_FILE_MAGIC, file->magic, strlen(CBFS_FILE_MAGIC)) != 0) {
offset = CBFS_ALIGN_UP(offset, align);
continue;
}
lprintf(LOG_DEBUG, "%s: Found entry \"%s\" at offset 0x%06x\n",
__func__, CBFS_NAME(file), offset);
if (strcmp(CBFS_NAME(file), name) == 0) {
return file;
}
offset = CBFS_ALIGN(offset +
ntohl(file->len) + ntohl(file->offset),
align);
}
return NULL;
}
void *cbfs_get_file(const char *name, const uint8_t *buf, size_t size)
{
struct cbfs_file *file = cbfs_find(name, buf, size);
if (file == NULL) {
lprintf(LOG_DEBUG, "Could not find file '%s'.\n", name);
return NULL;
}
return (void*)CBFS_SUBHEADER(file);
}
void *cbfs_find_file(const char *name, int type, const uint8_t *buf, size_t size)
{
struct cbfs_file *file = cbfs_find(name, buf, size);
if (file == NULL) {
lprintf(LOG_DEBUG, "Could not find file '%s'.\n", name);
return NULL;
}
if (ntohl(file->type) != type) {
lprintf(LOG_DEBUG, "File '%s' is of type %x, but we requested %x.\n", name, ntohl(file->type), type);
return NULL;
}
return (void*)CBFS_SUBHEADER(file);
}
int cbfs_decompress(int algo, void *src, void *dst, int len)
{
switch (algo) {
case CBFS_COMPRESS_NONE:
memcpy(dst, src, len);
return 0;
#ifdef CBFS_CORE_WITH_LZMA
case CBFS_COMPRESS_LZMA:
if (ulzma(src, dst) != 0) {
return 0;
}
return -1;
#endif
default:
lprintf(LOG_DEBUG, "tried to decompress %d bytes with algorithm #%x, but that algorithm id is unsupported.\n", len, algo);
return -1;
}
}