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
This commit is contained in:
Jordan Crouse 2008-05-07 20:34:02 +00:00
parent 35993a231e
commit 681ec27e2c
5 changed files with 492 additions and 1 deletions

View File

@ -0,0 +1,46 @@
/*
* 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.
*/
#ifndef _ARCH_ENDIAN_H
#define _ARCH_ENDIAN_H
static u32 ntohl(u32 in)
{
return ((in & 0xFF) << 24) | ((in & 0xFF00) << 8) |
((in & 0xFF0000) >> 8) | ((in & 0xFF000000) >> 24);
}
static u64 ntohll(u64 in)
{
u32 h = in >> 32;
u32 l = in & 0xFFFFFFFF;
return (((u64) ntohl(l) << 32) | ((u64) ntohl(h)));
}
#endif

View File

@ -0,0 +1,94 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2006 coresystems GmbH
* (Written by Stefan Reinauer <stepan@coresystems.de> for coresystems GmbH)
*
* 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.
*
* 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
* ---------------------------------------------------------------------------
* 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.
* ---------------------------------------------------------------------------
*/
#ifndef LAR_H
#define LAR_H
#include <arch/types.h>
#define LAR_MAGIC "LARCHIVE"
#define LAR_MAX_PATHLEN 1024
struct lar_header {
char magic[8];
u32 len;
u32 reallen;
u32 checksum;
u32 compchecksum;
u32 offset;
/* Compression:
* 0 = no compression
* 1 = lzma
* 2 = nrv2b
* 3 = zeroes
*/
u32 compression;
u64 entry;
u64 loadaddress;
};
enum compalgo {
ALGO_NONE = 0,
ALGO_LZMA = 1,
ALGO_NRV2B = 2,
ALGO_ZEROES = 3,
/* invalid should always be the last entry. */
ALGO_INVALID
};
struct mem_file {
void *start;
int len;
u32 reallen;
u32 compression;
void *entry;
void *loadaddress;
};
#endif /* LAR_H */

View File

@ -36,6 +36,7 @@
#include <arch/io.h> #include <arch/io.h>
#include <sysinfo.h> #include <sysinfo.h>
#include <stdarg.h> #include <stdarg.h>
#include <lar.h>
#define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MIN(a,b) ((a) < (b) ? (a) : (b))
#define MAX(a,b) ((a) > (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b))
@ -207,6 +208,55 @@ struct timeval {
int gettimeofday(struct timeval *tv, void *tz); int gettimeofday(struct timeval *tv, void *tz);
/* libc/lar.c */
struct LAR {
void * start;
int cindex;
int count;
int alloc;
int eof;
void **headers;
};
struct larent {
u8 name[LAR_MAX_PATHLEN];
};
struct larstat {
u32 len;
u32 reallen;
u32 checksum;
u32 compchecksum;
u32 offset;
u32 compression;
u64 entry;
u64 loadaddress;
};
struct LFILE {
struct LAR *lar;
struct lar_header *header;
u32 size;
void *start;
u32 offset;
};
struct LAR *openlar(void *addr);
int closelar(struct LAR *lar);
struct larent *readlar(struct LAR *lar);
void rewindlar(struct LAR *lar);
int larstat(struct LAR *lar, const char *path, struct larstat *buf);
struct LFILE * lfopen(struct LAR *lar, const char *filename);
int lfread(void *ptr, size_t size, size_t nmemb, struct LFILE *stream);
#define SEEK_SET 0
#define SEEK_CUR 1
#define SEEK_END 2
int lfseek(struct LFILE *stream, long offset, int whence);
int lfclose(struct LFILE *file);
/* i386/coreboot.c */ /* i386/coreboot.c */
int get_coreboot_info(struct sysinfo_t *info); int get_coreboot_info(struct sysinfo_t *info);

View File

@ -29,4 +29,4 @@
TARGETS-y += libc/malloc.o libc/printf.o libc/console.o libc/string.o 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/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

View File

@ -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;
}