Line | Count | Source (jump to first uncovered line) |
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 |
37 | | _plat__NvErrors( |
38 | | BOOL recoverable, |
39 | | BOOL unrecoverable |
40 | | ) |
41 | 0 | { |
42 | 0 | s_NV_unrecoverable = unrecoverable; |
43 | 0 | s_NV_recoverable = recoverable; |
44 | 0 | } |
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 |
64 | | _plat__NVEnable( |
65 | | void *platParameter // IN: platform specific parameter |
66 | | ) |
67 | 11.2k | { |
68 | | // Start assuming everything is OK |
69 | 11.2k | s_NV_unrecoverable = FALSE; |
70 | 11.2k | s_NV_recoverable = FALSE; |
71 | 11.2k | #ifdef FILE_BACKED_NV |
72 | 11.2k | if(s_NVFile != NULL) return 0; |
73 | | // Try to open an exist NVChip file for read/write |
74 | 5.63k | s_NVFile = fopen("NVChip", "r+b"); |
75 | 5.63k | if(NULL != s_NVFile) |
76 | 5.63k | { |
77 | | // See if the NVChip file is empty |
78 | 5.63k | fseek(s_NVFile, 0, SEEK_END); |
79 | 5.63k | if(0 == ftell(s_NVFile)) |
80 | 0 | s_NVFile = NULL; |
81 | 5.63k | } |
82 | 5.63k | if(s_NVFile == NULL) |
83 | 1 | { |
84 | | // Initialize all the byte in the new file to 0 |
85 | 1 | memset(s_NV, 0, NV_MEMORY_SIZE); |
86 | | // If NVChip file does not exist, try to create it for read/write |
87 | 1 | s_NVFile = fopen("NVChip", "w+b"); |
88 | | // Start initialize at the end of new file |
89 | 1 | fseek(s_NVFile, 0, SEEK_END); |
90 | | // Write 0s to NVChip file |
91 | 1 | fwrite(s_NV, 1, NV_MEMORY_SIZE, s_NVFile); |
92 | 1 | } |
93 | 5.63k | else |
94 | 5.63k | { |
95 | | // If NVChip file exist, assume the size is correct |
96 | 5.63k | fseek(s_NVFile, 0, SEEK_END); |
97 | 5.63k | assert(ftell(s_NVFile) == NV_MEMORY_SIZE); |
98 | | // read NV file data to memory |
99 | 5.63k | fseek(s_NVFile, 0, SEEK_SET); |
100 | 5.63k | assert(1 == fread(s_NV, NV_MEMORY_SIZE, 1, s_NVFile)); |
101 | 5.63k | } |
102 | 5.63k | #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 | 5.63k | if(s_NV_unrecoverable) |
107 | 0 | return -1; |
108 | 5.63k | return s_NV_recoverable; |
109 | 5.63k | } |
110 | | // |
111 | | // |
112 | | // _plat__NVDisable() |
113 | | // |
114 | | // Disable NV memory |
115 | | // |
116 | | LIB_EXPORT void |
117 | | _plat__NVDisable( |
118 | | void |
119 | | ) |
120 | 5.63k | { |
121 | 5.63k | #ifdef FILE_BACKED_NV |
122 | 5.63k | assert(s_NVFile != NULL); |
123 | | // Close NV file |
124 | 5.63k | fclose(s_NVFile); |
125 | | // Set file handle to NULL |
126 | | // |
127 | 5.63k | s_NVFile = NULL; |
128 | 5.63k | #endif |
129 | 5.63k | return; |
130 | 5.63k | } |
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 |
144 | | _plat__IsNvAvailable( |
145 | | void |
146 | | ) |
147 | 33.9k | { |
148 | | // NV is not available if the TPM is in failure mode |
149 | 33.9k | if(!s_NvIsAvailable) |
150 | 0 | return 1; |
151 | 33.9k | #ifdef FILE_BACKED_NV |
152 | 33.9k | if(s_NVFile == NULL) |
153 | 0 | return 1; |
154 | 33.9k | #endif |
155 | 33.9k | return 0; |
156 | 33.9k | } |
157 | | // |
158 | | // |
159 | | // _plat__NvMemoryRead() |
160 | | // |
161 | | // Function: Read a chunk of NV memory |
162 | | // |
163 | | LIB_EXPORT void |
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 | 220k | { |
170 | 220k | assert(startOffset + size <= NV_MEMORY_SIZE); |
171 | | // Copy data from RAM |
172 | 220k | memcpy(data, &s_NV[startOffset], size); |
173 | 220k | return; |
174 | 220k | } |
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 |
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 | 0 | { |
197 | 0 | return (memcmp(&s_NV[startOffset], data, size) != 0); |
198 | 0 | } |
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 |
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 | 220k | { |
213 | 220k | assert(startOffset + size <= NV_MEMORY_SIZE); |
214 | | // Copy the data to the NV image |
215 | 220k | memcpy(&s_NV[startOffset], data, size); |
216 | 220k | } |
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 |
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 | 0 | { |
231 | 0 | assert(sourceOffset + size <= NV_MEMORY_SIZE); |
232 | 0 | assert(destOffset + size <= NV_MEMORY_SIZE); |
233 | | // Move data in RAM |
234 | 0 | memmove(&s_NV[destOffset], &s_NV[sourceOffset], size); |
235 | 0 | return; |
236 | 0 | } |
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 |
251 | | _plat__NvCommit( |
252 | | void |
253 | | ) |
254 | 11.3k | { |
255 | 11.3k | #ifdef FILE_BACKED_NV |
256 | | // If NV file is not available, return failure |
257 | 11.3k | if(s_NVFile == NULL) |
258 | 0 | return 1; |
259 | | // Write RAM data to NV |
260 | 11.3k | fseek(s_NVFile, 0, SEEK_SET); |
261 | 11.3k | fwrite(s_NV, 1, NV_MEMORY_SIZE, s_NVFile); |
262 | 11.3k | return 0; |
263 | | #else |
264 | | return 0; |
265 | | #endif |
266 | 11.3k | } |
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 |
275 | | _plat__SetNvAvail( |
276 | | void |
277 | | ) |
278 | 5.63k | { |
279 | 5.63k | s_NvIsAvailable = TRUE; |
280 | 5.63k | return; |
281 | 5.63k | } |
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 |
290 | | _plat__ClearNvAvail( |
291 | | void |
292 | | ) |
293 | 0 | { |
294 | 0 | s_NvIsAvailable = FALSE; |
295 | 0 | return; |
296 | 0 | } |
297 | | // |
298 | | // |
299 | | // _plat__NvGetHandleVirtualOffset() |
300 | | // |
301 | | // Dummy implementation that effectively disables vNVRAM. |
302 | | // |
303 | | LIB_EXPORT uint32_t |
304 | | _plat__NvGetHandleVirtualOffset(uint32_t handle) |
305 | 183 | { |
306 | 183 | return 0; |
307 | 183 | } |
308 | | // |
309 | | // |
310 | | // _plat__NvOffsetIsVirtual() |
311 | | // |
312 | | // Always returns false, as vNVRAM is not supported so no offsets are virtual. |
313 | | // |
314 | | LIB_EXPORT BOOL |
315 | | _plat__NvOffsetIsVirtual(unsigned int startOffset) |
316 | 0 | { |
317 | 0 | return FALSE; |
318 | 0 | } |
319 | | // |
320 | | // |
321 | | // _plat__NvVirtualMemoryRead() |
322 | | // |
323 | | // The above functions have effectively disabled vNVRAM, so this function should |
324 | | // never be called; sets memory to dummy value to highlight errors if it is |
325 | | // called by accident, and to ensure no information is leaked. |
326 | | // |
327 | | LIB_EXPORT void |
328 | | _plat__NvVirtualMemoryRead( |
329 | | unsigned int startOffset, |
330 | | unsigned int size, |
331 | | void *data) |
332 | 0 | { |
333 | 0 | memset((BYTE *)data, 0xab, size); |
334 | 0 | } |
335 | | // |
336 | | // Check if a non-PLATFORMCREATE index shall nevertheless be retained when |
337 | | // performing TPM2_Clear. |
338 | | // |
339 | | LIB_EXPORT BOOL |
340 | | _plat__ShallSurviveOwnerClear( |
341 | | uint32_t index |
342 | | ) |
343 | 0 | { |
344 | 0 | return FALSE; |
345 | 0 | } |
346 | | |
347 | | LIB_EXPORT void |
348 | | _plat__NvInformIndexDataChanged(uint32_t handle) |
349 | 0 | { |
350 | | /* Do nothing */ |
351 | 0 | return; |
352 | 0 | } |
353 | | |
354 | | // |
355 | | // |
356 | | // _plat__NvUpdateAllowed() |
357 | | // |
358 | | // Always returns TRUE. No platform-specific reasons to prevent updates. |
359 | | // |
360 | | LIB_EXPORT BOOL |
361 | | _plat__NvUpdateAllowed(uint32_t handle) |
362 | 72 | { |
363 | 72 | return TRUE; |
364 | 72 | } |