Home | History | Annotate | Download | only in lib
      1 /* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
      2  * Use of this source code is governed by a BSD-style license that can be
      3  * found in the LICENSE file.
      4  *
      5  * Functions for querying, manipulating and locking rollback indices
      6  * stored in the TPM NVRAM.
      7  */
      8 
      9 #include "sysincludes.h"
     10 
     11 #include "crc8.h"
     12 #include "rollback_index.h"
     13 #include "tlcl.h"
     14 #include "tss_constants.h"
     15 #include "utility.h"
     16 #include "vboot_api.h"
     17 
     18 #ifndef offsetof
     19 #define offsetof(A,B) __builtin_offsetof(A,B)
     20 #endif
     21 
     22 /*
     23  * Provide protoypes for functions not in the header file. These prototypes
     24  * fix -Wmissing-prototypes warnings.
     25  */
     26 uint32_t ReadSpaceFirmware(RollbackSpaceFirmware *rsf);
     27 uint32_t WriteSpaceFirmware(RollbackSpaceFirmware *rsf);
     28 uint32_t ReadSpaceKernel(RollbackSpaceKernel *rsk);
     29 uint32_t WriteSpaceKernel(RollbackSpaceKernel *rsk);
     30 
     31 #ifdef FOR_TEST
     32 /*
     33  * Compiling for unit test, so we need the real implementations of
     34  * rollback functions.  The unit test mocks the underlying tlcl
     35  * functions, so this is ok to run on the host.
     36  */
     37 #undef CHROMEOS_ENVIRONMENT
     38 #undef DISABLE_ROLLBACK_TPM
     39 #endif
     40 
     41 #define RETURN_ON_FAILURE(tpm_command) do {				\
     42 		uint32_t result_;					\
     43 		if ((result_ = (tpm_command)) != TPM_SUCCESS) {		\
     44 			VBDEBUG(("Rollback: %08x returned by " #tpm_command \
     45 				 "\n", (int)result_));			\
     46 			return result_;					\
     47 		}							\
     48 	} while (0)
     49 
     50 
     51 uint32_t TPMClearAndReenable(void)
     52 {
     53 	VBDEBUG(("TPM: Clear and re-enable\n"));
     54 	RETURN_ON_FAILURE(TlclForceClear());
     55 	RETURN_ON_FAILURE(TlclSetEnable());
     56 	RETURN_ON_FAILURE(TlclSetDeactivated(0));
     57 
     58 	return TPM_SUCCESS;
     59 }
     60 
     61 uint32_t SafeWrite(uint32_t index, const void *data, uint32_t length)
     62 {
     63 	uint32_t result = TlclWrite(index, data, length);
     64 	if (result == TPM_E_MAXNVWRITES) {
     65 		RETURN_ON_FAILURE(TPMClearAndReenable());
     66 		return TlclWrite(index, data, length);
     67 	} else {
     68 		return result;
     69 	}
     70 }
     71 
     72 uint32_t SafeDefineSpace(uint32_t index, uint32_t perm, uint32_t size)
     73 {
     74 	uint32_t result = TlclDefineSpace(index, perm, size);
     75 	if (result == TPM_E_MAXNVWRITES) {
     76 		RETURN_ON_FAILURE(TPMClearAndReenable());
     77 		return TlclDefineSpace(index, perm, size);
     78 	} else {
     79 		return result;
     80 	}
     81 }
     82 
     83 /* Functions to read and write firmware and kernel spaces. */
     84 uint32_t ReadSpaceFirmware(RollbackSpaceFirmware *rsf)
     85 {
     86 	uint32_t r;
     87 	int attempts = 3;
     88 
     89 	while (attempts--) {
     90 		r = TlclRead(FIRMWARE_NV_INDEX, rsf,
     91 			     sizeof(RollbackSpaceFirmware));
     92 		if (r != TPM_SUCCESS)
     93 			return r;
     94 
     95 		/*
     96 		 * No CRC in this version, so we'll create one when we write
     97 		 * it. Note that we're marking this as version 2, not
     98 		 * ROLLBACK_SPACE_FIRMWARE_VERSION, because version 2 just
     99 		 * added the CRC. Later versions will need to set default
    100 		 * values for any extra fields explicitly (probably here).
    101 		 */
    102 		if (rsf->struct_version < 2) {
    103 			/* Danger Will Robinson! Danger! */
    104 			rsf->struct_version = 2;
    105 			return TPM_SUCCESS;
    106 		}
    107 
    108 		/*
    109 		 * If the CRC is good, we're done. If it's bad, try a couple
    110 		 * more times to see if it gets better before we give up. It
    111 		 * could just be noise.
    112 		 */
    113 		if (rsf->crc8 == Crc8(rsf,
    114 				      offsetof(RollbackSpaceFirmware, crc8)))
    115 			return TPM_SUCCESS;
    116 
    117 		VBDEBUG(("TPM: %s() - bad CRC\n", __func__));
    118 	}
    119 
    120 	VBDEBUG(("TPM: %s() - too many bad CRCs, giving up\n", __func__));
    121 	return TPM_E_CORRUPTED_STATE;
    122 }
    123 
    124 uint32_t WriteSpaceFirmware(RollbackSpaceFirmware *rsf)
    125 {
    126 	RollbackSpaceFirmware rsf2;
    127 	uint32_t r;
    128 	int attempts = 3;
    129 
    130 	/* All writes should use struct_version 2 or greater. */
    131 	if (rsf->struct_version < 2)
    132 		rsf->struct_version = 2;
    133 	rsf->crc8 = Crc8(rsf, offsetof(RollbackSpaceFirmware, crc8));
    134 
    135 	while (attempts--) {
    136 		r = SafeWrite(FIRMWARE_NV_INDEX, rsf,
    137 			      sizeof(RollbackSpaceFirmware));
    138 		/* Can't write, not gonna try again */
    139 		if (r != TPM_SUCCESS)
    140 			return r;
    141 
    142 		/* Read it back to be sure it got the right values. */
    143 		r = ReadSpaceFirmware(&rsf2);    /* This checks the CRC */
    144 		if (r == TPM_SUCCESS)
    145 			return r;
    146 
    147 		VBDEBUG(("TPM: %s() - bad CRC\n", __func__));
    148 		/* Try writing it again. Maybe it was garbled on the way out. */
    149 	}
    150 
    151 	VBDEBUG(("TPM: %s() - too many bad CRCs, giving up\n", __func__));
    152 	return TPM_E_CORRUPTED_STATE;
    153 }
    154 
    155 uint32_t SetVirtualDevMode(int val)
    156 {
    157 	RollbackSpaceFirmware rsf;
    158 
    159 	VBDEBUG(("TPM: Entering %s()\n", __func__));
    160 	if (TPM_SUCCESS != ReadSpaceFirmware(&rsf))
    161 		return VBERROR_TPM_FIRMWARE_SETUP;
    162 
    163 	VBDEBUG(("TPM: flags were 0x%02x\n", rsf.flags));
    164 	if (val)
    165 		rsf.flags |= FLAG_VIRTUAL_DEV_MODE_ON;
    166 	else
    167 		rsf.flags &= ~FLAG_VIRTUAL_DEV_MODE_ON;
    168 	/*
    169 	 * NOTE: This doesn't update the FLAG_LAST_BOOT_DEVELOPER bit.  That
    170 	 * will be done by SetupTPM() on the next boot.
    171 	 */
    172 	VBDEBUG(("TPM: flags are now 0x%02x\n", rsf.flags));
    173 
    174 	if (TPM_SUCCESS != WriteSpaceFirmware(&rsf))
    175 		return VBERROR_TPM_SET_BOOT_MODE_STATE;
    176 
    177 	VBDEBUG(("TPM: Leaving %s()\n", __func__));
    178 	return VBERROR_SUCCESS;
    179 }
    180 
    181 uint32_t ReadSpaceKernel(RollbackSpaceKernel *rsk)
    182 {
    183 	uint32_t r;
    184 	int attempts = 3;
    185 
    186 	while (attempts--) {
    187 		r = TlclRead(KERNEL_NV_INDEX, rsk, sizeof(RollbackSpaceKernel));
    188 		if (r != TPM_SUCCESS)
    189 			return r;
    190 
    191 		/*
    192 		 * No CRC in this version, so we'll create one when we write
    193 		 * it. Note that we're marking this as version 2, not
    194 		 * ROLLBACK_SPACE_KERNEL_VERSION, because version 2 just added
    195 		 * the CRC. Later versions will need to set default values for
    196 		 * any extra fields explicitly (probably here).
    197 		 */
    198 		if (rsk->struct_version < 2) {
    199 			/* Danger Will Robinson! Danger! */
    200 			rsk->struct_version = 2;
    201 			return TPM_SUCCESS;
    202 		}
    203 
    204 		/*
    205 		 * If the CRC is good, we're done. If it's bad, try a couple
    206 		 * more times to see if it gets better before we give up. It
    207 		 * could just be noise.
    208 		 */
    209 		if (rsk->crc8 == Crc8(rsk, offsetof(RollbackSpaceKernel, crc8)))
    210 			return TPM_SUCCESS;
    211 
    212 		VBDEBUG(("TPM: %s() - bad CRC\n", __func__));
    213 	}
    214 
    215 	VBDEBUG(("TPM: %s() - too many bad CRCs, giving up\n", __func__));
    216 	return TPM_E_CORRUPTED_STATE;
    217 }
    218 
    219 uint32_t WriteSpaceKernel(RollbackSpaceKernel *rsk)
    220 {
    221 	RollbackSpaceKernel rsk2;
    222 	uint32_t r;
    223 	int attempts = 3;
    224 
    225 	/* All writes should use struct_version 2 or greater. */
    226 	if (rsk->struct_version < 2)
    227 		rsk->struct_version = 2;
    228 	rsk->crc8 = Crc8(rsk, offsetof(RollbackSpaceKernel, crc8));
    229 
    230 	while (attempts--) {
    231 		r = SafeWrite(KERNEL_NV_INDEX, rsk,
    232 			      sizeof(RollbackSpaceKernel));
    233 		/* Can't write, not gonna try again */
    234 		if (r != TPM_SUCCESS)
    235 			return r;
    236 
    237 		/* Read it back to be sure it got the right values. */
    238 		r = ReadSpaceKernel(&rsk2);    /* This checks the CRC */
    239 		if (r == TPM_SUCCESS)
    240 			return r;
    241 
    242 		VBDEBUG(("TPM: %s() - bad CRC\n", __func__));
    243 		/* Try writing it again. Maybe it was garbled on the way out. */
    244 	}
    245 
    246 	VBDEBUG(("TPM: %s() - too many bad CRCs, giving up\n", __func__));
    247 	return TPM_E_CORRUPTED_STATE;
    248 }
    249 
    250 uint32_t OneTimeInitializeTPM(RollbackSpaceFirmware *rsf,
    251                               RollbackSpaceKernel *rsk)
    252 {
    253 	static const RollbackSpaceFirmware rsf_init = {
    254 		.struct_version = ROLLBACK_SPACE_FIRMWARE_VERSION,
    255 	};
    256 	static const RollbackSpaceKernel rsk_init = {
    257 		.struct_version = ROLLBACK_SPACE_KERNEL_VERSION,
    258 		.uid = ROLLBACK_SPACE_KERNEL_UID,
    259 	};
    260 	TPM_PERMANENT_FLAGS pflags;
    261 	uint32_t result;
    262 
    263 	VBDEBUG(("TPM: One-time initialization\n"));
    264 
    265 	/*
    266 	 * Do a full test.  This only happens the first time the device is
    267 	 * turned on in the factory, so performance is not an issue.  This is
    268 	 * almost certainly not necessary, but it gives us more confidence
    269 	 * about some code paths below that are difficult to
    270 	 * test---specifically the ones that set lifetime flags, and are only
    271 	 * executed once per physical TPM.
    272 	 */
    273 	result = TlclSelfTestFull();
    274 	if (result != TPM_SUCCESS)
    275 		return result;
    276 
    277 	result = TlclGetPermanentFlags(&pflags);
    278 	if (result != TPM_SUCCESS)
    279 		return result;
    280 
    281 	/*
    282 	 * TPM may come from the factory without physical presence finalized.
    283 	 * Fix if necessary.
    284 	 */
    285 	VBDEBUG(("TPM: physicalPresenceLifetimeLock=%d\n",
    286 		 pflags.physicalPresenceLifetimeLock));
    287 	if (!pflags.physicalPresenceLifetimeLock) {
    288 		VBDEBUG(("TPM: Finalizing physical presence\n"));
    289 		RETURN_ON_FAILURE(TlclFinalizePhysicalPresence());
    290 	}
    291 
    292 	/*
    293 	 * The TPM will not enforce the NV authorization restrictions until the
    294 	 * execution of a TPM_NV_DefineSpace with the handle of
    295 	 * TPM_NV_INDEX_LOCK.  Here we create that space if it doesn't already
    296 	 * exist. */
    297 	VBDEBUG(("TPM: nvLocked=%d\n", pflags.nvLocked));
    298 	if (!pflags.nvLocked) {
    299 		VBDEBUG(("TPM: Enabling NV locking\n"));
    300 		RETURN_ON_FAILURE(TlclSetNvLocked());
    301 	}
    302 
    303 	/* Clear TPM owner, in case the TPM is already owned for some reason. */
    304 	VBDEBUG(("TPM: Clearing owner\n"));
    305 	RETURN_ON_FAILURE(TPMClearAndReenable());
    306 
    307 	/* Initializes the firmware and kernel spaces */
    308 	Memcpy(rsf, &rsf_init, sizeof(RollbackSpaceFirmware));
    309 	Memcpy(rsk, &rsk_init, sizeof(RollbackSpaceKernel));
    310 
    311 	/* Define the backup space. No need to initialize it, though. */
    312 	RETURN_ON_FAILURE(SafeDefineSpace(
    313 			BACKUP_NV_INDEX, TPM_NV_PER_PPWRITE, BACKUP_NV_SIZE));
    314 
    315 	/* Define and initialize the kernel space */
    316 	RETURN_ON_FAILURE(SafeDefineSpace(KERNEL_NV_INDEX, TPM_NV_PER_PPWRITE,
    317 					  sizeof(RollbackSpaceKernel)));
    318 	RETURN_ON_FAILURE(WriteSpaceKernel(rsk));
    319 
    320 	/* Do the firmware space last, so we retry if we don't get this far. */
    321 	RETURN_ON_FAILURE(SafeDefineSpace(
    322 			FIRMWARE_NV_INDEX,
    323 			TPM_NV_PER_GLOBALLOCK | TPM_NV_PER_PPWRITE,
    324 			sizeof(RollbackSpaceFirmware)));
    325 	RETURN_ON_FAILURE(WriteSpaceFirmware(rsf));
    326 
    327 	return TPM_SUCCESS;
    328 }
    329 
    330 
    331 /*
    332  * SetupTPM starts the TPM and establishes the root of trust for the
    333  * anti-rollback mechanism.  SetupTPM can fail for three reasons.  1 A bug. 2 a
    334  * TPM hardware failure. 3 An unexpected TPM state due to some attack.  In
    335  * general we cannot easily distinguish the kind of failure, so our strategy is
    336  * to reboot in recovery mode in all cases.  The recovery mode calls SetupTPM
    337  * again, which executes (almost) the same sequence of operations.  There is a
    338  * good chance that, if recovery mode was entered because of a TPM failure, the
    339  * failure will repeat itself.  (In general this is impossible to guarantee
    340  * because we have no way of creating the exact TPM initial state at the
    341  * previous boot.)  In recovery mode, we ignore the failure and continue, thus
    342  * giving the recovery kernel a chance to fix things (that's why we don't set
    343  * bGlobalLock).  The choice is between a knowingly insecure device and a
    344  * bricked device.
    345  *
    346  * As a side note, observe that we go through considerable hoops to avoid using
    347  * the STCLEAR permissions for the index spaces.  We do this to avoid writing
    348  * to the TPM flashram at every reboot or wake-up, because of concerns about
    349  * the durability of the NVRAM.
    350  */
    351 uint32_t SetupTPM(int developer_mode, int disable_dev_request,
    352                   int clear_tpm_owner_request, RollbackSpaceFirmware* rsf)
    353 {
    354 	uint8_t in_flags;
    355 	uint8_t disable;
    356 	uint8_t deactivated;
    357 	uint32_t result;
    358 	uint32_t versions;
    359 
    360 	RETURN_ON_FAILURE(TlclLibInit());
    361 
    362 #ifdef TEGRA_SOFT_REBOOT_WORKAROUND
    363 	result = TlclStartup();
    364 	if (result == TPM_E_INVALID_POSTINIT) {
    365 		/*
    366 		 * Some prototype hardware doesn't reset the TPM on a CPU
    367 		 * reset.  We do a hard reset to get around this.
    368 		 */
    369 		VBDEBUG(("TPM: soft reset detected\n", result));
    370 		return TPM_E_MUST_REBOOT;
    371 	} else if (result != TPM_SUCCESS) {
    372 		VBDEBUG(("TPM: TlclStartup returned %08x\n", result));
    373 		return result;
    374 	}
    375 #else
    376 	RETURN_ON_FAILURE(TlclStartup());
    377 #endif
    378 
    379   /*
    380    * Some TPMs start the self test automatically at power on.  In that case we
    381    * don't need to call ContinueSelfTest.  On some (other) TPMs,
    382    * ContinueSelfTest may block.  In that case, we definitely don't want to
    383    * call it here.  For TPMs in the intersection of these two sets, we're
    384    * screwed.  (In other words: TPMs that require manually starting the
    385    * self-test AND block will have poor performance until we split
    386    * TlclSendReceive() into Send() and Receive(), and have a state machine to
    387    * control setup.)
    388    *
    389    * This comment is likely to become obsolete in the near future, so don't
    390    * trust it.  It may have not been updated.
    391    */
    392 #ifdef TPM_MANUAL_SELFTEST
    393 #ifdef TPM_BLOCKING_CONTINUESELFTEST
    394 #warning "lousy TPM!"
    395 #endif
    396 	RETURN_ON_FAILURE(TlclContinueSelfTest());
    397 #endif
    398 	result = TlclAssertPhysicalPresence();
    399 	if (result != TPM_SUCCESS) {
    400 		/*
    401 		 * It is possible that the TPM was delivered with the physical
    402 		 * presence command disabled.  This tries enabling it, then
    403 		 * tries asserting PP again.
    404 		 */
    405 		RETURN_ON_FAILURE(TlclPhysicalPresenceCMDEnable());
    406 		RETURN_ON_FAILURE(TlclAssertPhysicalPresence());
    407 	}
    408 
    409 	/* Check that the TPM is enabled and activated. */
    410 	RETURN_ON_FAILURE(TlclGetFlags(&disable, &deactivated, NULL));
    411 	if (disable || deactivated) {
    412 		VBDEBUG(("TPM: disabled (%d) or deactivated (%d).  Fixing...\n",
    413 			 disable, deactivated));
    414 		RETURN_ON_FAILURE(TlclSetEnable());
    415 		RETURN_ON_FAILURE(TlclSetDeactivated(0));
    416 		VBDEBUG(("TPM: Must reboot to re-enable\n"));
    417 		return TPM_E_MUST_REBOOT;
    418 	}
    419 
    420 	/* Read the firmware space. */
    421 	result = ReadSpaceFirmware(rsf);
    422 	if (TPM_E_BADINDEX == result) {
    423 		RollbackSpaceKernel rsk;
    424 
    425 		/*
    426 		 * This is the first time we've run, and the TPM has not been
    427 		 * initialized.  Initialize it.
    428 		 */
    429 		VBDEBUG(("TPM: Not initialized yet.\n"));
    430 		RETURN_ON_FAILURE(OneTimeInitializeTPM(rsf, &rsk));
    431 	} else if (TPM_SUCCESS != result) {
    432 		VBDEBUG(("TPM: Firmware space in a bad state; giving up.\n"));
    433 		return TPM_E_CORRUPTED_STATE;
    434 	}
    435 	Memcpy(&versions, &rsf->fw_versions, sizeof(versions));
    436 	VBDEBUG(("TPM: Firmware space sv%d f%x v%x\n",
    437 		 rsf->struct_version, rsf->flags, versions));
    438 	in_flags = rsf->flags;
    439 
    440 	/* If we've been asked to clear the virtual dev-mode flag, do so now */
    441 	if (disable_dev_request) {
    442 		rsf->flags &= ~FLAG_VIRTUAL_DEV_MODE_ON;
    443 		VBDEBUG(("TPM: Clearing virt dev-switch: f%x\n", rsf->flags));
    444 	}
    445 
    446 	/*
    447 	 * The developer_mode value that's passed in is only set by a hardware
    448 	 * dev-switch. We should OR it with the virtual switch, whether or not
    449 	 * the virtual switch is used. If it's not used, it shouldn't change,
    450 	 * so it doesn't matter.
    451 	 */
    452 	if (rsf->flags & FLAG_VIRTUAL_DEV_MODE_ON)
    453 		developer_mode = 1;
    454 
    455 	/*
    456 	 * Clear ownership if developer flag has toggled, or if an owner-clear
    457 	 * has been requested.
    458 	 */
    459 	if ((developer_mode ? FLAG_LAST_BOOT_DEVELOPER : 0) !=
    460 	    (in_flags & FLAG_LAST_BOOT_DEVELOPER)) {
    461 		VBDEBUG(("TPM: Developer flag changed; clearing owner.\n"));
    462 		RETURN_ON_FAILURE(TPMClearAndReenable());
    463 	} else if (clear_tpm_owner_request) {
    464 		VBDEBUG(("TPM: Clearing owner as specifically requested.\n"));
    465 		RETURN_ON_FAILURE(TPMClearAndReenable());
    466 	}
    467 
    468 	if (developer_mode)
    469 		rsf->flags |= FLAG_LAST_BOOT_DEVELOPER;
    470 	else
    471 		rsf->flags &= ~FLAG_LAST_BOOT_DEVELOPER;
    472 
    473 
    474 	/* If firmware space is dirty, flush it back to the TPM */
    475 	if (rsf->flags != in_flags) {
    476 		VBDEBUG(("TPM: Updating firmware space.\n"));
    477 		RETURN_ON_FAILURE(WriteSpaceFirmware(rsf));
    478 	}
    479 
    480 	VBDEBUG(("TPM: SetupTPM() succeeded\n"));
    481 	return TPM_SUCCESS;
    482 }
    483 
    484 
    485 #ifdef DISABLE_ROLLBACK_TPM
    486 /* Dummy implementations which don't support TPM rollback protection */
    487 
    488 uint32_t RollbackS3Resume(void)
    489 {
    490 #ifndef CHROMEOS_ENVIRONMENT
    491 	/*
    492 	 * Initialize the TPM, but ignore return codes.  In ChromeOS
    493 	 * environment, don't even talk to the TPM.
    494 	 */
    495 	TlclLibInit();
    496 	TlclResume();
    497 #endif
    498 	return TPM_SUCCESS;
    499 }
    500 
    501 uint32_t RollbackFirmwareSetup(int is_hw_dev,
    502                                int disable_dev_request,
    503                                int clear_tpm_owner_request,
    504                                int *is_virt_dev, uint32_t *version)
    505 {
    506 #ifndef CHROMEOS_ENVIRONMENT
    507 	/*
    508 	 * Initialize the TPM, but ignores return codes.  In ChromeOS
    509 	 * environment, don't even talk to the TPM.
    510 	 */
    511 	TlclLibInit();
    512 	TlclStartup();
    513 	TlclContinueSelfTest();
    514 #endif
    515 	*is_virt_dev = 0;
    516 	*version = 0;
    517 	return TPM_SUCCESS;
    518 }
    519 
    520 uint32_t RollbackFirmwareWrite(uint32_t version)
    521 {
    522 	return TPM_SUCCESS;
    523 }
    524 
    525 uint32_t RollbackFirmwareLock(void)
    526 {
    527 	return TPM_SUCCESS;
    528 }
    529 
    530 uint32_t RollbackKernelRead(uint32_t* version)
    531 {
    532 	*version = 0;
    533 	return TPM_SUCCESS;
    534 }
    535 
    536 uint32_t RollbackKernelWrite(uint32_t version)
    537 {
    538 	return TPM_SUCCESS;
    539 }
    540 
    541 uint32_t RollbackBackupRead(uint8_t *raw)
    542 {
    543 	return TPM_SUCCESS;
    544 }
    545 
    546 uint32_t RollbackBackupWrite(uint8_t *raw)
    547 {
    548 	return TPM_SUCCESS;
    549 }
    550 
    551 uint32_t RollbackKernelLock(int recovery_mode)
    552 {
    553 	return TPM_SUCCESS;
    554 }
    555 
    556 #else
    557 
    558 uint32_t RollbackS3Resume(void)
    559 {
    560 	uint32_t result;
    561 	RETURN_ON_FAILURE(TlclLibInit());
    562 	result = TlclResume();
    563 	if (result == TPM_E_INVALID_POSTINIT) {
    564 		/*
    565 		 * We're on a platform where the TPM maintains power in S3, so
    566 		 * it's already initialized.
    567 		 */
    568 		return TPM_SUCCESS;
    569 	}
    570 	return result;
    571 }
    572 
    573 uint32_t RollbackFirmwareSetup(int is_hw_dev,
    574                                int disable_dev_request,
    575                                int clear_tpm_owner_request,
    576                                int *is_virt_dev, uint32_t *version)
    577 {
    578 	RollbackSpaceFirmware rsf;
    579 
    580 	/* Set version to 0 in case we fail */
    581 	*version = 0;
    582 
    583 	RETURN_ON_FAILURE(SetupTPM(is_hw_dev, disable_dev_request,
    584 				   clear_tpm_owner_request, &rsf));
    585 	Memcpy(version, &rsf.fw_versions, sizeof(*version));
    586 	*is_virt_dev = (rsf.flags & FLAG_VIRTUAL_DEV_MODE_ON) ? 1 : 0;
    587 	VBDEBUG(("TPM: RollbackFirmwareSetup %x\n", (int)*version));
    588 	return TPM_SUCCESS;
    589 }
    590 
    591 uint32_t RollbackFirmwareWrite(uint32_t version)
    592 {
    593 	RollbackSpaceFirmware rsf;
    594 	uint32_t old_version;
    595 
    596 	RETURN_ON_FAILURE(ReadSpaceFirmware(&rsf));
    597 	Memcpy(&old_version, &rsf.fw_versions, sizeof(old_version));
    598 	VBDEBUG(("TPM: RollbackFirmwareWrite %x --> %x\n", (int)old_version,
    599 		 (int)version));
    600 	Memcpy(&rsf.fw_versions, &version, sizeof(version));
    601 	return WriteSpaceFirmware(&rsf);
    602 }
    603 
    604 uint32_t RollbackFirmwareLock(void)
    605 {
    606 	return TlclSetGlobalLock();
    607 }
    608 
    609 uint32_t RollbackKernelRead(uint32_t* version)
    610 {
    611 	RollbackSpaceKernel rsk;
    612 	uint32_t perms, uid;
    613 
    614 	/*
    615 	 * Read the kernel space and verify its permissions.  If the kernel
    616 	 * space has the wrong permission, or it doesn't contain the right
    617 	 * identifier, we give up.  This will need to be fixed by the
    618 	 * recovery kernel.  We have to worry about this because at any time
    619 	 * (even with PP turned off) the TPM owner can remove and redefine a
    620 	 * PP-protected space (but not write to it).
    621 	 */
    622 	RETURN_ON_FAILURE(ReadSpaceKernel(&rsk));
    623 	RETURN_ON_FAILURE(TlclGetPermissions(KERNEL_NV_INDEX, &perms));
    624 	Memcpy(&uid, &rsk.uid, sizeof(uid));
    625 	if (TPM_NV_PER_PPWRITE != perms || ROLLBACK_SPACE_KERNEL_UID != uid)
    626 		return TPM_E_CORRUPTED_STATE;
    627 
    628 	Memcpy(version, &rsk.kernel_versions, sizeof(*version));
    629 	VBDEBUG(("TPM: RollbackKernelRead %x\n", (int)*version));
    630 	return TPM_SUCCESS;
    631 }
    632 
    633 uint32_t RollbackKernelWrite(uint32_t version)
    634 {
    635 	RollbackSpaceKernel rsk;
    636 	uint32_t old_version;
    637 	RETURN_ON_FAILURE(ReadSpaceKernel(&rsk));
    638 	Memcpy(&old_version, &rsk.kernel_versions, sizeof(old_version));
    639 	VBDEBUG(("TPM: RollbackKernelWrite %x --> %x\n",
    640 		 (int)old_version, (int)version));
    641 	Memcpy(&rsk.kernel_versions, &version, sizeof(version));
    642 	return WriteSpaceKernel(&rsk);
    643 }
    644 
    645 /*
    646  * We don't really care whether the TPM owner has been messing with this or
    647  * not. We lock it along with the Kernel space just to avoid problems, but it's
    648  * only useful in dev-mode and only when the battery has been drained
    649  * completely. There aren't any security issues. It's just in the TPM because
    650  * we don't have any other place to keep it.
    651  */
    652 uint32_t RollbackBackupRead(uint8_t *raw)
    653 {
    654 	uint32_t r;
    655 	r = TlclRead(BACKUP_NV_INDEX, raw, BACKUP_NV_SIZE);
    656 	VBDEBUG(("TPM: %s returning 0x%x\n", __func__, r));
    657 	return r;
    658 }
    659 
    660 uint32_t RollbackBackupWrite(uint8_t *raw)
    661 {
    662 	uint32_t r;
    663 	r = TlclWrite(BACKUP_NV_INDEX, raw, BACKUP_NV_SIZE);
    664 	VBDEBUG(("TPM: %s returning 0x%x\n", __func__, r));
    665 	return r;
    666 }
    667 
    668 uint32_t RollbackKernelLock(int recovery_mode)
    669 {
    670 	if (recovery_mode)
    671 		return TPM_SUCCESS;
    672 	else
    673 		return TlclLockPhysicalPresence();
    674 }
    675 
    676 #endif /* DISABLE_ROLLBACK_TPM */
    677