1 /* Copyright 2018 The ChromiumOS Authors
2 * Use of this source code is governed by a BSD-style license that can be
3 * found in the LICENSE file.
4 *
5 * The board-specific quirks needed by firmware updater.
6 */
7
8 #include <assert.h>
9 #include <stdio.h>
10 #include <string.h>
11 #include <sys/types.h>
12 #include <sys/stat.h>
13
14 #include "cbfstool.h"
15 #include "crossystem.h"
16 #include "futility.h"
17 #include "host_misc.h"
18 #include "platform_csme.h"
19 #include "updater.h"
20
21 struct quirks_record {
22 const char * const match;
23 const char * const quirks;
24 };
25
26 /*
27 * The 'match by firmware name' is now deprecated. Please do not add any
28 * new records below. We now support reading quirks from CBFS, which is
29 * easier and more reliable. To do that, create a text file 'updater_quirks'
30 * and install to the CBFS.
31 *
32 * Examples: CL:*3365287, CL:*3351831, CL:*4441527
33 */
34 static const struct quirks_record quirks_records[] = {
35 { .match = "Google_Eve.",
36 .quirks = "unlock_csme_eve,eve_smm_store" },
37
38 { .match = "Google_Poppy.", .quirks = "min_platform_version=6" },
39 { .match = "Google_Scarlet.", .quirks = "min_platform_version=1" },
40 { .match = "Google_Trogdor.", .quirks = "min_platform_version=2" },
41
42 /* Legacy custom label units. */
43
44 /* reference design: octopus */
45 { .match = "Google_Phaser.", .quirks = "override_custom_label" },
46 };
47
48 /*
49 * Returns True if the system has EC software sync enabled.
50 */
is_ec_software_sync_enabled(struct updater_config * cfg)51 static int is_ec_software_sync_enabled(struct updater_config *cfg)
52 {
53 const struct vb2_gbb_header *gbb;
54
55 int vdat_flags = dut_get_property_int("vdat_flags", cfg);
56 if (vdat_flags < 0) {
57 WARN("Failed to identify DUT vdat_flags.\n");
58 return 0;
59 }
60
61 /* Check if current system has disabled software sync or no support. */
62 if (!(vdat_flags & VBSD_EC_SOFTWARE_SYNC)) {
63 INFO("EC Software Sync is not available.\n");
64 return 0;
65 }
66
67 /* Check if the system has been updated to disable software sync. */
68 gbb = find_gbb(&cfg->image);
69 if (!gbb) {
70 WARN("Invalid AP firmware image.\n");
71 return 0;
72 }
73 if (gbb->flags & VB2_GBB_FLAG_DISABLE_EC_SOFTWARE_SYNC) {
74 INFO("EC Software Sync will be disabled in next boot.\n");
75 return 0;
76 }
77 return 1;
78 }
79
80 /*
81 * Schedules an EC RO software sync (in next boot) if applicable.
82 */
ec_ro_software_sync(struct updater_config * cfg)83 static int ec_ro_software_sync(struct updater_config *cfg)
84 {
85 const char *ec_ro_path;
86 uint8_t *ec_ro_data;
87 uint32_t ec_ro_len;
88 int is_same_ec_ro;
89 struct firmware_section ec_ro_sec;
90 const char *image_file = get_firmware_image_temp_file(
91 &cfg->image, &cfg->tempfiles);
92
93 if (!image_file)
94 return 1;
95 find_firmware_section(&ec_ro_sec, &cfg->ec_image, "EC_RO");
96 if (!ec_ro_sec.data || !ec_ro_sec.size) {
97 ERROR("EC image has invalid section '%s'.\n", "EC_RO");
98 return 1;
99 }
100
101 ec_ro_path = create_temp_file(&cfg->tempfiles);
102 if (!ec_ro_path) {
103 ERROR("Failed to create temp file.\n");
104 return 1;
105 }
106 if (cbfstool_extract(image_file, FMAP_RO_CBFS, "ecro", ec_ro_path) ||
107 !cbfstool_file_exists(image_file, FMAP_RO_CBFS, "ecro.hash")) {
108 INFO("No valid EC RO for software sync in AP firmware.\n");
109 return 1;
110 }
111 if (vb2_read_file(ec_ro_path, &ec_ro_data, &ec_ro_len) != VB2_SUCCESS) {
112 ERROR("Failed to read EC RO.\n");
113 return 1;
114 }
115
116 is_same_ec_ro = (ec_ro_len <= ec_ro_sec.size &&
117 memcmp(ec_ro_sec.data, ec_ro_data, ec_ro_len) == 0);
118 free(ec_ro_data);
119
120 if (!is_same_ec_ro) {
121 /* TODO(hungte) If change AP RO is not a problem (hash will be
122 * different, which may be a problem to factory and HWID), or if
123 * we can be be sure this is for developers, extract EC RO and
124 * update AP RO CBFS to trigger EC RO sync with new EC.
125 */
126 ERROR("The EC RO contents specified from AP (--image) and EC "
127 "(--ec_image) firmware images are different, cannot "
128 "update by EC RO software sync.\n");
129 return 1;
130 }
131 dut_set_property_int("try_ro_sync", 1, cfg);
132 return 0;
133 }
134
135 /*
136 * Returns True if EC is running in RW.
137 */
is_ec_in_rw(struct updater_config * cfg)138 static int is_ec_in_rw(struct updater_config *cfg)
139 {
140 char buf[VB_MAX_STRING_PROPERTY];
141 return (dut_get_property_string("ecfw_act", buf, sizeof(buf), cfg) == 0
142 && strcasecmp(buf, "RW") == 0);
143 }
144
145 /*
146 * Quirk to enlarge a firmware image to match flash size. This is needed by
147 * devices using multiple SPI flash with different sizes, for example 8M and
148 * 16M. The image_to will be padded with 0xFF using the size of image_from.
149 * Returns 0 on success, otherwise failure.
150 */
quirk_enlarge_image(struct updater_config * cfg)151 static int quirk_enlarge_image(struct updater_config *cfg)
152 {
153 struct firmware_image *image_from = &cfg->image_current,
154 *image_to = &cfg->image;
155 const char *tmp_path;
156 size_t to_write;
157 FILE *fp;
158
159 if (image_from->size <= image_to->size)
160 return 0;
161
162 tmp_path = get_firmware_image_temp_file(image_to, &cfg->tempfiles);
163 if (!tmp_path)
164 return -1;
165
166 VB2_DEBUG("Resize image from %u to %u.\n",
167 image_to->size, image_from->size);
168 to_write = image_from->size - image_to->size;
169 fp = fopen(tmp_path, "ab");
170 if (!fp) {
171 ERROR("Cannot open temporary file %s.\n", tmp_path);
172 return -1;
173 }
174 while (to_write-- > 0)
175 fputc('\xff', fp);
176 fclose(fp);
177 return reload_firmware_image(tmp_path, image_to);
178 }
179
180 /*
181 * Platform specific quirks to unlock a firmware image with SI_ME (management
182 * engine). This may be useful when updating so the system has a chance to make
183 * sure SI_ME won't be corrupted on next boot before locking the Flash Master
184 * values in SI_DESC.
185 *
186 * Returns 0 on success, otherwise failure.
187 */
quirk_unlock_csme_eve(struct updater_config * cfg)188 static int quirk_unlock_csme_eve(struct updater_config *cfg)
189 {
190 return unlock_csme_eve(&cfg->image);
191 }
192
quirk_unlock_csme(struct updater_config * cfg)193 static int quirk_unlock_csme(struct updater_config *cfg)
194 {
195 return unlock_csme(cfg);
196 }
197
198 /*
199 * Checks and returns 0 if the platform version of current system is larger
200 * or equal to given number, otherwise non-zero.
201 */
quirk_min_platform_version(struct updater_config * cfg)202 static int quirk_min_platform_version(struct updater_config *cfg)
203 {
204 int min_version = get_config_quirk(QUIRK_MIN_PLATFORM_VERSION, cfg);
205 int platform_version = dut_get_property(DUT_PROP_PLATFORM_VER, cfg);
206
207 VB2_DEBUG("Minimum required version=%d, current platform version=%d\n",
208 min_version, platform_version);
209
210 if (platform_version >= min_version)
211 return 0;
212 ERROR("Need platform version >= %d (current is %d). "
213 "This firmware will only run on newer systems.\n",
214 min_version, platform_version);
215 return -1;
216 }
217
218 /*
219 * Quirk to help preserving SMM store on devices without a dedicated "SMMSTORE"
220 * FMAP section. These devices will store "smm_store" file in same CBFS where
221 * the legacy boot loader lives (i.e, FMAP RW_LEGACY).
222 * Note this currently has dependency on external program "cbstool".
223 * Returns 0 if the SMM store is properly preserved, or if the system is not
224 * available to do that (problem in cbfstool, or no "smm_store" in current
225 * system firmware). Otherwise non-zero as failure.
226 */
quirk_eve_smm_store(struct updater_config * cfg)227 static int quirk_eve_smm_store(struct updater_config *cfg)
228 {
229 const char *smm_store_name = "smm_store";
230 const char *old_store;
231 char *command;
232 const char *temp_image = get_firmware_image_temp_file(
233 &cfg->image_current, &cfg->tempfiles);
234
235 if (!temp_image)
236 return -1;
237
238 old_store = create_temp_file(&cfg->tempfiles);
239 if (!old_store) {
240 ERROR("Failed to create temp file.\n");
241 return 1;
242 }
243 if (cbfstool_extract(temp_image, FMAP_RW_LEGACY, smm_store_name,
244 old_store)) {
245 VB2_DEBUG("cbfstool failure or SMM store not available. "
246 "Don't preserve.\n");
247 return 0;
248 }
249
250 /* Reuse temp_image */
251 temp_image = get_firmware_image_temp_file(&cfg->image, &cfg->tempfiles);
252 if (!temp_image)
253 return -1;
254
255 /* crosreview.com/1165109: The offset is fixed at 0x1bf000. */
256 ASPRINTF(&command,
257 "cbfstool \"%s\" remove -r %s -n \"%s\" 2>/dev/null; "
258 "cbfstool \"%s\" add -r %s -n \"%s\" -f \"%s\" "
259 " -t raw -b 0x1bf000", temp_image, FMAP_RW_LEGACY,
260 smm_store_name, temp_image, FMAP_RW_LEGACY,
261 smm_store_name, old_store);
262 free(host_shell(command));
263 free(command);
264
265 return reload_firmware_image(temp_image, &cfg->image);
266 }
267
268 /*
269 * Update EC (RO+RW) in most reliable way.
270 *
271 * Some EC will reset TCPC when doing sysjump, and will make rootfs unavailable
272 * if the system was boot from USB, or other unexpected issues even if the
273 * system was boot from internal disk. To prevent that, try to partial update
274 * only RO and expect EC software sync to update RW later, or perform EC RO
275 * software sync.
276 *
277 * Note: EC RO software sync was not fully tested and may cause problems
278 * (b/218612817, b/187789991).
279 * RO-update (without extra sysjump) needs support from flashrom and is
280 * currently disabled.
281 *
282 * Returns:
283 * EC_RECOVERY_FULL to indicate a full recovery is needed.
284 * EC_RECOVERY_RO to indicate partial update (WP_RO) is needed.
285 * EC_RECOVERY_DONE to indicate EC RO software sync is applied.
286 * Other values to report failure.
287 */
quirk_ec_partial_recovery(struct updater_config * cfg)288 static int quirk_ec_partial_recovery(struct updater_config *cfg)
289 {
290 /*
291 * http://crbug.com/1024401: Some EC needs extra header outside EC_RO so
292 * we have to update whole WP_RO, not just EC_RO.
293 */
294 const char *ec_ro = "WP_RO";
295 struct firmware_image *ec_image = &cfg->ec_image;
296 int do_partial = get_config_quirk(QUIRK_EC_PARTIAL_RECOVERY, cfg);
297
298 if (!do_partial) {
299 /* Need full update. */
300 } else if (!firmware_section_exists(ec_image, ec_ro)) {
301 INFO("EC image does not have section '%s'.\n", ec_ro);
302 /* Need full update. */
303 } else if (!is_ec_software_sync_enabled(cfg)) {
304 /* Message already printed, need full update. */
305 } else if (is_ec_in_rw(cfg)) {
306 WARN("EC Software Sync detected, will only update EC RO. "
307 "The contents in EC RW will be updated after reboot.\n");
308 return EC_RECOVERY_RO;
309 } else if (ec_ro_software_sync(cfg) == 0) {
310 INFO("EC RO and RW should be updated after reboot.\n");
311 return EC_RECOVERY_DONE;
312 }
313
314 WARN("Update EC RO+RW and may cause unexpected error later. "
315 "See http://crbug.com/782427#c4 for more information.\n");
316 return EC_RECOVERY_FULL;
317 }
318
319 /*
320 * Preserve ME during firmware update.
321 *
322 * Updating ME region while SoC is in S0 state is an unsupported use-case. On
323 * recent platforms, we are seeing issues more frequently because of this use-
324 * case. For the firmware updates performed for autoupdate firmware updates,
325 * preserve the ME region so that it gets updated in the successive boot.
326 *
327 * Returns:
328 * 1 to signal ME needs to be preserved.
329 * 0 to signal ME does not need to be preserved.
330 */
quirk_preserve_me(struct updater_config * cfg)331 static int quirk_preserve_me(struct updater_config *cfg)
332 {
333 /*
334 * Only preserve the ME if performing an autoupdate-mode firmware
335 * update. Recovery, factory and any other update modes cannot leave the
336 * ME as is. Otherwise, a recovery firmware update cannot be relied upon
337 * to update the ME to a valid version for WP-disabled devices.
338 */
339 if (cfg->try_update == TRY_UPDATE_OFF) {
340 INFO("No auto-update requested. Not preserving ME.\n");
341 return 0;
342 }
343 INFO("Auto-update requested. Preserving ME.\n");
344
345 /*
346 * b/213706510: subratabanik@ confirmed CSE may modify itself while we
347 * are doing system update, and currently the 'preserve' is done by
348 * flashing the same (e.g., "previously read") contents to skip erasing
349 * and writing; so we have to use the diff image to prevent contents
350 * being changed when writing.
351 */
352 cfg->use_diff_image = 1;
353
354 return 1;
355 }
356
quirk_clear_mrc_data(struct updater_config * cfg)357 static int quirk_clear_mrc_data(struct updater_config *cfg)
358 {
359 struct firmware_section section;
360 struct firmware_image *image = &cfg->image_current;
361 int i, count = 0;
362 int flash_now = 0;
363
364 /*
365 * Devices with multiple MRC caches (RECOVERY, RW, RW_VAR) will have the
366 * UNIFIED_MRC_CACHE; and devices with single RW cache will only have
367 * RW_MRC_CACHE (for example MediaTek devices).
368 */
369 const char * const mrc_names[] = {
370 "UNIFIED_MRC_CACHE",
371 "RW_MRC_CACHE",
372 };
373
374 if (is_ap_write_protection_enabled(cfg) || cfg->try_update)
375 flash_now = 1;
376
377 for (i = 0; i < ARRAY_SIZE(mrc_names); i++) {
378 const char *name = mrc_names[i];
379
380 find_firmware_section(§ion, image, name);
381 if (!section.size)
382 continue;
383
384 WARN("Wiping memory training data: %s\n", name);
385 memset(section.data, 0xff, section.size);
386 if (flash_now) {
387 const char *write_names[] = {name};
388 write_system_firmware(cfg, image, write_names,
389 ARRAY_SIZE(write_names));
390 }
391 count++;
392 break;
393 }
394
395 if (count)
396 WARN("Next boot will take a few mins for memory training.\n");
397 else
398 ERROR("No known memory training data in the firmware image.\n");
399
400 return 0;
401 }
402
403 /*
404 * Disable checking platform compatibility.
405 */
quirk_no_check_platform(struct updater_config * cfg)406 static int quirk_no_check_platform(struct updater_config *cfg)
407 {
408 WARN("Disabled checking platform. You are on your own.\n");
409 cfg->check_platform = 0;
410 return 0;
411 }
412
413 /*
414 * Disable verifying contents after flashing.
415 */
quirk_no_verify(struct updater_config * cfg)416 static int quirk_no_verify(struct updater_config *cfg)
417 {
418 WARN("Disabled verifying flashed contents. You are on your own.\n");
419 cfg->do_verify = 0;
420 return 0;
421 }
422
updater_register_quirks(struct updater_config * cfg)423 void updater_register_quirks(struct updater_config *cfg)
424 {
425 struct quirk_entry *quirks;
426
427 assert(ARRAY_SIZE(cfg->quirks) == QUIRK_MAX);
428 quirks = &cfg->quirks[QUIRK_ENLARGE_IMAGE];
429 quirks->name = "enlarge_image";
430 quirks->help = "Enlarge firmware image by flash size.";
431 quirks->apply = quirk_enlarge_image;
432
433 quirks = &cfg->quirks[QUIRK_MIN_PLATFORM_VERSION];
434 quirks->name = "min_platform_version";
435 quirks->help = "Minimum compatible platform version "
436 "(also known as Board ID version).";
437 quirks->apply = quirk_min_platform_version;
438
439 quirks = &cfg->quirks[QUIRK_UNLOCK_CSME_EVE];
440 quirks->name = "unlock_csme_eve";
441 quirks->help = "b/35568719; (skl, kbl) only lock management engine in board-postinst.";
442 quirks->apply = quirk_unlock_csme_eve;
443
444 quirks = &cfg->quirks[QUIRK_UNLOCK_CSME];
445 quirks->name = "unlock_csme";
446 quirks->help = "b/273168873; unlock the Intel management engine. "
447 "Applies to all recent Intel platforms (CML onwards)";
448 quirks->apply = quirk_unlock_csme;
449
450 quirks = &cfg->quirks[QUIRK_EVE_SMM_STORE];
451 quirks->name = "eve_smm_store";
452 quirks->help = "b/70682365; preserve UEFI SMM store without "
453 "dedicated FMAP section.";
454 quirks->apply = quirk_eve_smm_store;
455
456 quirks = &cfg->quirks[QUIRK_EC_PARTIAL_RECOVERY];
457 quirks->name = "ec_partial_recovery";
458 quirks->help = "chromium/1024401; recover EC by partial RO update.";
459 quirks->apply = quirk_ec_partial_recovery;
460
461 quirks = &cfg->quirks[QUIRK_OVERRIDE_CUSTOM_LABEL];
462 quirks->name = "override_custom_label";
463 quirks->help = "b/146876241; override custom label name for "
464 "devices shipped with different root key.";
465 quirks->apply = NULL; /* Simple config. */
466
467 quirks = &cfg->quirks[QUIRK_PRESERVE_ME];
468 quirks->name = "preserve_me";
469 quirks->help = "b/165590952; Preserve ME during firmware update except "
470 "for factory update or developer images.";
471 quirks->apply = quirk_preserve_me;
472
473 quirks = &cfg->quirks[QUIRK_NO_CHECK_PLATFORM];
474 quirks->name = "no_check_platform";
475 quirks->help = "Do not check platform name.";
476 quirks->apply = quirk_no_check_platform;
477
478 quirks = &cfg->quirks[QUIRK_NO_VERIFY];
479 quirks->name = "no_verify";
480 quirks->help = "Do not verify when flashing.";
481 quirks->apply = quirk_no_verify;
482
483 quirks = &cfg->quirks[QUIRK_EXTRA_RETRIES];
484 quirks->name = "extra_retries";
485 quirks->help = "Extra retries when writing to system firmware.";
486 quirks->apply = NULL; /* Simple config. */
487
488 quirks = &cfg->quirks[QUIRK_CLEAR_MRC_DATA];
489 quirks->name = "clear_mrc_data";
490 quirks->help = "b/255617349: Clear memory training data (MRC).";
491 quirks->apply = quirk_clear_mrc_data;
492 }
493
updater_get_model_quirks(struct updater_config * cfg)494 const char * const updater_get_model_quirks(struct updater_config *cfg)
495 {
496 const char *pattern = cfg->image.ro_version;
497 int i;
498
499 if (!pattern) {
500 VB2_DEBUG("Cannot identify system for default quirks.\n");
501 return NULL;
502 }
503
504 for (i = 0; i < ARRAY_SIZE(quirks_records); i++) {
505 const struct quirks_record *r = &quirks_records[i];
506 if (strncmp(r->match, pattern, strlen(r->match)) != 0)
507 continue;
508 VB2_DEBUG("Found system default quirks: %s\n", r->quirks);
509 return r->quirks;
510 }
511 return NULL;
512 }
513
updater_get_cbfs_quirks(struct updater_config * cfg)514 char *updater_get_cbfs_quirks(struct updater_config *cfg)
515 {
516 const char *entry_name = "updater_quirks";
517 const char *cbfs_region = "FW_MAIN_A";
518 struct firmware_section cbfs_section;
519
520 /* Before invoking cbfstool, try to search for CBFS file name. */
521 find_firmware_section(&cbfs_section, &cfg->image, cbfs_region);
522 if (!cbfs_section.size || !memmem(cbfs_section.data, cbfs_section.size,
523 entry_name, strlen(entry_name))) {
524 if (!cbfs_section.size)
525 VB2_DEBUG("Missing region: %s\n", cbfs_region);
526 else
527 VB2_DEBUG("Cannot find entry: %s\n", entry_name);
528 return NULL;
529 }
530
531 const char *image_file = get_firmware_image_temp_file(
532 &cfg->image, &cfg->tempfiles);
533 uint8_t *data = NULL;
534 uint32_t size = 0;
535 const char *entry_file;
536
537 /* Although the name exists, it may not be a real file. */
538 if (!cbfstool_file_exists(image_file, cbfs_region, entry_name)) {
539 VB2_DEBUG("Found string '%s' but not a file.\n", entry_name);
540 return NULL;
541 }
542
543 VB2_DEBUG("Found %s from CBFS %s\n", entry_name, cbfs_region);
544 entry_file = create_temp_file(&cfg->tempfiles);
545 if (!entry_file) {
546 ERROR("Failed to create temp file.\n");
547 return NULL;
548 }
549 if (cbfstool_extract(image_file, cbfs_region, entry_name, entry_file) ||
550 vb2_read_file(entry_file, &data, &size) != VB2_SUCCESS) {
551 ERROR("Failed to read [%s] from CBFS [%s].\n",
552 entry_name, cbfs_region);
553 return NULL;
554 }
555 VB2_DEBUG("Got quirks (%u bytes): %s\n", size, data);
556 return (char *)data;
557 }
558
quirk_override_custom_label(struct updater_config * cfg,const struct manifest * manifest,const struct model_config * model)559 const struct model_config *quirk_override_custom_label(
560 struct updater_config *cfg,
561 const struct manifest *manifest,
562 const struct model_config *model)
563 {
564 /* If not write protected, no need to apply the hack. */
565 if (!is_ap_write_protection_enabled(cfg)) {
566 VB2_DEBUG("Skipped because AP not write protected.\n");
567 return NULL;
568 }
569
570 const struct firmware_image *image = &cfg->image_current;
571 assert(image && image->data);
572
573 if (strcmp(model->name, "phaser360") == 0) {
574 /* b/146876241 */
575 const char *key_hash = get_firmware_rootkey_hash(image);
576 const char * const DOPEFISH_KEY_HASH =
577 "9a1f2cc319e2f2e61237dc51125e35ddd4d20984";
578
579 if (key_hash && strcmp(key_hash, DOPEFISH_KEY_HASH) == 0) {
580 const char * const dopefish = "phaser360-dopefish";
581 WARN("A Phaser360 with Dopefish rootkey - "
582 "override custom label to '%s'.\n", dopefish);
583 model = manifest_find_model(cfg, manifest, dopefish);
584 if (model)
585 INFO("Model changed to '%s'.\n", model->name);
586 else
587 ERROR("No model defined for '%s'.\n", dopefish);
588
589 return model;
590 }
591 }
592 return NULL;
593 }
594