1 /* SPDX-License-Identifier: GPL-2.0-only */
4 #include <boot_device.h>
6 #include <commonlib/bsd/cbfs_private.h>
7 #include <commonlib/bsd/compression.h>
8 #include <commonlib/endian.h>
9 #include <console/console.h>
12 #include <security/tpm/tspi/crtm.h>
13 #include <security/vboot/vboot_common.h>
17 #include <timestamp.h>
19 int cbfs_boot_locate(struct cbfsf
*fh
, const char *name
, uint32_t *type
)
21 struct region_device rdev
;
23 if (cbfs_boot_region_device(&rdev
))
27 cb_err_t err
= cbfs_lookup(&rdev
, name
, &fh
->mdata
, &data_offset
, NULL
);
29 if (CONFIG(VBOOT_ENABLE_CBFS_FALLBACK
) && err
== CB_CBFS_NOT_FOUND
) {
30 printk(BIOS_INFO
, "CBFS: Fall back to RO region for %s\n",
32 if (fmap_locate_area_as_rdev("COREBOOT", &rdev
))
34 err
= cbfs_lookup(&rdev
, name
, &fh
->mdata
, &data_offset
, NULL
);
39 size_t msize
= be32toh(fh
->mdata
.h
.offset
);
40 if (rdev_chain(&fh
->metadata
, &addrspace_32bit
.rdev
,
41 (uintptr_t)&fh
->mdata
, msize
) ||
42 rdev_chain(&fh
->data
, &rdev
, data_offset
, be32toh(fh
->mdata
.h
.len
)))
46 *type
= be32toh(fh
->mdata
.h
.type
);
47 else if (*type
!= be32toh(fh
->mdata
.h
.type
))
51 if (tspi_measure_cbfs_hook(fh
, name
))
57 void *cbfs_boot_map_with_leak(const char *name
, uint32_t type
, size_t *size
)
62 if (cbfs_boot_locate(&fh
, name
, &type
))
65 fsize
= region_device_sz(&fh
.data
);
70 return rdev_mmap(&fh
.data
, 0, fsize
);
73 int cbfs_locate_file_in_region(struct cbfsf
*fh
, const char *region_name
,
74 const char *name
, uint32_t *type
)
76 struct region_device rdev
;
78 if (fmap_locate_area_as_rdev(region_name
, &rdev
)) {
79 LOG("%s region not found while looking for %s\n",
84 ret
= cbfs_locate(fh
, &rdev
, name
, type
);
86 if (tspi_measure_cbfs_hook(fh
, name
))
91 static inline bool fsps_env(void)
93 /* FSP-S is assumed to be loaded in ramstage. */
99 static inline bool fspm_env(void)
101 /* FSP-M is assumed to be loaded in romstage. */
107 static inline bool cbfs_lz4_enabled(void)
109 if (fsps_env() && CONFIG(FSP_COMPRESS_FSP_S_LZ4
))
111 if (fspm_env() && CONFIG(FSP_COMPRESS_FSP_M_LZ4
))
114 if ((ENV_BOOTBLOCK
|| ENV_SEPARATE_VERSTAGE
) && !CONFIG(COMPRESS_PRERAM_STAGES
))
120 static inline bool cbfs_lzma_enabled(void)
122 if (fsps_env() && CONFIG(FSP_COMPRESS_FSP_S_LZMA
))
124 if (fspm_env() && CONFIG(FSP_COMPRESS_FSP_M_LZMA
))
126 /* We assume here romstage and postcar are never compressed. */
127 if (ENV_BOOTBLOCK
|| ENV_SEPARATE_VERSTAGE
)
129 if (ENV_ROMSTAGE
&& CONFIG(POSTCAR_STAGE
))
131 if ((ENV_ROMSTAGE
|| ENV_POSTCAR
)
132 && !CONFIG(COMPRESS_RAMSTAGE
))
137 size_t cbfs_load_and_decompress(const struct region_device
*rdev
, size_t offset
,
138 size_t in_size
, void *buffer
, size_t buffer_size
, uint32_t compression
)
143 switch (compression
) {
144 case CBFS_COMPRESS_NONE
:
145 if (buffer_size
< in_size
)
147 if (rdev_readat(rdev
, buffer
, offset
, in_size
) != in_size
)
151 case CBFS_COMPRESS_LZ4
:
152 if (!cbfs_lz4_enabled())
155 /* cbfs_stage_load_and_decompress() takes care of in-place
156 lz4 decompression by setting up the rdev to be in memory. */
157 map
= rdev_mmap(rdev
, offset
, in_size
);
161 timestamp_add_now(TS_START_ULZ4F
);
162 out_size
= ulz4fn(map
, in_size
, buffer
, buffer_size
);
163 timestamp_add_now(TS_END_ULZ4F
);
165 rdev_munmap(rdev
, map
);
169 case CBFS_COMPRESS_LZMA
:
170 if (!cbfs_lzma_enabled())
172 map
= rdev_mmap(rdev
, offset
, in_size
);
176 /* Note: timestamp not useful for memory-mapped media (x86) */
177 timestamp_add_now(TS_START_ULZMA
);
178 out_size
= ulzman(map
, in_size
, buffer
, buffer_size
);
179 timestamp_add_now(TS_END_ULZMA
);
181 rdev_munmap(rdev
, map
);
190 static size_t cbfs_stage_load_and_decompress(const struct region_device
*rdev
,
191 size_t offset
, size_t in_size
, void *buffer
, size_t buffer_size
,
192 uint32_t compression
)
194 struct region_device rdev_src
;
196 if (compression
== CBFS_COMPRESS_LZ4
) {
197 if (!cbfs_lz4_enabled())
199 /* Load the compressed image to the end of the available memory
200 * area for in-place decompression. It is the responsibility of
201 * the caller to ensure that buffer_size is large enough
202 * (see compression.h, guaranteed by cbfstool for stages). */
203 void *compr_start
= buffer
+ buffer_size
- in_size
;
204 if (rdev_readat(rdev
, compr_start
, offset
, in_size
) != in_size
)
206 /* Create a region device backed by memory. */
207 rdev_chain(&rdev_src
, &addrspace_32bit
.rdev
,
208 (uintptr_t)compr_start
, in_size
);
210 return cbfs_load_and_decompress(&rdev_src
, 0, in_size
, buffer
,
211 buffer_size
, compression
);
214 /* All other algorithms can use the generic implementation. */
215 return cbfs_load_and_decompress(rdev
, offset
, in_size
, buffer
,
216 buffer_size
, compression
);
219 static inline int tohex4(unsigned int c
)
221 return (c
<= 9) ? (c
+ '0') : (c
- 10 + 'a');
224 static void tohex8(unsigned int val
, char *dest
)
226 dest
[0] = tohex4((val
>> 4) & 0xf);
227 dest
[1] = tohex4(val
& 0xf);
230 static void tohex16(unsigned int val
, char *dest
)
232 dest
[0] = tohex4(val
>> 12);
233 dest
[1] = tohex4((val
>> 8) & 0xf);
234 dest
[2] = tohex4((val
>> 4) & 0xf);
235 dest
[3] = tohex4(val
& 0xf);
238 void *cbfs_boot_map_optionrom(uint16_t vendor
, uint16_t device
)
240 char name
[17] = "pciXXXX,XXXX.rom";
242 tohex16(vendor
, name
+ 3);
243 tohex16(device
, name
+ 8);
245 return cbfs_boot_map_with_leak(name
, CBFS_TYPE_OPTIONROM
, NULL
);
248 void *cbfs_boot_map_optionrom_revision(uint16_t vendor
, uint16_t device
, uint8_t rev
)
250 char name
[20] = "pciXXXX,XXXX,XX.rom";
252 tohex16(vendor
, name
+ 3);
253 tohex16(device
, name
+ 8);
254 tohex8(rev
, name
+ 13);
256 return cbfs_boot_map_with_leak(name
, CBFS_TYPE_OPTIONROM
, NULL
);
259 size_t cbfs_boot_load_file(const char *name
, void *buf
, size_t buf_size
,
263 uint32_t compression_algo
;
264 size_t decompressed_size
;
266 if (cbfs_boot_locate(&fh
, name
, &type
) < 0)
269 if (cbfsf_decompression_info(&fh
, &compression_algo
,
272 || decompressed_size
> buf_size
)
275 return cbfs_load_and_decompress(&fh
.data
, 0, region_device_sz(&fh
.data
),
276 buf
, buf_size
, compression_algo
);
279 int cbfs_prog_stage_load(struct prog
*pstage
)
281 struct cbfs_stage stage
;
286 const struct region_device
*fh
= prog_rdev(pstage
);
288 if (rdev_readat(fh
, &stage
, 0, sizeof(stage
)) != sizeof(stage
))
291 fsize
= region_device_sz(fh
);
292 fsize
-= sizeof(stage
);
294 foffset
+= sizeof(stage
);
296 /* cbfs_stage fields are written in little endian despite the other
297 cbfs data types being encoded in big endian. */
298 stage
.compression
= read_le32(&stage
.compression
);
299 stage
.entry
= read_le64(&stage
.entry
);
300 stage
.load
= read_le64(&stage
.load
);
301 stage
.len
= read_le32(&stage
.len
);
302 stage
.memlen
= read_le32(&stage
.memlen
);
304 assert(fsize
== stage
.len
);
306 load
= (void *)(uintptr_t)stage
.load
;
307 entry
= (void *)(uintptr_t)stage
.entry
;
309 /* Hacky way to not load programs over read only media. The stages
310 * that would hit this path initialize themselves. */
311 if ((ENV_BOOTBLOCK
|| ENV_SEPARATE_VERSTAGE
) &&
312 !CONFIG(NO_XIP_EARLY_STAGES
) && CONFIG(BOOT_DEVICE_MEMORY_MAPPED
)) {
313 void *mapping
= rdev_mmap(fh
, foffset
, fsize
);
314 rdev_munmap(fh
, mapping
);
319 fsize
= cbfs_stage_load_and_decompress(fh
, foffset
, fsize
, load
,
320 stage
.memlen
, stage
.compression
);
324 /* Clear area not covered by file. */
325 memset(&load
[fsize
], 0, stage
.memlen
- fsize
);
327 prog_segment_loaded((uintptr_t)load
, stage
.memlen
, SEG_FINAL
);
330 prog_set_area(pstage
, load
, stage
.memlen
);
331 prog_set_entry(pstage
, entry
, NULL
);
336 int cbfs_boot_region_device(struct region_device
*rdev
)
339 return vboot_locate_cbfs(rdev
) &&
340 fmap_locate_area_as_rdev("COREBOOT", rdev
);