coreboot/payloads/libpayload/libc/lar.c
<<
>>
Prefs
   1/*
   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
 117        if (!lar->headers)
 118                return NULL;
 119
 120        lar->alloc = 16;
 121        lar->count = lar->eof = 0;
 122        lar->cindex = 0;
 123
 124        return lar;
 125}
 126
 127/**
 128 * Close a LAR stream
 129 *
 130 * @param lar A pointer to the LAR stream
 131 * @return Return 0 on success, -1 on error
 132 */
 133
 134int closelar(struct LAR *lar)
 135{
 136        if (!lar)
 137                return 0;
 138
 139        if (lar->headers)
 140                free(lar->headers);
 141
 142        free(lar);
 143
 144        return 0;
 145}
 146
 147/**
 148 * Read an entry from the LAR
 149 *
 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
 153 */
 154
 155struct larent *readlar(struct LAR *lar)
 156{
 157        static struct larent _larent;
 158        struct lar_header *header;
 159        int nlen;
 160
 161        if (!lar)
 162                return NULL;
 163
 164        header = lar_get_header(lar, lar->cindex);
 165
 166        if (header == NULL)
 167                return NULL;
 168
 169        nlen = ntohl(header->offset) - sizeof(*header);
 170
 171        if (nlen > LAR_MAX_PATHLEN - 1)
 172                nlen = LAR_MAX_PATHLEN - 1;
 173
 174        memcpy((void *) _larent.name, ((char *) header + sizeof(*header)),
 175                nlen);
 176
 177        _larent.name[nlen] = 0;
 178
 179        lar->cindex++;
 180
 181        return (struct larent *) &_larent;
 182}
 183
 184void rewindlar(struct LAR *lar)
 185{
 186        if (lar != NULL)
 187                lar->cindex = 0;
 188}
 189
 190static struct lar_header *get_header_by_name(struct LAR *lar, const char *name)
 191{
 192        struct lar_header *header;
 193        int i;
 194
 195        for(i = 0; ; i++) {
 196                header = lar_get_header(lar, i);
 197
 198                if (header == NULL)
 199                        return NULL;
 200
 201                if (!strcmp(name, ((char *) header + sizeof(*header))))
 202                        return header;
 203        }
 204}
 205
 206int larstat(struct LAR *lar, const char *path, struct larstat *buf)
 207{
 208        struct lar_header *header = get_header_by_name(lar, path);
 209
 210        if (header == NULL || buf == NULL)
 211                return -1;
 212
 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);
 221
 222        return 0;
 223}
 224
 225void * larfptr(struct LAR *lar, const char *filename)
 226{
 227        struct lar_header *header = get_header_by_name(lar, filename);
 228
 229        if (header == NULL)
 230                return NULL;
 231
 232        return (void *) ((u8 *) header + ntohl(header->offset));
 233}
 234
 235/**
 236 * Verify the checksum on a particular LAR entry
 237 *
 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
 241 * on error
 242 */
 243
 244int lfverify(struct LAR *lar, const char *filename)
 245{
 246        struct lar_header *header = get_header_by_name(lar, filename);
 247
 248        u8 *ptr = (u8 *) header;
 249        int len = ntohl(header->len) + ntohl(header->offset);
 250        int offset;
 251        u32 csum = 0;
 252
 253        if (header == NULL)
 254                return -1;
 255
 256        /* The checksum needs to be calulated on entire data section,
 257         * including any padding for the 16 byte alignment (which should
 258         * be zeros
 259         */
 260
 261        len = (len + 15) & 0xFFFFFFF0;
 262
 263        for(offset = 0; offset < len; offset += 4) {
 264                csum += *((u32 *) (ptr + offset));
 265        }
 266
 267        return (csum == 0xFFFFFFFF) ? 1 : 0;
 268}
 269
 270struct LFILE * lfopen(struct LAR *lar, const char *filename)
 271{
 272        struct LFILE *file;
 273        struct lar_header *header = get_header_by_name(lar, filename);
 274
 275        if (header == NULL)
 276                return NULL;
 277
 278        /* FIXME: What other validations do we want to do on the file here? */
 279
 280        file = malloc(sizeof(struct LFILE));
 281
 282        if (file == NULL)
 283                return NULL;
 284
 285        file->lar = lar;
 286        file->header = header;
 287        file->size = ntohl(header->len);
 288        file->start = ((u8 *) header + ntohl(header->offset));
 289        file->offset = 0;
 290
 291        return file;
 292}
 293
 294void *lfmap(struct LFILE *file, int offset)
 295{
 296        if (file == NULL)
 297                return (void *) -1;
 298
 299        if (offset > file->size)
 300                return (void *) -1;
 301
 302        return (void *) (file->start + offset);
 303};
 304
 305int lfread(void *ptr, size_t size, size_t nmemb, struct LFILE *stream)
 306{
 307        size_t tsize, actual;
 308        size_t remain = stream->size - stream->offset;
 309
 310        if (!stream || !remain)
 311                return 0;
 312
 313        tsize = (size * nmemb);
 314        actual = (tsize > remain) ? remain : tsize;
 315
 316        memcpy(ptr, (void *) (stream->start + stream->offset), actual);
 317        stream->offset += actual;
 318
 319        return actual;
 320}
 321
 322int lfseek(struct LFILE *file, long offset, int whence)
 323{
 324        int o = file->offset;
 325
 326        switch(whence) {
 327        case SEEK_SET:
 328                o = offset;
 329                break;
 330        case SEEK_CUR:
 331                o += offset;
 332                break;
 333
 334        case SEEK_END:
 335                return -1;
 336        }
 337
 338        if (o < 0 || o > file->size)
 339                return -1;
 340
 341        file->offset = o;
 342        return file->offset;
 343}
 344
 345int lfclose(struct LFILE *file)
 346{
 347        if (file)
 348                free(file);
 349        return 0;
 350}
 351
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.