• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Microsoft Reference Implementation for TPM 2.0
2  *
3  *  The copyright in this software is being made available under the BSD License,
4  *  included below. This software may be subject to other third party and
5  *  contributor rights, including patent rights, and no such rights are granted
6  *  under this license.
7  *
8  *  Copyright (c) Microsoft Corporation
9  *
10  *  All rights reserved.
11  *
12  *  BSD License
13  *
14  *  Redistribution and use in source and binary forms, with or without modification,
15  *  are permitted provided that the following conditions are met:
16  *
17  *  Redistributions of source code must retain the above copyright notice, this list
18  *  of conditions and the following disclaimer.
19  *
20  *  Redistributions in binary form must reproduce the above copyright notice, this
21  *  list of conditions and the following disclaimer in the documentation and/or
22  *  other materials provided with the distribution.
23  *
24  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ""AS IS""
25  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27  *  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
28  *  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29  *  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
31  *  ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32  *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33  *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34  */
35 //** Introduction
36 
37 // The NV memory is divided into two areas: dynamic space for user defined NV
38 // indexes and evict objects, and reserved space for TPM persistent and state save
39 // data.
40 //
41 // The entries in dynamic space are a linked list of entries. Each entry has, as its
42 // first field, a size. If the size field is zero, it marks the end of the
43 // list.
44 //
45 // An Index allocation will contain an NV_INDEX structure. If the Index does not
46 // have the orderly attribute, the NV_INDEX is followed immediately by the NV data.
47 //
48 // An evict object entry contains a handle followed by an OBJECT structure. This
49 // results in both the Index and Evict Object having an identifying handle as the
50 // first field following the size field.
51 //
52 // When an Index has the orderly attribute, the data is kept in RAM. This RAM is
53 // saved to backing store in NV memory on any orderly shutdown. The entries in
54 // orderly memory are also a linked list using a size field as the first entry.
55 //
56 // The attributes of an orderly index are maintained in RAM memory in order to
57 // reduce the number of NV writes needed for orderly data. When an orderly index
58 // is created, an entry is made in the dynamic NV memory space that holds the Index
59 // authorizations (authPolicy and authValue) and the size of the data. This entry is
60 // only modified if the authValue  of the index is changed. The more volatile data
61 // of the index is kept in RAM. When an orderly Index is created or deleted, the
62 // RAM data is copied to NV backing store so that the image in the backing store
63 // matches the layout of RAM. In normal operation. The RAM data is also copied on
64 // any orderly shutdown. In normal operation, the only other reason for writing
65 // to the backing store for RAM is when a counter is first written (TPMA_NV_WRITTEN
66 // changes from CLEAR to SET) or when a counter ""rolls over"".
67 //
68 // Static space contains items that are individually modifiable. The values are in
69 // the 'gp' PERSISTENT_DATA structure in RAM and mapped to locations in NV.
70 //
71 
72 //** Includes, Defines and Data Definitions
73 #define NV_C
74 #include "Tpm.h"
75 
76 //** Local Functions
77 
78 
79 //*** NvNext()
80 //  This function provides a method to traverse every data entry in NV dynamic
81 //  area.
82 //
83 //  To begin with, parameter 'iter' should be initialized to NV_REF_INIT
84 //  indicating the first element.  Every time this function is called, the
85 //  value in 'iter' would be adjusted pointing to the next element in
86 //  traversal.  If there is no next element, 'iter' value would be 0.
87 //  This function returns the address of the 'data entry' pointed by the
88 //  'iter'.  If there are no more elements in the set, a 0 value is returned
89 //  indicating the end of traversal.
90 //
91 static NV_REF
NvNext(NV_REF * iter,TPM_HANDLE * handle)92 NvNext(
93     NV_REF          *iter,          // IN/OUT: the list iterator
94     TPM_HANDLE      *handle         // OUT: the handle of the next item.
95     )
96 {
97     NV_REF               currentAddr;
98     NV_ENTRY_HEADER      header;
99 //
100     // If iterator is at the beginning of list
101     if(*iter == NV_REF_INIT)
102     {
103         // Initialize iterator
104         *iter = NV_USER_DYNAMIC;
105     }
106     // Step over the size field and point to the handle
107     currentAddr = *iter + sizeof(UINT32);
108 
109     // read the header of the next entry
110     NvRead(&header, *iter, sizeof(NV_ENTRY_HEADER));
111 
112     // if the size field is zero, then we have hit the end of the list
113     if(header.size == 0)
114         // leave the *iter pointing at the end of the list
115         return 0;
116     // advance the header by the size of the entry
117     *iter += header.size;
118 
119     if(handle != NULL)
120         *handle = header.handle;
121     return currentAddr;
122 }
123 
124 
125 //*** NvNextByType()
126 // This function returns a reference to the next NV entry of the desired type
127 //  Return Type: NV_REF
128 //      0               end of list
129 //      != 0            the next entry of the indicated type
130 static NV_REF
NvNextByType(TPM_HANDLE * handle,NV_REF * iter,TPM_HT type)131 NvNextByType(
132     TPM_HANDLE      *handle,        // OUT: the handle of the found type or 0
133     NV_REF          *iter,          // IN: the iterator
134     TPM_HT           type           // IN: the handle type to look for
135     )
136 {
137     NV_REF           addr;
138     TPM_HANDLE       nvHandle = 0;
139 //
140     while((addr = NvNext(iter, &nvHandle)) != 0)
141     {
142         // addr: the address of the location containing the handle of the value
143         // iter: the next location.
144         if(HandleGetType(nvHandle) == type)
145             break;
146     }
147     if(handle != NULL)
148         *handle = nvHandle;
149     return addr;
150 }
151 
152 //*** NvNextIndex()
153 // This function returns the reference to the next NV Index entry.  A value
154 // of 0 indicates the end of the list.
155 //  Return Type: NV_REF
156 //      0               end of list
157 //      != 0            the next reference
158 #define NvNextIndex(handle, iter)                   \
159     NvNextByType(handle, iter, TPM_HT_NV_INDEX)
160 
161 //*** NvNextEvict()
162 // This function returns the offset in NV of the next evict object entry.  A value
163 // of 0 indicates the end of the list.
164 #define NvNextEvict(handle, iter)                   \
165     NvNextByType(handle, iter, TPM_HT_PERSISTENT)
166 
167 //*** NvGetEnd()
168 // Function to find the end of the NV dynamic data list
169 static NV_REF
NvGetEnd(void)170 NvGetEnd(
171     void
172     )
173 {
174     NV_REF          iter = NV_REF_INIT;
175     NV_REF          currentAddr;
176 //
177     // Scan until the next address is 0
178     while((currentAddr = NvNext(&iter, NULL)) != 0);
179     return iter;
180 }
181 
182 //*** NvGetFreeBytes
183 // This function returns the number of free octets in NV space.
184 static UINT32
NvGetFreeBytes(void)185 NvGetFreeBytes(
186     void
187     )
188 {
189     // This does not have an overflow issue because NvGetEnd() cannot return a value
190     // that is larger than s_evictNvEnd. This is because there is always a 'stop'
191     // word in the NV memory that terminates the search for the end before the
192     // value can go past s_evictNvEnd.
193     return s_evictNvEnd - NvGetEnd();
194 }
195 
196 //*** NvTestSpace()
197 // This function will test if there is enough space to add a new entity.
198 //  Return Type: BOOL
199 //      TRUE(1)         space available
200 //      FALSE(0)        no enough space
201 static BOOL
NvTestSpace(UINT32 size,BOOL isIndex,BOOL isCounter)202 NvTestSpace(
203     UINT32           size,          // IN: size of the entity to be added
204     BOOL             isIndex,       // IN: TRUE if the entity is an index
205     BOOL             isCounter      // IN: TRUE if the index is a counter
206     )
207 {
208     UINT32      remainBytes = NvGetFreeBytes();
209     UINT32      reserved = sizeof(UINT32)       // size of the forward pointer
210         + sizeof(NV_LIST_TERMINATOR);
211 //
212     // Do a compile time sanity check on the setting for NV_MEMORY_SIZE
213 #if NV_MEMORY_SIZE < 1024
214 #error "NV_MEMORY_SIZE probably isn't large enough"
215 #endif
216 
217     // For NV Index, need to make sure that we do not allocate an Index if this
218     // would mean that the TPM cannot allocate the minimum number of evict
219     // objects.
220     if(isIndex)
221     {
222         // Get the number of persistent objects allocated
223         UINT32      persistentNum = NvCapGetPersistentNumber();
224 
225         // If we have not allocated the requisite number of evict objects, then we
226         // need to reserve space for them.
227         // NOTE: some of this is not written as simply as it might seem because
228         // the values are all unsigned and subtracting needs to be done carefully
229         // so that an underflow doesn't cause problems.
230         if(persistentNum < MIN_EVICT_OBJECTS)
231             reserved += (MIN_EVICT_OBJECTS - persistentNum) * NV_EVICT_OBJECT_SIZE;
232     }
233     // If this is not an index or is not a counter, reserve space for the
234     // required number of counter indexes
235     if(!isIndex || !isCounter)
236     {
237         // Get the number of counters
238         UINT32      counterNum = NvCapGetCounterNumber();
239 
240         // If the required number of counters have not been allocated, reserved
241         // space for the extra needed counters
242         if(counterNum < MIN_COUNTER_INDICES)
243             reserved += (MIN_COUNTER_INDICES - counterNum) * NV_INDEX_COUNTER_SIZE;
244     }
245     // Check that the requested allocation will fit after making sure that there
246     // will be no chance of overflow
247     return ((reserved < remainBytes)
248             && (size <= remainBytes)
249             && (size + reserved <= remainBytes));
250 }
251 
252 //*** NvWriteNvListEnd()
253 // Function to write the list terminator.
254 NV_REF
NvWriteNvListEnd(NV_REF end)255 NvWriteNvListEnd(
256     NV_REF           end
257     )
258 {
259     // Marker is initialized with zeros
260     BYTE        listEndMarker[sizeof(NV_LIST_TERMINATOR)] = {0};
261     UINT64      maxCount = NvReadMaxCount();
262 //
263     // This is a constant check that can be resolved at compile time.
264     cAssert(sizeof(UINT64) <= sizeof(NV_LIST_TERMINATOR) - sizeof(UINT32));
265 
266     // Copy the maxCount value to the marker buffer
267     MemoryCopy(&listEndMarker[sizeof(UINT32)], &maxCount, sizeof(UINT64));
268     pAssert(end + sizeof(NV_LIST_TERMINATOR) <= s_evictNvEnd);
269 
270     // Write it to memory
271     NvWrite(end, sizeof(NV_LIST_TERMINATOR), &listEndMarker);
272     return end + sizeof(NV_LIST_TERMINATOR);
273 }
274 
275 
276 //*** NvAdd()
277 // This function adds a new entity to NV.
278 //
279 // This function requires that there is enough space to add a new entity (i.e.,
280 // that NvTestSpace() has been called and the available space is at least as
281 // large as the required space).
282 //
283 // The 'totalSize' will be the size of 'entity'. If a handle is added, this
284 // function will increase the size accordingly.
285 static TPM_RC
NvAdd(UINT32 totalSize,UINT32 bufferSize,TPM_HANDLE handle,BYTE * entity)286 NvAdd(
287     UINT32           totalSize,     // IN: total size needed for this entity For
288                                     //     evict object, totalSize is the same as
289                                     //     bufferSize.  For NV Index, totalSize is
290                                     //     bufferSize plus index data size
291     UINT32           bufferSize,    // IN: size of initial buffer
292     TPM_HANDLE       handle,        // IN: optional handle
293     BYTE            *entity         // IN: initial buffer
294     )
295 {
296     NV_REF          newAddr;        // IN: where the new entity will start
297     NV_REF          nextAddr;
298 //
299     RETURN_IF_NV_IS_NOT_AVAILABLE;
300 
301     // Get the end of data list
302     newAddr = NvGetEnd();
303 
304     // Step over the forward pointer
305     nextAddr = newAddr + sizeof(UINT32);
306 
307     // Optionally write the handle. For indexes, the handle is TPM_RH_UNASSIGNED
308     // so that the handle in the nvIndex is used instead of writing this value
309     if(handle != TPM_RH_UNASSIGNED)
310     {
311         NvWrite((UINT32)nextAddr, sizeof(TPM_HANDLE), &handle);
312         nextAddr += sizeof(TPM_HANDLE);
313     }
314     // Write entity data
315     NvWrite((UINT32)nextAddr, bufferSize, entity);
316 
317     // Advance the pointer by the amount of the total
318     nextAddr += totalSize;
319 
320     // Finish by writing the link value
321 
322     // Write the next offset (relative addressing)
323     totalSize = nextAddr - newAddr;
324 
325     // Write link value
326     NvWrite((UINT32)newAddr, sizeof(UINT32), &totalSize);
327 
328     // Write the list terminator
329     NvWriteNvListEnd(nextAddr);
330 
331     return TPM_RC_SUCCESS;
332 }
333 
334 //*** NvDelete()
335 // This function is used to delete an NV Index or persistent object from NV memory.
336 static TPM_RC
NvDelete(NV_REF entityRef)337 NvDelete(
338     NV_REF           entityRef      // IN: reference to entity to be deleted
339     )
340 {
341     UINT32          entrySize;
342     // adjust entityAddr to back up and point to the forward pointer
343     NV_REF          entryRef = entityRef - sizeof(UINT32);
344     NV_REF          endRef = NvGetEnd();
345     NV_REF          nextAddr; // address of the next entry
346 //
347     RETURN_IF_NV_IS_NOT_AVAILABLE;
348 
349     // Get the offset of the next entry. That is, back up and point to the size
350     // field of the entry
351     NvRead(&entrySize, entryRef, sizeof(UINT32));
352 
353     // The next entry after the one being deleted is at a relative offset
354     // from the current entry
355     nextAddr = entryRef + entrySize;
356 
357     // If this is not the last entry, move everything up
358     if(nextAddr < endRef)
359     {
360         pAssert(nextAddr > entryRef);
361         _plat__NvMemoryMove(nextAddr,
362                             entryRef,
363                             (endRef - nextAddr));
364     }
365     // The end of the used space is now moved up by the amount of space we just
366     // reclaimed
367     endRef -= entrySize;
368 
369     // Write the end marker, and make the new end equal to the first byte after
370     // the just added end value. This will automatically update the NV value for
371     // maxCounter.
372     // NOTE: This is the call that sets flag to cause NV to be updated
373     endRef = NvWriteNvListEnd(endRef);
374 
375     // Clear the reclaimed memory
376     _plat__NvMemoryClear(endRef, entrySize);
377 
378     return TPM_RC_SUCCESS;
379 }
380 
381 //************************************************
382 //** RAM-based NV Index Data Access Functions
383 //************************************************
384 //*** Introduction
385 // The data layout in ram buffer is {size of(NV_handle + attributes + data
386 // NV_handle, attributes, data}
387 // for each NV Index data stored in RAM.
388 //
389 // NV storage associated with orderly data is updated when a NV Index is added
390 // but NOT when the data or attributes are changed. Orderly data is only updated
391 // to NV on an orderly shutdown (TPM2_Shutdown())
392 
393 //*** NvRamNext()
394 // This function is used to iterate trough the list of Ram Index values. *iter needs
395 // to be initialized by calling
396 static NV_RAM_REF
NvRamNext(NV_RAM_REF * iter,TPM_HANDLE * handle)397 NvRamNext(
398     NV_RAM_REF      *iter,          // IN/OUT: the list iterator
399     TPM_HANDLE      *handle         // OUT: the handle of the next item.
400     )
401 {
402     NV_RAM_REF           currentAddr;
403     NV_RAM_HEADER        header;
404 //
405     // If iterator is at the beginning of list
406     if(*iter == NV_RAM_REF_INIT)
407     {
408         // Initialize iterator
409         *iter = &s_indexOrderlyRam[0];
410     }
411     // if we are going to return what the iter is currently pointing to...
412     currentAddr = *iter;
413 
414     // If iterator reaches the end of NV space, then don't advance and return
415     // that we are at the end of the list. The end of the list occurs when
416     // we don't have space for a size and a handle
417     if(currentAddr + sizeof(NV_RAM_HEADER) > RAM_ORDERLY_END)
418         return NULL;
419     // read the header of the next entry
420     MemoryCopy(&header, currentAddr, sizeof(NV_RAM_HEADER));
421 
422     // if the size field is zero, then we have hit the end of the list
423     if(header.size == 0)
424         // leave the *iter pointing at the end of the list
425         return NULL;
426     // advance the header by the size of the entry
427     *iter = currentAddr + header.size;
428 
429 //    pAssert(*iter <= RAM_ORDERLY_END);
430     if(handle != NULL)
431         *handle = header.handle;
432     return currentAddr;
433 }
434 
435 //*** NvRamGetEnd()
436 // This routine performs the same function as NvGetEnd() but for the RAM data.
437 static NV_RAM_REF
NvRamGetEnd(void)438 NvRamGetEnd(
439     void
440     )
441 {
442     NV_RAM_REF           iter = NV_RAM_REF_INIT;
443     NV_RAM_REF           currentAddr;
444 //
445     // Scan until the next address is 0
446     while((currentAddr = NvRamNext(&iter, NULL)) != 0);
447     return iter;
448 }
449 
450 //*** NvRamTestSpaceIndex()
451 // This function indicates if there is enough RAM space to add a data for a
452 // new NV Index.
453 //  Return Type: BOOL
454 //      TRUE(1)         space available
455 //      FALSE(0)        no enough space
456 static BOOL
NvRamTestSpaceIndex(UINT32 size)457 NvRamTestSpaceIndex(
458     UINT32           size           // IN: size of the data to be added to RAM
459     )
460 {
461     UINT32          remaining = (UINT32)(RAM_ORDERLY_END - NvRamGetEnd());
462     UINT32          needed = sizeof(NV_RAM_HEADER) + size;
463 //
464     // NvRamGetEnd points to the next available byte.
465     return remaining >= needed;
466 }
467 
468 //*** NvRamGetIndex()
469 // This function returns the offset of NV data in the RAM buffer
470 //
471 // This function requires that NV Index is in RAM. That is, the
472 // index must be known to exist.
473 static NV_RAM_REF
NvRamGetIndex(TPMI_RH_NV_INDEX handle)474 NvRamGetIndex(
475     TPMI_RH_NV_INDEX     handle         // IN: NV handle
476     )
477 {
478     NV_RAM_REF          iter = NV_RAM_REF_INIT;
479     NV_RAM_REF          currentAddr;
480     TPM_HANDLE          foundHandle;
481 //
482     while((currentAddr = NvRamNext(&iter, &foundHandle)) != 0)
483     {
484         if(handle == foundHandle)
485             break;
486     }
487     return currentAddr;
488 }
489 
490 //*** NvUpdateIndexOrderlyData()
491 // This function is used to cause an update of the orderly data to the NV backing
492 // store.
493 void
NvUpdateIndexOrderlyData(void)494 NvUpdateIndexOrderlyData(
495     void
496     )
497 {
498     // Write reserved RAM space to NV
499     NvWrite(NV_INDEX_RAM_DATA, sizeof(s_indexOrderlyRam), s_indexOrderlyRam);
500 }
501 
502 //*** NvAddRAM()
503 // This function adds a new data area to RAM.
504 //
505 // This function requires that enough free RAM space is available to add
506 // the new data.
507 //
508 // This function should be called after the NV Index space has been updated
509 // and the index removed. This insures that NV is available so that checking
510 // for NV availability is not required during this function.
511 static void
NvAddRAM(TPMS_NV_PUBLIC * index)512 NvAddRAM(
513     TPMS_NV_PUBLIC  *index          // IN: the index descriptor
514     )
515 {
516     NV_RAM_HEADER       header;
517     NV_RAM_REF          end = NvRamGetEnd();
518 //
519     header.size = sizeof(NV_RAM_HEADER) + index->dataSize;
520     header.handle = index->nvIndex;
521     MemoryCopy(&header.attributes, &index->attributes, sizeof(TPMA_NV));
522 
523     pAssert(ORDERLY_RAM_ADDRESS_OK(end, header.size));
524 
525     // Copy the header to the memory
526     MemoryCopy(end, &header, sizeof(NV_RAM_HEADER));
527 
528     // Clear the data area (just in case)
529     MemorySet(end + sizeof(NV_RAM_HEADER), 0, index->dataSize);
530 
531     // Step over this new entry
532     end += header.size;
533 
534     // If the end marker will fit, add it
535     if(end + sizeof(UINT32) < RAM_ORDERLY_END)
536         MemorySet(end, 0, sizeof(UINT32));
537     // Write reserved RAM space to NV to reflect the newly added NV Index
538     SET_NV_UPDATE(UT_ORDERLY);
539 
540     return;
541 }
542 
543 //*** NvDeleteRAM()
544 // This function is used to delete a RAM-backed NV Index data area.
545 // The space used by the entry are overwritten by the contents of the
546 // Index data that comes after (the data is moved up to fill the hole left
547 // by removing this index. The reclaimed space is cleared to zeros.
548 // This function assumes the data of NV Index exists in RAM.
549 //
550 // This function should be called after the NV Index space has been updated
551 // and the index removed. This insures that NV is available so that checking
552 // for NV availability is not required during this function.
553 static void
NvDeleteRAM(TPMI_RH_NV_INDEX handle)554 NvDeleteRAM(
555     TPMI_RH_NV_INDEX     handle         // IN: NV handle
556     )
557 {
558     NV_RAM_REF           nodeAddress;
559     NV_RAM_REF           nextNode;
560     UINT32               size;
561     NV_RAM_REF           lastUsed = NvRamGetEnd();
562 //
563     nodeAddress = NvRamGetIndex(handle);
564 
565     pAssert(nodeAddress != 0);
566 
567     // Get node size
568     MemoryCopy(&size, nodeAddress, sizeof(size));
569 
570     // Get the offset of next node
571     nextNode = nodeAddress + size;
572 
573     // Copy the data
574     MemoryCopy(nodeAddress, nextNode, (int)(lastUsed - nextNode));
575 
576     // Clear out the reclaimed space
577     MemorySet(lastUsed - size, 0, size);
578 
579     // Write reserved RAM space to NV to reflect the newly delete NV Index
580     SET_NV_UPDATE(UT_ORDERLY);
581 
582     return;
583 }
584 
585 //*** NvReadIndex()
586 // This function is used to read the NV Index NV_INDEX. This is used so that the
587 // index information can be compressed and only this function would be needed
588 // to decompress it. Mostly, compression would only be able to save the space
589 // needed by the policy.
590 void
NvReadNvIndexInfo(NV_REF ref,NV_INDEX * nvIndex)591 NvReadNvIndexInfo(
592     NV_REF           ref,           // IN: points to NV where index is located
593     NV_INDEX        *nvIndex        // OUT: place to receive index data
594     )
595 {
596     pAssert(nvIndex != NULL);
597     NvRead(nvIndex, ref, sizeof(NV_INDEX));
598     return;
599 }
600 
601 //*** NvReadObject()
602 // This function is used to read a persistent object. This is used so that the
603 // object information can be compressed and only this function would be needed
604 // to uncompress it.
605 void
NvReadObject(NV_REF ref,OBJECT * object)606 NvReadObject(
607     NV_REF           ref,           // IN: points to NV where index is located
608     OBJECT          *object         // OUT: place to receive the object data
609     )
610 {
611     NvRead(object, (ref + sizeof(TPM_HANDLE)), sizeof(OBJECT));
612     return;
613 }
614 
615 //*** NvFindEvict()
616 // This function will return the NV offset of an evict object
617 //  Return Type: UINT32
618 //      0               evict object not found
619 //      != 0            offset of evict object
620 static NV_REF
NvFindEvict(TPM_HANDLE nvHandle,OBJECT * object)621 NvFindEvict(
622     TPM_HANDLE       nvHandle,
623     OBJECT          *object
624     )
625 {
626     NV_REF          found = NvFindHandle(nvHandle);
627 //
628     // If we found the handle and the request included an object pointer, fill it in
629     if(found != 0 && object != NULL)
630         NvReadObject(found, object);
631     return found;
632 }
633 
634 //*** NvIndexIsDefined()
635 // See if an index is already defined
636 BOOL
NvIndexIsDefined(TPM_HANDLE nvHandle)637 NvIndexIsDefined(
638     TPM_HANDLE       nvHandle       // IN: Index to look for
639     )
640 {
641     return (NvFindHandle(nvHandle) != 0);
642 }
643 
644 //*** NvConditionallyWrite()
645 // Function to check if the data to be written has changed
646 // and write it if it has
647 //  Return Type: TPM_RC
648 //      TPM_RC_NV_RATE           NV is unavailable because of rate limit
649 //      TPM_RC_NV_UNAVAILABLE    NV is inaccessible
650 static TPM_RC
NvConditionallyWrite(NV_REF entryAddr,UINT32 size,void * data)651 NvConditionallyWrite(
652     NV_REF           entryAddr,     // IN: stating address
653     UINT32           size,          // IN: size of the data to write
654     void            *data           // IN: the data to write
655     )
656 {
657     // If the index data is actually changed, then a write to NV is required
658     if(_plat__NvIsDifferent(entryAddr, size, data))
659     {
660         // Write the data if NV is available
661         if(g_NvStatus == TPM_RC_SUCCESS)
662         {
663             NvWrite(entryAddr, size, data);
664         }
665         return g_NvStatus;
666     }
667     return TPM_RC_SUCCESS;
668 }
669 
670 //*** NvReadNvIndexAttributes()
671 // This function returns the attributes of an NV Index.
672 static TPMA_NV
NvReadNvIndexAttributes(NV_REF locator)673 NvReadNvIndexAttributes(
674     NV_REF           locator        // IN: reference to an NV index
675     )
676 {
677     TPMA_NV                 attributes;
678 //
679     NvRead(&attributes,
680            locator + offsetof(NV_INDEX, publicArea.attributes),
681            sizeof(TPMA_NV));
682     return attributes;
683 }
684 
685 //*** NvReadRamIndexAttributes()
686 // This function returns the attributes from the RAM header structure. This function
687 // is used to deal with the fact that the header structure is only byte aligned.
688 static TPMA_NV
NvReadRamIndexAttributes(NV_RAM_REF ref)689 NvReadRamIndexAttributes(
690     NV_RAM_REF       ref            // IN: pointer to a NV_RAM_HEADER
691     )
692 {
693     TPMA_NV         attributes;
694 //
695     MemoryCopy(&attributes, ref + offsetof(NV_RAM_HEADER, attributes),
696                sizeof(TPMA_NV));
697     return attributes;
698 }
699 
700 //*** NvWriteNvIndexAttributes()
701 // This function is used to write just the attributes of an index to NV.
702 //  Return type: TPM_RC
703 //      TPM_RC_NV_RATE          NV is rate limiting so retry
704 //      TPM_RC_NV_UNAVAILABLE   NV is not available
705 static TPM_RC
NvWriteNvIndexAttributes(NV_REF locator,TPMA_NV attributes)706 NvWriteNvIndexAttributes(
707     NV_REF           locator,       // IN: location of the index
708     TPMA_NV          attributes     // IN: attributes to write
709     )
710 {
711     return NvConditionallyWrite(
712         locator + offsetof(NV_INDEX, publicArea.attributes),
713         sizeof(TPMA_NV),
714         &attributes);
715 }
716 
717 //*** NvWriteRamIndexAttributes()
718 // This function is used to write the index attributes into an unaligned structure
719 static void
NvWriteRamIndexAttributes(NV_RAM_REF ref,TPMA_NV attributes)720 NvWriteRamIndexAttributes(
721     NV_RAM_REF       ref,           // IN: address of the header
722     TPMA_NV          attributes     // IN: the attributes to write
723     )
724 {
725     MemoryCopy(ref + offsetof(NV_RAM_HEADER, attributes), &attributes,
726                sizeof(TPMA_NV));
727     return;
728 }
729 
730 //************************************************
731 //** Externally Accessible Functions
732 //************************************************
733 
734 //*** NvIsPlatformPersistentHandle()
735 // This function indicates if a handle references a persistent object in the
736 // range belonging to the platform.
737 //  Return Type: BOOL
738 //      TRUE(1)         handle references a platform persistent object
739 //      FALSE(0)        handle does not reference platform persistent object
740 BOOL
NvIsPlatformPersistentHandle(TPM_HANDLE handle)741 NvIsPlatformPersistentHandle(
742     TPM_HANDLE       handle         // IN: handle
743     )
744 {
745     return (handle >= PLATFORM_PERSISTENT && handle <= PERSISTENT_LAST);
746 }
747 
748 //*** NvIsOwnerPersistentHandle()
749 // This function indicates if a handle references a persistent object in the
750 // range belonging to the owner.
751 //  Return Type: BOOL
752 //      TRUE(1)         handle is owner persistent handle
753 //      FALSE(0)        handle is not owner persistent handle and may not be
754 //                      a persistent handle at all
755 BOOL
NvIsOwnerPersistentHandle(TPM_HANDLE handle)756 NvIsOwnerPersistentHandle(
757     TPM_HANDLE       handle         // IN: handle
758     )
759 {
760     return (handle >= PERSISTENT_FIRST && handle < PLATFORM_PERSISTENT);
761 }
762 
763 //*** NvIndexIsAccessible()
764 //
765 // This function validates that a handle references a defined NV Index and
766 // that the Index is currently accessible.
767 //  Return Type: TPM_RC
768 //      TPM_RC_HANDLE           the handle points to an undefined NV Index
769 //                              If shEnable is CLEAR, this would include an index
770 //                              created using ownerAuth. If phEnableNV is CLEAR,
771 //                              this would include and index created using
772 //                              platformAuth
773 //      TPM_RC_NV_READLOCKED    Index is present but locked for reading and command
774 //                              does not write to the index
775 //      TPM_RC_NV_WRITELOCKED   Index is present but locked for writing and command
776 //                              writes to the index
777 TPM_RC
NvIndexIsAccessible(TPMI_RH_NV_INDEX handle)778 NvIndexIsAccessible(
779     TPMI_RH_NV_INDEX     handle        // IN: handle
780     )
781 {
782     NV_INDEX            *nvIndex = NvGetIndexInfo(handle, NULL);
783 //
784     if(nvIndex == NULL)
785     // If index is not found, return TPM_RC_HANDLE
786         return TPM_RC_HANDLE;
787     if(gc.shEnable == FALSE || gc.phEnableNV == FALSE)
788     {
789         // if shEnable is CLEAR, an ownerCreate NV Index should not be
790         // indicated as present
791         if(!IS_ATTRIBUTE(nvIndex->publicArea.attributes, TPMA_NV, PLATFORMCREATE))
792         {
793             if(gc.shEnable == FALSE)
794                 return TPM_RC_HANDLE;
795         }
796         // if phEnableNV is CLEAR, a platform created Index should not
797         // be visible
798         else if(gc.phEnableNV == FALSE)
799             return TPM_RC_HANDLE;
800     }
801 #if 0 // Writelock test for debug
802     // If the Index is write locked and this is an NV Write operation...
803     if(IS_ATTRIBUTE(nvIndex->publicArea.attributes, TPMA_NV, WRITELOCKED)
804        &&  IsWriteOperation(commandIndex))
805     {
806         // then return a locked indication unless the command is TPM2_NV_WriteLock
807         if(GetCommandCode(commandIndex) != TPM_CC_NV_WriteLock)
808             return TPM_RC_NV_LOCKED;
809         return TPM_RC_SUCCESS;
810     }
811 #endif
812 #if 0   // Readlock Test for debug
813     // If the Index is read locked and this is an NV Read operation...
814     if(IS_ATTRIBUTE(nvIndex->publicArea.attributes, TPMA_NV, READLOCKED)
815        && IsReadOperation(commandIndex))
816     {
817         // then return a locked indication unless the command is TPM2_NV_ReadLock
818         if(GetCommandCode(commandIndex) != TPM_CC_NV_ReadLock)
819             return TPM_RC_NV_LOCKED;
820     }
821 #endif
822     // NV Index is accessible
823     return TPM_RC_SUCCESS;
824 }
825 
826 //*** NvGetEvictObject()
827 // This function is used to dereference an evict object handle and get a pointer
828 // to the object.
829 //  Return Type: TPM_RC
830 //      TPM_RC_HANDLE           the handle does not point to an existing
831 //                              persistent object
832 TPM_RC
NvGetEvictObject(TPM_HANDLE handle,OBJECT * object)833 NvGetEvictObject(
834     TPM_HANDLE       handle,        // IN: handle
835     OBJECT          *object         // OUT: object data
836     )
837 {
838     NV_REF          entityAddr;         // offset points to the entity
839 //
840     // Find the address of evict object and copy to object
841     entityAddr = NvFindEvict(handle, object);
842 
843     // whether there is an error or not, make sure that the evict
844     // status of the object is set so that the slot will get freed on exit
845     // Must do this after NvFindEvict loads the object
846     object->attributes.evict = SET;
847 
848     // If handle is not found, return an error
849     if(entityAddr == 0)
850         return TPM_RC_HANDLE;
851     return TPM_RC_SUCCESS;
852 }
853 
854 //*** NvIndexCacheInit()
855 // Function to initialize the Index cache
856 void
NvIndexCacheInit(void)857 NvIndexCacheInit(
858     void
859     )
860 {
861     s_cachedNvRef = NV_REF_INIT;
862     s_cachedNvRamRef = NV_RAM_REF_INIT;
863     s_cachedNvIndex.publicArea.nvIndex = TPM_RH_UNASSIGNED;
864     return;
865 }
866 
867 
868 //*** NvGetIndexData()
869 // This function is used to access the data in an NV Index. The data is returned
870 // as a byte sequence.
871 //
872 // This function requires that the NV Index be defined, and that the
873 // required data is within the data range.  It also requires that TPMA_NV_WRITTEN
874 // of the Index is SET.
875 void
NvGetIndexData(NV_INDEX * nvIndex,NV_REF locator,UINT32 offset,UINT16 size,void * data)876 NvGetIndexData(
877     NV_INDEX            *nvIndex,       // IN: the in RAM index descriptor
878     NV_REF               locator,       // IN: where the data is located
879     UINT32               offset,        // IN: offset of NV data
880     UINT16               size,          // IN: number of octets of NV data to read
881     void                *data           // OUT: data buffer
882     )
883 {
884     TPMA_NV             nvAttributes;
885 //
886     pAssert(nvIndex != NULL);
887 
888     nvAttributes = nvIndex->publicArea.attributes;
889 
890     pAssert(IS_ATTRIBUTE(nvAttributes, TPMA_NV, WRITTEN));
891 
892     if(IS_ATTRIBUTE(nvAttributes, TPMA_NV, ORDERLY))
893     {
894         // Get data from RAM buffer
895         NV_RAM_REF           ramAddr = NvRamGetIndex(nvIndex->publicArea.nvIndex);
896         pAssert(ramAddr != 0 && (size <=
897                 ((NV_RAM_HEADER *)ramAddr)->size - sizeof(NV_RAM_HEADER) - offset));
898         MemoryCopy(data, ramAddr + sizeof(NV_RAM_HEADER) + offset, size);
899     }
900     else
901     {
902         // Validate that read falls within range of the index
903         pAssert(offset <= nvIndex->publicArea.dataSize
904                 &&  size <= (nvIndex->publicArea.dataSize - offset));
905         NvRead(data, locator + sizeof(NV_INDEX) + offset, size);
906     }
907     return;
908 }
909 
910 //*** NvHashIndexData()
911 // This function adds Index data to a hash. It does this in parts to avoid large stack
912 // buffers.
913 void
NvHashIndexData(HASH_STATE * hashState,NV_INDEX * nvIndex,NV_REF locator,UINT32 offset,UINT16 size)914 NvHashIndexData(
915     HASH_STATE          *hashState,     // IN: Initialized hash state
916     NV_INDEX            *nvIndex,       // IN: Index
917     NV_REF               locator,       // IN: where the data is located
918     UINT32               offset,        // IN: starting offset
919     UINT16               size           // IN: amount to hash
920 )
921 {
922 #define BUFFER_SIZE     64
923     BYTE                 buffer[BUFFER_SIZE];
924     if (offset > nvIndex->publicArea.dataSize)
925         return;
926     // Make sure that we don't try to read off the end.
927     if ((offset + size) > nvIndex->publicArea.dataSize)
928         size = nvIndex->publicArea.dataSize - (UINT16)offset;
929 #if BUFFER_SIZE >= MAX_NV_INDEX_SIZE
930     NvGetIndexData(nvIndex, locator, offset, size, buffer);
931     CryptDigestUpdate(hashState, size, buffer);
932 #else
933     {
934         INT16                i;
935         UINT16               readSize;
936         //
937         for (i = size; i > 0; offset += readSize, i -= readSize)
938         {
939             readSize = (i < BUFFER_SIZE) ? i : BUFFER_SIZE;
940             NvGetIndexData(nvIndex, locator, offset, readSize, buffer);
941             CryptDigestUpdate(hashState, readSize, buffer);
942         }
943     }
944 #endif // BUFFER_SIZE >= MAX_NV_INDEX_SIZE
945 #undef  BUFFER_SIZE
946 }
947 
948 
949 //*** NvGetUINT64Data()
950 // Get data in integer format of a bit or counter NV Index.
951 //
952 // This function requires that the NV Index is defined and that the NV Index
953 // previously has been written.
954 UINT64
NvGetUINT64Data(NV_INDEX * nvIndex,NV_REF locator)955 NvGetUINT64Data(
956     NV_INDEX            *nvIndex,       // IN: the in RAM index descriptor
957     NV_REF               locator        // IN: where index exists in NV
958     )
959 {
960     UINT64                intVal;
961 //
962     // Read the value and convert it to internal format
963     NvGetIndexData(nvIndex, locator, 0, 8, &intVal);
964     return BYTE_ARRAY_TO_UINT64(((BYTE *)&intVal));
965 }
966 
967 //*** NvWriteIndexAttributes()
968 // This function is used to write just the attributes of an index.
969 //  Return type: TPM_RC
970 //      TPM_RC_NV_RATE          NV is rate limiting so retry
971 //      TPM_RC_NV_UNAVAILABLE   NV is not available
972 TPM_RC
NvWriteIndexAttributes(TPM_HANDLE handle,NV_REF locator,TPMA_NV attributes)973 NvWriteIndexAttributes(
974     TPM_HANDLE       handle,
975     NV_REF           locator,       // IN: location of the index
976     TPMA_NV          attributes     // IN: attributes to write
977     )
978 {
979     TPM_RC              result;
980 //
981     if(IS_ATTRIBUTE(attributes, TPMA_NV, ORDERLY))
982     {
983         NV_RAM_REF      ram = NvRamGetIndex(handle);
984         NvWriteRamIndexAttributes(ram, attributes);
985         result = TPM_RC_SUCCESS;
986     }
987     else
988     {
989         result = NvWriteNvIndexAttributes(locator, attributes);
990     }
991     return result;
992 }
993 
994 //*** NvWriteIndexAuth()
995 // This function is used to write the authValue of an index. It is used by
996 // TPM2_NV_ChangeAuth()
997 //  Return type: TPM_RC
998 //      TPM_RC_NV_RATE          NV is rate limiting so retry
999 //      TPM_RC_NV_UNAVAILABLE   NV is not available
1000 TPM_RC
NvWriteIndexAuth(NV_REF locator,TPM2B_AUTH * authValue)1001 NvWriteIndexAuth(
1002     NV_REF           locator,       // IN: location of the index
1003     TPM2B_AUTH      *authValue      // IN: the authValue to write
1004     )
1005 {
1006     TPM_RC              result;
1007 //
1008     // If the locator is pointing to the cached index value...
1009     if(locator == s_cachedNvRef)
1010     {
1011         // copy the authValue to the cached index so it will be there if we
1012         // look for it. This is a safety thing.
1013         MemoryCopy2B(&s_cachedNvIndex.authValue.b, &authValue->b,
1014                      sizeof(s_cachedNvIndex.authValue.t.buffer));
1015     }
1016     result = NvConditionallyWrite(
1017         locator + offsetof(NV_INDEX, authValue),
1018         sizeof(UINT16) + authValue->t.size,
1019         authValue);
1020     return result;
1021 }
1022 
1023 //*** NvGetIndexInfo()
1024 // This function loads the nvIndex Info into the NV cache and returns a pointer
1025 // to the NV_INDEX. If the returned value is zero, the index was not found.
1026 // The 'locator' parameter, if not NULL, will be set to the offset in NV of the
1027 // Index (the location of the handle of the Index).
1028 //
1029 // This function will set the index cache. If the index is orderly, the attributes
1030 // from RAM are substituted for the attributes in the cached index
1031 NV_INDEX *
NvGetIndexInfo(TPM_HANDLE nvHandle,NV_REF * locator)1032 NvGetIndexInfo(
1033     TPM_HANDLE       nvHandle,      // IN: the index handle
1034     NV_REF          *locator        // OUT: location of the index
1035     )
1036 {
1037     if(s_cachedNvIndex.publicArea.nvIndex != nvHandle)
1038     {
1039         s_cachedNvIndex.publicArea.nvIndex = TPM_RH_UNASSIGNED;
1040         s_cachedNvRamRef = 0;
1041         s_cachedNvRef = NvFindHandle(nvHandle);
1042         if(s_cachedNvRef == 0)
1043             return NULL;
1044         NvReadNvIndexInfo(s_cachedNvRef, &s_cachedNvIndex);
1045         if(IS_ATTRIBUTE(s_cachedNvIndex.publicArea.attributes, TPMA_NV, ORDERLY))
1046         {
1047             s_cachedNvRamRef = NvRamGetIndex(nvHandle);
1048             s_cachedNvIndex.publicArea.attributes =
1049                 NvReadRamIndexAttributes(s_cachedNvRamRef);
1050         }
1051     }
1052     if(locator != NULL)
1053         *locator = s_cachedNvRef;
1054     return &s_cachedNvIndex;
1055 }
1056 
1057 //*** NvWriteIndexData()
1058 // This function is used to write NV index data. It is intended to be used to
1059 // update the data associated with the default index.
1060 //
1061 // This function requires that the NV Index is defined, and the data is
1062 // within the defined data range for the index.
1063 //
1064 // Index data is only written due to a command that modifies the data in a single
1065 // index. There is no case where changes are made to multiple indexes data at the
1066 // same time. Multiple attributes may be change but not multiple index data. This
1067 // is important because we will normally be handling the index for which we have
1068 // the cached pointer values.
1069 //  Return type: TPM_RC
1070 //      TPM_RC_NV_RATE          NV is rate limiting so retry
1071 //      TPM_RC_NV_UNAVAILABLE   NV is not available
1072 TPM_RC
NvWriteIndexData(NV_INDEX * nvIndex,UINT32 offset,UINT32 size,void * data)1073 NvWriteIndexData(
1074     NV_INDEX        *nvIndex,       // IN: the description of the index
1075     UINT32           offset,        // IN: offset of NV data
1076     UINT32           size,          // IN: size of NV data
1077     void            *data           // IN: data buffer
1078     )
1079 {
1080     TPM_RC               result = TPM_RC_SUCCESS;
1081 //
1082     pAssert(nvIndex != NULL);
1083     // Make sure that this is dealing with the 'default' index.
1084     // Note: it is tempting to change the calling sequence so that the 'default' is
1085     // presumed.
1086     pAssert(nvIndex->publicArea.nvIndex == s_cachedNvIndex.publicArea.nvIndex);
1087 
1088     // Validate that write falls within range of the index
1089     pAssert(offset <= nvIndex->publicArea.dataSize
1090             &&  size <= (nvIndex->publicArea.dataSize - offset));
1091 
1092     // Update TPMA_NV_WRITTEN bit if necessary
1093     if(!IS_ATTRIBUTE(nvIndex->publicArea.attributes, TPMA_NV, WRITTEN))
1094     {
1095         // Update the in memory version of the attributes
1096         SET_ATTRIBUTE(nvIndex->publicArea.attributes, TPMA_NV, WRITTEN);
1097 
1098         // If this is not orderly, then update the NV version of
1099         // the attributes
1100         if(!IS_ATTRIBUTE(nvIndex->publicArea.attributes, TPMA_NV, ORDERLY))
1101         {
1102             result = NvWriteNvIndexAttributes(s_cachedNvRef,
1103                                               nvIndex->publicArea.attributes);
1104             if(result != TPM_RC_SUCCESS)
1105                 return result;
1106             // If this is a partial write of an ordinary index, clear the whole
1107             // index.
1108             if(IsNvOrdinaryIndex(nvIndex->publicArea.attributes)
1109                && (nvIndex->publicArea.dataSize > size))
1110                 _plat__NvMemoryClear(s_cachedNvRef + sizeof(NV_INDEX),
1111                                      nvIndex->publicArea.dataSize);
1112         }
1113         else
1114         {
1115             // This is orderly so update the RAM version
1116             MemoryCopy(s_cachedNvRamRef + offsetof(NV_RAM_HEADER, attributes),
1117                        &nvIndex->publicArea.attributes, sizeof(TPMA_NV));
1118             // If setting WRITTEN for an orderly counter, make sure that the
1119             // state saved version of the counter is saved
1120             if(IsNvCounterIndex(nvIndex->publicArea.attributes))
1121                 SET_NV_UPDATE(UT_ORDERLY);
1122             // If setting the written attribute on an ordinary index, make sure that
1123             // the data is all cleared out in case there is a partial write. This
1124             // is only necessary for ordinary indexes because all of the other types
1125             // are always written in total.
1126             else if(IsNvOrdinaryIndex(nvIndex->publicArea.attributes))
1127                 MemorySet(s_cachedNvRamRef + sizeof(NV_RAM_HEADER),
1128                           0, nvIndex->publicArea.dataSize);
1129         }
1130     }
1131     // If this is orderly data, write it to RAM
1132     if(IS_ATTRIBUTE(nvIndex->publicArea.attributes, TPMA_NV, ORDERLY))
1133     {
1134         // Note: if this is the first write to a counter, the code above will queue
1135         // the write to NV of the RAM data in order to update TPMA_NV_WRITTEN. In
1136         // process of doing that write, it will also write the initial counter value
1137 
1138         // Update RAM
1139         MemoryCopy(s_cachedNvRamRef + sizeof(NV_RAM_HEADER) + offset, data, size);
1140 
1141         // And indicate that the TPM is no longer orderly
1142         g_clearOrderly = TRUE;
1143     }
1144     else
1145     {
1146         // Offset into the index to the first byte of the data to be written to NV
1147         result = NvConditionallyWrite(s_cachedNvRef + sizeof(NV_INDEX) + offset,
1148                                       size, data);
1149     }
1150     return result;
1151 }
1152 
1153 //*** NvWriteUINT64Data()
1154 // This function to write back a UINT64 value. The various UINT64 values (bits,
1155 // counters, and PINs) are kept in canonical format but manipulate in native
1156 // format. This takes a native format value converts it and saves it back as
1157 // in canonical format.
1158 //
1159 // This function will return the value from NV or RAM depending on the type of the
1160 // index (orderly or not)
1161 //
1162 TPM_RC
NvWriteUINT64Data(NV_INDEX * nvIndex,UINT64 intValue)1163 NvWriteUINT64Data(
1164     NV_INDEX        *nvIndex,       // IN: the description of the index
1165     UINT64           intValue       // IN: the value to write
1166     )
1167 {
1168     BYTE            bytes[8];
1169     UINT64_TO_BYTE_ARRAY(intValue, bytes);
1170 //
1171     return NvWriteIndexData(nvIndex, 0, 8, &bytes);
1172 }
1173 
1174 //*** NvGetIndexName()
1175 // This function computes the Name of an index
1176 // The 'name' buffer receives the bytes of the Name and the return value
1177 // is the number of octets in the Name.
1178 //
1179 // This function requires that the NV Index is defined.
1180 TPM2B_NAME *
NvGetIndexName(NV_INDEX * nvIndex,TPM2B_NAME * name)1181 NvGetIndexName(
1182     NV_INDEX        *nvIndex,       // IN: the index over which the name is to be
1183                                     //     computed
1184     TPM2B_NAME      *name           // OUT: name of the index
1185     )
1186 {
1187     UINT16               dataSize, digestSize;
1188     BYTE                 marshalBuffer[sizeof(TPMS_NV_PUBLIC)];
1189     BYTE                *buffer;
1190     HASH_STATE           hashState;
1191 //
1192     // Marshal public area
1193     buffer = marshalBuffer;
1194     dataSize = TPMS_NV_PUBLIC_Marshal(&nvIndex->publicArea, &buffer, NULL);
1195 
1196     // hash public area
1197     digestSize = CryptHashStart(&hashState, nvIndex->publicArea.nameAlg);
1198     CryptDigestUpdate(&hashState, dataSize, marshalBuffer);
1199 
1200     // Complete digest leaving room for the nameAlg
1201     CryptHashEnd(&hashState, digestSize, &name->b.buffer[2]);
1202 
1203     // Include the nameAlg
1204     UINT16_TO_BYTE_ARRAY(nvIndex->publicArea.nameAlg, name->b.buffer);
1205     name->t.size = digestSize + 2;
1206     return name;
1207 }
1208 
1209 //*** NvGetNameByIndexHandle()
1210 // This function is used to compute the Name of an NV Index referenced by handle.
1211 //
1212 // The 'name' buffer receives the bytes of the Name and the return value
1213 // is the number of octets in the Name.
1214 //
1215 // This function requires that the NV Index is defined.
1216 TPM2B_NAME *
NvGetNameByIndexHandle(TPMI_RH_NV_INDEX handle,TPM2B_NAME * name)1217 NvGetNameByIndexHandle(
1218     TPMI_RH_NV_INDEX     handle,        // IN: handle of the index
1219     TPM2B_NAME          *name           // OUT: name of the index
1220     )
1221 {
1222     NV_INDEX             *nvIndex = NvGetIndexInfo(handle, NULL);
1223 //
1224     return NvGetIndexName(nvIndex, name);
1225 }
1226 
1227 //*** NvDefineIndex()
1228 // This function is used to assign NV memory to an NV Index.
1229 //
1230 //  Return Type: TPM_RC
1231 //      TPM_RC_NV_SPACE         insufficient NV space
1232 TPM_RC
NvDefineIndex(TPMS_NV_PUBLIC * publicArea,TPM2B_AUTH * authValue)1233 NvDefineIndex(
1234     TPMS_NV_PUBLIC  *publicArea,    // IN: A template for an area to create.
1235     TPM2B_AUTH      *authValue      // IN: The initial authorization value
1236     )
1237 {
1238     // The buffer to be written to NV memory
1239     NV_INDEX        nvIndex;            // the index data
1240     UINT16          entrySize;          // size of entry
1241     TPM_RC          result;
1242 //
1243     entrySize = sizeof(NV_INDEX);
1244 
1245     // only allocate data space for indexes that are going to be written to NV.
1246     // Orderly indexes don't need space.
1247     if(!IS_ATTRIBUTE(publicArea->attributes, TPMA_NV, ORDERLY))
1248         entrySize += publicArea->dataSize;
1249     // Check if we have enough space to create the NV Index
1250     // In this implementation, the only resource limitation is the available NV
1251     // space (and possibly RAM space.)  Other implementation may have other
1252     // limitation on counter or on NV slots
1253     if(!NvTestSpace(entrySize, TRUE, IsNvCounterIndex(publicArea->attributes)))
1254         return TPM_RC_NV_SPACE;
1255 
1256     // if the index to be defined is RAM backed, check RAM space availability
1257     // as well
1258     if(IS_ATTRIBUTE(publicArea->attributes, TPMA_NV, ORDERLY)
1259        &&  !NvRamTestSpaceIndex(publicArea->dataSize))
1260         return TPM_RC_NV_SPACE;
1261     // Copy input value to nvBuffer
1262     nvIndex.publicArea = *publicArea;
1263 
1264     // Copy the authValue
1265     nvIndex.authValue = *authValue;
1266 
1267     // Add index to NV memory
1268     result = NvAdd(entrySize, sizeof(NV_INDEX), TPM_RH_UNASSIGNED,
1269                    (BYTE *)&nvIndex);
1270     if(result == TPM_RC_SUCCESS)
1271     {
1272     // If the data of NV Index is RAM backed, add the data area in RAM as well
1273         if(IS_ATTRIBUTE(publicArea->attributes, TPMA_NV, ORDERLY))
1274             NvAddRAM(publicArea);
1275     }
1276     return result;
1277 }
1278 
1279 //*** NvAddEvictObject()
1280 // This function is used to assign NV memory to a persistent object.
1281 //  Return Type: TPM_RC
1282 //      TPM_RC_NV_HANDLE        the requested handle is already in use
1283 //      TPM_RC_NV_SPACE         insufficient NV space
1284 TPM_RC
NvAddEvictObject(TPMI_DH_OBJECT evictHandle,OBJECT * object)1285 NvAddEvictObject(
1286     TPMI_DH_OBJECT   evictHandle,   // IN: new evict handle
1287     OBJECT          *object         // IN: object to be added
1288     )
1289 {
1290     TPM_HANDLE       temp = object->evictHandle;
1291     TPM_RC           result;
1292 //
1293     // Check if we have enough space to add the evict object
1294     // An evict object needs 8 bytes in index table + sizeof OBJECT
1295     // In this implementation, the only resource limitation is the available NV
1296     // space.  Other implementation may have other limitation on evict object
1297     // handle space
1298     if(!NvTestSpace(sizeof(OBJECT) + sizeof(TPM_HANDLE), FALSE, FALSE))
1299         return TPM_RC_NV_SPACE;
1300 
1301     // Set evict attribute and handle
1302     object->attributes.evict = SET;
1303     object->evictHandle = evictHandle;
1304 
1305     // Now put this in NV
1306     result = NvAdd(sizeof(OBJECT), sizeof(OBJECT), evictHandle, (BYTE *)object);
1307 
1308     // Put things back the way they were
1309     object->attributes.evict = CLEAR;
1310     object->evictHandle = temp;
1311 
1312     return result;
1313 }
1314 
1315 //*** NvDeleteIndex()
1316 // This function is used to delete an NV Index.
1317 //  Return Type: TPM_RC
1318 //      TPM_RC_NV_UNAVAILABLE   NV is not accessible
1319 //      TPM_RC_NV_RATE          NV is rate limiting
1320 TPM_RC
NvDeleteIndex(NV_INDEX * nvIndex,NV_REF entityAddr)1321 NvDeleteIndex(
1322     NV_INDEX        *nvIndex,       // IN: an in RAM index descriptor
1323     NV_REF           entityAddr     // IN: location in NV
1324     )
1325 {
1326     TPM_RC           result;
1327 //
1328     if(nvIndex != NULL)
1329     {
1330         // Whenever a counter is deleted, make sure that the MaxCounter value is
1331         // updated to reflect the value
1332         if(IsNvCounterIndex(nvIndex->publicArea.attributes)
1333            && IS_ATTRIBUTE(nvIndex->publicArea.attributes, TPMA_NV, WRITTEN))
1334             NvUpdateMaxCount(NvGetUINT64Data(nvIndex, entityAddr));
1335         result = NvDelete(entityAddr);
1336         if(result != TPM_RC_SUCCESS)
1337             return result;
1338         // If the NV Index is RAM backed, delete the RAM data as well
1339         if(IS_ATTRIBUTE(nvIndex->publicArea.attributes, TPMA_NV, ORDERLY))
1340             NvDeleteRAM(nvIndex->publicArea.nvIndex);
1341         NvIndexCacheInit();
1342     }
1343     return TPM_RC_SUCCESS;
1344 }
1345 
1346 //*** NvDeleteEvict()
1347 // This function will delete a NV evict object.
1348 // Will return success if object deleted or if it does not exist
1349 
1350 TPM_RC
NvDeleteEvict(TPM_HANDLE handle)1351 NvDeleteEvict(
1352     TPM_HANDLE       handle         // IN: handle of entity to be deleted
1353     )
1354 {
1355     NV_REF      entityAddr = NvFindEvict(handle, NULL);     // pointer to entity
1356     TPM_RC      result = TPM_RC_SUCCESS;
1357 //
1358     if(entityAddr != 0)
1359         result = NvDelete(entityAddr);
1360     return result;
1361 }
1362 
1363 //*** NvFlushHierarchy()
1364 // This function will delete persistent objects belonging to the indicated hierarchy.
1365 // If the storage hierarchy is selected, the function will also delete any
1366 // NV Index defined using ownerAuth.
1367 //  Return Type: TPM_RC
1368 //      TPM_RC_NV_RATE           NV is unavailable because of rate limit
1369 //      TPM_RC_NV_UNAVAILABLE    NV is inaccessible
1370 TPM_RC
NvFlushHierarchy(TPMI_RH_HIERARCHY hierarchy)1371 NvFlushHierarchy(
1372     TPMI_RH_HIERARCHY    hierarchy      // IN: hierarchy to be flushed.
1373     )
1374 {
1375     NV_REF           iter = NV_REF_INIT;
1376     NV_REF           currentAddr;
1377     TPM_HANDLE       entityHandle;
1378     TPM_RC           result = TPM_RC_SUCCESS;
1379 //
1380     while((currentAddr = NvNext(&iter, &entityHandle)) != 0)
1381     {
1382         if(HandleGetType(entityHandle) == TPM_HT_NV_INDEX)
1383         {
1384             NV_INDEX        nvIndex;
1385 //
1386             // If flush endorsement or platform hierarchy, no NV Index would be
1387             // flushed
1388             if(hierarchy == TPM_RH_ENDORSEMENT || hierarchy == TPM_RH_PLATFORM)
1389                 continue;
1390             // Get the index information
1391             NvReadNvIndexInfo(currentAddr, &nvIndex);
1392 
1393             // For storage hierarchy, flush OwnerCreated index
1394             if(!IS_ATTRIBUTE(nvIndex.publicArea.attributes, TPMA_NV,
1395                              PLATFORMCREATE))
1396             {
1397                 // Delete the index (including RAM for orderly)
1398                 result = NvDeleteIndex(&nvIndex, currentAddr);
1399                 if(result != TPM_RC_SUCCESS)
1400                     break;
1401                 // Re-iterate from beginning after a delete
1402                 iter = NV_REF_INIT;
1403             }
1404         }
1405         else if(HandleGetType(entityHandle) == TPM_HT_PERSISTENT)
1406         {
1407             OBJECT_ATTRIBUTES           attributes;
1408 //
1409             NvRead(&attributes,
1410                    (UINT32)(currentAddr
1411                             + sizeof(TPM_HANDLE)
1412                             + offsetof(OBJECT, attributes)),
1413                    sizeof(OBJECT_ATTRIBUTES));
1414             // If the evict object belongs to the hierarchy to be flushed...
1415             if((hierarchy == TPM_RH_PLATFORM && attributes.ppsHierarchy == SET)
1416                || (hierarchy == TPM_RH_OWNER && attributes.spsHierarchy == SET)
1417                || (hierarchy == TPM_RH_ENDORSEMENT
1418                    &&  attributes.epsHierarchy == SET))
1419             {
1420                 // ...then delete the evict object
1421                 result = NvDelete(currentAddr);
1422                 if(result != TPM_RC_SUCCESS)
1423                     break;
1424                 // Re-iterate from beginning after a delete
1425                 iter = NV_REF_INIT;
1426             }
1427         }
1428         else
1429         {
1430             FAIL(FATAL_ERROR_INTERNAL);
1431         }
1432     }
1433     return result;
1434 }
1435 
1436 //*** NvSetGlobalLock()
1437 // This function is used to SET the TPMA_NV_WRITELOCKED attribute for all
1438 // NV indexes that have TPMA_NV_GLOBALLOCK SET. This function is use by
1439 // TPM2_NV_GlobalWriteLock().
1440 //  Return Type: TPM_RC
1441 //      TPM_RC_NV_RATE           NV is unavailable because of rate limit
1442 //      TPM_RC_NV_UNAVAILABLE    NV is inaccessible
1443 TPM_RC
NvSetGlobalLock(void)1444 NvSetGlobalLock(
1445     void
1446     )
1447 {
1448     NV_REF           iter = NV_REF_INIT;
1449     NV_RAM_REF       ramIter = NV_RAM_REF_INIT;
1450     NV_REF           currentAddr;
1451     NV_RAM_REF       currentRamAddr;
1452     TPM_RC           result = TPM_RC_SUCCESS;
1453 //
1454     // Check all normal indexes
1455     while((currentAddr = NvNextIndex(NULL, &iter)) != 0)
1456     {
1457         TPMA_NV         attributes = NvReadNvIndexAttributes(currentAddr);
1458 //
1459         // See if it should be locked
1460         if(!IS_ATTRIBUTE(attributes, TPMA_NV, ORDERLY)
1461            &&  IS_ATTRIBUTE(attributes, TPMA_NV, GLOBALLOCK))
1462         {
1463             SET_ATTRIBUTE(attributes, TPMA_NV, WRITELOCKED);
1464             result = NvWriteNvIndexAttributes(currentAddr, attributes);
1465             if(result != TPM_RC_SUCCESS)
1466                 return result;
1467         }
1468     }
1469     // Now search all the orderly attributes
1470     while((currentRamAddr = NvRamNext(&ramIter, NULL)) != 0)
1471     {
1472         // See if it should be locked
1473         TPMA_NV         attributes = NvReadRamIndexAttributes(currentRamAddr);
1474         if(IS_ATTRIBUTE(attributes, TPMA_NV, GLOBALLOCK))
1475         {
1476             SET_ATTRIBUTE(attributes, TPMA_NV, WRITELOCKED);
1477             NvWriteRamIndexAttributes(currentRamAddr, attributes);
1478         }
1479     }
1480     return result;
1481 }
1482 
1483 //***InsertSort()
1484 // Sort a handle into handle list in ascending order.  The total handle number in
1485 // the list should not exceed MAX_CAP_HANDLES
1486 static void
InsertSort(TPML_HANDLE * handleList,UINT32 count,TPM_HANDLE entityHandle)1487 InsertSort(
1488     TPML_HANDLE     *handleList,    // IN/OUT: sorted handle list
1489     UINT32           count,         // IN: maximum count in the handle list
1490     TPM_HANDLE       entityHandle   // IN: handle to be inserted
1491     )
1492 {
1493     UINT32          i, j;
1494     UINT32          originalCount;
1495 //
1496     // For a corner case that the maximum count is 0, do nothing
1497     if(count == 0)
1498         return;
1499     // For empty list, add the handle at the beginning and return
1500     if(handleList->count == 0)
1501     {
1502         handleList->handle[0] = entityHandle;
1503         handleList->count++;
1504         return;
1505     }
1506     // Check if the maximum of the list has been reached
1507     originalCount = handleList->count;
1508     if(originalCount < count)
1509         handleList->count++;
1510     // Insert the handle to the list
1511     for(i = 0; i < originalCount; i++)
1512     {
1513         if(handleList->handle[i] > entityHandle)
1514         {
1515             for(j = handleList->count - 1; j > i; j--)
1516             {
1517                 handleList->handle[j] = handleList->handle[j - 1];
1518             }
1519             break;
1520         }
1521     }
1522     // If a slot was found, insert the handle in this position
1523     if(i < originalCount || handleList->count > originalCount)
1524         handleList->handle[i] = entityHandle;
1525     return;
1526 }
1527 
1528 //*** NvCapGetPersistent()
1529 // This function is used to get a list of handles of the persistent objects,
1530 // starting at 'handle'.
1531 //
1532 // 'Handle' must be in valid persistent object handle range, but does not
1533 // have to reference an existing persistent object.
1534 //  Return Type: TPMI_YES_NO
1535 //      YES         if there are more handles available
1536 //      NO          all the available handles has been returned
1537 TPMI_YES_NO
NvCapGetPersistent(TPMI_DH_OBJECT handle,UINT32 count,TPML_HANDLE * handleList)1538 NvCapGetPersistent(
1539     TPMI_DH_OBJECT   handle,        // IN: start handle
1540     UINT32           count,         // IN: maximum number of returned handles
1541     TPML_HANDLE     *handleList     // OUT: list of handle
1542     )
1543 {
1544     TPMI_YES_NO              more = NO;
1545     NV_REF                   iter = NV_REF_INIT;
1546     NV_REF                   currentAddr;
1547     TPM_HANDLE               entityHandle;
1548 //
1549     pAssert(HandleGetType(handle) == TPM_HT_PERSISTENT);
1550 
1551     // Initialize output handle list
1552     handleList->count = 0;
1553 
1554     // The maximum count of handles we may return is MAX_CAP_HANDLES
1555     if(count > MAX_CAP_HANDLES) count = MAX_CAP_HANDLES;
1556 
1557     while((currentAddr = NvNextEvict(&entityHandle, &iter)) != 0)
1558     {
1559         // Ignore persistent handles that have values less than the input handle
1560         if(entityHandle < handle)
1561             continue;
1562         // if the handles in the list have reached the requested count, and there
1563         // are still handles need to be inserted, indicate that there are more.
1564         if(handleList->count == count)
1565             more = YES;
1566         // A handle with a value larger than start handle is a candidate
1567         // for return. Insert sort it to the return list.  Insert sort algorithm
1568         // is chosen here for simplicity based on the assumption that the total
1569         // number of NV indexes is small.  For an implementation that may allow
1570         // large number of NV indexes, a more efficient sorting algorithm may be
1571         // used here.
1572         InsertSort(handleList, count, entityHandle);
1573     }
1574     return more;
1575 }
1576 
1577 //*** NvCapGetIndex()
1578 // This function returns a list of handles of NV indexes, starting from 'handle'.
1579 // 'Handle' must be in the range of NV indexes, but does not have to reference
1580 // an existing NV Index.
1581 //  Return Type: TPMI_YES_NO
1582 //      YES         if there are more handles to report
1583 //      NO          all the available handles has been reported
1584 TPMI_YES_NO
NvCapGetIndex(TPMI_DH_OBJECT handle,UINT32 count,TPML_HANDLE * handleList)1585 NvCapGetIndex(
1586     TPMI_DH_OBJECT   handle,        // IN: start handle
1587     UINT32           count,         // IN: max number of returned handles
1588     TPML_HANDLE     *handleList     // OUT: list of handle
1589     )
1590 {
1591     TPMI_YES_NO              more = NO;
1592     NV_REF                   iter = NV_REF_INIT;
1593     NV_REF                   currentAddr;
1594     TPM_HANDLE               nvHandle;
1595 //
1596     pAssert(HandleGetType(handle) == TPM_HT_NV_INDEX);
1597 
1598     // Initialize output handle list
1599     handleList->count = 0;
1600 
1601     // The maximum count of handles we may return is MAX_CAP_HANDLES
1602     if(count > MAX_CAP_HANDLES) count = MAX_CAP_HANDLES;
1603 
1604     while((currentAddr = NvNextIndex(&nvHandle, &iter)) != 0)
1605     {
1606         // Ignore index handles that have values less than the 'handle'
1607         if(nvHandle < handle)
1608             continue;
1609         // if the count of handles in the list has reached the requested count,
1610         // and there are still handles to report, set more.
1611         if(handleList->count == count)
1612             more = YES;
1613         // A handle with a value larger than start handle is a candidate
1614         // for return. Insert sort it to the return list.  Insert sort algorithm
1615         // is chosen here for simplicity based on the assumption that the total
1616         // number of NV indexes is small.  For an implementation that may allow
1617         // large number of NV indexes, a more efficient sorting algorithm may be
1618         // used here.
1619         InsertSort(handleList, count, nvHandle);
1620     }
1621     return more;
1622 }
1623 
1624 //*** NvCapGetIndexNumber()
1625 // This function returns the count of NV Indexes currently defined.
1626 UINT32
NvCapGetIndexNumber(void)1627 NvCapGetIndexNumber(
1628     void
1629     )
1630 {
1631     UINT32           num = 0;
1632     NV_REF           iter = NV_REF_INIT;
1633 //
1634     while(NvNextIndex(NULL, &iter) != 0)
1635         num++;
1636     return num;
1637 }
1638 
1639 //*** NvCapGetPersistentNumber()
1640 // Function returns the count of persistent objects currently in NV memory.
1641 UINT32
NvCapGetPersistentNumber(void)1642 NvCapGetPersistentNumber(
1643     void
1644     )
1645 {
1646     UINT32          num = 0;
1647     NV_REF         iter = NV_REF_INIT;
1648     TPM_HANDLE      handle;
1649 //
1650     while(NvNextEvict(&handle, &iter) != 0)
1651         num++;
1652     return num;
1653 }
1654 
1655 //*** NvCapGetPersistentAvail()
1656 // This function returns an estimate of the number of additional persistent
1657 // objects that could be loaded into NV memory.
1658 UINT32
NvCapGetPersistentAvail(void)1659 NvCapGetPersistentAvail(
1660     void
1661     )
1662 {
1663     UINT32          availNVSpace;
1664     UINT32          counterNum = NvCapGetCounterNumber();
1665     UINT32          reserved = sizeof(NV_LIST_TERMINATOR);
1666 //
1667     // Get the available space in NV storage
1668     availNVSpace = NvGetFreeBytes();
1669 
1670     if(counterNum < MIN_COUNTER_INDICES)
1671     {
1672         // Some space has to be reserved for counter objects.
1673         reserved += (MIN_COUNTER_INDICES - counterNum) * NV_INDEX_COUNTER_SIZE;
1674         if(reserved > availNVSpace)
1675             availNVSpace = 0;
1676         else
1677             availNVSpace -= reserved;
1678     }
1679     return availNVSpace / NV_EVICT_OBJECT_SIZE;
1680 }
1681 
1682 //*** NvCapGetCounterNumber()
1683 // Get the number of defined NV Indexes that are counter indexes.
1684 UINT32
NvCapGetCounterNumber(void)1685 NvCapGetCounterNumber(
1686     void
1687     )
1688 {
1689     NV_REF           iter = NV_REF_INIT;
1690     NV_REF           currentAddr;
1691     UINT32           num = 0;
1692 //
1693     while((currentAddr = NvNextIndex(NULL, &iter)) != 0)
1694     {
1695         TPMA_NV             attributes = NvReadNvIndexAttributes(currentAddr);
1696         if(IsNvCounterIndex(attributes))
1697             num++;
1698     }
1699     return num;
1700 }
1701 
1702 //*** NvSetStartupAttributes()
1703 // Local function to set the attributes of an Index at TPM Reset and TPM Restart.
1704 static TPMA_NV
NvSetStartupAttributes(TPMA_NV attributes,STARTUP_TYPE type)1705 NvSetStartupAttributes(
1706     TPMA_NV         attributes,         // IN: attributes to change
1707     STARTUP_TYPE     type               // IN: start up type
1708     )
1709 {
1710     // Clear read lock
1711     CLEAR_ATTRIBUTE(attributes, TPMA_NV, READLOCKED);
1712 
1713     // Will change a non counter index to the unwritten state if:
1714     // a) TPMA_NV_CLEAR_STCLEAR is SET
1715     // b) orderly and TPM Reset
1716     if(!IsNvCounterIndex(attributes))
1717     {
1718         if(IS_ATTRIBUTE(attributes, TPMA_NV, CLEAR_STCLEAR)
1719            || (IS_ATTRIBUTE(attributes, TPMA_NV, ORDERLY)
1720                && (type == SU_RESET)))
1721             CLEAR_ATTRIBUTE(attributes, TPMA_NV, WRITTEN);
1722     }
1723     // Unlock any index that is not written or that does not have
1724     // TPMA_NV_WRITEDEFINE SET.
1725     if(!IS_ATTRIBUTE(attributes, TPMA_NV, WRITTEN)
1726        || !IS_ATTRIBUTE(attributes, TPMA_NV, WRITEDEFINE))
1727         CLEAR_ATTRIBUTE(attributes, TPMA_NV, WRITELOCKED);
1728     return attributes;
1729 }
1730 
1731 //*** NvEntityStartup()
1732 //  This function is called at TPM_Startup(). If the startup completes
1733 //  a TPM Resume cycle, no action is taken. If the startup is a TPM Reset
1734 //  or a TPM Restart, then this function will:
1735 //  a) clear read/write lock;
1736 //  b) reset NV Index data that has TPMA_NV_CLEAR_STCLEAR SET; and
1737 //  c) set the lower bits in orderly counters to 1 for a non-orderly startup
1738 //
1739 //  It is a prerequisite that NV be available for writing before this
1740 //  function is called.
1741 BOOL
NvEntityStartup(STARTUP_TYPE type)1742 NvEntityStartup(
1743     STARTUP_TYPE     type           // IN: start up type
1744     )
1745 {
1746     NV_REF               iter = NV_REF_INIT;
1747     NV_RAM_REF           ramIter = NV_RAM_REF_INIT;
1748     NV_REF               currentAddr;        // offset points to the current entity
1749     NV_RAM_REF           currentRamAddr;
1750     TPM_HANDLE           nvHandle;
1751     TPMA_NV              attributes;
1752 //
1753     // Restore RAM index data
1754     NvRead(s_indexOrderlyRam, NV_INDEX_RAM_DATA, sizeof(s_indexOrderlyRam));
1755 
1756     // Initialize the max NV counter value
1757     NvSetMaxCount(NvGetMaxCount());
1758 
1759     // If recovering from state save, do nothing else
1760     if(type == SU_RESUME)
1761         return TRUE;
1762     // Iterate all the NV Index to clear the locks
1763     while((currentAddr = NvNextIndex(&nvHandle, &iter)) != 0)
1764     {
1765         attributes = NvReadNvIndexAttributes(currentAddr);
1766 
1767         // If this is an orderly index, defer processing until loop below
1768         if(IS_ATTRIBUTE(attributes, TPMA_NV, ORDERLY))
1769             continue;
1770         // Set the attributes appropriate for this startup type
1771         attributes = NvSetStartupAttributes(attributes, type);
1772         NvWriteNvIndexAttributes(currentAddr, attributes);
1773     }
1774     // Iterate all the orderly indexes to clear the locks and initialize counters
1775     while((currentRamAddr = NvRamNext(&ramIter, NULL)) != 0)
1776     {
1777         attributes = NvReadRamIndexAttributes(currentRamAddr);
1778 
1779         attributes = NvSetStartupAttributes(attributes, type);
1780 
1781         // update attributes in RAM
1782         NvWriteRamIndexAttributes(currentRamAddr, attributes);
1783 
1784         // Set the lower bits in an orderly counter to 1 for a non-orderly startup
1785         if(IsNvCounterIndex(attributes)
1786            && (g_prevOrderlyState == SU_NONE_VALUE))
1787         {
1788             UINT64      counter;
1789 //
1790             // Read the counter value last saved to NV.
1791             counter = BYTE_ARRAY_TO_UINT64(currentRamAddr + sizeof(NV_RAM_HEADER));
1792 
1793             // Set the lower bits of counter to 1's
1794             counter |= MAX_ORDERLY_COUNT;
1795 
1796             // Write back to RAM
1797             // NOTE: Do not want to force a write to NV here. The counter value will
1798             // stay in RAM until the next shutdown or rollover.
1799             UINT64_TO_BYTE_ARRAY(counter, currentRamAddr + sizeof(NV_RAM_HEADER));
1800         }
1801     }
1802     return TRUE;
1803 }
1804 
1805 //*** NvCapGetCounterAvail()
1806 // This function returns an estimate of the number of additional counter type
1807 // NV indexes that can be defined.
1808 UINT32
NvCapGetCounterAvail(void)1809 NvCapGetCounterAvail(
1810     void
1811     )
1812 {
1813     UINT32          availNVSpace;
1814     UINT32          availRAMSpace;
1815     UINT32          persistentNum = NvCapGetPersistentNumber();
1816     UINT32          reserved = sizeof(NV_LIST_TERMINATOR);
1817 //
1818     // Get the available space in NV storage
1819     availNVSpace = NvGetFreeBytes();
1820 
1821     if(persistentNum < MIN_EVICT_OBJECTS)
1822     {
1823         // Some space has to be reserved for evict object. Adjust availNVSpace.
1824         reserved += (MIN_EVICT_OBJECTS - persistentNum) * NV_EVICT_OBJECT_SIZE;
1825         if(reserved > availNVSpace)
1826             availNVSpace = 0;
1827         else
1828             availNVSpace -= reserved;
1829     }
1830     // Compute the available space in RAM
1831     availRAMSpace = (int)(RAM_ORDERLY_END - NvRamGetEnd());
1832 
1833     // Return the min of counter number in NV and in RAM
1834     if(availNVSpace / NV_INDEX_COUNTER_SIZE
1835         > availRAMSpace / NV_RAM_INDEX_COUNTER_SIZE)
1836         return availRAMSpace / NV_RAM_INDEX_COUNTER_SIZE;
1837     else
1838         return availNVSpace / NV_INDEX_COUNTER_SIZE;
1839 }
1840 
1841 //*** NvFindHandle()
1842 // this function returns the offset in NV memory of the entity associated
1843 // with the input handle.  A value of zero indicates that handle does not
1844 //  exist reference an existing persistent object or defined NV Index.
1845 NV_REF
NvFindHandle(TPM_HANDLE handle)1846 NvFindHandle(
1847     TPM_HANDLE       handle
1848     )
1849 {
1850     NV_REF           addr;
1851     NV_REF           iter = NV_REF_INIT;
1852     TPM_HANDLE       nextHandle;
1853 //
1854     while((addr = NvNext(&iter, &nextHandle)) != 0)
1855     {
1856         if(nextHandle == handle)
1857             break;
1858     }
1859     return addr;
1860 }
1861 
1862 //** NV Max Counter
1863 //*** Introduction
1864 // The TPM keeps track of the highest value of a deleted counter index. When an
1865 // index is deleted, this value is updated if the deleted counter index is greater
1866 // than the previous value. When a new index is created and first incremented, it
1867 // will get a value that is at least one greater than any other index than any
1868 // previously deleted index. This insures that it is not possible to roll back an
1869 // index.
1870 //
1871 // The highest counter value is kept in NV in a special end-of-list marker. This
1872 // marker is only updated when an index is deleted. Otherwise it just moves.
1873 //
1874 // When the TPM starts up, it searches NV for the end of list marker and initializes
1875 // an in memory value (s_maxCounter).
1876 
1877 //*** NvReadMaxCount()
1878 // This function returns the max NV counter value.
1879 //
1880 UINT64
NvReadMaxCount(void)1881 NvReadMaxCount(
1882     void
1883     )
1884 {
1885     return s_maxCounter;
1886 }
1887 
1888 //*** NvUpdateMaxCount()
1889 // This function updates the max counter value to NV memory. This is just staging
1890 // for the actual write that will occur when the NV index memory is modified.
1891 //
1892 void
NvUpdateMaxCount(UINT64 count)1893 NvUpdateMaxCount(
1894     UINT64           count
1895     )
1896 {
1897     if(count > s_maxCounter)
1898         s_maxCounter = count;
1899 }
1900 
1901 //*** NvSetMaxCount()
1902 // This function is used at NV initialization time to set the initial value of
1903 // the maximum counter.
1904 void
NvSetMaxCount(UINT64 value)1905 NvSetMaxCount(
1906     UINT64          value
1907     )
1908 {
1909     s_maxCounter = value;
1910 }
1911 
1912 //*** NvGetMaxCount()
1913 // Function to get the NV max counter value from the end-of-list marker
1914 UINT64
NvGetMaxCount(void)1915 NvGetMaxCount(
1916     void
1917     )
1918 {
1919     NV_REF               iter = NV_REF_INIT;
1920     NV_REF               currentAddr;
1921     UINT64               maxCount;
1922 //
1923     // Find the end of list marker and initialize the NV Max Counter value.
1924     while((currentAddr = NvNext(&iter, NULL )) != 0);
1925     // 'iter' should be pointing at the end of list marker so read in the current
1926     // value of the s_maxCounter.
1927     NvRead(&maxCount, iter + sizeof(UINT32), sizeof(maxCount));
1928 
1929     return maxCount;
1930 }
1931