1 // This file was extracted from the TCG Published
2 // Trusted Platform Module Library
3 // Part 4: Supporting Routines
4 // Family "2.0"
5 // Level 00 Revision 01.16
6 // October 30, 2014
7
8 #include <memory.h>
9 #include <stdio.h>
10 #include <string.h>
11
12 #include "PlatformData.h"
13 #include "TpmError.h"
14 #include "assert.h"
15
16 #ifndef EMBEDDED_MODE
17 #define FILE_BACKED_NV
18 #endif
19
20 #if defined FILE_BACKED_NV
21 static FILE* s_NVFile;
22 #endif
23 static unsigned char s_NV[NV_MEMORY_SIZE];
24 static BOOL s_NvIsAvailable;
25 static BOOL s_NV_unrecoverable;
26 static BOOL s_NV_recoverable;
27 //
28 //
29 // Functions
30 //
31 // _plat__NvErrors()
32 //
33 // This function is used by the simulator to set the error flags in the NV subsystem to simulate an error in the
34 // NV loading process
35 //
36 LIB_EXPORT void
_plat__NvErrors(BOOL recoverable,BOOL unrecoverable)37 _plat__NvErrors(
38 BOOL recoverable,
39 BOOL unrecoverable
40 )
41 {
42 s_NV_unrecoverable = unrecoverable;
43 s_NV_recoverable = recoverable;
44 }
45 //
46 //
47 // _plat__NVEnable()
48 //
49 // Enable NV memory.
50 // This version just pulls in data from a file. In a real TPM, with NV on chip, this function would verify the
51 // integrity of the saved context. If the NV memory was not on chip but was in something like RPMB, the NV
52 // state would be read in, decrypted and integrity checked.
53 // The recovery from an integrity failure depends on where the error occurred. It it was in the state that is
54 // discarded by TPM Reset, then the error is recoverable if the TPM is reset. Otherwise, the TPM must go
55 // into failure mode.
56 //
57 // Return Value Meaning
58 //
59 // 0 if success
60 // >0 if receive recoverable error
61 // <0 if unrecoverable error
62 //
63 LIB_EXPORT int
_plat__NVEnable(void * platParameter)64 _plat__NVEnable(
65 void *platParameter // IN: platform specific parameter
66 )
67 {
68 // Start assuming everything is OK
69 s_NV_unrecoverable = FALSE;
70 s_NV_recoverable = FALSE;
71 #ifdef FILE_BACKED_NV
72 if(s_NVFile != NULL) return 0;
73 // Try to open an exist NVChip file for read/write
74 s_NVFile = fopen("NVChip", "r+b");
75 if(NULL != s_NVFile)
76 {
77 // See if the NVChip file is empty
78 fseek(s_NVFile, 0, SEEK_END);
79 if(0 == ftell(s_NVFile))
80 s_NVFile = NULL;
81 }
82 if(s_NVFile == NULL)
83 {
84 // Initialize all the byte in the new file to 0
85 memset(s_NV, 0, NV_MEMORY_SIZE);
86 // If NVChip file does not exist, try to create it for read/write
87 s_NVFile = fopen("NVChip", "w+b");
88 // Start initialize at the end of new file
89 fseek(s_NVFile, 0, SEEK_END);
90 // Write 0s to NVChip file
91 fwrite(s_NV, 1, NV_MEMORY_SIZE, s_NVFile);
92 }
93 else
94 {
95 // If NVChip file exist, assume the size is correct
96 fseek(s_NVFile, 0, SEEK_END);
97 assert(ftell(s_NVFile) == NV_MEMORY_SIZE);
98 // read NV file data to memory
99 fseek(s_NVFile, 0, SEEK_SET);
100 assert(1 == fread(s_NV, NV_MEMORY_SIZE, 1, s_NVFile));
101 }
102 #endif
103 // NV contents have been read and the error checks have been performed. For
104 // simulation purposes, use the signaling interface to indicate if an error is
105 // to be simulated and the type of the error.
106 if(s_NV_unrecoverable)
107 return -1;
108 return s_NV_recoverable;
109 }
110 //
111 //
112 // _plat__NVDisable()
113 //
114 // Disable NV memory
115 //
116 LIB_EXPORT void
_plat__NVDisable(void)117 _plat__NVDisable(
118 void
119 )
120 {
121 #ifdef FILE_BACKED_NV
122 assert(s_NVFile != NULL);
123 // Close NV file
124 fclose(s_NVFile);
125 // Set file handle to NULL
126 //
127 s_NVFile = NULL;
128 #endif
129 return;
130 }
131 //
132 //
133 // _plat__IsNvAvailable()
134 //
135 // Check if NV is available
136 //
137 // Return Value Meaning
138 //
139 // 0 NV is available
140 // 1 NV is not available due to write failure
141 // 2 NV is not available due to rate limit
142 //
143 LIB_EXPORT int
_plat__IsNvAvailable(void)144 _plat__IsNvAvailable(
145 void
146 )
147 {
148 // NV is not available if the TPM is in failure mode
149 if(!s_NvIsAvailable)
150 return 1;
151 #ifdef FILE_BACKED_NV
152 if(s_NVFile == NULL)
153 return 1;
154 #endif
155 return 0;
156 }
157 //
158 //
159 // _plat__NvMemoryRead()
160 //
161 // Function: Read a chunk of NV memory
162 //
163 LIB_EXPORT void
_plat__NvMemoryRead(unsigned int startOffset,unsigned int size,void * data)164 _plat__NvMemoryRead(
165 unsigned int startOffset, // IN: read start
166 unsigned int size, // IN: size of bytes to read
167 void *data // OUT: data buffer
168 )
169 {
170 assert(startOffset + size <= NV_MEMORY_SIZE);
171 // Copy data from RAM
172 memcpy(data, &s_NV[startOffset], size);
173 return;
174 }
175 //
176 //
177 // _plat__NvIsDifferent()
178 //
179 // This function checks to see if the NV is different from the test value. This is so that NV will not be written if
180 // it has not changed.
181 //
182 //
183 //
184 //
185 // Return Value Meaning
186 //
187 // TRUE the NV location is different from the test value
188 // FALSE the NV location is the same as the test value
189 //
190 LIB_EXPORT BOOL
_plat__NvIsDifferent(unsigned int startOffset,unsigned int size,void * data)191 _plat__NvIsDifferent(
192 unsigned int startOffset, // IN: read start
193 unsigned int size, // IN: size of bytes to read
194 void *data // IN: data buffer
195 )
196 {
197 return (memcmp(&s_NV[startOffset], data, size) != 0);
198 }
199 //
200 //
201 // _plat__NvMemoryWrite()
202 //
203 // This function is used to update NV memory. The write is to a memory copy of NV. At the end of the
204 // current command, any changes are written to the actual NV memory.
205 //
206 LIB_EXPORT void
_plat__NvMemoryWrite(unsigned int startOffset,unsigned int size,void * data)207 _plat__NvMemoryWrite(
208 unsigned int startOffset, // IN: write start
209 unsigned int size, // IN: size of bytes to write
210 void *data // OUT: data buffer
211 )
212 {
213 assert(startOffset + size <= NV_MEMORY_SIZE);
214 // Copy the data to the NV image
215 memcpy(&s_NV[startOffset], data, size);
216 }
217 //
218 //
219 // _plat__NvMemoryMove()
220 //
221 // Function: Move a chunk of NV memory from source to destination This function should ensure that if
222 // there overlap, the original data is copied before it is written
223 //
224 LIB_EXPORT void
_plat__NvMemoryMove(unsigned int sourceOffset,unsigned int destOffset,unsigned int size)225 _plat__NvMemoryMove(
226 unsigned int sourceOffset, // IN: source offset
227 unsigned int destOffset, // IN: destination offset
228 unsigned int size // IN: size of data being moved
229 )
230 {
231 assert(sourceOffset + size <= NV_MEMORY_SIZE);
232 assert(destOffset + size <= NV_MEMORY_SIZE);
233 // Move data in RAM
234 memmove(&s_NV[destOffset], &s_NV[sourceOffset], size);
235 return;
236 }
237 //
238 //
239 // _plat__NvCommit()
240 //
241 // Update NV chip
242 //
243 //
244 //
245 // Return Value Meaning
246 //
247 // 0 NV write success
248 // non-0 NV write fail
249 //
250 LIB_EXPORT int
_plat__NvCommit(void)251 _plat__NvCommit(
252 void
253 )
254 {
255 #ifdef FILE_BACKED_NV
256 // If NV file is not available, return failure
257 if(s_NVFile == NULL)
258 return 1;
259 // Write RAM data to NV
260 fseek(s_NVFile, 0, SEEK_SET);
261 fwrite(s_NV, 1, NV_MEMORY_SIZE, s_NVFile);
262 return 0;
263 #else
264 return 0;
265 #endif
266 }
267 //
268 //
269 // _plat__SetNvAvail()
270 //
271 // Set the current NV state to available. This function is for testing purpose only. It is not part of the
272 // platform NV logic
273 //
274 LIB_EXPORT void
_plat__SetNvAvail(void)275 _plat__SetNvAvail(
276 void
277 )
278 {
279 s_NvIsAvailable = TRUE;
280 return;
281 }
282 //
283 //
284 // _plat__ClearNvAvail()
285 //
286 // Set the current NV state to unavailable. This function is for testing purpose only. It is not part of the
287 // platform NV logic
288 //
289 LIB_EXPORT void
_plat__ClearNvAvail(void)290 _plat__ClearNvAvail(
291 void
292 )
293 {
294 s_NvIsAvailable = FALSE;
295 return;
296 }
297