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 #define NV_ITER_INIT 0xFFFFFFFF // initial value to start an
16 // iterator
17 //
18 //
19 // NV Utility Functions
20 //
21 // NvCheckState()
22 //
23 // Function to check the NV state by accessing the platform-specific function to get the NV state. The result
24 // state is registered in s_NvIsAvailable that will be reported by NvIsAvailable().
25 // This function is called at the beginning of ExecuteCommand() before any potential call to NvIsAvailable().
26 //
27 void
NvCheckState(void)28 NvCheckState(void)
29 {
30 int func_return;
31 func_return = _plat__IsNvAvailable();
32 if(func_return == 0)
33 {
34 s_NvStatus = TPM_RC_SUCCESS;
35 }
36 else if(func_return == 1)
37 {
38 s_NvStatus = TPM_RC_NV_UNAVAILABLE;
39 }
40 else
41 {
42 s_NvStatus = TPM_RC_NV_RATE;
43 }
44 return;
45 }
46 //
47 //
48 // NvIsAvailable()
49 //
50 // This function returns the NV availability parameter.
51 //
52 // Error Returns Meaning
53 //
54 // TPM_RC_SUCCESS NV is available
55 // TPM_RC_NV_RATE NV is unavailable because of rate limit
56 // TPM_RC_NV_UNAVAILABLE NV is inaccessible
57 //
58 TPM_RC
NvIsAvailable(void)59 NvIsAvailable(
60 void
61 )
62 {
63 return s_NvStatus;
64 }
65 //
66 //
67 // NvCommit
68 //
69 // This is a wrapper for the platform function to commit pending NV writes.
70 //
71 BOOL
NvCommit(void)72 NvCommit(
73 void
74 )
75 {
76 BOOL success = (_plat__NvCommit() == 0);
77 return success;
78 }
79 //
80 //
81 // NvReadMaxCount()
82 //
83 // This function returns the max NV counter value.
84 //
85 static UINT64
NvReadMaxCount(void)86 NvReadMaxCount(
87 void
88 )
89 {
90 UINT64 countValue;
91 _plat__NvMemoryRead(s_maxCountAddr, sizeof(UINT64), &countValue);
92 return countValue;
93 }
94 //
95 //
96 // NvWriteMaxCount()
97 //
98 // This function updates the max counter value to NV memory.
99 //
100 static void
NvWriteMaxCount(UINT64 maxCount)101 NvWriteMaxCount(
102 UINT64 maxCount
103 )
104 {
105 _plat__NvMemoryWrite(s_maxCountAddr, sizeof(UINT64), &maxCount);
106 return;
107 }
108 //
109 //
110 // NV Index and Persistent Object Access Functions
111 //
112 // Introduction
113 //
114 // These functions are used to access an NV Index and persistent object memory. In this implementation,
115 // the memory is simulated with RAM. The data in dynamic area is organized as a linked list, starting from
116 // address s_evictNvStart. The first 4 bytes of a node in this link list is the offset of next node, followed by
117 // the data entry. A 0-valued offset value indicates the end of the list. If the data entry area of the last node
118 // happens to reach the end of the dynamic area without space left for an additional 4 byte end marker, the
119 // end address, s_evictNvEnd, should serve as the mark of list end
120 //
121 // NvNext()
122 //
123 // This function provides a method to traverse every data entry in NV dynamic area.
124 // To begin with, parameter iter should be initialized to NV_ITER_INIT indicating the first element. Every
125 // time this function is called, the value in iter would be adjusted pointing to the next element in traversal. If
126 // there is no next element, iter value would be 0. This function returns the address of the 'data entry'
127 // pointed by the iter. If there is no more element in the set, a 0 value is returned indicating the end of
128 // traversal.
129 //
130 static UINT32
NvNext(NV_ITER * iter)131 NvNext(
132 NV_ITER *iter
133 )
134 {
135 NV_ITER currentIter;
136 // If iterator is at the beginning of list
137 if(*iter == NV_ITER_INIT)
138 {
139 // Initialize iterator
140 *iter = s_evictNvStart;
141 }
142 // If iterator reaches the end of NV space, or iterator indicates list end
143 if(*iter + sizeof(UINT32) > s_evictNvEnd || *iter == 0)
144 return 0;
145 // Save the current iter offset
146 currentIter = *iter;
147 // Adjust iter pointer pointing to next entity
148 // Read pointer value
149 _plat__NvMemoryRead(*iter, sizeof(UINT32), iter);
150 if(*iter == 0) return 0;
151 return currentIter + sizeof(UINT32); // entity stores after the pointer
152 }
153 //
154 //
155 // NvGetEnd()
156 //
157 // Function to find the end of the NV dynamic data list
158 //
159 static UINT32
NvGetEnd(void)160 NvGetEnd(
161 void
162 )
163 {
164 NV_ITER iter = NV_ITER_INIT;
165 UINT32 endAddr = s_evictNvStart;
166 UINT32 currentAddr;
167 while((currentAddr = NvNext(&iter)) != 0)
168 endAddr = currentAddr;
169 if(endAddr != s_evictNvStart)
170 {
171 // Read offset
172 endAddr -= sizeof(UINT32);
173 _plat__NvMemoryRead(endAddr, sizeof(UINT32), &endAddr);
174 }
175 return endAddr;
176 }
177 //
178 //
179 // NvGetFreeByte
180 //
181 // This function returns the number of free octets in NV space.
182 //
183 static UINT32
NvGetFreeByte(void)184 NvGetFreeByte(
185 void
186 )
187 {
188 return s_evictNvEnd - NvGetEnd();
189 }
190 //
191 // NvGetEvictObjectSize
192 //
193 // This function returns the size of an evict object in NV space
194 //
195 static UINT32
NvGetEvictObjectSize(void)196 NvGetEvictObjectSize(
197 void
198 )
199 {
200 return sizeof(TPM_HANDLE) + sizeof(OBJECT) + sizeof(UINT32);
201 }
202 //
203 //
204 // NvGetCounterSize
205 //
206 // This function returns the size of a counter index in NV space.
207 //
208 static UINT32
NvGetCounterSize(void)209 NvGetCounterSize(
210 void
211 )
212 {
213 // It takes an offset field, a handle and the sizeof(NV_INDEX) and
214 // sizeof(UINT64) for counter data
215 return sizeof(TPM_HANDLE) + sizeof(NV_INDEX) + sizeof(UINT64) + sizeof(UINT32);
216 }
217 //
218 //
219 // NvTestSpace()
220 //
221 // This function will test if there is enough space to add a new entity.
222 //
223 // Return Value Meaning
224 //
225 // TRUE space available
226 // FALSE no enough space
227 //
228 static BOOL
NvTestSpace(UINT32 size,BOOL isIndex)229 NvTestSpace(
230 UINT32 size, // IN: size of the entity to be added
231 BOOL isIndex // IN: TRUE if the entity is an index
232 )
233 {
234 UINT32 remainByte = NvGetFreeByte();
235 // For NV Index, need to make sure that we do not allocate and Index if this
236 // would mean that the TPM cannot allocate the minimum number of evict
237 // objects.
238 if(isIndex)
239 {
240 // Get the number of persistent objects allocated
241 UINT32 persistentNum = NvCapGetPersistentNumber();
242 // If we have not allocated the requisite number of evict objects, then we
243 // need to reserve space for them.
244 // NOTE: some of this is not written as simply as it might seem because
245 // the values are all unsigned and subtracting needs to be done carefully
246 // so that an underflow doesn't cause problems.
247 if(persistentNum < MIN_EVICT_OBJECTS)
248 {
249 UINT32 needed = (MIN_EVICT_OBJECTS - persistentNum)
250 * NvGetEvictObjectSize();
251 if(needed > remainByte)
252 remainByte = 0;
253 else
254 remainByte -= needed;
255 }
256 // if the requisite number of evict objects have been allocated then
257 // no need to reserve additional space
258 }
259 // This checks for the size of the value being added plus the index value.
260 // NOTE: This does not check to see if the end marker can be placed in
261 // memory because the end marker will not be written if it will not fit.
262 return (size + sizeof(UINT32) <= remainByte);
263 }
264 //
265 //
266 // NvAdd()
267 //
268 // This function adds a new entity to NV.
269 // This function requires that there is enough space to add a new entity (i.e., that NvTestSpace() has been
270 // called and the available space is at least as large as the required space).
271 //
272 static void
NvAdd(UINT32 totalSize,UINT32 bufferSize,BYTE * entity)273 NvAdd(
274 UINT32 totalSize, // IN: total size needed for this entity For
275 // evict object, totalSize is the same as
276 // bufferSize. For NV Index, totalSize is
277 // bufferSize plus index data size
278 UINT32 bufferSize, // IN: size of initial buffer
279 BYTE *entity // IN: initial buffer
280 )
281 {
282 UINT32 endAddr;
283 UINT32 nextAddr;
284 UINT32 listEnd = 0;
285 // Get the end of data list
286 endAddr = NvGetEnd();
287 // Calculate the value of next pointer, which is the size of a pointer +
288 // the entity data size
289 nextAddr = endAddr + sizeof(UINT32) + totalSize;
290 // Write next pointer
291 _plat__NvMemoryWrite(endAddr, sizeof(UINT32), &nextAddr);
292 // Write entity data
293 _plat__NvMemoryWrite(endAddr + sizeof(UINT32), bufferSize, entity);
294 // Write the end of list if it is not going to exceed the NV space
295 if(nextAddr + sizeof(UINT32) <= s_evictNvEnd)
296 _plat__NvMemoryWrite(nextAddr, sizeof(UINT32), &listEnd);
297 // Set the flag so that NV changes are committed before the command completes.
298 g_updateNV = TRUE;
299 }
300 //
301 //
302 // NvDelete()
303 //
304 // This function is used to delete an NV Index or persistent object from NV memory.
305 //
306 static void
NvDelete(UINT32 entityAddr)307 NvDelete(
308 UINT32 entityAddr // IN: address of entity to be deleted
309 )
310 {
311 UINT32 next;
312 UINT32 entrySize;
313 UINT32 entryAddr = entityAddr - sizeof(UINT32);
314 UINT32 listEnd = 0;
315 // Get the offset of the next entry.
316 _plat__NvMemoryRead(entryAddr, sizeof(UINT32), &next);
317 // The size of this entry is the difference between the current entry and the
318 // next entry.
319 entrySize = next - entryAddr;
320 // Move each entry after the current one to fill the freed space.
321 // Stop when we have reached the end of all the indexes. There are two
322 // ways to detect the end of the list. The first is to notice that there
323 // is no room for anything else because we are at the end of NV. The other
324 // indication is that we find an end marker.
325 // The loop condition checks for the end of NV.
326 while(next + sizeof(UINT32) <= s_evictNvEnd)
327 {
328 UINT32 size, oldAddr, newAddr;
329 // Now check for the end marker
330 _plat__NvMemoryRead(next, sizeof(UINT32), &oldAddr);
331 if(oldAddr == 0)
332 break;
333 size = oldAddr - next;
334 // Move entry
335 _plat__NvMemoryMove(next, next - entrySize, size);
336 // Update forward link
337 newAddr = oldAddr - entrySize;
338 _plat__NvMemoryWrite(next - entrySize, sizeof(UINT32), &newAddr);
339 next = oldAddr;
340 }
341 // Mark the end of list
342 _plat__NvMemoryWrite(next - entrySize, sizeof(UINT32), &listEnd);
343 // Set the flag so that NV changes are committed before the command completes.
344 g_updateNV = TRUE;
345 }
346 //
347 //
348 // RAM-based NV Index Data Access Functions
349 //
350 // Introduction
351 //
352 // The data layout in ram buffer is {size of(NV_handle() + data), NV_handle(), data} for each NV Index data
353 // stored in RAM.
354 // NV storage is updated when a NV Index is added or deleted. We do NOT updated NV storage when the
355 // data is updated/
356 //
357 // NvTestRAMSpace()
358 //
359 // This function indicates if there is enough RAM space to add a data for a new NV Index.
360 //
361 //
362 //
363 //
364 // Return Value Meaning
365 //
366 // TRUE space available
367 // FALSE no enough space
368 //
369 static BOOL
NvTestRAMSpace(UINT32 size)370 NvTestRAMSpace(
371 UINT32 size // IN: size of the data to be added to RAM
372 )
373 {
374 BOOL success = ( s_ramIndexSize
375 + size
376 + sizeof(TPM_HANDLE) + sizeof(UINT32)
377 <= RAM_INDEX_SPACE);
378 return success;
379 }
380 //
381 //
382 // NvGetRamIndexOffset
383 //
384 // This function returns the offset of NV data in the RAM buffer
385 // This function requires that NV Index is in RAM. That is, the index must be known to exist.
386 //
387 static UINT32
NvGetRAMIndexOffset(TPMI_RH_NV_INDEX handle)388 NvGetRAMIndexOffset(
389 TPMI_RH_NV_INDEX handle // IN: NV handle
390 )
391 {
392 UINT32 currAddr = 0;
393 while(currAddr < s_ramIndexSize)
394 {
395 TPMI_RH_NV_INDEX currHandle;
396 UINT32 currSize;
397 memcpy(&currHandle, &s_ramIndex[currAddr + sizeof(UINT32)],
398 sizeof(currHandle));
399 // Found a match
400 if(currHandle == handle)
401 // data buffer follows the handle and size field
402 break;
403 memcpy(&currSize, &s_ramIndex[currAddr], sizeof(currSize));
404 currAddr += sizeof(UINT32) + currSize;
405 }
406 // We assume the index data is existing in RAM space
407 pAssert(currAddr < s_ramIndexSize);
408 return currAddr + sizeof(TPMI_RH_NV_INDEX) + sizeof(UINT32);
409 }
410 //
411 //
412 // NvAddRAM()
413 //
414 // This function adds a new data area to RAM.
415 // This function requires that enough free RAM space is available to add the new data.
416 //
417 static void
NvAddRAM(TPMI_RH_NV_INDEX handle,UINT32 size)418 NvAddRAM(
419 TPMI_RH_NV_INDEX handle, // IN: NV handle
420 UINT32 size // IN: size of data
421 )
422 {
423 // Add data space at the end of reserved RAM buffer
424 UINT32 value = size + sizeof(TPMI_RH_NV_INDEX);
425 memcpy(&s_ramIndex[s_ramIndexSize], &value,
426 sizeof(s_ramIndex[s_ramIndexSize]));
427 memcpy(&s_ramIndex[s_ramIndexSize + sizeof(UINT32)], &handle,
428 sizeof(s_ramIndex[s_ramIndexSize + sizeof(UINT32)]));
429 s_ramIndexSize += sizeof(UINT32) + sizeof(TPMI_RH_NV_INDEX) + size;
430 pAssert(s_ramIndexSize <= RAM_INDEX_SPACE);
431 // Update NV version of s_ramIndexSize
432 _plat__NvMemoryWrite(s_ramIndexSizeAddr, sizeof(UINT32), &s_ramIndexSize);
433 // Write reserved RAM space to NV to reflect the newly added NV Index
434 _plat__NvMemoryWrite(s_ramIndexAddr, RAM_INDEX_SPACE, s_ramIndex);
435 return;
436 }
437 //
438 //
439 // NvDeleteRAM()
440 //
441 // This function is used to delete a RAM-backed NV Index data area.
442 // This function assumes the data of NV Index exists in RAM
443 //
444 static void
NvDeleteRAM(TPMI_RH_NV_INDEX handle)445 NvDeleteRAM(
446 TPMI_RH_NV_INDEX handle // IN: NV handle
447 )
448 {
449 UINT32 nodeOffset;
450 UINT32 nextNode;
451 UINT32 size;
452 nodeOffset = NvGetRAMIndexOffset(handle);
453 // Move the pointer back to get the size field of this node
454 nodeOffset -= sizeof(UINT32) + sizeof(TPMI_RH_NV_INDEX);
455 // Get node size
456 memcpy(&size, &s_ramIndex[nodeOffset], sizeof(size));
457 // Get the offset of next node
458 nextNode = nodeOffset + sizeof(UINT32) + size;
459 // Move data
460 MemoryMove(s_ramIndex + nodeOffset, s_ramIndex + nextNode,
461 s_ramIndexSize - nextNode, s_ramIndexSize - nextNode);
462 // Update RAM size
463 s_ramIndexSize -= size + sizeof(UINT32);
464 // Update NV version of s_ramIndexSize
465 _plat__NvMemoryWrite(s_ramIndexSizeAddr, sizeof(UINT32), &s_ramIndexSize);
466 // Write reserved RAM space to NV to reflect the newly delete NV Index
467 _plat__NvMemoryWrite(s_ramIndexAddr, RAM_INDEX_SPACE, s_ramIndex);
468 return;
469 }
470 //
471 //
472 //
473 // Utility Functions
474 //
475 // NvInitStatic()
476 //
477 // This function initializes the static variables used in the NV subsystem.
478 //
479 static void
NvInitStatic(void)480 NvInitStatic(
481 void
482 )
483 {
484 UINT16 i;
485 UINT32 reservedAddr;
486 s_reservedSize[NV_DISABLE_CLEAR] = sizeof(gp.disableClear);
487 s_reservedSize[NV_OWNER_ALG] = sizeof(gp.ownerAlg);
488 s_reservedSize[NV_ENDORSEMENT_ALG] = sizeof(gp.endorsementAlg);
489 s_reservedSize[NV_LOCKOUT_ALG] = sizeof(gp.lockoutAlg);
490 s_reservedSize[NV_OWNER_POLICY] = sizeof(gp.ownerPolicy);
491 s_reservedSize[NV_ENDORSEMENT_POLICY] = sizeof(gp.endorsementPolicy);
492 s_reservedSize[NV_LOCKOUT_POLICY] = sizeof(gp.lockoutPolicy);
493 s_reservedSize[NV_OWNER_AUTH] = sizeof(gp.ownerAuth);
494 s_reservedSize[NV_ENDORSEMENT_AUTH] = sizeof(gp.endorsementAuth);
495 s_reservedSize[NV_LOCKOUT_AUTH] = sizeof(gp.lockoutAuth);
496 s_reservedSize[NV_EP_SEED] = sizeof(gp.EPSeed);
497 s_reservedSize[NV_SP_SEED] = sizeof(gp.SPSeed);
498 s_reservedSize[NV_PP_SEED] = sizeof(gp.PPSeed);
499 s_reservedSize[NV_PH_PROOF] = sizeof(gp.phProof);
500 s_reservedSize[NV_SH_PROOF] = sizeof(gp.shProof);
501 s_reservedSize[NV_EH_PROOF] = sizeof(gp.ehProof);
502 s_reservedSize[NV_TOTAL_RESET_COUNT] = sizeof(gp.totalResetCount);
503 s_reservedSize[NV_RESET_COUNT] = sizeof(gp.resetCount);
504 s_reservedSize[NV_PCR_POLICIES] = sizeof(gp.pcrPolicies);
505 s_reservedSize[NV_PCR_ALLOCATED] = sizeof(gp.pcrAllocated);
506 s_reservedSize[NV_PP_LIST] = sizeof(gp.ppList);
507 s_reservedSize[NV_FAILED_TRIES] = sizeof(gp.failedTries);
508 s_reservedSize[NV_MAX_TRIES] = sizeof(gp.maxTries);
509 s_reservedSize[NV_RECOVERY_TIME] = sizeof(gp.recoveryTime);
510 s_reservedSize[NV_LOCKOUT_RECOVERY] = sizeof(gp.lockoutRecovery);
511 s_reservedSize[NV_LOCKOUT_AUTH_ENABLED] = sizeof(gp.lockOutAuthEnabled);
512 s_reservedSize[NV_ORDERLY] = sizeof(gp.orderlyState);
513 s_reservedSize[NV_AUDIT_COMMANDS] = sizeof(gp.auditComands);
514 s_reservedSize[NV_AUDIT_HASH_ALG] = sizeof(gp.auditHashAlg);
515 s_reservedSize[NV_AUDIT_COUNTER] = sizeof(gp.auditCounter);
516 s_reservedSize[NV_ALGORITHM_SET] = sizeof(gp.algorithmSet);
517 s_reservedSize[NV_FIRMWARE_V1] = sizeof(gp.firmwareV1);
518 s_reservedSize[NV_FIRMWARE_V2] = sizeof(gp.firmwareV2);
519 s_reservedSize[NV_ORDERLY_DATA] = sizeof(go);
520 s_reservedSize[NV_STATE_CLEAR] = sizeof(gc);
521 s_reservedSize[NV_STATE_RESET] = sizeof(gr);
522 // Initialize reserved data address. In this implementation, reserved data
523 // is stored at the start of NV memory
524 reservedAddr = 0;
525 for(i = 0; i < NV_RESERVE_LAST; i++)
526 {
527 s_reservedAddr[i] = reservedAddr;
528 reservedAddr += s_reservedSize[i];
529 }
530 // Initialize auxiliary variable space for index/evict implementation.
531 // Auxiliary variables are stored after reserved data area
532 // RAM index copy starts at the beginning
533 s_ramIndexSizeAddr = reservedAddr;
534 s_ramIndexAddr = s_ramIndexSizeAddr + sizeof(UINT32);
535 // Maximum counter value
536 s_maxCountAddr = s_ramIndexAddr + RAM_INDEX_SPACE;
537 // dynamic memory start
538 s_evictNvStart = s_maxCountAddr + sizeof(UINT64);
539 // dynamic memory ends at the end of NV memory
540 s_evictNvEnd = NV_MEMORY_SIZE;
541 return;
542 }
543 //
544 //
545 // NvInit()
546 //
547 // This function initializes the NV system at pre-install time.
548 // This function should only be called in a manufacturing environment or in a simulation.
549 // The layout of NV memory space is an implementation choice.
550 //
551 void
NvInit(void)552 NvInit(
553 void
554 )
555 {
556 UINT32 nullPointer = 0;
557 UINT64 zeroCounter = 0;
558 // Initialize static variables
559 NvInitStatic();
560 // Initialize RAM index space as unused
561 _plat__NvMemoryWrite(s_ramIndexSizeAddr, sizeof(UINT32), &nullPointer);
562 // Initialize max counter value to 0
563 _plat__NvMemoryWrite(s_maxCountAddr, sizeof(UINT64), &zeroCounter);
564 // Initialize the next offset of the first entry in evict/index list to 0
565 _plat__NvMemoryWrite(s_evictNvStart, sizeof(TPM_HANDLE), &nullPointer);
566 return;
567 }
568 //
569 //
570 // NvReadReserved()
571 //
572 // This function is used to move reserved data from NV memory to RAM.
573 //
574 void
NvReadReserved(NV_RESERVE type,void * buffer)575 NvReadReserved(
576 NV_RESERVE type, // IN: type of reserved data
577 void *buffer // OUT: buffer receives the data.
578 )
579 {
580 // Input type should be valid
581 pAssert(type >= 0 && type < NV_RESERVE_LAST);
582 _plat__NvMemoryRead(s_reservedAddr[type], s_reservedSize[type], buffer);
583 return;
584 }
585 //
586 //
587 // NvWriteReserved()
588 //
589 // This function is used to post a reserved data for writing to NV memory. Before the TPM completes the
590 // operation, the value will be written.
591 //
592 void
NvWriteReserved(NV_RESERVE type,void * buffer)593 NvWriteReserved(
594 NV_RESERVE type, // IN: type of reserved data
595 void *buffer // IN: data buffer
596 )
597 {
598 // Input type should be valid
599 pAssert(type >= 0 && type < NV_RESERVE_LAST);
600 _plat__NvMemoryWrite(s_reservedAddr[type], s_reservedSize[type], buffer);
601 // Set the flag that a NV write happens
602 g_updateNV = TRUE;
603 return;
604 }
605 //
606 //
607 // NvReadPersistent()
608 //
609 // This function reads persistent data to the RAM copy of the gp structure.
610 //
611 void
NvReadPersistent(void)612 NvReadPersistent(
613 void
614 )
615 {
616 // Hierarchy persistent data
617 NvReadReserved(NV_DISABLE_CLEAR, &gp.disableClear);
618 NvReadReserved(NV_OWNER_ALG, &gp.ownerAlg);
619 NvReadReserved(NV_ENDORSEMENT_ALG, &gp.endorsementAlg);
620 NvReadReserved(NV_LOCKOUT_ALG, &gp.lockoutAlg);
621 NvReadReserved(NV_OWNER_POLICY, &gp.ownerPolicy);
622 NvReadReserved(NV_ENDORSEMENT_POLICY, &gp.endorsementPolicy);
623 NvReadReserved(NV_LOCKOUT_POLICY, &gp.lockoutPolicy);
624 NvReadReserved(NV_OWNER_AUTH, &gp.ownerAuth);
625 NvReadReserved(NV_ENDORSEMENT_AUTH, &gp.endorsementAuth);
626 NvReadReserved(NV_LOCKOUT_AUTH, &gp.lockoutAuth);
627 NvReadReserved(NV_EP_SEED, &gp.EPSeed);
628 NvReadReserved(NV_SP_SEED, &gp.SPSeed);
629 NvReadReserved(NV_PP_SEED, &gp.PPSeed);
630 NvReadReserved(NV_PH_PROOF, &gp.phProof);
631 NvReadReserved(NV_SH_PROOF, &gp.shProof);
632 NvReadReserved(NV_EH_PROOF, &gp.ehProof);
633 // Time persistent data
634 NvReadReserved(NV_TOTAL_RESET_COUNT, &gp.totalResetCount);
635 NvReadReserved(NV_RESET_COUNT, &gp.resetCount);
636 // PCR persistent data
637 NvReadReserved(NV_PCR_POLICIES, &gp.pcrPolicies);
638 NvReadReserved(NV_PCR_ALLOCATED, &gp.pcrAllocated);
639 // Physical Presence persistent data
640 NvReadReserved(NV_PP_LIST, &gp.ppList);
641 // Dictionary attack values persistent data
642 NvReadReserved(NV_FAILED_TRIES, &gp.failedTries);
643 NvReadReserved(NV_MAX_TRIES, &gp.maxTries);
644 NvReadReserved(NV_RECOVERY_TIME, &gp.recoveryTime);
645 //
646 NvReadReserved(NV_LOCKOUT_RECOVERY, &gp.lockoutRecovery);
647 NvReadReserved(NV_LOCKOUT_AUTH_ENABLED, &gp.lockOutAuthEnabled);
648 // Orderly State persistent data
649 NvReadReserved(NV_ORDERLY, &gp.orderlyState);
650 // Command audit values persistent data
651 NvReadReserved(NV_AUDIT_COMMANDS, &gp.auditComands);
652 NvReadReserved(NV_AUDIT_HASH_ALG, &gp.auditHashAlg);
653 NvReadReserved(NV_AUDIT_COUNTER, &gp.auditCounter);
654 // Algorithm selection persistent data
655 NvReadReserved(NV_ALGORITHM_SET, &gp.algorithmSet);
656 // Firmware version persistent data
657 NvReadReserved(NV_FIRMWARE_V1, &gp.firmwareV1);
658 NvReadReserved(NV_FIRMWARE_V2, &gp.firmwareV2);
659 return;
660 }
661 //
662 //
663 // NvIsPlatformPersistentHandle()
664 //
665 // This function indicates if a handle references a persistent object in the range belonging to the platform.
666 //
667 // Return Value Meaning
668 //
669 // TRUE handle references a platform persistent object
670 // FALSE handle does not reference platform persistent object and may
671 // reference an owner persistent object either
672 //
673 BOOL
NvIsPlatformPersistentHandle(TPM_HANDLE handle)674 NvIsPlatformPersistentHandle(
675 TPM_HANDLE handle // IN: handle
676 )
677 {
678 return (handle >= PLATFORM_PERSISTENT && handle <= PERSISTENT_LAST);
679 }
680 //
681 //
682 // NvIsOwnerPersistentHandle()
683 //
684 // This function indicates if a handle references a persistent object in the range belonging to the owner.
685 //
686 // Return Value Meaning
687 //
688 // TRUE handle is owner persistent handle
689 // FALSE handle is not owner persistent handle and may not be a persistent
690 // handle at all
691 //
692 BOOL
NvIsOwnerPersistentHandle(TPM_HANDLE handle)693 NvIsOwnerPersistentHandle(
694 TPM_HANDLE handle // IN: handle
695 )
696 {
697 return (handle >= PERSISTENT_FIRST && handle < PLATFORM_PERSISTENT);
698 }
699 //
700 //
701 // NvNextIndex()
702 //
703 // This function returns the offset in NV of the next NV Index entry. A value of 0 indicates the end of the list.
704 // Family "2.0" TCG Published Page 131
705 // Level 00 Revision 01.16 Copyright © TCG 2006-2014 October 30, 2014
706 // Trusted Platform Module Library Part 4: Supporting Routines
707 //
708 static UINT32
NvNextIndex(NV_ITER * iter)709 NvNextIndex(
710 NV_ITER *iter
711 )
712 {
713 UINT32 addr;
714 TPM_HANDLE handle;
715 while((addr = NvNext(iter)) != 0)
716 {
717 // Read handle
718 _plat__NvMemoryRead(addr, sizeof(TPM_HANDLE), &handle);
719 if(HandleGetType(handle) == TPM_HT_NV_INDEX)
720 return addr;
721 }
722 pAssert(addr == 0);
723 return addr;
724 }
725 //
726 //
727 // NvNextEvict()
728 //
729 // This function returns the offset in NV of the next evict object entry. A value of 0 indicates the end of the
730 // list.
731 //
732 static UINT32
NvNextEvict(NV_ITER * iter)733 NvNextEvict(
734 NV_ITER *iter
735 )
736 {
737 UINT32 addr;
738 TPM_HANDLE handle;
739 while((addr = NvNext(iter)) != 0)
740 {
741 // Read handle
742 _plat__NvMemoryRead(addr, sizeof(TPM_HANDLE), &handle);
743 if(HandleGetType(handle) == TPM_HT_PERSISTENT)
744 return addr;
745 }
746 pAssert(addr == 0);
747 return addr;
748 }
749 //
750 //
751 // NvFindHandle()
752 //
753 // this function returns the offset in NV memory of the entity associated with the input handle. A value of
754 // zero indicates that handle does not exist reference an existing persistent object or defined NV Index.
755 //
756 static UINT32
NvFindHandle(TPM_HANDLE handle)757 NvFindHandle(
758 TPM_HANDLE handle
759 )
760 {
761 UINT32 addr;
762 NV_ITER iter = NV_ITER_INIT;
763 while((addr = NvNext(&iter)) != 0)
764 {
765 TPM_HANDLE entityHandle;
766 // Read handle
767 //
768 _plat__NvMemoryRead(addr, sizeof(TPM_HANDLE), &entityHandle);
769 if(entityHandle == handle)
770 return addr;
771 }
772 pAssert(addr == 0);
773 return addr;
774 }
775 //
776 //
777 // NvPowerOn()
778 //
779 // This function is called at _TPM_Init() to initialize the NV environment.
780 //
781 // Return Value Meaning
782 //
783 // TRUE all NV was initialized
784 // FALSE the NV containing saved state had an error and
785 // TPM2_Startup(CLEAR) is required
786 //
787 BOOL
NvPowerOn(void)788 NvPowerOn(
789 void
790 )
791 {
792 int nvError = 0;
793 // If power was lost, need to re-establish the RAM data that is loaded from
794 // NV and initialize the static variables
795 if(_plat__WasPowerLost(TRUE))
796 {
797 if((nvError = _plat__NVEnable(0)) < 0)
798 FAIL(FATAL_ERROR_NV_UNRECOVERABLE);
799 NvInitStatic();
800 }
801 return nvError == 0;
802 }
803 //
804 //
805 // NvStateSave()
806 //
807 // This function is used to cause the memory containing the RAM backed NV Indices to be written to NV.
808 //
809 void
NvStateSave(void)810 NvStateSave(
811 void
812 )
813 {
814 // Write RAM backed NV Index info to NV
815 // No need to save s_ramIndexSize because we save it to NV whenever it is
816 // updated.
817 _plat__NvMemoryWrite(s_ramIndexAddr, RAM_INDEX_SPACE, s_ramIndex);
818 // Set the flag so that an NV write happens before the command completes.
819 g_updateNV = TRUE;
820 return;
821 }
822 //
823 //
824 //
825 // NvEntityStartup()
826 //
827 // This function is called at TPM_Startup(). If the startup completes a TPM Resume cycle, no action is
828 // taken. If the startup is a TPM Reset or a TPM Restart, then this function will:
829 // a) clear read/write lock;
830 // b) reset NV Index data that has TPMA_NV_CLEAR_STCLEAR SET; and
831 // c) set the lower bits in orderly counters to 1 for a non-orderly startup
832 // It is a prerequisite that NV be available for writing before this function is called.
833 //
834 void
NvEntityStartup(STARTUP_TYPE type)835 NvEntityStartup(
836 STARTUP_TYPE type // IN: start up type
837 )
838 {
839 NV_ITER iter = NV_ITER_INIT;
840 UINT32 currentAddr; // offset points to the current entity
841 // Restore RAM index data
842 _plat__NvMemoryRead(s_ramIndexSizeAddr, sizeof(UINT32), &s_ramIndexSize);
843 _plat__NvMemoryRead(s_ramIndexAddr, RAM_INDEX_SPACE, s_ramIndex);
844 // If recovering from state save, do nothing
845 if(type == SU_RESUME)
846 return;
847 // Iterate all the NV Index to clear the locks
848 while((currentAddr = NvNextIndex(&iter)) != 0)
849 {
850 NV_INDEX nvIndex;
851 UINT32 indexAddr; // NV address points to index info
852 TPMA_NV attributes;
853 UINT32 attributesValue;
854 UINT32 publicAreaAttributesValue;
855 indexAddr = currentAddr + sizeof(TPM_HANDLE);
856 // Read NV Index info structure
857 _plat__NvMemoryRead(indexAddr, sizeof(NV_INDEX), &nvIndex);
858 attributes = nvIndex.publicArea.attributes;
859 // Clear read/write lock
860 if(attributes.TPMA_NV_READLOCKED == SET)
861 attributes.TPMA_NV_READLOCKED = CLEAR;
862 if( attributes.TPMA_NV_WRITELOCKED == SET
863 && ( attributes.TPMA_NV_WRITTEN == CLEAR
864 || attributes.TPMA_NV_WRITEDEFINE == CLEAR
865 )
866 )
867 attributes.TPMA_NV_WRITELOCKED = CLEAR;
868 // Reset NV data for TPMA_NV_CLEAR_STCLEAR
869 if(attributes.TPMA_NV_CLEAR_STCLEAR == SET)
870 {
871 attributes.TPMA_NV_WRITTEN = CLEAR;
872 attributes.TPMA_NV_WRITELOCKED = CLEAR;
873 }
874 // Reset NV data for orderly values that are not counters
875 // NOTE: The function has already exited on a TPM Resume, so the only
876 // things being processed are TPM Restart and TPM Reset
877 if( type == SU_RESET
878 && attributes.TPMA_NV_ORDERLY == SET
879 && attributes.TPMA_NV_COUNTER == CLEAR
880 )
881 attributes.TPMA_NV_WRITTEN = CLEAR;
882 // Write NV Index info back if it has changed
883 memcpy(&attributesValue, &attributes, sizeof(attributesValue));
884 memcpy(&publicAreaAttributesValue, &nvIndex.publicArea.attributes,
885 sizeof(publicAreaAttributesValue));
886 if(attributesValue != publicAreaAttributesValue)
887 {
888 nvIndex.publicArea.attributes = attributes;
889 _plat__NvMemoryWrite(indexAddr, sizeof(NV_INDEX), &nvIndex);
890 // Set the flag that a NV write happens
891 g_updateNV = TRUE;
892 }
893 // Set the lower bits in an orderly counter to 1 for a non-orderly startup
894 if( g_prevOrderlyState == SHUTDOWN_NONE
895 && attributes.TPMA_NV_WRITTEN == SET)
896 {
897 if( attributes.TPMA_NV_ORDERLY == SET
898 && attributes.TPMA_NV_COUNTER == SET)
899 {
900 TPMI_RH_NV_INDEX nvHandle;
901 UINT64 counter;
902 // Read NV handle
903 _plat__NvMemoryRead(currentAddr, sizeof(TPM_HANDLE), &nvHandle);
904 // Read the counter value saved to NV upon the last roll over.
905 // Do not use RAM backed storage for this once.
906 nvIndex.publicArea.attributes.TPMA_NV_ORDERLY = CLEAR;
907 NvGetIntIndexData(nvHandle, &nvIndex, &counter);
908 nvIndex.publicArea.attributes.TPMA_NV_ORDERLY = SET;
909 // Set the lower bits of counter to 1's
910 counter |= MAX_ORDERLY_COUNT;
911 // Write back to RAM
912 NvWriteIndexData(nvHandle, &nvIndex, 0, sizeof(counter), &counter);
913 // No write to NV because an orderly shutdown will update the
914 // counters.
915 }
916 }
917 }
918 return;
919 }
920 //
921 //
922 // NV Access Functions
923 //
924 // Introduction
925 //
926 // This set of functions provide accessing NV Index and persistent objects based using a handle for
927 // reference to the entity.
928 //
929 // NvIsUndefinedIndex()
930 //
931 // This function is used to verify that an NV Index is not defined. This is only used by
932 // TPM2_NV_DefineSpace().
933 //
934 //
935 //
936 //
937 // Return Value Meaning
938 //
939 // TRUE the handle points to an existing NV Index
940 // FALSE the handle points to a non-existent Index
941 //
942 BOOL
NvIsUndefinedIndex(TPMI_RH_NV_INDEX handle)943 NvIsUndefinedIndex(
944 TPMI_RH_NV_INDEX handle // IN: handle
945 )
946 {
947 UINT32 entityAddr; // offset points to the entity
948 pAssert(HandleGetType(handle) == TPM_HT_NV_INDEX);
949 // Find the address of index
950 entityAddr = NvFindHandle(handle);
951 // If handle is not found, return TPM_RC_SUCCESS
952 if(entityAddr == 0)
953 return TPM_RC_SUCCESS;
954 // NV Index is defined
955 return TPM_RC_NV_DEFINED;
956 }
957 //
958 //
959 // NvIndexIsAccessible()
960 //
961 // This function validates that a handle references a defined NV Index and that the Index is currently
962 // accessible.
963 //
964 // Error Returns Meaning
965 //
966 // TPM_RC_HANDLE the handle points to an undefined NV Index If shEnable is CLEAR,
967 // this would include an index created using ownerAuth. If phEnableNV
968 // is CLEAR, this would include and index created using platform auth
969 // TPM_RC_NV_READLOCKED Index is present but locked for reading and command does not write
970 // to the index
971 // TPM_RC_NV_WRITELOCKED Index is present but locked for writing and command writes to the
972 // index
973 //
974 TPM_RC
NvIndexIsAccessible(TPMI_RH_NV_INDEX handle,TPM_CC commandCode)975 NvIndexIsAccessible(
976 TPMI_RH_NV_INDEX handle, // IN: handle
977 TPM_CC commandCode // IN: the command
978 )
979 {
980 UINT32 entityAddr; // offset points to the entity
981 NV_INDEX nvIndex; //
982 pAssert(HandleGetType(handle) == TPM_HT_NV_INDEX);
983 // Find the address of index
984 entityAddr = NvFindHandle(handle);
985 // If handle is not found, return TPM_RC_HANDLE
986 if(entityAddr == 0)
987 return TPM_RC_HANDLE;
988 // Read NV Index info structure
989 _plat__NvMemoryRead(entityAddr + sizeof(TPM_HANDLE), sizeof(NV_INDEX),
990 &nvIndex);
991 if(gc.shEnable == FALSE || gc.phEnableNV == FALSE)
992 {
993 // if shEnable is CLEAR, an ownerCreate NV Index should not be
994 // indicated as present
995 if(nvIndex.publicArea.attributes.TPMA_NV_PLATFORMCREATE == CLEAR)
996 {
997 if(gc.shEnable == FALSE)
998 return TPM_RC_HANDLE;
999 }
1000 // if phEnableNV is CLEAR, a platform created Index should not
1001 // be visible
1002 else if(gc.phEnableNV == FALSE)
1003 return TPM_RC_HANDLE;
1004 }
1005 // If the Index is write locked and this is an NV Write operation...
1006 if( nvIndex.publicArea.attributes.TPMA_NV_WRITELOCKED
1007 && IsWriteOperation(commandCode))
1008 {
1009 // then return a locked indication unless the command is TPM2_NV_WriteLock
1010 if(commandCode != TPM_CC_NV_WriteLock)
1011 return TPM_RC_NV_LOCKED;
1012 return TPM_RC_SUCCESS;
1013 }
1014 // If the Index is read locked and this is an NV Read operation...
1015 if( nvIndex.publicArea.attributes.TPMA_NV_READLOCKED
1016 && IsReadOperation(commandCode))
1017 {
1018 // then return a locked indication unless the command is TPM2_NV_ReadLock
1019 if(commandCode != TPM_CC_NV_ReadLock)
1020 return TPM_RC_NV_LOCKED;
1021 return TPM_RC_SUCCESS;
1022 }
1023 // NV Index is accessible
1024 return TPM_RC_SUCCESS;
1025 }
1026 //
1027 //
1028 // NvIsUndefinedEvictHandle()
1029 //
1030 // This function indicates if a handle does not reference an existing persistent object. This function requires
1031 // that the handle be in the proper range for persistent objects.
1032 //
1033 // Return Value Meaning
1034 //
1035 // TRUE handle does not reference an existing persistent object
1036 // FALSE handle does reference an existing persistent object
1037 //
1038 static BOOL
NvIsUndefinedEvictHandle(TPM_HANDLE handle)1039 NvIsUndefinedEvictHandle(
1040 TPM_HANDLE handle // IN: handle
1041 )
1042 {
1043 UINT32 entityAddr; // offset points to the entity
1044 pAssert(HandleGetType(handle) == TPM_HT_PERSISTENT);
1045 // Find the address of evict object
1046 entityAddr = NvFindHandle(handle);
1047 // If handle is not found, return TRUE
1048 if(entityAddr == 0)
1049 return TRUE;
1050 else
1051 return FALSE;
1052 }
1053 //
1054 //
1055 // NvGetEvictObject()
1056 //
1057 // This function is used to dereference an evict object handle and get a pointer to the object.
1058 //
1059 // Error Returns Meaning
1060 //
1061 // TPM_RC_HANDLE the handle does not point to an existing persistent object
1062 //
1063 TPM_RC
NvGetEvictObject(TPM_HANDLE handle,OBJECT * object)1064 NvGetEvictObject(
1065 TPM_HANDLE handle, // IN: handle
1066 OBJECT *object // OUT: object data
1067 )
1068 {
1069 UINT32 entityAddr; // offset points to the entity
1070 TPM_RC result = TPM_RC_SUCCESS;
1071 pAssert(HandleGetType(handle) == TPM_HT_PERSISTENT);
1072 // Find the address of evict object
1073 entityAddr = NvFindHandle(handle);
1074 // If handle is not found, return an error
1075 if(entityAddr == 0)
1076 result = TPM_RC_HANDLE;
1077 else
1078 // Read evict object
1079 _plat__NvMemoryRead(entityAddr + sizeof(TPM_HANDLE),
1080 sizeof(OBJECT),
1081 object);
1082 // whether there is an error or not, make sure that the evict
1083 // status of the object is set so that the slot will get freed on exit
1084 object->attributes.evict = SET;
1085 return result;
1086 }
1087 //
1088 //
1089 // NvGetIndexInfo()
1090 //
1091 // This function is used to retrieve the contents of an NV Index.
1092 // An implementation is allowed to save the NV Index in a vendor-defined format. If the format is different
1093 // from the default used by the reference code, then this function would be changed to reformat the data into
1094 // the default format.
1095 // A prerequisite to calling this function is that the handle must be known to reference a defined NV Index.
1096 //
1097 void
NvGetIndexInfo(TPMI_RH_NV_INDEX handle,NV_INDEX * nvIndex)1098 NvGetIndexInfo(
1099 TPMI_RH_NV_INDEX handle, // IN: handle
1100 NV_INDEX *nvIndex // OUT: NV index structure
1101 )
1102 {
1103 UINT32 entityAddr; // offset points to the entity
1104 pAssert(HandleGetType(handle) == TPM_HT_NV_INDEX);
1105 // Find the address of NV index
1106 entityAddr = NvFindHandle(handle);
1107 pAssert(entityAddr != 0);
1108 // This implementation uses the default format so just
1109 // read the data in
1110 _plat__NvMemoryRead(entityAddr + sizeof(TPM_HANDLE), sizeof(NV_INDEX),
1111 nvIndex);
1112 return;
1113 }
1114 //
1115 //
1116 // NvInitialCounter()
1117 //
1118 // This function returns the value to be used when a counter index is initialized. It will scan the NV counters
1119 // and find the highest value in any active counter. It will use that value as the starting point. If there are no
1120 // active counters, it will use the value of the previous largest counter.
1121 //
1122 UINT64
NvInitialCounter(void)1123 NvInitialCounter(
1124 void
1125 )
1126 {
1127 UINT64 maxCount;
1128 NV_ITER iter = NV_ITER_INIT;
1129 UINT32 currentAddr;
1130 // Read the maxCount value
1131 maxCount = NvReadMaxCount();
1132 // Iterate all existing counters
1133 while((currentAddr = NvNextIndex(&iter)) != 0)
1134 {
1135 TPMI_RH_NV_INDEX nvHandle;
1136 NV_INDEX nvIndex;
1137 // Read NV handle
1138 _plat__NvMemoryRead(currentAddr, sizeof(TPM_HANDLE), &nvHandle);
1139 // Get NV Index
1140 NvGetIndexInfo(nvHandle, &nvIndex);
1141 if( nvIndex.publicArea.attributes.TPMA_NV_COUNTER == SET
1142 && nvIndex.publicArea.attributes.TPMA_NV_WRITTEN == SET)
1143 {
1144 UINT64 countValue;
1145 // Read counter value
1146 NvGetIntIndexData(nvHandle, &nvIndex, &countValue);
1147 if(countValue > maxCount)
1148 maxCount = countValue;
1149 }
1150 }
1151 // Initialize the new counter value to be maxCount + 1
1152 // A counter is only initialized the first time it is written. The
1153 // way to write a counter is with TPM2_NV_INCREMENT(). Since the
1154 // "initial" value of a defined counter is the largest count value that
1155 // may have existed in this index previously, then the first use would
1156 // add one to that value.
1157 return maxCount;
1158 }
1159 //
1160 //
1161 // NvGetIndexData()
1162 //
1163 // This function is used to access the data in an NV Index. The data is returned as a byte sequence. Since
1164 // counter values are kept in native format, they are converted to canonical form before being returned.
1165 // Family "2.0" TCG Published Page 139
1166 // Level 00 Revision 01.16 Copyright © TCG 2006-2014 October 30, 2014
1167 // Trusted Platform Module Library Part 4: Supporting Routines
1168 //
1169 //
1170 // This function requires that the NV Index be defined, and that the required data is within the data range. It
1171 // also requires that TPMA_NV_WRITTEN of the Index is SET.
1172 //
1173 void
NvGetIndexData(TPMI_RH_NV_INDEX handle,NV_INDEX * nvIndex,UINT32 offset,UINT16 size,void * data)1174 NvGetIndexData(
1175 TPMI_RH_NV_INDEX handle, // IN: handle
1176 NV_INDEX *nvIndex, // IN: RAM image of index header
1177 UINT32 offset, // IN: offset of NV data
1178 UINT16 size, // IN: size of NV data
1179 void *data // OUT: data buffer
1180 )
1181 {
1182 pAssert(nvIndex->publicArea.attributes.TPMA_NV_WRITTEN == SET);
1183 if( nvIndex->publicArea.attributes.TPMA_NV_BITS == SET
1184 || nvIndex->publicArea.attributes.TPMA_NV_COUNTER == SET)
1185 {
1186 // Read bit or counter data in canonical form
1187 UINT64 dataInInt;
1188 NvGetIntIndexData(handle, nvIndex, &dataInInt);
1189 UINT64_TO_BYTE_ARRAY(dataInInt, (BYTE *)data);
1190 }
1191 else
1192 {
1193 if(nvIndex->publicArea.attributes.TPMA_NV_ORDERLY == SET)
1194 {
1195 UINT32 ramAddr;
1196 // Get data from RAM buffer
1197 ramAddr = NvGetRAMIndexOffset(handle);
1198 MemoryCopy(data, s_ramIndex + ramAddr + offset, size, size);
1199 }
1200 else
1201 {
1202 UINT32 entityAddr;
1203 entityAddr = NvFindHandle(handle);
1204 // Get data from NV
1205 // Skip NV Index info, read data buffer
1206 entityAddr += sizeof(TPM_HANDLE) + sizeof(NV_INDEX) + offset;
1207 // Read the data
1208 _plat__NvMemoryRead(entityAddr, size, data);
1209 }
1210 }
1211 return;
1212 }
1213 //
1214 //
1215 // NvGetIntIndexData()
1216 //
1217 // Get data in integer format of a bit or counter NV Index.
1218 // This function requires that the NV Index is defined and that the NV Index previously has been written.
1219 //
1220 void
NvGetIntIndexData(TPMI_RH_NV_INDEX handle,NV_INDEX * nvIndex,UINT64 * data)1221 NvGetIntIndexData(
1222 TPMI_RH_NV_INDEX handle, // IN: handle
1223 NV_INDEX *nvIndex, // IN: RAM image of NV Index header
1224 UINT64 *data // IN: UINT64 pointer for counter or bit
1225 )
1226 {
1227 // Validate that index has been written and is the right type
1228 pAssert( nvIndex->publicArea.attributes.TPMA_NV_WRITTEN == SET
1229 && ( nvIndex->publicArea.attributes.TPMA_NV_BITS == SET
1230 || nvIndex->publicArea.attributes.TPMA_NV_COUNTER == SET
1231 )
1232 );
1233 // bit and counter value is store in native format for TPM CPU. So we directly
1234 // copy the contents of NV to output data buffer
1235 if(nvIndex->publicArea.attributes.TPMA_NV_ORDERLY == SET)
1236 {
1237 UINT32 ramAddr;
1238 // Get data from RAM buffer
1239 ramAddr = NvGetRAMIndexOffset(handle);
1240 MemoryCopy(data, s_ramIndex + ramAddr, sizeof(*data), sizeof(*data));
1241 }
1242 else
1243 {
1244 UINT32 entityAddr;
1245 entityAddr = NvFindHandle(handle);
1246 // Get data from NV
1247 // Skip NV Index info, read data buffer
1248 _plat__NvMemoryRead(
1249 entityAddr + sizeof(TPM_HANDLE) + sizeof(NV_INDEX),
1250 sizeof(UINT64), data);
1251 }
1252 return;
1253 }
1254 //
1255 //
1256 // NvWriteIndexInfo()
1257 //
1258 // This function is called to queue the write of NV Index data to persistent memory.
1259 // This function requires that NV Index is defined.
1260 //
1261 // Error Returns Meaning
1262 //
1263 // TPM_RC_NV_RATE NV is rate limiting so retry
1264 // TPM_RC_NV_UNAVAILABLE NV is not available
1265 //
1266 TPM_RC
NvWriteIndexInfo(TPMI_RH_NV_INDEX handle,NV_INDEX * nvIndex)1267 NvWriteIndexInfo(
1268 TPMI_RH_NV_INDEX handle, // IN: handle
1269 NV_INDEX *nvIndex // IN: NV Index info to be written
1270 )
1271 {
1272 UINT32 entryAddr;
1273 TPM_RC result;
1274 // Get the starting offset for the index in the RAM image of NV
1275 entryAddr = NvFindHandle(handle);
1276 pAssert(entryAddr != 0);
1277 // Step over the link value
1278 entryAddr = entryAddr + sizeof(TPM_HANDLE);
1279 // If the index data is actually changed, then a write to NV is required
1280 if(_plat__NvIsDifferent(entryAddr, sizeof(NV_INDEX),nvIndex))
1281 {
1282 // Make sure that NV is available
1283 result = NvIsAvailable();
1284 if(result != TPM_RC_SUCCESS)
1285 return result;
1286 _plat__NvMemoryWrite(entryAddr, sizeof(NV_INDEX), nvIndex);
1287 g_updateNV = TRUE;
1288 }
1289 return TPM_RC_SUCCESS;
1290 }
1291 //
1292 //
1293 // NvWriteIndexData()
1294 //
1295 // This function is used to write NV index data.
1296 // This function requires that the NV Index is defined, and the data is within the defined data range for the
1297 // index.
1298 //
1299 // Error Returns Meaning
1300 //
1301 // TPM_RC_NV_RATE NV is rate limiting so retry
1302 // TPM_RC_NV_UNAVAILABLE NV is not available
1303 //
1304 TPM_RC
NvWriteIndexData(TPMI_RH_NV_INDEX handle,NV_INDEX * nvIndex,UINT32 offset,UINT32 size,void * data)1305 NvWriteIndexData(
1306 TPMI_RH_NV_INDEX handle, // IN: handle
1307 NV_INDEX *nvIndex, // IN: RAM copy of NV Index
1308 UINT32 offset, // IN: offset of NV data
1309 UINT32 size, // IN: size of NV data
1310 void *data // OUT: data buffer
1311 )
1312 {
1313 TPM_RC result;
1314 // Validate that write falls within range of the index
1315 pAssert(nvIndex->publicArea.dataSize >= offset + size);
1316 // Update TPMA_NV_WRITTEN bit if necessary
1317 if(nvIndex->publicArea.attributes.TPMA_NV_WRITTEN == CLEAR)
1318 {
1319 nvIndex->publicArea.attributes.TPMA_NV_WRITTEN = SET;
1320 result = NvWriteIndexInfo(handle, nvIndex);
1321 if(result != TPM_RC_SUCCESS)
1322 return result;
1323 }
1324 // Check to see if process for an orderly index is required.
1325 if(nvIndex->publicArea.attributes.TPMA_NV_ORDERLY == SET)
1326 {
1327 UINT32 ramAddr;
1328 // Write data to RAM buffer
1329 ramAddr = NvGetRAMIndexOffset(handle);
1330 MemoryCopy(s_ramIndex + ramAddr + offset, data, size,
1331 sizeof(s_ramIndex) - ramAddr - offset);
1332 // NV update does not happen for orderly index. Have
1333 // to clear orderlyState to reflect that we have changed the
1334 // NV and an orderly shutdown is required. Only going to do this if we
1335 // are not processing a counter that has just rolled over
1336 if(g_updateNV == FALSE)
1337 g_clearOrderly = TRUE;
1338 }
1339 // Need to process this part if the Index isn't orderly or if it is
1340 // an orderly counter that just rolled over.
1341 if(g_updateNV || nvIndex->publicArea.attributes.TPMA_NV_ORDERLY == CLEAR)
1342 {
1343 // Processing for an index with TPMA_NV_ORDERLY CLEAR
1344 UINT32 entryAddr = NvFindHandle(handle);
1345 pAssert(entryAddr != 0);
1346 //
1347 // Offset into the index to the first byte of the data to be written
1348 entryAddr += sizeof(TPM_HANDLE) + sizeof(NV_INDEX) + offset;
1349 // If the data is actually changed, then a write to NV is required
1350 if(_plat__NvIsDifferent(entryAddr, size, data))
1351 {
1352 // Make sure that NV is available
1353 result = NvIsAvailable();
1354 if(result != TPM_RC_SUCCESS)
1355 return result;
1356 _plat__NvMemoryWrite(entryAddr, size, data);
1357 g_updateNV = TRUE;
1358 }
1359 }
1360 return TPM_RC_SUCCESS;
1361 }
1362 //
1363 //
1364 // NvGetName()
1365 //
1366 // This function is used to compute the Name of an NV Index.
1367 // The name buffer receives the bytes of the Name and the return value is the number of octets in the
1368 // Name.
1369 // This function requires that the NV Index is defined.
1370 //
1371 UINT16
NvGetName(TPMI_RH_NV_INDEX handle,NAME * name)1372 NvGetName(
1373 TPMI_RH_NV_INDEX handle, // IN: handle of the index
1374 NAME *name // OUT: name of the index
1375 )
1376 {
1377 UINT16 dataSize, digestSize;
1378 NV_INDEX nvIndex;
1379 BYTE marshalBuffer[sizeof(TPMS_NV_PUBLIC)];
1380 BYTE *buffer;
1381 INT32 bufferSize;
1382 HASH_STATE hashState;
1383 // Get NV public info
1384 NvGetIndexInfo(handle, &nvIndex);
1385 // Marshal public area
1386 buffer = marshalBuffer;
1387 bufferSize = sizeof(TPMS_NV_PUBLIC);
1388 dataSize = TPMS_NV_PUBLIC_Marshal(&nvIndex.publicArea, &buffer, &bufferSize);
1389 // hash public area
1390 digestSize = CryptStartHash(nvIndex.publicArea.nameAlg, &hashState);
1391 CryptUpdateDigest(&hashState, dataSize, marshalBuffer);
1392 // Complete digest leaving room for the nameAlg
1393 CryptCompleteHash(&hashState, digestSize, &((BYTE *)name)[2]);
1394 // Include the nameAlg
1395 UINT16_TO_BYTE_ARRAY(nvIndex.publicArea.nameAlg, (BYTE *)name);
1396 return digestSize + 2;
1397 }
1398 //
1399 //
1400 // NvDefineIndex()
1401 //
1402 // This function is used to assign NV memory to an NV Index.
1403 //
1404 //
1405 //
1406 // Error Returns Meaning
1407 //
1408 // TPM_RC_NV_SPACE insufficient NV space
1409 //
1410 TPM_RC
NvDefineIndex(TPMS_NV_PUBLIC * publicArea,TPM2B_AUTH * authValue)1411 NvDefineIndex(
1412 TPMS_NV_PUBLIC *publicArea, // IN: A template for an area to create.
1413 TPM2B_AUTH *authValue // IN: The initial authorization value
1414 )
1415 {
1416 // The buffer to be written to NV memory
1417 BYTE nvBuffer[sizeof(TPM_HANDLE) + sizeof(NV_INDEX)];
1418 NV_INDEX *nvIndex; // a pointer to the NV_INDEX data in
1419 // nvBuffer
1420 UINT16 entrySize; // size of entry
1421 entrySize = sizeof(TPM_HANDLE) + sizeof(NV_INDEX) + publicArea->dataSize;
1422 // Check if we have enough space to create the NV Index
1423 // In this implementation, the only resource limitation is the available NV
1424 // space. Other implementation may have other limitation on counter or on
1425 // NV slot
1426 if(!NvTestSpace(entrySize, TRUE)) return TPM_RC_NV_SPACE;
1427 // if the index to be defined is RAM backed, check RAM space availability
1428 // as well
1429 if(publicArea->attributes.TPMA_NV_ORDERLY == SET
1430 && !NvTestRAMSpace(publicArea->dataSize))
1431 return TPM_RC_NV_SPACE;
1432 // Copy input value to nvBuffer
1433 // Copy handle
1434 memcpy(nvBuffer, &publicArea->nvIndex, sizeof(TPM_HANDLE));
1435 // Copy NV_INDEX
1436 nvIndex = (NV_INDEX *) (nvBuffer + sizeof(TPM_HANDLE));
1437 nvIndex->publicArea = *publicArea;
1438 nvIndex->authValue = *authValue;
1439 // Add index to NV memory
1440 NvAdd(entrySize, sizeof(TPM_HANDLE) + sizeof(NV_INDEX), nvBuffer);
1441 // If the data of NV Index is RAM backed, add the data area in RAM as well
1442 if(publicArea->attributes.TPMA_NV_ORDERLY == SET)
1443 NvAddRAM(publicArea->nvIndex, publicArea->dataSize);
1444 return TPM_RC_SUCCESS;
1445 }
1446 //
1447 //
1448 // NvAddEvictObject()
1449 //
1450 // This function is used to assign NV memory to a persistent object.
1451 //
1452 // Error Returns Meaning
1453 //
1454 // TPM_RC_NV_HANDLE the requested handle is already in use
1455 // TPM_RC_NV_SPACE insufficient NV space
1456 //
1457 TPM_RC
NvAddEvictObject(TPMI_DH_OBJECT evictHandle,OBJECT * object)1458 NvAddEvictObject(
1459 TPMI_DH_OBJECT evictHandle, // IN: new evict handle
1460 //
1461 OBJECT *object // IN: object to be added
1462 )
1463 {
1464 // The buffer to be written to NV memory
1465 BYTE nvBuffer[sizeof(TPM_HANDLE) + sizeof(OBJECT)];
1466 OBJECT *nvObject; // a pointer to the OBJECT data in
1467 // nvBuffer
1468 UINT16 entrySize; // size of entry
1469 // evict handle type should match the object hierarchy
1470 pAssert( ( NvIsPlatformPersistentHandle(evictHandle)
1471 && object->attributes.ppsHierarchy == SET)
1472 || ( NvIsOwnerPersistentHandle(evictHandle)
1473 && ( object->attributes.spsHierarchy == SET
1474 || object->attributes.epsHierarchy == SET)));
1475 // An evict needs 4 bytes of handle + sizeof OBJECT
1476 entrySize = sizeof(TPM_HANDLE) + sizeof(OBJECT);
1477 // Check if we have enough space to add the evict object
1478 // An evict object needs 8 bytes in index table + sizeof OBJECT
1479 // In this implementation, the only resource limitation is the available NV
1480 // space. Other implementation may have other limitation on evict object
1481 // handle space
1482 if(!NvTestSpace(entrySize, FALSE)) return TPM_RC_NV_SPACE;
1483 // Allocate a new evict handle
1484 if(!NvIsUndefinedEvictHandle(evictHandle))
1485 return TPM_RC_NV_DEFINED;
1486 // Copy evict object to nvBuffer
1487 // Copy handle
1488 memcpy(nvBuffer, &evictHandle, sizeof(TPM_HANDLE));
1489 // Copy OBJECT
1490 nvObject = (OBJECT *) (nvBuffer + sizeof(TPM_HANDLE));
1491 *nvObject = *object;
1492 // Set evict attribute and handle
1493 nvObject->attributes.evict = SET;
1494 nvObject->evictHandle = evictHandle;
1495 // Add evict to NV memory
1496 NvAdd(entrySize, entrySize, nvBuffer);
1497 return TPM_RC_SUCCESS;
1498 }
1499 //
1500 //
1501 // NvDeleteEntity()
1502 //
1503 // This function will delete a NV Index or an evict object.
1504 // This function requires that the index/evict object has been defined.
1505 //
1506 void
NvDeleteEntity(TPM_HANDLE handle)1507 NvDeleteEntity(
1508 TPM_HANDLE handle // IN: handle of entity to be deleted
1509 )
1510 {
1511 UINT32 entityAddr; // pointer to entity
1512 entityAddr = NvFindHandle(handle);
1513 pAssert(entityAddr != 0);
1514 if(HandleGetType(handle) == TPM_HT_NV_INDEX)
1515 {
1516 NV_INDEX nvIndex;
1517 // Read the NV Index info
1518 _plat__NvMemoryRead(entityAddr + sizeof(TPM_HANDLE), sizeof(NV_INDEX),
1519 &nvIndex);
1520 // If the entity to be deleted is a counter with the maximum counter
1521 // value, record it in NV memory
1522 if(nvIndex.publicArea.attributes.TPMA_NV_COUNTER == SET
1523 && nvIndex.publicArea.attributes.TPMA_NV_WRITTEN == SET)
1524 {
1525 UINT64 countValue;
1526 UINT64 maxCount;
1527 NvGetIntIndexData(handle, &nvIndex, &countValue);
1528 maxCount = NvReadMaxCount();
1529 if(countValue > maxCount)
1530 NvWriteMaxCount(countValue);
1531 }
1532 // If the NV Index is RAM back, delete the RAM data as well
1533 if(nvIndex.publicArea.attributes.TPMA_NV_ORDERLY == SET)
1534 NvDeleteRAM(handle);
1535 }
1536 NvDelete(entityAddr);
1537 return;
1538 }
1539 //
1540 //
1541 // NvFlushHierarchy()
1542 //
1543 // This function will delete persistent objects belonging to the indicated If the storage hierarchy is selected,
1544 // the function will also delete any NV Index define using ownerAuth.
1545 //
1546 void
NvFlushHierarchy(TPMI_RH_HIERARCHY hierarchy)1547 NvFlushHierarchy(
1548 TPMI_RH_HIERARCHY hierarchy // IN: hierarchy to be flushed.
1549 )
1550 {
1551 NV_ITER iter = NV_ITER_INIT;
1552 UINT32 currentAddr;
1553 while((currentAddr = NvNext(&iter)) != 0)
1554 {
1555 TPM_HANDLE entityHandle;
1556 // Read handle information.
1557 _plat__NvMemoryRead(currentAddr, sizeof(TPM_HANDLE), &entityHandle);
1558 if(HandleGetType(entityHandle) == TPM_HT_NV_INDEX)
1559 {
1560 // Handle NV Index
1561 NV_INDEX nvIndex;
1562 // If flush endorsement or platform hierarchy, no NV Index would be
1563 // flushed
1564 if(hierarchy == TPM_RH_ENDORSEMENT || hierarchy == TPM_RH_PLATFORM)
1565 continue;
1566 _plat__NvMemoryRead(currentAddr + sizeof(TPM_HANDLE),
1567 sizeof(NV_INDEX), &nvIndex);
1568 // For storage hierarchy, flush OwnerCreated index
1569 if( nvIndex.publicArea.attributes.TPMA_NV_PLATFORMCREATE == CLEAR)
1570 {
1571 // Delete the NV Index
1572 NvDelete(currentAddr);
1573 // Re-iterate from beginning after a delete
1574 iter = NV_ITER_INIT;
1575 // If the NV Index is RAM back, delete the RAM data as well
1576 if(nvIndex.publicArea.attributes.TPMA_NV_ORDERLY == SET)
1577 NvDeleteRAM(entityHandle);
1578 }
1579 }
1580 else if(HandleGetType(entityHandle) == TPM_HT_PERSISTENT)
1581 {
1582 OBJECT object;
1583 // Get evict object
1584 NvGetEvictObject(entityHandle, &object);
1585 // If the evict object belongs to the hierarchy to be flushed
1586 if( ( hierarchy == TPM_RH_PLATFORM
1587 && object.attributes.ppsHierarchy == SET)
1588 || ( hierarchy == TPM_RH_OWNER
1589 && object.attributes.spsHierarchy == SET)
1590 || ( hierarchy == TPM_RH_ENDORSEMENT
1591 && object.attributes.epsHierarchy == SET)
1592 )
1593 {
1594 // Delete the evict object
1595 NvDelete(currentAddr);
1596 // Re-iterate from beginning after a delete
1597 iter = NV_ITER_INIT;
1598 }
1599 }
1600 else
1601 {
1602 pAssert(FALSE);
1603 }
1604 }
1605 return;
1606 }
1607 //
1608 //
1609 // NvSetGlobalLock()
1610 //
1611 // This function is used to SET the TPMA_NV_WRITELOCKED attribute for all NV Indices that have
1612 // TPMA_NV_GLOBALLOCK SET. This function is use by TPM2_NV_GlobalWriteLock().
1613 //
1614 void
NvSetGlobalLock(void)1615 NvSetGlobalLock(
1616 void
1617 )
1618 {
1619 NV_ITER iter = NV_ITER_INIT;
1620 UINT32 currentAddr;
1621 // Check all Indices
1622 while((currentAddr = NvNextIndex(&iter)) != 0)
1623 {
1624 NV_INDEX nvIndex;
1625 // Read the index data
1626 _plat__NvMemoryRead(currentAddr + sizeof(TPM_HANDLE),
1627 sizeof(NV_INDEX), &nvIndex);
1628 // See if it should be locked
1629 if(nvIndex.publicArea.attributes.TPMA_NV_GLOBALLOCK == SET)
1630 {
1631 // if so, lock it
1632 nvIndex.publicArea.attributes.TPMA_NV_WRITELOCKED = SET;
1633 _plat__NvMemoryWrite(currentAddr + sizeof(TPM_HANDLE),
1634 sizeof(NV_INDEX), &nvIndex);
1635 // Set the flag that a NV write happens
1636 g_updateNV = TRUE;
1637 }
1638 }
1639 return;
1640 }
1641 //
1642 //
1643 // InsertSort()
1644 //
1645 // Sort a handle into handle list in ascending order. The total handle number in the list should not exceed
1646 // MAX_CAP_HANDLES
1647 //
1648 static void
InsertSort(TPML_HANDLE * handleList,UINT32 count,TPM_HANDLE entityHandle)1649 InsertSort(
1650 TPML_HANDLE *handleList, // IN/OUT: sorted handle list
1651 UINT32 count, // IN: maximum count in the handle list
1652 TPM_HANDLE entityHandle // IN: handle to be inserted
1653 )
1654 {
1655 UINT32 i, j;
1656 UINT32 originalCount;
1657 // For a corner case that the maximum count is 0, do nothing
1658 if(count == 0) return;
1659 // For empty list, add the handle at the beginning and return
1660 if(handleList->count == 0)
1661 {
1662 handleList->handle[0] = entityHandle;
1663 handleList->count++;
1664 return;
1665 }
1666 // Check if the maximum of the list has been reached
1667 originalCount = handleList->count;
1668 if(originalCount < count)
1669 handleList->count++;
1670 // Insert the handle to the list
1671 for(i = 0; i < originalCount; i++)
1672 {
1673 if(handleList->handle[i] > entityHandle)
1674 {
1675 for(j = handleList->count - 1; j > i; j--)
1676 {
1677 handleList->handle[j] = handleList->handle[j-1];
1678 }
1679 break;
1680 }
1681 }
1682 // If a slot was found, insert the handle in this position
1683 if(i < originalCount || handleList->count > originalCount)
1684 handleList->handle[i] = entityHandle;
1685 return;
1686 }
1687 //
1688 //
1689 // NvCapGetPersistent()
1690 //
1691 // This function is used to get a list of handles of the persistent objects, starting at handle.
1692 // Handle must be in valid persistent object handle range, but does not have to reference an existing
1693 // persistent object.
1694 //
1695 // Return Value Meaning
1696 //
1697 // YES if there are more handles available
1698 // NO all the available handles has been returned
1699 //
1700 TPMI_YES_NO
NvCapGetPersistent(TPMI_DH_OBJECT handle,UINT32 count,TPML_HANDLE * handleList)1701 NvCapGetPersistent(
1702 TPMI_DH_OBJECT handle, // IN: start handle
1703 UINT32 count, // IN: maximum number of returned handle
1704 TPML_HANDLE *handleList // OUT: list of handle
1705 )
1706 {
1707 TPMI_YES_NO more = NO;
1708 NV_ITER iter = NV_ITER_INIT;
1709 UINT32 currentAddr;
1710 pAssert(HandleGetType(handle) == TPM_HT_PERSISTENT);
1711 // Initialize output handle list
1712 handleList->count = 0;
1713 // The maximum count of handles we may return is MAX_CAP_HANDLES
1714 if(count > MAX_CAP_HANDLES) count = MAX_CAP_HANDLES;
1715 while((currentAddr = NvNextEvict(&iter)) != 0)
1716 {
1717 TPM_HANDLE entityHandle;
1718 // Read handle information.
1719 _plat__NvMemoryRead(currentAddr, sizeof(TPM_HANDLE), &entityHandle);
1720 // Ignore persistent handles that have values less than the input handle
1721 if(entityHandle < handle)
1722 continue;
1723 // if the handles in the list have reached the requested count, and there
1724 // are still handles need to be inserted, indicate that there are more.
1725 if(handleList->count == count)
1726 more = YES;
1727 // A handle with a value larger than start handle is a candidate
1728 // for return. Insert sort it to the return list. Insert sort algorithm
1729 // is chosen here for simplicity based on the assumption that the total
1730 // number of NV Indices is small. For an implementation that may allow
1731 // large number of NV Indices, a more efficient sorting algorithm may be
1732 // used here.
1733 InsertSort(handleList, count, entityHandle);
1734 //
1735 }
1736 return more;
1737 }
1738 //
1739 //
1740 // NvCapGetIndex()
1741 //
1742 // This function returns a list of handles of NV Indices, starting from handle. Handle must be in the range of
1743 // NV Indices, but does not have to reference an existing NV Index.
1744 //
1745 // Return Value Meaning
1746 //
1747 // YES if there are more handles to report
1748 // NO all the available handles has been reported
1749 //
1750 TPMI_YES_NO
NvCapGetIndex(TPMI_DH_OBJECT handle,UINT32 count,TPML_HANDLE * handleList)1751 NvCapGetIndex(
1752 TPMI_DH_OBJECT handle, // IN: start handle
1753 UINT32 count, // IN: maximum number of returned handle
1754 TPML_HANDLE *handleList // OUT: list of handle
1755 )
1756 {
1757 TPMI_YES_NO more = NO;
1758 NV_ITER iter = NV_ITER_INIT;
1759 UINT32 currentAddr;
1760 pAssert(HandleGetType(handle) == TPM_HT_NV_INDEX);
1761 // Initialize output handle list
1762 handleList->count = 0;
1763 // The maximum count of handles we may return is MAX_CAP_HANDLES
1764 if(count > MAX_CAP_HANDLES) count = MAX_CAP_HANDLES;
1765 while((currentAddr = NvNextIndex(&iter)) != 0)
1766 {
1767 TPM_HANDLE entityHandle;
1768 // Read handle information.
1769 _plat__NvMemoryRead(currentAddr, sizeof(TPM_HANDLE), &entityHandle);
1770 // Ignore index handles that have values less than the 'handle'
1771 if(entityHandle < handle)
1772 continue;
1773 // if the count of handles in the list has reached the requested count,
1774 // and there are still handles to report, set more.
1775 if(handleList->count == count)
1776 more = YES;
1777 // A handle with a value larger than start handle is a candidate
1778 // for return. Insert sort it to the return list. Insert sort algorithm
1779 // is chosen here for simplicity based on the assumption that the total
1780 // number of NV Indices is small. For an implementation that may allow
1781 // large number of NV Indices, a more efficient sorting algorithm may be
1782 // used here.
1783 InsertSort(handleList, count, entityHandle);
1784 }
1785 return more;
1786 }
1787 //
1788 //
1789 //
1790 // NvCapGetIndexNumber()
1791 //
1792 // This function returns the count of NV Indexes currently defined.
1793 //
1794 UINT32
NvCapGetIndexNumber(void)1795 NvCapGetIndexNumber(
1796 void
1797 )
1798 {
1799 UINT32 num = 0;
1800 NV_ITER iter = NV_ITER_INIT;
1801 while(NvNextIndex(&iter) != 0) num++;
1802 return num;
1803 }
1804 //
1805 //
1806 // NvCapGetPersistentNumber()
1807 //
1808 // Function returns the count of persistent objects currently in NV memory.
1809 //
1810 UINT32
NvCapGetPersistentNumber(void)1811 NvCapGetPersistentNumber(
1812 void
1813 )
1814 {
1815 UINT32 num = 0;
1816 NV_ITER iter = NV_ITER_INIT;
1817 while(NvNextEvict(&iter) != 0) num++;
1818 return num;
1819 }
1820 //
1821 //
1822 // NvCapGetPersistentAvail()
1823 //
1824 // This function returns an estimate of the number of additional persistent objects that could be loaded into
1825 // NV memory.
1826 //
1827 UINT32
NvCapGetPersistentAvail(void)1828 NvCapGetPersistentAvail(
1829 void
1830 )
1831 {
1832 UINT32 availSpace;
1833 UINT32 objectSpace;
1834 // Compute the available space in NV storage
1835 availSpace = NvGetFreeByte();
1836 // Get the space needed to add a persistent object to NV storage
1837 objectSpace = NvGetEvictObjectSize();
1838 return availSpace / objectSpace;
1839 }
1840 //
1841 //
1842 // NvCapGetCounterNumber()
1843 //
1844 // Get the number of defined NV Indexes that have NV TPMA_NV_COUNTER attribute SET.
1845 //
1846 //
1847 UINT32
NvCapGetCounterNumber(void)1848 NvCapGetCounterNumber(
1849 void
1850 )
1851 {
1852 NV_ITER iter = NV_ITER_INIT;
1853 UINT32 currentAddr;
1854 UINT32 num = 0;
1855 while((currentAddr = NvNextIndex(&iter)) != 0)
1856 {
1857 NV_INDEX nvIndex;
1858 // Get NV Index info
1859 _plat__NvMemoryRead(currentAddr + sizeof(TPM_HANDLE),
1860 sizeof(NV_INDEX), &nvIndex);
1861 if(nvIndex.publicArea.attributes.TPMA_NV_COUNTER == SET) num++;
1862 }
1863 return num;
1864 }
1865 //
1866 //
1867 // NvCapGetCounterAvail()
1868 //
1869 // This function returns an estimate of the number of additional counter type NV Indices that can be defined.
1870 //
1871 UINT32
NvCapGetCounterAvail(void)1872 NvCapGetCounterAvail(
1873 void
1874 )
1875 {
1876 UINT32 availNVSpace;
1877 UINT32 availRAMSpace;
1878 UINT32 counterNVSpace;
1879 UINT32 counterRAMSpace;
1880 UINT32 persistentNum = NvCapGetPersistentNumber();
1881 // Get the available space in NV storage
1882 availNVSpace = NvGetFreeByte();
1883 if (persistentNum < MIN_EVICT_OBJECTS)
1884 {
1885 // Some space have to be reserved for evict object. Adjust availNVSpace.
1886 UINT32 reserved = (MIN_EVICT_OBJECTS - persistentNum)
1887 * NvGetEvictObjectSize();
1888 if (reserved > availNVSpace)
1889 availNVSpace = 0;
1890 else
1891 availNVSpace -= reserved;
1892 }
1893 // Get the space needed to add a counter index to NV storage
1894 counterNVSpace = NvGetCounterSize();
1895 // Compute the available space in RAM
1896 availRAMSpace = RAM_INDEX_SPACE - s_ramIndexSize;
1897 // Compute the space needed to add a counter index to RAM storage
1898 // It takes an size field, a handle and sizeof(UINT64) for counter data
1899 counterRAMSpace = sizeof(UINT32) + sizeof(TPM_HANDLE) + sizeof(UINT64);
1900 // Return the min of counter number in NV and in RAM
1901 if(availNVSpace / counterNVSpace > availRAMSpace / counterRAMSpace)
1902 return availRAMSpace / counterRAMSpace;
1903 else
1904 return availNVSpace / counterNVSpace;
1905 }
1906