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