diff --git a/common/ccd_config.c b/common/ccd_config.c index ee3e6adb9e..8b60a1e84b 100644 --- a/common/ccd_config.c +++ b/common/ccd_config.c @@ -93,21 +93,6 @@ struct ccd_capability_info { enum ccd_capability_state default_state; }; -/* Flags for ccd_reset_config() */ -enum ccd_reset_config_flags { - /* Also reset test lab flag */ - CCD_RESET_TEST_LAB = (1 << 0), - - /* Only reset Always/UnlessLocked settings */ - CCD_RESET_UNLOCKED_ONLY = (1 << 1), - - /* Use RMA/factory defaults */ - CCD_RESET_RMA = (1 << 2) -}; - -/* Forward declarations of static functions */ -static int ccd_reset_config(unsigned flags); - /* Nvmem variable name for CCD config */ static const uint8_t k_ccd_config = NVMEM_VAR_CCD_CONFIG; @@ -454,13 +439,7 @@ static int ccd_set_cap(enum ccd_capability cap, enum ccd_capability_state state) return ccd_save_config(); } -/** - * Reset CCD config to defaults. - * - * @param flags Reset flags (see enum ccd_reset_config_flags) - * @return EC_SUCCESS, or non-zero if error. - */ -static int ccd_reset_config(unsigned flags) +int ccd_reset_config(unsigned int flags) { int old_lab = ccd_get_flag(CCD_FLAG_TEST_LAB); diff --git a/common/rma_auth.c b/common/rma_auth.c index 926dfb1328..2bb5550e9d 100644 --- a/common/rma_auth.c +++ b/common/rma_auth.c @@ -8,10 +8,12 @@ #include "common.h" #include "base32.h" #include "byteorder.h" +#include "ccd_config.h" #include "chip/g/board_id.h" #include "console.h" #include "curve25519.h" #include "extension.h" +#include "hooks.h" #include "rma_auth.h" #include "shared_mem.h" #include "system.h" @@ -225,6 +227,78 @@ static enum vendor_cmd_rc get_challenge(uint8_t *buf, size_t *buf_size) return VENDOR_RC_SUCCESS; } +static uint8_t ccd_hook_active; + +static void ccd_config_changed(void) +{ + if (!ccd_hook_active) + return; + + CPRINTF("%s: CCD change saved, rebooting\n", __func__); + cflush(); + system_reset(SYSTEM_RESET_HARD); +} +DECLARE_HOOK(HOOK_CCD_CHANGE, ccd_config_changed, HOOK_PRIO_LAST); + +static void rma_reset_failed(void) +{ + ccd_hook_active = 0; + CPRINTF("%s: CCD RMA reset failed\n"); + deassert_ec_rst(); +} +DECLARE_DEFERRED(rma_reset_failed); + +/* The below time constants are way longer than should be required in practice: + * + * Time it takes to finish processing TPM command which provided valid RMA + * authentication code. + */ +#define TPM_PROCESSING_TIME (1 * SECOND) + +/* + * Time it takse TPM reset function to wipe out the NVMEM and reboot the + * device. + */ +#define TPM_RESET_TIME (10 * SECOND) + +/* Total time deep sleep should not be allowed. */ +#define DISABLE_SLEEP_TIME (TPM_PROCESSING_TIME + TPM_RESET_TIME) + +static void enter_rma_mode(void) +{ + int rv; + + CPRINTF("%s: resetting TPM\n", __func__); + + /* + * Let's make sure the rest of the system is out of the way while TPM + * is being wiped out. + */ + assert_ec_rst(); + + if (tpm_reset_request(1, 1) != EC_SUCCESS) { + CPRINTF("%s: TPM reset attempt failed\n", __func__); + deassert_ec_rst(); + return; + } + + tpm_reinstate_nvmem_commits(); + + CPRINTF("%s: TPM reset succeeded, RMA resetting CCD\n", __func__); + + ccd_hook_active = 1; + rv = ccd_reset_config(CCD_RESET_RMA); + if (rv != EC_SUCCESS) + rma_reset_failed(); + + /* + * Make sure we never end up with the EC held in reset, no matter what + * prevents the proper RMA flow from succeeding. + */ + hook_call_deferred(&rma_reset_failed_data, TPM_RESET_TIME); +} +DECLARE_DEFERRED(enter_rma_mode); + /* * Compare response sent by the operator with the pre-compiled auth code. * Return error code or success depending on the comparison results. @@ -249,6 +323,8 @@ static enum vendor_cmd_rc process_response(uint8_t *buf, if (rv == EC_SUCCESS) { CPRINTF("%s: success!\n", __func__); *response_size = 0; + delay_sleep_by(DISABLE_SLEEP_TIME); + hook_call_deferred(&enter_rma_mode_data, TPM_PROCESSING_TIME); return VENDOR_RC_SUCCESS; } diff --git a/include/ccd_config.h b/include/ccd_config.h index 333f4552b7..075cb53502 100644 --- a/include/ccd_config.h +++ b/include/ccd_config.h @@ -156,4 +156,24 @@ enum ccd_state ccd_get_state(void); */ void ccd_disable(void); +/* Flags for ccd_reset_config() */ +enum ccd_reset_config_flags { + /* Also reset test lab flag */ + CCD_RESET_TEST_LAB = (1 << 0), + + /* Only reset Always/UnlessLocked settings */ + CCD_RESET_UNLOCKED_ONLY = (1 << 1), + + /* Use RMA/factory defaults */ + CCD_RESET_RMA = (1 << 2) +}; + +/** + * Reset CCD config to the desired state. + * + * @param flags Reset flags (see enum ccd_reset_config_flags) + * @return EC_SUCCESS, or non-zero if error. + */ +int ccd_reset_config(unsigned int flags); + #endif /* __CROS_EC_CCD_CONFIG_H */