soc/intel: Remove blank lines before '}' and after '{'
[coreboot2.git] / payloads / libpayload / libcbfs / cbfs.c
blob0cee9145dfbc8705fd6c52ceb1238d28b8891989
1 /* SPDX-License-Identifier: BSD-3-Clause */
3 #include <libpayload-config.h>
4 #include <arch/virtual.h>
5 #include <assert.h>
6 #include <cbfs.h>
7 #include <cbfs_glue.h>
8 #include <commonlib/bsd/cbfs_private.h>
9 #include <commonlib/bsd/fmap_serialized.h>
10 #include <libpayload.h>
11 #include <lp_vboot.h>
12 #include <lz4.h>
13 #include <lzma.h>
14 #include <string.h>
15 #include <sysinfo.h>
18 static const struct cbfs_boot_device *cbfs_get_boot_device(bool force_ro)
20 static struct cbfs_boot_device ro;
21 static struct cbfs_boot_device rw;
23 if (!force_ro) {
24 if (!rw.dev.size) {
25 rw.dev.offset = lib_sysinfo.cbfs_offset;
26 rw.dev.size = lib_sysinfo.cbfs_size;
27 rw.mcache = phys_to_virt(lib_sysinfo.cbfs_rw_mcache_offset);
28 rw.mcache_size = lib_sysinfo.cbfs_rw_mcache_size;
30 return &rw;
33 if (ro.dev.size)
34 return &ro;
36 if (fmap_locate_area("COREBOOT", &ro.dev.offset, &ro.dev.size))
37 return NULL;
39 ro.mcache = phys_to_virt(lib_sysinfo.cbfs_ro_mcache_offset);
40 ro.mcache_size = lib_sysinfo.cbfs_ro_mcache_size;
42 return &ro;
45 ssize_t _cbfs_boot_lookup(const char *name, bool force_ro, union cbfs_mdata *mdata)
47 const struct cbfs_boot_device *cbd = cbfs_get_boot_device(force_ro);
48 if (!cbd)
49 return CB_ERR;
51 size_t data_offset;
52 enum cb_err err = CB_CBFS_CACHE_FULL;
53 if (cbd->mcache_size)
54 err = cbfs_mcache_lookup(cbd->mcache, cbd->mcache_size, name, mdata,
55 &data_offset);
57 if (err == CB_CBFS_CACHE_FULL)
58 err = cbfs_lookup(&cbd->dev, name, mdata, &data_offset, NULL);
60 /* Fallback to RO if possible. */
61 if (CONFIG(LP_ENABLE_CBFS_FALLBACK) && !force_ro && err == CB_CBFS_NOT_FOUND) {
62 LOG("Fall back to RO region for '%s'\n", name);
63 return _cbfs_boot_lookup(name, true, mdata);
66 if (err) {
67 if (err == CB_CBFS_NOT_FOUND)
68 LOG("'%s' not found.\n", name);
69 else
70 ERROR("Error %d when looking up '%s'\n", err, name);
71 return err;
74 return cbd->dev.offset + data_offset;
77 void cbfs_unmap(void *mapping)
79 free(mapping);
82 static bool cbfs_file_hash_mismatch(const void *buffer, size_t size,
83 const union cbfs_mdata *mdata, bool skip_verification)
85 if (!CONFIG(LP_CBFS_VERIFICATION) || skip_verification)
86 return false;
88 const struct vb2_hash *hash = cbfs_file_hash(mdata);
89 if (!hash) {
90 ERROR("'%s' does not have a file hash!\n", mdata->h.filename);
91 return true;
93 vb2_error_t rv = vb2_hash_verify(cbfs_hwcrypto_allowed(), buffer, size, hash);
94 if (rv != VB2_SUCCESS) {
95 ERROR("'%s' file hash mismatch!\n", mdata->h.filename);
96 if (CONFIG(LP_VBOOT_CBFS_INTEGRATION) && !vboot_recovery_mode_enabled())
97 vboot_fail_and_reboot(vboot_get_context(), VB2_RECOVERY_FW_BODY, rv);
98 return true;
101 return false;
104 static size_t cbfs_load_and_decompress(size_t offset, size_t in_size, void *buffer,
105 size_t buffer_size, uint32_t compression,
106 const union cbfs_mdata *mdata, bool skip_verification)
108 void *load = buffer;
109 size_t out_size = 0;
111 DEBUG("Decompressing %zu bytes from '%s' to %p with algo %d\n", in_size,
112 mdata->h.filename, buffer, compression);
114 if (compression != CBFS_COMPRESS_NONE) {
115 load = malloc(in_size);
116 if (!load) {
117 ERROR("'%s' buffer allocation failed\n", mdata->h.filename);
118 return 0;
122 if (boot_device_read(load, offset, in_size) != in_size) {
123 ERROR("'%s' failed to read contents of file\n", mdata->h.filename);
124 goto out;
127 if (cbfs_file_hash_mismatch(load, in_size, mdata, skip_verification))
128 goto out;
130 switch (compression) {
131 case CBFS_COMPRESS_NONE:
132 out_size = in_size;
133 break;
134 case CBFS_COMPRESS_LZ4:
135 if (!CONFIG(LP_LZ4))
136 goto out;
137 out_size = ulz4fn(load, in_size, buffer, buffer_size);
138 break;
139 case CBFS_COMPRESS_LZMA:
140 if (!CONFIG(LP_LZMA))
141 goto out;
142 out_size = ulzman(load, in_size, buffer, buffer_size);
143 break;
144 default:
145 ERROR("'%s' decompression algo %d not supported\n", mdata->h.filename,
146 compression);
148 out:
149 if (load != buffer)
150 free(load);
151 return out_size;
154 static void *do_load(union cbfs_mdata *mdata, ssize_t offset, void *buf, size_t *size_inout,
155 bool skip_verification)
157 bool malloced = false;
158 size_t buf_size = 0;
159 size_t out_size;
160 uint32_t compression = CBFS_COMPRESS_NONE;
161 const struct cbfs_file_attr_compression *cattr =
162 cbfs_find_attr(mdata, CBFS_FILE_ATTR_TAG_COMPRESSION, sizeof(*cattr));
163 if (cattr) {
164 compression = be32toh(cattr->compression);
165 out_size = be32toh(cattr->decompressed_size);
166 } else {
167 out_size = be32toh(mdata->h.len);
170 if (size_inout) {
171 buf_size = *size_inout;
172 *size_inout = out_size;
175 if (buf) {
176 if (!size_inout || buf_size < out_size) {
177 ERROR("'%s' buffer too small\n", mdata->h.filename);
178 return NULL;
180 } else {
181 buf = malloc(out_size);
182 if (!buf) {
183 ERROR("'%s' allocation failure\n", mdata->h.filename);
184 return NULL;
186 malloced = true;
189 if (cbfs_load_and_decompress(offset, be32toh(mdata->h.len), buf, out_size, compression,
190 mdata, skip_verification)
191 != out_size) {
192 if (malloced)
193 free(buf);
194 return NULL;
197 return buf;
200 void *_cbfs_load(const char *name, void *buf, size_t *size_inout, bool force_ro)
202 ssize_t offset;
203 union cbfs_mdata mdata;
205 DEBUG("%s(name='%s', buf=%p, force_ro=%s)\n", __func__, name, buf,
206 force_ro ? "true" : "false");
208 offset = _cbfs_boot_lookup(name, force_ro, &mdata);
209 if (offset < 0)
210 return NULL;
212 return do_load(&mdata, offset, buf, size_inout, false);
215 void *_cbfs_unverified_area_load(const char *area, const char *name, void *buf,
216 size_t *size_inout)
218 struct cbfs_dev dev;
219 union cbfs_mdata mdata;
220 size_t data_offset;
222 DEBUG("%s(area='%s', name='%s', buf=%p)\n", __func__, area, name, buf);
224 if (fmap_locate_area(area, &dev.offset, &dev.size) != CB_SUCCESS)
225 return NULL;
227 if (cbfs_lookup(&dev, name, &mdata, &data_offset, NULL)) {
228 ERROR("'%s' not found in '%s'\n", name, area);
229 return NULL;
232 return do_load(&mdata, dev.offset + data_offset, buf, size_inout, true);
235 /* This should be overridden by payloads that want to enforce more explicit
236 policy on using HW crypto. */
237 __weak bool cbfs_hwcrypto_allowed(void)
239 /* Avoid compiling vboot calls to prevent linker errors. */
240 if (!CONFIG(LP_CBFS_VERIFICATION))
241 return true;
243 return vb2api_hwcrypto_allowed(vboot_get_context());