2 * Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
4 * SPDX-License-Identifier: GPL-2.0+
10 #include <asm/byteorder.h>
12 enum cbfs_result file_cbfs_result
;
14 const char *file_cbfs_error(void)
16 switch (file_cbfs_result
) {
19 case CBFS_NOT_INITIALIZED
:
20 return "CBFS not initialized";
22 return "Bad CBFS header";
24 return "Bad CBFS file";
25 case CBFS_FILE_NOT_FOUND
:
26 return "File not found";
33 static const u32 good_magic
= 0x4f524243;
34 static const u8 good_file_magic
[] = "LARCHIVE";
37 static int initialized
;
38 static struct cbfs_header cbfs_header
;
39 static struct cbfs_cachenode
*file_cache
;
41 /* Do endian conversion on the CBFS header structure. */
42 static void swap_header(struct cbfs_header
*dest
, struct cbfs_header
*src
)
44 dest
->magic
= be32_to_cpu(src
->magic
);
45 dest
->version
= be32_to_cpu(src
->version
);
46 dest
->rom_size
= be32_to_cpu(src
->rom_size
);
47 dest
->boot_block_size
= be32_to_cpu(src
->boot_block_size
);
48 dest
->align
= be32_to_cpu(src
->align
);
49 dest
->offset
= be32_to_cpu(src
->offset
);
52 /* Do endian conversion on a CBFS file header. */
53 static void swap_file_header(struct cbfs_fileheader
*dest
,
54 const struct cbfs_fileheader
*src
)
56 memcpy(&dest
->magic
, &src
->magic
, sizeof(dest
->magic
));
57 dest
->len
= be32_to_cpu(src
->len
);
58 dest
->type
= be32_to_cpu(src
->type
);
59 dest
->checksum
= be32_to_cpu(src
->checksum
);
60 dest
->offset
= be32_to_cpu(src
->offset
);
64 * Given a starting position in memory, scan forward, bounded by a size, and
65 * find the next valid CBFS file. No memory is allocated by this function. The
66 * caller is responsible for allocating space for the new file structure.
68 * @param start The location in memory to start from.
69 * @param size The size of the memory region to search.
70 * @param align The alignment boundaries to check on.
71 * @param newNode A pointer to the file structure to load.
72 * @param used A pointer to the count of of bytes scanned through,
73 * including the file if one is found.
75 * @return 1 if a file is found, 0 if one isn't.
77 static int file_cbfs_next_file(u8
*start
, u32 size
, u32 align
,
78 struct cbfs_cachenode
*newNode
, u32
*used
)
80 struct cbfs_fileheader header
;
84 while (size
>= align
) {
85 const struct cbfs_fileheader
*fileHeader
=
86 (const struct cbfs_fileheader
*)start
;
90 /* Check if there's a file here. */
91 if (memcmp(good_file_magic
, &(fileHeader
->magic
),
92 sizeof(fileHeader
->magic
))) {
99 swap_file_header(&header
, fileHeader
);
100 if (header
.offset
< sizeof(struct cbfs_fileheader
) ||
101 header
.offset
> header
.len
) {
102 file_cbfs_result
= CBFS_BAD_FILE
;
105 newNode
->next
= NULL
;
106 newNode
->type
= header
.type
;
107 newNode
->data
= start
+ header
.offset
;
108 newNode
->data_length
= header
.len
;
109 name_len
= header
.offset
- sizeof(struct cbfs_fileheader
);
110 newNode
->name
= (char *)fileHeader
+
111 sizeof(struct cbfs_fileheader
);
112 newNode
->name_length
= name_len
;
113 newNode
->checksum
= header
.checksum
;
117 step
= step
+ align
- step
% align
;
125 /* Look through a CBFS instance and copy file metadata into regular memory. */
126 static void file_cbfs_fill_cache(u8
*start
, u32 size
, u32 align
)
128 struct cbfs_cachenode
*cache_node
;
129 struct cbfs_cachenode
*newNode
;
130 struct cbfs_cachenode
**cache_tail
= &file_cache
;
132 /* Clear out old information. */
133 cache_node
= file_cache
;
135 struct cbfs_cachenode
*oldNode
= cache_node
;
136 cache_node
= cache_node
->next
;
141 while (size
>= align
) {
145 newNode
= (struct cbfs_cachenode
*)
146 malloc(sizeof(struct cbfs_cachenode
));
147 result
= file_cbfs_next_file(start
, size
, align
,
153 } else if (result
== 0) {
157 *cache_tail
= newNode
;
158 cache_tail
= &newNode
->next
;
163 file_cbfs_result
= CBFS_SUCCESS
;
166 /* Get the CBFS header out of the ROM and do endian conversion. */
167 static int file_cbfs_load_header(uintptr_t end_of_rom
,
168 struct cbfs_header
*header
)
170 struct cbfs_header
*header_in_rom
;
172 header_in_rom
= (struct cbfs_header
*)(uintptr_t)
173 *(u32
*)(end_of_rom
- 3);
174 swap_header(header
, header_in_rom
);
176 if (header
->magic
!= good_magic
|| header
->offset
>
177 header
->rom_size
- header
->boot_block_size
) {
178 file_cbfs_result
= CBFS_BAD_HEADER
;
184 void file_cbfs_init(uintptr_t end_of_rom
)
189 if (file_cbfs_load_header(end_of_rom
, &cbfs_header
))
192 start_of_rom
= (u8
*)(end_of_rom
+ 1 - cbfs_header
.rom_size
);
194 file_cbfs_fill_cache(start_of_rom
+ cbfs_header
.offset
,
195 cbfs_header
.rom_size
, cbfs_header
.align
);
196 if (file_cbfs_result
== CBFS_SUCCESS
)
200 const struct cbfs_header
*file_cbfs_get_header(void)
203 file_cbfs_result
= CBFS_SUCCESS
;
206 file_cbfs_result
= CBFS_NOT_INITIALIZED
;
211 const struct cbfs_cachenode
*file_cbfs_get_first(void)
214 file_cbfs_result
= CBFS_NOT_INITIALIZED
;
217 file_cbfs_result
= CBFS_SUCCESS
;
222 void file_cbfs_get_next(const struct cbfs_cachenode
**file
)
225 file_cbfs_result
= CBFS_NOT_INITIALIZED
;
231 *file
= (*file
)->next
;
232 file_cbfs_result
= CBFS_SUCCESS
;
235 const struct cbfs_cachenode
*file_cbfs_find(const char *name
)
237 struct cbfs_cachenode
*cache_node
= file_cache
;
240 file_cbfs_result
= CBFS_NOT_INITIALIZED
;
245 if (!strcmp(name
, cache_node
->name
))
247 cache_node
= cache_node
->next
;
250 file_cbfs_result
= CBFS_FILE_NOT_FOUND
;
252 file_cbfs_result
= CBFS_SUCCESS
;
257 const struct cbfs_cachenode
*file_cbfs_find_uncached(uintptr_t end_of_rom
,
263 static struct cbfs_cachenode node
;
265 if (file_cbfs_load_header(end_of_rom
, &cbfs_header
))
268 start
= (u8
*)(end_of_rom
+ 1 - cbfs_header
.rom_size
);
269 size
= cbfs_header
.rom_size
;
270 align
= cbfs_header
.align
;
272 while (size
>= align
) {
276 result
= file_cbfs_next_file(start
, size
, align
, &node
, &used
);
280 else if (result
== 0)
283 if (!strcmp(name
, node
.name
))
289 file_cbfs_result
= CBFS_FILE_NOT_FOUND
;
293 const char *file_cbfs_name(const struct cbfs_cachenode
*file
)
295 file_cbfs_result
= CBFS_SUCCESS
;
299 u32
file_cbfs_size(const struct cbfs_cachenode
*file
)
301 file_cbfs_result
= CBFS_SUCCESS
;
302 return file
->data_length
;
305 u32
file_cbfs_type(const struct cbfs_cachenode
*file
)
307 file_cbfs_result
= CBFS_SUCCESS
;
311 long file_cbfs_read(const struct cbfs_cachenode
*file
, void *buffer
,
312 unsigned long maxsize
)
316 size
= file
->data_length
;
317 if (maxsize
&& size
> maxsize
)
320 memcpy(buffer
, file
->data
, size
);
322 file_cbfs_result
= CBFS_SUCCESS
;