summaryrefslogtreecommitdiff
path: root/payloads/libpayload/libc
diff options
context:
space:
mode:
authorJordan Crouse <jordan.crouse@amd.com>2008-05-07 20:34:02 +0000
committerJordan Crouse <jordan.crouse@amd.com>2008-05-07 20:34:02 +0000
commit681ec27e2c64763bba02ef816d41b6b366559f03 (patch)
treef943180f77f85b553e7e47791c06deaf44f184d3 /payloads/libpayload/libc
parent35993a231ecb4957d18719801cc4519b1df80d70 (diff)
downloadcoreboot-681ec27e2c64763bba02ef816d41b6b366559f03.tar.xz
libpayload: Add LAR walking support
Add suport for walking LARs. These try to emulate the f* functions from POSIX, though they are obviously different in their behavior. Signed-off-by: Jordan Crouse <jordan.crouse@amd.com> Acked-by: Myles Watson <mylesgw@gmail.com> git-svn-id: svn://svn.coreboot.org/coreboot/trunk@3288 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
Diffstat (limited to 'payloads/libpayload/libc')
-rw-r--r--payloads/libpayload/libc/Makefile.inc2
-rw-r--r--payloads/libpayload/libc/lar.c301
2 files changed, 302 insertions, 1 deletions
diff --git a/payloads/libpayload/libc/Makefile.inc b/payloads/libpayload/libc/Makefile.inc
index 938c1fe10c..0e2fba8d66 100644
--- a/payloads/libpayload/libc/Makefile.inc
+++ b/payloads/libpayload/libc/Makefile.inc
@@ -29,4 +29,4 @@
TARGETS-y += libc/malloc.o libc/printf.o libc/console.o libc/string.o
TARGETS-y += libc/memory.o libc/ctype.o libc/ipchecksum.o libc/lib.o
-TARGETS-y += libc/rand.o libc/time.o
+TARGETS-y += libc/rand.o libc/time.o libc/lar.o
diff --git a/payloads/libpayload/libc/lar.c b/payloads/libpayload/libc/lar.c
new file mode 100644
index 0000000000..65b503d1c8
--- /dev/null
+++ b/payloads/libpayload/libc/lar.c
@@ -0,0 +1,301 @@
+/*
+ * This file is part of the libpayload project.
+ *
+ * Copyright (C) 2008 Advanced Micro Devices, 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.
+ */
+
+#include <libpayload.h>
+#include <arch/endian.h>
+
+#define ROM_RESET_VECTOR 0xFFFFFFF0
+
+static void * next_header(void * cur)
+{
+ struct lar_header *header = (struct lar_header *) cur;
+ int offset = ((ntohl(header->offset) + ntohl(header->len)) + 15) &
+ 0xFFFFFFF0;
+
+ return (void *) (cur + offset);
+}
+
+static struct lar_header *lar_get_header(struct LAR *lar, int index)
+{
+ int i;
+
+ if (index < lar->count)
+ return (struct lar_header *) lar->headers[index];
+
+ if (lar->eof && index >= lar->eof)
+ return NULL;
+
+ for(i = lar->count; i <= index; i++) {
+ void *next = (i == 0) ?
+ lar->start : next_header(lar->headers[i - 1]);
+
+ if (strncmp((const char *) next, LAR_MAGIC, 8)) {
+ lar->eof = lar->count;
+ return NULL;
+ }
+
+ if (lar->count == lar->alloc) {
+ void *tmp = realloc(lar->headers,
+ (lar->alloc + 16) * sizeof(void *));
+
+ if (tmp == NULL)
+ return NULL;
+
+ lar->headers = tmp;
+ lar->alloc += 16;
+ }
+
+ lar->headers[lar->count++] = next;
+ }
+
+ return (struct lar_header *) lar->headers[index];
+}
+
+
+/**
+ * Open a LAR stream
+ *
+ * @param addr The address in memory where the LAR is located.
+ * Use NULL to specify the boot LAR
+ * @return a pointer to the LAR stream
+ */
+
+struct LAR *openlar(void *addr)
+{
+ struct LAR *lar;
+
+ /* If the address is null, then figure out the start of the
+ boot LAR */
+
+ if (addr == NULL) {
+ u32 size = *((u32 *) (ROM_RESET_VECTOR + 4));
+ addr = (void *) ((ROM_RESET_VECTOR + 16) - size);
+ }
+
+ /* Check the magic to make sure this is a LAR */
+ if (strncmp((const char *) addr, LAR_MAGIC, strlen(LAR_MAGIC)))
+ return NULL;
+
+ lar = calloc(sizeof(struct LAR), 1);
+
+ if (!lar)
+ return NULL;
+
+ lar->start = addr;
+
+ /* Preallocate 16 slots in the cache - this saves wear and
+ * tear on the heap */
+
+ lar->headers = malloc(16 * sizeof(void *));
+ lar->alloc = 16;
+ lar->count = lar->eof = 0;
+ lar->cindex = 0;
+
+ return lar;
+}
+
+/**
+ * Close a LAR stream
+ *
+ * @param lar A pointer to the LAR stream
+ * @return Return 0 on success, -1 on error
+ */
+
+int closelar(struct LAR *lar)
+{
+ if (!lar)
+ return 0;
+
+ if (lar->headers)
+ free(lar->headers);
+
+ free(lar);
+
+ return 0;
+}
+
+/**
+ * Read an entry from the LAR
+ *
+ * @param lar A pointer to the LAR stream
+ * @return A pointer to a larent structure
+ representing the next file in the LAR
+ */
+
+struct larent *readlar(struct LAR *lar)
+{
+ static struct larent _larent;
+ struct lar_header *header;
+ int nlen;
+
+ if (!lar)
+ return NULL;
+
+ header = lar_get_header(lar, lar->cindex);
+
+ if (header == NULL)
+ return NULL;
+
+ nlen = ntohl(header->offset) - sizeof(*header);
+
+ if (nlen > LAR_MAX_PATHLEN - 1)
+ nlen = LAR_MAX_PATHLEN - 1;
+
+ memcpy((void *) _larent.name, ((char *) header + sizeof(*header)),
+ nlen);
+
+ _larent.name[nlen] = 0;
+
+ lar->cindex++;
+
+ return (struct larent *) &_larent;
+}
+
+void rewindlar(struct LAR *lar)
+{
+ if (lar != NULL)
+ lar->cindex = 0;
+}
+
+static struct lar_header *get_header_by_name(struct LAR *lar, const char *name)
+{
+ struct lar_header *header;
+ int i;
+
+ for(i = 0; ; i++) {
+ header = lar_get_header(lar, i);
+
+ if (header == NULL)
+ return NULL;
+
+ if (!strcmp(name, ((char *) header + sizeof(*header))))
+ return header;
+ }
+}
+
+int larstat(struct LAR *lar, const char *path, struct larstat *buf)
+{
+ struct lar_header *header = get_header_by_name(lar, path);
+
+ if (header == NULL || buf == NULL)
+ return -1;
+
+ buf->len = ntohl(header->len);
+ buf->reallen = ntohl(header->reallen);
+ buf->checksum = ntohl(header->checksum);
+ buf->compchecksum = ntohl(header->compchecksum);
+ buf->compression = ntohl(header->compression);
+ buf->entry = ntohll(header->entry);
+ buf->loadaddress = ntohll(header->loadaddress);
+ buf->offset = ((u32) header - (u32) lar->start) + ntohl(header->offset);
+
+ return 0;
+}
+
+struct LFILE * lfopen(struct LAR *lar, const char *filename)
+{
+ struct LFILE *file;
+ struct lar_header *header = get_header_by_name(lar, filename);
+
+ if (header == NULL)
+ return NULL;
+
+ /* FIXME: What other validations do we want to do on the file here? */
+
+ file = malloc(sizeof(struct LFILE));
+
+ if (file == NULL)
+ return NULL;
+
+ file->lar = lar;
+ file->header = header;
+ file->size = ntohl(header->len);
+ file->start = ((u8 *) header + ntohl(header->offset));
+ file->offset = 0;
+
+ return file;
+}
+
+void *lfmap(struct LFILE *file, int offset)
+{
+ if (file == NULL)
+ return (void *) -1;
+
+ if (offset > file->size)
+ return (void *) -1;
+
+ return (void *) (file->start + offset);
+};
+
+int lfread(void *ptr, size_t size, size_t nmemb, struct LFILE *stream)
+{
+ size_t tsize, actual;
+ size_t remain = stream->size - stream->offset;
+
+ if (!stream || !remain)
+ return 0;
+
+ tsize = (size * nmemb);
+ actual = (tsize > remain) ? remain : tsize;
+
+ memcpy(ptr, (void *) (stream->start + stream->offset), actual);
+ stream->offset += actual;
+
+ return actual;
+}
+
+int lfseek(struct LFILE *file, long offset, int whence)
+{
+ int o = file->offset;
+
+ switch(whence) {
+ case SEEK_SET:
+ o = offset;
+ break;
+ case SEEK_CUR:
+ o += offset;
+ break;
+
+ case SEEK_END:
+ return -1;
+ }
+
+ if (o < 0 || o > file->size)
+ return -1;
+
+ file->offset = o;
+ return file->offset;
+}
+
+int lfclose(struct LFILE *file)
+{
+ if (file)
+ free(file);
+ return 0;
+}