1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
9 #include <asm/byteorder.h>
11 /* Offset of master header from the start of a coreboot ROM */
12 #define MASTER_HDR_OFFSET 0x38
14 static const u32 good_magic = 0x4f524243;
15 static const u8 good_file_magic[] = "LARCHIVE";
18 * struct cbfs_priv - Private data for this driver
20 * @initialised: true if this CBFS has been inited
21 * @start: Start position of CBFS in memory, typically memory-mapped SPI flash
22 * @header: Header read from the CBFS, byte-swapped so U-Boot can access it
23 * @file_cache: List of file headers read from CBFS
24 * @result: Success/error result
29 struct cbfs_header header;
30 struct cbfs_cachenode *file_cache;
31 enum cbfs_result result;
34 static struct cbfs_priv cbfs_s;
36 const char *file_cbfs_error(void)
38 switch (cbfs_s.result) {
41 case CBFS_NOT_INITIALIZED:
42 return "CBFS not initialized";
44 return "Bad CBFS header";
46 return "Bad CBFS file";
47 case CBFS_FILE_NOT_FOUND:
48 return "File not found";
54 enum cbfs_result cbfs_get_result(void)
59 /* Do endian conversion on the CBFS header structure. */
60 static void swap_header(struct cbfs_header *dest, struct cbfs_header *src)
62 dest->magic = be32_to_cpu(src->magic);
63 dest->version = be32_to_cpu(src->version);
64 dest->rom_size = be32_to_cpu(src->rom_size);
65 dest->boot_block_size = be32_to_cpu(src->boot_block_size);
66 dest->align = be32_to_cpu(src->align);
67 dest->offset = be32_to_cpu(src->offset);
70 /* Do endian conversion on a CBFS file header. */
71 static void swap_file_header(struct cbfs_fileheader *dest,
72 const struct cbfs_fileheader *src)
74 memcpy(&dest->magic, &src->magic, sizeof(dest->magic));
75 dest->len = be32_to_cpu(src->len);
76 dest->type = be32_to_cpu(src->type);
77 dest->attributes_offset = be32_to_cpu(src->attributes_offset);
78 dest->offset = be32_to_cpu(src->offset);
82 * Given a starting position in memory, scan forward, bounded by a size, and
83 * find the next valid CBFS file. No memory is allocated by this function. The
84 * caller is responsible for allocating space for the new file structure.
86 * @param start The location in memory to start from.
87 * @param size The size of the memory region to search.
88 * @param align The alignment boundaries to check on.
89 * @param new_node A pointer to the file structure to load.
90 * @param used A pointer to the count of of bytes scanned through,
91 * including the file if one is found.
93 * @return 0 if a file is found, -ENOENT if one isn't, -EBADF if a bad header
96 static int file_cbfs_next_file(struct cbfs_priv *priv, void *start, int size,
97 int align, struct cbfs_cachenode *new_node,
100 struct cbfs_fileheader header;
104 while (size >= align) {
105 const struct cbfs_fileheader *file_header = start;
109 /* Check if there's a file here. */
110 if (memcmp(good_file_magic, &file_header->magic,
111 sizeof(file_header->magic))) {
118 swap_file_header(&header, file_header);
119 if (header.offset < sizeof(struct cbfs_fileheader)) {
120 priv->result = CBFS_BAD_FILE;
123 new_node->next = NULL;
124 new_node->type = header.type;
125 new_node->data = start + header.offset;
126 new_node->data_length = header.len;
127 name_len = header.offset - sizeof(struct cbfs_fileheader);
128 new_node->name = (char *)file_header +
129 sizeof(struct cbfs_fileheader);
130 new_node->name_length = name_len;
131 new_node->attributes_offset = header.attributes_offset;
135 step = step + align - step % align;
144 /* Look through a CBFS instance and copy file metadata into regular memory. */
145 static int file_cbfs_fill_cache(struct cbfs_priv *priv, int size, int align)
147 struct cbfs_cachenode *cache_node;
148 struct cbfs_cachenode *new_node;
149 struct cbfs_cachenode **cache_tail = &priv->file_cache;
152 /* Clear out old information. */
153 cache_node = priv->file_cache;
155 struct cbfs_cachenode *old_node = cache_node;
156 cache_node = cache_node->next;
159 priv->file_cache = NULL;
162 while (size >= align) {
166 new_node = (struct cbfs_cachenode *)
167 malloc(sizeof(struct cbfs_cachenode));
170 ret = file_cbfs_next_file(priv, start, size, align, new_node,
179 *cache_tail = new_node;
180 cache_tail = &new_node->next;
185 priv->result = CBFS_SUCCESS;
191 * load_header() - Load the CBFS header
193 * Get the CBFS header out of the ROM and do endian conversion.
195 * @priv: Private data, which is inited by this function
196 * @addr: Address of CBFS header in memory-mapped SPI flash
197 * @return 0 if OK, -ENXIO if the header is bad
199 static int load_header(struct cbfs_priv *priv, ulong addr)
201 struct cbfs_header *header = &priv->header;
202 struct cbfs_header *header_in_rom;
204 memset(priv, '\0', sizeof(*priv));
205 header_in_rom = (struct cbfs_header *)addr;
206 swap_header(header, header_in_rom);
208 if (header->magic != good_magic || header->offset >
209 header->rom_size - header->boot_block_size) {
210 priv->result = CBFS_BAD_HEADER;
218 * file_cbfs_load_header() - Get the CBFS header out of the ROM, given the end
220 * @priv: Private data, which is inited by this function
221 * @end_of_rom: Address of the last byte of the ROM (typically 0xffffffff)
222 * @return 0 if OK, -ENXIO if the header is bad
224 static int file_cbfs_load_header(struct cbfs_priv *priv, ulong end_of_rom)
226 int offset = *(u32 *)(end_of_rom - 3);
229 ret = load_header(priv, end_of_rom + offset + 1);
232 priv->start = (void *)(end_of_rom + 1 - priv->header.rom_size);
238 * cbfs_load_header_ptr() - Get the CBFS header out of the ROM, given the base
240 * @priv: Private data, which is inited by this function
241 * @base: Address of the first byte of the ROM (e.g. 0xff000000)
242 * @return 0 if OK, -ENXIO if the header is bad
244 static int cbfs_load_header_ptr(struct cbfs_priv *priv, ulong base)
248 ret = load_header(priv, base + MASTER_HDR_OFFSET);
251 priv->start = (void *)base;
256 static void cbfs_init(struct cbfs_priv *priv, ulong end_of_rom)
258 if (file_cbfs_load_header(priv, end_of_rom))
261 file_cbfs_fill_cache(priv, priv->header.rom_size, priv->header.align);
262 if (priv->result == CBFS_SUCCESS)
263 priv->initialized = true;
266 void file_cbfs_init(ulong end_of_rom)
268 cbfs_init(&cbfs_s, end_of_rom);
271 int cbfs_init_mem(ulong base, ulong size, struct cbfs_priv **privp)
273 struct cbfs_priv priv_s, *priv = &priv_s;
277 * Use a local variable to start with until we know that the CBFS is
280 ret = cbfs_load_header_ptr(priv, base);
284 file_cbfs_fill_cache(priv, priv->header.rom_size, priv->header.align);
285 if (priv->result != CBFS_SUCCESS)
288 priv->initialized = true;
289 priv = malloc(sizeof(priv_s));
292 memcpy(priv, &priv_s, sizeof(priv_s));
298 const struct cbfs_header *file_cbfs_get_header(void)
300 struct cbfs_priv *priv = &cbfs_s;
302 if (priv->initialized) {
303 priv->result = CBFS_SUCCESS;
304 return &priv->header;
306 priv->result = CBFS_NOT_INITIALIZED;
311 const struct cbfs_cachenode *file_cbfs_get_first(void)
313 struct cbfs_priv *priv = &cbfs_s;
315 if (!priv->initialized) {
316 priv->result = CBFS_NOT_INITIALIZED;
319 priv->result = CBFS_SUCCESS;
320 return priv->file_cache;
324 void file_cbfs_get_next(const struct cbfs_cachenode **file)
326 struct cbfs_priv *priv = &cbfs_s;
328 if (!priv->initialized) {
329 priv->result = CBFS_NOT_INITIALIZED;
335 *file = (*file)->next;
336 priv->result = CBFS_SUCCESS;
339 const struct cbfs_cachenode *cbfs_find_file(struct cbfs_priv *priv,
342 struct cbfs_cachenode *cache_node = priv->file_cache;
344 if (!priv->initialized) {
345 priv->result = CBFS_NOT_INITIALIZED;
350 if (!strcmp(name, cache_node->name))
352 cache_node = cache_node->next;
355 priv->result = CBFS_FILE_NOT_FOUND;
357 priv->result = CBFS_SUCCESS;
362 const struct cbfs_cachenode *file_cbfs_find(const char *name)
364 return cbfs_find_file(&cbfs_s, name);
367 const struct cbfs_cachenode *file_cbfs_find_uncached(ulong end_of_rom,
370 struct cbfs_priv *priv = &cbfs_s;
374 static struct cbfs_cachenode node;
376 if (file_cbfs_load_header(priv, end_of_rom))
380 size = priv->header.rom_size;
381 align = priv->header.align;
383 while (size >= align) {
387 ret = file_cbfs_next_file(priv, start, size, align, &node,
393 if (!strcmp(name, node.name))
399 cbfs_s.result = CBFS_FILE_NOT_FOUND;
403 const char *file_cbfs_name(const struct cbfs_cachenode *file)
405 cbfs_s.result = CBFS_SUCCESS;
410 u32 file_cbfs_size(const struct cbfs_cachenode *file)
412 cbfs_s.result = CBFS_SUCCESS;
414 return file->data_length;
417 u32 file_cbfs_type(const struct cbfs_cachenode *file)
419 cbfs_s.result = CBFS_SUCCESS;
424 long file_cbfs_read(const struct cbfs_cachenode *file, void *buffer,
425 unsigned long maxsize)
429 size = file->data_length;
430 if (maxsize && size > maxsize)
433 memcpy(buffer, file->data, size);
434 cbfs_s.result = CBFS_SUCCESS;