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