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