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