From 53a6bef971baa7110b6c2367554acf8b77331fb6 Mon Sep 17 00:00:00 2001 From: Mary Ruthven Date: Thu, 23 Mar 2023 12:51:34 -0500 Subject: cr50: add fwmp wp policy BUG=b:268352167 TEST=see bug Change-Id: I3a4f2ae746cbc2e64df535c4c91b16cdbd7f292a Signed-off-by: Mary Ruthven Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/4367525 Reviewed-by: Andrey Pronin --- board/cr50/scratch_reg1.h | 5 +++ board/cr50/wp.c | 78 ++++++++++++++++++++++++++++++++++++++++++----- include/tpm_vendor_cmds.h | 1 + 3 files changed, 76 insertions(+), 8 deletions(-) diff --git a/board/cr50/scratch_reg1.h b/board/cr50/scratch_reg1.h index 31a3b541d7..7967c50de6 100644 --- a/board/cr50/scratch_reg1.h +++ b/board/cr50/scratch_reg1.h @@ -104,6 +104,11 @@ */ #define BOARD_USE_DIOM4 BIT(24) +/* + * The FWMP settings force WP enable. + */ +#define BOARD_FWMP_FORCE_WP_EN BIT(25) + /* * Indicates successful completion of FIPS power up * tests earlier. Reduces wake up time after sleep. diff --git a/board/cr50/wp.c b/board/cr50/wp.c index 54dc17318c..c6dbf15779 100644 --- a/board/cr50/wp.c +++ b/board/cr50/wp.c @@ -39,6 +39,14 @@ int board_battery_is_present(void) return bp_forced ? bp_connect : !gpio_get_level(GPIO_BATT_PRES_L); } +/** + * Return non-zero if the FWMP is enabling write protect. + */ +static int board_fwmp_force_wp_en(void) +{ + return !!(GREG32(PMU, LONG_LIFE_SCRATCH1) & BOARD_FWMP_FORCE_WP_EN); +} + /** * Return non-zero if the wp state is being overridden. */ @@ -54,6 +62,11 @@ static int board_forcing_wp(void) */ static void set_wp_state(int asserted) { + /* This shouldn't be possible. Ensure nothing can disable wp. */ + if (board_fwmp_force_wp_en() && !asserted) { + CPRINTS("FWMP: WP ovrd"); + asserted = 1; + } /* Enable writing to the long life register */ GWRITE_FIELD(PMU, LONG_LIFE_SCRATCH_WR_EN, REG1, 1); @@ -85,7 +98,7 @@ static void check_wp_battery_presence(void) int bp = board_battery_is_present(); /* If we're forcing WP, ignore battery detect */ - if (board_forcing_wp()) + if (board_fwmp_force_wp_en() || board_forcing_wp()) return; /* Otherwise, mirror battery */ @@ -148,6 +161,17 @@ static enum vendor_cmd_rc vc_set_wp(enum vendor_cmd_cc code, } /* Get current wp settings */ + if (board_fwmp_force_wp_en()) { + response |= WPV_FWMP_FORCE_WP_EN; + /* + * Setting WPV_ATBOOT_SET and WPV_ATBOOT_ENABLE isn't completely + * necessary. It just makes cr50 more compatible with old + * gsctool versions. These flags show WP is enabled at boot + * which is essentially what the FWMP override does. + */ + response |= WPV_ATBOOT_SET; + response |= WPV_ATBOOT_ENABLE; + } if (board_forcing_wp()) response |= WPV_FORCE; if (wp_is_asserted()) @@ -220,6 +244,11 @@ static int command_wp(int argc, char **argv) if (!ccd_is_cap_enabled(CCD_CAP_OVERRIDE_WP)) return EC_ERROR_ACCESS_DENIED; + /* It's not possible to change WP when the FWMP enables it. */ + if (board_fwmp_force_wp_en()) { + ccprintf("FWMP enabled WP\n"); + return EC_ERROR_ACCESS_DENIED; + } /* Update WP */ if (!strncasecmp(argv[1], "follow", 6)) forced = 0; @@ -237,10 +266,14 @@ static int command_wp(int argc, char **argv) } } - ccprintf("Flash WP: %s%sabled\n", board_forcing_wp() ? "forced " : "", - wp_is_asserted() ? "en" : "dis"); + ccprintf("Flash WP: %s%s%sabled\n", + board_fwmp_force_wp_en() ? "fwmp " : "", + board_forcing_wp() ? "forced " : "", + wp_is_asserted() ? "en" : "dis"); ccprintf(" at boot: "); - if (ccd_get_flag(CCD_FLAG_OVERRIDE_WP_AT_BOOT)) + if (board_fwmp_force_wp_en()) + ccprintf("fwmp enabled\n"); + else if (ccd_get_flag(CCD_FLAG_OVERRIDE_WP_AT_BOOT)) ccprintf("forced %sabled\n", ccd_get_flag(CCD_FLAG_OVERRIDE_WP_STATE_ENABLED) ? "en" : "dis"); @@ -267,7 +300,9 @@ void set_bp_follow_ccd_config(void) static void set_wp_follow_ccd_config(void) { - if (ccd_get_flag(CCD_FLAG_OVERRIDE_WP_AT_BOOT)) { + if (board_fwmp_force_wp_en()) { + force_write_protect(1, 1); + } else if (ccd_get_flag(CCD_FLAG_OVERRIDE_WP_AT_BOOT)) { /* Reset to at-boot state specified by CCD */ force_write_protect(1, ccd_get_flag (CCD_FLAG_OVERRIDE_WP_STATE_ENABLED)); @@ -289,6 +324,24 @@ void board_wp_follow_ccd_config(void) set_wp_follow_ccd_config(); } +static int board_fwmp_check_wp_policy(void) +{ + int fwmp_force_wp = !board_fwmp_allows_unlock(); + int update_brdprop = fwmp_force_wp != board_fwmp_force_wp_en(); + + if (update_brdprop) { + CPRINTS("%s", __func__); + board_write_prop(BOARD_FWMP_FORCE_WP_EN, fwmp_force_wp); + } + + if (fwmp_force_wp && (!wp_is_asserted() || update_brdprop)) { + CPRINTS("%s: force en", __func__); + force_write_protect(1, 1); + return 0; + } + return update_brdprop; +} + void init_wp_state(void) { /* @@ -297,6 +350,16 @@ void init_wp_state(void) */ set_bp_follow_ccd_config(); + /* + * If the FWMP is forcing WP, enable write protect. It overrides other + * configs. + */ + board_fwmp_check_wp_policy(); + if (board_fwmp_force_wp_en()) { + set_wp_state(1); + return; + } + /* Check system reset flags after CCD config is initially loaded */ if ((system_get_reset_flags() & EC_RESET_FLAG_HIBERNATE) && !system_rollback_detected()) { @@ -498,9 +561,8 @@ int board_fwmp_allows_boot_policy_update(void) void board_fwmp_update_policies(void) { -#ifdef CR50_DEV - CPRINTS("Update fwmp policies."); -#endif + if (board_fwmp_check_wp_policy()) + set_wp_follow_ccd_config(); } int board_vboot_dev_mode_enabled(void) diff --git a/include/tpm_vendor_cmds.h b/include/tpm_vendor_cmds.h index ba8c1a208c..943fafd1a2 100644 --- a/include/tpm_vendor_cmds.h +++ b/include/tpm_vendor_cmds.h @@ -346,5 +346,6 @@ struct vendor_cc_spi_hash_request { #define WPV_FORCE BIT(2) #define WPV_ATBOOT_SET BIT(3) #define WPV_ATBOOT_ENABLE BIT(4) +#define WPV_FWMP_FORCE_WP_EN BIT(5) #endif /* __INCLUDE_TPM_VENDOR_CMDS_H */ -- cgit v1.2.1