blob: 8714cc0ec62fdbf48e9b4eafdee07c62ba94da69 [file] [log] [blame]
Julius Werner1e37c9c2019-12-11 17:09:39 -08001/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0-or-later */
2
3#include <assert.h>
4#include <commonlib/bsd/cbfs_private.h>
Thomas Heijligen3f9613b2022-11-28 11:46:48 +01005#include <commonlib/bsd/helpers.h>
Julius Werner1e37c9c2019-12-11 17:09:39 -08006
7/*
8 * A CBFS metadata cache is an in memory data structure storing CBFS file headers (= metadata).
9 * It is defined by its start pointer and size. It contains a sequence of variable-length
10 * union mcache_entry entries. There is no overall header structure for the cache.
11 *
12 * Each mcache_entry is the raw metadata for a CBFS file (including attributes) in the same form
13 * as stored on flash (i.e. values in big-endian), except that the CBFS magic signature in the
14 * first 8 bytes ('LARCHIVE') is overwritten with mcache-internal bookkeeping data. The first 4
15 * bytes are a magic number (MCACHE_MAGIC_FILE) and the next 4 bytes are the absolute offset in
16 * bytes on the cbfs_dev_t that this metadata blob was found at. (Note that depending on the
17 * implementation of cbfs_dev_t, this offset may still be relative to the start of a subregion
18 * of the underlying storage device.)
19 *
20 * The length of an mcache_entry (i.e. length of the underlying metadata blob) is encoded in the
21 * metadata (entry->file.h.offset). The next mcache_entry begins at the next
22 * CBFS_MCACHE_ALIGNMENT boundary after that. The cache is terminated by a special 4-byte
23 * mcache_entry that consists only of a magic number (MCACHE_MAGIC_END or MCACHE_MAGIC_FULL).
24 */
25
26#define MCACHE_MAGIC_FILE 0x454c4946 /* 'FILE' */
27#define MCACHE_MAGIC_FULL 0x4c4c5546 /* 'FULL' */
28#define MCACHE_MAGIC_END 0x444e4524 /* '$END' */
29
30union mcache_entry {
31 union cbfs_mdata file;
32 struct { /* These fields exactly overlap file.h.magic */
33 uint32_t magic;
34 uint32_t offset;
35 };
36};
37
38struct cbfs_mcache_build_args {
39 void *mcache;
40 void *end;
41 int count;
42};
43
Julius Werner69cc5572022-03-04 17:49:56 -080044static enum cb_err build_walker(cbfs_dev_t dev, size_t offset, const union cbfs_mdata *mdata,
45 size_t already_read, void *arg)
Julius Werner1e37c9c2019-12-11 17:09:39 -080046{
47 struct cbfs_mcache_build_args *args = arg;
48 union mcache_entry *entry = args->mcache;
49 const uint32_t data_offset = be32toh(mdata->h.offset);
50
51 if (args->end - args->mcache < data_offset)
52 return CB_CBFS_CACHE_FULL;
53
54 if (cbfs_copy_fill_metadata(args->mcache, mdata, already_read, dev, offset))
55 return CB_CBFS_IO;
56
57 entry->magic = MCACHE_MAGIC_FILE;
58 entry->offset = offset;
59
60 args->mcache += ALIGN_UP(data_offset, CBFS_MCACHE_ALIGNMENT);
61 args->count++;
62
63 return CB_CBFS_NOT_FOUND;
64}
65
Julius Werner69cc5572022-03-04 17:49:56 -080066enum cb_err cbfs_mcache_build(cbfs_dev_t dev, void *mcache, size_t size,
67 struct vb2_hash *metadata_hash)
Julius Werner1e37c9c2019-12-11 17:09:39 -080068{
69 struct cbfs_mcache_build_args args = {
70 .mcache = mcache,
71 .end = mcache + ALIGN_DOWN(size, CBFS_MCACHE_ALIGNMENT)
72 - sizeof(uint32_t), /* leave space for terminating magic */
73 .count = 0,
74 };
75
76 assert(size > sizeof(uint32_t) && IS_ALIGNED((uintptr_t)mcache, CBFS_MCACHE_ALIGNMENT));
Julius Werner69cc5572022-03-04 17:49:56 -080077 enum cb_err ret = cbfs_walk(dev, build_walker, &args, metadata_hash, 0);
Julius Werner1e37c9c2019-12-11 17:09:39 -080078 union mcache_entry *entry = args.mcache;
79 if (ret == CB_CBFS_NOT_FOUND) {
80 ret = CB_SUCCESS;
81 entry->magic = MCACHE_MAGIC_END;
82 } else if (ret == CB_CBFS_CACHE_FULL) {
83 ERROR("mcache overflow, should increase CBFS_MCACHE size!\n");
84 entry->magic = MCACHE_MAGIC_FULL;
85 }
86
87 LOG("mcache @%p built for %d files, used %#zx of %#zx bytes\n", mcache,
88 args.count, args.mcache + sizeof(entry->magic) - mcache, size);
89 return ret;
90}
91
Julius Werner69cc5572022-03-04 17:49:56 -080092enum cb_err cbfs_mcache_lookup(const void *mcache, size_t mcache_size, const char *name,
93 union cbfs_mdata *mdata_out, size_t *data_offset_out)
Julius Werner1e37c9c2019-12-11 17:09:39 -080094{
95 const size_t namesize = strlen(name) + 1; /* Count trailing \0 so we can memcmp() it. */
96 const void *end = mcache + mcache_size;
97 const void *current = mcache;
98
Julius Werner20f5dce2020-12-03 12:25:11 -080099 while (current + sizeof(uint32_t) <= end) {
Julius Werner1e37c9c2019-12-11 17:09:39 -0800100 const union mcache_entry *entry = current;
101
102 if (entry->magic == MCACHE_MAGIC_END)
103 return CB_CBFS_NOT_FOUND;
104 if (entry->magic == MCACHE_MAGIC_FULL)
105 return CB_CBFS_CACHE_FULL;
106
107 assert(entry->magic == MCACHE_MAGIC_FILE);
108 const uint32_t data_offset = be32toh(entry->file.h.offset);
109 const uint32_t data_length = be32toh(entry->file.h.len);
Julius Wernerd4775652020-03-13 16:43:34 -0700110 if (namesize <= data_offset - offsetof(union cbfs_mdata, h.filename) &&
111 memcmp(name, entry->file.h.filename, namesize) == 0) {
Julius Werner1e37c9c2019-12-11 17:09:39 -0800112 LOG("Found '%s' @%#x size %#x in mcache @%p\n",
113 name, entry->offset, data_length, current);
114 *data_offset_out = entry->offset + data_offset;
115 memcpy(mdata_out, &entry->file, data_offset);
116 return CB_SUCCESS;
117 }
118
119 current += ALIGN_UP(data_offset, CBFS_MCACHE_ALIGNMENT);
120 }
121
Julius Wernerb5718462021-04-08 17:08:28 -0700122 ERROR("CBFS mcache is not terminated!\n"); /* should never happen */
Julius Werner1e37c9c2019-12-11 17:09:39 -0800123 return CB_ERR;
124}
125
126size_t cbfs_mcache_real_size(const void *mcache, size_t mcache_size)
127{
128 const void *end = mcache + mcache_size;
129 const void *current = mcache;
130
Julius Wernerb5718462021-04-08 17:08:28 -0700131 while (current + sizeof(uint32_t) <= end) {
Julius Werner1e37c9c2019-12-11 17:09:39 -0800132 const union mcache_entry *entry = current;
133
134 if (entry->magic == MCACHE_MAGIC_FULL || entry->magic == MCACHE_MAGIC_END) {
135 current += sizeof(entry->magic);
136 break;
137 }
138
139 assert(entry->magic == MCACHE_MAGIC_FILE);
140 current += ALIGN_UP(be32toh(entry->file.h.offset), CBFS_MCACHE_ALIGNMENT);
141 }
142
143 return current - mcache;
144}