1 /* SPDX-License-Identifier: BSD-3-Clause */
3 #include <libpayload-config.h>
4 #include <arch/virtual.h>
8 #include <commonlib/bsd/cbfs_private.h>
9 #include <commonlib/bsd/fmap_serialized.h>
10 #include <libpayload.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
;
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
;
36 if (fmap_locate_area("COREBOOT", &ro
.dev
.offset
, &ro
.dev
.size
))
39 ro
.mcache
= phys_to_virt(lib_sysinfo
.cbfs_ro_mcache_offset
);
40 ro
.mcache_size
= lib_sysinfo
.cbfs_ro_mcache_size
;
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
);
52 enum cb_err err
= CB_CBFS_CACHE_FULL
;
54 err
= cbfs_mcache_lookup(cbd
->mcache
, cbd
->mcache_size
, name
, mdata
,
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
);
67 if (err
== CB_CBFS_NOT_FOUND
)
68 LOG("'%s' not found.\n", name
);
70 ERROR("Error %d when looking up '%s'\n", err
, name
);
74 return cbd
->dev
.offset
+ data_offset
;
77 void cbfs_unmap(void *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
)
88 const struct vb2_hash
*hash
= cbfs_file_hash(mdata
);
90 ERROR("'%s' does not have a file hash!\n", mdata
->h
.filename
);
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
);
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
)
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
);
117 ERROR("'%s' buffer allocation failed\n", mdata
->h
.filename
);
122 if (boot_device_read(load
, offset
, in_size
) != in_size
) {
123 ERROR("'%s' failed to read contents of file\n", mdata
->h
.filename
);
127 if (cbfs_file_hash_mismatch(load
, in_size
, mdata
, skip_verification
))
130 switch (compression
) {
131 case CBFS_COMPRESS_NONE
:
134 case CBFS_COMPRESS_LZ4
:
137 out_size
= ulz4fn(load
, in_size
, buffer
, buffer_size
);
139 case CBFS_COMPRESS_LZMA
:
140 if (!CONFIG(LP_LZMA
))
142 out_size
= ulzman(load
, in_size
, buffer
, buffer_size
);
145 ERROR("'%s' decompression algo %d not supported\n", mdata
->h
.filename
,
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;
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
));
164 compression
= be32toh(cattr
->compression
);
165 out_size
= be32toh(cattr
->decompressed_size
);
167 out_size
= be32toh(mdata
->h
.len
);
171 buf_size
= *size_inout
;
172 *size_inout
= out_size
;
176 if (!size_inout
|| buf_size
< out_size
) {
177 ERROR("'%s' buffer too small\n", mdata
->h
.filename
);
181 buf
= malloc(out_size
);
183 ERROR("'%s' allocation failure\n", mdata
->h
.filename
);
189 if (cbfs_load_and_decompress(offset
, be32toh(mdata
->h
.len
), buf
, out_size
, compression
,
190 mdata
, skip_verification
)
200 void *_cbfs_load(const char *name
, void *buf
, size_t *size_inout
, bool force_ro
)
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
);
212 return do_load(&mdata
, offset
, buf
, size_inout
, false);
215 void *_cbfs_unverified_area_load(const char *area
, const char *name
, void *buf
,
219 union cbfs_mdata mdata
;
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
)
227 if (cbfs_lookup(&dev
, name
, &mdata
, &data_offset
, NULL
)) {
228 ERROR("'%s' not found in '%s'\n", name
, area
);
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
))
243 return vb2api_hwcrypto_allowed(vboot_get_context());