2 * Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
4 * SPDX-License-Identifier: GPL-2.0+
9 #include <asm/byteorder.h>
11 enum cbfs_result file_cbfs_result
;
13 const char *file_cbfs_error(void)
15 switch (file_cbfs_result
) {
18 case CBFS_NOT_INITIALIZED
:
19 return "CBFS not initialized";
21 return "Bad CBFS header";
23 return "Bad CBFS file";
24 case CBFS_FILE_NOT_FOUND
:
25 return "File not found";
32 static const u32 good_magic
= 0x4f524243;
33 static const u8 good_file_magic
[] = "LARCHIVE";
36 static int initialized
;
37 static struct cbfs_header cbfs_header
;
38 static struct cbfs_cachenode
*file_cache
;
40 /* Do endian conversion on the CBFS header structure. */
41 static void swap_header(struct cbfs_header
*dest
, struct cbfs_header
*src
)
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
);
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
)
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
);
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.
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.
74 * @return 1 if a file is found, 0 if one isn't.
76 static int file_cbfs_next_file(u8
*start
, u32 size
, u32 align
,
77 struct cbfs_cachenode
*newNode
, u32
*used
)
79 struct cbfs_fileheader header
;
83 while (size
>= align
) {
84 const struct cbfs_fileheader
*fileHeader
=
85 (const struct cbfs_fileheader
*)start
;
89 /* Check if there's a file here. */
90 if (memcmp(good_file_magic
, &(fileHeader
->magic
),
91 sizeof(fileHeader
->magic
))) {
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
;
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
;
116 step
= step
+ align
- step
% align
;
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
)
127 struct cbfs_cachenode
*cache_node
;
128 struct cbfs_cachenode
*newNode
;
129 struct cbfs_cachenode
**cache_tail
= &file_cache
;
131 /* Clear out old information. */
132 cache_node
= file_cache
;
134 struct cbfs_cachenode
*oldNode
= cache_node
;
135 cache_node
= cache_node
->next
;
140 while (size
>= align
) {
144 newNode
= (struct cbfs_cachenode
*)
145 malloc(sizeof(struct cbfs_cachenode
));
146 result
= file_cbfs_next_file(start
, size
, align
,
152 } else if (result
== 0) {
156 *cache_tail
= newNode
;
157 cache_tail
= &newNode
->next
;
162 file_cbfs_result
= CBFS_SUCCESS
;
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
)
169 struct cbfs_header
*header_in_rom
;
171 header_in_rom
= (struct cbfs_header
*)(uintptr_t)
172 *(u32
*)(end_of_rom
- 3);
173 swap_header(header
, header_in_rom
);
175 if (header
->magic
!= good_magic
|| header
->offset
>
176 header
->rom_size
- header
->boot_block_size
) {
177 file_cbfs_result
= CBFS_BAD_HEADER
;
183 void file_cbfs_init(uintptr_t end_of_rom
)
188 if (file_cbfs_load_header(end_of_rom
, &cbfs_header
))
191 start_of_rom
= (u8
*)(end_of_rom
+ 1 - cbfs_header
.rom_size
);
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
)
199 const struct cbfs_header
*file_cbfs_get_header(void)
202 file_cbfs_result
= CBFS_SUCCESS
;
205 file_cbfs_result
= CBFS_NOT_INITIALIZED
;
210 const struct cbfs_cachenode
*file_cbfs_get_first(void)
213 file_cbfs_result
= CBFS_NOT_INITIALIZED
;
216 file_cbfs_result
= CBFS_SUCCESS
;
221 void file_cbfs_get_next(const struct cbfs_cachenode
**file
)
224 file_cbfs_result
= CBFS_NOT_INITIALIZED
;
230 *file
= (*file
)->next
;
231 file_cbfs_result
= CBFS_SUCCESS
;
234 const struct cbfs_cachenode
*file_cbfs_find(const char *name
)
236 struct cbfs_cachenode
*cache_node
= file_cache
;
239 file_cbfs_result
= CBFS_NOT_INITIALIZED
;
244 if (!strcmp(name
, cache_node
->name
))
246 cache_node
= cache_node
->next
;
249 file_cbfs_result
= CBFS_FILE_NOT_FOUND
;
251 file_cbfs_result
= CBFS_SUCCESS
;
256 const struct cbfs_cachenode
*file_cbfs_find_uncached(uintptr_t end_of_rom
,
262 static struct cbfs_cachenode node
;
264 if (file_cbfs_load_header(end_of_rom
, &cbfs_header
))
267 start
= (u8
*)(end_of_rom
+ 1 - cbfs_header
.rom_size
);
268 size
= cbfs_header
.rom_size
;
269 align
= cbfs_header
.align
;
271 while (size
>= align
) {
275 result
= file_cbfs_next_file(start
, size
, align
, &node
, &used
);
279 else if (result
== 0)
282 if (!strcmp(name
, node
.name
))
288 file_cbfs_result
= CBFS_FILE_NOT_FOUND
;
292 const char *file_cbfs_name(const struct cbfs_cachenode
*file
)
294 file_cbfs_result
= CBFS_SUCCESS
;
298 u32
file_cbfs_size(const struct cbfs_cachenode
*file
)
300 file_cbfs_result
= CBFS_SUCCESS
;
301 return file
->data_length
;
304 u32
file_cbfs_type(const struct cbfs_cachenode
*file
)
306 file_cbfs_result
= CBFS_SUCCESS
;
310 long file_cbfs_read(const struct cbfs_cachenode
*file
, void *buffer
,
311 unsigned long maxsize
)
315 size
= file
->data_length
;
316 if (maxsize
&& size
> maxsize
)
319 memcpy(buffer
, file
->data
, size
);
321 file_cbfs_result
= CBFS_SUCCESS
;