blob: 225b19001a1532e522f59951f544f5d5a217dac8 [file] [log] [blame]
Jordan Crouse681ec272008-05-07 20:34:02 +00001/*
2 * This file is part of the libpayload project.
3 *
4 * Copyright (C) 2008 Advanced Micro Devices, Inc.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
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.
16 *
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
27 * SUCH DAMAGE.
28 */
29
30#include <libpayload.h>
31#include <arch/endian.h>
32
33#define ROM_RESET_VECTOR 0xFFFFFFF0
34
35static void * next_header(void * cur)
36{
37 struct lar_header *header = (struct lar_header *) cur;
38 int offset = ((ntohl(header->offset) + ntohl(header->len)) + 15) &
39 0xFFFFFFF0;
40
41 return (void *) (cur + offset);
42}
43
44static struct lar_header *lar_get_header(struct LAR *lar, int index)
45{
46 int i;
47
48 if (index < lar->count)
49 return (struct lar_header *) lar->headers[index];
50
51 if (lar->eof && index >= lar->eof)
52 return NULL;
53
54 for(i = lar->count; i <= index; i++) {
55 void *next = (i == 0) ?
56 lar->start : next_header(lar->headers[i - 1]);
57
58 if (strncmp((const char *) next, LAR_MAGIC, 8)) {
59 lar->eof = lar->count;
60 return NULL;
61 }
62
63 if (lar->count == lar->alloc) {
64 void *tmp = realloc(lar->headers,
65 (lar->alloc + 16) * sizeof(void *));
66
67 if (tmp == NULL)
68 return NULL;
69
70 lar->headers = tmp;
71 lar->alloc += 16;
72 }
73
74 lar->headers[lar->count++] = next;
75 }
76
77 return (struct lar_header *) lar->headers[index];
78}
79
80
81/**
82 * Open a LAR stream
83 *
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
87 */
88
89struct LAR *openlar(void *addr)
90{
91 struct LAR *lar;
92
93 /* If the address is null, then figure out the start of the
94 boot LAR */
95
96 if (addr == NULL) {
97 u32 size = *((u32 *) (ROM_RESET_VECTOR + 4));
98 addr = (void *) ((ROM_RESET_VECTOR + 16) - size);
99 }
100
101 /* Check the magic to make sure this is a LAR */
102 if (strncmp((const char *) addr, LAR_MAGIC, strlen(LAR_MAGIC)))
103 return NULL;
104
105 lar = calloc(sizeof(struct LAR), 1);
106
107 if (!lar)
108 return NULL;
109
110 lar->start = addr;
111
112 /* Preallocate 16 slots in the cache - this saves wear and
113 * tear on the heap */
114
115 lar->headers = malloc(16 * sizeof(void *));
116 lar->alloc = 16;
117 lar->count = lar->eof = 0;
118 lar->cindex = 0;
119
120 return lar;
121}
122
123/**
124 * Close a LAR stream
125 *
126 * @param lar A pointer to the LAR stream
127 * @return Return 0 on success, -1 on error
128 */
129
130int closelar(struct LAR *lar)
131{
132 if (!lar)
133 return 0;
134
135 if (lar->headers)
136 free(lar->headers);
137
138 free(lar);
139
140 return 0;
141}
142
143/**
144 * Read an entry from the LAR
145 *
146 * @param lar A pointer to the LAR stream
147 * @return A pointer to a larent structure
148 representing the next file in the LAR
149 */
150
151struct larent *readlar(struct LAR *lar)
152{
153 static struct larent _larent;
154 struct lar_header *header;
155 int nlen;
156
157 if (!lar)
158 return NULL;
159
160 header = lar_get_header(lar, lar->cindex);
161
162 if (header == NULL)
163 return NULL;
164
165 nlen = ntohl(header->offset) - sizeof(*header);
166
167 if (nlen > LAR_MAX_PATHLEN - 1)
168 nlen = LAR_MAX_PATHLEN - 1;
169
170 memcpy((void *) _larent.name, ((char *) header + sizeof(*header)),
171 nlen);
172
173 _larent.name[nlen] = 0;
174
175 lar->cindex++;
176
177 return (struct larent *) &_larent;
178}
179
180void rewindlar(struct LAR *lar)
181{
182 if (lar != NULL)
183 lar->cindex = 0;
184}
185
186static struct lar_header *get_header_by_name(struct LAR *lar, const char *name)
187{
188 struct lar_header *header;
189 int i;
190
191 for(i = 0; ; i++) {
192 header = lar_get_header(lar, i);
193
194 if (header == NULL)
195 return NULL;
196
197 if (!strcmp(name, ((char *) header + sizeof(*header))))
198 return header;
199 }
200}
201
202int larstat(struct LAR *lar, const char *path, struct larstat *buf)
203{
204 struct lar_header *header = get_header_by_name(lar, path);
205
206 if (header == NULL || buf == NULL)
207 return -1;
208
209 buf->len = ntohl(header->len);
210 buf->reallen = ntohl(header->reallen);
211 buf->checksum = ntohl(header->checksum);
212 buf->compchecksum = ntohl(header->compchecksum);
213 buf->compression = ntohl(header->compression);
214 buf->entry = ntohll(header->entry);
215 buf->loadaddress = ntohll(header->loadaddress);
216 buf->offset = ((u32) header - (u32) lar->start) + ntohl(header->offset);
217
218 return 0;
219}
220
Jordan Crouse50698082008-05-20 20:09:42 +0000221void * larfptr(struct LAR *lar, const char *filename)
222{
223 struct lar_header *header = get_header_by_name(lar, filename);
224
225 if (header == NULL)
226 return NULL;
227
228 return (void *) ((u8 *) header + ntohl(header->offset));
229}
230
Jordan Crouse9e734c22008-05-27 19:57:53 +0000231/**
232 * Verify the checksum on a particular LAR entry
233 *
234 * @param lar A pointer to the LAR stream
235 * @param filename The lar entry to verify
236 * @return Return 1 if the entry is valid, 0 if it is not, or -1
237 * on error
238 */
239
240int lfverify(struct LAR *lar, const char *filename)
241{
242 struct lar_header *header = get_header_by_name(lar, filename);
243
244 u8 *ptr = (u8 *) header;
245 int len = ntohl(header->len) + ntohl(header->offset);
246 int offset;
247 u32 csum = 0;
248
249 if (header == NULL)
250 return -1;
251
252 /* The checksum needs to be calulated on entire data section,
253 * including any padding for the 16 byte alignment (which should
254 * be zeros
255 */
256
257 len = (len + 15) & 0xFFFFFFF0;
258
259 for(offset = 0; offset < len; offset += 4) {
260 csum += *((u32 *) (ptr + offset));
261 }
262
263 return (csum == 0xFFFFFFFF) ? 1 : 0;
264}
265
Jordan Crouse681ec272008-05-07 20:34:02 +0000266struct LFILE * lfopen(struct LAR *lar, const char *filename)
267{
268 struct LFILE *file;
269 struct lar_header *header = get_header_by_name(lar, filename);
270
271 if (header == NULL)
272 return NULL;
273
274 /* FIXME: What other validations do we want to do on the file here? */
275
276 file = malloc(sizeof(struct LFILE));
277
278 if (file == NULL)
279 return NULL;
280
281 file->lar = lar;
282 file->header = header;
283 file->size = ntohl(header->len);
284 file->start = ((u8 *) header + ntohl(header->offset));
285 file->offset = 0;
286
287 return file;
288}
289
290void *lfmap(struct LFILE *file, int offset)
291{
292 if (file == NULL)
293 return (void *) -1;
294
295 if (offset > file->size)
296 return (void *) -1;
297
298 return (void *) (file->start + offset);
299};
300
301int lfread(void *ptr, size_t size, size_t nmemb, struct LFILE *stream)
302{
303 size_t tsize, actual;
304 size_t remain = stream->size - stream->offset;
305
306 if (!stream || !remain)
307 return 0;
308
309 tsize = (size * nmemb);
310 actual = (tsize > remain) ? remain : tsize;
311
312 memcpy(ptr, (void *) (stream->start + stream->offset), actual);
313 stream->offset += actual;
314
315 return actual;
316}
317
318int lfseek(struct LFILE *file, long offset, int whence)
319{
320 int o = file->offset;
321
322 switch(whence) {
323 case SEEK_SET:
324 o = offset;
325 break;
326 case SEEK_CUR:
327 o += offset;
328 break;
329
330 case SEEK_END:
331 return -1;
332 }
333
334 if (o < 0 || o > file->size)
335 return -1;
336
337 file->offset = o;
338 return file->offset;
339}
340
341int lfclose(struct LFILE *file)
342{
343 if (file)
344 free(file);
345 return 0;
346}