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