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