1 /* Microsoft Reference Implementation for TPM 2.0
2 *
3 * The copyright in this software is being made available under the BSD License,
4 * included below. This software may be subject to other third party and
5 * contributor rights, including patent rights, and no such rights are granted
6 * under this license.
7 *
8 * Copyright (c) Microsoft Corporation
9 *
10 * All rights reserved.
11 *
12 * BSD License
13 *
14 * Redistribution and use in source and binary forms, with or without modification,
15 * are permitted provided that the following conditions are met:
16 *
17 * Redistributions of source code must retain the above copyright notice, this list
18 * of conditions and the following disclaimer.
19 *
20 * Redistributions in binary form must reproduce the above copyright notice, this
21 * list of conditions and the following disclaimer in the documentation and/or
22 * other materials provided with the distribution.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ""AS IS""
25 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
28 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
31 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 */
35 //** Introduction
36
37 // The NV memory is divided into two areas: dynamic space for user defined NV
38 // Indices and evict objects, and reserved space for TPM persistent and state save
39 // data.
40 //
41 // The entries in dynamic space are a linked list of entries. Each entry has, as its
42 // first field, a size. If the size field is zero, it marks the end of the
43 // list.
44 //
45 // An allocation of an Index or evict object may use almost all of the remaining
46 // NV space such that the size field will not fit. The functions that search the
47 // list are aware of this and will terminate the search if they either find a zero
48 // size or recognize that there is insufficient space for the size field.
49 //
50 // An Index allocation will contain an NV_INDEX structure. If the Index does not
51 // have the orderly attribute, the NV_INDEX is followed immediately by the NV data.
52 //
53 // An evict object entry contains a handle followed by an OBJECT structure. This
54 // results in both the Index and Evict Object having an identifying handle as the
55 // first field following the size field.
56 //
57 // When an Index has the orderly attribute, the data is kept in RAM. This RAM is
58 // saved to backing store in NV memory on any orderly shutdown. The entries in
59 // orderly memory are also a linked list using a size field as the first entry. As
60 // with the NV memory, the list is terminated by a zero size field or when the last
61 // entry leaves insufficient space for the terminating size field.
62 //
63 // The attributes of an orderly index are maintained in RAM memory in order to
64 // reduce the number of NV writes needed for orderly data. When an orderly index
65 // is created, an entry is made in the dynamic NV memory space that holds the Index
66 // authorizations (authPolicy and authValue) and the size of the data. This entry is
67 // only modified if the authValue of the index is changed. The more volatile data
68 // of the index is kept in RAM. When an orderly Index is created or deleted, the
69 // RAM data is copied to NV backing store so that the image in the backing store
70 // matches the layout of RAM. In normal operation. The RAM data is also copied on
71 // any orderly shutdown. In normal operation, the only other reason for writing
72 // to the backing store for RAM is when a counter is first written (TPMA_NV_WRITTEN
73 // changes from CLEAR to SET) or when a counter "rolls over."
74 //
75 // Static space contains items that are individually modifiable. The values are in
76 // the 'gp' PERSISTENT_DATA structure in RAM and mapped to locations in NV.
77 //
78
79 //** Includes, Defines
80 #define NV_C
81 #include "Tpm.h"
82
83 //************************************************
84 //** Functions
85 //************************************************
86
87
88 //*** NvInitStatic()
89 // This function initializes the static variables used in the NV subsystem.
90 static void
NvInitStatic(void)91 NvInitStatic(
92 void
93 )
94 {
95 // In some implementations, the end of NV is variable and is set at boot time.
96 // This value will be the same for each boot, but is not necessarily known
97 // at compile time.
98 s_evictNvEnd = (NV_REF)NV_MEMORY_SIZE;
99 return;
100 }
101
102 //*** NvCheckState()
103 // Function to check the NV state by accessing the platform-specific function
104 // to get the NV state. The result state is registered in s_NvIsAvailable
105 // that will be reported by NvIsAvailable.
106 //
107 // This function is called at the beginning of ExecuteCommand before any potential
108 // check of g_NvStatus.
109 void
NvCheckState(void)110 NvCheckState(
111 void
112 )
113 {
114 int func_return;
115 //
116 func_return = _plat__IsNvAvailable();
117 if(func_return == 0)
118 g_NvStatus = TPM_RC_SUCCESS;
119 else if(func_return == 1)
120 g_NvStatus = TPM_RC_NV_UNAVAILABLE;
121 else
122 g_NvStatus = TPM_RC_NV_RATE;
123 return;
124 }
125
126 //*** NvCommit
127 // This is a wrapper for the platform function to commit pending NV writes.
128 BOOL
NvCommit(void)129 NvCommit(
130 void
131 )
132 {
133 return (_plat__NvCommit() == 0);
134 }
135
136 //*** NvPowerOn()
137 // This function is called at _TPM_Init to initialize the NV environment.
138 // Return Type: BOOL
139 // TRUE(1) all NV was initialized
140 // FALSE(0) the NV containing saved state had an error and
141 // TPM2_Startup(CLEAR) is required
142 BOOL
NvPowerOn(void)143 NvPowerOn(
144 void
145 )
146 {
147 int nvError = 0;
148 // If power was lost, need to re-establish the RAM data that is loaded from
149 // NV and initialize the static variables
150 if(g_powerWasLost)
151 {
152 if((nvError = _plat__NVEnable(0)) < 0)
153 FAIL(FATAL_ERROR_NV_UNRECOVERABLE);
154 NvInitStatic();
155 }
156 return nvError == 0;
157 }
158
159 //*** NvManufacture()
160 // This function initializes the NV system at pre-install time.
161 //
162 // This function should only be called in a manufacturing environment or in a
163 // simulation.
164 //
165 // The layout of NV memory space is an implementation choice.
166 void
NvManufacture(void)167 NvManufacture(
168 void
169 )
170 {
171 #if SIMULATION
172 // Simulate the NV memory being in the erased state.
173 _plat__NvMemoryClear(0, NV_MEMORY_SIZE);
174 #endif
175 // Initialize static variables
176 NvInitStatic();
177 // Clear the RAM used for Orderly Index data
178 MemorySet(s_indexOrderlyRam, 0, RAM_INDEX_SPACE);
179 // Write that Orderly Index data to NV
180 NvUpdateIndexOrderlyData();
181 // Initialize the next offset of the first entry in evict/index list to 0 (the
182 // end of list marker) and the initial s_maxCounterValue;
183 NvSetMaxCount(0);
184 // Put the end of list marker at the end of memory. This contains the MaxCount
185 // value as well as the end marker.
186 NvWriteNvListEnd(NV_USER_DYNAMIC);
187 return;
188 }
189
190 //*** NvRead()
191 // This function is used to move reserved data from NV memory to RAM.
192 void
NvRead(void * outBuffer,UINT32 nvOffset,UINT32 size)193 NvRead(
194 void *outBuffer, // OUT: buffer to receive data
195 UINT32 nvOffset, // IN: offset in NV of value
196 UINT32 size // IN: size of the value to read
197 )
198 {
199 // Input type should be valid
200 pAssert(nvOffset + size < NV_MEMORY_SIZE);
201 _plat__NvMemoryRead(nvOffset, size, outBuffer);
202 return;
203 }
204
205 //*** NvWrite()
206 // This function is used to post reserved data for writing to NV memory. Before
207 // the TPM completes the operation, the value will be written.
208 BOOL
NvWrite(UINT32 nvOffset,UINT32 size,void * inBuffer)209 NvWrite(
210 UINT32 nvOffset, // IN: location in NV to receive data
211 UINT32 size, // IN: size of the data to move
212 void *inBuffer // IN: location containing data to write
213 )
214 {
215 // Input type should be valid
216 if(nvOffset + size <= NV_MEMORY_SIZE)
217 {
218 // Set the flag that a NV write happened
219 SET_NV_UPDATE(UT_NV);
220 return _plat__NvMemoryWrite(nvOffset, size, inBuffer);
221 }
222 return FALSE;
223 }
224
225 //*** NvUpdatePersistent()
226 // This function is used to update a value in the PERSISTENT_DATA structure and
227 // commits the value to NV.
228 void
NvUpdatePersistent(UINT32 offset,UINT32 size,void * buffer)229 NvUpdatePersistent(
230 UINT32 offset, // IN: location in PERMANENT_DATA to be updated
231 UINT32 size, // IN: size of the value
232 void *buffer // IN: the new data
233 )
234 {
235 pAssert(offset + size <= sizeof(gp));
236 MemoryCopy(&gp + offset, buffer, size);
237 NvWrite(offset, size, buffer);
238 }
239
240 //*** NvClearPersistent()
241 // This function is used to clear a persistent data entry and commit it to NV
242 void
NvClearPersistent(UINT32 offset,UINT32 size)243 NvClearPersistent(
244 UINT32 offset, // IN: the offset in the PERMANENT_DATA
245 // structure to be cleared (zeroed)
246 UINT32 size // IN: number of bytes to clear
247 )
248 {
249 pAssert(offset + size <= sizeof(gp));
250 MemorySet((&gp) + offset, 0, size);
251 NvWrite(offset, size, (&gp) + offset);
252 }
253
254 //*** NvReadPersistent()
255 // This function reads persistent data to the RAM copy of the 'gp' structure.
256 void
NvReadPersistent(void)257 NvReadPersistent(
258 void
259 )
260 {
261 NvRead(&gp, NV_PERSISTENT_DATA, sizeof(gp));
262 return;
263 }