coreboot
coreboot is an Open Source project aimed at replacing the proprietary BIOS found in most computers.
cbfs_mcache.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0-or-later */
2 
3 #include <assert.h>
5 
6 /*
7  * A CBFS metadata cache is an in memory data structure storing CBFS file headers (= metadata).
8  * It is defined by its start pointer and size. It contains a sequence of variable-length
9  * union mcache_entry entries. There is no overall header structure for the cache.
10  *
11  * Each mcache_entry is the raw metadata for a CBFS file (including attributes) in the same form
12  * as stored on flash (i.e. values in big-endian), except that the CBFS magic signature in the
13  * first 8 bytes ('LARCHIVE') is overwritten with mcache-internal bookkeeping data. The first 4
14  * bytes are a magic number (MCACHE_MAGIC_FILE) and the next 4 bytes are the absolute offset in
15  * bytes on the cbfs_dev_t that this metadata blob was found at. (Note that depending on the
16  * implementation of cbfs_dev_t, this offset may still be relative to the start of a subregion
17  * of the underlying storage device.)
18  *
19  * The length of an mcache_entry (i.e. length of the underlying metadata blob) is encoded in the
20  * metadata (entry->file.h.offset). The next mcache_entry begins at the next
21  * CBFS_MCACHE_ALIGNMENT boundary after that. The cache is terminated by a special 4-byte
22  * mcache_entry that consists only of a magic number (MCACHE_MAGIC_END or MCACHE_MAGIC_FULL).
23  */
24 
25 #define MCACHE_MAGIC_FILE 0x454c4946 /* 'FILE' */
26 #define MCACHE_MAGIC_FULL 0x4c4c5546 /* 'FULL' */
27 #define MCACHE_MAGIC_END 0x444e4524 /* '$END' */
28 
29 union mcache_entry {
30  union cbfs_mdata file;
31  struct { /* These fields exactly overlap file.h.magic */
34  };
35 };
36 
38  void *mcache;
39  void *end;
40  int count;
41 };
42 
43 static enum cb_err build_walker(cbfs_dev_t dev, size_t offset, const union cbfs_mdata *mdata,
44  size_t already_read, void *arg)
45 {
47  union mcache_entry *entry = args->mcache;
48  const uint32_t data_offset = be32toh(mdata->h.offset);
49 
50  if (args->end - args->mcache < data_offset)
51  return CB_CBFS_CACHE_FULL;
52 
53  if (cbfs_copy_fill_metadata(args->mcache, mdata, already_read, dev, offset))
54  return CB_CBFS_IO;
55 
56  entry->magic = MCACHE_MAGIC_FILE;
57  entry->offset = offset;
58 
59  args->mcache += ALIGN_UP(data_offset, CBFS_MCACHE_ALIGNMENT);
60  args->count++;
61 
62  return CB_CBFS_NOT_FOUND;
63 }
64 
65 enum cb_err cbfs_mcache_build(cbfs_dev_t dev, void *mcache, size_t size,
66  struct vb2_hash *metadata_hash)
67 {
68  struct cbfs_mcache_build_args args = {
69  .mcache = mcache,
71  - sizeof(uint32_t), /* leave space for terminating magic */
72  .count = 0,
73  };
74 
76  enum cb_err ret = cbfs_walk(dev, build_walker, &args, metadata_hash, 0);
77  union mcache_entry *entry = args.mcache;
78  if (ret == CB_CBFS_NOT_FOUND) {
79  ret = CB_SUCCESS;
80  entry->magic = MCACHE_MAGIC_END;
81  } else if (ret == CB_CBFS_CACHE_FULL) {
82  ERROR("mcache overflow, should increase CBFS_MCACHE size!\n");
83  entry->magic = MCACHE_MAGIC_FULL;
84  }
85 
86  LOG("mcache @%p built for %d files, used %#zx of %#zx bytes\n", mcache,
87  args.count, args.mcache + sizeof(entry->magic) - mcache, size);
88  return ret;
89 }
90 
91 enum cb_err cbfs_mcache_lookup(const void *mcache, size_t mcache_size, const char *name,
92  union cbfs_mdata *mdata_out, size_t *data_offset_out)
93 {
94  const size_t namesize = strlen(name) + 1; /* Count trailing \0 so we can memcmp() it. */
95  const void *end = mcache + mcache_size;
96  const void *current = mcache;
97 
98  while (current + sizeof(uint32_t) <= end) {
99  const union mcache_entry *entry = current;
100 
101  if (entry->magic == MCACHE_MAGIC_END)
102  return CB_CBFS_NOT_FOUND;
103  if (entry->magic == MCACHE_MAGIC_FULL)
104  return CB_CBFS_CACHE_FULL;
105 
106  assert(entry->magic == MCACHE_MAGIC_FILE);
107  const uint32_t data_offset = be32toh(entry->file.h.offset);
108  const uint32_t data_length = be32toh(entry->file.h.len);
109  if (namesize <= data_offset - offsetof(union cbfs_mdata, h.filename) &&
110  memcmp(name, entry->file.h.filename, namesize) == 0) {
111  LOG("Found '%s' @%#x size %#x in mcache @%p\n",
112  name, entry->offset, data_length, current);
113  *data_offset_out = entry->offset + data_offset;
114  memcpy(mdata_out, &entry->file, data_offset);
115  return CB_SUCCESS;
116  }
117 
118  current += ALIGN_UP(data_offset, CBFS_MCACHE_ALIGNMENT);
119  }
120 
121  ERROR("CBFS mcache is not terminated!\n"); /* should never happen */
122  return CB_ERR;
123 }
124 
125 size_t cbfs_mcache_real_size(const void *mcache, size_t mcache_size)
126 {
127  const void *end = mcache + mcache_size;
128  const void *current = mcache;
129 
130  while (current + sizeof(uint32_t) <= end) {
131  const union mcache_entry *entry = current;
132 
133  if (entry->magic == MCACHE_MAGIC_FULL || entry->magic == MCACHE_MAGIC_END) {
134  current += sizeof(entry->magic);
135  break;
136  }
137 
138  assert(entry->magic == MCACHE_MAGIC_FILE);
139  current += ALIGN_UP(be32toh(entry->file.h.offset), CBFS_MCACHE_ALIGNMENT);
140  }
141 
142  return current - mcache;
143 }
const char * name
Definition: mmu.c:92
void * memcpy(void *dest, const void *src, size_t n)
Definition: memcpy.c:7
#define assert(statement)
Definition: assert.h:74
#define IS_ALIGNED(x, a)
Definition: helpers.h:19
#define offsetof(TYPE, MEMBER)
Definition: helpers.h:84
#define ALIGN_DOWN(x, a)
Definition: helpers.h:18
#define ALIGN_UP(x, a)
Definition: helpers.h:17
cb_err
coreboot error codes
Definition: cb_err.h:15
@ CB_ERR
Generic error code.
Definition: cb_err.h:17
@ CB_CBFS_CACHE_FULL
Metadata cache overflowed.
Definition: cb_err.h:42
@ CB_SUCCESS
Call completed successfully.
Definition: cb_err.h:16
@ CB_CBFS_IO
Underlying I/O error.
Definition: cb_err.h:39
@ CB_CBFS_NOT_FOUND
File not found in directory.
Definition: cb_err.h:40
#define ERROR(...)
Definition: cbfs_glue.h:22
#define LOG(...)
Definition: cbfs_glue.h:23
enum cb_err cbfs_mcache_build(cbfs_dev_t dev, void *mcache, size_t size, struct vb2_hash *metadata_hash)
Definition: cbfs_mcache.c:65
enum cb_err cbfs_mcache_lookup(const void *mcache, size_t mcache_size, const char *name, union cbfs_mdata *mdata_out, size_t *data_offset_out)
Definition: cbfs_mcache.c:91
#define MCACHE_MAGIC_FULL
Definition: cbfs_mcache.c:26
size_t cbfs_mcache_real_size(const void *mcache, size_t mcache_size)
Definition: cbfs_mcache.c:125
#define MCACHE_MAGIC_FILE
Definition: cbfs_mcache.c:25
#define MCACHE_MAGIC_END
Definition: cbfs_mcache.c:27
static enum cb_err build_walker(cbfs_dev_t dev, size_t offset, const union cbfs_mdata *mdata, size_t already_read, void *arg)
Definition: cbfs_mcache.c:43
enum cb_err cbfs_walk(cbfs_dev_t dev, enum cb_err(*walker)(cbfs_dev_t dev, size_t offset, const union cbfs_mdata *mdata, size_t already_read, void *arg), void *arg, struct vb2_hash *metadata_hash, enum cbfs_walk_flags flags)
Definition: cbfs_private.c:25
enum cb_err cbfs_copy_fill_metadata(union cbfs_mdata *dst, const union cbfs_mdata *src, size_t already_read, cbfs_dev_t dev, size_t offset)
Definition: cbfs_private.c:116
#define CBFS_MCACHE_ALIGNMENT
Definition: cbfs_private.h:101
struct @413::@414 args
static size_t offset
Definition: flashconsole.c:16
static uint32_t be32toh(uint32_t big_endian_32bits)
Definition: endian.h:130
struct bootblock_arg arg
Definition: decompressor.c:22
unsigned int uint32_t
Definition: stdint.h:14
unsigned long uintptr_t
Definition: stdint.h:21
int memcmp(const void *s1, const void *s2, size_t n)
Definition: memcmp.c:3
size_t strlen(const char *src)
Definition: string.c:42
uint32_t len
uint32_t offset
char filename[0]
Definition: gcov-glue.c:7
struct cbfs_file h
Definition: cbfs_mdata.h:21
Definition: cbfs_mcache.c:29
uint32_t offset
Definition: cbfs_mcache.c:33
union cbfs_mdata file
Definition: cbfs_mcache.c:30
uint32_t magic
Definition: cbfs_mcache.c:32
#define count