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