~pmdj/ubuntu/trusty/qemu/2.9+applesmc+fadtv3

« back to all changes in this revision

Viewing changes to roms/u-boot/fs/cbfs/cbfs.c

  • Committer: Phil Dennis-Jordan
  • Date: 2017-07-21 08:03:43 UTC
  • mfrom: (1.1.1)
  • Revision ID: phil@philjordan.eu-20170721080343-2yr2vdj7713czahv
New upstream release 2.9.0.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
 
3
 *
 
4
 * SPDX-License-Identifier:     GPL-2.0+
 
5
 */
 
6
 
 
7
#include <cbfs.h>
 
8
#include <malloc.h>
 
9
#include <asm/byteorder.h>
 
10
 
 
11
enum cbfs_result file_cbfs_result;
 
12
 
 
13
const char *file_cbfs_error(void)
 
14
{
 
15
        switch (file_cbfs_result) {
 
16
        case CBFS_SUCCESS:
 
17
                return "Success";
 
18
        case CBFS_NOT_INITIALIZED:
 
19
                return "CBFS not initialized";
 
20
        case CBFS_BAD_HEADER:
 
21
                return "Bad CBFS header";
 
22
        case CBFS_BAD_FILE:
 
23
                return "Bad CBFS file";
 
24
        case CBFS_FILE_NOT_FOUND:
 
25
                return "File not found";
 
26
        default:
 
27
                return "Unknown";
 
28
        }
 
29
}
 
30
 
 
31
 
 
32
static const u32 good_magic = 0x4f524243;
 
33
static const u8 good_file_magic[] = "LARCHIVE";
 
34
 
 
35
 
 
36
static int initialized;
 
37
static struct cbfs_header cbfs_header;
 
38
static struct cbfs_cachenode *file_cache;
 
39
 
 
40
/* Do endian conversion on the CBFS header structure. */
 
41
static void swap_header(struct cbfs_header *dest, struct cbfs_header *src)
 
42
{
 
43
        dest->magic = be32_to_cpu(src->magic);
 
44
        dest->version = be32_to_cpu(src->version);
 
45
        dest->rom_size = be32_to_cpu(src->rom_size);
 
46
        dest->boot_block_size = be32_to_cpu(src->boot_block_size);
 
47
        dest->align = be32_to_cpu(src->align);
 
48
        dest->offset = be32_to_cpu(src->offset);
 
49
}
 
50
 
 
51
/* Do endian conversion on a CBFS file header. */
 
52
static void swap_file_header(struct cbfs_fileheader *dest,
 
53
                             const struct cbfs_fileheader *src)
 
54
{
 
55
        memcpy(&dest->magic, &src->magic, sizeof(dest->magic));
 
56
        dest->len = be32_to_cpu(src->len);
 
57
        dest->type = be32_to_cpu(src->type);
 
58
        dest->checksum = be32_to_cpu(src->checksum);
 
59
        dest->offset = be32_to_cpu(src->offset);
 
60
}
 
61
 
 
62
/*
 
63
 * Given a starting position in memory, scan forward, bounded by a size, and
 
64
 * find the next valid CBFS file. No memory is allocated by this function. The
 
65
 * caller is responsible for allocating space for the new file structure.
 
66
 *
 
67
 * @param start         The location in memory to start from.
 
68
 * @param size          The size of the memory region to search.
 
69
 * @param align         The alignment boundaries to check on.
 
70
 * @param newNode       A pointer to the file structure to load.
 
71
 * @param used          A pointer to the count of of bytes scanned through,
 
72
 *                      including the file if one is found.
 
73
 *
 
74
 * @return 1 if a file is found, 0 if one isn't.
 
75
 */
 
76
static int file_cbfs_next_file(u8 *start, u32 size, u32 align,
 
77
                               struct cbfs_cachenode *newNode, u32 *used)
 
78
{
 
79
        struct cbfs_fileheader header;
 
80
 
 
81
        *used = 0;
 
82
 
 
83
        while (size >= align) {
 
84
                const struct cbfs_fileheader *fileHeader =
 
85
                        (const struct cbfs_fileheader *)start;
 
86
                u32 name_len;
 
87
                u32 step;
 
88
 
 
89
                /* Check if there's a file here. */
 
90
                if (memcmp(good_file_magic, &(fileHeader->magic),
 
91
                                sizeof(fileHeader->magic))) {
 
92
                        *used += align;
 
93
                        size -= align;
 
94
                        start += align;
 
95
                        continue;
 
96
                }
 
97
 
 
98
                swap_file_header(&header, fileHeader);
 
99
                if (header.offset < sizeof(const struct cbfs_cachenode *) ||
 
100
                                header.offset > header.len) {
 
101
                        file_cbfs_result = CBFS_BAD_FILE;
 
102
                        return -1;
 
103
                }
 
104
                newNode->next = NULL;
 
105
                newNode->type = header.type;
 
106
                newNode->data = start + header.offset;
 
107
                newNode->data_length = header.len;
 
108
                name_len = header.offset - sizeof(struct cbfs_cachenode *);
 
109
                newNode->name = (char *)fileHeader +
 
110
                                sizeof(struct cbfs_cachenode *);
 
111
                newNode->name_length = name_len;
 
112
                newNode->checksum = header.checksum;
 
113
 
 
114
                step = header.len;
 
115
                if (step % align)
 
116
                        step = step + align - step % align;
 
117
 
 
118
                *used += step;
 
119
                return 1;
 
120
        }
 
121
        return 0;
 
122
}
 
123
 
 
124
/* Look through a CBFS instance and copy file metadata into regular memory. */
 
125
static void file_cbfs_fill_cache(u8 *start, u32 size, u32 align)
 
126
{
 
127
        struct cbfs_cachenode *cache_node;
 
128
        struct cbfs_cachenode *newNode;
 
129
        struct cbfs_cachenode **cache_tail = &file_cache;
 
130
 
 
131
        /* Clear out old information. */
 
132
        cache_node = file_cache;
 
133
        while (cache_node) {
 
134
                struct cbfs_cachenode *oldNode = cache_node;
 
135
                cache_node = cache_node->next;
 
136
                free(oldNode);
 
137
        }
 
138
        file_cache = NULL;
 
139
 
 
140
        while (size >= align) {
 
141
                int result;
 
142
                u32 used;
 
143
 
 
144
                newNode = (struct cbfs_cachenode *)
 
145
                                malloc(sizeof(struct cbfs_cachenode));
 
146
                result = file_cbfs_next_file(start, size, align,
 
147
                        newNode, &used);
 
148
 
 
149
                if (result < 0) {
 
150
                        free(newNode);
 
151
                        return;
 
152
                } else if (result == 0) {
 
153
                        free(newNode);
 
154
                        break;
 
155
                }
 
156
                *cache_tail = newNode;
 
157
                cache_tail = &newNode->next;
 
158
 
 
159
                size -= used;
 
160
                start += used;
 
161
        }
 
162
        file_cbfs_result = CBFS_SUCCESS;
 
163
}
 
164
 
 
165
/* Get the CBFS header out of the ROM and do endian conversion. */
 
166
static int file_cbfs_load_header(uintptr_t end_of_rom,
 
167
                                 struct cbfs_header *header)
 
168
{
 
169
        struct cbfs_header *header_in_rom;
 
170
 
 
171
        header_in_rom = (struct cbfs_header *)(uintptr_t)
 
172
                        *(u32 *)(end_of_rom - 3);
 
173
        swap_header(header, header_in_rom);
 
174
 
 
175
        if (header->magic != good_magic || header->offset >
 
176
                        header->rom_size - header->boot_block_size) {
 
177
                file_cbfs_result = CBFS_BAD_HEADER;
 
178
                return 1;
 
179
        }
 
180
        return 0;
 
181
}
 
182
 
 
183
void file_cbfs_init(uintptr_t end_of_rom)
 
184
{
 
185
        u8 *start_of_rom;
 
186
        initialized = 0;
 
187
 
 
188
        if (file_cbfs_load_header(end_of_rom, &cbfs_header))
 
189
                return;
 
190
 
 
191
        start_of_rom = (u8 *)(end_of_rom + 1 - cbfs_header.rom_size);
 
192
 
 
193
        file_cbfs_fill_cache(start_of_rom + cbfs_header.offset,
 
194
                             cbfs_header.rom_size, cbfs_header.align);
 
195
        if (file_cbfs_result == CBFS_SUCCESS)
 
196
                initialized = 1;
 
197
}
 
198
 
 
199
const struct cbfs_header *file_cbfs_get_header(void)
 
200
{
 
201
        if (initialized) {
 
202
                file_cbfs_result = CBFS_SUCCESS;
 
203
                return &cbfs_header;
 
204
        } else {
 
205
                file_cbfs_result = CBFS_NOT_INITIALIZED;
 
206
                return NULL;
 
207
        }
 
208
}
 
209
 
 
210
const struct cbfs_cachenode *file_cbfs_get_first(void)
 
211
{
 
212
        if (!initialized) {
 
213
                file_cbfs_result = CBFS_NOT_INITIALIZED;
 
214
                return NULL;
 
215
        } else {
 
216
                file_cbfs_result = CBFS_SUCCESS;
 
217
                return file_cache;
 
218
        }
 
219
}
 
220
 
 
221
void file_cbfs_get_next(const struct cbfs_cachenode **file)
 
222
{
 
223
        if (!initialized) {
 
224
                file_cbfs_result = CBFS_NOT_INITIALIZED;
 
225
                file = NULL;
 
226
                return;
 
227
        }
 
228
 
 
229
        if (*file)
 
230
                *file = (*file)->next;
 
231
        file_cbfs_result = CBFS_SUCCESS;
 
232
}
 
233
 
 
234
const struct cbfs_cachenode *file_cbfs_find(const char *name)
 
235
{
 
236
        struct cbfs_cachenode *cache_node = file_cache;
 
237
 
 
238
        if (!initialized) {
 
239
                file_cbfs_result = CBFS_NOT_INITIALIZED;
 
240
                return NULL;
 
241
        }
 
242
 
 
243
        while (cache_node) {
 
244
                if (!strcmp(name, cache_node->name))
 
245
                        break;
 
246
                cache_node = cache_node->next;
 
247
        }
 
248
        if (!cache_node)
 
249
                file_cbfs_result = CBFS_FILE_NOT_FOUND;
 
250
        else
 
251
                file_cbfs_result = CBFS_SUCCESS;
 
252
 
 
253
        return cache_node;
 
254
}
 
255
 
 
256
const struct cbfs_cachenode *file_cbfs_find_uncached(uintptr_t end_of_rom,
 
257
                                                     const char *name)
 
258
{
 
259
        u8 *start;
 
260
        u32 size;
 
261
        u32 align;
 
262
        static struct cbfs_cachenode node;
 
263
 
 
264
        if (file_cbfs_load_header(end_of_rom, &cbfs_header))
 
265
                return NULL;
 
266
 
 
267
        start = (u8 *)(end_of_rom + 1 - cbfs_header.rom_size);
 
268
        size = cbfs_header.rom_size;
 
269
        align = cbfs_header.align;
 
270
 
 
271
        while (size >= align) {
 
272
                int result;
 
273
                u32 used;
 
274
 
 
275
                result = file_cbfs_next_file(start, size, align, &node, &used);
 
276
 
 
277
                if (result < 0)
 
278
                        return NULL;
 
279
                else if (result == 0)
 
280
                        break;
 
281
 
 
282
                if (!strcmp(name, node.name))
 
283
                        return &node;
 
284
 
 
285
                size -= used;
 
286
                start += used;
 
287
        }
 
288
        file_cbfs_result = CBFS_FILE_NOT_FOUND;
 
289
        return NULL;
 
290
}
 
291
 
 
292
const char *file_cbfs_name(const struct cbfs_cachenode *file)
 
293
{
 
294
        file_cbfs_result = CBFS_SUCCESS;
 
295
        return file->name;
 
296
}
 
297
 
 
298
u32 file_cbfs_size(const struct cbfs_cachenode *file)
 
299
{
 
300
        file_cbfs_result = CBFS_SUCCESS;
 
301
        return file->data_length;
 
302
}
 
303
 
 
304
u32 file_cbfs_type(const struct cbfs_cachenode *file)
 
305
{
 
306
        file_cbfs_result = CBFS_SUCCESS;
 
307
        return file->type;
 
308
}
 
309
 
 
310
long file_cbfs_read(const struct cbfs_cachenode *file, void *buffer,
 
311
                    unsigned long maxsize)
 
312
{
 
313
        u32 size;
 
314
 
 
315
        size = file->data_length;
 
316
        if (maxsize && size > maxsize)
 
317
                size = maxsize;
 
318
 
 
319
        memcpy(buffer, file->data, size);
 
320
 
 
321
        file_cbfs_result = CBFS_SUCCESS;
 
322
        return size;
 
323
}