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 if(gc.shEnable == FALSE) 1049 return TPM_RC_HANDLE; 1050 } 1051 // if phEnableNV is CLEAR, a platform created Index should not 1052 // be visible 1053 else if(gc.phEnableNV == FALSE) 1054 return TPM_RC_HANDLE; 1055 } 1056 // If the Index is write locked and this is an NV Write operation... 1057 if( nvIndex.publicArea.attributes.TPMA_NV_WRITELOCKED 1058 && IsWriteOperation(commandCode)) 1059 { 1060 // then return a locked indication unless the command is TPM2_NV_WriteLock 1061 if(commandCode != TPM_CC_NV_WriteLock) 1062 return TPM_RC_NV_LOCKED; 1063 return TPM_RC_SUCCESS; 1064 } 1065 // If the Index is read locked and this is an NV Read operation... 1066 if( nvIndex.publicArea.attributes.TPMA_NV_READLOCKED 1067 && IsReadOperation(commandCode)) 1068 { 1069 // then return a locked indication unless the command is TPM2_NV_ReadLock 1070 if(commandCode != TPM_CC_NV_ReadLock) 1071 return TPM_RC_NV_LOCKED; 1072 return TPM_RC_SUCCESS; 1073 } 1074 // NV Index is accessible 1075 return TPM_RC_SUCCESS; 1076} 1077// 1078// 1079// NvIsUndefinedEvictHandle() 1080// 1081// This function indicates if a handle does not reference an existing persistent object. This function requires 1082// that the handle be in the proper range for persistent objects. 1083// 1084// Return Value Meaning 1085// 1086// TRUE handle does not reference an existing persistent object 1087// FALSE handle does reference an existing persistent object 1088// 1089static BOOL 1090NvIsUndefinedEvictHandle( 1091 TPM_HANDLE handle // IN: handle 1092 ) 1093{ 1094 UINT32 entityAddr; // offset points to the entity 1095 pAssert(HandleGetType(handle) == TPM_HT_PERSISTENT); 1096 // Find the address of evict object 1097 entityAddr = NvFindHandle(handle); 1098 // If handle is not found, return TRUE 1099 if(entityAddr == 0) 1100 return TRUE; 1101 else 1102 return FALSE; 1103} 1104 1105// 1106// 1107// NvUnmarshalObject() 1108// 1109// This function accepts a buffer containing a marshaled OBJECT 1110// structure, a pointer to the area where the input data should be 1111// unmarshaled, and a pointer to the size of the output area. 1112// 1113// No error checking is performed, unmarshaled data is guaranteed not to 1114// spill over the allocated space. 1115// 1116static TPM_RC NvUnmarshalObject(OBJECT *o, BYTE **buf, INT32 *size) 1117{ 1118 TPM_RC result; 1119 1120 // There is no generated function to unmarshal the attributes field, do it 1121 // by hand. 1122 MemoryCopy(&o->attributes, *buf, sizeof(o->attributes), *size); 1123 *buf += sizeof(o->attributes); 1124 *size -= sizeof(o->attributes); 1125 1126 result = TPMT_PUBLIC_Unmarshal(&o->publicArea, buf, size); 1127 if (result != TPM_RC_SUCCESS) 1128 return result; 1129 1130 result = TPMT_SENSITIVE_Unmarshal(&o->sensitive, buf, size); 1131 if (result != TPM_RC_SUCCESS) 1132 return result; 1133 1134#ifdef TPM_ALG_RSA 1135 result = TPM2B_PUBLIC_KEY_RSA_Unmarshal(&o->privateExponent, buf, size); 1136 if (result != TPM_RC_SUCCESS) 1137 return result; 1138#endif 1139 1140 result = TPM2B_NAME_Unmarshal(&o->qualifiedName, buf, size); 1141 if (result != TPM_RC_SUCCESS) 1142 return result; 1143 1144 result = TPMI_DH_OBJECT_Unmarshal(&o->evictHandle, buf, size, TRUE); 1145 if (result != TPM_RC_SUCCESS) 1146 return result; 1147 1148 return TPM2B_NAME_Unmarshal(&o->name, buf, size); 1149} 1150 1151// 1152// 1153// NvGetEvictObject() 1154// 1155// This function is used to dereference an evict object handle and get a pointer to the object. 1156// 1157// Error Returns Meaning 1158// 1159// TPM_RC_HANDLE the handle does not point to an existing persistent object 1160// 1161TPM_RC 1162NvGetEvictObject( 1163 TPM_HANDLE handle, // IN: handle 1164 OBJECT *object // OUT: object data 1165 ) 1166{ 1167 UINT32 entityAddr; // offset points to the entity 1168 TPM_RC result = TPM_RC_SUCCESS; 1169 pAssert(HandleGetType(handle) == TPM_HT_PERSISTENT); 1170 // Find the address of evict object 1171 entityAddr = NvFindHandle(handle); 1172 // If handle is not found, return an error 1173 if(entityAddr == 0) { 1174 result = TPM_RC_HANDLE; 1175 } else { 1176 UINT32 storedSize; 1177 UINT32 nextEntryAddr; 1178 1179 // Let's calculate the size of object as stored in NVMEM. 1180 _plat__NvMemoryRead(entityAddr - sizeof(UINT32), 1181 sizeof(UINT32), &nextEntryAddr); 1182 1183 storedSize = nextEntryAddr - entityAddr; 1184 1185 if (storedSize == (sizeof(TPM_HANDLE) + sizeof(OBJECT))) { 1186 // Read evict object stored unmarshaled. 1187 _plat__NvMemoryRead(entityAddr + sizeof(TPM_HANDLE), 1188 sizeof(OBJECT), 1189 object); 1190 } else { 1191 // Must be stored marshaled, let's unmarshal it. 1192 BYTE marshaled[sizeof(OBJECT)]; 1193 INT32 max_size = sizeof(marshaled); 1194 BYTE *marshaledPtr = marshaled; 1195 1196 _plat__NvMemoryRead(entityAddr + sizeof(TPM_HANDLE), 1197 storedSize, marshaled); 1198 result = NvUnmarshalObject(object, &marshaledPtr, &max_size); 1199 } 1200 } 1201 // whether there is an error or not, make sure that the evict 1202 // status of the object is set so that the slot will get freed on exit 1203 object->attributes.evict = SET; 1204 return result; 1205} 1206// 1207// 1208// NvGetIndexInfo() 1209// 1210// This function is used to retrieve the contents of an NV Index. 1211// An implementation is allowed to save the NV Index in a vendor-defined format. If the format is different 1212// from the default used by the reference code, then this function would be changed to reformat the data into 1213// the default format. 1214// A prerequisite to calling this function is that the handle must be known to reference a defined NV Index. 1215// 1216void 1217NvGetIndexInfo( 1218 TPMI_RH_NV_INDEX handle, // IN: handle 1219 NV_INDEX *nvIndex // OUT: NV index structure 1220 ) 1221{ 1222 UINT32 entityAddr; // offset points to the entity 1223 pAssert(HandleGetType(handle) == TPM_HT_NV_INDEX); 1224 // Find the address of NV index 1225 entityAddr = NvFindHandle(handle); 1226 pAssert(entityAddr != 0); 1227 // This implementation uses the default format so just 1228 // read the data in 1229 _plat__NvMemoryRead(entityAddr + sizeof(TPM_HANDLE), sizeof(NV_INDEX), 1230 nvIndex); 1231 return; 1232} 1233// 1234// 1235// NvInitialCounter() 1236// 1237// This function returns the value to be used when a counter index is initialized. It will scan the NV counters 1238// and find the highest value in any active counter. It will use that value as the starting point. If there are no 1239// active counters, it will use the value of the previous largest counter. 1240// 1241UINT64 1242NvInitialCounter( 1243 void 1244 ) 1245{ 1246 UINT64 maxCount; 1247 NV_ITER iter = NV_ITER_INIT; 1248 UINT32 currentAddr; 1249 // Read the maxCount value 1250 maxCount = NvReadMaxCount(); 1251 // Iterate all existing counters 1252 while((currentAddr = NvNextIndex(&iter)) != 0) 1253 { 1254 TPMI_RH_NV_INDEX nvHandle; 1255 NV_INDEX nvIndex; 1256 // Read NV handle 1257 _plat__NvMemoryRead(currentAddr, sizeof(TPM_HANDLE), &nvHandle); 1258 // Get NV Index 1259 NvGetIndexInfo(nvHandle, &nvIndex); 1260 if( nvIndex.publicArea.attributes.TPMA_NV_COUNTER == SET 1261 && nvIndex.publicArea.attributes.TPMA_NV_WRITTEN == SET) 1262 { 1263 UINT64 countValue; 1264 // Read counter value 1265 NvGetIntIndexData(nvHandle, &nvIndex, &countValue); 1266 if(countValue > maxCount) 1267 maxCount = countValue; 1268 } 1269 } 1270 // Initialize the new counter value to be maxCount + 1 1271 // A counter is only initialized the first time it is written. The 1272 // way to write a counter is with TPM2_NV_INCREMENT(). Since the 1273 // "initial" value of a defined counter is the largest count value that 1274 // may have existed in this index previously, then the first use would 1275 // add one to that value. 1276 return maxCount; 1277} 1278// 1279// 1280// NvGetIndexData() 1281// 1282// This function is used to access the data in an NV Index. The data is returned as a byte sequence. Since 1283// counter values are kept in native format, they are converted to canonical form before being returned. 1284// Family "2.0" TCG Published Page 139 1285// Level 00 Revision 01.16 Copyright © TCG 2006-2014 October 30, 2014 1286// Trusted Platform Module Library Part 4: Supporting Routines 1287// 1288// 1289// This function requires that the NV Index be defined, and that the required data is within the data range. It 1290// also requires that TPMA_NV_WRITTEN of the Index is SET. 1291// 1292void 1293NvGetIndexData( 1294 TPMI_RH_NV_INDEX handle, // IN: handle 1295 NV_INDEX *nvIndex, // IN: RAM image of index header 1296 UINT32 offset, // IN: offset of NV data 1297 UINT16 size, // IN: size of NV data 1298 void *data // OUT: data buffer 1299 ) 1300{ 1301 pAssert(nvIndex->publicArea.attributes.TPMA_NV_WRITTEN == SET); 1302 if( nvIndex->publicArea.attributes.TPMA_NV_BITS == SET 1303 || nvIndex->publicArea.attributes.TPMA_NV_COUNTER == SET) 1304 { 1305 // Read bit or counter data in canonical form 1306 UINT64 dataInInt; 1307 NvGetIntIndexData(handle, nvIndex, &dataInInt); 1308 UINT64_TO_BYTE_ARRAY(dataInInt, (BYTE *)data); 1309 } 1310 else 1311 { 1312 if(nvIndex->publicArea.attributes.TPMA_NV_ORDERLY == SET) 1313 { 1314 UINT32 ramAddr; 1315 // Get data from RAM buffer 1316 ramAddr = NvGetRAMIndexOffset(handle); 1317 MemoryCopy(data, s_ramIndex + ramAddr + offset, size, size); 1318 } 1319 else 1320 { 1321 UINT32 entityAddr; 1322 entityAddr = NvFindHandle(handle); 1323 // Get data from NV 1324 // Skip NV Index info, read data buffer 1325 entityAddr += sizeof(TPM_HANDLE) + sizeof(NV_INDEX) + offset; 1326 // Read the data 1327 _plat__NvMemoryRead(entityAddr, size, data); 1328 } 1329 } 1330 return; 1331} 1332// 1333// 1334// NvGetIntIndexData() 1335// 1336// Get data in integer format of a bit or counter NV Index. 1337// This function requires that the NV Index is defined and that the NV Index previously has been written. 1338// 1339void 1340NvGetIntIndexData( 1341 TPMI_RH_NV_INDEX handle, // IN: handle 1342 NV_INDEX *nvIndex, // IN: RAM image of NV Index header 1343 UINT64 *data // IN: UINT64 pointer for counter or bit 1344 ) 1345{ 1346 // Validate that index has been written and is the right type 1347 pAssert( nvIndex->publicArea.attributes.TPMA_NV_WRITTEN == SET 1348 && ( nvIndex->publicArea.attributes.TPMA_NV_BITS == SET 1349 || nvIndex->publicArea.attributes.TPMA_NV_COUNTER == SET 1350 ) 1351 ); 1352 // bit and counter value is store in native format for TPM CPU. So we directly 1353 // copy the contents of NV to output data buffer 1354 if(nvIndex->publicArea.attributes.TPMA_NV_ORDERLY == SET) 1355 { 1356 UINT32 ramAddr; 1357 // Get data from RAM buffer 1358 ramAddr = NvGetRAMIndexOffset(handle); 1359 MemoryCopy(data, s_ramIndex + ramAddr, sizeof(*data), sizeof(*data)); 1360 } 1361 else 1362 { 1363 UINT32 entityAddr; 1364 entityAddr = NvFindHandle(handle); 1365 // Get data from NV 1366 // Skip NV Index info, read data buffer 1367 _plat__NvMemoryRead( 1368 entityAddr + sizeof(TPM_HANDLE) + sizeof(NV_INDEX), 1369 sizeof(UINT64), data); 1370 } 1371 return; 1372} 1373// 1374// 1375// NvWriteIndexInfo() 1376// 1377// This function is called to queue the write of NV Index data to persistent memory. 1378// This function requires that NV Index is defined. 1379// 1380// Error Returns Meaning 1381// 1382// TPM_RC_NV_RATE NV is rate limiting so retry 1383// TPM_RC_NV_UNAVAILABLE NV is not available 1384// 1385TPM_RC 1386NvWriteIndexInfo( 1387 TPMI_RH_NV_INDEX handle, // IN: handle 1388 NV_INDEX *nvIndex // IN: NV Index info to be written 1389 ) 1390{ 1391 UINT32 entryAddr; 1392 TPM_RC result; 1393 // Get the starting offset for the index in the RAM image of NV 1394 entryAddr = NvFindHandle(handle); 1395 pAssert(entryAddr != 0); 1396 // Step over the link value 1397 entryAddr = entryAddr + sizeof(TPM_HANDLE); 1398 // If the index data is actually changed, then a write to NV is required 1399 if(_plat__NvIsDifferent(entryAddr, sizeof(NV_INDEX),nvIndex)) 1400 { 1401 // Make sure that NV is available 1402 result = NvIsAvailable(); 1403 if(result != TPM_RC_SUCCESS) 1404 return result; 1405 _plat__NvMemoryWrite(entryAddr, sizeof(NV_INDEX), nvIndex); 1406 g_updateNV = TRUE; 1407 } 1408 return TPM_RC_SUCCESS; 1409} 1410// 1411// 1412// NvWriteIndexData() 1413// 1414// This function is used to write NV index data. 1415// This function requires that the NV Index is defined, and the data is within the defined data range for the 1416// index. 1417// 1418// Error Returns Meaning 1419// 1420// TPM_RC_NV_RATE NV is rate limiting so retry 1421// TPM_RC_NV_UNAVAILABLE NV is not available 1422// 1423TPM_RC 1424NvWriteIndexData( 1425 TPMI_RH_NV_INDEX handle, // IN: handle 1426 NV_INDEX *nvIndex, // IN: RAM copy of NV Index 1427 UINT32 offset, // IN: offset of NV data 1428 UINT32 size, // IN: size of NV data 1429 void *data // OUT: data buffer 1430 ) 1431{ 1432 TPM_RC result; 1433 // Validate that write falls within range of the index 1434 pAssert(nvIndex->publicArea.dataSize >= offset + size); 1435 // Update TPMA_NV_WRITTEN bit if necessary 1436 if(nvIndex->publicArea.attributes.TPMA_NV_WRITTEN == CLEAR) 1437 { 1438 nvIndex->publicArea.attributes.TPMA_NV_WRITTEN = SET; 1439 result = NvWriteIndexInfo(handle, nvIndex); 1440 if(result != TPM_RC_SUCCESS) 1441 return result; 1442 } 1443 // Check to see if process for an orderly index is required. 1444 if(nvIndex->publicArea.attributes.TPMA_NV_ORDERLY == SET) 1445 { 1446 UINT32 ramAddr; 1447 // Write data to RAM buffer 1448 ramAddr = NvGetRAMIndexOffset(handle); 1449 MemoryCopy(s_ramIndex + ramAddr + offset, data, size, 1450 sizeof(s_ramIndex) - ramAddr - offset); 1451 // NV update does not happen for orderly index. Have 1452 // to clear orderlyState to reflect that we have changed the 1453 // NV and an orderly shutdown is required. Only going to do this if we 1454 // are not processing a counter that has just rolled over 1455 if(g_updateNV == FALSE) 1456 g_clearOrderly = TRUE; 1457 } 1458 // Need to process this part if the Index isn't orderly or if it is 1459 // an orderly counter that just rolled over. 1460 if(g_updateNV || nvIndex->publicArea.attributes.TPMA_NV_ORDERLY == CLEAR) 1461 { 1462 // Processing for an index with TPMA_NV_ORDERLY CLEAR 1463 UINT32 entryAddr = NvFindHandle(handle); 1464 pAssert(entryAddr != 0); 1465// 1466 // Offset into the index to the first byte of the data to be written 1467 entryAddr += sizeof(TPM_HANDLE) + sizeof(NV_INDEX) + offset; 1468 // If the data is actually changed, then a write to NV is required 1469 if(_plat__NvIsDifferent(entryAddr, size, data)) 1470 { 1471 // Make sure that NV is available 1472 result = NvIsAvailable(); 1473 if(result != TPM_RC_SUCCESS) 1474 return result; 1475 _plat__NvMemoryWrite(entryAddr, size, data); 1476 g_updateNV = TRUE; 1477 } 1478 } 1479 return TPM_RC_SUCCESS; 1480} 1481// 1482// 1483// NvGetName() 1484// 1485// This function is used to compute the Name of an NV Index. 1486// The name buffer receives the bytes of the Name and the return value is the number of octets in the 1487// Name. 1488// This function requires that the NV Index is defined. 1489// 1490UINT16 1491NvGetName( 1492 TPMI_RH_NV_INDEX handle, // IN: handle of the index 1493 NAME *name // OUT: name of the index 1494 ) 1495{ 1496 UINT16 dataSize, digestSize; 1497 NV_INDEX nvIndex; 1498 BYTE marshalBuffer[sizeof(TPMS_NV_PUBLIC)]; 1499 BYTE *buffer; 1500 INT32 bufferSize; 1501 HASH_STATE hashState; 1502 // Get NV public info 1503 NvGetIndexInfo(handle, &nvIndex); 1504 // Marshal public area 1505 buffer = marshalBuffer; 1506 bufferSize = sizeof(TPMS_NV_PUBLIC); 1507 dataSize = TPMS_NV_PUBLIC_Marshal(&nvIndex.publicArea, &buffer, &bufferSize); 1508 // hash public area 1509 digestSize = CryptStartHash(nvIndex.publicArea.nameAlg, &hashState); 1510 CryptUpdateDigest(&hashState, dataSize, marshalBuffer); 1511 // Complete digest leaving room for the nameAlg 1512 CryptCompleteHash(&hashState, digestSize, &((BYTE *)name)[2]); 1513 // Include the nameAlg 1514 UINT16_TO_BYTE_ARRAY(nvIndex.publicArea.nameAlg, (BYTE *)name); 1515 return digestSize + 2; 1516} 1517// 1518// 1519// NvDefineIndex() 1520// 1521// This function is used to assign NV memory to an NV Index. 1522// 1523// 1524// 1525// Error Returns Meaning 1526// 1527// TPM_RC_NV_SPACE insufficient NV space 1528// 1529TPM_RC 1530NvDefineIndex( 1531 TPMS_NV_PUBLIC *publicArea, // IN: A template for an area to create. 1532 TPM2B_AUTH *authValue // IN: The initial authorization value 1533 ) 1534{ 1535 // The buffer to be written to NV memory 1536 BYTE nvBuffer[sizeof(TPM_HANDLE) + sizeof(NV_INDEX)]; 1537 NV_INDEX *nvIndex; // a pointer to the NV_INDEX data in 1538 // nvBuffer 1539 UINT16 entrySize; // size of entry 1540 entrySize = sizeof(TPM_HANDLE) + sizeof(NV_INDEX) + publicArea->dataSize; 1541 // Check if we have enough space to create the NV Index 1542 // In this implementation, the only resource limitation is the available NV 1543 // space. Other implementation may have other limitation on counter or on 1544 // NV slot 1545 if(!NvTestSpace(entrySize, TRUE)) return TPM_RC_NV_SPACE; 1546 // if the index to be defined is RAM backed, check RAM space availability 1547 // as well 1548 if(publicArea->attributes.TPMA_NV_ORDERLY == SET 1549 && !NvTestRAMSpace(publicArea->dataSize)) 1550 return TPM_RC_NV_SPACE; 1551 // Copy input value to nvBuffer 1552 // Copy handle 1553 memcpy(nvBuffer, &publicArea->nvIndex, sizeof(TPM_HANDLE)); 1554 // Copy NV_INDEX 1555 nvIndex = (NV_INDEX *) (nvBuffer + sizeof(TPM_HANDLE)); 1556 nvIndex->publicArea = *publicArea; 1557 nvIndex->authValue = *authValue; 1558 // Add index to NV memory 1559 NvAdd(entrySize, sizeof(TPM_HANDLE) + sizeof(NV_INDEX), nvBuffer); 1560 // If the data of NV Index is RAM backed, add the data area in RAM as well 1561 if(publicArea->attributes.TPMA_NV_ORDERLY == SET) 1562 NvAddRAM(publicArea->nvIndex, publicArea->dataSize); 1563 return TPM_RC_SUCCESS; 1564} 1565 1566// 1567// 1568// NvMarshalObject() 1569// 1570// This function marshals the passed in OBJECT structure into a buffer. A 1571// pointer to pointer to the buffer and a pointer to the size of the 1572// buffer are passed in for this function to update as appropriate. 1573// 1574// On top of marshaling the object, this function also modifies one of 1575// the object's properties and sets the evictHandle field of the 1576// marshaled object to the requested value. 1577// 1578// Returns 1579// 1580// Marshaled size of the object. 1581// 1582static UINT16 NvMarshalObject(OBJECT *o, TPMI_DH_OBJECT evictHandle, 1583 BYTE **buf, INT32 *size) 1584{ 1585 UINT16 marshaledSize; 1586 OBJECT_ATTRIBUTES stored_attributes; 1587 1588 stored_attributes = o->attributes; 1589 stored_attributes.evict = SET; 1590 marshaledSize = sizeof(stored_attributes); 1591 MemoryCopy(*buf, &stored_attributes, marshaledSize, *size); 1592 *buf += marshaledSize; 1593 *size -= marshaledSize; 1594 1595 marshaledSize += TPMT_PUBLIC_Marshal(&o->publicArea, buf, size); 1596 marshaledSize += TPMT_SENSITIVE_Marshal(&o->sensitive, buf, size); 1597#ifdef TPM_ALG_RSA 1598 marshaledSize += TPM2B_PUBLIC_KEY_RSA_Marshal(&o->privateExponent, 1599 buf, size); 1600#endif 1601 marshaledSize += TPM2B_NAME_Marshal(&o->qualifiedName, buf, size); 1602 1603 // Use the supplied handle instead of the object contents. 1604 marshaledSize += TPMI_DH_OBJECT_Marshal(&evictHandle, buf, size); 1605 marshaledSize += TPM2B_NAME_Marshal(&o->name, buf, size); 1606 1607 return marshaledSize; 1608} 1609 1610// 1611// 1612// NvAddEvictObject() 1613// 1614// This function is used to assign NV memory to a persistent object. 1615// 1616// Error Returns Meaning 1617// 1618// TPM_RC_NV_HANDLE the requested handle is already in use 1619// TPM_RC_NV_SPACE insufficient NV space 1620// 1621TPM_RC 1622NvAddEvictObject( 1623 TPMI_DH_OBJECT evictHandle, // IN: new evict handle 1624// 1625 OBJECT *object // IN: object to be added 1626 ) 1627{ 1628 // The buffer to be written to NV memory 1629 BYTE nvBuffer[sizeof(TPM_HANDLE) + sizeof(OBJECT)]; 1630 UINT16 entrySize; // size of entry 1631 BYTE *marshalSpace; 1632 INT32 marshalRoom; 1633 1634 // evict handle type should match the object hierarchy 1635 pAssert( ( NvIsPlatformPersistentHandle(evictHandle) 1636 && object->attributes.ppsHierarchy == SET) 1637 || ( NvIsOwnerPersistentHandle(evictHandle) 1638 && ( object->attributes.spsHierarchy == SET 1639 || object->attributes.epsHierarchy == SET))); 1640 1641 // Do not attemp storing a duplicate handle. 1642 if(!NvIsUndefinedEvictHandle(evictHandle)) 1643 return TPM_RC_NV_DEFINED; 1644 1645 // Copy handle 1646 entrySize = sizeof(TPM_HANDLE); 1647 memcpy(nvBuffer, &evictHandle, entrySize); 1648 1649 // Let's serialize the object before storing it in NVMEM 1650 marshalSpace = nvBuffer + entrySize; 1651 marshalRoom = sizeof(nvBuffer) - entrySize; 1652 entrySize += NvMarshalObject(object, evictHandle, 1653 &marshalSpace, &marshalRoom); 1654 1655 // Check if we have enough space to add this evict object 1656 if(!NvTestSpace(entrySize, FALSE)) return TPM_RC_NV_SPACE; 1657 1658 // Add evict to NV memory 1659 NvAdd(entrySize, entrySize, nvBuffer); 1660 return TPM_RC_SUCCESS; 1661} 1662// 1663// 1664// NvDeleteEntity() 1665// 1666// This function will delete a NV Index or an evict object. 1667// This function requires that the index/evict object has been defined. 1668// 1669void 1670NvDeleteEntity( 1671 TPM_HANDLE handle // IN: handle of entity to be deleted 1672 ) 1673{ 1674 UINT32 entityAddr; // pointer to entity 1675 entityAddr = NvFindHandle(handle); 1676 pAssert(entityAddr != 0); 1677 if(HandleGetType(handle) == TPM_HT_NV_INDEX) 1678 { 1679 NV_INDEX nvIndex; 1680 // Read the NV Index info 1681 _plat__NvMemoryRead(entityAddr + sizeof(TPM_HANDLE), sizeof(NV_INDEX), 1682 &nvIndex); 1683 // If the entity to be deleted is a counter with the maximum counter 1684 // value, record it in NV memory 1685 if(nvIndex.publicArea.attributes.TPMA_NV_COUNTER == SET 1686 && nvIndex.publicArea.attributes.TPMA_NV_WRITTEN == SET) 1687 { 1688 UINT64 countValue; 1689 UINT64 maxCount; 1690 NvGetIntIndexData(handle, &nvIndex, &countValue); 1691 maxCount = NvReadMaxCount(); 1692 if(countValue > maxCount) 1693 NvWriteMaxCount(countValue); 1694 } 1695 // If the NV Index is RAM back, delete the RAM data as well 1696 if(nvIndex.publicArea.attributes.TPMA_NV_ORDERLY == SET) 1697 NvDeleteRAM(handle); 1698 } 1699 NvDelete(entityAddr); 1700 return; 1701} 1702// 1703// 1704// NvFlushHierarchy() 1705// 1706// This function will delete persistent objects belonging to the indicated If the storage hierarchy is selected, 1707// the function will also delete any NV Index define using ownerAuth. 1708// 1709void 1710NvFlushHierarchy( 1711 TPMI_RH_HIERARCHY hierarchy // IN: hierarchy to be flushed. 1712 ) 1713{ 1714 NV_ITER iter = NV_ITER_INIT; 1715 UINT32 currentAddr; 1716 while((currentAddr = NvNext(&iter)) != 0) 1717 { 1718 TPM_HANDLE entityHandle; 1719 // Read handle information. 1720 _plat__NvMemoryRead(currentAddr, sizeof(TPM_HANDLE), &entityHandle); 1721 if(HandleGetType(entityHandle) == TPM_HT_NV_INDEX) 1722 { 1723 // Handle NV Index 1724 NV_INDEX nvIndex; 1725 // If flush endorsement or platform hierarchy, no NV Index would be 1726 // flushed 1727 if(hierarchy == TPM_RH_ENDORSEMENT || hierarchy == TPM_RH_PLATFORM) 1728 continue; 1729 _plat__NvMemoryRead(currentAddr + sizeof(TPM_HANDLE), 1730 sizeof(NV_INDEX), &nvIndex); 1731 // For storage hierarchy, flush OwnerCreated index 1732 if( nvIndex.publicArea.attributes.TPMA_NV_PLATFORMCREATE == CLEAR) 1733 { 1734 // Delete the NV Index 1735 NvDelete(currentAddr); 1736 // Re-iterate from beginning after a delete 1737 iter = NV_ITER_INIT; 1738 // If the NV Index is RAM back, delete the RAM data as well 1739 if(nvIndex.publicArea.attributes.TPMA_NV_ORDERLY == SET) 1740 NvDeleteRAM(entityHandle); 1741 } 1742 } 1743 else if(HandleGetType(entityHandle) == TPM_HT_PERSISTENT) 1744 { 1745 OBJECT object; 1746 // Get evict object 1747 NvGetEvictObject(entityHandle, &object); 1748 // If the evict object belongs to the hierarchy to be flushed 1749 if( ( hierarchy == TPM_RH_PLATFORM 1750 && object.attributes.ppsHierarchy == SET) 1751 || ( hierarchy == TPM_RH_OWNER 1752 && object.attributes.spsHierarchy == SET) 1753 || ( hierarchy == TPM_RH_ENDORSEMENT 1754 && object.attributes.epsHierarchy == SET) 1755 ) 1756 { 1757 // Delete the evict object 1758 NvDelete(currentAddr); 1759 // Re-iterate from beginning after a delete 1760 iter = NV_ITER_INIT; 1761 } 1762 } 1763 else 1764 { 1765 pAssert(FALSE); 1766 } 1767 } 1768 return; 1769} 1770// 1771// 1772// NvSetGlobalLock() 1773// 1774// This function is used to SET the TPMA_NV_WRITELOCKED attribute for all NV Indices that have 1775// TPMA_NV_GLOBALLOCK SET. This function is use by TPM2_NV_GlobalWriteLock(). 1776// 1777void 1778NvSetGlobalLock( 1779 void 1780 ) 1781{ 1782 NV_ITER iter = NV_ITER_INIT; 1783 UINT32 currentAddr; 1784 // Check all Indices 1785 while((currentAddr = NvNextIndex(&iter)) != 0) 1786 { 1787 NV_INDEX nvIndex; 1788 // Read the index data 1789 _plat__NvMemoryRead(currentAddr + sizeof(TPM_HANDLE), 1790 sizeof(NV_INDEX), &nvIndex); 1791 // See if it should be locked 1792 if(nvIndex.publicArea.attributes.TPMA_NV_GLOBALLOCK == SET) 1793 { 1794 // if so, lock it 1795 nvIndex.publicArea.attributes.TPMA_NV_WRITELOCKED = SET; 1796 _plat__NvMemoryWrite(currentAddr + sizeof(TPM_HANDLE), 1797 sizeof(NV_INDEX), &nvIndex); 1798 // Set the flag that a NV write happens 1799 g_updateNV = TRUE; 1800 } 1801 } 1802 return; 1803} 1804// 1805// 1806// InsertSort() 1807// 1808// Sort a handle into handle list in ascending order. The total handle number in the list should not exceed 1809// MAX_CAP_HANDLES 1810// 1811static void 1812InsertSort( 1813 TPML_HANDLE *handleList, // IN/OUT: sorted handle list 1814 UINT32 count, // IN: maximum count in the handle list 1815 TPM_HANDLE entityHandle // IN: handle to be inserted 1816 ) 1817{ 1818 UINT32 i, j; 1819 UINT32 originalCount; 1820 // For a corner case that the maximum count is 0, do nothing 1821 if(count == 0) return; 1822 // For empty list, add the handle at the beginning and return 1823 if(handleList->count == 0) 1824 { 1825 handleList->handle[0] = entityHandle; 1826 handleList->count++; 1827 return; 1828 } 1829 // Check if the maximum of the list has been reached 1830 originalCount = handleList->count; 1831 if(originalCount < count) 1832 handleList->count++; 1833 // Insert the handle to the list 1834 for(i = 0; i < originalCount; i++) 1835 { 1836 if(handleList->handle[i] > entityHandle) 1837 { 1838 for(j = handleList->count - 1; j > i; j--) 1839 { 1840 handleList->handle[j] = handleList->handle[j-1]; 1841 } 1842 break; 1843 } 1844 } 1845 // If a slot was found, insert the handle in this position 1846 if(i < originalCount || handleList->count > originalCount) 1847 handleList->handle[i] = entityHandle; 1848 return; 1849} 1850// 1851// 1852// NvCapGetPersistent() 1853// 1854// This function is used to get a list of handles of the persistent objects, starting at handle. 1855// Handle must be in valid persistent object handle range, but does not have to reference an existing 1856// persistent object. 1857// 1858// Return Value Meaning 1859// 1860// YES if there are more handles available 1861// NO all the available handles has been returned 1862// 1863TPMI_YES_NO 1864NvCapGetPersistent( 1865 TPMI_DH_OBJECT handle, // IN: start handle 1866 UINT32 count, // IN: maximum number of returned handle 1867 TPML_HANDLE *handleList // OUT: list of handle 1868 ) 1869{ 1870 TPMI_YES_NO more = NO; 1871 NV_ITER iter = NV_ITER_INIT; 1872 UINT32 currentAddr; 1873 pAssert(HandleGetType(handle) == TPM_HT_PERSISTENT); 1874 // Initialize output handle list 1875 handleList->count = 0; 1876 // The maximum count of handles we may return is MAX_CAP_HANDLES 1877 if(count > MAX_CAP_HANDLES) count = MAX_CAP_HANDLES; 1878 while((currentAddr = NvNextEvict(&iter)) != 0) 1879 { 1880 TPM_HANDLE entityHandle; 1881 // Read handle information. 1882 _plat__NvMemoryRead(currentAddr, sizeof(TPM_HANDLE), &entityHandle); 1883 // Ignore persistent handles that have values less than the input handle 1884 if(entityHandle < handle) 1885 continue; 1886 // if the handles in the list have reached the requested count, and there 1887 // are still handles need to be inserted, indicate that there are more. 1888 if(handleList->count == count) 1889 more = YES; 1890 // A handle with a value larger than start handle is a candidate 1891 // for return. Insert sort it to the return list. Insert sort algorithm 1892 // is chosen here for simplicity based on the assumption that the total 1893 // number of NV Indices is small. For an implementation that may allow 1894 // large number of NV Indices, a more efficient sorting algorithm may be 1895 // used here. 1896 InsertSort(handleList, count, entityHandle); 1897// 1898 } 1899 return more; 1900} 1901// 1902// 1903// NvCapGetIndex() 1904// 1905// This function returns a list of handles of NV Indices, starting from handle. Handle must be in the range of 1906// NV Indices, but does not have to reference an existing NV Index. 1907// 1908// Return Value Meaning 1909// 1910// YES if there are more handles to report 1911// NO all the available handles has been reported 1912// 1913TPMI_YES_NO 1914NvCapGetIndex( 1915 TPMI_DH_OBJECT handle, // IN: start handle 1916 UINT32 count, // IN: maximum number of returned handle 1917 TPML_HANDLE *handleList // OUT: list of handle 1918 ) 1919{ 1920 TPMI_YES_NO more = NO; 1921 NV_ITER iter = NV_ITER_INIT; 1922 UINT32 currentAddr; 1923 pAssert(HandleGetType(handle) == TPM_HT_NV_INDEX); 1924 // Initialize output handle list 1925 handleList->count = 0; 1926 // The maximum count of handles we may return is MAX_CAP_HANDLES 1927 if(count > MAX_CAP_HANDLES) count = MAX_CAP_HANDLES; 1928 while((currentAddr = NvNextIndex(&iter)) != 0) 1929 { 1930 TPM_HANDLE entityHandle; 1931 // Read handle information. 1932 _plat__NvMemoryRead(currentAddr, sizeof(TPM_HANDLE), &entityHandle); 1933 // Ignore index handles that have values less than the 'handle' 1934 if(entityHandle < handle) 1935 continue; 1936 // if the count of handles in the list has reached the requested count, 1937 // and there are still handles to report, set more. 1938 if(handleList->count == count) 1939 more = YES; 1940 // A handle with a value larger than start handle is a candidate 1941 // for return. Insert sort it to the return list. Insert sort algorithm 1942 // is chosen here for simplicity based on the assumption that the total 1943 // number of NV Indices is small. For an implementation that may allow 1944 // large number of NV Indices, a more efficient sorting algorithm may be 1945 // used here. 1946 InsertSort(handleList, count, entityHandle); 1947 } 1948 return more; 1949} 1950// 1951// 1952// 1953// NvCapGetIndexNumber() 1954// 1955// This function returns the count of NV Indexes currently defined. 1956// 1957UINT32 1958NvCapGetIndexNumber( 1959 void 1960 ) 1961{ 1962 UINT32 num = 0; 1963 NV_ITER iter = NV_ITER_INIT; 1964 while(NvNextIndex(&iter) != 0) num++; 1965 return num; 1966} 1967// 1968// 1969// NvCapGetPersistentNumber() 1970// 1971// Function returns the count of persistent objects currently in NV memory. 1972// 1973UINT32 1974NvCapGetPersistentNumber( 1975 void 1976 ) 1977{ 1978 UINT32 num = 0; 1979 NV_ITER iter = NV_ITER_INIT; 1980 while(NvNextEvict(&iter) != 0) num++; 1981 return num; 1982} 1983// 1984// 1985// NvCapGetPersistentAvail() 1986// 1987// This function returns an estimate of the number of additional persistent objects that could be loaded into 1988// NV memory. 1989// 1990UINT32 1991NvCapGetPersistentAvail( 1992 void 1993 ) 1994{ 1995 UINT32 availSpace; 1996 UINT32 objectSpace; 1997 // Compute the available space in NV storage 1998 availSpace = NvGetFreeByte(); 1999 // Get the space needed to add a persistent object to NV storage 2000 objectSpace = NvGetEvictObjectSize(); 2001 return availSpace / objectSpace; 2002} 2003// 2004// 2005// NvCapGetCounterNumber() 2006// 2007// Get the number of defined NV Indexes that have NV TPMA_NV_COUNTER attribute SET. 2008// 2009// 2010UINT32 2011NvCapGetCounterNumber( 2012 void 2013 ) 2014{ 2015 NV_ITER iter = NV_ITER_INIT; 2016 UINT32 currentAddr; 2017 UINT32 num = 0; 2018 while((currentAddr = NvNextIndex(&iter)) != 0) 2019 { 2020 NV_INDEX nvIndex; 2021 // Get NV Index info 2022 _plat__NvMemoryRead(currentAddr + sizeof(TPM_HANDLE), 2023 sizeof(NV_INDEX), &nvIndex); 2024 if(nvIndex.publicArea.attributes.TPMA_NV_COUNTER == SET) num++; 2025 } 2026 return num; 2027} 2028// 2029// 2030// NvCapGetCounterAvail() 2031// 2032// This function returns an estimate of the number of additional counter type NV Indices that can be defined. 2033// 2034UINT32 2035NvCapGetCounterAvail( 2036 void 2037 ) 2038{ 2039 UINT32 availNVSpace; 2040 UINT32 availRAMSpace; 2041 UINT32 counterNVSpace; 2042 UINT32 counterRAMSpace; 2043 UINT32 persistentNum = NvCapGetPersistentNumber(); 2044 // Get the available space in NV storage 2045 availNVSpace = NvGetFreeByte(); 2046 if (persistentNum < MIN_EVICT_OBJECTS) 2047 { 2048 // Some space have to be reserved for evict object. Adjust availNVSpace. 2049 UINT32 reserved = (MIN_EVICT_OBJECTS - persistentNum) 2050 * NvGetEvictObjectSize(); 2051 if (reserved > availNVSpace) 2052 availNVSpace = 0; 2053 else 2054 availNVSpace -= reserved; 2055 } 2056 // Get the space needed to add a counter index to NV storage 2057 counterNVSpace = NvGetCounterSize(); 2058 // Compute the available space in RAM 2059 availRAMSpace = RAM_INDEX_SPACE - s_ramIndexSize; 2060 // Compute the space needed to add a counter index to RAM storage 2061 // It takes an size field, a handle and sizeof(UINT64) for counter data 2062 counterRAMSpace = sizeof(UINT32) + sizeof(TPM_HANDLE) + sizeof(UINT64); 2063 // Return the min of counter number in NV and in RAM 2064 if(availNVSpace / counterNVSpace > availRAMSpace / counterRAMSpace) 2065 return availRAMSpace / counterRAMSpace; 2066 else 2067 return availNVSpace / counterNVSpace; 2068} 2069