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