Recovery mode: Clear TPM and extend PCR0 with recovery mode value
Change-Id: I55125046f91ded4424c4dd8451c878bd70d2a15f
Google-Bug-Id: 22506543
diff --git a/arch/arm/boards/optimus/optimus.c b/arch/arm/boards/optimus/optimus.c
index 5b759ae..43554e1 100644
--- a/arch/arm/boards/optimus/optimus.c
+++ b/arch/arm/boards/optimus/optimus.c
@@ -512,6 +512,12 @@
#ifdef CONFIG_TPM
if (tpm_init() != TPM_SUCCESS) {
printf("TPM initialization failed\n");
+ if (recovery_mode) {
+ printf("Can't continue boot to recovery mode\nPower cycle needed\n");
+ while (1) {
+ mdelay(100);
+ }
+ }
}
#endif
#endif
diff --git a/arch/arm/boards/optimus/tpm.c b/arch/arm/boards/optimus/tpm.c
index 084cc3f..182b931 100644
--- a/arch/arm/boards/optimus/tpm.c
+++ b/arch/arm/boards/optimus/tpm.c
@@ -35,17 +35,29 @@
#define PCR_DIGEST_LENGTH 20
-#define SHA1_NON_SECURE_BOOT 0
-#define SHA1_SECURE_BOOT 1
+#define SHA1_NON_SECURE_BOOT 0
+#define SHA1_SECURE_BOOT 1
+#define SHA1_RECOVERY_MODE_NON_SECURE 2
+#define SHA1_RECOVERY_MODE_SECURE 3
-static const uint8_t bootmode_digests[2][PCR_DIGEST_LENGTH] = {
+extern int is_recovery_mode(void);
+
+static const uint8_t bootmode_digests[4][PCR_DIGEST_LENGTH] = {
/* non-secure boot [0, 0, 2] */
{0x1e, 0xf6, 0x24, 0x48, 0x2d, 0x62, 0x0e, 0x43, 0xe6, 0xd3,
0x4d, 0xa1, 0xaf, 0xe4, 0x62, 0x67, 0xfc, 0x69, 0x5d, 0x9b},
/* secure boot [0, 0, 1] */
{0x25, 0x47, 0xcc, 0x73, 0x6e, 0x95, 0x1f, 0xa4, 0x91, 0x98,
- 0x53, 0xc4, 0x3a, 0xe8, 0x90, 0x86, 0x1a, 0x3b, 0x32, 0x64}
+ 0x53, 0xc4, 0x3a, 0xe8, 0x90, 0x86, 0x1a, 0x3b, 0x32, 0x64},
+
+ /* recovery mode, non-secure [0, 1, 2] */
+ {0x0c, 0x7a, 0x62, 0x3f, 0xd2, 0xbb, 0xc0, 0x5b, 0x06, 0x42,
+ 0x3b, 0xe3, 0x59, 0xe4, 0x02, 0x1d, 0x36, 0xe7, 0x21, 0xad},
+
+ /* recovery mode, secure [0, 1, 1] */
+ {0xee, 0xe4, 0x47, 0xed, 0xc7, 0x9f, 0xea, 0x1c, 0xa7, 0xc7,
+ 0xd3, 0x4e, 0x46, 0x32, 0x61, 0xcd, 0xa4, 0xba, 0x33, 0x9e}
};
static const uint8_t sha256_gfsc100[PCR_DIGEST_LENGTH] = {
@@ -68,7 +80,7 @@
result = tlcl_startup();
if ((result != TPM_SUCCESS) &&
- (result != TPM_E_INVALID_POSTINIT)) {
+ (is_recovery_mode() || (result != TPM_E_INVALID_POSTINIT))) {
/* Invalid postinit indicates that TPM_Startup has already been
executed. This situation occurs on reboots on the GFSC100
platform because a reboot does not powercycle the TPM */
@@ -80,30 +92,49 @@
functions will return TPM_NEEDS_SELFTEST otherwise */
RETURN_ON_FAILURE(tlcl_continue_self_test());
- RETURN_ON_FAILURE(tlcl_get_flags(&disable, &deactivated, NULL));
- if (disable || deactivated) {
- printk(KERN_DEBUG "TPM: disabled (%d) or deactivated (%d). "
- "Fixing...\n", disable, deactivated);
- RETURN_ON_FAILURE(tlcl_assert_physical_presence());
- RETURN_ON_FAILURE(tlcl_set_enable());
- RETURN_ON_FAILURE(tlcl_set_deactivated(0));
- }
+ if (!is_recovery_mode()) {
+ RETURN_ON_FAILURE(tlcl_get_flags(&disable, &deactivated, NULL));
+ if (disable || deactivated) {
+ printk(KERN_DEBUG "TPM: disabled (%d) or deactivated (%d). "
+ "Fixing...\n", disable, deactivated);
+ RETURN_ON_FAILURE(tlcl_assert_physical_presence());
+ RETURN_ON_FAILURE(tlcl_set_enable());
+ RETURN_ON_FAILURE(tlcl_set_deactivated(0));
+ }
- RETURN_ON_FAILURE(tlcl_get_stclear_flags(&sflags));
- if (sflags.deactivated) {
- printk(KERN_DEBUG "TPM: Must reboot to re-enable\n");
- return TPM_E_MUST_REBOOT;
- }
+ RETURN_ON_FAILURE(tlcl_get_stclear_flags(&sflags));
+ if (sflags.deactivated) {
+ printk(KERN_DEBUG "TPM: Must reboot to re-enable\n");
+ return TPM_E_MUST_REBOOT;
+ }
- RETURN_ON_FAILURE(tlcl_read_pcr(0, pcr_value));
- if (!memcmp(pcr_value, PCR_uninitialized, PCR_DIGEST_LENGTH)) {
- /* PCR0 not initialized, extend it with the boot mode */
+ RETURN_ON_FAILURE(tlcl_read_pcr(0, pcr_value));
+ if (!memcmp(pcr_value, PCR_uninitialized, PCR_DIGEST_LENGTH)) {
+ /* PCR0 not initialized, extend it with the boot mode */
+ const uint8_t *digest;
+
+ if (get_secure_boot_mode() == SECURE) {
+ digest = bootmode_digests[SHA1_SECURE_BOOT];
+ } else {
+ digest = bootmode_digests[SHA1_NON_SECURE_BOOT];
+ }
+
+ RETURN_ON_FAILURE(tlcl_extend(0, digest, NULL));
+ }
+ } else {
const uint8_t *digest;
+ printk(KERN_DEBUG "TPM: Clearing\n");
+ RETURN_ON_FAILURE(tlcl_assert_physical_presence());
+ RETURN_ON_FAILURE(tlcl_force_clear());
+
+ RETURN_ON_FAILURE(tlcl_set_enable());
+ RETURN_ON_FAILURE(tlcl_set_deactivated(0));
+
if (get_secure_boot_mode() == SECURE) {
- digest = bootmode_digests[SHA1_SECURE_BOOT];
+ digest = bootmode_digests[SHA1_RECOVERY_MODE_SECURE];
} else {
- digest = bootmode_digests[SHA1_NON_SECURE_BOOT];
+ digest = bootmode_digests[SHA1_RECOVERY_MODE_NON_SECURE];
}
RETURN_ON_FAILURE(tlcl_extend(0, digest, NULL));