/ src / include / cbfs.h
cbfs.h
  1  /* SPDX-License-Identifier: GPL-2.0-only */
  2  
  3  #ifndef _CBFS_H_
  4  #define _CBFS_H_
  5  
  6  #include <cbmem.h>
  7  #include <commonlib/bsd/cbfs_mdata.h>
  8  #include <commonlib/mem_pool.h>
  9  #include <commonlib/region.h>
 10  #include <endian.h>
 11  #include <program_loading.h>
 12  #include <types.h>
 13  #include <vb2_sha.h>
 14  
 15  
 16  /**********************************************************************************************
 17   *                                  CBFS FILE ACCESS APIs                                     *
 18   **********************************************************************************************/
 19  
 20  /*
 21   * These are the APIs used to access files in CBFS. In order to keep the calls simple and free
 22   * of clutter in the common cases, but still offer all advanced functionality when needed, there
 23   * are many different variations that are implemented by wrapping the same underlying API with
 24   * static inlines. All accessors have in common that they look up files by name, and will
 25   * transparently decompress files that are compressed.
 26   *
 27   * There are three main flavors of CBFS accessors:
 28   *
 29   * size_t cbfs_load(char *name, void *buf, size_t size): Loads the contents of a CBFS file into
 30   *	a buffer provided by the caller (by providing pointer and size to it). Will return the
 31   *	amount of bytes loaded on success, or 0 on error.
 32   *
 33   * void *cbfs_map(char *name, size_t *size_out): Maps a file into the address space. If the file
 34   *	is not compressed and the platform supports direct memory-mapping for the boot medium,
 35   *	a pointer to the platform mapping is returned directly. In all other cases, memory will
 36   *	be allocated from the cbfs_cache and file data will be loaded into there. Returns a
 37   *	pointer to the mapping on success, or NULL on error. If an optional size_out parameter
 38   *	is passed in, it will be filled out with the size of the mapped data. Caller should call
 39   *	cbfs_unmap() after it is done using the mapping to free up the cbfs_cache if possible.
 40   *
 41   * void *cbfs_alloc(char *name, cbfs_allocator_t allocator, void *arg, size_t *size_out): Loads
 42   *	file data into memory provided by a custom allocator function that the caller passes in.
 43   *	The caller may pass an argument that is passed through verbatim to the allocator.
 44   *	Returns the pointer returned by the allocator (where the file data was loaded to) on
 45   *	success, or NULL on error. If an optional size_out parameter is passed in, it will be
 46   *	filled out with the size of the loaded data.
 47   *
 48   * void *cbfs_cbmem_alloc(char *name, uint32_t cbmem_id, size_t *size_out): Wrapper around
 49   *	cbfs_alloc() that will provide an allocator function for allocating space for the file
 50   *	data in CBMEM, with the provided CBMEM ID.
 51   *
 52   * All of these flavors have variations with any of the following optional parameters added:
 53   *
 54   * ..._ro_...: Will force looking up the CBFS file in the read-only CBFS (the "COREBOOT" FMAP
 55   *	section), even when running in an RW stage from one of the RW CBFSs. Only relevant if
 56   *	CONFIG(VBOOT) is set.
 57   *
 58   * ..._unverified_area_...: Will look for the CBFS file in the named FMAP area, rather than
 59   *	any of the default (RO or RW) CBFSs. Files accessed this way are *not* verified in any
 60   *	way (even if CONFIG(CBFS_VERIFICATION) is enabled) and should always be treated as
 61   *	untrusted (potentially malicious) data. Mutually exclusive with the ..._ro_... variant.
 62   *
 63   * ..._type_...: May pass in an extra enum cbfs_type *type parameter. If the value it points to
 64   *	is CBFS_TYPE_QUERY, it will be replaced with the actual CBFS type of the found file. If
 65   *	it is anything else, the type will be compared with the actually found type, and the
 66   *	operation will fail if they don't match.
 67   */
 68  
 69  /*
 70   * An allocator function for passing to cbfs_alloc(). Takes the argument that was originally
 71   * passed to cbfs_alloc(), the size of the file to be loaded, and a pointer to the already
 72   * loaded and verified file metadata (for rare cases where the allocator needs to check custom
 73   * attributes). Must return a pointer to space of the requested size where the file data should
 74   * be loaded, or NULL to make the operation fail.
 75   */
 76  typedef void *(*cbfs_allocator_t)(void *arg, size_t size, const union cbfs_mdata *mdata);
 77  
 78  static inline size_t cbfs_load(const char *name, void *buf, size_t size);
 79  static inline size_t cbfs_ro_load(const char *name, void *buf, size_t size);
 80  static inline size_t cbfs_type_load(const char *name, void *buf, size_t size,
 81  				    enum cbfs_type *type);
 82  static inline size_t cbfs_ro_type_load(const char *name, void *buf, size_t size,
 83  				    enum cbfs_type *type);
 84  static inline size_t cbfs_unverified_area_load(const char *area, const char *name,
 85  					       void *buf, size_t size);
 86  
 87  static inline void *cbfs_map(const char *name, size_t *size_out);
 88  static inline void *cbfs_ro_map(const char *name, size_t *size_out);
 89  static inline void *cbfs_type_map(const char *name, size_t *size_out, enum cbfs_type *type);
 90  static inline void *cbfs_ro_type_map(const char *name, size_t *size_out, enum cbfs_type *type);
 91  static inline void *cbfs_unverified_area_map(const char *area, const char *name,
 92  					      size_t *size_out);
 93  
 94  static inline void *cbfs_alloc(const char *name, cbfs_allocator_t allocator, void *arg,
 95  			       size_t *size_out);
 96  static inline void *cbfs_ro_alloc(const char *name, cbfs_allocator_t allocator, void *arg,
 97  				  size_t *size_out);
 98  static inline void *cbfs_type_alloc(const char *name, cbfs_allocator_t allocator, void *arg,
 99  				    size_t *size_out, enum cbfs_type *type);
100  static inline void *cbfs_ro_type_alloc(const char *name, cbfs_allocator_t allocator, void *arg,
101  				       size_t *size_out, enum cbfs_type *type);
102  static inline void *cbfs_unverified_area_alloc(const char *area, const char *name,
103  						cbfs_allocator_t allocator, void *arg,
104  						size_t *size_out);
105  
106  static inline void *cbfs_cbmem_alloc(const char *name, uint32_t cbmem_id, size_t *size_out);
107  static inline void *cbfs_ro_cbmem_alloc(const char *name, uint32_t cbmem_id, size_t *size_out);
108  static inline void *cbfs_type_cbmem_alloc(const char *name, uint32_t cbmem_id, size_t *size_out,
109  					  enum cbfs_type *type);
110  static inline void *cbfs_ro_type_cbmem_alloc(const char *name, uint32_t cbmem_id,
111  					     size_t *size_out, enum cbfs_type *type);
112  static inline void *cbfs_unverified_area_cbmem_alloc(const char *area, const char *name,
113  						      uint32_t cbmem_id, size_t *size_out);
114  
115  /*
116   * Starts the processes of preloading a file into RAM.
117   *
118   * This method depends on COOP_MULTITASKING to parallelize the loading. This method is only
119   * effective when the underlying rdev supports DMA operations.
120   *
121   * When `cbfs_load`, `cbfs_alloc`, or `cbfs_map` are called after a preload has been started,
122   * they will wait for the preload to complete (if it hasn't already) and then perform
123   * verification and/or decompression.
124   *
125   * This method does not have a return value because the system should boot regardless if this
126   * method succeeds or fails.
127   */
128  void cbfs_preload(const char *name);
129  
130  /* Removes a previously allocated CBFS mapping. Should try to unmap mappings in strict LIFO
131     order where possible, since mapping backends often don't support more complicated cases. */
132  void cbfs_unmap(void *mapping);
133  
134  /* Load stage into memory filling in prog. Return 0 on success. < 0 on error. */
135  enum cb_err cbfs_prog_stage_load(struct prog *prog);
136  
137  /* Returns the size of a CBFS file, or 0 on error. Avoid using this function to allocate space,
138     and instead use cbfs_alloc() so the file only needs to be looked up once. */
139  static inline size_t cbfs_get_size(const char *name);
140  static inline size_t cbfs_ro_get_size(const char *name);
141  
142  /* Returns the type of a CBFS file, or CBFS_TYPE_NULL on error. Use cbfs_type_load() instead of
143     this where possible to avoid looking up the file more than once. */
144  static inline enum cbfs_type cbfs_get_type(const char *name);
145  static inline enum cbfs_type cbfs_ro_get_type(const char *name);
146  
147  /* Check whether a CBFS file exists. */
148  static inline bool cbfs_file_exists(const char *name);
149  static inline bool cbfs_ro_file_exists(const char *name);
150  
151  
152  /**********************************************************************************************
153   *                                BOOT DEVICE HELPER APIs                                     *
154   **********************************************************************************************/
155  
156  /*
157   * The shared memory pool for backing mapped CBFS files, and other CBFS allocation needs.
158   */
159  extern struct mem_pool cbfs_cache;
160  
161  /*
162   * Data structure that represents "a" CBFS boot device, with optional metadata cache. Generally
163   * we only have one of these, or two (RO and RW) when CONFIG(VBOOT) is set. The region device
164   * stored here must always be a subregion of boot_device_ro().
165   */
166  struct cbfs_boot_device {
167  	struct region_device rdev;
168  	void *mcache;
169  	size_t mcache_size;
170  };
171  
172  /* Helper to fill out |mcache| and |mcache_size| in a cbfs_boot_device. */
173  void cbfs_boot_device_find_mcache(struct cbfs_boot_device *cbd, uint32_t id);
174  
175  /*
176   * Retrieves the currently active CBFS boot device. If |force_ro| is set, will always return the
177   * read-only CBFS instead (this only makes a difference when CONFIG(VBOOT) is enabled). May
178   * perform certain CBFS initialization tasks. Returns NULL on error (e.g. boot device IO error).
179   */
180  const struct cbfs_boot_device *cbfs_get_boot_device(bool force_ro);
181  
182  /*
183   * Builds the mcache (if |cbd->mcache| is set) and verifies |metadata_hash| (if it is not NULL).
184   * If CB_CBFS_CACHE_FULL is returned, the mcache is incomplete but still valid and the metadata
185   * hash was still verified. Should be called once per *boot* (not once per stage) before the
186   * first CBFS access.
187   */
188  enum cb_err cbfs_init_boot_device(const struct cbfs_boot_device *cbd,
189  				  struct vb2_hash *metadata_hash);
190  
191  
192  /**********************************************************************************************
193   *                         INTERNAL HELPERS FOR INLINES, DO NOT USE.                          *
194   **********************************************************************************************/
195  enum cb_err _cbfs_boot_lookup(const char *name, bool force_ro,
196  			      union cbfs_mdata *mdata, struct region_device *rdev);
197  
198  void *_cbfs_alloc(const char *name, cbfs_allocator_t allocator, void *arg,
199  		  size_t *size_out, bool force_ro, enum cbfs_type *type);
200  
201  void *_cbfs_unverified_area_alloc(const char *area, const char *name,
202  				  cbfs_allocator_t allocator, void *arg, size_t *size_out);
203  
204  struct _cbfs_default_allocator_arg {
205  	void *buf;
206  	size_t buf_size;
207  };
208  void *_cbfs_default_allocator(void *arg, size_t size, const union cbfs_mdata *unused);
209  
210  void *_cbfs_cbmem_allocator(void *arg, size_t size, const union cbfs_mdata *unused);
211  
212  /**********************************************************************************************
213   *                                  INLINE IMPLEMENTATIONS                                    *
214   **********************************************************************************************/
215  static inline void *cbfs_alloc(const char *name, cbfs_allocator_t allocator, void *arg,
216  			       size_t *size_out)
217  {
218  	return cbfs_type_alloc(name, allocator, arg, size_out, NULL);
219  }
220  
221  static inline void *cbfs_ro_alloc(const char *name, cbfs_allocator_t allocator, void *arg,
222  				  size_t *size_out)
223  {
224  	return cbfs_ro_type_alloc(name, allocator, arg, size_out, NULL);
225  }
226  
227  static inline void *cbfs_type_alloc(const char *name, cbfs_allocator_t allocator, void *arg,
228  				    size_t *size_out, enum cbfs_type *type)
229  {
230  	return _cbfs_alloc(name, allocator, arg, size_out, false, type);
231  }
232  
233  static inline void *cbfs_ro_type_alloc(const char *name, cbfs_allocator_t allocator, void *arg,
234  				       size_t *size_out, enum cbfs_type *type)
235  {
236  	return _cbfs_alloc(name, allocator, arg, size_out, true, type);
237  }
238  
239  static inline void *cbfs_unverified_area_alloc(const char *area, const char *name,
240  					       cbfs_allocator_t allocator, void *arg,
241  					       size_t *size_out)
242  {
243  	return _cbfs_unverified_area_alloc(area, name, allocator, arg, size_out);
244  }
245  
246  static inline void *cbfs_map(const char *name, size_t *size_out)
247  {
248  	return cbfs_type_map(name, size_out, NULL);
249  }
250  
251  static inline void *cbfs_ro_map(const char *name, size_t *size_out)
252  {
253  	return cbfs_ro_type_map(name, size_out, NULL);
254  }
255  
256  static inline void *cbfs_type_map(const char *name, size_t *size_out, enum cbfs_type *type)
257  {
258  	return cbfs_type_alloc(name, NULL, NULL, size_out, type);
259  }
260  
261  static inline void *cbfs_ro_type_map(const char *name, size_t *size_out, enum cbfs_type *type)
262  {
263  	return cbfs_ro_type_alloc(name, NULL, NULL, size_out, type);
264  }
265  
266  static inline void *cbfs_unverified_area_map(const char *area, const char *name,
267  					     size_t *size_out)
268  {
269  	return _cbfs_unverified_area_alloc(area, name, NULL, NULL, size_out);
270  }
271  
272  static inline size_t _cbfs_load(const char *name, void *buf, size_t size, bool force_ro,
273  				enum cbfs_type *type)
274  {
275  	struct _cbfs_default_allocator_arg arg = { .buf = buf, .buf_size = size };
276  	if (_cbfs_alloc(name, _cbfs_default_allocator, &arg, &size, force_ro, type))
277  		return size;
278  	else
279  		return 0;
280  }
281  
282  static inline size_t cbfs_load(const char *name, void *buf, size_t size)
283  {
284  	return cbfs_type_load(name, buf, size, NULL);
285  }
286  
287  static inline size_t cbfs_type_load(const char *name, void *buf, size_t size,
288  				    enum cbfs_type *type)
289  {
290  	return _cbfs_load(name, buf, size, false, type);
291  }
292  
293  static inline size_t cbfs_ro_load(const char *name, void *buf, size_t size)
294  {
295  	return cbfs_ro_type_load(name, buf, size, NULL);
296  }
297  
298  static inline size_t cbfs_ro_type_load(const char *name, void *buf, size_t size,
299  				    enum cbfs_type *type)
300  {
301  	return _cbfs_load(name, buf, size, true, type);
302  }
303  
304  static inline size_t cbfs_unverified_area_load(const char *area, const char *name,
305  					       void *buf, size_t size)
306  {
307  	struct _cbfs_default_allocator_arg arg = { .buf = buf, .buf_size = size };
308  	if (_cbfs_unverified_area_alloc(area, name, _cbfs_default_allocator, &arg, &size))
309  		return size;
310  	else
311  		return 0;
312  }
313  
314  static inline void *cbfs_cbmem_alloc(const char *name, uint32_t cbmem_id, size_t *size_out)
315  {
316  	return cbfs_type_cbmem_alloc(name, cbmem_id, size_out, NULL);
317  }
318  
319  static inline void *cbfs_ro_cbmem_alloc(const char *name, uint32_t cbmem_id, size_t *size_out)
320  {
321  	return cbfs_ro_type_cbmem_alloc(name, cbmem_id, size_out, NULL);
322  }
323  
324  static inline void *cbfs_type_cbmem_alloc(const char *name, uint32_t cbmem_id, size_t *size_out,
325  					  enum cbfs_type *type)
326  {
327  	return cbfs_type_alloc(name, _cbfs_cbmem_allocator, (void *)(uintptr_t)cbmem_id,
328  			       size_out, type);
329  }
330  
331  static inline void *cbfs_ro_type_cbmem_alloc(const char *name, uint32_t cbmem_id,
332  					     size_t *size_out, enum cbfs_type *type)
333  {
334  	return cbfs_ro_type_alloc(name, _cbfs_cbmem_allocator, (void *)(uintptr_t)cbmem_id,
335  				  size_out, type);
336  }
337  
338  static inline void *cbfs_unverified_area_cbmem_alloc(const char *area, const char *name,
339  						     uint32_t cbmem_id, size_t *size_out)
340  {
341  	return _cbfs_unverified_area_alloc(area, name, _cbfs_cbmem_allocator,
342  					   (void *)(uintptr_t)cbmem_id, size_out);
343  }
344  
345  static inline size_t cbfs_get_size(const char *name)
346  {
347  	union cbfs_mdata mdata;
348  	struct region_device rdev;
349  	if (_cbfs_boot_lookup(name, false, &mdata, &rdev) != CB_SUCCESS)
350  		return 0;
351  	return be32toh(mdata.h.len);
352  }
353  
354  static inline size_t cbfs_ro_get_size(const char *name)
355  {
356  	union cbfs_mdata mdata;
357  	struct region_device rdev;
358  	if (_cbfs_boot_lookup(name, true, &mdata, &rdev) != CB_SUCCESS)
359  		return 0;
360  	return be32toh(mdata.h.len);
361  }
362  
363  static inline enum cbfs_type cbfs_get_type(const char *name)
364  {
365  	union cbfs_mdata mdata;
366  	struct region_device rdev;
367  	if (_cbfs_boot_lookup(name, false, &mdata, &rdev) != CB_SUCCESS)
368  		return CBFS_TYPE_NULL;
369  	return be32toh(mdata.h.type);
370  }
371  
372  static inline enum cbfs_type cbfs_ro_get_type(const char *name)
373  {
374  	union cbfs_mdata mdata;
375  	struct region_device rdev;
376  	if (_cbfs_boot_lookup(name, true, &mdata, &rdev) != CB_SUCCESS)
377  		return CBFS_TYPE_NULL;
378  	return be32toh(mdata.h.type);
379  }
380  
381  static inline bool cbfs_file_exists(const char *name)
382  {
383  	union cbfs_mdata mdata;
384  	struct region_device rdev;
385  	if (_cbfs_boot_lookup(name, false, &mdata, &rdev) != CB_SUCCESS)
386  		return false;
387  	return true;
388  }
389  
390  static inline bool cbfs_ro_file_exists(const char *name)
391  {
392  	union cbfs_mdata mdata;
393  	struct region_device rdev;
394  	if (_cbfs_boot_lookup(name, true, &mdata, &rdev) != CB_SUCCESS)
395  		return false;
396  	return true;
397  }
398  
399  #endif