blob: 84bbdb05b3b79bf6abf5bcd684b3f445bf24e4f0 [file] [log] [blame]
Aaron Durbin9a7d7bc2013-09-07 00:41:48 -05001/*
2 * This file is part of the coreboot project.
3 *
Duncan Lauried8c4f2b2014-04-22 10:46:06 -07004 * Copyright (C) 2014 Google Inc.
Aaron Durbin9a7d7bc2013-09-07 00:41:48 -05005 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
Aaron Durbin9a7d7bc2013-09-07 00:41:48 -050014 */
15
16#include <string.h>
Aaron Durbin31be2c92016-12-03 22:08:20 -060017#include <boot_device.h>
Aaron Durbin4d3de7e2015-09-02 17:34:04 -050018#include <bootstate.h>
Aaron Durbincb0c40d2017-12-14 13:53:14 -070019#include <bootmode.h>
Aaron Durbin9a7d7bc2013-09-07 00:41:48 -050020#include <console/console.h>
21#include <cbmem.h>
Aaron Durbin7d9068f2016-11-04 10:07:14 -050022#include <elog.h>
Aaron Durbin0424c952015-03-28 23:56:22 -050023#include <fmap.h>
Aaron Durbin9a7d7bc2013-09-07 00:41:48 -050024#include <ip_checksum.h>
Aaron Durbin31be2c92016-12-03 22:08:20 -060025#include <region_file.h>
Philipp Deppenwiesefea24292017-10-17 17:02:29 +020026#include <security/vboot/vboot_common.h>
Aaron Durbincb0c40d2017-12-14 13:53:14 -070027#include <spi_flash.h>
Furquan Shaikh0325dc62016-07-25 13:02:36 -070028
Duncan Lauried8c4f2b2014-04-22 10:46:06 -070029#include "mrc_cache.h"
Aaron Durbin9a7d7bc2013-09-07 00:41:48 -050030
Aaron Durbin31be2c92016-12-03 22:08:20 -060031#define DEFAULT_MRC_CACHE "RW_MRC_CACHE"
32#define VARIABLE_MRC_CACHE "RW_VAR_MRC_CACHE"
33#define RECOVERY_MRC_CACHE "RECOVERY_MRC_CACHE"
34#define UNIFIED_MRC_CACHE "UNIFIED_MRC_CACHE"
35
Aaron Durbin9a7d7bc2013-09-07 00:41:48 -050036#define MRC_DATA_SIGNATURE (('M'<<0)|('R'<<8)|('C'<<16)|('D'<<24))
37
Aaron Durbin31be2c92016-12-03 22:08:20 -060038struct mrc_metadata {
39 uint32_t signature;
40 uint32_t data_size;
41 uint16_t data_checksum;
42 uint16_t header_checksum;
43 uint32_t version;
Stefan Reinauer6a001132017-07-13 02:20:27 +020044} __packed;
Aaron Durbin9a7d7bc2013-09-07 00:41:48 -050045
Andrey Petrovef9a9ea2016-11-08 08:30:06 -080046enum result {
Aaron Durbin31be2c92016-12-03 22:08:20 -060047 UPDATE_FAILURE = -1,
Andrey Petrovef9a9ea2016-11-08 08:30:06 -080048 UPDATE_SUCCESS = 0,
49 ALREADY_UPTODATE = 1
50};
51
Aaron Durbin31be2c92016-12-03 22:08:20 -060052#define NORMAL_FLAG (1 << 0)
53#define RECOVERY_FLAG (1 << 1)
54
55struct cache_region {
56 const char *name;
57 uint32_t cbmem_id;
58 int type;
59 int elog_slot;
60 int flags;
61};
62
63static const struct cache_region recovery_training = {
64 .name = RECOVERY_MRC_CACHE,
65 .cbmem_id = CBMEM_ID_MRCDATA,
66 .type = MRC_TRAINING_DATA,
67 .elog_slot = ELOG_MEM_CACHE_UPDATE_SLOT_RECOVERY,
68#if IS_ENABLED(CONFIG_HAS_RECOVERY_MRC_CACHE)
69 .flags = RECOVERY_FLAG,
70#else
71 .flags = 0,
72#endif
73};
74
75static const struct cache_region normal_training = {
76 .name = DEFAULT_MRC_CACHE,
77 .cbmem_id = CBMEM_ID_MRCDATA,
78 .type = MRC_TRAINING_DATA,
79 .elog_slot = ELOG_MEM_CACHE_UPDATE_SLOT_NORMAL,
80 .flags = NORMAL_FLAG | RECOVERY_FLAG,
81};
82
83static const struct cache_region variable_data = {
84 .name = VARIABLE_MRC_CACHE,
85 .cbmem_id = CBMEM_ID_VAR_MRCDATA,
86 .type = MRC_VARIABLE_DATA,
87 .elog_slot = ELOG_MEM_CACHE_UPDATE_SLOT_VARIABLE,
88 .flags = NORMAL_FLAG | RECOVERY_FLAG,
89};
90
91/* Order matters here for priority in matching. */
92static const struct cache_region *cache_regions[] = {
93 &recovery_training,
94 &normal_training,
95 &variable_data,
96};
97
98static int lookup_region_by_name(const char *name, struct region *r)
Aaron Durbin9a7d7bc2013-09-07 00:41:48 -050099{
Aaron Durbin31be2c92016-12-03 22:08:20 -0600100 if (fmap_locate_area(name, r) == 0)
101 return 0;
Arthur Heymans82aa8332018-01-07 23:12:49 +0100102 return -1;
Aaron Durbin9a7d7bc2013-09-07 00:41:48 -0500103}
104
Aaron Durbin31be2c92016-12-03 22:08:20 -0600105static const struct cache_region *lookup_region_type(int type)
Furquan Shaikhcab1c012016-11-05 23:57:02 -0700106{
Aaron Durbin31be2c92016-12-03 22:08:20 -0600107 int i;
108 int flags;
Furquan Shaikhcab1c012016-11-05 23:57:02 -0700109
Aaron Durbin31be2c92016-12-03 22:08:20 -0600110 if (vboot_recovery_mode_enabled())
111 flags = RECOVERY_FLAG;
112 else
113 flags = NORMAL_FLAG;
114
115 for (i = 0; i < ARRAY_SIZE(cache_regions); i++) {
116 if (cache_regions[i]->type != type)
117 continue;
118 if ((cache_regions[i]->flags & flags) == flags)
119 return cache_regions[i];
Furquan Shaikhcab1c012016-11-05 23:57:02 -0700120 }
121
Aaron Durbin31be2c92016-12-03 22:08:20 -0600122 return NULL;
123}
124
125int mrc_cache_stash_data(int type, uint32_t version, const void *data,
126 size_t size)
127{
128 const struct cache_region *cr;
129 size_t cbmem_size;
130 struct mrc_metadata *md;
131
132 cr = lookup_region_type(type);
133 if (cr == NULL) {
134 printk(BIOS_ERR, "MRC: failed to add to cbmem for type %d.\n",
135 type);
Furquan Shaikhcab1c012016-11-05 23:57:02 -0700136 return -1;
137 }
138
Aaron Durbin31be2c92016-12-03 22:08:20 -0600139 cbmem_size = sizeof(*md) + size;
Furquan Shaikhcab1c012016-11-05 23:57:02 -0700140
Aaron Durbin31be2c92016-12-03 22:08:20 -0600141 md = cbmem_add(cr->cbmem_id, cbmem_size);
142
143 if (md == NULL) {
144 printk(BIOS_ERR, "MRC: failed to add '%s' to cbmem.\n",
145 cr->name);
Furquan Shaikhcab1c012016-11-05 23:57:02 -0700146 return -1;
147 }
148
Aaron Durbin31be2c92016-12-03 22:08:20 -0600149 memset(md, 0, sizeof(*md));
150 md->signature = MRC_DATA_SIGNATURE;
151 md->data_size = size;
152 md->version = version;
153 md->data_checksum = compute_ip_checksum(data, size);
154 md->header_checksum = compute_ip_checksum(md, sizeof(*md));
155 memcpy(&md[1], data, size);
Furquan Shaikhcab1c012016-11-05 23:57:02 -0700156
157 return 0;
158}
159
Aaron Durbin31be2c92016-12-03 22:08:20 -0600160static const struct cache_region *lookup_region(struct region *r, int type)
Furquan Shaikhcab1c012016-11-05 23:57:02 -0700161{
Aaron Durbin31be2c92016-12-03 22:08:20 -0600162 const struct cache_region *cr;
Furquan Shaikhcab1c012016-11-05 23:57:02 -0700163
Aaron Durbin31be2c92016-12-03 22:08:20 -0600164 cr = lookup_region_type(type);
165
166 if (cr == NULL) {
167 printk(BIOS_ERR, "MRC: failed to locate region type %d.\n",
168 type);
169 return NULL;
170 }
171
172 if (lookup_region_by_name(cr->name, r) < 0)
173 return NULL;
174
175 return cr;
176}
177
178static int mrc_header_valid(struct region_device *rdev, struct mrc_metadata *md)
179{
180 uint16_t checksum;
181 uint16_t checksum_result;
182 size_t size;
183
184 if (rdev_readat(rdev, md, 0, sizeof(*md)) < 0) {
185 printk(BIOS_ERR, "MRC: couldn't read metadata\n");
Furquan Shaikhcab1c012016-11-05 23:57:02 -0700186 return -1;
187 }
188
Aaron Durbin31be2c92016-12-03 22:08:20 -0600189 if (md->signature != MRC_DATA_SIGNATURE) {
190 printk(BIOS_ERR, "MRC: invalid header signature\n");
Furquan Shaikhcab1c012016-11-05 23:57:02 -0700191 return -1;
192 }
193
Aaron Durbin31be2c92016-12-03 22:08:20 -0600194 /* Compute checksum over header with 0 as the value. */
195 checksum = md->header_checksum;
196 md->header_checksum = 0;
197 checksum_result = compute_ip_checksum(md, sizeof(*md));
198
199 if (checksum != checksum_result) {
200 printk(BIOS_ERR, "MRC: header checksum mismatch: %x vs %x\n",
201 checksum, checksum_result);
202 return -1;
203 }
204
205 /* Put back original. */
206 md->header_checksum = checksum;
207
208 /* Re-size the region device according to the metadata as a region_file
209 * does block allocation. */
210 size = sizeof(*md) + md->data_size;
211 if (rdev_chain(rdev, rdev, 0, size) < 0) {
212 printk(BIOS_ERR, "MRC: size exceeds rdev size: %zx vs %zx\n",
213 size, region_device_sz(rdev));
Furquan Shaikhcab1c012016-11-05 23:57:02 -0700214 return -1;
215 }
Duncan Lauried8c4f2b2014-04-22 10:46:06 -0700216
Aaron Durbin9a7d7bc2013-09-07 00:41:48 -0500217 return 0;
218}
219
Aaron Durbin31be2c92016-12-03 22:08:20 -0600220static int mrc_data_valid(const struct region_device *rdev,
221 const struct mrc_metadata *md)
Aaron Durbin9a7d7bc2013-09-07 00:41:48 -0500222{
Aaron Durbin31be2c92016-12-03 22:08:20 -0600223 void *data;
224 uint16_t checksum;
225 const size_t md_size = sizeof(*md);
226 const size_t data_size = md->data_size;
Aaron Durbin9a7d7bc2013-09-07 00:41:48 -0500227
Aaron Durbin31be2c92016-12-03 22:08:20 -0600228 data = rdev_mmap(rdev, md_size, data_size);
229 if (data == NULL) {
230 printk(BIOS_ERR, "MRC: mmap failure on data verification.\n");
Aaron Durbin9a7d7bc2013-09-07 00:41:48 -0500231 return -1;
232 }
233
Aaron Durbin31be2c92016-12-03 22:08:20 -0600234 checksum = compute_ip_checksum(data, data_size);
Aaron Durbin9a7d7bc2013-09-07 00:41:48 -0500235
Aaron Durbin31be2c92016-12-03 22:08:20 -0600236 rdev_munmap(rdev, data);
237 if (md->data_checksum != checksum) {
238 printk(BIOS_ERR, "MRC: data checksum mismatch: %x vs %x\n",
239 md->data_checksum, checksum);
240 return -1;
241 }
Aaron Durbin9a7d7bc2013-09-07 00:41:48 -0500242
243 return 0;
244}
245
Aaron Durbin31be2c92016-12-03 22:08:20 -0600246static int mrc_cache_latest(const char *name,
247 const struct region_device *backing_rdev,
248 struct mrc_metadata *md,
249 struct region_file *cache_file,
250 struct region_device *rdev,
251 bool fail_bad_data)
Andrey Petrovef9a9ea2016-11-08 08:30:06 -0800252{
Aaron Durbin31be2c92016-12-03 22:08:20 -0600253 /* Init and obtain a handle to the file data. */
254 if (region_file_init(cache_file, backing_rdev) < 0) {
255 printk(BIOS_ERR, "MRC: region file invalid in '%s'\n", name);
256 return -1;
Aaron Durbin9a7d7bc2013-09-07 00:41:48 -0500257 }
258
Aaron Durbin31be2c92016-12-03 22:08:20 -0600259 /* Provide a 0 sized region_device from here on out so the caller
260 * has a valid yet unusable region_device. */
261 rdev_chain(rdev, backing_rdev, 0, 0);
262
263 /* No data to return. */
264 if (region_file_data(cache_file, rdev) < 0) {
265 printk(BIOS_ERR, "MRC: no data in '%s'\n", name);
266 return fail_bad_data ? -1 : 0;
267 }
268
269 /* Validate header and resize region to reflect actual usage on the
270 * saved medium (including metadata and data). */
271 if (mrc_header_valid(rdev, md) < 0) {
272 printk(BIOS_ERR, "MRC: invalid header in '%s'\n", name);
273 return fail_bad_data ? -1 : 0;
274 }
275
276 /* Validate Data */
277 if (mrc_data_valid(rdev, md) < 0) {
278 printk(BIOS_ERR, "MRC: invalid data in '%s'\n", name);
279 return fail_bad_data ? -1 : 0;
280 }
281
282 return 0;
283}
284
285int mrc_cache_get_current(int type, uint32_t version,
286 struct region_device *rdev)
287{
288 const struct cache_region *cr;
289 struct region region;
290 struct region_device read_rdev;
291 struct region_file cache_file;
292 struct mrc_metadata md;
293 size_t data_size;
294 const size_t md_size = sizeof(md);
295 const bool fail_bad_data = true;
296
297 cr = lookup_region(&region, type);
298
299 if (cr == NULL)
300 return -1;
301
302 if (boot_device_ro_subregion(&region, &read_rdev) < 0)
303 return -1;
304
305 if (mrc_cache_latest(cr->name, &read_rdev, &md, &cache_file, rdev,
306 fail_bad_data) < 0)
307 return -1;
308
309 if (version != md.version) {
310 printk(BIOS_INFO, "MRC: version mismatch: %x vs %x\n",
311 md.version, version);
312 return -1;
313 }
314
315 /* Re-size rdev to only contain the data. i.e. remove metadata. */
316 data_size = md.data_size;
317 return rdev_chain(rdev, rdev, md_size, data_size);
318}
319
320static bool mrc_cache_needs_update(const struct region_device *rdev,
321 const struct cbmem_entry *to_be_updated)
322{
323 void *mapping;
324 size_t size = region_device_sz(rdev);
325 bool need_update = false;
326
327 if (cbmem_entry_size(to_be_updated) != size)
328 return true;
329
330 mapping = rdev_mmap_full(rdev);
331
332 if (memcmp(cbmem_entry_start(to_be_updated), mapping, size))
333 need_update = true;
334
335 rdev_munmap(rdev, mapping);
336
337 return need_update;
Aaron Durbin9a7d7bc2013-09-07 00:41:48 -0500338}
339
Andrey Petrovef9a9ea2016-11-08 08:30:06 -0800340static void log_event_cache_update(uint8_t slot, enum result res)
Aaron Durbin7d9068f2016-11-04 10:07:14 -0500341{
342 const int type = ELOG_TYPE_MEM_CACHE_UPDATE;
343 struct elog_event_mem_cache_update event = {
Andrey Petrovef9a9ea2016-11-08 08:30:06 -0800344 .slot = slot
Aaron Durbin7d9068f2016-11-04 10:07:14 -0500345 };
346
Andrey Petrovef9a9ea2016-11-08 08:30:06 -0800347 /* Filter through interesting events only */
348 switch (res) {
Aaron Durbin31be2c92016-12-03 22:08:20 -0600349 case UPDATE_FAILURE:
Andrey Petrovef9a9ea2016-11-08 08:30:06 -0800350 event.status = ELOG_MEM_CACHE_UPDATE_STATUS_FAIL;
351 break;
352 case UPDATE_SUCCESS:
353 event.status = ELOG_MEM_CACHE_UPDATE_STATUS_SUCCESS;
354 break;
355 default:
356 return;
357 }
358
Aaron Durbin7d9068f2016-11-04 10:07:14 -0500359 if (elog_add_event_raw(type, &event, sizeof(event)) < 0)
360 printk(BIOS_ERR, "Failed to log mem cache update event.\n");
361}
362
Aaron Durbin31be2c92016-12-03 22:08:20 -0600363/* During ramstage this code purposefully uses incoherent transactions between
364 * read and write. The read assumes a memory-mapped boot device that can be used
365 * to quickly locate and compare the up-to-date data. However, when an update
366 * is required it uses the writeable region access to perform the update. */
367static void update_mrc_cache_by_type(int type)
Aaron Durbin9a7d7bc2013-09-07 00:41:48 -0500368{
Aaron Durbin31be2c92016-12-03 22:08:20 -0600369 const struct cache_region *cr;
370 struct region region;
371 struct region_device read_rdev;
372 struct region_device write_rdev;
373 struct region_file cache_file;
374 struct mrc_metadata md;
375 const struct cbmem_entry *to_be_updated;
376 struct incoherent_rdev backing_irdev;
377 const struct region_device *backing_rdev;
378 struct region_device latest_rdev;
379 const bool fail_bad_data = false;
Aaron Durbin9a7d7bc2013-09-07 00:41:48 -0500380
Aaron Durbin31be2c92016-12-03 22:08:20 -0600381 cr = lookup_region(&region, type);
Aaron Durbin9a7d7bc2013-09-07 00:41:48 -0500382
Aaron Durbin31be2c92016-12-03 22:08:20 -0600383 if (cr == NULL)
384 return;
Furquan Shaikhcab1c012016-11-05 23:57:02 -0700385
Aaron Durbin31be2c92016-12-03 22:08:20 -0600386 to_be_updated = cbmem_entry_find(cr->cbmem_id);
387 if (to_be_updated == NULL) {
388 printk(BIOS_ERR, "MRC: No data in cbmem for '%s'.\n",
389 cr->name);
390 return;
Aaron Durbin9a7d7bc2013-09-07 00:41:48 -0500391 }
392
Aaron Durbin31be2c92016-12-03 22:08:20 -0600393 printk(BIOS_DEBUG, "MRC: Checking cached data update for '%s'.\n",
394 cr->name);
395
396 if (boot_device_ro_subregion(&region, &read_rdev) < 0)
397 return;
398
399 if (boot_device_rw_subregion(&region, &write_rdev) < 0)
400 return;
401
402 backing_rdev = incoherent_rdev_init(&backing_irdev, &region, &read_rdev,
403 &write_rdev);
404
405 if (backing_rdev == NULL)
406 return;
407
408 if (mrc_cache_latest(cr->name, backing_rdev, &md, &cache_file,
409 &latest_rdev, fail_bad_data) < 0)
410 return;
411
412 if (!mrc_cache_needs_update(&latest_rdev, to_be_updated)) {
413 log_event_cache_update(cr->elog_slot, ALREADY_UPTODATE);
414 return;
Aaron Durbin9a7d7bc2013-09-07 00:41:48 -0500415 }
416
Aaron Durbin31be2c92016-12-03 22:08:20 -0600417 printk(BIOS_DEBUG, "MRC: cache data '%s' needs update.\n", cr->name);
418
419 if (region_file_update_data(&cache_file,
420 cbmem_entry_start(to_be_updated),
421 cbmem_entry_size(to_be_updated)) < 0)
422 log_event_cache_update(cr->elog_slot, UPDATE_FAILURE);
423 else
424 log_event_cache_update(cr->elog_slot, UPDATE_SUCCESS);
425}
426
Aaron Durbincb0c40d2017-12-14 13:53:14 -0700427/* Read flash status register to determine if write protect is active */
428static int nvm_is_write_protected(void)
429{
430 u8 sr1;
431 u8 wp_gpio;
432 u8 wp_spi;
433
434 if (!IS_ENABLED(CONFIG_CHROMEOS))
435 return 0;
436
437 if (!IS_ENABLED(CONFIG_BOOT_DEVICE_SPI_FLASH))
438 return 0;
439
440 /* Read Write Protect GPIO if available */
441 wp_gpio = get_write_protect_state();
442
443 /* Read Status Register 1 */
444 if (spi_flash_status(boot_device_spi_flash(), &sr1) < 0) {
445 printk(BIOS_ERR, "Failed to read SPI status register 1\n");
446 return -1;
447 }
448 wp_spi = !!(sr1 & 0x80);
449
450 printk(BIOS_DEBUG, "SPI flash protection: WPSW=%d SRP0=%d\n",
451 wp_gpio, wp_spi);
452
453 return wp_gpio && wp_spi;
454}
455
456/* Apply protection to a range of flash */
457static int nvm_protect(const struct region *r)
458{
Rizwan Qureshif9f50932018-12-31 15:19:16 +0530459 const struct spi_flash *flash = boot_device_spi_flash();
460
Aaron Durbincb0c40d2017-12-14 13:53:14 -0700461 if (!IS_ENABLED(CONFIG_MRC_SETTINGS_PROTECT))
462 return 0;
463
464 if (!IS_ENABLED(CONFIG_BOOT_DEVICE_SPI_FLASH))
465 return 0;
466
Rizwan Qureshif9f50932018-12-31 15:19:16 +0530467 return spi_flash_ctrlr_protect_region(flash, r, WRITE_PROTECT);
Aaron Durbincb0c40d2017-12-14 13:53:14 -0700468}
469
Aaron Durbin31be2c92016-12-03 22:08:20 -0600470/* Protect mrc region with a Protected Range Register */
471static int protect_mrc_cache(const char *name)
472{
473 struct region region;
474
475 if (!IS_ENABLED(CONFIG_MRC_SETTINGS_PROTECT))
476 return 0;
477
478 if (lookup_region_by_name(name, &region) < 0) {
479 printk(BIOS_ERR, "MRC: Could not find region '%s'\n", name);
480 return -1;
Aaron Durbin9a7d7bc2013-09-07 00:41:48 -0500481 }
482
Aaron Durbin31be2c92016-12-03 22:08:20 -0600483 if (nvm_is_write_protected() <= 0) {
484 printk(BIOS_INFO, "MRC: NOT enabling PRR for '%s'.\n", name);
485 return 0;
Aaron Durbin9a7d7bc2013-09-07 00:41:48 -0500486 }
487
Aaron Durbin31be2c92016-12-03 22:08:20 -0600488 if (nvm_protect(&region) < 0) {
489 printk(BIOS_ERR, "MRC: ERROR setting PRR for '%s'.\n", name);
490 return -1;
Aaron Durbin9a7d7bc2013-09-07 00:41:48 -0500491 }
492
Aaron Durbin31be2c92016-12-03 22:08:20 -0600493 printk(BIOS_INFO, "MRC: Enabled Protected Range on '%s'.\n", name);
494 return 0;
Furquan Shaikhcab1c012016-11-05 23:57:02 -0700495}
Aaron Durbin7d9068f2016-11-04 10:07:14 -0500496
Furquan Shaikhcab1c012016-11-05 23:57:02 -0700497static void protect_mrc_region(void)
498{
499 /*
500 * Check if there is a single unified region that encompasses both
501 * RECOVERY_MRC_CACHE and DEFAULT_MRC_CACHE. In that case protect the
502 * entire region using a single PRR.
503 *
504 * If we are not able to protect the entire region, try protecting
505 * individual regions next.
506 */
507 if (protect_mrc_cache(UNIFIED_MRC_CACHE) == 0)
508 return;
509
510 if (IS_ENABLED(CONFIG_HAS_RECOVERY_MRC_CACHE))
511 protect_mrc_cache(RECOVERY_MRC_CACHE);
512
513 protect_mrc_cache(DEFAULT_MRC_CACHE);
514}
515
Aaron Durbind09142c2016-12-14 15:36:56 -0600516static void invalidate_normal_cache(void)
517{
518 struct region_file cache_file;
519 struct region_device rdev;
520 const char *name = DEFAULT_MRC_CACHE;
521 const uint32_t invalid = ~MRC_DATA_SIGNATURE;
522
523 /* Invalidate only on recovery mode with retraining enabled. */
524 if (!vboot_recovery_mode_enabled())
525 return;
526 if (!vboot_recovery_mode_memory_retrain())
527 return;
528
529 if (fmap_locate_area_as_rdev_rw(name, &rdev) < 0) {
530 printk(BIOS_ERR, "MRC: Couldn't find '%s' region. Invalidation failed\n",
531 name);
532 return;
533 }
534
535 if (region_file_init(&cache_file, &rdev) < 0) {
536 printk(BIOS_ERR, "MRC: region file invalid for '%s'. Invalidation failed\n",
537 name);
538 return;
539 }
540
541 /* Push an update that consists of 4 bytes that is smaller than the
542 * MRC metadata as well as an invalid signature. */
543 if (region_file_update_data(&cache_file, &invalid, sizeof(invalid)) < 0)
544 printk(BIOS_ERR, "MRC: invalidation failed for '%s'.\n", name);
545}
546
Furquan Shaikhcab1c012016-11-05 23:57:02 -0700547static void update_mrc_cache(void *unused)
548{
Aaron Durbin31be2c92016-12-03 22:08:20 -0600549 update_mrc_cache_by_type(MRC_TRAINING_DATA);
Andrey Petrovef9a9ea2016-11-08 08:30:06 -0800550
Aaron Durbin31be2c92016-12-03 22:08:20 -0600551 if (IS_ENABLED(CONFIG_MRC_SETTINGS_VARIABLE_DATA))
552 update_mrc_cache_by_type(MRC_VARIABLE_DATA);
Andrey Petrovef9a9ea2016-11-08 08:30:06 -0800553
Aaron Durbind09142c2016-12-14 15:36:56 -0600554 if (IS_ENABLED(CONFIG_MRC_CLEAR_NORMAL_CACHE_ON_RECOVERY_RETRAIN))
555 invalidate_normal_cache();
556
Furquan Shaikhcab1c012016-11-05 23:57:02 -0700557 protect_mrc_region();
Aaron Durbin9a7d7bc2013-09-07 00:41:48 -0500558}
559
Subrata Banik2d1dd592017-08-16 16:42:46 +0530560/*
Marshall Dawsonf69d2d62017-12-18 15:56:44 -0700561 * Ensures MRC training data is stored into SPI after PCI enumeration is done.
562 * Some implementations may require this to be later than others.
Subrata Banik2d1dd592017-08-16 16:42:46 +0530563 */
Marshall Dawsonf69d2d62017-12-18 15:56:44 -0700564
565#if IS_ENABLED(CONFIG_MRC_WRITE_NV_LATE)
566BOOT_STATE_INIT_ENTRY(BS_OS_RESUME_CHECK, BS_ON_ENTRY, update_mrc_cache, NULL);
567#else
Subrata Banik2d1dd592017-08-16 16:42:46 +0530568BOOT_STATE_INIT_ENTRY(BS_DEV_ENUMERATE, BS_ON_EXIT, update_mrc_cache, NULL);
Marshall Dawsonf69d2d62017-12-18 15:56:44 -0700569#endif