1/* Copyright (c) 2010 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
6/* This program mimicks the TPM usage from read-only firmware.  It exercises
7 * the TPM functionality needed in the read-only firmware.  It is meant to be
8 * integrated with the rest of the read-only firmware.  It is also provided as
9 * a test.
10 */
11
12#include <stdio.h>
13#include <stdint.h>
14#include <stdlib.h>
15
16#include "tlcl.h"
17#include "utility.h"
18
19/* These index values are used to create NVRAM spaces.  They only need to be
20 * unique.
21 */
22#define INDEX0 0xda70
23#define INDEX1 0xda71
24#define INDEX2 0xda72
25#define INDEX3 0xda73
26
27#define INDEX_INITIALIZED 0xda80
28
29/* This is called once at initialization time.  It may be called again from
30 * recovery mode to rebuild the spaces if something incomprehensible happened
31 * and the spaces are gone or messed up.  This is called after TPM_Startup and
32 * before the spaces are write-locked, so there is a chance that they can be
33 * recreated (but who knows---if anything can happen, there are plenty of ways
34 * of making this FUBAR).
35 */
36void InitializeSpaces(void) {
37  uint32_t zero = 0;
38  uint32_t perm = TPM_NV_PER_WRITE_STCLEAR | TPM_NV_PER_PPWRITE;
39
40  printf("Initializing spaces\n");
41  TlclSetNvLocked();  /* useful only the first time */
42
43  TlclDefineSpace(INDEX0, perm, 4);
44  TlclWrite(INDEX0, (uint8_t *) &zero, 4);
45  TlclDefineSpace(INDEX1, perm, 4);
46  TlclWrite(INDEX1, (uint8_t *) &zero, 4);
47  TlclDefineSpace(INDEX2, perm, 4);
48  TlclWrite(INDEX2, (uint8_t *) &zero, 4);
49  TlclDefineSpace(INDEX3, perm, 4);
50  TlclWrite(INDEX3, (uint8_t *) &zero, 4);
51
52  perm = TPM_NV_PER_READ_STCLEAR | TPM_NV_PER_WRITE_STCLEAR |
53    TPM_NV_PER_PPWRITE;
54  TlclDefineSpace(INDEX_INITIALIZED, perm, 1);
55}
56
57
58void EnterRecoveryMode(void) {
59  printf("entering recovery mode");
60  exit(0);
61}
62
63
64int main(int argc, char** argv) {
65  uint8_t c;
66  uint32_t index_0, index_1, index_2, index_3;
67
68  TlclLibInit();
69
70  TlclStartup();
71  TlclSelfTestFull();
72
73  TlclAssertPhysicalPresence();
74
75  /* Checks if initialization has completed by trying to read-lock a space
76   * that's created at the end of initialization.
77   */
78  if (TlclRead(INDEX_INITIALIZED, &c, 0) == TPM_E_BADINDEX) {
79    /* The initialization did not complete.
80     */
81    InitializeSpaces();
82  }
83
84  /* Checks if spaces are OK or messed up.
85   */
86  if (TlclRead(INDEX0, (uint8_t*) &index_0, sizeof(index_0)) != TPM_SUCCESS ||
87      TlclRead(INDEX1, (uint8_t*) &index_1, sizeof(index_1)) != TPM_SUCCESS ||
88      TlclRead(INDEX2, (uint8_t*) &index_2, sizeof(index_2)) != TPM_SUCCESS ||
89      TlclRead(INDEX3, (uint8_t*) &index_3, sizeof(index_3)) != TPM_SUCCESS) {
90    EnterRecoveryMode();
91  }
92
93  /* Writes space, and locks it.  Then attempts to write again.  I really wish
94   * I could use the imperative.
95   */
96  index_0 += 1;
97  if (TlclWrite(INDEX0, (uint8_t*) &index_0, sizeof(index_0) != TPM_SUCCESS)) {
98    error("could not write index 0\n");
99  }
100  TlclWriteLock(INDEX0);
101  if (TlclWrite(INDEX0, (uint8_t*) &index_0, sizeof(index_0)) == TPM_SUCCESS) {
102    error("index 0 is not locked\n");
103  }
104
105  /* Done for now.
106   */
107  printf("TEST SUCCEEDED\n");
108  exit(0);
109}
110