soc/intel/tigerlake: Utilize vbt data size Kconfig option
[coreboot.git] / src / lib / cbfs.c
blob447d91f1be7fdfab51409b71892a938eabcf70e0
1 /* SPDX-License-Identifier: GPL-2.0-only */
3 #include <assert.h>
4 #include <boot_device.h>
5 #include <cbfs.h>
6 #include <commonlib/bsd/cbfs_private.h>
7 #include <commonlib/bsd/compression.h>
8 #include <commonlib/endian.h>
9 #include <console/console.h>
10 #include <fmap.h>
11 #include <lib.h>
12 #include <security/tpm/tspi/crtm.h>
13 #include <security/vboot/vboot_common.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <symbols.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))
24 return -1;
26 size_t data_offset;
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",
31 name);
32 if (fmap_locate_area_as_rdev("COREBOOT", &rdev))
33 return -1;
34 err = cbfs_lookup(&rdev, name, &fh->mdata, &data_offset, NULL);
36 if (err)
37 return -1;
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)))
43 return -1;
44 if (type) {
45 if (!*type)
46 *type = be32toh(fh->mdata.h.type);
47 else if (*type != be32toh(fh->mdata.h.type))
48 return -1;
51 if (tspi_measure_cbfs_hook(fh, name))
52 return -1;
54 return 0;
57 void *cbfs_boot_map_with_leak(const char *name, uint32_t type, size_t *size)
59 struct cbfsf fh;
60 size_t fsize;
62 if (cbfs_boot_locate(&fh, name, &type))
63 return NULL;
65 fsize = region_device_sz(&fh.data);
67 if (size != NULL)
68 *size = fsize;
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;
77 int ret = 0;
78 if (fmap_locate_area_as_rdev(region_name, &rdev)) {
79 LOG("%s region not found while looking for %s\n",
80 region_name, name);
81 return -1;
84 ret = cbfs_locate(fh, &rdev, name, type);
85 if (!ret)
86 if (tspi_measure_cbfs_hook(fh, name))
87 return -1;
88 return ret;
91 static inline bool fsps_env(void)
93 /* FSP-S is assumed to be loaded in ramstage. */
94 if (ENV_RAMSTAGE)
95 return true;
96 return false;
99 static inline bool fspm_env(void)
101 /* FSP-M is assumed to be loaded in romstage. */
102 if (ENV_ROMSTAGE)
103 return true;
104 return false;
107 static inline bool cbfs_lz4_enabled(void)
109 if (fsps_env() && CONFIG(FSP_COMPRESS_FSP_S_LZ4))
110 return true;
111 if (fspm_env() && CONFIG(FSP_COMPRESS_FSP_M_LZ4))
112 return true;
114 if ((ENV_BOOTBLOCK || ENV_SEPARATE_VERSTAGE) && !CONFIG(COMPRESS_PRERAM_STAGES))
115 return false;
117 return true;
120 static inline bool cbfs_lzma_enabled(void)
122 if (fsps_env() && CONFIG(FSP_COMPRESS_FSP_S_LZMA))
123 return true;
124 if (fspm_env() && CONFIG(FSP_COMPRESS_FSP_M_LZMA))
125 return true;
126 /* We assume here romstage and postcar are never compressed. */
127 if (ENV_BOOTBLOCK || ENV_SEPARATE_VERSTAGE)
128 return false;
129 if (ENV_ROMSTAGE && CONFIG(POSTCAR_STAGE))
130 return false;
131 if ((ENV_ROMSTAGE || ENV_POSTCAR)
132 && !CONFIG(COMPRESS_RAMSTAGE))
133 return false;
134 return true;
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)
140 size_t out_size;
141 void *map;
143 switch (compression) {
144 case CBFS_COMPRESS_NONE:
145 if (buffer_size < in_size)
146 return 0;
147 if (rdev_readat(rdev, buffer, offset, in_size) != in_size)
148 return 0;
149 return in_size;
151 case CBFS_COMPRESS_LZ4:
152 if (!cbfs_lz4_enabled())
153 return 0;
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);
158 if (map == NULL)
159 return 0;
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);
167 return out_size;
169 case CBFS_COMPRESS_LZMA:
170 if (!cbfs_lzma_enabled())
171 return 0;
172 map = rdev_mmap(rdev, offset, in_size);
173 if (map == NULL)
174 return 0;
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);
183 return out_size;
185 default:
186 return 0;
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())
198 return 0;
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)
205 return 0;
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,
260 uint32_t type)
262 struct cbfsf fh;
263 uint32_t compression_algo;
264 size_t decompressed_size;
266 if (cbfs_boot_locate(&fh, name, &type) < 0)
267 return 0;
269 if (cbfsf_decompression_info(&fh, &compression_algo,
270 &decompressed_size)
272 || decompressed_size > buf_size)
273 return 0;
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;
282 uint8_t *load;
283 void *entry;
284 size_t fsize;
285 size_t foffset;
286 const struct region_device *fh = prog_rdev(pstage);
288 if (rdev_readat(fh, &stage, 0, sizeof(stage)) != sizeof(stage))
289 return -1;
291 fsize = region_device_sz(fh);
292 fsize -= sizeof(stage);
293 foffset = 0;
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);
315 if (mapping == load)
316 goto out;
319 fsize = cbfs_stage_load_and_decompress(fh, foffset, fsize, load,
320 stage.memlen, stage.compression);
321 if (!fsize)
322 return -1;
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);
329 out:
330 prog_set_area(pstage, load, stage.memlen);
331 prog_set_entry(pstage, entry, NULL);
333 return 0;
336 int cbfs_boot_region_device(struct region_device *rdev)
338 boot_device_init();
339 return vboot_locate_cbfs(rdev) &&
340 fmap_locate_area_as_rdev("COREBOOT", rdev);