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    return s_NvStatus;
64}
65//
66//
67//           NvCommit
68//
69//     This is a wrapper for the platform function to commit pending NV writes.
70//
71BOOL
72NvCommit(
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//
85static UINT64
86NvReadMaxCount(
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//
100static void
101NvWriteMaxCount(
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//
130static UINT32
131NvNext(
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//
159static UINT32
160NvGetEnd(
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//
183static UINT32
184NvGetFreeByte(
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//
195static UINT32
196NvGetEvictObjectSize(
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//
208static UINT32
209NvGetCounterSize(
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//
228static BOOL
229NvTestSpace(
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//
272static void
273NvAdd(
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//
306static void
307NvDelete(
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//
369static BOOL
370NvTestRAMSpace(
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//
387static UINT32
388NvGetRAMIndexOffset(
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//
417static void
418NvAddRAM(
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//
444static void
445NvDeleteRAM(
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//
479static void
480NvInitStatic(
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//
551void
552NvInit(
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//
574void
575NvReadReserved(
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//
592void
593NvWriteReserved(
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//
611void
612NvReadPersistent(
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//
673BOOL
674NvIsPlatformPersistentHandle(
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//
692BOOL
693NvIsOwnerPersistentHandle(
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//
708static UINT32
709NvNextIndex(
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//
732static UINT32
733NvNextEvict(
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//
756static UINT32
757NvFindHandle(
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//
787BOOL
788NvPowerOn(
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//
809void
810NvStateSave(
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//
834void
835NvEntityStartup(
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//
942BOOL
943NvIsUndefinedIndex(
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//
974TPM_RC
975NvIndexIsAccessible(
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//
1038static BOOL
1039NvIsUndefinedEvictHandle(
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//
1063TPM_RC
1064NvGetEvictObject(
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//
1097void
1098NvGetIndexInfo(
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//
1122UINT64
1123NvInitialCounter(
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//
1173void
1174NvGetIndexData(
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//
1220void
1221NvGetIntIndexData(
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//
1266TPM_RC
1267NvWriteIndexInfo(
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//
1304TPM_RC
1305NvWriteIndexData(
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//
1371UINT16
1372NvGetName(
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//
1410TPM_RC
1411NvDefineIndex(
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//
1457TPM_RC
1458NvAddEvictObject(
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//
1506void
1507NvDeleteEntity(
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//
1546void
1547NvFlushHierarchy(
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//
1614void
1615NvSetGlobalLock(
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//
1648static void
1649InsertSort(
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//
1700TPMI_YES_NO
1701NvCapGetPersistent(
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//
1750TPMI_YES_NO
1751NvCapGetIndex(
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//
1794UINT32
1795NvCapGetIndexNumber(
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//
1810UINT32
1811NvCapGetPersistentNumber(
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//
1827UINT32
1828NvCapGetPersistentAvail(
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//
1847UINT32
1848NvCapGetCounterNumber(
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//
1871UINT32
1872NvCapGetCounterAvail(
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