blob: fbe6e43496054fdf494cb2420ac1b4253cd893cd [file] [log] [blame]
Peter Stuge483b7bb2009-04-14 07:40:01 +00001/*
2 * This file is part of the coreboot project.
3 *
Aaron Durbin899d13d2015-05-15 23:39:23 -05004 * Copyright (C) 2011 secunet Security Networks AG
5 * Copyright 2015 Google Inc.
Peter Stuge483b7bb2009-04-14 07:40:01 +00006 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2 of the License.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
Peter Stuge483b7bb2009-04-14 07:40:01 +000015 */
16
Aaron Durbin899d13d2015-05-15 23:39:23 -050017#include <assert.h>
Elyes HAOUAS351e3e52019-04-05 18:11:19 +020018#include <console/console.h>
Aaron Durbin899d13d2015-05-15 23:39:23 -050019#include <string.h>
20#include <stdlib.h>
21#include <boot_device.h>
22#include <cbfs.h>
Julius Werner09f29212015-09-29 13:51:35 -070023#include <commonlib/compression.h>
Aaron Durbin899d13d2015-05-15 23:39:23 -050024#include <endian.h>
25#include <lib.h>
26#include <symbols.h>
Julius Werner09f29212015-09-29 13:51:35 -070027#include <timestamp.h>
Pratik Prajapati2a7708a2016-11-30 17:29:10 -080028#include <fmap.h>
Philipp Deppenwiese66f9a092018-11-08 10:59:40 +010029#include <security/vboot/vboot_crtm.h>
Patrick Georgi58a150a2016-05-02 17:22:29 +080030
Aaron Durbin899d13d2015-05-15 23:39:23 -050031#define ERROR(x...) printk(BIOS_ERR, "CBFS: " x)
32#define LOG(x...) printk(BIOS_INFO, "CBFS: " x)
Julius Wernercd49cce2019-03-05 16:53:33 -080033#if CONFIG(DEBUG_CBFS)
Aaron Durbin899d13d2015-05-15 23:39:23 -050034#define DEBUG(x...) printk(BIOS_SPEW, "CBFS: " x)
35#else
36#define DEBUG(x...)
37#endif
Peter Stuge483b7bb2009-04-14 07:40:01 +000038
Aaron Durbin37a5d152015-09-17 16:09:30 -050039int cbfs_boot_locate(struct cbfsf *fh, const char *name, uint32_t *type)
Aaron Durbin899d13d2015-05-15 23:39:23 -050040{
Aaron Durbin899d13d2015-05-15 23:39:23 -050041 struct region_device rdev;
42 const struct region_device *boot_dev;
43 struct cbfs_props props;
44
Nico Huber6ee37ef2018-12-06 15:46:26 +010045 if (cbfs_boot_region_properties(&props)) {
46 printk(BIOS_ALERT, "ERROR: Failed to locate boot region\n");
Aaron Durbin899d13d2015-05-15 23:39:23 -050047 return -1;
Nico Huber6ee37ef2018-12-06 15:46:26 +010048 }
Aaron Durbin899d13d2015-05-15 23:39:23 -050049
Patrick Georgid13c4cd2018-04-30 15:05:58 +020050 /* All boot CBFS operations are performed using the RO device. */
Aaron Durbin899d13d2015-05-15 23:39:23 -050051 boot_dev = boot_device_ro();
52
Nico Huber6ee37ef2018-12-06 15:46:26 +010053 if (boot_dev == NULL) {
54 printk(BIOS_ALERT, "ERROR: Failed to find boot device\n");
Aaron Durbin899d13d2015-05-15 23:39:23 -050055 return -1;
Nico Huber6ee37ef2018-12-06 15:46:26 +010056 }
Aaron Durbin899d13d2015-05-15 23:39:23 -050057
Nico Huber6ee37ef2018-12-06 15:46:26 +010058 if (rdev_chain(&rdev, boot_dev, props.offset, props.size)) {
59 printk(BIOS_ALERT, "ERROR: Failed to access boot region inside boot device\n");
Aaron Durbin899d13d2015-05-15 23:39:23 -050060 return -1;
Nico Huber6ee37ef2018-12-06 15:46:26 +010061 }
Aaron Durbin899d13d2015-05-15 23:39:23 -050062
Philipp Deppenwiese66f9a092018-11-08 10:59:40 +010063 int ret = cbfs_locate(fh, &rdev, name, type);
Wim Vervoorn114e2e82019-11-05 14:09:16 +010064
65 if (CONFIG(VBOOT_ENABLE_CBFS_FALLBACK) && ret) {
66
67 /*
68 * When VBOOT_ENABLE_CBFS_FALLBACK is enabled and a file is not available in the
69 * active RW region, the RO (COREBOOT) region will be used to locate the file.
70 *
71 * This functionality makes it possible to avoid duplicate files in the RO
72 * and RW partitions while maintaining updateability.
73 *
74 * Files can be added to the RO_REGION_ONLY config option to use this feature.
75 */
76 printk(BIOS_DEBUG, "Fall back to RO region for %s\n", name);
77 ret = cbfs_locate_file_in_region(fh, "COREBOOT", name, type);
78 }
79
Philipp Deppenwiese66f9a092018-11-08 10:59:40 +010080 if (!ret)
81 if (vboot_measure_cbfs_hook(fh, name))
82 return -1;
83
84 return ret;
Aaron Durbin899d13d2015-05-15 23:39:23 -050085}
86
87void *cbfs_boot_map_with_leak(const char *name, uint32_t type, size_t *size)
88{
Aaron Durbin37a5d152015-09-17 16:09:30 -050089 struct cbfsf fh;
Aaron Durbin899d13d2015-05-15 23:39:23 -050090 size_t fsize;
91
92 if (cbfs_boot_locate(&fh, name, &type))
93 return NULL;
94
Aaron Durbin37a5d152015-09-17 16:09:30 -050095 fsize = region_device_sz(&fh.data);
Aaron Durbin899d13d2015-05-15 23:39:23 -050096
97 if (size != NULL)
98 *size = fsize;
99
Aaron Durbin37a5d152015-09-17 16:09:30 -0500100 return rdev_mmap(&fh.data, 0, fsize);
Aaron Durbin899d13d2015-05-15 23:39:23 -0500101}
102
Pratik Prajapati2a7708a2016-11-30 17:29:10 -0800103int cbfs_locate_file_in_region(struct cbfsf *fh, const char *region_name,
Philipp Deppenwiese66f9a092018-11-08 10:59:40 +0100104 const char *name, uint32_t *type)
Pratik Prajapati2a7708a2016-11-30 17:29:10 -0800105{
106 struct region_device rdev;
107
108 if (fmap_locate_area_as_rdev(region_name, &rdev)) {
109 LOG("%s region not found while looking for %s\n",
Philipp Deppenwiese66f9a092018-11-08 10:59:40 +0100110 region_name, name);
Pratik Prajapati2a7708a2016-11-30 17:29:10 -0800111 return -1;
112 }
113
114 return cbfs_locate(fh, &rdev, name, type);
115}
116
Julius Werner09f29212015-09-29 13:51:35 -0700117size_t cbfs_load_and_decompress(const struct region_device *rdev, size_t offset,
118 size_t in_size, void *buffer, size_t buffer_size, uint32_t compression)
Aaron Durbin899d13d2015-05-15 23:39:23 -0500119{
Julius Werner09f29212015-09-29 13:51:35 -0700120 size_t out_size;
121
122 switch (compression) {
123 case CBFS_COMPRESS_NONE:
Julius Wernerf975e552016-08-19 15:43:06 -0700124 if (buffer_size < in_size)
125 return 0;
Julius Werner09f29212015-09-29 13:51:35 -0700126 if (rdev_readat(rdev, buffer, offset, in_size) != in_size)
127 return 0;
128 return in_size;
129
130 case CBFS_COMPRESS_LZ4:
131 if ((ENV_BOOTBLOCK || ENV_VERSTAGE) &&
Julius Wernercd49cce2019-03-05 16:53:33 -0800132 !CONFIG(COMPRESS_PRERAM_STAGES))
Julius Werner09f29212015-09-29 13:51:35 -0700133 return 0;
134
135 /* Load the compressed image to the end of the available memory
136 * area for in-place decompression. It is the responsibility of
137 * the caller to ensure that buffer_size is large enough
138 * (see compression.h, guaranteed by cbfstool for stages). */
139 void *compr_start = buffer + buffer_size - in_size;
140 if (rdev_readat(rdev, compr_start, offset, in_size) != in_size)
141 return 0;
142
143 timestamp_add_now(TS_START_ULZ4F);
144 out_size = ulz4fn(compr_start, in_size, buffer, buffer_size);
145 timestamp_add_now(TS_END_ULZ4F);
146 return out_size;
147
148 case CBFS_COMPRESS_LZMA:
Kyösti Mälkkib5211ef2018-06-01 07:11:25 +0300149 /* We assume here romstage and postcar are never compressed. */
Julius Werner09f29212015-09-29 13:51:35 -0700150 if (ENV_BOOTBLOCK || ENV_VERSTAGE)
151 return 0;
Julius Wernercd49cce2019-03-05 16:53:33 -0800152 if (ENV_ROMSTAGE && CONFIG(POSTCAR_STAGE))
Kyösti Mälkkib5211ef2018-06-01 07:11:25 +0300153 return 0;
Lee Leahyd950f512016-07-25 09:53:35 -0700154 if ((ENV_ROMSTAGE || ENV_POSTCAR)
Julius Wernercd49cce2019-03-05 16:53:33 -0800155 && !CONFIG(COMPRESS_RAMSTAGE))
Julius Werner09f29212015-09-29 13:51:35 -0700156 return 0;
Julius Werner09f29212015-09-29 13:51:35 -0700157 void *map = rdev_mmap(rdev, offset, in_size);
158 if (map == NULL)
159 return 0;
160
161 /* Note: timestamp not useful for memory-mapped media (x86) */
162 timestamp_add_now(TS_START_ULZMA);
163 out_size = ulzman(map, in_size, buffer, buffer_size);
164 timestamp_add_now(TS_END_ULZMA);
165
166 rdev_munmap(rdev, map);
167
168 return out_size;
169
170 default:
Aaron Durbin899d13d2015-05-15 23:39:23 -0500171 return 0;
Julius Werner09f29212015-09-29 13:51:35 -0700172 }
Aaron Durbin899d13d2015-05-15 23:39:23 -0500173}
174
Stefan Reinauer800379f2010-03-01 08:34:19 +0000175static inline int tohex4(unsigned int c)
Patrick Georgib203c2f2009-08-20 14:48:03 +0000176{
Hung-Te Lin6fe0cab2013-01-22 18:57:56 +0800177 return (c <= 9) ? (c + '0') : (c - 10 + 'a');
Patrick Georgib203c2f2009-08-20 14:48:03 +0000178}
179
Lee Leahyb2d834a2017-03-08 16:52:22 -0800180static void tohex16(unsigned int val, char *dest)
Patrick Georgib203c2f2009-08-20 14:48:03 +0000181{
Philipp Deppenwiese66f9a092018-11-08 10:59:40 +0100182 dest[0] = tohex4(val >> 12);
183 dest[1] = tohex4((val >> 8) & 0xf);
184 dest[2] = tohex4((val >> 4) & 0xf);
Hung-Te Lin6fe0cab2013-01-22 18:57:56 +0800185 dest[3] = tohex4(val & 0xf);
Patrick Georgib203c2f2009-08-20 14:48:03 +0000186}
187
Aaron Durbin899d13d2015-05-15 23:39:23 -0500188void *cbfs_boot_map_optionrom(uint16_t vendor, uint16_t device)
Peter Stuge483b7bb2009-04-14 07:40:01 +0000189{
Hung-Te Lin6fe0cab2013-01-22 18:57:56 +0800190 char name[17] = "pciXXXX,XXXX.rom";
Peter Stuge483b7bb2009-04-14 07:40:01 +0000191
Philipp Deppenwiese66f9a092018-11-08 10:59:40 +0100192 tohex16(vendor, name + 3);
193 tohex16(device, name + 8);
Peter Stuge483b7bb2009-04-14 07:40:01 +0000194
Aaron Durbin899d13d2015-05-15 23:39:23 -0500195 return cbfs_boot_map_with_leak(name, CBFS_TYPE_OPTIONROM, NULL);
Peter Stuge483b7bb2009-04-14 07:40:01 +0000196}
197
Aaron Durbin899d13d2015-05-15 23:39:23 -0500198void *cbfs_boot_load_stage_by_name(const char *name)
Peter Stuge483b7bb2009-04-14 07:40:01 +0000199{
Aaron Durbin37a5d152015-09-17 16:09:30 -0500200 struct cbfsf fh;
Aaron Durbin7e7a4df2015-12-08 14:34:35 -0600201 struct prog stage = PROG_INIT(PROG_UNKNOWN, name);
Aaron Durbin899d13d2015-05-15 23:39:23 -0500202 uint32_t type = CBFS_TYPE_STAGE;
Aaron Durbin3948e532015-03-20 13:00:20 -0500203
Aaron Durbin37a5d152015-09-17 16:09:30 -0500204 if (cbfs_boot_locate(&fh, name, &type))
Aaron Durbin899d13d2015-05-15 23:39:23 -0500205 return NULL;
Aaron Durbin3948e532015-03-20 13:00:20 -0500206
Aaron Durbin37a5d152015-09-17 16:09:30 -0500207 /* Chain data portion in the prog. */
208 cbfs_file_data(prog_rdev(&stage), &fh);
209
Aaron Durbin899d13d2015-05-15 23:39:23 -0500210 if (cbfs_prog_stage_load(&stage))
211 return NULL;
212
213 return prog_entry(&stage);
Peter Stuge483b7bb2009-04-14 07:40:01 +0000214}
215
T Michael Turney809fa7b2018-04-12 13:36:40 -0700216size_t cbfs_boot_load_file(const char *name, void *buf, size_t buf_size,
217 uint32_t type)
Julius Wernerf975e552016-08-19 15:43:06 -0700218{
219 struct cbfsf fh;
220 uint32_t compression_algo;
221 size_t decompressed_size;
Julius Wernerf975e552016-08-19 15:43:06 -0700222
223 if (cbfs_boot_locate(&fh, name, &type) < 0)
224 return 0;
225
226 if (cbfsf_decompression_info(&fh, &compression_algo,
Philipp Deppenwiese66f9a092018-11-08 10:59:40 +0100227 &decompressed_size)
228 < 0
229 || decompressed_size > buf_size)
Julius Wernerf975e552016-08-19 15:43:06 -0700230 return 0;
231
232 return cbfs_load_and_decompress(&fh.data, 0, region_device_sz(&fh.data),
233 buf, buf_size, compression_algo);
234}
235
Kyösti Mälkki9d6f3652016-06-28 07:38:46 +0300236size_t cbfs_prog_stage_section(struct prog *pstage, uintptr_t *base)
237{
238 struct cbfs_stage stage;
239 const struct region_device *fh = prog_rdev(pstage);
240
241 if (rdev_readat(fh, &stage, 0, sizeof(stage)) != sizeof(stage))
242 return 0;
243
244 *base = (uintptr_t)stage.load;
245 return stage.memlen;
246}
247
Aaron Durbin899d13d2015-05-15 23:39:23 -0500248int cbfs_prog_stage_load(struct prog *pstage)
249{
250 struct cbfs_stage stage;
251 uint8_t *load;
252 void *entry;
253 size_t fsize;
254 size_t foffset;
Aaron Durbin37a5d152015-09-17 16:09:30 -0500255 const struct region_device *fh = prog_rdev(pstage);
Hung-Te Lin6fe0cab2013-01-22 18:57:56 +0800256
Aaron Durbin899d13d2015-05-15 23:39:23 -0500257 if (rdev_readat(fh, &stage, 0, sizeof(stage)) != sizeof(stage))
Julius Wernerb29bd27b2015-12-03 11:29:12 -0800258 return -1;
Aaron Durbin899d13d2015-05-15 23:39:23 -0500259
260 fsize = region_device_sz(fh);
261 fsize -= sizeof(stage);
262 foffset = 0;
263 foffset += sizeof(stage);
264
265 assert(fsize == stage.len);
266
267 /* Note: cbfs_stage fields are currently in the endianness of the
268 * running processor. */
269 load = (void *)(uintptr_t)stage.load;
270 entry = (void *)(uintptr_t)stage.entry;
271
Aaron Durbined253c82015-10-07 17:22:42 -0500272 /* Hacky way to not load programs over read only media. The stages
273 * that would hit this path initialize themselves. */
Arthur Heymans7c24de92019-10-25 16:53:29 +0200274 if ((ENV_BOOTBLOCK || ENV_VERSTAGE) && !CONFIG(NO_XIP_EARLY_STAGES) &&
Julius Wernercd49cce2019-03-05 16:53:33 -0800275 CONFIG(BOOT_DEVICE_MEMORY_MAPPED)) {
Aaron Durbined253c82015-10-07 17:22:42 -0500276 void *mapping = rdev_mmap(fh, foffset, fsize);
277 rdev_munmap(fh, mapping);
278 if (mapping == load)
279 goto out;
280 }
281
Julius Werner09f29212015-09-29 13:51:35 -0700282 fsize = cbfs_load_and_decompress(fh, foffset, fsize, load,
283 stage.memlen, stage.compression);
284 if (!fsize)
Aaron Durbin899d13d2015-05-15 23:39:23 -0500285 return -1;
286
287 /* Clear area not covered by file. */
288 memset(&load[fsize], 0, stage.memlen - fsize);
289
Aaron Durbin096f4572016-03-31 13:49:00 -0500290 prog_segment_loaded((uintptr_t)load, stage.memlen, SEG_FINAL);
Aaron Durbined253c82015-10-07 17:22:42 -0500291
292out:
Aaron Durbin899d13d2015-05-15 23:39:23 -0500293 prog_set_area(pstage, load, stage.memlen);
294 prog_set_entry(pstage, entry, NULL);
295
296 return 0;
Hung-Te Lin6fe0cab2013-01-22 18:57:56 +0800297}
Aaron Durbin6d720f32015-12-08 17:00:23 -0600298
Julius Werner32e13c02019-11-08 13:06:20 -0800299/* The default locator to find the CBFS in the "COREBOOT" FMAP region. */
300int cbfs_default_props(struct cbfs_props *props)
Aaron Durbin6d720f32015-12-08 17:00:23 -0600301{
Julius Werner32e13c02019-11-08 13:06:20 -0800302 struct region region;
Aaron Durbin6d720f32015-12-08 17:00:23 -0600303
Julius Werner32e13c02019-11-08 13:06:20 -0800304 if (fmap_locate_area("COREBOOT", &region))
Aaron Durbin6d720f32015-12-08 17:00:23 -0600305 return -1;
306
Julius Werner32e13c02019-11-08 13:06:20 -0800307 props->offset = region_offset(&region);
308 props->size = region_sz(&region);
Aaron Durbin6d720f32015-12-08 17:00:23 -0600309
310 printk(BIOS_SPEW, "CBFS @ %zx size %zx\n", props->offset, props->size);
311
312 return 0;
313}
314
315/* This struct is marked as weak to allow a particular platform to
316 * override the master header logic. This implementation should work for most
317 * devices. */
Julius Werner32e13c02019-11-08 13:06:20 -0800318const struct cbfs_locator __weak cbfs_default_locator = {
319 .name = "COREBOOT Locator",
320 .locate = cbfs_default_props,
Aaron Durbin6d720f32015-12-08 17:00:23 -0600321};
322
323extern const struct cbfs_locator vboot_locator;
324
325static const struct cbfs_locator *locators[] = {
Julius Wernercd49cce2019-03-05 16:53:33 -0800326#if CONFIG(VBOOT)
Patrick Rudolph9554b262018-06-05 15:12:56 +0200327 /*
328 * NOTE: Does not link in SMM, as the vboot_locator isn't compiled.
329 * ATM there's no need for VBOOT functionality in SMM and it's not
330 * a problem.
331 */
Aaron Durbin6d720f32015-12-08 17:00:23 -0600332 &vboot_locator,
333#endif
Julius Werner32e13c02019-11-08 13:06:20 -0800334 &cbfs_default_locator,
Aaron Durbin6d720f32015-12-08 17:00:23 -0600335};
336
337int cbfs_boot_region_properties(struct cbfs_props *props)
338{
339 int i;
340
341 boot_device_init();
342
343 for (i = 0; i < ARRAY_SIZE(locators); i++) {
344 const struct cbfs_locator *ops;
345
346 ops = locators[i];
347
348 if (ops->locate == NULL)
349 continue;
350
351 if (ops->locate(props))
352 continue;
353
354 LOG("'%s' located CBFS at [%zx:%zx)\n",
Philipp Deppenwiese66f9a092018-11-08 10:59:40 +0100355 ops->name, props->offset, props->offset + props->size);
Aaron Durbin6d720f32015-12-08 17:00:23 -0600356
357 return 0;
358 }
359
360 return -1;
361}