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 */
26uint32_t ReadSpaceFirmware(RollbackSpaceFirmware *rsf);
27uint32_t WriteSpaceFirmware(RollbackSpaceFirmware *rsf);
28uint32_t ReadSpaceKernel(RollbackSpaceKernel *rsk);
29uint32_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
51uint32_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
61uint32_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
72uint32_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. */
84uint32_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
124uint32_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
155uint32_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
181uint32_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
219uint32_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
250uint32_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 */
351uint32_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
488uint32_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
501uint32_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
520uint32_t RollbackFirmwareWrite(uint32_t version)
521{
522	return TPM_SUCCESS;
523}
524
525uint32_t RollbackFirmwareLock(void)
526{
527	return TPM_SUCCESS;
528}
529
530uint32_t RollbackKernelRead(uint32_t* version)
531{
532	*version = 0;
533	return TPM_SUCCESS;
534}
535
536uint32_t RollbackKernelWrite(uint32_t version)
537{
538	return TPM_SUCCESS;
539}
540
541uint32_t RollbackBackupRead(uint8_t *raw)
542{
543	return TPM_SUCCESS;
544}
545
546uint32_t RollbackBackupWrite(uint8_t *raw)
547{
548	return TPM_SUCCESS;
549}
550
551uint32_t RollbackKernelLock(int recovery_mode)
552{
553	return TPM_SUCCESS;
554}
555
556#else
557
558uint32_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
573uint32_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
591uint32_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
604uint32_t RollbackFirmwareLock(void)
605{
606	return TlclSetGlobalLock();
607}
608
609uint32_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
633uint32_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 */
652uint32_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
660uint32_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
668uint32_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