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