1// 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 // Make sure that NV state is still good 64 if (s_NvStatus == TPM_RC_SUCCESS) 65 NvCheckState(); 66 67 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; 401 memcpy(&currHandle, &s_ramIndex[currAddr + sizeof(UINT32)], 402 sizeof(currHandle)); 403 // Found a match 404 if(currHandle == handle) 405 // data buffer follows the handle and size field 406 break; 407 memcpy(&currSize, &s_ramIndex[currAddr], sizeof(currSize)); 408 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 428 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)])); 433 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 460 memcpy(&size, &s_ramIndex[nodeOffset], sizeof(size)); 461 // 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#ifdef EMBEDDED_MODE 662 _plat__GetFwVersion(&gp.firmwareV1, &gp.firmwareV2); 663#else 664 NvReadReserved(NV_FIRMWARE_V1, &gp.firmwareV1); 665 NvReadReserved(NV_FIRMWARE_V2, &gp.firmwareV2); 666#endif 667 return; 668} 669// 670// 671// NvIsPlatformPersistentHandle() 672// 673// This function indicates if a handle references a persistent object in the range belonging to the platform. 674// 675// Return Value Meaning 676// 677// TRUE handle references a platform persistent object 678// FALSE handle does not reference platform persistent object and may 679// reference an owner persistent object either 680// 681BOOL 682NvIsPlatformPersistentHandle( 683 TPM_HANDLE handle // IN: handle 684 ) 685{ 686 return (handle >= PLATFORM_PERSISTENT && handle <= PERSISTENT_LAST); 687} 688// 689// 690// NvIsOwnerPersistentHandle() 691// 692// This function indicates if a handle references a persistent object in the range belonging to the owner. 693// 694// Return Value Meaning 695// 696// TRUE handle is owner persistent handle 697// FALSE handle is not owner persistent handle and may not be a persistent 698// handle at all 699// 700BOOL 701NvIsOwnerPersistentHandle( 702 TPM_HANDLE handle // IN: handle 703 ) 704{ 705 return (handle >= PERSISTENT_FIRST && handle < PLATFORM_PERSISTENT); 706} 707// 708// 709// NvNextIndex() 710// 711// This function returns the offset in NV of the next NV Index entry. A value of 0 indicates the end of the list. 712// Family "2.0" TCG Published Page 131 713// Level 00 Revision 01.16 Copyright © TCG 2006-2014 October 30, 2014 714// Trusted Platform Module Library Part 4: Supporting Routines 715// 716static UINT32 717NvNextIndex( 718 NV_ITER *iter 719 ) 720{ 721 UINT32 addr; 722 TPM_HANDLE handle; 723 while((addr = NvNext(iter)) != 0) 724 { 725 // Read handle 726 _plat__NvMemoryRead(addr, sizeof(TPM_HANDLE), &handle); 727 if(HandleGetType(handle) == TPM_HT_NV_INDEX) 728 return addr; 729 } 730 pAssert(addr == 0); 731 return addr; 732} 733// 734// 735// NvNextEvict() 736// 737// This function returns the offset in NV of the next evict object entry. A value of 0 indicates the end of the 738// list. 739// 740static UINT32 741NvNextEvict( 742 NV_ITER *iter 743 ) 744{ 745 UINT32 addr; 746 TPM_HANDLE handle; 747 while((addr = NvNext(iter)) != 0) 748 { 749 // Read handle 750 _plat__NvMemoryRead(addr, sizeof(TPM_HANDLE), &handle); 751 if(HandleGetType(handle) == TPM_HT_PERSISTENT) 752 return addr; 753 } 754 pAssert(addr == 0); 755 return addr; 756} 757// 758// 759// NvFindHandle() 760// 761// this function returns the offset in NV memory of the entity associated with the input handle. A value of 762// zero indicates that handle does not exist reference an existing persistent object or defined NV Index. 763// 764static UINT32 765NvFindHandle( 766 TPM_HANDLE handle 767 ) 768{ 769 UINT32 addr; 770 NV_ITER iter = NV_ITER_INIT; 771 while((addr = NvNext(&iter)) != 0) 772 { 773 TPM_HANDLE entityHandle; 774 // Read handle 775// 776 _plat__NvMemoryRead(addr, sizeof(TPM_HANDLE), &entityHandle); 777 if(entityHandle == handle) 778 return addr; 779 } 780 pAssert(addr == 0); 781 return addr; 782} 783 784// 785// NvCheckAndMigrateIfNeeded() 786// 787// Supported only in EMBEDDED_MODE. 788// 789// Check if the NVRAM storage format changed, and if so - reinitialize the 790// NVRAM. No content migration yet, hopefully it will come one day. 791// 792// Note that the NV_FIRMWARE_V1 and NV_FIRMWARE_V2 values not used to store 793// TPM versoion when in embedded mode are used for NVRAM format version 794// instead. 795// 796// 797static void 798NvCheckAndMigrateIfNeeded(void) 799{ 800#ifdef EMBEDDED_MODE 801 UINT32 nv_vers1; 802 UINT32 nv_vers2; 803 804 NvReadReserved(NV_FIRMWARE_V1, &nv_vers1); 805 NvReadReserved(NV_FIRMWARE_V2, &nv_vers2); 806 807 if ((nv_vers1 == ~nv_vers2) && (nv_vers1 == NV_FORMAT_VERSION)) 808 return; // All is well. 809 810 // This will reinitialize NVRAM to empty. Migration code will come here 811 // later. 812 NvInit(); 813 814 nv_vers1 = NV_FORMAT_VERSION; 815 nv_vers2 = ~NV_FORMAT_VERSION; 816 817 NvWriteReserved(NV_FIRMWARE_V1, &nv_vers1); 818 NvWriteReserved(NV_FIRMWARE_V2, &nv_vers2); 819 820 NvCommit(); 821#endif 822} 823 824 825// 826// 827// NvPowerOn() 828// 829// This function is called at _TPM_Init() to initialize the NV environment. 830// 831// Return Value Meaning 832// 833// TRUE all NV was initialized 834// FALSE the NV containing saved state had an error and 835// TPM2_Startup(CLEAR) is required 836// 837BOOL 838NvPowerOn( 839 void 840 ) 841{ 842 int nvError = 0; 843 // If power was lost, need to re-establish the RAM data that is loaded from 844 // NV and initialize the static variables 845 if(_plat__WasPowerLost(TRUE)) 846 { 847 if((nvError = _plat__NVEnable(0)) < 0) 848 FAIL(FATAL_ERROR_NV_UNRECOVERABLE); 849 NvInitStatic(); 850 NvCheckAndMigrateIfNeeded(); 851 } 852 return nvError == 0; 853} 854// 855// 856// NvStateSave() 857// 858// This function is used to cause the memory containing the RAM backed NV Indices to be written to NV. 859// 860void 861NvStateSave( 862 void 863 ) 864{ 865 // Write RAM backed NV Index info to NV 866 // No need to save s_ramIndexSize because we save it to NV whenever it is 867 // updated. 868 _plat__NvMemoryWrite(s_ramIndexAddr, RAM_INDEX_SPACE, s_ramIndex); 869 // Set the flag so that an NV write happens before the command completes. 870 g_updateNV = TRUE; 871 return; 872} 873// 874// 875// 876// NvEntityStartup() 877// 878// This function is called at TPM_Startup(). If the startup completes a TPM Resume cycle, no action is 879// taken. If the startup is a TPM Reset or a TPM Restart, then this function will: 880// a) clear read/write lock; 881// b) reset NV Index data that has TPMA_NV_CLEAR_STCLEAR SET; and 882// c) set the lower bits in orderly counters to 1 for a non-orderly startup 883// It is a prerequisite that NV be available for writing before this function is called. 884// 885void 886NvEntityStartup( 887 STARTUP_TYPE type // IN: start up type 888 ) 889{ 890 NV_ITER iter = NV_ITER_INIT; 891 UINT32 currentAddr; // offset points to the current entity 892 // Restore RAM index data 893 _plat__NvMemoryRead(s_ramIndexSizeAddr, sizeof(UINT32), &s_ramIndexSize); 894 _plat__NvMemoryRead(s_ramIndexAddr, RAM_INDEX_SPACE, s_ramIndex); 895 // If recovering from state save, do nothing 896 if(type == SU_RESUME) 897 return; 898 // Iterate all the NV Index to clear the locks 899 while((currentAddr = NvNextIndex(&iter)) != 0) 900 { 901 NV_INDEX nvIndex; 902 UINT32 indexAddr; // NV address points to index info 903 TPMA_NV attributes; 904 UINT32 attributesValue; 905 UINT32 publicAreaAttributesValue; 906 indexAddr = currentAddr + sizeof(TPM_HANDLE); 907 // Read NV Index info structure 908 _plat__NvMemoryRead(indexAddr, sizeof(NV_INDEX), &nvIndex); 909 attributes = nvIndex.publicArea.attributes; 910 // Clear read/write lock 911 if(attributes.TPMA_NV_READLOCKED == SET) 912 attributes.TPMA_NV_READLOCKED = CLEAR; 913 if( attributes.TPMA_NV_WRITELOCKED == SET 914 && ( attributes.TPMA_NV_WRITTEN == CLEAR 915 || attributes.TPMA_NV_WRITEDEFINE == CLEAR 916 ) 917 ) 918 attributes.TPMA_NV_WRITELOCKED = CLEAR; 919 // Reset NV data for TPMA_NV_CLEAR_STCLEAR 920 if(attributes.TPMA_NV_CLEAR_STCLEAR == SET) 921 { 922 attributes.TPMA_NV_WRITTEN = CLEAR; 923 attributes.TPMA_NV_WRITELOCKED = CLEAR; 924 } 925 // Reset NV data for orderly values that are not counters 926 // NOTE: The function has already exited on a TPM Resume, so the only 927 // things being processed are TPM Restart and TPM Reset 928 if( type == SU_RESET 929 && attributes.TPMA_NV_ORDERLY == SET 930 && attributes.TPMA_NV_COUNTER == CLEAR 931 ) 932 attributes.TPMA_NV_WRITTEN = CLEAR; 933 // Write NV Index info back if it has changed 934 memcpy(&attributesValue, &attributes, sizeof(attributesValue)); 935 memcpy(&publicAreaAttributesValue, &nvIndex.publicArea.attributes, 936 sizeof(publicAreaAttributesValue)); 937 if(attributesValue != publicAreaAttributesValue) 938 { 939 nvIndex.publicArea.attributes = attributes; 940 _plat__NvMemoryWrite(indexAddr, sizeof(NV_INDEX), &nvIndex); 941 // Set the flag that a NV write happens 942 g_updateNV = TRUE; 943 } 944 // Set the lower bits in an orderly counter to 1 for a non-orderly startup 945 if( g_prevOrderlyState == SHUTDOWN_NONE 946 && attributes.TPMA_NV_WRITTEN == SET) 947 { 948 if( attributes.TPMA_NV_ORDERLY == SET 949 && attributes.TPMA_NV_COUNTER == SET) 950 { 951 TPMI_RH_NV_INDEX nvHandle; 952 UINT64 counter; 953 // Read NV handle 954 _plat__NvMemoryRead(currentAddr, sizeof(TPM_HANDLE), &nvHandle); 955 // Read the counter value saved to NV upon the last roll over. 956 // Do not use RAM backed storage for this once. 957 nvIndex.publicArea.attributes.TPMA_NV_ORDERLY = CLEAR; 958 NvGetIntIndexData(nvHandle, &nvIndex, &counter); 959 nvIndex.publicArea.attributes.TPMA_NV_ORDERLY = SET; 960 // Set the lower bits of counter to 1's 961 counter |= MAX_ORDERLY_COUNT; 962 // Write back to RAM 963 NvWriteIndexData(nvHandle, &nvIndex, 0, sizeof(counter), &counter); 964 // No write to NV because an orderly shutdown will update the 965 // counters. 966 } 967 } 968 } 969 return; 970} 971// 972// 973// NV Access Functions 974// 975// Introduction 976// 977// This set of functions provide accessing NV Index and persistent objects based using a handle for 978// reference to the entity. 979// 980// NvIsUndefinedIndex() 981// 982// This function is used to verify that an NV Index is not defined. This is only used by 983// TPM2_NV_DefineSpace(). 984// 985// 986// 987// 988// Return Value Meaning 989// 990// TRUE the handle points to an existing NV Index 991// FALSE the handle points to a non-existent Index 992// 993BOOL 994NvIsUndefinedIndex( 995 TPMI_RH_NV_INDEX handle // IN: handle 996 ) 997{ 998 UINT32 entityAddr; // offset points to the entity 999 pAssert(HandleGetType(handle) == TPM_HT_NV_INDEX); 1000 // Find the address of index 1001 entityAddr = NvFindHandle(handle); 1002 // If handle is not found, return TPM_RC_SUCCESS 1003 if(entityAddr == 0) 1004 return TPM_RC_SUCCESS; 1005 // NV Index is defined 1006 return TPM_RC_NV_DEFINED; 1007} 1008// 1009// 1010// NvIndexIsAccessible() 1011// 1012// This function validates that a handle references a defined NV Index and that the Index is currently 1013// accessible. 1014// 1015// Error Returns Meaning 1016// 1017// TPM_RC_HANDLE the handle points to an undefined NV Index If shEnable is CLEAR, 1018// this would include an index created using ownerAuth. If phEnableNV 1019// is CLEAR, this would include and index created using platform auth 1020// TPM_RC_NV_READLOCKED Index is present but locked for reading and command does not write 1021// to the index 1022// TPM_RC_NV_WRITELOCKED Index is present but locked for writing and command writes to the 1023// index 1024// 1025TPM_RC 1026NvIndexIsAccessible( 1027 TPMI_RH_NV_INDEX handle, // IN: handle 1028 TPM_CC commandCode // IN: the command 1029 ) 1030{ 1031 UINT32 entityAddr; // offset points to the entity 1032 NV_INDEX nvIndex; // 1033 pAssert(HandleGetType(handle) == TPM_HT_NV_INDEX); 1034 // Find the address of index 1035 entityAddr = NvFindHandle(handle); 1036 // If handle is not found, return TPM_RC_HANDLE 1037 if(entityAddr == 0) 1038 return TPM_RC_HANDLE; 1039 // Read NV Index info structure 1040 _plat__NvMemoryRead(entityAddr + sizeof(TPM_HANDLE), sizeof(NV_INDEX), 1041 &nvIndex); 1042 if(gc.shEnable == FALSE || gc.phEnableNV == FALSE) 1043 { 1044 // if shEnable is CLEAR, an ownerCreate NV Index should not be 1045 // indicated as present 1046 if(nvIndex.publicArea.attributes.TPMA_NV_PLATFORMCREATE == CLEAR) 1047 { 1048 /* 1049 * FWMP is a Chrome OS specific object saved at address 0x100a, it 1050 * needs to be available for reading even before TPM2_Startup 1051 * command is issued. 1052 */ 1053 UINT32 isFwmpRead = (handle == 0x100100a) && 1054 IsReadOperation(commandCode); 1055 1056 if((gc.shEnable == FALSE) && !isFwmpRead) 1057 return TPM_RC_HANDLE; 1058 } 1059 // if phEnableNV is CLEAR, a platform created Index should not 1060 // be visible 1061 else if(gc.phEnableNV == FALSE) 1062 return TPM_RC_HANDLE; 1063 } 1064 // If the Index is write locked and this is an NV Write operation... 1065 if( nvIndex.publicArea.attributes.TPMA_NV_WRITELOCKED 1066 && IsWriteOperation(commandCode)) 1067 { 1068 // then return a locked indication unless the command is TPM2_NV_WriteLock 1069 if(commandCode != TPM_CC_NV_WriteLock) 1070 return TPM_RC_NV_LOCKED; 1071 return TPM_RC_SUCCESS; 1072 } 1073 // If the Index is read locked and this is an NV Read operation... 1074 if( nvIndex.publicArea.attributes.TPMA_NV_READLOCKED 1075 && IsReadOperation(commandCode)) 1076 { 1077 // then return a locked indication unless the command is TPM2_NV_ReadLock 1078 if(commandCode != TPM_CC_NV_ReadLock) 1079 return TPM_RC_NV_LOCKED; 1080 return TPM_RC_SUCCESS; 1081 } 1082 // NV Index is accessible 1083 return TPM_RC_SUCCESS; 1084} 1085// 1086// 1087// NvIsUndefinedEvictHandle() 1088// 1089// This function indicates if a handle does not reference an existing persistent object. This function requires 1090// that the handle be in the proper range for persistent objects. 1091// 1092// Return Value Meaning 1093// 1094// TRUE handle does not reference an existing persistent object 1095// FALSE handle does reference an existing persistent object 1096// 1097static BOOL 1098NvIsUndefinedEvictHandle( 1099 TPM_HANDLE handle // IN: handle 1100 ) 1101{ 1102 UINT32 entityAddr; // offset points to the entity 1103 pAssert(HandleGetType(handle) == TPM_HT_PERSISTENT); 1104 // Find the address of evict object 1105 entityAddr = NvFindHandle(handle); 1106 // If handle is not found, return TRUE 1107 if(entityAddr == 0) 1108 return TRUE; 1109 else 1110 return FALSE; 1111} 1112 1113// 1114// 1115// NvUnmarshalObject() 1116// 1117// This function accepts a buffer containing a marshaled OBJECT 1118// structure, a pointer to the area where the input data should be 1119// unmarshaled, and a pointer to the size of the output area. 1120// 1121// No error checking is performed, unmarshaled data is guaranteed not to 1122// spill over the allocated space. 1123// 1124static TPM_RC NvUnmarshalObject(OBJECT *o, BYTE **buf, INT32 *size) 1125{ 1126 TPM_RC result; 1127 1128 // There is no generated function to unmarshal the attributes field, do it 1129 // by hand. 1130 MemoryCopy(&o->attributes, *buf, sizeof(o->attributes), *size); 1131 *buf += sizeof(o->attributes); 1132 *size -= sizeof(o->attributes); 1133 1134 result = TPMT_PUBLIC_Unmarshal(&o->publicArea, buf, size); 1135 if (result != TPM_RC_SUCCESS) 1136 return result; 1137 1138 result = TPMT_SENSITIVE_Unmarshal(&o->sensitive, buf, size); 1139 if (result != TPM_RC_SUCCESS) 1140 return result; 1141 1142#ifdef TPM_ALG_RSA 1143 result = TPM2B_PUBLIC_KEY_RSA_Unmarshal(&o->privateExponent, buf, size); 1144 if (result != TPM_RC_SUCCESS) 1145 return result; 1146#endif 1147 1148 result = TPM2B_NAME_Unmarshal(&o->qualifiedName, buf, size); 1149 if (result != TPM_RC_SUCCESS) 1150 return result; 1151 1152 result = TPMI_DH_OBJECT_Unmarshal(&o->evictHandle, buf, size, TRUE); 1153 if (result != TPM_RC_SUCCESS) 1154 return result; 1155 1156 return TPM2B_NAME_Unmarshal(&o->name, buf, size); 1157} 1158 1159// 1160// 1161// NvGetEvictObject() 1162// 1163// This function is used to dereference an evict object handle and get a pointer to the object. 1164// 1165// Error Returns Meaning 1166// 1167// TPM_RC_HANDLE the handle does not point to an existing persistent object 1168// 1169TPM_RC 1170NvGetEvictObject( 1171 TPM_HANDLE handle, // IN: handle 1172 OBJECT *object // OUT: object data 1173 ) 1174{ 1175 UINT32 entityAddr; // offset points to the entity 1176 TPM_RC result = TPM_RC_SUCCESS; 1177 pAssert(HandleGetType(handle) == TPM_HT_PERSISTENT); 1178 // Find the address of evict object 1179 entityAddr = NvFindHandle(handle); 1180 // If handle is not found, return an error 1181 if(entityAddr == 0) { 1182 result = TPM_RC_HANDLE; 1183 } else { 1184 UINT32 storedSize; 1185 UINT32 nextEntryAddr; 1186 1187 // Let's calculate the size of object as stored in NVMEM. 1188 _plat__NvMemoryRead(entityAddr - sizeof(UINT32), 1189 sizeof(UINT32), &nextEntryAddr); 1190 1191 storedSize = nextEntryAddr - entityAddr; 1192 1193 if (storedSize == (sizeof(TPM_HANDLE) + sizeof(OBJECT))) { 1194 // Read evict object stored unmarshaled. 1195 _plat__NvMemoryRead(entityAddr + sizeof(TPM_HANDLE), 1196 sizeof(OBJECT), 1197 object); 1198 } else { 1199 // Must be stored marshaled, let's unmarshal it. 1200 BYTE marshaled[sizeof(OBJECT)]; 1201 INT32 max_size = sizeof(marshaled); 1202 BYTE *marshaledPtr = marshaled; 1203 1204 _plat__NvMemoryRead(entityAddr + sizeof(TPM_HANDLE), 1205 storedSize, marshaled); 1206 result = NvUnmarshalObject(object, &marshaledPtr, &max_size); 1207 } 1208 } 1209 // whether there is an error or not, make sure that the evict 1210 // status of the object is set so that the slot will get freed on exit 1211 object->attributes.evict = SET; 1212 return result; 1213} 1214// 1215// 1216// NvGetIndexInfo() 1217// 1218// This function is used to retrieve the contents of an NV Index. 1219// An implementation is allowed to save the NV Index in a vendor-defined format. If the format is different 1220// from the default used by the reference code, then this function would be changed to reformat the data into 1221// the default format. 1222// A prerequisite to calling this function is that the handle must be known to reference a defined NV Index. 1223// 1224void 1225NvGetIndexInfo( 1226 TPMI_RH_NV_INDEX handle, // IN: handle 1227 NV_INDEX *nvIndex // OUT: NV index structure 1228 ) 1229{ 1230 UINT32 entityAddr; // offset points to the entity 1231 pAssert(HandleGetType(handle) == TPM_HT_NV_INDEX); 1232 // Find the address of NV index 1233 entityAddr = NvFindHandle(handle); 1234 pAssert(entityAddr != 0); 1235 // This implementation uses the default format so just 1236 // read the data in 1237 _plat__NvMemoryRead(entityAddr + sizeof(TPM_HANDLE), sizeof(NV_INDEX), 1238 nvIndex); 1239 return; 1240} 1241// 1242// 1243// NvInitialCounter() 1244// 1245// This function returns the value to be used when a counter index is initialized. It will scan the NV counters 1246// and find the highest value in any active counter. It will use that value as the starting point. If there are no 1247// active counters, it will use the value of the previous largest counter. 1248// 1249UINT64 1250NvInitialCounter( 1251 void 1252 ) 1253{ 1254 UINT64 maxCount; 1255 NV_ITER iter = NV_ITER_INIT; 1256 UINT32 currentAddr; 1257 // Read the maxCount value 1258 maxCount = NvReadMaxCount(); 1259 // Iterate all existing counters 1260 while((currentAddr = NvNextIndex(&iter)) != 0) 1261 { 1262 TPMI_RH_NV_INDEX nvHandle; 1263 NV_INDEX nvIndex; 1264 // Read NV handle 1265 _plat__NvMemoryRead(currentAddr, sizeof(TPM_HANDLE), &nvHandle); 1266 // Get NV Index 1267 NvGetIndexInfo(nvHandle, &nvIndex); 1268 if( nvIndex.publicArea.attributes.TPMA_NV_COUNTER == SET 1269 && nvIndex.publicArea.attributes.TPMA_NV_WRITTEN == SET) 1270 { 1271 UINT64 countValue; 1272 // Read counter value 1273 NvGetIntIndexData(nvHandle, &nvIndex, &countValue); 1274 if(countValue > maxCount) 1275 maxCount = countValue; 1276 } 1277 } 1278 // Initialize the new counter value to be maxCount + 1 1279 // A counter is only initialized the first time it is written. The 1280 // way to write a counter is with TPM2_NV_INCREMENT(). Since the 1281 // "initial" value of a defined counter is the largest count value that 1282 // may have existed in this index previously, then the first use would 1283 // add one to that value. 1284 return maxCount; 1285} 1286// 1287// 1288// NvGetIndexData() 1289// 1290// This function is used to access the data in an NV Index. The data is returned as a byte sequence. Since 1291// counter values are kept in native format, they are converted to canonical form before being returned. 1292// Family "2.0" TCG Published Page 139 1293// Level 00 Revision 01.16 Copyright © TCG 2006-2014 October 30, 2014 1294// Trusted Platform Module Library Part 4: Supporting Routines 1295// 1296// 1297// This function requires that the NV Index be defined, and that the required data is within the data range. It 1298// also requires that TPMA_NV_WRITTEN of the Index is SET. 1299// 1300void 1301NvGetIndexData( 1302 TPMI_RH_NV_INDEX handle, // IN: handle 1303 NV_INDEX *nvIndex, // IN: RAM image of index header 1304 UINT32 offset, // IN: offset of NV data 1305 UINT16 size, // IN: size of NV data 1306 void *data // OUT: data buffer 1307 ) 1308{ 1309 pAssert(nvIndex->publicArea.attributes.TPMA_NV_WRITTEN == SET); 1310 if( nvIndex->publicArea.attributes.TPMA_NV_BITS == SET 1311 || nvIndex->publicArea.attributes.TPMA_NV_COUNTER == SET) 1312 { 1313 // Read bit or counter data in canonical form 1314 UINT64 dataInInt; 1315 NvGetIntIndexData(handle, nvIndex, &dataInInt); 1316 UINT64_TO_BYTE_ARRAY(dataInInt, (BYTE *)data); 1317 } 1318 else 1319 { 1320 if(nvIndex->publicArea.attributes.TPMA_NV_ORDERLY == SET) 1321 { 1322 UINT32 ramAddr; 1323 // Get data from RAM buffer 1324 ramAddr = NvGetRAMIndexOffset(handle); 1325 MemoryCopy(data, s_ramIndex + ramAddr + offset, size, size); 1326 } 1327 else 1328 { 1329 UINT32 entityAddr; 1330 entityAddr = NvFindHandle(handle); 1331 // Get data from NV 1332 // Skip NV Index info, read data buffer 1333 entityAddr += sizeof(TPM_HANDLE) + sizeof(NV_INDEX) + offset; 1334 // Read the data 1335 _plat__NvMemoryRead(entityAddr, size, data); 1336 } 1337 } 1338 return; 1339} 1340// 1341// 1342// NvGetIntIndexData() 1343// 1344// Get data in integer format of a bit or counter NV Index. 1345// This function requires that the NV Index is defined and that the NV Index previously has been written. 1346// 1347void 1348NvGetIntIndexData( 1349 TPMI_RH_NV_INDEX handle, // IN: handle 1350 NV_INDEX *nvIndex, // IN: RAM image of NV Index header 1351 UINT64 *data // IN: UINT64 pointer for counter or bit 1352 ) 1353{ 1354 // Validate that index has been written and is the right type 1355 pAssert( nvIndex->publicArea.attributes.TPMA_NV_WRITTEN == SET 1356 && ( nvIndex->publicArea.attributes.TPMA_NV_BITS == SET 1357 || nvIndex->publicArea.attributes.TPMA_NV_COUNTER == SET 1358 ) 1359 ); 1360 // bit and counter value is store in native format for TPM CPU. So we directly 1361 // copy the contents of NV to output data buffer 1362 if(nvIndex->publicArea.attributes.TPMA_NV_ORDERLY == SET) 1363 { 1364 UINT32 ramAddr; 1365 // Get data from RAM buffer 1366 ramAddr = NvGetRAMIndexOffset(handle); 1367 MemoryCopy(data, s_ramIndex + ramAddr, sizeof(*data), sizeof(*data)); 1368 } 1369 else 1370 { 1371 UINT32 entityAddr; 1372 entityAddr = NvFindHandle(handle); 1373 // Get data from NV 1374 // Skip NV Index info, read data buffer 1375 _plat__NvMemoryRead( 1376 entityAddr + sizeof(TPM_HANDLE) + sizeof(NV_INDEX), 1377 sizeof(UINT64), data); 1378 } 1379 return; 1380} 1381// 1382// 1383// NvWriteIndexInfo() 1384// 1385// This function is called to queue the write of NV Index data to persistent memory. 1386// This function requires that NV Index is defined. 1387// 1388// Error Returns Meaning 1389// 1390// TPM_RC_NV_RATE NV is rate limiting so retry 1391// TPM_RC_NV_UNAVAILABLE NV is not available 1392// 1393TPM_RC 1394NvWriteIndexInfo( 1395 TPMI_RH_NV_INDEX handle, // IN: handle 1396 NV_INDEX *nvIndex // IN: NV Index info to be written 1397 ) 1398{ 1399 UINT32 entryAddr; 1400 TPM_RC result; 1401 // Get the starting offset for the index in the RAM image of NV 1402 entryAddr = NvFindHandle(handle); 1403 pAssert(entryAddr != 0); 1404 // Step over the link value 1405 entryAddr = entryAddr + sizeof(TPM_HANDLE); 1406 // If the index data is actually changed, then a write to NV is required 1407 if(_plat__NvIsDifferent(entryAddr, sizeof(NV_INDEX),nvIndex)) 1408 { 1409 // Make sure that NV is available 1410 result = NvIsAvailable(); 1411 if(result != TPM_RC_SUCCESS) 1412 return result; 1413 _plat__NvMemoryWrite(entryAddr, sizeof(NV_INDEX), nvIndex); 1414 g_updateNV = TRUE; 1415 } 1416 return TPM_RC_SUCCESS; 1417} 1418// 1419// 1420// NvWriteIndexData() 1421// 1422// This function is used to write NV index data. 1423// This function requires that the NV Index is defined, and the data is within the defined data range for the 1424// index. 1425// 1426// Error Returns Meaning 1427// 1428// TPM_RC_NV_RATE NV is rate limiting so retry 1429// TPM_RC_NV_UNAVAILABLE NV is not available 1430// 1431TPM_RC 1432NvWriteIndexData( 1433 TPMI_RH_NV_INDEX handle, // IN: handle 1434 NV_INDEX *nvIndex, // IN: RAM copy of NV Index 1435 UINT32 offset, // IN: offset of NV data 1436 UINT32 size, // IN: size of NV data 1437 void *data // OUT: data buffer 1438 ) 1439{ 1440 TPM_RC result; 1441 // Validate that write falls within range of the index 1442 pAssert(nvIndex->publicArea.dataSize >= offset + size); 1443 // Update TPMA_NV_WRITTEN bit if necessary 1444 if(nvIndex->publicArea.attributes.TPMA_NV_WRITTEN == CLEAR) 1445 { 1446 nvIndex->publicArea.attributes.TPMA_NV_WRITTEN = SET; 1447 result = NvWriteIndexInfo(handle, nvIndex); 1448 if(result != TPM_RC_SUCCESS) 1449 return result; 1450 } 1451 // Check to see if process for an orderly index is required. 1452 if(nvIndex->publicArea.attributes.TPMA_NV_ORDERLY == SET) 1453 { 1454 UINT32 ramAddr; 1455 // Write data to RAM buffer 1456 ramAddr = NvGetRAMIndexOffset(handle); 1457 MemoryCopy(s_ramIndex + ramAddr + offset, data, size, 1458 sizeof(s_ramIndex) - ramAddr - offset); 1459 // NV update does not happen for orderly index. Have 1460 // to clear orderlyState to reflect that we have changed the 1461 // NV and an orderly shutdown is required. Only going to do this if we 1462 // are not processing a counter that has just rolled over 1463 if(g_updateNV == FALSE) 1464 g_clearOrderly = TRUE; 1465 } 1466 // Need to process this part if the Index isn't orderly or if it is 1467 // an orderly counter that just rolled over. 1468 if(g_updateNV || nvIndex->publicArea.attributes.TPMA_NV_ORDERLY == CLEAR) 1469 { 1470 // Processing for an index with TPMA_NV_ORDERLY CLEAR 1471 UINT32 entryAddr = NvFindHandle(handle); 1472 pAssert(entryAddr != 0); 1473// 1474 // Offset into the index to the first byte of the data to be written 1475 entryAddr += sizeof(TPM_HANDLE) + sizeof(NV_INDEX) + offset; 1476 // If the data is actually changed, then a write to NV is required 1477 if(_plat__NvIsDifferent(entryAddr, size, data)) 1478 { 1479 // Make sure that NV is available 1480 result = NvIsAvailable(); 1481 if(result != TPM_RC_SUCCESS) 1482 return result; 1483 _plat__NvMemoryWrite(entryAddr, size, data); 1484 g_updateNV = TRUE; 1485 } 1486 } 1487 return TPM_RC_SUCCESS; 1488} 1489// 1490// 1491// NvGetName() 1492// 1493// This function is used to compute the Name of an NV Index. 1494// The name buffer receives the bytes of the Name and the return value is the number of octets in the 1495// Name. 1496// This function requires that the NV Index is defined. 1497// 1498UINT16 1499NvGetName( 1500 TPMI_RH_NV_INDEX handle, // IN: handle of the index 1501 NAME *name // OUT: name of the index 1502 ) 1503{ 1504 UINT16 dataSize, digestSize; 1505 NV_INDEX nvIndex; 1506 BYTE marshalBuffer[sizeof(TPMS_NV_PUBLIC)]; 1507 BYTE *buffer; 1508 INT32 bufferSize; 1509 HASH_STATE hashState; 1510 // Get NV public info 1511 NvGetIndexInfo(handle, &nvIndex); 1512 // Marshal public area 1513 buffer = marshalBuffer; 1514 bufferSize = sizeof(TPMS_NV_PUBLIC); 1515 dataSize = TPMS_NV_PUBLIC_Marshal(&nvIndex.publicArea, &buffer, &bufferSize); 1516 // hash public area 1517 digestSize = CryptStartHash(nvIndex.publicArea.nameAlg, &hashState); 1518 CryptUpdateDigest(&hashState, dataSize, marshalBuffer); 1519 // Complete digest leaving room for the nameAlg 1520 CryptCompleteHash(&hashState, digestSize, &((BYTE *)name)[2]); 1521 // Include the nameAlg 1522 UINT16_TO_BYTE_ARRAY(nvIndex.publicArea.nameAlg, (BYTE *)name); 1523 return digestSize + 2; 1524} 1525// 1526// 1527// NvDefineIndex() 1528// 1529// This function is used to assign NV memory to an NV Index. 1530// 1531// 1532// 1533// Error Returns Meaning 1534// 1535// TPM_RC_NV_SPACE insufficient NV space 1536// 1537TPM_RC 1538NvDefineIndex( 1539 TPMS_NV_PUBLIC *publicArea, // IN: A template for an area to create. 1540 TPM2B_AUTH *authValue // IN: The initial authorization value 1541 ) 1542{ 1543 // The buffer to be written to NV memory 1544 BYTE nvBuffer[sizeof(TPM_HANDLE) + sizeof(NV_INDEX)]; 1545 NV_INDEX *nvIndex; // a pointer to the NV_INDEX data in 1546 // nvBuffer 1547 UINT16 entrySize; // size of entry 1548 entrySize = sizeof(TPM_HANDLE) + sizeof(NV_INDEX) + publicArea->dataSize; 1549 // Check if we have enough space to create the NV Index 1550 // In this implementation, the only resource limitation is the available NV 1551 // space. Other implementation may have other limitation on counter or on 1552 // NV slot 1553 if(!NvTestSpace(entrySize, TRUE)) return TPM_RC_NV_SPACE; 1554 // if the index to be defined is RAM backed, check RAM space availability 1555 // as well 1556 if(publicArea->attributes.TPMA_NV_ORDERLY == SET 1557 && !NvTestRAMSpace(publicArea->dataSize)) 1558 return TPM_RC_NV_SPACE; 1559 // Copy input value to nvBuffer 1560 // Copy handle 1561 memcpy(nvBuffer, &publicArea->nvIndex, sizeof(TPM_HANDLE)); 1562 // Copy NV_INDEX 1563 nvIndex = (NV_INDEX *) (nvBuffer + sizeof(TPM_HANDLE)); 1564 nvIndex->publicArea = *publicArea; 1565 nvIndex->authValue = *authValue; 1566 // Add index to NV memory 1567 NvAdd(entrySize, sizeof(TPM_HANDLE) + sizeof(NV_INDEX), nvBuffer); 1568 // If the data of NV Index is RAM backed, add the data area in RAM as well 1569 if(publicArea->attributes.TPMA_NV_ORDERLY == SET) 1570 NvAddRAM(publicArea->nvIndex, publicArea->dataSize); 1571 return TPM_RC_SUCCESS; 1572} 1573 1574// 1575// 1576// NvMarshalObject() 1577// 1578// This function marshals the passed in OBJECT structure into a buffer. A 1579// pointer to pointer to the buffer and a pointer to the size of the 1580// buffer are passed in for this function to update as appropriate. 1581// 1582// On top of marshaling the object, this function also modifies one of 1583// the object's properties and sets the evictHandle field of the 1584// marshaled object to the requested value. 1585// 1586// Returns 1587// 1588// Marshaled size of the object. 1589// 1590static UINT16 NvMarshalObject(OBJECT *o, TPMI_DH_OBJECT evictHandle, 1591 BYTE **buf, INT32 *size) 1592{ 1593 UINT16 marshaledSize; 1594 OBJECT_ATTRIBUTES stored_attributes; 1595 1596 stored_attributes = o->attributes; 1597 stored_attributes.evict = SET; 1598 marshaledSize = sizeof(stored_attributes); 1599 MemoryCopy(*buf, &stored_attributes, marshaledSize, *size); 1600 *buf += marshaledSize; 1601 *size -= marshaledSize; 1602 1603 marshaledSize += TPMT_PUBLIC_Marshal(&o->publicArea, buf, size); 1604 marshaledSize += TPMT_SENSITIVE_Marshal(&o->sensitive, buf, size); 1605#ifdef TPM_ALG_RSA 1606 marshaledSize += TPM2B_PUBLIC_KEY_RSA_Marshal(&o->privateExponent, 1607 buf, size); 1608#endif 1609 marshaledSize += TPM2B_NAME_Marshal(&o->qualifiedName, buf, size); 1610 1611 // Use the supplied handle instead of the object contents. 1612 marshaledSize += TPMI_DH_OBJECT_Marshal(&evictHandle, buf, size); 1613 marshaledSize += TPM2B_NAME_Marshal(&o->name, buf, size); 1614 1615 return marshaledSize; 1616} 1617 1618// 1619// 1620// NvAddEvictObject() 1621// 1622// This function is used to assign NV memory to a persistent object. 1623// 1624// Error Returns Meaning 1625// 1626// TPM_RC_NV_HANDLE the requested handle is already in use 1627// TPM_RC_NV_SPACE insufficient NV space 1628// 1629TPM_RC 1630NvAddEvictObject( 1631 TPMI_DH_OBJECT evictHandle, // IN: new evict handle 1632// 1633 OBJECT *object // IN: object to be added 1634 ) 1635{ 1636 // The buffer to be written to NV memory 1637 BYTE nvBuffer[sizeof(TPM_HANDLE) + sizeof(OBJECT)]; 1638 UINT16 entrySize; // size of entry 1639 BYTE *marshalSpace; 1640 INT32 marshalRoom; 1641 1642 // evict handle type should match the object hierarchy 1643 pAssert( ( NvIsPlatformPersistentHandle(evictHandle) 1644 && object->attributes.ppsHierarchy == SET) 1645 || ( NvIsOwnerPersistentHandle(evictHandle) 1646 && ( object->attributes.spsHierarchy == SET 1647 || object->attributes.epsHierarchy == SET))); 1648 1649 // Do not attemp storing a duplicate handle. 1650 if(!NvIsUndefinedEvictHandle(evictHandle)) 1651 return TPM_RC_NV_DEFINED; 1652 1653 // Copy handle 1654 entrySize = sizeof(TPM_HANDLE); 1655 memcpy(nvBuffer, &evictHandle, entrySize); 1656 1657 // Let's serialize the object before storing it in NVMEM 1658 marshalSpace = nvBuffer + entrySize; 1659 marshalRoom = sizeof(nvBuffer) - entrySize; 1660 entrySize += NvMarshalObject(object, evictHandle, 1661 &marshalSpace, &marshalRoom); 1662 1663 // Check if we have enough space to add this evict object 1664 if(!NvTestSpace(entrySize, FALSE)) return TPM_RC_NV_SPACE; 1665 1666 // Add evict to NV memory 1667 NvAdd(entrySize, entrySize, nvBuffer); 1668 return TPM_RC_SUCCESS; 1669} 1670// 1671// 1672// NvDeleteEntity() 1673// 1674// This function will delete a NV Index or an evict object. 1675// This function requires that the index/evict object has been defined. 1676// 1677void 1678NvDeleteEntity( 1679 TPM_HANDLE handle // IN: handle of entity to be deleted 1680 ) 1681{ 1682 UINT32 entityAddr; // pointer to entity 1683 entityAddr = NvFindHandle(handle); 1684 pAssert(entityAddr != 0); 1685 if(HandleGetType(handle) == TPM_HT_NV_INDEX) 1686 { 1687 NV_INDEX nvIndex; 1688 // Read the NV Index info 1689 _plat__NvMemoryRead(entityAddr + sizeof(TPM_HANDLE), sizeof(NV_INDEX), 1690 &nvIndex); 1691 // If the entity to be deleted is a counter with the maximum counter 1692 // value, record it in NV memory 1693 if(nvIndex.publicArea.attributes.TPMA_NV_COUNTER == SET 1694 && nvIndex.publicArea.attributes.TPMA_NV_WRITTEN == SET) 1695 { 1696 UINT64 countValue; 1697 UINT64 maxCount; 1698 NvGetIntIndexData(handle, &nvIndex, &countValue); 1699 maxCount = NvReadMaxCount(); 1700 if(countValue > maxCount) 1701 NvWriteMaxCount(countValue); 1702 } 1703 // If the NV Index is RAM back, delete the RAM data as well 1704 if(nvIndex.publicArea.attributes.TPMA_NV_ORDERLY == SET) 1705 NvDeleteRAM(handle); 1706 } 1707 NvDelete(entityAddr); 1708 return; 1709} 1710// 1711// 1712// NvFlushHierarchy() 1713// 1714// This function will delete persistent objects belonging to the indicated If the storage hierarchy is selected, 1715// the function will also delete any NV Index define using ownerAuth. 1716// 1717void 1718NvFlushHierarchy( 1719 TPMI_RH_HIERARCHY hierarchy // IN: hierarchy to be flushed. 1720 ) 1721{ 1722 NV_ITER iter = NV_ITER_INIT; 1723 UINT32 currentAddr; 1724 while((currentAddr = NvNext(&iter)) != 0) 1725 { 1726 TPM_HANDLE entityHandle; 1727 // Read handle information. 1728 _plat__NvMemoryRead(currentAddr, sizeof(TPM_HANDLE), &entityHandle); 1729 if(HandleGetType(entityHandle) == TPM_HT_NV_INDEX) 1730 { 1731 // Handle NV Index 1732 NV_INDEX nvIndex; 1733 // If flush endorsement or platform hierarchy, no NV Index would be 1734 // flushed 1735 if(hierarchy == TPM_RH_ENDORSEMENT || hierarchy == TPM_RH_PLATFORM) 1736 continue; 1737 _plat__NvMemoryRead(currentAddr + sizeof(TPM_HANDLE), 1738 sizeof(NV_INDEX), &nvIndex); 1739 // For storage hierarchy, flush OwnerCreated index 1740 if( nvIndex.publicArea.attributes.TPMA_NV_PLATFORMCREATE == CLEAR) 1741 { 1742 // Delete the NV Index 1743 NvDelete(currentAddr); 1744 // Re-iterate from beginning after a delete 1745 iter = NV_ITER_INIT; 1746 // If the NV Index is RAM back, delete the RAM data as well 1747 if(nvIndex.publicArea.attributes.TPMA_NV_ORDERLY == SET) 1748 NvDeleteRAM(entityHandle); 1749 } 1750 } 1751 else if(HandleGetType(entityHandle) == TPM_HT_PERSISTENT) 1752 { 1753 OBJECT object; 1754 // Get evict object 1755 NvGetEvictObject(entityHandle, &object); 1756 // If the evict object belongs to the hierarchy to be flushed 1757 if( ( hierarchy == TPM_RH_PLATFORM 1758 && object.attributes.ppsHierarchy == SET) 1759 || ( hierarchy == TPM_RH_OWNER 1760 && object.attributes.spsHierarchy == SET) 1761 || ( hierarchy == TPM_RH_ENDORSEMENT 1762 && object.attributes.epsHierarchy == SET) 1763 ) 1764 { 1765 // Delete the evict object 1766 NvDelete(currentAddr); 1767 // Re-iterate from beginning after a delete 1768 iter = NV_ITER_INIT; 1769 } 1770 } 1771 else 1772 { 1773 pAssert(FALSE); 1774 } 1775 } 1776 return; 1777} 1778// 1779// 1780// NvSetGlobalLock() 1781// 1782// This function is used to SET the TPMA_NV_WRITELOCKED attribute for all NV Indices that have 1783// TPMA_NV_GLOBALLOCK SET. This function is use by TPM2_NV_GlobalWriteLock(). 1784// 1785void 1786NvSetGlobalLock( 1787 void 1788 ) 1789{ 1790 NV_ITER iter = NV_ITER_INIT; 1791 UINT32 currentAddr; 1792 // Check all Indices 1793 while((currentAddr = NvNextIndex(&iter)) != 0) 1794 { 1795 NV_INDEX nvIndex; 1796 // Read the index data 1797 _plat__NvMemoryRead(currentAddr + sizeof(TPM_HANDLE), 1798 sizeof(NV_INDEX), &nvIndex); 1799 // See if it should be locked 1800 if(nvIndex.publicArea.attributes.TPMA_NV_GLOBALLOCK == SET) 1801 { 1802 // if so, lock it 1803 nvIndex.publicArea.attributes.TPMA_NV_WRITELOCKED = SET; 1804 _plat__NvMemoryWrite(currentAddr + sizeof(TPM_HANDLE), 1805 sizeof(NV_INDEX), &nvIndex); 1806 // Set the flag that a NV write happens 1807 g_updateNV = TRUE; 1808 } 1809 } 1810 return; 1811} 1812// 1813// 1814// InsertSort() 1815// 1816// Sort a handle into handle list in ascending order. The total handle number in the list should not exceed 1817// MAX_CAP_HANDLES 1818// 1819static void 1820InsertSort( 1821 TPML_HANDLE *handleList, // IN/OUT: sorted handle list 1822 UINT32 count, // IN: maximum count in the handle list 1823 TPM_HANDLE entityHandle // IN: handle to be inserted 1824 ) 1825{ 1826 UINT32 i, j; 1827 UINT32 originalCount; 1828 // For a corner case that the maximum count is 0, do nothing 1829 if(count == 0) return; 1830 // For empty list, add the handle at the beginning and return 1831 if(handleList->count == 0) 1832 { 1833 handleList->handle[0] = entityHandle; 1834 handleList->count++; 1835 return; 1836 } 1837 // Check if the maximum of the list has been reached 1838 originalCount = handleList->count; 1839 if(originalCount < count) 1840 handleList->count++; 1841 // Insert the handle to the list 1842 for(i = 0; i < originalCount; i++) 1843 { 1844 if(handleList->handle[i] > entityHandle) 1845 { 1846 for(j = handleList->count - 1; j > i; j--) 1847 { 1848 handleList->handle[j] = handleList->handle[j-1]; 1849 } 1850 break; 1851 } 1852 } 1853 // If a slot was found, insert the handle in this position 1854 if(i < originalCount || handleList->count > originalCount) 1855 handleList->handle[i] = entityHandle; 1856 return; 1857} 1858// 1859// 1860// NvCapGetPersistent() 1861// 1862// This function is used to get a list of handles of the persistent objects, starting at handle. 1863// Handle must be in valid persistent object handle range, but does not have to reference an existing 1864// persistent object. 1865// 1866// Return Value Meaning 1867// 1868// YES if there are more handles available 1869// NO all the available handles has been returned 1870// 1871TPMI_YES_NO 1872NvCapGetPersistent( 1873 TPMI_DH_OBJECT handle, // IN: start handle 1874 UINT32 count, // IN: maximum number of returned handle 1875 TPML_HANDLE *handleList // OUT: list of handle 1876 ) 1877{ 1878 TPMI_YES_NO more = NO; 1879 NV_ITER iter = NV_ITER_INIT; 1880 UINT32 currentAddr; 1881 pAssert(HandleGetType(handle) == TPM_HT_PERSISTENT); 1882 // Initialize output handle list 1883 handleList->count = 0; 1884 // The maximum count of handles we may return is MAX_CAP_HANDLES 1885 if(count > MAX_CAP_HANDLES) count = MAX_CAP_HANDLES; 1886 while((currentAddr = NvNextEvict(&iter)) != 0) 1887 { 1888 TPM_HANDLE entityHandle; 1889 // Read handle information. 1890 _plat__NvMemoryRead(currentAddr, sizeof(TPM_HANDLE), &entityHandle); 1891 // Ignore persistent handles that have values less than the input handle 1892 if(entityHandle < handle) 1893 continue; 1894 // if the handles in the list have reached the requested count, and there 1895 // are still handles need to be inserted, indicate that there are more. 1896 if(handleList->count == count) 1897 more = YES; 1898 // A handle with a value larger than start handle is a candidate 1899 // for return. Insert sort it to the return list. Insert sort algorithm 1900 // is chosen here for simplicity based on the assumption that the total 1901 // number of NV Indices is small. For an implementation that may allow 1902 // large number of NV Indices, a more efficient sorting algorithm may be 1903 // used here. 1904 InsertSort(handleList, count, entityHandle); 1905// 1906 } 1907 return more; 1908} 1909// 1910// 1911// NvCapGetIndex() 1912// 1913// This function returns a list of handles of NV Indices, starting from handle. Handle must be in the range of 1914// NV Indices, but does not have to reference an existing NV Index. 1915// 1916// Return Value Meaning 1917// 1918// YES if there are more handles to report 1919// NO all the available handles has been reported 1920// 1921TPMI_YES_NO 1922NvCapGetIndex( 1923 TPMI_DH_OBJECT handle, // IN: start handle 1924 UINT32 count, // IN: maximum number of returned handle 1925 TPML_HANDLE *handleList // OUT: list of handle 1926 ) 1927{ 1928 TPMI_YES_NO more = NO; 1929 NV_ITER iter = NV_ITER_INIT; 1930 UINT32 currentAddr; 1931 pAssert(HandleGetType(handle) == TPM_HT_NV_INDEX); 1932 // Initialize output handle list 1933 handleList->count = 0; 1934 // The maximum count of handles we may return is MAX_CAP_HANDLES 1935 if(count > MAX_CAP_HANDLES) count = MAX_CAP_HANDLES; 1936 while((currentAddr = NvNextIndex(&iter)) != 0) 1937 { 1938 TPM_HANDLE entityHandle; 1939 // Read handle information. 1940 _plat__NvMemoryRead(currentAddr, sizeof(TPM_HANDLE), &entityHandle); 1941 // Ignore index handles that have values less than the 'handle' 1942 if(entityHandle < handle) 1943 continue; 1944 // if the count of handles in the list has reached the requested count, 1945 // and there are still handles to report, set more. 1946 if(handleList->count == count) 1947 more = YES; 1948 // A handle with a value larger than start handle is a candidate 1949 // for return. Insert sort it to the return list. Insert sort algorithm 1950 // is chosen here for simplicity based on the assumption that the total 1951 // number of NV Indices is small. For an implementation that may allow 1952 // large number of NV Indices, a more efficient sorting algorithm may be 1953 // used here. 1954 InsertSort(handleList, count, entityHandle); 1955 } 1956 return more; 1957} 1958// 1959// 1960// 1961// NvCapGetIndexNumber() 1962// 1963// This function returns the count of NV Indexes currently defined. 1964// 1965UINT32 1966NvCapGetIndexNumber( 1967 void 1968 ) 1969{ 1970 UINT32 num = 0; 1971 NV_ITER iter = NV_ITER_INIT; 1972 while(NvNextIndex(&iter) != 0) num++; 1973 return num; 1974} 1975// 1976// 1977// NvCapGetPersistentNumber() 1978// 1979// Function returns the count of persistent objects currently in NV memory. 1980// 1981UINT32 1982NvCapGetPersistentNumber( 1983 void 1984 ) 1985{ 1986 UINT32 num = 0; 1987 NV_ITER iter = NV_ITER_INIT; 1988 while(NvNextEvict(&iter) != 0) num++; 1989 return num; 1990} 1991// 1992// 1993// NvCapGetPersistentAvail() 1994// 1995// This function returns an estimate of the number of additional persistent objects that could be loaded into 1996// NV memory. 1997// 1998UINT32 1999NvCapGetPersistentAvail( 2000 void 2001 ) 2002{ 2003 UINT32 availSpace; 2004 UINT32 objectSpace; 2005 // Compute the available space in NV storage 2006 availSpace = NvGetFreeByte(); 2007 // Get the space needed to add a persistent object to NV storage 2008 objectSpace = NvGetEvictObjectSize(); 2009 return availSpace / objectSpace; 2010} 2011// 2012// 2013// NvCapGetCounterNumber() 2014// 2015// Get the number of defined NV Indexes that have NV TPMA_NV_COUNTER attribute SET. 2016// 2017// 2018UINT32 2019NvCapGetCounterNumber( 2020 void 2021 ) 2022{ 2023 NV_ITER iter = NV_ITER_INIT; 2024 UINT32 currentAddr; 2025 UINT32 num = 0; 2026 while((currentAddr = NvNextIndex(&iter)) != 0) 2027 { 2028 NV_INDEX nvIndex; 2029 // Get NV Index info 2030 _plat__NvMemoryRead(currentAddr + sizeof(TPM_HANDLE), 2031 sizeof(NV_INDEX), &nvIndex); 2032 if(nvIndex.publicArea.attributes.TPMA_NV_COUNTER == SET) num++; 2033 } 2034 return num; 2035} 2036// 2037// 2038// NvCapGetCounterAvail() 2039// 2040// This function returns an estimate of the number of additional counter type NV Indices that can be defined. 2041// 2042UINT32 2043NvCapGetCounterAvail( 2044 void 2045 ) 2046{ 2047 UINT32 availNVSpace; 2048 UINT32 availRAMSpace; 2049 UINT32 counterNVSpace; 2050 UINT32 counterRAMSpace; 2051 UINT32 persistentNum = NvCapGetPersistentNumber(); 2052 // Get the available space in NV storage 2053 availNVSpace = NvGetFreeByte(); 2054 if (persistentNum < MIN_EVICT_OBJECTS) 2055 { 2056 // Some space have to be reserved for evict object. Adjust availNVSpace. 2057 UINT32 reserved = (MIN_EVICT_OBJECTS - persistentNum) 2058 * NvGetEvictObjectSize(); 2059 if (reserved > availNVSpace) 2060 availNVSpace = 0; 2061 else 2062 availNVSpace -= reserved; 2063 } 2064 // Get the space needed to add a counter index to NV storage 2065 counterNVSpace = NvGetCounterSize(); 2066 // Compute the available space in RAM 2067 availRAMSpace = RAM_INDEX_SPACE - s_ramIndexSize; 2068 // Compute the space needed to add a counter index to RAM storage 2069 // It takes an size field, a handle and sizeof(UINT64) for counter data 2070 counterRAMSpace = sizeof(UINT32) + sizeof(TPM_HANDLE) + sizeof(UINT64); 2071 // Return the min of counter number in NV and in RAM 2072 if(availNVSpace / counterNVSpace > availRAMSpace / counterRAMSpace) 2073 return availRAMSpace / counterRAMSpace; 2074 else 2075 return availNVSpace / counterNVSpace; 2076} 2077