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 | | #define NV_C |
9 | | #include "InternalRoutines.h" |
10 | | #include "Platform.h" |
11 | | // |
12 | | // NV Index/evict object iterator value |
13 | | // |
14 | | typedef UINT32 NV_ITER; // type of a NV iterator |
15 | 428 | #define NV_ITER_INIT 0xFFFFFFFF // initial value to start an |
16 | | // iterator |
17 | | |
18 | | // List of pre-defined address of reserved data |
19 | | static const UINT16 s_reservedAddr[NV_RESERVE_LAST]; |
20 | | |
21 | | // List of pre-defined reserved data size in byte |
22 | | static const UINT16 s_reservedSize[NV_RESERVE_LAST]; |
23 | | |
24 | | // Address of size of RAM index space in NV |
25 | | static const UINT32 s_ramIndexSizeAddr; |
26 | | |
27 | | // |
28 | | // |
29 | | // NV Utility Functions |
30 | | // |
31 | | // NvCheckState() |
32 | | // |
33 | | // Function to check the NV state by accessing the platform-specific function to get the NV state. The result |
34 | | // state is registered in s_NvIsAvailable that will be reported by NvIsAvailable(). |
35 | | // This function is called at the beginning of ExecuteCommand() before any potential call to NvIsAvailable(). |
36 | | // |
37 | | void |
38 | | NvCheckState(void) |
39 | 1.27k | { |
40 | 1.27k | int func_return; |
41 | 1.27k | func_return = _plat__IsNvAvailable(); |
42 | 1.27k | if(func_return == 0) |
43 | 1.27k | { |
44 | 1.27k | s_NvStatus = TPM_RC_SUCCESS; |
45 | 1.27k | } |
46 | 0 | else if(func_return == 1) |
47 | 0 | { |
48 | 0 | s_NvStatus = TPM_RC_NV_UNAVAILABLE; |
49 | 0 | } |
50 | 0 | else |
51 | 0 | { |
52 | 0 | s_NvStatus = TPM_RC_NV_RATE; |
53 | 0 | } |
54 | 1.27k | return; |
55 | 1.27k | } |
56 | | // |
57 | | // |
58 | | // NvIsAvailable() |
59 | | // |
60 | | // This function returns the NV availability parameter. |
61 | | // |
62 | | // Error Returns Meaning |
63 | | // |
64 | | // TPM_RC_SUCCESS NV is available |
65 | | // TPM_RC_NV_RATE NV is unavailable because of rate limit |
66 | | // TPM_RC_NV_UNAVAILABLE NV is inaccessible |
67 | | // |
68 | | TPM_RC |
69 | | NvIsAvailable( |
70 | | void |
71 | | ) |
72 | 852 | { |
73 | | // Make sure that NV state is still good |
74 | 852 | if (s_NvStatus == TPM_RC_SUCCESS) |
75 | 852 | NvCheckState(); |
76 | | |
77 | 852 | return s_NvStatus; |
78 | 852 | } |
79 | | // |
80 | | // |
81 | | // NvCommit |
82 | | // |
83 | | // This is a wrapper for the platform function to commit pending NV writes. |
84 | | // |
85 | | BOOL |
86 | | NvCommit( |
87 | | void |
88 | | ) |
89 | 426 | { |
90 | 426 | BOOL success = (_plat__NvCommit() == 0); |
91 | 426 | return success; |
92 | 426 | } |
93 | | // |
94 | | // |
95 | | // NvReadMaxCount() |
96 | | // |
97 | | // This function returns the max NV counter value. |
98 | | // |
99 | | static UINT64 |
100 | | NvReadMaxCount( |
101 | | void |
102 | | ) |
103 | 0 | { |
104 | 0 | UINT64 countValue; |
105 | 0 | _plat__NvMemoryRead(s_maxCountAddr, sizeof(UINT64), &countValue); |
106 | 0 | return countValue; |
107 | 0 | } |
108 | | // |
109 | | // |
110 | | // NvWriteMaxCount() |
111 | | // |
112 | | // This function updates the max counter value to NV memory. |
113 | | // |
114 | | static void |
115 | | NvWriteMaxCount( |
116 | | UINT64 maxCount |
117 | | ) |
118 | 0 | { |
119 | 0 | _plat__NvMemoryWrite(s_maxCountAddr, sizeof(UINT64), &maxCount); |
120 | 0 | return; |
121 | 0 | } |
122 | | // |
123 | | // |
124 | | // NV Index and Persistent Object Access Functions |
125 | | // |
126 | | // Introduction |
127 | | // |
128 | | // These functions are used to access an NV Index and persistent object memory. In this implementation, |
129 | | // the memory is simulated with RAM. The data in dynamic area is organized as a linked list, starting from |
130 | | // address s_evictNvStart. The first 4 bytes of a node in this link list is the offset of next node, followed by |
131 | | // the data entry. A 0-valued offset value indicates the end of the list. If the data entry area of the last node |
132 | | // happens to reach the end of the dynamic area without space left for an additional 4 byte end marker, the |
133 | | // end address, s_evictNvEnd, should serve as the mark of list end |
134 | | // |
135 | | // NvNext() |
136 | | // |
137 | | // This function provides a method to traverse every data entry in NV dynamic area. |
138 | | // To begin with, parameter iter should be initialized to NV_ITER_INIT indicating the first element. Every |
139 | | // time this function is called, the value in iter would be adjusted pointing to the next element in traversal. If |
140 | | // there is no next element, iter value would be 0. This function returns the address of the 'data entry' |
141 | | // pointed by the iter. If there is no more element in the set, a 0 value is returned indicating the end of |
142 | | // traversal. |
143 | | // |
144 | | static UINT32 |
145 | | NvNext( |
146 | | NV_ITER *iter |
147 | | ) |
148 | 214 | { |
149 | 214 | NV_ITER currentIter; |
150 | | // If iterator is at the beginning of list |
151 | 214 | if(*iter == NV_ITER_INIT) |
152 | 214 | { |
153 | | // Initialize iterator |
154 | 214 | *iter = s_evictNvStart; |
155 | 214 | } |
156 | | // If iterator reaches the end of NV space, or iterator indicates list end |
157 | 214 | if(*iter + sizeof(UINT32) > s_evictNvEnd || *iter == 0) |
158 | 0 | return 0; |
159 | | // Save the current iter offset |
160 | 214 | currentIter = *iter; |
161 | | // Adjust iter pointer pointing to next entity |
162 | | // Read pointer value |
163 | 214 | _plat__NvMemoryRead(*iter, sizeof(UINT32), iter); |
164 | 214 | if(!*iter || (*iter == NV_ITER_INIT)) return 0; |
165 | 0 | return currentIter + sizeof(UINT32); // entity stores after the pointer |
166 | 214 | } |
167 | | // |
168 | | // |
169 | | // NvGetEnd() |
170 | | // |
171 | | // Function to find the end of the NV dynamic data list |
172 | | // |
173 | | static UINT32 |
174 | | NvGetEnd( |
175 | | void |
176 | | ) |
177 | 0 | { |
178 | 0 | NV_ITER iter = NV_ITER_INIT; |
179 | 0 | UINT32 endAddr = s_evictNvStart; |
180 | 0 | UINT32 currentAddr; |
181 | 0 | while((currentAddr = NvNext(&iter)) != 0) |
182 | 0 | endAddr = currentAddr; |
183 | 0 | if(endAddr != s_evictNvStart) |
184 | 0 | { |
185 | | // Read offset |
186 | 0 | endAddr -= sizeof(UINT32); |
187 | 0 | _plat__NvMemoryRead(endAddr, sizeof(UINT32), &endAddr); |
188 | 0 | } |
189 | 0 | return endAddr; |
190 | 0 | } |
191 | | // |
192 | | // |
193 | | // NvGetFreeByte |
194 | | // |
195 | | // This function returns the number of free octets in NV space. |
196 | | // |
197 | | static UINT32 |
198 | | NvGetFreeByte( |
199 | | void |
200 | | ) |
201 | 0 | { |
202 | 0 | return s_evictNvEnd - NvGetEnd(); |
203 | 0 | } |
204 | | // |
205 | | // NvGetEvictObjectSize |
206 | | // |
207 | | // This function returns the size of an evict object in NV space |
208 | | // |
209 | | static UINT32 |
210 | | NvGetEvictObjectSize( |
211 | | void |
212 | | ) |
213 | 0 | { |
214 | 0 | return sizeof(TPM_HANDLE) + sizeof(OBJECT) + sizeof(UINT32); |
215 | 0 | } |
216 | | // |
217 | | // |
218 | | // NvGetCounterSize |
219 | | // |
220 | | // This function returns the size of a counter index in NV space. |
221 | | // |
222 | | static UINT32 |
223 | | NvGetCounterSize( |
224 | | void |
225 | | ) |
226 | 0 | { |
227 | | // It takes an offset field, a handle and the sizeof(NV_INDEX) and |
228 | | // sizeof(UINT64) for counter data |
229 | 0 | return sizeof(TPM_HANDLE) + sizeof(NV_INDEX) + sizeof(UINT64) + sizeof(UINT32); |
230 | 0 | } |
231 | | // |
232 | | // |
233 | | // NvTestSpace() |
234 | | // |
235 | | // This function will test if there is enough space to add a new entity. |
236 | | // |
237 | | // Return Value Meaning |
238 | | // |
239 | | // TRUE space available |
240 | | // FALSE no enough space |
241 | | // |
242 | | static BOOL |
243 | | NvTestSpace( |
244 | | UINT32 size, // IN: size of the entity to be added |
245 | | BOOL isIndex // IN: TRUE if the entity is an index |
246 | | ) |
247 | 0 | { |
248 | 0 | UINT32 remainByte = NvGetFreeByte(); |
249 | | // For NV Index, need to make sure that we do not allocate and Index if this |
250 | | // would mean that the TPM cannot allocate the minimum number of evict |
251 | | // objects. |
252 | 0 | if(isIndex) |
253 | 0 | { |
254 | | // Get the number of persistent objects allocated |
255 | 0 | UINT32 persistentNum = NvCapGetPersistentNumber(); |
256 | | // If we have not allocated the requisite number of evict objects, then we |
257 | | // need to reserve space for them. |
258 | | // NOTE: some of this is not written as simply as it might seem because |
259 | | // the values are all unsigned and subtracting needs to be done carefully |
260 | | // so that an underflow doesn't cause problems. |
261 | 0 | if(persistentNum < MIN_EVICT_OBJECTS) |
262 | 0 | { |
263 | 0 | UINT32 needed = (MIN_EVICT_OBJECTS - persistentNum) |
264 | 0 | * NvGetEvictObjectSize(); |
265 | 0 | if(needed > remainByte) |
266 | 0 | remainByte = 0; |
267 | 0 | else |
268 | 0 | remainByte -= needed; |
269 | 0 | } |
270 | | // if the requisite number of evict objects have been allocated then |
271 | | // no need to reserve additional space |
272 | 0 | } |
273 | | // This checks for the size of the value being added plus the index value. |
274 | | // NOTE: This does not check to see if the end marker can be placed in |
275 | | // memory because the end marker will not be written if it will not fit. |
276 | 0 | return (size + sizeof(UINT32) <= remainByte); |
277 | 0 | } |
278 | | // |
279 | | // |
280 | | // NvAdd() |
281 | | // |
282 | | // This function adds a new entity to NV. |
283 | | // This function requires that there is enough space to add a new entity (i.e., that NvTestSpace() has been |
284 | | // called and the available space is at least as large as the required space). |
285 | | // |
286 | | static void |
287 | | NvAdd( |
288 | | UINT32 totalSize, // IN: total size needed for this entity For |
289 | | // evict object, totalSize is the same as |
290 | | // bufferSize. For NV Index, totalSize is |
291 | | // bufferSize plus index data size |
292 | | UINT32 bufferSize, // IN: size of initial buffer |
293 | | BYTE *entity // IN: initial buffer |
294 | | ) |
295 | 0 | { |
296 | 0 | UINT32 endAddr; |
297 | 0 | UINT32 nextAddr; |
298 | 0 | UINT32 listEnd = 0; |
299 | | // Get the end of data list |
300 | 0 | endAddr = NvGetEnd(); |
301 | | // Calculate the value of next pointer, which is the size of a pointer + |
302 | | // the entity data size |
303 | 0 | nextAddr = endAddr + sizeof(UINT32) + totalSize; |
304 | | // Write next pointer |
305 | 0 | _plat__NvMemoryWrite(endAddr, sizeof(UINT32), &nextAddr); |
306 | | // Write entity data |
307 | 0 | _plat__NvMemoryWrite(endAddr + sizeof(UINT32), bufferSize, entity); |
308 | | // Write the end of list if it is not going to exceed the NV space |
309 | 0 | if(nextAddr + sizeof(UINT32) <= s_evictNvEnd) |
310 | 0 | _plat__NvMemoryWrite(nextAddr, sizeof(UINT32), &listEnd); |
311 | | // Set the flag so that NV changes are committed before the command completes. |
312 | 0 | g_updateNV = TRUE; |
313 | 0 | } |
314 | | // |
315 | | // |
316 | | // NvDelete() |
317 | | // |
318 | | // This function is used to delete an NV Index or persistent object from NV memory. |
319 | | // |
320 | | static void |
321 | | NvDelete( |
322 | | UINT32 entityAddr // IN: address of entity to be deleted |
323 | | ) |
324 | 0 | { |
325 | 0 | UINT32 next; |
326 | 0 | UINT32 entrySize; |
327 | 0 | UINT32 entryAddr = entityAddr - sizeof(UINT32); |
328 | 0 | UINT32 listEnd = 0; |
329 | | // Get the offset of the next entry. |
330 | 0 | _plat__NvMemoryRead(entryAddr, sizeof(UINT32), &next); |
331 | | // The size of this entry is the difference between the current entry and the |
332 | | // next entry. |
333 | 0 | entrySize = next - entryAddr; |
334 | | // Move each entry after the current one to fill the freed space. |
335 | | // Stop when we have reached the end of all the indexes. There are two |
336 | | // ways to detect the end of the list. The first is to notice that there |
337 | | // is no room for anything else because we are at the end of NV. The other |
338 | | // indication is that we find an end marker. |
339 | | // The loop condition checks for the end of NV. |
340 | 0 | while(next + sizeof(UINT32) <= s_evictNvEnd) |
341 | 0 | { |
342 | 0 | UINT32 size, oldAddr, newAddr; |
343 | | // Now check for the end marker |
344 | 0 | _plat__NvMemoryRead(next, sizeof(UINT32), &oldAddr); |
345 | 0 | if(oldAddr == 0) |
346 | 0 | break; |
347 | 0 | size = oldAddr - next; |
348 | | // Move entry |
349 | 0 | _plat__NvMemoryMove(next, next - entrySize, size); |
350 | | // Update forward link |
351 | 0 | newAddr = oldAddr - entrySize; |
352 | 0 | _plat__NvMemoryWrite(next - entrySize, sizeof(UINT32), &newAddr); |
353 | 0 | next = oldAddr; |
354 | 0 | } |
355 | | // Mark the end of list |
356 | 0 | _plat__NvMemoryWrite(next - entrySize, sizeof(UINT32), &listEnd); |
357 | | // Set the flag so that NV changes are committed before the command completes. |
358 | 0 | g_updateNV = TRUE; |
359 | 0 | } |
360 | | // |
361 | | // |
362 | | // RAM-based NV Index Data Access Functions |
363 | | // |
364 | | // Introduction |
365 | | // |
366 | | // The data layout in ram buffer is {size of(NV_handle() + data), NV_handle(), data} for each NV Index data |
367 | | // stored in RAM. |
368 | | // NV storage is updated when a NV Index is added or deleted. We do NOT updated NV storage when the |
369 | | // data is updated/ |
370 | | // |
371 | | // NvTestRAMSpace() |
372 | | // |
373 | | // This function indicates if there is enough RAM space to add a data for a new NV Index. |
374 | | // |
375 | | // |
376 | | // |
377 | | // |
378 | | // Return Value Meaning |
379 | | // |
380 | | // TRUE space available |
381 | | // FALSE no enough space |
382 | | // |
383 | | static BOOL |
384 | | NvTestRAMSpace( |
385 | | UINT32 size // IN: size of the data to be added to RAM |
386 | | ) |
387 | 0 | { |
388 | 0 | BOOL success = ( s_ramIndexSize |
389 | 0 | + size |
390 | 0 | + sizeof(TPM_HANDLE) + sizeof(UINT32) |
391 | 0 | <= RAM_INDEX_SPACE); |
392 | 0 | return success; |
393 | 0 | } |
394 | | // |
395 | | // |
396 | | // NvGetRamIndexOffset |
397 | | // |
398 | | // This function returns the offset of NV data in the RAM buffer |
399 | | // This function requires that NV Index is in RAM. That is, the index must be known to exist. |
400 | | // |
401 | | static UINT32 |
402 | | NvGetRAMIndexOffset( |
403 | | TPMI_RH_NV_INDEX handle // IN: NV handle |
404 | | ) |
405 | 0 | { |
406 | 0 | UINT32 currAddr = 0; |
407 | 0 | while(currAddr < s_ramIndexSize) |
408 | 0 | { |
409 | 0 | TPMI_RH_NV_INDEX currHandle; |
410 | 0 | UINT32 currSize; |
411 | 0 | memcpy(&currHandle, &s_ramIndex[currAddr + sizeof(UINT32)], |
412 | 0 | sizeof(currHandle)); |
413 | | // Found a match |
414 | 0 | if(currHandle == handle) |
415 | | // data buffer follows the handle and size field |
416 | 0 | break; |
417 | 0 | memcpy(&currSize, &s_ramIndex[currAddr], sizeof(currSize)); |
418 | 0 | currAddr += sizeof(UINT32) + currSize; |
419 | 0 | } |
420 | | // We assume the index data is existing in RAM space |
421 | 0 | pAssert(currAddr < s_ramIndexSize); |
422 | 0 | return currAddr + sizeof(TPMI_RH_NV_INDEX) + sizeof(UINT32); |
423 | 0 | } |
424 | | // |
425 | | // |
426 | | // NvAddRAM() |
427 | | // |
428 | | // This function adds a new data area to RAM. |
429 | | // This function requires that enough free RAM space is available to add the new data. |
430 | | // |
431 | | static void |
432 | | NvAddRAM( |
433 | | TPMI_RH_NV_INDEX handle, // IN: NV handle |
434 | | UINT32 size // IN: size of data |
435 | | ) |
436 | 0 | { |
437 | | // Add data space at the end of reserved RAM buffer |
438 | 0 | UINT32 value = size + sizeof(TPMI_RH_NV_INDEX); |
439 | 0 | memcpy(&s_ramIndex[s_ramIndexSize], &value, |
440 | 0 | sizeof(value)); |
441 | 0 | memcpy(&s_ramIndex[s_ramIndexSize + sizeof(UINT32)], &handle, |
442 | 0 | sizeof(handle)); |
443 | 0 | s_ramIndexSize += sizeof(UINT32) + sizeof(TPMI_RH_NV_INDEX) + size; |
444 | 0 | pAssert(s_ramIndexSize <= RAM_INDEX_SPACE); |
445 | | // Update NV version of s_ramIndexSize |
446 | 0 | _plat__NvMemoryWrite(s_ramIndexSizeAddr, sizeof(UINT32), &s_ramIndexSize); |
447 | | // Write reserved RAM space to NV to reflect the newly added NV Index |
448 | 0 | _plat__NvMemoryWrite(s_ramIndexAddr, RAM_INDEX_SPACE, s_ramIndex); |
449 | 0 | return; |
450 | 0 | } |
451 | | // |
452 | | // |
453 | | // NvDeleteRAM() |
454 | | // |
455 | | // This function is used to delete a RAM-backed NV Index data area. |
456 | | // This function assumes the data of NV Index exists in RAM |
457 | | // |
458 | | static void |
459 | | NvDeleteRAM( |
460 | | TPMI_RH_NV_INDEX handle // IN: NV handle |
461 | | ) |
462 | 0 | { |
463 | 0 | UINT32 nodeOffset; |
464 | 0 | UINT32 nextNode; |
465 | 0 | UINT32 size; |
466 | 0 | nodeOffset = NvGetRAMIndexOffset(handle); |
467 | 0 | if(nodeOffset >= s_ramIndexSize) |
468 | 0 | return; |
469 | | // Move the pointer back to get the size field of this node |
470 | 0 | nodeOffset -= sizeof(UINT32) + sizeof(TPMI_RH_NV_INDEX); |
471 | | // Get node size |
472 | 0 | memcpy(&size, &s_ramIndex[nodeOffset], sizeof(size)); |
473 | | // Get the offset of next node |
474 | 0 | nextNode = nodeOffset + sizeof(UINT32) + size; |
475 | | // Move data |
476 | 0 | MemoryMove(s_ramIndex + nodeOffset, s_ramIndex + nextNode, |
477 | 0 | s_ramIndexSize - nextNode, s_ramIndexSize - nextNode); |
478 | | // Update RAM size |
479 | 0 | s_ramIndexSize -= size + sizeof(UINT32); |
480 | | // Update NV version of s_ramIndexSize |
481 | 0 | _plat__NvMemoryWrite(s_ramIndexSizeAddr, sizeof(UINT32), &s_ramIndexSize); |
482 | | // Write reserved RAM space to NV to reflect the newly delete NV Index |
483 | 0 | _plat__NvMemoryWrite(s_ramIndexAddr, RAM_INDEX_SPACE, s_ramIndex); |
484 | 0 | return; |
485 | 0 | } |
486 | | // |
487 | | // |
488 | | // NvCleanBadFromRAM() |
489 | | // |
490 | | // This function is used to delete RAM-backed NV Index data areas |
491 | | // for indexes, which shouldn't be there (e.g. created with b/211564769). |
492 | | static void |
493 | | NvCleanBadFromRAM() |
494 | 213 | { |
495 | 213 | UINT32 currAddr = 0; |
496 | 213 | BOOL foundBad = FALSE; |
497 | | |
498 | 213 | if(NvIsAvailable() != TPM_RC_SUCCESS) |
499 | 0 | return; |
500 | | |
501 | 213 | while(currAddr < s_ramIndexSize) |
502 | 0 | { |
503 | 0 | UINT32 currSize; |
504 | 0 | TPMI_RH_NV_INDEX currHandle; |
505 | 0 | UINT32 nextAddr; |
506 | |
|
507 | 0 | memcpy(&currSize, &s_ramIndex[currAddr], sizeof(currSize)); |
508 | 0 | nextAddr = currAddr + sizeof(UINT32) + currSize; |
509 | 0 | if(nextAddr > s_ramIndexSize || currSize < sizeof(TPMI_RH_NV_INDEX)) |
510 | 0 | break; |
511 | | |
512 | 0 | memcpy(&currHandle, &s_ramIndex[currAddr + sizeof(UINT32)], |
513 | 0 | sizeof(currHandle)); |
514 | |
|
515 | 0 | if(HandleGetType(currHandle) != TPM_HT_NV_INDEX) |
516 | 0 | { |
517 | 0 | MemoryMove(s_ramIndex + currAddr, s_ramIndex + nextAddr, |
518 | 0 | s_ramIndexSize - nextAddr, s_ramIndexSize - nextAddr); |
519 | 0 | s_ramIndexSize -= currSize + sizeof(UINT32); |
520 | 0 | foundBad = TRUE; |
521 | 0 | } |
522 | 0 | else |
523 | 0 | { |
524 | 0 | currAddr = nextAddr; |
525 | 0 | } |
526 | 0 | } |
527 | 213 | if(foundBad) |
528 | 0 | { |
529 | 0 | _plat__NvMemoryWrite(s_ramIndexSizeAddr, sizeof(UINT32), &s_ramIndexSize); |
530 | 0 | _plat__NvMemoryWrite(s_ramIndexAddr, RAM_INDEX_SPACE, s_ramIndex); |
531 | 0 | g_updateNV = TRUE; |
532 | 0 | } |
533 | 213 | } |
534 | | |
535 | | static const UINT16 s_reservedSize[NV_RESERVE_LAST] = { |
536 | | [NV_DISABLE_CLEAR] = sizeof(gp.disableClear), |
537 | | [NV_OWNER_ALG] = sizeof(gp.ownerAlg), |
538 | | [NV_ENDORSEMENT_ALG] = sizeof(gp.endorsementAlg), |
539 | | [NV_LOCKOUT_ALG] = sizeof(gp.lockoutAlg), |
540 | | [NV_OWNER_POLICY] = sizeof(gp.ownerPolicy), |
541 | | [NV_ENDORSEMENT_POLICY] = sizeof(gp.endorsementPolicy), |
542 | | [NV_LOCKOUT_POLICY] = sizeof(gp.lockoutPolicy), |
543 | | [NV_OWNER_AUTH] = sizeof(gp.ownerAuth), |
544 | | [NV_ENDORSEMENT_AUTH] = sizeof(gp.endorsementAuth), |
545 | | [NV_LOCKOUT_AUTH] = sizeof(gp.lockoutAuth), |
546 | | [NV_EP_SEED] = sizeof(gp.EPSeed), |
547 | | [NV_SP_SEED] = sizeof(gp.SPSeed), |
548 | | [NV_PP_SEED] = sizeof(gp.PPSeed), |
549 | | [NV_PH_PROOF] = sizeof(gp.phProof), |
550 | | [NV_SH_PROOF] = sizeof(gp.shProof), |
551 | | [NV_EH_PROOF] = sizeof(gp.ehProof), |
552 | | [NV_TOTAL_RESET_COUNT] = sizeof(gp.totalResetCount), |
553 | | [NV_RESET_COUNT] = sizeof(gp.resetCount), |
554 | | [NV_PCR_POLICIES] = sizeof(gp.pcrPolicies), |
555 | | [NV_PCR_ALLOCATED] = sizeof(gp.pcrAllocated), |
556 | | [NV_PP_LIST] = sizeof(gp.ppList), |
557 | | [NV_FAILED_TRIES] = sizeof(gp.failedTries), |
558 | | [NV_MAX_TRIES] = sizeof(gp.maxTries), |
559 | | [NV_RECOVERY_TIME] = sizeof(gp.recoveryTime), |
560 | | [NV_LOCKOUT_RECOVERY] = sizeof(gp.lockoutRecovery), |
561 | | [NV_LOCKOUT_AUTH_ENABLED] = sizeof(gp.lockOutAuthEnabled), |
562 | | [NV_ORDERLY] = sizeof(gp.orderlyState), |
563 | | [NV_AUDIT_COMMANDS] = sizeof(gp.auditComands), |
564 | | [NV_AUDIT_HASH_ALG] = sizeof(gp.auditHashAlg), |
565 | | [NV_AUDIT_COUNTER] = sizeof(gp.auditCounter), |
566 | | [NV_ALGORITHM_SET] = sizeof(gp.algorithmSet), |
567 | | [NV_FIRMWARE_V1] = sizeof(gp.firmwareV1), |
568 | | [NV_FIRMWARE_V2] = sizeof(gp.firmwareV2), |
569 | | [NV_ORDERLY_DATA] = sizeof(go), |
570 | | [NV_STATE_CLEAR] = sizeof(gc), |
571 | | [NV_STATE_RESET] = sizeof(gr) |
572 | | }; |
573 | | |
574 | | // PERSISTENT_DATA struct declares certain fields as UINT32 or UINT64, thus |
575 | | // preventing use of offsetof(PERSISTENT_DATA, field) directly as we need to |
576 | | // preserve nvmem layout for compatibility. So, declare an intermediate struct |
577 | | // to follow nvmem layout |
578 | | struct NV_LAYOUT { |
579 | | BYTE disableClear[sizeof(gp.disableClear)]; |
580 | | BYTE ownerAlg[sizeof(gp.ownerAlg)]; |
581 | | BYTE endorsementAlg[sizeof(gp.endorsementAlg)]; |
582 | | BYTE lockoutAlg[sizeof(gp.lockoutAlg)]; |
583 | | BYTE ownerPolicy[sizeof(gp.ownerPolicy)]; |
584 | | BYTE endorsementPolicy[sizeof(gp.endorsementPolicy)]; |
585 | | BYTE lockoutPolicy[sizeof(gp.lockoutPolicy)]; |
586 | | BYTE ownerAuth[sizeof(gp.ownerAuth)]; |
587 | | BYTE endorsementAuth[sizeof(gp.endorsementAuth)]; |
588 | | BYTE lockoutAuth[sizeof(gp.lockoutAuth)]; |
589 | | BYTE EPSeed[sizeof(gp.EPSeed)]; |
590 | | BYTE SPSeed[sizeof(gp.SPSeed)]; |
591 | | BYTE PPSeed[sizeof(gp.PPSeed)]; |
592 | | BYTE phProof[sizeof(gp.phProof)]; |
593 | | BYTE shProof[sizeof(gp.shProof)]; |
594 | | BYTE ehProof[sizeof(gp.ehProof)]; |
595 | | BYTE totalResetCount[sizeof(gp.totalResetCount)]; |
596 | | BYTE resetCount[sizeof(gp.resetCount)]; |
597 | | BYTE pcrPolicies[sizeof(gp.pcrPolicies)]; |
598 | | BYTE pcrAllocated[sizeof(gp.pcrAllocated)]; |
599 | | BYTE ppList[sizeof(gp.ppList)]; |
600 | | BYTE failedTries[sizeof(gp.failedTries)]; |
601 | | BYTE maxTries[sizeof(gp.maxTries)]; |
602 | | BYTE recoveryTime[sizeof(gp.recoveryTime)]; |
603 | | BYTE lockoutRecovery[sizeof(gp.lockoutRecovery)]; |
604 | | BYTE lockOutAuthEnabled[sizeof(gp.lockOutAuthEnabled)]; |
605 | | BYTE orderlyState[sizeof(gp.orderlyState)]; |
606 | | BYTE auditComands[sizeof(gp.auditComands)]; |
607 | | BYTE auditHashAlg[sizeof(gp.auditHashAlg)]; |
608 | | BYTE auditCounter[sizeof(gp.auditCounter)]; |
609 | | BYTE algorithmSet[sizeof(gp.algorithmSet)]; |
610 | | BYTE firmwareV1[sizeof(gp.firmwareV1)]; |
611 | | BYTE firmwareV2[sizeof(gp.firmwareV2)]; |
612 | | BYTE _go[sizeof(go)]; |
613 | | BYTE _gc[sizeof(gc)]; |
614 | | BYTE _gr[sizeof(gr)]; |
615 | | }; |
616 | | |
617 | | // Initialize reserved data address. In this implementation, reserved data |
618 | | // is stored at the start of NV memory |
619 | | // reservedAddr = 0; |
620 | | // for(i = 0; i < NV_RESERVE_LAST; i++) |
621 | | // { |
622 | | // s_reservedAddr[i] = reservedAddr; |
623 | | // reservedAddr += s_reservedSize[i]; |
624 | | // } |
625 | | // s_ramIndexSizeAddr = reservedAddr; |
626 | | static const UINT16 s_reservedAddr[NV_RESERVE_LAST] = { |
627 | | [NV_DISABLE_CLEAR] = offsetof(struct NV_LAYOUT, disableClear), |
628 | | [NV_OWNER_ALG] = offsetof(struct NV_LAYOUT, ownerAlg), |
629 | | [NV_ENDORSEMENT_ALG] = offsetof(struct NV_LAYOUT, endorsementAlg), |
630 | | [NV_LOCKOUT_ALG] = offsetof(struct NV_LAYOUT, lockoutAlg), |
631 | | [NV_OWNER_POLICY] = offsetof(struct NV_LAYOUT, ownerPolicy), |
632 | | [NV_ENDORSEMENT_POLICY] = offsetof(struct NV_LAYOUT, endorsementPolicy), |
633 | | [NV_LOCKOUT_POLICY] = offsetof(struct NV_LAYOUT, lockoutPolicy), |
634 | | [NV_OWNER_AUTH] = offsetof(struct NV_LAYOUT, ownerAuth), |
635 | | [NV_ENDORSEMENT_AUTH] = offsetof(struct NV_LAYOUT, endorsementAuth), |
636 | | [NV_LOCKOUT_AUTH] = offsetof(struct NV_LAYOUT, lockoutAuth), |
637 | | [NV_EP_SEED] = offsetof(struct NV_LAYOUT, EPSeed), |
638 | | [NV_SP_SEED] = offsetof(struct NV_LAYOUT, SPSeed), |
639 | | [NV_PP_SEED] = offsetof(struct NV_LAYOUT, PPSeed), |
640 | | [NV_PH_PROOF] = offsetof(struct NV_LAYOUT, phProof), |
641 | | [NV_SH_PROOF] = offsetof(struct NV_LAYOUT, shProof), |
642 | | [NV_EH_PROOF] = offsetof(struct NV_LAYOUT, ehProof), |
643 | | [NV_TOTAL_RESET_COUNT] = offsetof(struct NV_LAYOUT, totalResetCount), |
644 | | [NV_RESET_COUNT] = offsetof(struct NV_LAYOUT, resetCount), |
645 | | [NV_PCR_POLICIES] = offsetof(struct NV_LAYOUT, pcrPolicies), |
646 | | [NV_PCR_ALLOCATED] = offsetof(struct NV_LAYOUT, pcrAllocated), |
647 | | [NV_PP_LIST] = offsetof(struct NV_LAYOUT, ppList), |
648 | | [NV_FAILED_TRIES] = offsetof(struct NV_LAYOUT, failedTries), |
649 | | [NV_MAX_TRIES] = offsetof(struct NV_LAYOUT, maxTries), |
650 | | [NV_RECOVERY_TIME] = offsetof(struct NV_LAYOUT, recoveryTime), |
651 | | [NV_LOCKOUT_RECOVERY] = offsetof(struct NV_LAYOUT, lockoutRecovery), |
652 | | [NV_LOCKOUT_AUTH_ENABLED] = offsetof(struct NV_LAYOUT, lockOutAuthEnabled), |
653 | | [NV_ORDERLY] = offsetof(struct NV_LAYOUT, orderlyState), |
654 | | [NV_AUDIT_COMMANDS] = offsetof(struct NV_LAYOUT, auditComands), |
655 | | [NV_AUDIT_HASH_ALG] = offsetof(struct NV_LAYOUT, auditHashAlg), |
656 | | [NV_AUDIT_COUNTER] = offsetof(struct NV_LAYOUT, auditCounter), |
657 | | [NV_ALGORITHM_SET] = offsetof(struct NV_LAYOUT, algorithmSet), |
658 | | [NV_FIRMWARE_V1] = offsetof(struct NV_LAYOUT, firmwareV1), |
659 | | [NV_FIRMWARE_V2] = offsetof(struct NV_LAYOUT, firmwareV2), |
660 | | [NV_ORDERLY_DATA] = offsetof(struct NV_LAYOUT, _go), |
661 | | [NV_STATE_CLEAR] = offsetof(struct NV_LAYOUT, _gc), |
662 | | [NV_STATE_RESET] = offsetof(struct NV_LAYOUT, _gr), |
663 | | }; |
664 | | |
665 | | static const UINT32 s_ramIndexSizeAddr = sizeof(struct NV_LAYOUT); |
666 | | |
667 | | // |
668 | | // |
669 | | // |
670 | | // Utility Functions |
671 | | // |
672 | | // NvInitStatic() |
673 | | // |
674 | | // This function initializes the static variables used in the NV subsystem. |
675 | | // |
676 | | static void |
677 | | NvInitStatic( |
678 | | void |
679 | | ) |
680 | 426 | { |
681 | | // Initialize auxiliary variable space for index/evict implementation. |
682 | | // Auxiliary variables are stored after reserved data area |
683 | | // RAM index copy starts at the beginning |
684 | 426 | s_ramIndexAddr = s_ramIndexSizeAddr + sizeof(UINT32); |
685 | | // Maximum counter value |
686 | 426 | s_maxCountAddr = s_ramIndexAddr + RAM_INDEX_SPACE; |
687 | | // dynamic memory start |
688 | 426 | s_evictNvStart = s_maxCountAddr + sizeof(UINT64); |
689 | | // dynamic memory ends at the end of NV memory |
690 | 426 | s_evictNvEnd = NV_MEMORY_SIZE; |
691 | 426 | return; |
692 | 426 | } |
693 | | // |
694 | | // |
695 | | // NvInit() |
696 | | // |
697 | | // This function initializes the NV system at pre-install time. |
698 | | // This function should only be called in a manufacturing environment or in a simulation. |
699 | | // The layout of NV memory space is an implementation choice. |
700 | | // |
701 | | void |
702 | | NvInit( |
703 | | void |
704 | | ) |
705 | 213 | { |
706 | 213 | UINT32 nullPointer = 0; |
707 | 213 | UINT64 zeroCounter = 0; |
708 | | // Initialize static variables |
709 | 213 | NvInitStatic(); |
710 | | // Initialize RAM index space as unused |
711 | 213 | _plat__NvMemoryWrite(s_ramIndexSizeAddr, sizeof(UINT32), &nullPointer); |
712 | | // Initialize max counter value to 0 |
713 | 213 | _plat__NvMemoryWrite(s_maxCountAddr, sizeof(UINT64), &zeroCounter); |
714 | | // Initialize the next offset of the first entry in evict/index list to 0 |
715 | 213 | _plat__NvMemoryWrite(s_evictNvStart, sizeof(TPM_HANDLE), &nullPointer); |
716 | 213 | return; |
717 | 213 | } |
718 | | // |
719 | | // |
720 | | // NvReadReserved() |
721 | | // |
722 | | // This function is used to move reserved data from NV memory to RAM. |
723 | | // |
724 | | void |
725 | | NvReadReserved( |
726 | | NV_RESERVE type, // IN: type of reserved data |
727 | | void *buffer // OUT: buffer receives the data. |
728 | | ) |
729 | 7.66k | { |
730 | | // Input type should be valid |
731 | 7.66k | pAssert(type >= 0 && type < NV_RESERVE_LAST); |
732 | 7.66k | _plat__NvMemoryRead(s_reservedAddr[type], s_reservedSize[type], buffer); |
733 | 7.66k | return; |
734 | 7.66k | } |
735 | | // |
736 | | // |
737 | | // NvWriteReserved() |
738 | | // |
739 | | // This function is used to post a reserved data for writing to NV memory. Before the TPM completes the |
740 | | // operation, the value will be written. |
741 | | // |
742 | | void |
743 | | NvWriteReserved( |
744 | | NV_RESERVE type, // IN: type of reserved data |
745 | | void *buffer // IN: data buffer |
746 | | ) |
747 | 7.66k | { |
748 | | // Input type should be valid |
749 | 7.66k | pAssert(type >= 0 && type < NV_RESERVE_LAST); |
750 | 7.66k | _plat__NvMemoryWrite(s_reservedAddr[type], s_reservedSize[type], buffer); |
751 | | // Set the flag that a NV write happens |
752 | 7.66k | g_updateNV = TRUE; |
753 | 7.66k | return; |
754 | 7.66k | } |
755 | | // |
756 | | // |
757 | | // NvReadPersistent() |
758 | | // |
759 | | // This function reads persistent data to the RAM copy of the gp structure. |
760 | | // |
761 | | void |
762 | | NvReadPersistent( |
763 | | void |
764 | | ) |
765 | 213 | { |
766 | | // Hierarchy persistent data |
767 | 213 | NvReadReserved(NV_DISABLE_CLEAR, &gp.disableClear); |
768 | 213 | NvReadReserved(NV_OWNER_ALG, &gp.ownerAlg); |
769 | 213 | NvReadReserved(NV_ENDORSEMENT_ALG, &gp.endorsementAlg); |
770 | 213 | NvReadReserved(NV_LOCKOUT_ALG, &gp.lockoutAlg); |
771 | 213 | NvReadReserved(NV_OWNER_POLICY, &gp.ownerPolicy); |
772 | 213 | NvReadReserved(NV_ENDORSEMENT_POLICY, &gp.endorsementPolicy); |
773 | 213 | NvReadReserved(NV_LOCKOUT_POLICY, &gp.lockoutPolicy); |
774 | 213 | NvReadReserved(NV_OWNER_AUTH, &gp.ownerAuth); |
775 | 213 | NvReadReserved(NV_ENDORSEMENT_AUTH, &gp.endorsementAuth); |
776 | 213 | NvReadReserved(NV_LOCKOUT_AUTH, &gp.lockoutAuth); |
777 | 213 | NvReadReserved(NV_EP_SEED, &gp.EPSeed); |
778 | 213 | NvReadReserved(NV_SP_SEED, &gp.SPSeed); |
779 | 213 | NvReadReserved(NV_PP_SEED, &gp.PPSeed); |
780 | 213 | NvReadReserved(NV_PH_PROOF, &gp.phProof); |
781 | 213 | NvReadReserved(NV_SH_PROOF, &gp.shProof); |
782 | 213 | NvReadReserved(NV_EH_PROOF, &gp.ehProof); |
783 | | // Time persistent data |
784 | 213 | NvReadReserved(NV_TOTAL_RESET_COUNT, &gp.totalResetCount); |
785 | 213 | NvReadReserved(NV_RESET_COUNT, &gp.resetCount); |
786 | | // PCR persistent data |
787 | 213 | NvReadReserved(NV_PCR_POLICIES, &gp.pcrPolicies); |
788 | 213 | NvReadReserved(NV_PCR_ALLOCATED, &gp.pcrAllocated); |
789 | | // Physical Presence persistent data |
790 | 213 | NvReadReserved(NV_PP_LIST, &gp.ppList); |
791 | | // Dictionary attack values persistent data |
792 | 213 | NvReadReserved(NV_FAILED_TRIES, &gp.failedTries); |
793 | 213 | NvReadReserved(NV_MAX_TRIES, &gp.maxTries); |
794 | 213 | NvReadReserved(NV_RECOVERY_TIME, &gp.recoveryTime); |
795 | | // |
796 | 213 | NvReadReserved(NV_LOCKOUT_RECOVERY, &gp.lockoutRecovery); |
797 | 213 | NvReadReserved(NV_LOCKOUT_AUTH_ENABLED, &gp.lockOutAuthEnabled); |
798 | | // Orderly State persistent data |
799 | 213 | NvReadReserved(NV_ORDERLY, &gp.orderlyState); |
800 | | // Command audit values persistent data |
801 | 213 | NvReadReserved(NV_AUDIT_COMMANDS, &gp.auditComands); |
802 | 213 | NvReadReserved(NV_AUDIT_HASH_ALG, &gp.auditHashAlg); |
803 | 213 | NvReadReserved(NV_AUDIT_COUNTER, &gp.auditCounter); |
804 | | // Algorithm selection persistent data |
805 | 213 | NvReadReserved(NV_ALGORITHM_SET, &gp.algorithmSet); |
806 | | // Firmware version persistent data |
807 | | #ifdef EMBEDDED_MODE |
808 | | _plat__GetFwVersion(&gp.firmwareV1, &gp.firmwareV2); |
809 | | #else |
810 | 213 | NvReadReserved(NV_FIRMWARE_V1, &gp.firmwareV1); |
811 | 213 | NvReadReserved(NV_FIRMWARE_V2, &gp.firmwareV2); |
812 | 213 | #endif |
813 | 213 | return; |
814 | 213 | } |
815 | | // |
816 | | // |
817 | | // NvIsPlatformPersistentHandle() |
818 | | // |
819 | | // This function indicates if a handle references a persistent object in the range belonging to the platform. |
820 | | // |
821 | | // Return Value Meaning |
822 | | // |
823 | | // TRUE handle references a platform persistent object |
824 | | // FALSE handle does not reference platform persistent object and may |
825 | | // reference an owner persistent object either |
826 | | // |
827 | | BOOL |
828 | | NvIsPlatformPersistentHandle( |
829 | | TPM_HANDLE handle // IN: handle |
830 | | ) |
831 | 0 | { |
832 | 0 | return (handle >= PLATFORM_PERSISTENT && handle <= PERSISTENT_LAST); |
833 | 0 | } |
834 | | // |
835 | | // |
836 | | // NvIsOwnerPersistentHandle() |
837 | | // |
838 | | // This function indicates if a handle references a persistent object in the range belonging to the owner. |
839 | | // |
840 | | // Return Value Meaning |
841 | | // |
842 | | // TRUE handle is owner persistent handle |
843 | | // FALSE handle is not owner persistent handle and may not be a persistent |
844 | | // handle at all |
845 | | // |
846 | | BOOL |
847 | | NvIsOwnerPersistentHandle( |
848 | | TPM_HANDLE handle // IN: handle |
849 | | ) |
850 | 0 | { |
851 | 0 | return (handle >= PERSISTENT_FIRST && handle < PLATFORM_PERSISTENT); |
852 | 0 | } |
853 | | // |
854 | | // |
855 | | // NvNextIndex() |
856 | | // |
857 | | // This function returns the offset in NV of the next NV Index entry. A value of 0 indicates the end of the list. |
858 | | // Family "2.0" TCG Published Page 131 |
859 | | // Level 00 Revision 01.16 Copyright © TCG 2006-2014 October 30, 2014 |
860 | | // Trusted Platform Module Library Part 4: Supporting Routines |
861 | | // |
862 | | static UINT32 |
863 | | NvNextIndex( |
864 | | NV_ITER *iter |
865 | | ) |
866 | 213 | { |
867 | 213 | UINT32 addr; |
868 | 213 | TPM_HANDLE handle; |
869 | 213 | while((addr = NvNext(iter)) != 0) |
870 | 0 | { |
871 | | // Read handle |
872 | 0 | _plat__NvMemoryRead(addr, sizeof(TPM_HANDLE), &handle); |
873 | 0 | if(HandleGetType(handle) == TPM_HT_NV_INDEX) |
874 | 0 | return addr; |
875 | 0 | } |
876 | 213 | pAssert(addr == 0); |
877 | 213 | return addr; |
878 | 213 | } |
879 | | // |
880 | | // |
881 | | // NvNextEvict() |
882 | | // |
883 | | // This function returns the offset in NV of the next evict object entry. A value of 0 indicates the end of the |
884 | | // list. |
885 | | // |
886 | | static UINT32 |
887 | | NvNextEvict( |
888 | | NV_ITER *iter |
889 | | ) |
890 | 0 | { |
891 | 0 | UINT32 addr; |
892 | 0 | TPM_HANDLE handle; |
893 | 0 | while((addr = NvNext(iter)) != 0) |
894 | 0 | { |
895 | | // Read handle |
896 | 0 | _plat__NvMemoryRead(addr, sizeof(TPM_HANDLE), &handle); |
897 | 0 | if(HandleGetType(handle) == TPM_HT_PERSISTENT) |
898 | 0 | return addr; |
899 | 0 | } |
900 | 0 | pAssert(addr == 0); |
901 | 0 | return addr; |
902 | 0 | } |
903 | | // |
904 | | // |
905 | | // NvFindHandle() |
906 | | // |
907 | | // this function returns the offset in NV memory of the entity associated with the input handle. A value of |
908 | | // zero indicates that handle does not exist reference an existing persistent object or defined NV Index. |
909 | | // |
910 | | static UINT32 |
911 | | NvFindHandle( |
912 | | TPM_HANDLE handle |
913 | | ) |
914 | 1 | { |
915 | 1 | UINT32 addr; |
916 | 1 | NV_ITER iter = NV_ITER_INIT; |
917 | | |
918 | 1 | if ((addr = _plat__NvGetHandleVirtualOffset(handle)) != 0) { |
919 | 0 | return addr; |
920 | 0 | } |
921 | | |
922 | 1 | while((addr = NvNext(&iter)) != 0) |
923 | 0 | { |
924 | 0 | TPM_HANDLE entityHandle; |
925 | | // Read handle |
926 | | // |
927 | 0 | _plat__NvMemoryRead(addr, sizeof(TPM_HANDLE), &entityHandle); |
928 | 0 | if(entityHandle == handle) |
929 | 0 | return addr; |
930 | 0 | } |
931 | 1 | pAssert(addr == 0); |
932 | 1 | return addr; |
933 | 1 | } |
934 | | |
935 | | // |
936 | | // NvCheckAndMigrateIfNeeded() |
937 | | // |
938 | | // Supported only in EMBEDDED_MODE. |
939 | | // |
940 | | // Check if the NVRAM storage format changed, and if so - reinitialize the |
941 | | // NVRAM. No content migration yet, hopefully it will come one day. |
942 | | // |
943 | | // Note that the NV_FIRMWARE_V1 and NV_FIRMWARE_V2 values not used to store |
944 | | // TPM versoion when in embedded mode are used for NVRAM format version |
945 | | // instead. |
946 | | // |
947 | | // |
948 | | static void |
949 | | NvCheckAndMigrateIfNeeded(void) |
950 | 213 | { |
951 | | #ifdef EMBEDDED_MODE |
952 | | UINT32 nv_vers1; |
953 | | UINT32 nv_vers2; |
954 | | |
955 | | NvReadReserved(NV_FIRMWARE_V1, &nv_vers1); |
956 | | NvReadReserved(NV_FIRMWARE_V2, &nv_vers2); |
957 | | |
958 | | if ((nv_vers1 == ~nv_vers2) && (nv_vers1 == NV_FORMAT_VERSION)) |
959 | | return; // All is well. |
960 | | |
961 | | // This will reinitialize NVRAM to empty. Migration code will come here |
962 | | // later. |
963 | | NvInit(); |
964 | | |
965 | | nv_vers1 = NV_FORMAT_VERSION; |
966 | | nv_vers2 = ~NV_FORMAT_VERSION; |
967 | | |
968 | | NvWriteReserved(NV_FIRMWARE_V1, &nv_vers1); |
969 | | NvWriteReserved(NV_FIRMWARE_V2, &nv_vers2); |
970 | | |
971 | | NvCommit(); |
972 | | #endif |
973 | 213 | } |
974 | | |
975 | | |
976 | | // |
977 | | // |
978 | | // NvPowerOn() |
979 | | // |
980 | | // This function is called at _TPM_Init() to initialize the NV environment. |
981 | | // |
982 | | // Return Value Meaning |
983 | | // |
984 | | // TRUE all NV was initialized |
985 | | // FALSE the NV containing saved state had an error and |
986 | | // TPM2_Startup(CLEAR) is required |
987 | | // |
988 | | BOOL |
989 | | NvPowerOn( |
990 | | void |
991 | | ) |
992 | 213 | { |
993 | 213 | int nvError = 0; |
994 | | // If power was lost, need to re-establish the RAM data that is loaded from |
995 | | // NV and initialize the static variables |
996 | 213 | if(_plat__WasPowerLost(TRUE)) |
997 | 213 | { |
998 | 213 | if((nvError = _plat__NVEnable(0)) < 0) |
999 | 0 | FAIL(FATAL_ERROR_NV_UNRECOVERABLE); |
1000 | 213 | NvInitStatic(); |
1001 | 213 | NvCheckAndMigrateIfNeeded(); |
1002 | 213 | } |
1003 | 213 | return nvError == 0; |
1004 | 213 | } |
1005 | | // |
1006 | | // |
1007 | | // NvStateSave() |
1008 | | // |
1009 | | // This function is used to cause the memory containing the RAM backed NV Indices to be written to NV. |
1010 | | // |
1011 | | void |
1012 | | NvStateSave( |
1013 | | void |
1014 | | ) |
1015 | 0 | { |
1016 | | // Write RAM backed NV Index info to NV |
1017 | | // No need to save s_ramIndexSize because we save it to NV whenever it is |
1018 | | // updated. |
1019 | 0 | _plat__NvMemoryWrite(s_ramIndexAddr, RAM_INDEX_SPACE, s_ramIndex); |
1020 | | // Set the flag so that an NV write happens before the command completes. |
1021 | 0 | g_updateNV = TRUE; |
1022 | 0 | return; |
1023 | 0 | } |
1024 | | // |
1025 | | // |
1026 | | // NvStateCapture() |
1027 | | // |
1028 | | // This function is used to capture the current state of RAM backed NV Indices in an external `copy`. |
1029 | | // It doesn't need to capture s_ramIndexSize since that value is always saved to flash when it is modified. |
1030 | | // |
1031 | | void NvStateCapture(BYTE copy[RAM_INDEX_SPACE]) |
1032 | 0 | { |
1033 | 0 | memcpy(copy, s_ramIndex, RAM_INDEX_SPACE); |
1034 | 0 | } |
1035 | | // |
1036 | | // |
1037 | | // NvStateRestore() |
1038 | | // |
1039 | | // This function is used to restore the current state of RAM backed NV Indices from an external `copy`. |
1040 | | // It doesn't need to restore s_ramIndexSize since that value is always saved to flash when it is modified. |
1041 | | // |
1042 | | void NvStateRestore(const BYTE copy[RAM_INDEX_SPACE]) |
1043 | 0 | { |
1044 | 0 | memcpy(s_ramIndex, copy, RAM_INDEX_SPACE); |
1045 | 0 | g_nvStatePreserved = TRUE; |
1046 | 0 | } |
1047 | | // |
1048 | | // |
1049 | | // |
1050 | | // NvEntityStartup() |
1051 | | // |
1052 | | // This function is called at TPM_Startup(). If the startup completes a TPM Resume cycle, no action is |
1053 | | // taken. If the startup is a TPM Reset or a TPM Restart, then this function will: |
1054 | | // a) clear read/write lock; |
1055 | | // b) reset NV Index data that has TPMA_NV_CLEAR_STCLEAR SET; and |
1056 | | // c) set the lower bits in orderly counters to 1 for a non-orderly startup |
1057 | | // It is a prerequisite that NV be available for writing before this function is called. |
1058 | | // |
1059 | | void |
1060 | | NvEntityStartup( |
1061 | | STARTUP_TYPE type // IN: start up type |
1062 | | ) |
1063 | 213 | { |
1064 | 213 | NV_ITER iter = NV_ITER_INIT; |
1065 | 213 | UINT32 currentAddr; // offset points to the current entity |
1066 | 213 | BOOL nvStatePreserved = g_nvStatePreserved; |
1067 | | |
1068 | 213 | g_nvStatePreserved = FALSE; |
1069 | | // Restore RAM index size |
1070 | 213 | _plat__NvMemoryRead(s_ramIndexSizeAddr, sizeof(UINT32), &s_ramIndexSize); |
1071 | 213 | if (!nvStatePreserved) |
1072 | 213 | { |
1073 | | // Restore RAM index data |
1074 | 213 | _plat__NvMemoryRead(s_ramIndexAddr, RAM_INDEX_SPACE, s_ramIndex); |
1075 | 213 | NvCleanBadFromRAM(); |
1076 | 213 | } |
1077 | | // If recovering from state save, do nothing |
1078 | 213 | if(type == SU_RESUME) |
1079 | 0 | return; |
1080 | | // Iterate all the NV Index to clear the locks |
1081 | 213 | while((currentAddr = NvNextIndex(&iter)) != 0) |
1082 | 0 | { |
1083 | 0 | NV_INDEX nvIndex; |
1084 | 0 | UINT32 indexAddr; // NV address points to index info |
1085 | 0 | TPMA_NV attributes; |
1086 | 0 | UINT32 attributesValue; |
1087 | 0 | UINT32 publicAreaAttributesValue; |
1088 | 0 | indexAddr = currentAddr + sizeof(TPM_HANDLE); |
1089 | | // Read NV Index info structure |
1090 | 0 | _plat__NvMemoryRead(indexAddr, sizeof(NV_INDEX), &nvIndex); |
1091 | 0 | attributes = nvIndex.publicArea.attributes; |
1092 | | // Clear read/write lock |
1093 | 0 | if(attributes.TPMA_NV_READLOCKED == SET) |
1094 | 0 | attributes.TPMA_NV_READLOCKED = CLEAR; |
1095 | 0 | if( attributes.TPMA_NV_WRITELOCKED == SET |
1096 | 0 | && ( attributes.TPMA_NV_WRITTEN == CLEAR |
1097 | 0 | || attributes.TPMA_NV_WRITEDEFINE == CLEAR |
1098 | 0 | ) |
1099 | 0 | ) |
1100 | 0 | attributes.TPMA_NV_WRITELOCKED = CLEAR; |
1101 | | // Reset NV data for TPMA_NV_CLEAR_STCLEAR |
1102 | 0 | if(attributes.TPMA_NV_CLEAR_STCLEAR == SET) |
1103 | 0 | { |
1104 | 0 | attributes.TPMA_NV_WRITTEN = CLEAR; |
1105 | 0 | attributes.TPMA_NV_WRITELOCKED = CLEAR; |
1106 | 0 | } |
1107 | | // Reset NV data for orderly values that are not counters |
1108 | | // NOTE: The function has already exited on a TPM Resume, so the only |
1109 | | // things being processed are TPM Restart and TPM Reset |
1110 | 0 | if( type == SU_RESET |
1111 | 0 | && attributes.TPMA_NV_ORDERLY == SET |
1112 | 0 | && attributes.TPMA_NV_COUNTER == CLEAR |
1113 | 0 | ) |
1114 | 0 | attributes.TPMA_NV_WRITTEN = CLEAR; |
1115 | | // Write NV Index info back if it has changed |
1116 | 0 | memcpy(&attributesValue, &attributes, sizeof(attributesValue)); |
1117 | 0 | memcpy(&publicAreaAttributesValue, &nvIndex.publicArea.attributes, |
1118 | 0 | sizeof(publicAreaAttributesValue)); |
1119 | 0 | if(attributesValue != publicAreaAttributesValue) |
1120 | 0 | { |
1121 | 0 | nvIndex.publicArea.attributes = attributes; |
1122 | 0 | _plat__NvMemoryWrite(indexAddr, sizeof(NV_INDEX), &nvIndex); |
1123 | | // Set the flag that a NV write happens |
1124 | 0 | g_updateNV = TRUE; |
1125 | 0 | } |
1126 | | // Set the lower bits in an orderly counter to 1 for a non-orderly startup |
1127 | | // unless the state was restored for them. |
1128 | 0 | if( g_prevOrderlyState == SHUTDOWN_NONE |
1129 | 0 | && attributes.TPMA_NV_WRITTEN == SET |
1130 | 0 | && !nvStatePreserved) |
1131 | 0 | { |
1132 | 0 | if( attributes.TPMA_NV_ORDERLY == SET |
1133 | 0 | && attributes.TPMA_NV_COUNTER == SET) |
1134 | 0 | { |
1135 | 0 | TPMI_RH_NV_INDEX nvHandle; |
1136 | 0 | UINT64 counter; |
1137 | | // Read NV handle |
1138 | 0 | _plat__NvMemoryRead(currentAddr, sizeof(TPM_HANDLE), &nvHandle); |
1139 | | // Read the counter value saved to NV upon the last roll over. |
1140 | | // Do not use RAM backed storage for this once. |
1141 | 0 | nvIndex.publicArea.attributes.TPMA_NV_ORDERLY = CLEAR; |
1142 | 0 | NvGetIntIndexData(nvHandle, &nvIndex, &counter); |
1143 | 0 | nvIndex.publicArea.attributes.TPMA_NV_ORDERLY = SET; |
1144 | | // Set the lower bits of counter to 1's |
1145 | 0 | counter |= MAX_ORDERLY_COUNT; |
1146 | | // Write back to RAM |
1147 | 0 | NvWriteIndexData(nvHandle, &nvIndex, 0, sizeof(counter), &counter); |
1148 | | // No write to NV because an orderly shutdown will update the |
1149 | | // counters. |
1150 | 0 | } |
1151 | 0 | } |
1152 | 0 | } |
1153 | 213 | return; |
1154 | 213 | } |
1155 | | // |
1156 | | // |
1157 | | // NV Access Functions |
1158 | | // |
1159 | | // Introduction |
1160 | | // |
1161 | | // This set of functions provide accessing NV Index and persistent objects based using a handle for |
1162 | | // reference to the entity. |
1163 | | // |
1164 | | // NvIsUndefinedIndex() |
1165 | | // |
1166 | | // This function is used to verify that an NV Index is not defined. This is only used by |
1167 | | // TPM2_NV_DefineSpace(). |
1168 | | // |
1169 | | // |
1170 | | // |
1171 | | // |
1172 | | // Return Value Meaning |
1173 | | // |
1174 | | // TRUE the handle points to an existing NV Index |
1175 | | // FALSE the handle points to a non-existent Index |
1176 | | // |
1177 | | BOOL |
1178 | | NvIsUndefinedIndex( |
1179 | | TPMI_RH_NV_INDEX handle // IN: handle |
1180 | | ) |
1181 | 0 | { |
1182 | 0 | UINT32 entityAddr; // offset points to the entity |
1183 | 0 | pAssert(HandleGetType(handle) == TPM_HT_NV_INDEX); |
1184 | | // Find the address of index |
1185 | 0 | entityAddr = NvFindHandle(handle); |
1186 | | // If handle is not found, return TPM_RC_SUCCESS |
1187 | 0 | if(entityAddr == 0) |
1188 | 0 | return TPM_RC_SUCCESS; |
1189 | | // NV Index is defined |
1190 | 0 | return TPM_RC_NV_DEFINED; |
1191 | 0 | } |
1192 | | // |
1193 | | // |
1194 | | // NvIndexIsAccessible() |
1195 | | // |
1196 | | // This function validates that a handle references a defined NV Index and that the Index is currently |
1197 | | // accessible. |
1198 | | // |
1199 | | // Error Returns Meaning |
1200 | | // |
1201 | | // TPM_RC_HANDLE the handle points to an undefined NV Index If shEnable is CLEAR, |
1202 | | // this would include an index created using ownerAuth. If phEnableNV |
1203 | | // is CLEAR, this would include and index created using platform auth |
1204 | | // TPM_RC_NV_READLOCKED Index is present but locked for reading and command does not write |
1205 | | // to the index |
1206 | | // TPM_RC_NV_WRITELOCKED Index is present but locked for writing and command writes to the |
1207 | | // index |
1208 | | // |
1209 | | TPM_RC |
1210 | | NvIndexIsAccessible( |
1211 | | TPMI_RH_NV_INDEX handle, // IN: handle |
1212 | | TPM_CC commandCode // IN: the command |
1213 | | ) |
1214 | 1 | { |
1215 | 1 | UINT32 entityAddr; // offset points to the entity |
1216 | 1 | NV_INDEX nvIndex; // |
1217 | 1 | pAssert(HandleGetType(handle) == TPM_HT_NV_INDEX); |
1218 | | // Find the address of index |
1219 | 1 | entityAddr = NvFindHandle(handle); |
1220 | | // If handle is not found, return TPM_RC_HANDLE |
1221 | 1 | if(entityAddr == 0) |
1222 | 1 | return TPM_RC_HANDLE; |
1223 | | // Read NV Index info structure |
1224 | 0 | _plat__NvMemoryRead(entityAddr + sizeof(TPM_HANDLE), sizeof(NV_INDEX), |
1225 | 0 | &nvIndex); |
1226 | 0 | if(gc.shEnable == FALSE || gc.phEnableNV == FALSE) |
1227 | 0 | { |
1228 | | // if shEnable is CLEAR, an ownerCreate NV Index should not be |
1229 | | // indicated as present |
1230 | 0 | if(nvIndex.publicArea.attributes.TPMA_NV_PLATFORMCREATE == CLEAR) |
1231 | 0 | { |
1232 | | /* |
1233 | | * FWMP is a Chrome OS specific object saved at address 0x100a, it |
1234 | | * needs to be available for reading even before TPM2_Startup |
1235 | | * command is issued. |
1236 | | */ |
1237 | 0 | UINT32 isFwmpRead = (handle == 0x100100a) && |
1238 | 0 | IsReadOperation(commandCode); |
1239 | |
|
1240 | 0 | if((gc.shEnable == FALSE) && !isFwmpRead) |
1241 | 0 | return TPM_RC_HANDLE; |
1242 | 0 | } |
1243 | | // if phEnableNV is CLEAR, a platform created Index should not |
1244 | | // be visible |
1245 | 0 | else if(gc.phEnableNV == FALSE) |
1246 | 0 | return TPM_RC_HANDLE; |
1247 | 0 | } |
1248 | | // If the Index is write locked and this is an NV Write operation... |
1249 | 0 | if( nvIndex.publicArea.attributes.TPMA_NV_WRITELOCKED |
1250 | 0 | && IsWriteOperation(commandCode)) |
1251 | 0 | { |
1252 | | // then return a locked indication unless the command is TPM2_NV_WriteLock |
1253 | 0 | if(commandCode != TPM_CC_NV_WriteLock) |
1254 | 0 | return TPM_RC_NV_LOCKED; |
1255 | 0 | return TPM_RC_SUCCESS; |
1256 | 0 | } |
1257 | | // If the Index is read locked and this is an NV Read operation... |
1258 | 0 | if( nvIndex.publicArea.attributes.TPMA_NV_READLOCKED |
1259 | 0 | && IsReadOperation(commandCode)) |
1260 | 0 | { |
1261 | | // then return a locked indication unless the command is TPM2_NV_ReadLock |
1262 | 0 | if(commandCode != TPM_CC_NV_ReadLock) |
1263 | 0 | return TPM_RC_NV_LOCKED; |
1264 | 0 | return TPM_RC_SUCCESS; |
1265 | 0 | } |
1266 | | // NV Index is accessible |
1267 | 0 | return TPM_RC_SUCCESS; |
1268 | 0 | } |
1269 | | // |
1270 | | // |
1271 | | // NvIsUndefinedEvictHandle() |
1272 | | // |
1273 | | // This function indicates if a handle does not reference an existing persistent object. This function requires |
1274 | | // that the handle be in the proper range for persistent objects. |
1275 | | // |
1276 | | // Return Value Meaning |
1277 | | // |
1278 | | // TRUE handle does not reference an existing persistent object |
1279 | | // FALSE handle does reference an existing persistent object |
1280 | | // |
1281 | | static BOOL |
1282 | | NvIsUndefinedEvictHandle( |
1283 | | TPM_HANDLE handle // IN: handle |
1284 | | ) |
1285 | 0 | { |
1286 | 0 | UINT32 entityAddr; // offset points to the entity |
1287 | 0 | pAssert(HandleGetType(handle) == TPM_HT_PERSISTENT); |
1288 | | // Find the address of evict object |
1289 | 0 | entityAddr = NvFindHandle(handle); |
1290 | | // If handle is not found, return TRUE |
1291 | 0 | if(entityAddr == 0) |
1292 | 0 | return TRUE; |
1293 | 0 | else |
1294 | 0 | return FALSE; |
1295 | 0 | } |
1296 | | |
1297 | | // |
1298 | | // |
1299 | | // NvUnmarshalObject() |
1300 | | // |
1301 | | // This function accepts a buffer containing a marshaled OBJECT |
1302 | | // structure, a pointer to the area where the input data should be |
1303 | | // unmarshaled, and a pointer to the size of the output area. |
1304 | | // |
1305 | | // No error checking is performed, unmarshaled data is guaranteed not to |
1306 | | // spill over the allocated space. |
1307 | | // |
1308 | | static TPM_RC NvUnmarshalObject(OBJECT *o, BYTE **buf, INT32 *size) |
1309 | 0 | { |
1310 | 0 | TPM_RC result; |
1311 | | |
1312 | | // There is no generated function to unmarshal the attributes field, do it |
1313 | | // by hand. |
1314 | 0 | MemoryCopy(&o->attributes, *buf, sizeof(o->attributes), *size); |
1315 | 0 | *buf += sizeof(o->attributes); |
1316 | 0 | *size -= sizeof(o->attributes); |
1317 | |
|
1318 | 0 | result = TPMT_PUBLIC_Unmarshal(&o->publicArea, buf, size); |
1319 | 0 | if (result != TPM_RC_SUCCESS) |
1320 | 0 | return result; |
1321 | | |
1322 | 0 | result = TPMT_SENSITIVE_Unmarshal(&o->sensitive, buf, size); |
1323 | 0 | if (result != TPM_RC_SUCCESS) |
1324 | 0 | return result; |
1325 | | |
1326 | 0 | #ifdef TPM_ALG_RSA |
1327 | 0 | result = TPM2B_PUBLIC_KEY_RSA_Unmarshal(&o->privateExponent, buf, size); |
1328 | 0 | if (result != TPM_RC_SUCCESS) |
1329 | 0 | return result; |
1330 | 0 | #endif |
1331 | | |
1332 | 0 | result = TPM2B_NAME_Unmarshal(&o->qualifiedName, buf, size); |
1333 | 0 | if (result != TPM_RC_SUCCESS) |
1334 | 0 | return result; |
1335 | | |
1336 | 0 | result = TPMI_DH_OBJECT_Unmarshal(&o->evictHandle, buf, size, TRUE); |
1337 | 0 | if (result != TPM_RC_SUCCESS) |
1338 | 0 | return result; |
1339 | | |
1340 | 0 | return TPM2B_NAME_Unmarshal(&o->name, buf, size); |
1341 | 0 | } |
1342 | | |
1343 | | // |
1344 | | // |
1345 | | // NvGetEvictObject() |
1346 | | // |
1347 | | // This function is used to dereference an evict object handle and get a pointer to the object. |
1348 | | // |
1349 | | // Error Returns Meaning |
1350 | | // |
1351 | | // TPM_RC_HANDLE the handle does not point to an existing persistent object |
1352 | | // |
1353 | | TPM_RC |
1354 | | NvGetEvictObject( |
1355 | | TPM_HANDLE handle, // IN: handle |
1356 | | OBJECT *object // OUT: object data |
1357 | | ) |
1358 | 0 | { |
1359 | 0 | UINT32 entityAddr; // offset points to the entity |
1360 | 0 | TPM_RC result = TPM_RC_SUCCESS; |
1361 | 0 | pAssert(HandleGetType(handle) == TPM_HT_PERSISTENT); |
1362 | | // Find the address of evict object |
1363 | 0 | entityAddr = NvFindHandle(handle); |
1364 | | // If handle is not found, return an error |
1365 | 0 | if(entityAddr == 0) { |
1366 | 0 | result = TPM_RC_HANDLE; |
1367 | 0 | } else { |
1368 | 0 | UINT32 storedSize; |
1369 | 0 | UINT32 nextEntryAddr; |
1370 | | |
1371 | | // Let's calculate the size of object as stored in NVMEM. |
1372 | 0 | _plat__NvMemoryRead(entityAddr - sizeof(UINT32), |
1373 | 0 | sizeof(UINT32), &nextEntryAddr); |
1374 | |
|
1375 | 0 | storedSize = nextEntryAddr - entityAddr; |
1376 | |
|
1377 | 0 | if (storedSize == (sizeof(TPM_HANDLE) + sizeof(OBJECT))) { |
1378 | | // Read evict object stored unmarshaled. |
1379 | 0 | _plat__NvMemoryRead(entityAddr + sizeof(TPM_HANDLE), |
1380 | 0 | sizeof(OBJECT), |
1381 | 0 | object); |
1382 | 0 | } else { |
1383 | | // Must be stored marshaled, let's unmarshal it. |
1384 | 0 | BYTE marshaled[sizeof(OBJECT)]; |
1385 | 0 | INT32 max_size = sizeof(marshaled); |
1386 | 0 | BYTE *marshaledPtr = marshaled; |
1387 | |
|
1388 | 0 | _plat__NvMemoryRead(entityAddr + sizeof(TPM_HANDLE), |
1389 | 0 | storedSize, marshaled); |
1390 | 0 | result = NvUnmarshalObject(object, &marshaledPtr, &max_size); |
1391 | 0 | } |
1392 | 0 | } |
1393 | | // whether there is an error or not, make sure that the evict |
1394 | | // status of the object is set so that the slot will get freed on exit |
1395 | 0 | object->attributes.evict = SET; |
1396 | 0 | return result; |
1397 | 0 | } |
1398 | | // |
1399 | | // |
1400 | | // NvGetIndexInfo() |
1401 | | // |
1402 | | // This function is used to retrieve the contents of an NV Index. |
1403 | | // An implementation is allowed to save the NV Index in a vendor-defined format. If the format is different |
1404 | | // from the default used by the reference code, then this function would be changed to reformat the data into |
1405 | | // the default format. |
1406 | | // A prerequisite to calling this function is that the handle must be known to reference a defined NV Index. |
1407 | | // |
1408 | | void |
1409 | | NvGetIndexInfo( |
1410 | | TPMI_RH_NV_INDEX handle, // IN: handle |
1411 | | NV_INDEX *nvIndex // OUT: NV index structure |
1412 | | ) |
1413 | 0 | { |
1414 | 0 | NvReadIndexInfo(handle, 0, nvIndex); |
1415 | 0 | return; |
1416 | 0 | } |
1417 | | // |
1418 | | // |
1419 | | // NvReadIndexInfo() |
1420 | | // |
1421 | | // This function is used to retrieve the contents of an NV Index from the |
1422 | | // given address. |
1423 | | // A prerequisite to calling this function is that either handle or |
1424 | | // entityAddr must be valid value. If entityAddr is non-zero, then it will |
1425 | | // be regarded as a valid address of NV data. If it is zero, then "handle" |
1426 | | // shall be used to find its address. |
1427 | | // |
1428 | | void |
1429 | | NvReadIndexInfo( |
1430 | | TPMI_RH_NV_INDEX handle, // IN: handle |
1431 | | UINT32 entityAddr, // IN: Base address of NV data |
1432 | | NV_INDEX *nvIndex // OUT: NV index structure |
1433 | | ) |
1434 | 0 | { |
1435 | 0 | if (!entityAddr) { |
1436 | 0 | pAssert(HandleGetType(handle) == TPM_HT_NV_INDEX); |
1437 | | // Find the address of NV index |
1438 | 0 | entityAddr = NvFindHandle(handle); |
1439 | 0 | } |
1440 | |
|
1441 | 0 | pAssert(entityAddr != 0); |
1442 | | // This implementation uses the default format so just |
1443 | | // read the data in |
1444 | 0 | _plat__NvMemoryRead(entityAddr + sizeof(TPM_HANDLE), sizeof(NV_INDEX), |
1445 | 0 | nvIndex); |
1446 | 0 | return; |
1447 | 0 | } |
1448 | | // |
1449 | | // |
1450 | | // NvInitialCounter() |
1451 | | // |
1452 | | // This function returns the value to be used when a counter index is initialized. It will scan the NV counters |
1453 | | // and find the highest value in any active counter. It will use that value as the starting point. If there are no |
1454 | | // active counters, it will use the value of the previous largest counter. |
1455 | | // |
1456 | | UINT64 |
1457 | | NvInitialCounter( |
1458 | | void |
1459 | | ) |
1460 | 0 | { |
1461 | 0 | UINT64 maxCount; |
1462 | 0 | NV_ITER iter = NV_ITER_INIT; |
1463 | 0 | UINT32 currentAddr; |
1464 | | // Read the maxCount value |
1465 | 0 | maxCount = NvReadMaxCount(); |
1466 | | // Iterate all existing counters |
1467 | 0 | while((currentAddr = NvNextIndex(&iter)) != 0) |
1468 | 0 | { |
1469 | 0 | TPMI_RH_NV_INDEX nvHandle; |
1470 | 0 | NV_INDEX nvIndex; |
1471 | | // Read NV handle |
1472 | 0 | _plat__NvMemoryRead(currentAddr, sizeof(TPM_HANDLE), &nvHandle); |
1473 | | // Get NV Index |
1474 | 0 | NvGetIndexInfo(nvHandle, &nvIndex); |
1475 | 0 | if( nvIndex.publicArea.attributes.TPMA_NV_COUNTER == SET |
1476 | 0 | && nvIndex.publicArea.attributes.TPMA_NV_WRITTEN == SET) |
1477 | 0 | { |
1478 | 0 | UINT64 countValue; |
1479 | | // Read counter value |
1480 | 0 | NvGetIntIndexData(nvHandle, &nvIndex, &countValue); |
1481 | 0 | if(countValue > maxCount) |
1482 | 0 | maxCount = countValue; |
1483 | 0 | } |
1484 | 0 | } |
1485 | | // Initialize the new counter value to be maxCount + 1 |
1486 | | // A counter is only initialized the first time it is written. The |
1487 | | // way to write a counter is with TPM2_NV_INCREMENT(). Since the |
1488 | | // "initial" value of a defined counter is the largest count value that |
1489 | | // may have existed in this index previously, then the first use would |
1490 | | // add one to that value. |
1491 | 0 | return maxCount; |
1492 | 0 | } |
1493 | | // |
1494 | | // |
1495 | | // NvGetIndexData() |
1496 | | // |
1497 | | // This function is used to access the data in an NV Index. The data is returned as a byte sequence. Since |
1498 | | // counter values are kept in native format, they are converted to canonical form before being returned. |
1499 | | // Family "2.0" TCG Published Page 139 |
1500 | | // Level 00 Revision 01.16 Copyright © TCG 2006-2014 October 30, 2014 |
1501 | | // Trusted Platform Module Library Part 4: Supporting Routines |
1502 | | // |
1503 | | // |
1504 | | // This function requires that the NV Index be defined, and that the required data is within the data range. It |
1505 | | // also requires that TPMA_NV_WRITTEN of the Index is SET. |
1506 | | // |
1507 | | void |
1508 | | NvGetIndexData( |
1509 | | TPMI_RH_NV_INDEX handle, // IN: handle |
1510 | | NV_INDEX *nvIndex, // IN: RAM image of index header |
1511 | | UINT32 offset, // IN: offset of NV data |
1512 | | UINT16 size, // IN: size of NV data |
1513 | | void *data // OUT: data buffer |
1514 | | ) |
1515 | 0 | { |
1516 | 0 | NvReadIndexData(handle, nvIndex, 0, offset, size, data); |
1517 | 0 | } |
1518 | | // |
1519 | | // |
1520 | | // NvReadIndexData() |
1521 | | // |
1522 | | // This function is used to read the data in an NV Index from the given address. |
1523 | | // This function requires that the NV Index be defined, and that the required |
1524 | | // data is within the data range. It also requires that TPMA_NV_WRITTEN of the |
1525 | | // Index is SET. |
1526 | | // entityAddr is optional. If the value is zero, then it will be retrieved |
1527 | | // by calling NvFindHandle() in this function. |
1528 | | // |
1529 | | void |
1530 | | NvReadIndexData( |
1531 | | TPMI_RH_NV_INDEX handle, // IN: handle |
1532 | | NV_INDEX *nvIndex, // IN: RAM image of index header |
1533 | | UINT32 entityAddr, // IN: Base address of NV data |
1534 | | UINT32 offset, // IN: offset of NV data |
1535 | | UINT16 size, // IN: size of NV data |
1536 | | void *data // OUT: data buffer |
1537 | | ) |
1538 | 0 | { |
1539 | 0 | pAssert(nvIndex->publicArea.attributes.TPMA_NV_WRITTEN == SET); |
1540 | 0 | if( nvIndex->publicArea.attributes.TPMA_NV_BITS == SET |
1541 | 0 | || nvIndex->publicArea.attributes.TPMA_NV_COUNTER == SET) |
1542 | 0 | { |
1543 | | // Read bit or counter data in canonical form |
1544 | 0 | UINT64 dataInInt; |
1545 | 0 | NvGetIntIndexData(handle, nvIndex, &dataInInt); |
1546 | 0 | UINT64_TO_BYTE_ARRAY(dataInInt, (BYTE *)data); |
1547 | 0 | } |
1548 | 0 | else |
1549 | 0 | { |
1550 | 0 | if(nvIndex->publicArea.attributes.TPMA_NV_ORDERLY == SET) |
1551 | 0 | { |
1552 | 0 | UINT32 ramAddr; |
1553 | | // Get data from RAM buffer |
1554 | 0 | ramAddr = NvGetRAMIndexOffset(handle); |
1555 | 0 | if(ramAddr + offset + size <= s_ramIndexSize) |
1556 | 0 | { |
1557 | 0 | MemoryCopy(data, s_ramIndex + ramAddr + offset, size, size); |
1558 | 0 | } |
1559 | 0 | else |
1560 | 0 | { |
1561 | 0 | MemorySet(data, 0x00, size); |
1562 | 0 | } |
1563 | 0 | } |
1564 | 0 | else |
1565 | 0 | { |
1566 | 0 | if (!entityAddr) |
1567 | 0 | entityAddr = NvFindHandle(handle); |
1568 | 0 | pAssert(entityAddr != 0); |
1569 | | // Get data from NV |
1570 | | // Skip NV Index info, read data buffer |
1571 | 0 | entityAddr += sizeof(TPM_HANDLE) + sizeof(NV_INDEX) + offset; |
1572 | | // Read the data |
1573 | 0 | _plat__NvMemoryRead(entityAddr, size, data); |
1574 | 0 | } |
1575 | 0 | } |
1576 | 0 | return; |
1577 | 0 | } |
1578 | | // |
1579 | | // |
1580 | | // NvGetIntIndexData() |
1581 | | // |
1582 | | // Get data in integer format of a bit or counter NV Index. |
1583 | | // This function requires that the NV Index is defined and that the NV Index previously has been written. |
1584 | | // |
1585 | | void |
1586 | | NvGetIntIndexData( |
1587 | | TPMI_RH_NV_INDEX handle, // IN: handle |
1588 | | NV_INDEX *nvIndex, // IN: RAM image of NV Index header |
1589 | | UINT64 *data // IN: UINT64 pointer for counter or bit |
1590 | | ) |
1591 | 0 | { |
1592 | | // Validate that index has been written and is the right type |
1593 | 0 | pAssert( nvIndex->publicArea.attributes.TPMA_NV_WRITTEN == SET |
1594 | 0 | && ( nvIndex->publicArea.attributes.TPMA_NV_BITS == SET |
1595 | 0 | || nvIndex->publicArea.attributes.TPMA_NV_COUNTER == SET |
1596 | 0 | ) |
1597 | 0 | ); |
1598 | | // bit and counter value is store in native format for TPM CPU. So we directly |
1599 | | // copy the contents of NV to output data buffer |
1600 | 0 | if(nvIndex->publicArea.attributes.TPMA_NV_ORDERLY == SET) |
1601 | 0 | { |
1602 | 0 | UINT32 ramAddr; |
1603 | | // Get data from RAM buffer |
1604 | 0 | ramAddr = NvGetRAMIndexOffset(handle); |
1605 | 0 | if(ramAddr + sizeof(*data) <= s_ramIndexSize) |
1606 | 0 | { |
1607 | 0 | MemoryCopy(data, s_ramIndex + ramAddr, sizeof(*data), sizeof(*data)); |
1608 | 0 | } |
1609 | 0 | else if(ramAddr >= s_ramIndexSize) |
1610 | 0 | { |
1611 | | // No data space in RAM |
1612 | 0 | if(nvIndex->publicArea.attributes.TPMA_NV_COUNTER == SET) |
1613 | 0 | { |
1614 | 0 | *data = NvReadMaxCount(); |
1615 | 0 | } |
1616 | 0 | else |
1617 | 0 | { |
1618 | 0 | *data = 0; |
1619 | 0 | } |
1620 | | // Add missing data space at the end of reserved RAM buffer if possible |
1621 | 0 | if(NvTestRAMSpace(sizeof(*data))) |
1622 | 0 | { |
1623 | 0 | UINT32 size = sizeof(*data) + sizeof(TPMI_RH_NV_INDEX); |
1624 | 0 | memcpy(&s_ramIndex[s_ramIndexSize], &size, sizeof(size)); |
1625 | 0 | s_ramIndexSize += sizeof(UINT32); |
1626 | 0 | memcpy(&s_ramIndex[s_ramIndexSize], &handle, sizeof(handle)); |
1627 | 0 | s_ramIndexSize += sizeof(TPMI_RH_NV_INDEX); |
1628 | 0 | memcpy(&s_ramIndex[s_ramIndexSize], data, sizeof(*data)); |
1629 | 0 | s_ramIndexSize += sizeof(*data); |
1630 | 0 | _plat__NvMemoryWrite(s_ramIndexSizeAddr, sizeof(UINT32), &s_ramIndexSize); |
1631 | 0 | _plat__NvMemoryWrite(s_ramIndexAddr, RAM_INDEX_SPACE, s_ramIndex); |
1632 | 0 | g_updateNV = TRUE; |
1633 | 0 | } |
1634 | 0 | } |
1635 | 0 | } |
1636 | 0 | else |
1637 | 0 | { |
1638 | 0 | UINT32 entityAddr; |
1639 | 0 | entityAddr = NvFindHandle(handle); |
1640 | | // Get data from NV |
1641 | | // Skip NV Index info, read data buffer |
1642 | 0 | _plat__NvMemoryRead( |
1643 | 0 | entityAddr + sizeof(TPM_HANDLE) + sizeof(NV_INDEX), |
1644 | 0 | sizeof(UINT64), data); |
1645 | 0 | } |
1646 | 0 | return; |
1647 | 0 | } |
1648 | | // |
1649 | | // |
1650 | | // NvWriteIndexInfo() |
1651 | | // |
1652 | | // This function is called to queue the write of NV Index data to persistent memory. |
1653 | | // This function requires that NV Index is defined. |
1654 | | // |
1655 | | // Error Returns Meaning |
1656 | | // |
1657 | | // TPM_RC_NV_RATE NV is rate limiting so retry |
1658 | | // TPM_RC_NV_UNAVAILABLE NV is not available |
1659 | | // |
1660 | | TPM_RC |
1661 | | NvWriteIndexInfo( |
1662 | | TPMI_RH_NV_INDEX handle, // IN: handle |
1663 | | NV_INDEX *nvIndex // IN: NV Index info to be written |
1664 | | ) |
1665 | 0 | { |
1666 | 0 | UINT32 entryAddr; |
1667 | 0 | TPM_RC result; |
1668 | | // Get the starting offset for the index in the RAM image of NV |
1669 | 0 | entryAddr = NvFindHandle(handle); |
1670 | 0 | pAssert(entryAddr != 0); |
1671 | | // Step over the link value |
1672 | 0 | entryAddr = entryAddr + sizeof(TPM_HANDLE); |
1673 | | // If the index data is actually changed, then a write to NV is required |
1674 | 0 | if(_plat__NvIsDifferent(entryAddr, sizeof(NV_INDEX),nvIndex)) |
1675 | 0 | { |
1676 | | // Make sure that NV is available |
1677 | 0 | result = NvIsAvailable(); |
1678 | 0 | if(result != TPM_RC_SUCCESS) |
1679 | 0 | return result; |
1680 | 0 | _plat__NvMemoryWrite(entryAddr, sizeof(NV_INDEX), nvIndex); |
1681 | 0 | g_updateNV = TRUE; |
1682 | 0 | } |
1683 | 0 | return TPM_RC_SUCCESS; |
1684 | 0 | } |
1685 | | // |
1686 | | // |
1687 | | // NvWriteIndexData() |
1688 | | // |
1689 | | // This function is used to write NV index data. |
1690 | | // This function requires that the NV Index is defined, and the data is within the defined data range for the |
1691 | | // index. |
1692 | | // |
1693 | | // Error Returns Meaning |
1694 | | // |
1695 | | // TPM_RC_NV_RATE NV is rate limiting so retry |
1696 | | // TPM_RC_NV_UNAVAILABLE NV is not available |
1697 | | // |
1698 | | TPM_RC |
1699 | | NvWriteIndexData( |
1700 | | TPMI_RH_NV_INDEX handle, // IN: handle |
1701 | | NV_INDEX *nvIndex, // IN: RAM copy of NV Index |
1702 | | UINT32 offset, // IN: offset of NV data |
1703 | | UINT32 size, // IN: size of NV data |
1704 | | void *data // OUT: data buffer |
1705 | | ) |
1706 | 0 | { |
1707 | 0 | TPM_RC result; |
1708 | | // Validate that write falls within range of the index |
1709 | 0 | pAssert(nvIndex->publicArea.dataSize >= offset + size); |
1710 | | // Update TPMA_NV_WRITTEN bit if necessary |
1711 | 0 | if(nvIndex->publicArea.attributes.TPMA_NV_WRITTEN == CLEAR) |
1712 | 0 | { |
1713 | 0 | nvIndex->publicArea.attributes.TPMA_NV_WRITTEN = SET; |
1714 | 0 | result = NvWriteIndexInfo(handle, nvIndex); |
1715 | 0 | if(result != TPM_RC_SUCCESS) |
1716 | 0 | return result; |
1717 | 0 | } |
1718 | | // Check to see if process for an orderly index is required. |
1719 | 0 | if(nvIndex->publicArea.attributes.TPMA_NV_ORDERLY == SET) |
1720 | 0 | { |
1721 | 0 | UINT32 ramAddr; |
1722 | | // Write data to RAM buffer |
1723 | 0 | ramAddr = NvGetRAMIndexOffset(handle); |
1724 | 0 | if(ramAddr + offset + size <= s_ramIndexSize) |
1725 | 0 | { |
1726 | 0 | MemoryCopy(s_ramIndex + ramAddr + offset, data, size, |
1727 | 0 | sizeof(s_ramIndex) - ramAddr - offset); |
1728 | 0 | } |
1729 | | // NV update does not happen for orderly index. Have |
1730 | | // to clear orderlyState to reflect that we have changed the |
1731 | | // NV and an orderly shutdown is required. Only going to do this if we |
1732 | | // are not processing a counter that has just rolled over |
1733 | 0 | if(g_updateNV == FALSE) |
1734 | 0 | g_clearOrderly = TRUE; |
1735 | 0 | } |
1736 | | // Need to process this part if the Index isn't orderly or if it is |
1737 | | // an orderly counter that just rolled over. |
1738 | 0 | if(g_updateNV || nvIndex->publicArea.attributes.TPMA_NV_ORDERLY == CLEAR) |
1739 | 0 | { |
1740 | | // Processing for an index with TPMA_NV_ORDERLY CLEAR |
1741 | 0 | UINT32 entryAddr = NvFindHandle(handle); |
1742 | 0 | pAssert(entryAddr != 0); |
1743 | | // |
1744 | | // Offset into the index to the first byte of the data to be written |
1745 | 0 | entryAddr += sizeof(TPM_HANDLE) + sizeof(NV_INDEX) + offset; |
1746 | | // If the data is actually changed, then a write to NV is required |
1747 | 0 | if(_plat__NvIsDifferent(entryAddr, size, data)) |
1748 | 0 | { |
1749 | | // Make sure that NV is available |
1750 | 0 | result = NvIsAvailable(); |
1751 | 0 | if(result != TPM_RC_SUCCESS) |
1752 | 0 | return result; |
1753 | 0 | _plat__NvMemoryWrite(entryAddr, size, data); |
1754 | 0 | g_updateNV = TRUE; |
1755 | 0 | } |
1756 | 0 | } |
1757 | 0 | return TPM_RC_SUCCESS; |
1758 | 0 | } |
1759 | | // |
1760 | | // |
1761 | | // NvGetName() |
1762 | | // |
1763 | | // This function is used to compute the Name of an NV Index. |
1764 | | // The name buffer receives the bytes of the Name and the return value is the number of octets in the |
1765 | | // Name. |
1766 | | // This function requires that the NV Index is defined. |
1767 | | // |
1768 | | UINT16 |
1769 | | NvGetName( |
1770 | | TPMI_RH_NV_INDEX handle, // IN: handle of the index |
1771 | | NAME *name // OUT: name of the index |
1772 | | ) |
1773 | 0 | { |
1774 | 0 | UINT16 dataSize, digestSize; |
1775 | 0 | NV_INDEX nvIndex; |
1776 | 0 | BYTE marshalBuffer[sizeof(TPMS_NV_PUBLIC)]; |
1777 | 0 | BYTE *buffer; |
1778 | 0 | INT32 bufferSize; |
1779 | 0 | HASH_STATE hashState; |
1780 | | // Get NV public info |
1781 | 0 | NvGetIndexInfo(handle, &nvIndex); |
1782 | | // Marshal public area |
1783 | 0 | buffer = marshalBuffer; |
1784 | 0 | bufferSize = sizeof(TPMS_NV_PUBLIC); |
1785 | 0 | dataSize = TPMS_NV_PUBLIC_Marshal(&nvIndex.publicArea, &buffer, &bufferSize); |
1786 | | // hash public area |
1787 | 0 | digestSize = CryptStartHash(nvIndex.publicArea.nameAlg, &hashState); |
1788 | 0 | CryptUpdateDigest(&hashState, dataSize, marshalBuffer); |
1789 | | // Complete digest leaving room for the nameAlg |
1790 | 0 | CryptCompleteHash(&hashState, digestSize, &((BYTE *)name)[2]); |
1791 | | // Include the nameAlg |
1792 | 0 | UINT16_TO_BYTE_ARRAY(nvIndex.publicArea.nameAlg, (BYTE *)name); |
1793 | 0 | return digestSize + 2; |
1794 | 0 | } |
1795 | | // |
1796 | | // |
1797 | | // NvDefineIndex() |
1798 | | // |
1799 | | // This function is used to assign NV memory to an NV Index. |
1800 | | // |
1801 | | // |
1802 | | // |
1803 | | // Error Returns Meaning |
1804 | | // |
1805 | | // TPM_RC_NV_SPACE insufficient NV space |
1806 | | // |
1807 | | TPM_RC |
1808 | | NvDefineIndex( |
1809 | | TPMS_NV_PUBLIC *publicArea, // IN: A template for an area to create. |
1810 | | TPM2B_AUTH *authValue // IN: The initial authorization value |
1811 | | ) |
1812 | 0 | { |
1813 | | // The buffer to be written to NV memory |
1814 | 0 | BYTE nvBuffer[sizeof(TPM_HANDLE) + sizeof(NV_INDEX)]; |
1815 | 0 | NV_INDEX *nvIndex; // a pointer to the NV_INDEX data in |
1816 | | // nvBuffer |
1817 | 0 | UINT16 entrySize; // size of entry |
1818 | 0 | entrySize = sizeof(TPM_HANDLE) + sizeof(NV_INDEX) + publicArea->dataSize; |
1819 | | // Check if we have enough space to create the NV Index |
1820 | | // In this implementation, the only resource limitation is the available NV |
1821 | | // space. Other implementation may have other limitation on counter or on |
1822 | | // NV slot |
1823 | 0 | if(!NvTestSpace(entrySize, TRUE)) return TPM_RC_NV_SPACE; |
1824 | | // if the index to be defined is RAM backed, check RAM space availability |
1825 | | // as well |
1826 | 0 | if(publicArea->attributes.TPMA_NV_ORDERLY == SET |
1827 | 0 | && !NvTestRAMSpace(publicArea->dataSize)) |
1828 | 0 | return TPM_RC_NV_SPACE; |
1829 | | // Copy input value to nvBuffer |
1830 | | // Copy handle |
1831 | 0 | memcpy(nvBuffer, &publicArea->nvIndex, sizeof(TPM_HANDLE)); |
1832 | | // Copy NV_INDEX |
1833 | 0 | nvIndex = (NV_INDEX *) (nvBuffer + sizeof(TPM_HANDLE)); |
1834 | 0 | nvIndex->publicArea = *publicArea; |
1835 | 0 | nvIndex->authValue = *authValue; |
1836 | | // Add index to NV memory |
1837 | 0 | NvAdd(entrySize, sizeof(TPM_HANDLE) + sizeof(NV_INDEX), nvBuffer); |
1838 | | // If the data of NV Index is RAM backed, add the data area in RAM as well |
1839 | 0 | if(publicArea->attributes.TPMA_NV_ORDERLY == SET) |
1840 | 0 | NvAddRAM(publicArea->nvIndex, publicArea->dataSize); |
1841 | 0 | return TPM_RC_SUCCESS; |
1842 | 0 | } |
1843 | | |
1844 | | // |
1845 | | // |
1846 | | // NvMarshalObject() |
1847 | | // |
1848 | | // This function marshals the passed in OBJECT structure into a buffer. A |
1849 | | // pointer to pointer to the buffer and a pointer to the size of the |
1850 | | // buffer are passed in for this function to update as appropriate. |
1851 | | // |
1852 | | // On top of marshaling the object, this function also modifies one of |
1853 | | // the object's properties and sets the evictHandle field of the |
1854 | | // marshaled object to the requested value. |
1855 | | // |
1856 | | // Returns |
1857 | | // |
1858 | | // Marshaled size of the object. |
1859 | | // |
1860 | | static UINT16 NvMarshalObject(OBJECT *o, TPMI_DH_OBJECT evictHandle, |
1861 | | BYTE **buf, INT32 *size) |
1862 | 0 | { |
1863 | 0 | UINT16 marshaledSize; |
1864 | 0 | OBJECT_ATTRIBUTES stored_attributes; |
1865 | |
|
1866 | 0 | stored_attributes = o->attributes; |
1867 | 0 | stored_attributes.evict = SET; |
1868 | 0 | marshaledSize = sizeof(stored_attributes); |
1869 | 0 | MemoryCopy(*buf, &stored_attributes, marshaledSize, *size); |
1870 | 0 | *buf += marshaledSize; |
1871 | 0 | *size -= marshaledSize; |
1872 | |
|
1873 | 0 | marshaledSize += TPMT_PUBLIC_Marshal(&o->publicArea, buf, size); |
1874 | 0 | marshaledSize += TPMT_SENSITIVE_Marshal(&o->sensitive, buf, size); |
1875 | 0 | #ifdef TPM_ALG_RSA |
1876 | 0 | marshaledSize += TPM2B_PUBLIC_KEY_RSA_Marshal(&o->privateExponent, |
1877 | 0 | buf, size); |
1878 | 0 | #endif |
1879 | 0 | marshaledSize += TPM2B_NAME_Marshal(&o->qualifiedName, buf, size); |
1880 | | |
1881 | | // Use the supplied handle instead of the object contents. |
1882 | 0 | marshaledSize += TPMI_DH_OBJECT_Marshal(&evictHandle, buf, size); |
1883 | 0 | marshaledSize += TPM2B_NAME_Marshal(&o->name, buf, size); |
1884 | |
|
1885 | 0 | return marshaledSize; |
1886 | 0 | } |
1887 | | |
1888 | | // |
1889 | | // |
1890 | | // NvAddEvictObject() |
1891 | | // |
1892 | | // This function is used to assign NV memory to a persistent object. |
1893 | | // |
1894 | | // Error Returns Meaning |
1895 | | // |
1896 | | // TPM_RC_NV_HANDLE the requested handle is already in use |
1897 | | // TPM_RC_NV_SPACE insufficient NV space |
1898 | | // |
1899 | | TPM_RC |
1900 | | NvAddEvictObject( |
1901 | | TPMI_DH_OBJECT evictHandle, // IN: new evict handle |
1902 | | // |
1903 | | OBJECT *object // IN: object to be added |
1904 | | ) |
1905 | 0 | { |
1906 | | // The buffer to be written to NV memory |
1907 | 0 | BYTE nvBuffer[sizeof(TPM_HANDLE) + sizeof(OBJECT)]; |
1908 | 0 | UINT16 entrySize; // size of entry |
1909 | 0 | BYTE *marshalSpace; |
1910 | 0 | INT32 marshalRoom; |
1911 | | |
1912 | | // evict handle type should match the object hierarchy |
1913 | 0 | pAssert( ( NvIsPlatformPersistentHandle(evictHandle) |
1914 | 0 | && object->attributes.ppsHierarchy == SET) |
1915 | 0 | || ( NvIsOwnerPersistentHandle(evictHandle) |
1916 | 0 | && ( object->attributes.spsHierarchy == SET |
1917 | 0 | || object->attributes.epsHierarchy == SET))); |
1918 | | |
1919 | | // Do not attemp storing a duplicate handle. |
1920 | 0 | if(!NvIsUndefinedEvictHandle(evictHandle)) |
1921 | 0 | return TPM_RC_NV_DEFINED; |
1922 | | |
1923 | | // Copy handle |
1924 | 0 | entrySize = sizeof(TPM_HANDLE); |
1925 | 0 | memcpy(nvBuffer, &evictHandle, entrySize); |
1926 | | |
1927 | | // Let's serialize the object before storing it in NVMEM |
1928 | 0 | marshalSpace = nvBuffer + entrySize; |
1929 | 0 | marshalRoom = sizeof(nvBuffer) - entrySize; |
1930 | 0 | entrySize += NvMarshalObject(object, evictHandle, |
1931 | 0 | &marshalSpace, &marshalRoom); |
1932 | | |
1933 | | // Check if we have enough space to add this evict object |
1934 | 0 | if(!NvTestSpace(entrySize, FALSE)) return TPM_RC_NV_SPACE; |
1935 | | |
1936 | | // Add evict to NV memory |
1937 | 0 | NvAdd(entrySize, entrySize, nvBuffer); |
1938 | 0 | return TPM_RC_SUCCESS; |
1939 | 0 | } |
1940 | | // |
1941 | | // |
1942 | | // NvDeleteEntity() |
1943 | | // |
1944 | | // This function will delete a NV Index or an evict object. |
1945 | | // This function requires that the index/evict object has been defined. |
1946 | | // |
1947 | | void |
1948 | | NvDeleteEntity( |
1949 | | TPM_HANDLE handle // IN: handle of entity to be deleted |
1950 | | ) |
1951 | 0 | { |
1952 | 0 | UINT32 entityAddr; // pointer to entity |
1953 | | |
1954 | | // Deleting virtual NV indexes is not supported. |
1955 | 0 | if(_plat__NvGetHandleVirtualOffset(handle) != 0) |
1956 | 0 | { |
1957 | 0 | return; |
1958 | 0 | } |
1959 | | |
1960 | 0 | entityAddr = NvFindHandle(handle); |
1961 | 0 | pAssert(entityAddr != 0); |
1962 | 0 | if(HandleGetType(handle) == TPM_HT_NV_INDEX) |
1963 | 0 | { |
1964 | 0 | NV_INDEX nvIndex; |
1965 | | // Read the NV Index info |
1966 | 0 | _plat__NvMemoryRead(entityAddr + sizeof(TPM_HANDLE), sizeof(NV_INDEX), |
1967 | 0 | &nvIndex); |
1968 | | // If the entity to be deleted is a counter with the maximum counter |
1969 | | // value, record it in NV memory |
1970 | 0 | if(nvIndex.publicArea.attributes.TPMA_NV_COUNTER == SET |
1971 | 0 | && nvIndex.publicArea.attributes.TPMA_NV_WRITTEN == SET) |
1972 | 0 | { |
1973 | 0 | UINT64 countValue; |
1974 | 0 | UINT64 maxCount; |
1975 | 0 | NvGetIntIndexData(handle, &nvIndex, &countValue); |
1976 | 0 | maxCount = NvReadMaxCount(); |
1977 | 0 | if(countValue > maxCount) |
1978 | 0 | NvWriteMaxCount(countValue); |
1979 | 0 | } |
1980 | | // If the NV Index is RAM back, delete the RAM data as well |
1981 | 0 | if(nvIndex.publicArea.attributes.TPMA_NV_ORDERLY == SET) |
1982 | 0 | NvDeleteRAM(handle); |
1983 | 0 | } |
1984 | 0 | NvDelete(entityAddr); |
1985 | 0 | return; |
1986 | 0 | } |
1987 | | // |
1988 | | // |
1989 | | // NvFlushHierarchy() |
1990 | | // |
1991 | | // This function will delete persistent objects belonging to the indicated If the storage hierarchy is selected, |
1992 | | // the function will also delete any NV Index define using ownerAuth. |
1993 | | // |
1994 | | void |
1995 | | NvFlushHierarchy( |
1996 | | TPMI_RH_HIERARCHY hierarchy // IN: hierarchy to be flushed. |
1997 | | ) |
1998 | 0 | { |
1999 | 0 | NV_ITER iter = NV_ITER_INIT; |
2000 | 0 | UINT32 currentAddr; |
2001 | 0 | while((currentAddr = NvNext(&iter)) != 0) |
2002 | 0 | { |
2003 | 0 | TPM_HANDLE entityHandle; |
2004 | | // Read handle information. |
2005 | 0 | _plat__NvMemoryRead(currentAddr, sizeof(TPM_HANDLE), &entityHandle); |
2006 | 0 | if(HandleGetType(entityHandle) == TPM_HT_NV_INDEX) |
2007 | 0 | { |
2008 | | // Handle NV Index |
2009 | 0 | NV_INDEX nvIndex; |
2010 | | // If flush endorsement or platform hierarchy, no NV Index would be |
2011 | | // flushed |
2012 | 0 | if(hierarchy == TPM_RH_ENDORSEMENT || hierarchy == TPM_RH_PLATFORM) |
2013 | 0 | continue; |
2014 | 0 | _plat__NvMemoryRead(currentAddr + sizeof(TPM_HANDLE), |
2015 | 0 | sizeof(NV_INDEX), &nvIndex); |
2016 | | // For storage hierarchy, flush OwnerCreated index |
2017 | 0 | if( nvIndex.publicArea.attributes.TPMA_NV_PLATFORMCREATE == CLEAR) |
2018 | 0 | { |
2019 | 0 | if(_plat__ShallSurviveOwnerClear(nvIndex.publicArea.nvIndex)) |
2020 | 0 | continue; |
2021 | | // Delete the NV Index |
2022 | 0 | NvDelete(currentAddr); |
2023 | | // Re-iterate from beginning after a delete |
2024 | 0 | iter = NV_ITER_INIT; |
2025 | | // If the NV Index is RAM back, delete the RAM data as well |
2026 | 0 | if(nvIndex.publicArea.attributes.TPMA_NV_ORDERLY == SET) |
2027 | 0 | NvDeleteRAM(entityHandle); |
2028 | 0 | } |
2029 | 0 | } |
2030 | 0 | else if(HandleGetType(entityHandle) == TPM_HT_PERSISTENT) |
2031 | 0 | { |
2032 | 0 | OBJECT object; |
2033 | | // Get evict object |
2034 | 0 | NvGetEvictObject(entityHandle, &object); |
2035 | | // If the evict object belongs to the hierarchy to be flushed |
2036 | 0 | if( ( hierarchy == TPM_RH_PLATFORM |
2037 | 0 | && object.attributes.ppsHierarchy == SET) |
2038 | 0 | || ( hierarchy == TPM_RH_OWNER |
2039 | 0 | && object.attributes.spsHierarchy == SET) |
2040 | 0 | || ( hierarchy == TPM_RH_ENDORSEMENT |
2041 | 0 | && object.attributes.epsHierarchy == SET) |
2042 | 0 | ) |
2043 | 0 | { |
2044 | | // Delete the evict object |
2045 | 0 | NvDelete(currentAddr); |
2046 | | // Re-iterate from beginning after a delete |
2047 | 0 | iter = NV_ITER_INIT; |
2048 | 0 | } |
2049 | 0 | } |
2050 | 0 | else |
2051 | 0 | { |
2052 | 0 | pAssert(FALSE); |
2053 | 0 | } |
2054 | 0 | } |
2055 | 0 | return; |
2056 | 0 | } |
2057 | | // |
2058 | | // |
2059 | | // NvSetGlobalLock() |
2060 | | // |
2061 | | // This function is used to SET the TPMA_NV_WRITELOCKED attribute for all NV Indices that have |
2062 | | // TPMA_NV_GLOBALLOCK SET. This function is use by TPM2_NV_GlobalWriteLock(). |
2063 | | // |
2064 | | void |
2065 | | NvSetGlobalLock( |
2066 | | void |
2067 | | ) |
2068 | 0 | { |
2069 | 0 | NV_ITER iter = NV_ITER_INIT; |
2070 | 0 | UINT32 currentAddr; |
2071 | | // Check all Indices |
2072 | 0 | while((currentAddr = NvNextIndex(&iter)) != 0) |
2073 | 0 | { |
2074 | 0 | NV_INDEX nvIndex; |
2075 | | // Read the index data |
2076 | 0 | _plat__NvMemoryRead(currentAddr + sizeof(TPM_HANDLE), |
2077 | 0 | sizeof(NV_INDEX), &nvIndex); |
2078 | | // See if it should be locked |
2079 | 0 | if(nvIndex.publicArea.attributes.TPMA_NV_GLOBALLOCK == SET) |
2080 | 0 | { |
2081 | | // if so, lock it |
2082 | 0 | nvIndex.publicArea.attributes.TPMA_NV_WRITELOCKED = SET; |
2083 | 0 | _plat__NvMemoryWrite(currentAddr + sizeof(TPM_HANDLE), |
2084 | 0 | sizeof(NV_INDEX), &nvIndex); |
2085 | | // Set the flag that a NV write happens |
2086 | 0 | g_updateNV = TRUE; |
2087 | 0 | } |
2088 | 0 | } |
2089 | 0 | return; |
2090 | 0 | } |
2091 | | // |
2092 | | // |
2093 | | // InsertSort() |
2094 | | // |
2095 | | // Sort a handle into handle list in ascending order. The total handle number in the list should not exceed |
2096 | | // MAX_CAP_HANDLES |
2097 | | // |
2098 | | static void |
2099 | | InsertSort( |
2100 | | TPML_HANDLE *handleList, // IN/OUT: sorted handle list |
2101 | | UINT32 count, // IN: maximum count in the handle list |
2102 | | TPM_HANDLE entityHandle // IN: handle to be inserted |
2103 | | ) |
2104 | 0 | { |
2105 | 0 | UINT32 i, j; |
2106 | 0 | UINT32 originalCount; |
2107 | | // For a corner case that the maximum count is 0, do nothing |
2108 | 0 | if(count == 0) return; |
2109 | | // For empty list, add the handle at the beginning and return |
2110 | 0 | if(handleList->count == 0) |
2111 | 0 | { |
2112 | 0 | handleList->handle[0] = entityHandle; |
2113 | 0 | handleList->count++; |
2114 | 0 | return; |
2115 | 0 | } |
2116 | | // Check if the maximum of the list has been reached |
2117 | 0 | originalCount = handleList->count; |
2118 | 0 | if(originalCount < count) |
2119 | 0 | handleList->count++; |
2120 | | // Insert the handle to the list |
2121 | 0 | for(i = 0; i < originalCount; i++) |
2122 | 0 | { |
2123 | 0 | if(handleList->handle[i] > entityHandle) |
2124 | 0 | { |
2125 | 0 | for(j = handleList->count - 1; j > i; j--) |
2126 | 0 | { |
2127 | 0 | handleList->handle[j] = handleList->handle[j-1]; |
2128 | 0 | } |
2129 | 0 | break; |
2130 | 0 | } |
2131 | 0 | } |
2132 | | // If a slot was found, insert the handle in this position |
2133 | 0 | if(i < originalCount || handleList->count > originalCount) |
2134 | 0 | handleList->handle[i] = entityHandle; |
2135 | 0 | return; |
2136 | 0 | } |
2137 | | // |
2138 | | // |
2139 | | // NvCapGetPersistent() |
2140 | | // |
2141 | | // This function is used to get a list of handles of the persistent objects, starting at handle. |
2142 | | // Handle must be in valid persistent object handle range, but does not have to reference an existing |
2143 | | // persistent object. |
2144 | | // |
2145 | | // Return Value Meaning |
2146 | | // |
2147 | | // YES if there are more handles available |
2148 | | // NO all the available handles has been returned |
2149 | | // |
2150 | | TPMI_YES_NO |
2151 | | NvCapGetPersistent( |
2152 | | TPMI_DH_OBJECT handle, // IN: start handle |
2153 | | UINT32 count, // IN: maximum number of returned handle |
2154 | | TPML_HANDLE *handleList // OUT: list of handle |
2155 | | ) |
2156 | 0 | { |
2157 | 0 | TPMI_YES_NO more = NO; |
2158 | 0 | NV_ITER iter = NV_ITER_INIT; |
2159 | 0 | UINT32 currentAddr; |
2160 | 0 | pAssert(HandleGetType(handle) == TPM_HT_PERSISTENT); |
2161 | | // Initialize output handle list |
2162 | 0 | handleList->count = 0; |
2163 | | // The maximum count of handles we may return is MAX_CAP_HANDLES |
2164 | 0 | if(count > MAX_CAP_HANDLES) count = MAX_CAP_HANDLES; |
2165 | 0 | while((currentAddr = NvNextEvict(&iter)) != 0) |
2166 | 0 | { |
2167 | 0 | TPM_HANDLE entityHandle; |
2168 | | // Read handle information. |
2169 | 0 | _plat__NvMemoryRead(currentAddr, sizeof(TPM_HANDLE), &entityHandle); |
2170 | | // Ignore persistent handles that have values less than the input handle |
2171 | 0 | if(entityHandle < handle) |
2172 | 0 | continue; |
2173 | | // if the handles in the list have reached the requested count, and there |
2174 | | // are still handles need to be inserted, indicate that there are more. |
2175 | 0 | if(handleList->count == count) |
2176 | 0 | more = YES; |
2177 | | // A handle with a value larger than start handle is a candidate |
2178 | | // for return. Insert sort it to the return list. Insert sort algorithm |
2179 | | // is chosen here for simplicity based on the assumption that the total |
2180 | | // number of NV Indices is small. For an implementation that may allow |
2181 | | // large number of NV Indices, a more efficient sorting algorithm may be |
2182 | | // used here. |
2183 | 0 | InsertSort(handleList, count, entityHandle); |
2184 | | // |
2185 | 0 | } |
2186 | 0 | return more; |
2187 | 0 | } |
2188 | | // |
2189 | | // |
2190 | | // NvCapGetIndex() |
2191 | | // |
2192 | | // This function returns a list of handles of NV Indices, starting from handle. Handle must be in the range of |
2193 | | // NV Indices, but does not have to reference an existing NV Index. |
2194 | | // |
2195 | | // Return Value Meaning |
2196 | | // |
2197 | | // YES if there are more handles to report |
2198 | | // NO all the available handles has been reported |
2199 | | // |
2200 | | TPMI_YES_NO |
2201 | | NvCapGetIndex( |
2202 | | TPMI_DH_OBJECT handle, // IN: start handle |
2203 | | UINT32 count, // IN: maximum number of returned handle |
2204 | | TPML_HANDLE *handleList // OUT: list of handle |
2205 | | ) |
2206 | 0 | { |
2207 | 0 | TPMI_YES_NO more = NO; |
2208 | 0 | NV_ITER iter = NV_ITER_INIT; |
2209 | 0 | UINT32 currentAddr; |
2210 | 0 | pAssert(HandleGetType(handle) == TPM_HT_NV_INDEX); |
2211 | | // Initialize output handle list |
2212 | 0 | handleList->count = 0; |
2213 | | // The maximum count of handles we may return is MAX_CAP_HANDLES |
2214 | 0 | if(count > MAX_CAP_HANDLES) count = MAX_CAP_HANDLES; |
2215 | 0 | while((currentAddr = NvNextIndex(&iter)) != 0) |
2216 | 0 | { |
2217 | 0 | TPM_HANDLE entityHandle; |
2218 | | // Read handle information. |
2219 | 0 | _plat__NvMemoryRead(currentAddr, sizeof(TPM_HANDLE), &entityHandle); |
2220 | | // Ignore index handles that have values less than the 'handle' |
2221 | 0 | if(entityHandle < handle) |
2222 | 0 | continue; |
2223 | | // if the count of handles in the list has reached the requested count, |
2224 | | // and there are still handles to report, set more. |
2225 | 0 | if(handleList->count == count) |
2226 | 0 | more = YES; |
2227 | | // A handle with a value larger than start handle is a candidate |
2228 | | // for return. Insert sort it to the return list. Insert sort algorithm |
2229 | | // is chosen here for simplicity based on the assumption that the total |
2230 | | // number of NV Indices is small. For an implementation that may allow |
2231 | | // large number of NV Indices, a more efficient sorting algorithm may be |
2232 | | // used here. |
2233 | 0 | InsertSort(handleList, count, entityHandle); |
2234 | 0 | } |
2235 | 0 | return more; |
2236 | 0 | } |
2237 | | // |
2238 | | // |
2239 | | // |
2240 | | // NvCapGetIndexNumber() |
2241 | | // |
2242 | | // This function returns the count of NV Indexes currently defined. |
2243 | | // |
2244 | | UINT32 |
2245 | | NvCapGetIndexNumber( |
2246 | | void |
2247 | | ) |
2248 | 0 | { |
2249 | 0 | UINT32 num = 0; |
2250 | 0 | NV_ITER iter = NV_ITER_INIT; |
2251 | 0 | while(NvNextIndex(&iter) != 0) num++; |
2252 | 0 | return num; |
2253 | 0 | } |
2254 | | // |
2255 | | // |
2256 | | // NvCapGetPersistentNumber() |
2257 | | // |
2258 | | // Function returns the count of persistent objects currently in NV memory. |
2259 | | // |
2260 | | UINT32 |
2261 | | NvCapGetPersistentNumber( |
2262 | | void |
2263 | | ) |
2264 | 0 | { |
2265 | 0 | UINT32 num = 0; |
2266 | 0 | NV_ITER iter = NV_ITER_INIT; |
2267 | 0 | while(NvNextEvict(&iter) != 0) num++; |
2268 | 0 | return num; |
2269 | 0 | } |
2270 | | // |
2271 | | // |
2272 | | // NvCapGetPersistentAvail() |
2273 | | // |
2274 | | // This function returns an estimate of the number of additional persistent objects that could be loaded into |
2275 | | // NV memory. |
2276 | | // |
2277 | | UINT32 |
2278 | | NvCapGetPersistentAvail( |
2279 | | void |
2280 | | ) |
2281 | 0 | { |
2282 | 0 | UINT32 availSpace; |
2283 | 0 | UINT32 objectSpace; |
2284 | | // Compute the available space in NV storage |
2285 | 0 | availSpace = NvGetFreeByte(); |
2286 | | // Get the space needed to add a persistent object to NV storage |
2287 | 0 | objectSpace = NvGetEvictObjectSize(); |
2288 | 0 | return availSpace / objectSpace; |
2289 | 0 | } |
2290 | | // |
2291 | | // |
2292 | | // NvCapGetCounterNumber() |
2293 | | // |
2294 | | // Get the number of defined NV Indexes that have NV TPMA_NV_COUNTER attribute SET. |
2295 | | // |
2296 | | // |
2297 | | UINT32 |
2298 | | NvCapGetCounterNumber( |
2299 | | void |
2300 | | ) |
2301 | 0 | { |
2302 | 0 | NV_ITER iter = NV_ITER_INIT; |
2303 | 0 | UINT32 currentAddr; |
2304 | 0 | UINT32 num = 0; |
2305 | 0 | while((currentAddr = NvNextIndex(&iter)) != 0) |
2306 | 0 | { |
2307 | 0 | NV_INDEX nvIndex; |
2308 | | // Get NV Index info |
2309 | 0 | _plat__NvMemoryRead(currentAddr + sizeof(TPM_HANDLE), |
2310 | 0 | sizeof(NV_INDEX), &nvIndex); |
2311 | 0 | if(nvIndex.publicArea.attributes.TPMA_NV_COUNTER == SET) num++; |
2312 | 0 | } |
2313 | 0 | return num; |
2314 | 0 | } |
2315 | | // |
2316 | | // |
2317 | | // NvCapGetCounterAvail() |
2318 | | // |
2319 | | // This function returns an estimate of the number of additional counter type NV Indices that can be defined. |
2320 | | // |
2321 | | UINT32 |
2322 | | NvCapGetCounterAvail( |
2323 | | void |
2324 | | ) |
2325 | 0 | { |
2326 | 0 | UINT32 availNVSpace; |
2327 | 0 | UINT32 availRAMSpace; |
2328 | 0 | UINT32 counterNVSpace; |
2329 | 0 | UINT32 counterRAMSpace; |
2330 | 0 | UINT32 persistentNum = NvCapGetPersistentNumber(); |
2331 | | // Get the available space in NV storage |
2332 | 0 | availNVSpace = NvGetFreeByte(); |
2333 | 0 | if (persistentNum < MIN_EVICT_OBJECTS) |
2334 | 0 | { |
2335 | | // Some space have to be reserved for evict object. Adjust availNVSpace. |
2336 | 0 | UINT32 reserved = (MIN_EVICT_OBJECTS - persistentNum) |
2337 | 0 | * NvGetEvictObjectSize(); |
2338 | 0 | if (reserved > availNVSpace) |
2339 | 0 | availNVSpace = 0; |
2340 | 0 | else |
2341 | 0 | availNVSpace -= reserved; |
2342 | 0 | } |
2343 | | // Get the space needed to add a counter index to NV storage |
2344 | 0 | counterNVSpace = NvGetCounterSize(); |
2345 | | // Compute the available space in RAM |
2346 | 0 | availRAMSpace = RAM_INDEX_SPACE - s_ramIndexSize; |
2347 | | // Compute the space needed to add a counter index to RAM storage |
2348 | | // It takes an size field, a handle and sizeof(UINT64) for counter data |
2349 | 0 | counterRAMSpace = sizeof(UINT32) + sizeof(TPM_HANDLE) + sizeof(UINT64); |
2350 | | // Return the min of counter number in NV and in RAM |
2351 | 0 | if(availNVSpace / counterNVSpace > availRAMSpace / counterRAMSpace) |
2352 | 0 | return availRAMSpace / counterRAMSpace; |
2353 | 0 | else |
2354 | 0 | return availNVSpace / counterNVSpace; |
2355 | 0 | } |
2356 | | |
2357 | | // |
2358 | | // NvEarlyStageFindHandle |
2359 | | // |
2360 | | // This function checks if a certain handle is present in NVMEM, even before |
2361 | | // TPM_Startup was invoked. |
2362 | | // |
2363 | | // To facilitate NVMEM lookip this function initializes static variables if |
2364 | | // they are not yet initialized. |
2365 | | // |
2366 | | // Returns Non-zero if handle was found. The value is the offset in NV memory of |
2367 | | // the entity associated with the input handle. |
2368 | | // Zero if handle does not exist. |
2369 | | |
2370 | | // |
2371 | | UINT32 |
2372 | | NvEarlyStageFindHandle( |
2373 | | TPM_HANDLE handle |
2374 | | ) |
2375 | | |
2376 | 0 | { |
2377 | 0 | if (!s_evictNvEnd) |
2378 | 0 | NvInitStatic(); |
2379 | |
|
2380 | 0 | return NvFindHandle(handle); |
2381 | 0 | } |
2382 | | // |
2383 | | // NvIsDefinedHiddenObject() |
2384 | | // |
2385 | | // This function indicates if a handle references an existing |
2386 | | // hidden object. |
2387 | | // |
2388 | | // Return Value Meaning |
2389 | | // |
2390 | | // TRUE handle references an |
2391 | | // existing hidden object |
2392 | | // FALSE handle does not reference an |
2393 | | // existing hidden object |
2394 | | // |
2395 | | BOOL |
2396 | | NvIsDefinedHiddenObject( |
2397 | | TPM_HANDLE handle // IN: handle |
2398 | | ) |
2399 | 0 | { |
2400 | 0 | return HandleGetType(handle) == TPM_HT_HIDDEN && |
2401 | 0 | NvFindHandle(handle) != 0; |
2402 | 0 | } |
2403 | | // |
2404 | | // |
2405 | | // NvAddHiddenObject() |
2406 | | // |
2407 | | // This function is used to assign NV memory to a new hidden object. |
2408 | | // |
2409 | | // Error Returns Meaning |
2410 | | // |
2411 | | // TPM_RC_NV_HANDLE the requested handle is already in use |
2412 | | // TPM_RC_NV_SPACE insufficient NV space |
2413 | | // |
2414 | | TPM_RC |
2415 | | NvAddHiddenObject( |
2416 | | TPM_HANDLE handle, // IN: new handle |
2417 | | UINT16 object_size, |
2418 | | void *object // IN: data to be stored |
2419 | | ) |
2420 | 0 | { |
2421 | | // The buffer to be written to NV memory |
2422 | 0 | BYTE nvBuffer[sizeof(TPM_HANDLE) + object_size]; |
2423 | 0 | BYTE *buf = nvBuffer; |
2424 | |
|
2425 | 0 | if (HandleGetType(handle) != TPM_HT_HIDDEN) |
2426 | 0 | return TPM_RC_HANDLE; |
2427 | | |
2428 | | // Do not attemp storing a duplicate handle. |
2429 | 0 | if(NvIsDefinedHiddenObject(handle)) |
2430 | 0 | return TPM_RC_NV_DEFINED; |
2431 | | |
2432 | | // Check if we have enough space to add this hidden object |
2433 | 0 | if(!NvTestSpace(sizeof(nvBuffer), FALSE)) |
2434 | 0 | return TPM_RC_NV_SPACE; |
2435 | | |
2436 | 0 | memcpy(buf, &handle, sizeof(TPM_HANDLE)); |
2437 | 0 | buf += sizeof(TPM_HANDLE); |
2438 | |
|
2439 | 0 | memcpy(buf, object, object_size); |
2440 | |
|
2441 | 0 | NvAdd(sizeof(nvBuffer), sizeof(nvBuffer), nvBuffer); |
2442 | |
|
2443 | 0 | return TPM_RC_SUCCESS; |
2444 | 0 | } |
2445 | | |
2446 | | // |
2447 | | // |
2448 | | // NvGetHiddenObjectAddrSize() |
2449 | | // |
2450 | | // This function returns address (internal to nvmem) and size of |
2451 | | // hidden object. It requires the index to be defined. |
2452 | | // |
2453 | | // Error Returns Meaning |
2454 | | // |
2455 | | // TPM_RC_HANDLE the requested handle could not be found |
2456 | | // TPM_RC_TYPE handle is not a hidden object |
2457 | | static TPM_RC NvGetHiddenObjectAddrSize( |
2458 | | TPM_HANDLE handle, // IN: handle |
2459 | | UINT32 *addr, // OUT: address of entity |
2460 | | UINT16 *size // OUT: size of entity |
2461 | | ) |
2462 | 0 | { |
2463 | 0 | UINT32 entityAddr; |
2464 | 0 | NV_ITER iter; |
2465 | |
|
2466 | 0 | if (HandleGetType(handle) != TPM_HT_HIDDEN) |
2467 | 0 | return TPM_RC_TYPE; |
2468 | | |
2469 | 0 | entityAddr = NvFindHandle(handle); |
2470 | 0 | if (entityAddr == 0) |
2471 | 0 | return TPM_RC_HANDLE; |
2472 | | |
2473 | 0 | iter = entityAddr - sizeof(NV_ITER); |
2474 | | |
2475 | | // This will return the same address we already have in NvFindHandle, |
2476 | | // (we discard this return value), and advance iter to point to the |
2477 | | // start of next item in the list (its next pointer). |
2478 | 0 | NvNext(&iter); |
2479 | | // Calculate size of this entity using position of next item. |
2480 | 0 | *size = |
2481 | 0 | iter // Points to beginning of next entry. |
2482 | 0 | - entityAddr // Points to beginning of current item. |
2483 | 0 | - sizeof(TPM_HANDLE); // Current item includes a handle. |
2484 | |
|
2485 | 0 | *addr = entityAddr; |
2486 | 0 | return TPM_RC_SUCCESS; |
2487 | 0 | } |
2488 | | |
2489 | | // |
2490 | | // |
2491 | | // NvWriteHiddenObject() |
2492 | | // |
2493 | | // This function is used to write new data to an existing hidden object. |
2494 | | // |
2495 | | // Error Returns Meaning |
2496 | | // |
2497 | | // TPM_RC_HANDLE the requested handle could not be found |
2498 | | // TPM_RC_NV_SPACE size does not match NV space |
2499 | | // |
2500 | | TPM_RC NvWriteHiddenObject(TPM_HANDLE handle, // IN: new evict handle |
2501 | | UINT16 size, |
2502 | | void *object // IN: object to be added |
2503 | 0 | ) { |
2504 | 0 | UINT32 entityAddr; // offset points to the entity |
2505 | 0 | UINT16 entitySize; // recorded size of the entity |
2506 | 0 | TPM_RC rc; |
2507 | |
|
2508 | 0 | rc = NvGetHiddenObjectAddrSize(handle, &entityAddr, &entitySize); |
2509 | 0 | if (TPM_RC_SUCCESS != rc) |
2510 | 0 | return rc; |
2511 | 0 | if (size != entitySize) { |
2512 | 0 | return TPM_RC_NV_SPACE; |
2513 | 0 | } |
2514 | 0 | _plat__NvMemoryWrite(entityAddr + sizeof(TPM_HANDLE), |
2515 | 0 | size, object); |
2516 | 0 | g_updateNV = TRUE; |
2517 | 0 | return TPM_RC_SUCCESS; |
2518 | 0 | } |
2519 | | // |
2520 | | // |
2521 | | // NvGetHiddenObject() |
2522 | | // |
2523 | | // This function is used to access data stored as a hidden object. |
2524 | | // |
2525 | | // This function requires that the index be defined, and that the |
2526 | | // required data is within the data range. |
2527 | | // |
2528 | | // Error Returns Meaning |
2529 | | // |
2530 | | // TPM_RC_HANDLE the requested handle could not be found |
2531 | | TPM_RC |
2532 | | NvGetHiddenObject( |
2533 | | TPM_HANDLE handle, // IN: handle |
2534 | | UINT16 size, // IN: size of NV data |
2535 | | void *data // OUT: data buffer |
2536 | | ) |
2537 | 0 | { |
2538 | 0 | UINT32 entityAddr; |
2539 | 0 | UINT16 entitySize; |
2540 | 0 | TPM_RC rc; |
2541 | |
|
2542 | 0 | rc = NvGetHiddenObjectAddrSize(handle, &entityAddr, &entitySize); |
2543 | 0 | if (TPM_RC_SUCCESS != rc) |
2544 | 0 | return rc; |
2545 | | |
2546 | 0 | if (size > entitySize) { |
2547 | 0 | return TPM_RC_NV_SPACE; |
2548 | 0 | } |
2549 | | |
2550 | 0 | _plat__NvMemoryRead(entityAddr + sizeof(TPM_HANDLE), size, data); |
2551 | 0 | return TPM_RC_SUCCESS; |
2552 | 0 | } |
2553 | | // |
2554 | | // |
2555 | | // NvGetHiddenObjectSize() |
2556 | | // |
2557 | | // This function is used to get size of data stored as a hidden object. |
2558 | | // |
2559 | | // This function requires that the index be defined. |
2560 | | // |
2561 | | // Error Returns Meaning |
2562 | | // |
2563 | | // TPM_RC_HANDLE the requested handle could not be found |
2564 | | TPM_RC |
2565 | | NvGetHiddenObjectSize( |
2566 | | TPM_HANDLE handle, // IN: handle |
2567 | | UINT16 *size // OUT: size of NV data |
2568 | | ) |
2569 | 0 | { |
2570 | 0 | UINT32 entityAddr; |
2571 | |
|
2572 | 0 | return NvGetHiddenObjectAddrSize(handle, &entityAddr, size); |
2573 | 0 | } |
2574 | | // |
2575 | | // NVWipeCache |
2576 | | // |
2577 | | // A function to call to wipe out SRAM cache of NVMEM. Most evictable objects' |
2578 | | // contents get overwritten with some random data. The passed in two element |
2579 | | // array communicates an inclusive range of NV indexes to preserve during |
2580 | | // wipeout. |
2581 | | // |
2582 | | void NvSelectivelyInvalidateCache(const UINT16 *keep_range) |
2583 | 0 | { |
2584 | 0 | UINT32 addr; |
2585 | 0 | NV_ITER iter = NV_ITER_INIT; |
2586 | 0 | TPMI_RH_NV_INDEX bottom = NV_INDEX_FIRST + keep_range[0]; |
2587 | 0 | TPMI_RH_NV_INDEX top = NV_INDEX_FIRST + keep_range[1]; |
2588 | |
|
2589 | 0 | if (!s_evictNvEnd) |
2590 | 0 | return; /* Cache not initialized, nothing to do here. */ |
2591 | | |
2592 | 0 | while((addr = NvNext(&iter)) != 0) |
2593 | 0 | { |
2594 | 0 | TPM_HANDLE entityHandle; |
2595 | 0 | size_t space; |
2596 | | |
2597 | | /* |
2598 | | * Read the object's handle. Note that TPMI_RH_NV_INDEX is a handle of |
2599 | | * a certain type, the same size as TPM_HANDLE. |
2600 | | */ |
2601 | 0 | _plat__NvMemoryRead(addr, sizeof(TPM_HANDLE), &entityHandle); |
2602 | | |
2603 | | /* Skip it if it is in the range to preserve. */ |
2604 | 0 | if((entityHandle >= bottom) && (entityHandle <= top)) |
2605 | 0 | continue; |
2606 | | |
2607 | | /* |
2608 | | * Determine the space the object takes in the cache less the handle |
2609 | | * size. Note that at this point 'iter' points at the location right |
2610 | | * above the current object. |
2611 | | */ |
2612 | 0 | space = iter - addr - sizeof(TPMI_RH_NV_INDEX); |
2613 | | |
2614 | | /* Overwrite the cache space with junk data coped from text segment. */ |
2615 | 0 | _plat__NvMemoryWrite(addr + sizeof(TPMI_RH_NV_INDEX), space, |
2616 | 0 | NvCapGetCounterAvail); |
2617 | 0 | } |
2618 | 0 | } |
2619 | | |
2620 | | /* |
2621 | | * A helper function which allows the caller to find out NVMEM cache offset |
2622 | | * and size of all reserved objects AND of the RAM index space AND of the |
2623 | | * maxCount value. The last two items are technically not reserved objects, |
2624 | | * but are always present in the NVMEM cache and need to be preserved in |
2625 | | * non-volatile storage. |
2626 | | * |
2627 | | * From the caller's perspective these two items are considered reserved |
2628 | | * objects at indices NV_RAM_INDEX_SPACE and NV_MAX_COUNTER. |
2629 | | */ |
2630 | | void NvGetReserved(UINT32 index, NV_RESERVED_ITEM *ri) |
2631 | 0 | { |
2632 | 0 | UINT32 indexSize; |
2633 | |
|
2634 | 0 | if (index < NV_RESERVE_LAST) { |
2635 | 0 | ri->size = s_reservedSize[index]; |
2636 | 0 | ri->offset = s_reservedAddr[index]; |
2637 | 0 | return; |
2638 | 0 | } |
2639 | | |
2640 | 0 | switch (index) { |
2641 | 0 | case NV_RAM_INDEX_SPACE: |
2642 | | /* |
2643 | | * This is a request for the RAM index space, which is a concatenation of |
2644 | | * the 4 byte size field and the actual RAM index contents field. For the |
2645 | | * purposes of this function both fields are considered as single space |
2646 | | * with the size equal 4 + the value stored at s_ramIndexSize. |
2647 | | */ |
2648 | 0 | _plat__NvMemoryRead(s_ramIndexSizeAddr, sizeof(UINT32), &indexSize); |
2649 | 0 | if (indexSize > RAM_INDEX_SPACE) |
2650 | 0 | indexSize = 0; /* Must be starting with empty flash memory or bug. */ |
2651 | 0 | ri->offset = s_ramIndexSizeAddr; |
2652 | 0 | ri->size = indexSize + sizeof(indexSize); |
2653 | 0 | return; |
2654 | | |
2655 | 0 | case NV_MAX_COUNTER: |
2656 | 0 | ri->size = sizeof(UINT64); |
2657 | 0 | ri->offset = s_maxCountAddr; |
2658 | 0 | return; |
2659 | 0 | } |
2660 | | |
2661 | 0 | ri->size = 0; |
2662 | 0 | } |