2 * This file is part of the libpayload project.
4 * Copyright (C) 2008 Advanced Micro Devices, Inc.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 #include <libpayload.h>
31 #include <arch/endian.h>
33 #define ROM_RESET_VECTOR 0xFFFFFFF0
35 static void * next_header(void * cur)
37 struct lar_header *header = (struct lar_header *) cur;
38 int offset = ((ntohl(header->offset) + ntohl(header->len)) + 15) &
41 return (void *) (cur + offset);
44 static struct lar_header *lar_get_header(struct LAR *lar, int index)
48 if (index < lar->count)
49 return (struct lar_header *) lar->headers[index];
51 if (lar->eof && index >= lar->eof)
54 for(i = lar->count; i <= index; i++) {
55 void *next = (i == 0) ?
56 lar->start : next_header(lar->headers[i - 1]);
58 if (strncmp((const char *) next, LAR_MAGIC, 8)) {
59 lar->eof = lar->count;
63 if (lar->count == lar->alloc) {
64 void *tmp = realloc(lar->headers,
65 (lar->alloc + 16) * sizeof(void *));
74 lar->headers[lar->count++] = next;
77 return (struct lar_header *) lar->headers[index];
84 * @param addr The address in memory where the LAR is located.
85 * Use NULL to specify the boot LAR
86 * @return a pointer to the LAR stream
89 struct LAR *openlar(void *addr)
93 /* If the address is null, then figure out the start of the
97 u32 size = *((u32 *) (ROM_RESET_VECTOR + 4));
98 addr = (void *) ((ROM_RESET_VECTOR + 16) - size);
101 /* Check the magic to make sure this is a LAR */
102 if (strncmp((const char *) addr, LAR_MAGIC, strlen(LAR_MAGIC)))
105 lar = calloc(sizeof(struct LAR), 1);
112 /* Preallocate 16 slots in the cache - this saves wear and
113 * tear on the heap */
115 lar->headers = malloc(16 * sizeof(void *));
121 lar->count = lar->eof = 0;
130 * @param lar A pointer to the LAR stream
131 * @return Return 0 on success, -1 on error
134 int closelar(struct LAR *lar)
148 * Read an entry from the LAR
150 * @param lar A pointer to the LAR stream
151 * @return A pointer to a larent structure
152 representing the next file in the LAR
155 struct larent *readlar(struct LAR *lar)
157 static struct larent _larent;
158 struct lar_header *header;
164 header = lar_get_header(lar, lar->cindex);
169 nlen = ntohl(header->offset) - sizeof(*header);
171 if (nlen > LAR_MAX_PATHLEN - 1)
172 nlen = LAR_MAX_PATHLEN - 1;
174 memcpy((void *) _larent.name, ((char *) header + sizeof(*header)),
177 _larent.name[nlen] = 0;
181 return (struct larent *) &_larent;
184 void rewindlar(struct LAR *lar)
190 static struct lar_header *get_header_by_name(struct LAR *lar, const char *name)
192 struct lar_header *header;
196 header = lar_get_header(lar, i);
201 if (!strcmp(name, ((char *) header + sizeof(*header))))
206 int larstat(struct LAR *lar, const char *path, struct larstat *buf)
208 struct lar_header *header = get_header_by_name(lar, path);
210 if (header == NULL || buf == NULL)
213 buf->len = ntohl(header->len);
214 buf->reallen = ntohl(header->reallen);
215 buf->checksum = ntohl(header->checksum);
216 buf->compchecksum = ntohl(header->compchecksum);
217 buf->compression = ntohl(header->compression);
218 buf->entry = ntohll(header->entry);
219 buf->loadaddress = ntohll(header->loadaddress);
220 buf->offset = ((u32) header - (u32) lar->start) + ntohl(header->offset);
225 void * larfptr(struct LAR *lar, const char *filename)
227 struct lar_header *header = get_header_by_name(lar, filename);
232 return (void *) ((u8 *) header + ntohl(header->offset));
236 * Verify the checksum on a particular LAR entry
238 * @param lar A pointer to the LAR stream
239 * @param filename The lar entry to verify
240 * @return Return 1 if the entry is valid, 0 if it is not, or -1
244 int lfverify(struct LAR *lar, const char *filename)
246 struct lar_header *header = get_header_by_name(lar, filename);
248 u8 *ptr = (u8 *) header;
249 int len = ntohl(header->len) + ntohl(header->offset);
256 /* The checksum needs to be calulated on entire data section,
257 * including any padding for the 16 byte alignment (which should
261 len = (len + 15) & 0xFFFFFFF0;
263 for(offset = 0; offset < len; offset += 4) {
264 csum += *((u32 *) (ptr + offset));
267 return (csum == 0xFFFFFFFF) ? 1 : 0;
270 struct LFILE * lfopen(struct LAR *lar, const char *filename)
273 struct lar_header *header = get_header_by_name(lar, filename);
278 /* FIXME: What other validations do we want to do on the file here? */
280 file = malloc(sizeof(struct LFILE));
286 file->header = header;
287 file->size = ntohl(header->len);
288 file->start = ((u8 *) header + ntohl(header->offset));
294 void *lfmap(struct LFILE *file, int offset)
299 if (offset > file->size)
302 return (void *) (file->start + offset);
305 int lfread(void *ptr, size_t size, size_t nmemb, struct LFILE *stream)
307 size_t tsize, actual;
308 size_t remain = stream->size - stream->offset;
310 if (!stream || !remain)
313 tsize = (size * nmemb);
314 actual = (tsize > remain) ? remain : tsize;
316 memcpy(ptr, (void *) (stream->start + stream->offset), actual);
317 stream->offset += actual;
322 int lfseek(struct LFILE *file, long offset, int whence)
324 int o = file->offset;
338 if (o < 0 || o > file->size)
345 int lfclose(struct LFILE *file)