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