Coverage Report

Created: 2025-07-12 06:29

/src/libtpms/src/tpm2/NVDynamic.c
Line
Count
Source (jump to first uncovered line)
1
/********************************************************************************/
2
/*                    */
3
/*    Dynamic space for user defined NV             */
4
/*           Written by Ken Goldman       */
5
/*           IBM Thomas J. Watson Research Center     */
6
/*                    */
7
/*  Licenses and Notices              */
8
/*                    */
9
/*  1. Copyright Licenses:              */
10
/*                    */
11
/*  - Trusted Computing Group (TCG) grants to the user of the source code in  */
12
/*    this specification (the "Source Code") a worldwide, irrevocable,    */
13
/*    nonexclusive, royalty free, copyright license to reproduce, create  */
14
/*    derivative works, distribute, display and perform the Source Code and */
15
/*    derivative works thereof, and to grant others the rights granted herein.  */
16
/*                    */
17
/*  - The TCG grants to the user of the other parts of the specification  */
18
/*    (other than the Source Code) the rights to reproduce, distribute,   */
19
/*    display, and perform the specification solely for the purpose of    */
20
/*    developing products based on such documents.        */
21
/*                    */
22
/*  2. Source Code Distribution Conditions:         */
23
/*                    */
24
/*  - Redistributions of Source Code must retain the above copyright licenses,  */
25
/*    this list of conditions and the following disclaimers.      */
26
/*                    */
27
/*  - Redistributions in binary form must reproduce the above copyright   */
28
/*    licenses, this list of conditions and the following disclaimers in the  */
29
/*    documentation and/or other materials provided with the distribution.  */
30
/*                    */
31
/*  3. Disclaimers:               */
32
/*                    */
33
/*  - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */
34
/*  LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */
35
/*  RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */
36
/*  THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE.   */
37
/*  Contact TCG Administration (admin@trustedcomputinggroup.org) for    */
38
/*  information on specification licensing rights available through TCG   */
39
/*  membership agreements.              */
40
/*                    */
41
/*  - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED   */
42
/*    WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR   */
43
/*    FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR    */
44
/*    NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY    */
45
/*    OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE.   */
46
/*                    */
47
/*  - Without limitation, TCG and its members and licensors disclaim all  */
48
/*    liability, including liability for infringement of any proprietary  */
49
/*    rights, relating to use of information in this specification and to the */
50
/*    implementation of this specification, and TCG disclaims all liability for */
51
/*    cost of procurement of substitute goods or services, lost profits, loss   */
52
/*    of use, loss of data or any incidental, consequential, direct, indirect,  */
53
/*    or special damages, whether under contract, tort, warranty or otherwise,  */
54
/*    arising in any way out of use or reliance upon this specification or any  */
55
/*    information herein.             */
56
/*                    */
57
/*  (c) Copyright IBM Corp. and others, 2016 - 2023       */
58
/*                    */
59
/********************************************************************************/
60
61
//** Introduction
62
63
// The NV memory is divided into two areas: dynamic space for user defined NV
64
// indexes and evict objects, and reserved space for TPM persistent and state save
65
// data.
66
//
67
// The entries in dynamic space are a linked list of entries. Each entry has, as its
68
// first field, a size. If the size field is zero, it marks the end of the
69
// list.
70
//
71
// An Index allocation will contain an NV_INDEX structure. If the Index does not
72
// have the orderly attribute, the NV_INDEX is followed immediately by the NV data.
73
//
74
// An evict object entry contains a handle followed by an OBJECT structure. This
75
// results in both the Index and Evict Object having an identifying handle as the
76
// first field following the size field.
77
//
78
// When an Index has the orderly attribute, the data is kept in RAM. This RAM is
79
// saved to backing store in NV memory on any orderly shutdown. The entries in
80
// orderly memory are also a linked list using a size field as the first entry.
81
//
82
// The attributes of an orderly index are maintained in RAM memory in order to
83
// reduce the number of NV writes needed for orderly data. When an orderly index
84
// is created, an entry is made in the dynamic NV memory space that holds the Index
85
// authorizations (authPolicy and authValue) and the size of the data. This entry is
86
// only modified if the authValue  of the index is changed. The more volatile data
87
// of the index is kept in RAM. When an orderly Index is created or deleted, the
88
// RAM data is copied to NV backing store so that the image in the backing store
89
// matches the layout of RAM. In normal operation. The RAM data is also copied on
90
// any orderly shutdown. In normal operation, the only other reason for writing
91
// to the backing store for RAM is when a counter is first written (TPMA_NV_WRITTEN
92
// changes from CLEAR to SET) or when a counter ""rolls over"".
93
//
94
// Static space contains items that are individually modifiable. The values are in
95
// the 'gp' PERSISTENT_DATA structure in RAM and mapped to locations in NV.
96
//
97
98
//** Includes, Defines and Data Definitions
99
#define NV_C
100
#include "Tpm.h"
101
#include "Marshal.h"
102
#include "tpm_library_intern.h"       // libtpms added
103
#include "BackwardsCompatibilityObject.h"   // libtpms added
104
105
//** Local Functions
106
107
//*** NvNext()
108
//  This function provides a method to traverse every data entry in NV dynamic
109
//  area.
110
//
111
//  To begin with, parameter 'iter' should be initialized to NV_REF_INIT
112
//  indicating the first element.  Every time this function is called, the
113
//  value in 'iter' would be adjusted pointing to the next element in
114
//  traversal.  If there is no next element, 'iter' value would be 0.
115
//  This function returns the address of the 'data entry' pointed by the
116
//  'iter'.  If there are no more elements in the set, a 0 value is returned
117
//  indicating the end of traversal.
118
//
119
static NV_REF NvNext(NV_REF*     iter,   // IN/OUT: the list iterator
120
         TPM_HANDLE* handle  // OUT: the handle of the next item.
121
         )
122
12.5k
{
123
12.5k
    NV_REF          currentAddr;
124
12.5k
    NV_ENTRY_HEADER header;
125
    //
126
    // If iterator is at the beginning of list
127
12.5k
    if(*iter == NV_REF_INIT)
128
12.5k
  {
129
      // Initialize iterator
130
12.5k
      *iter = NV_USER_DYNAMIC;
131
12.5k
  }
132
    // Step over the size field and point to the handle
133
12.5k
    currentAddr = *iter + sizeof(UINT32);
134
135
    // read the header of the next entry
136
12.5k
    NvRead(&header, *iter, sizeof(NV_ENTRY_HEADER));
137
138
    // if the size field is zero, then we have hit the end of the list
139
12.5k
    if(header.size == 0)
140
  // leave the *iter pointing at the end of the list
141
12.5k
  return 0;
142
    // advance the header by the size of the entry
143
0
    *iter += header.size;
144
145
0
    if(handle != NULL)
146
0
  *handle = header.handle;
147
0
    return currentAddr;
148
12.5k
}
149
150
//*** NvNextByType()
151
// This function returns a reference to the next NV entry of the desired type
152
//  Return Type: NV_REF
153
//      0               end of list
154
//      != 0            the next entry of the indicated type
155
static NV_REF NvNextByType(
156
         TPM_HANDLE* handle,  // OUT: the handle of the found type or 0
157
         NV_REF*     iter,    // IN: the iterator
158
         TPM_HT      type     // IN: the handle type to look for
159
         )
160
6.19k
{
161
6.19k
    NV_REF     addr;
162
6.19k
    TPM_HANDLE nvHandle = 0;
163
    //
164
6.19k
    while((addr = NvNext(iter, &nvHandle)) != 0)
165
0
  {
166
      // addr: the address of the location containing the handle of the value
167
      // iter: the next location.
168
0
      if(HandleGetType(nvHandle) == type)
169
0
    break;
170
0
  }
171
6.19k
    if(handle != NULL)
172
6.11k
  *handle = nvHandle;
173
6.19k
    return addr;
174
6.19k
}
175
176
//*** NvNextIndex()
177
// This function returns the reference to the next NV Index entry.  A value
178
// of 0 indicates the end of the list.
179
//  Return Type: NV_REF
180
//      0               end of list
181
//      != 0            the next reference
182
6.08k
#define NvNextIndex(handle, iter) NvNextByType(handle, iter, TPM_HT_NV_INDEX)
183
184
//*** NvNextEvict()
185
// This function returns the offset in NV of the next evict object entry.  A value
186
// of 0 indicates the end of the list.
187
112
#define NvNextEvict(handle, iter) NvNextByType(handle, iter, TPM_HT_PERSISTENT)
188
189
//*** NvGetEnd()
190
// Function to find the end of the NV dynamic data list
191
static NV_REF NvGetEnd(void)
192
145
{
193
145
    NV_REF iter = NV_REF_INIT;
194
145
    NV_REF currentAddr;
195
    //
196
    // Scan until the next address is 0
197
145
    while((currentAddr = NvNext(&iter, NULL)) != 0)
198
0
  ;
199
145
    return iter;
200
145
}
201
202
//*** NvGetFreeBytes
203
// This function returns the number of free octets in NV space.
204
static UINT32 NvGetFreeBytes(void)
205
77
{
206
    // This does not have an overflow issue because NvGetEnd() cannot return a value
207
    // that is larger than s_evictNvEnd. This is because there is always a 'stop'
208
    // word in the NV memory that terminates the search for the end before the
209
    // value can go past s_evictNvEnd.
210
77
    return s_evictNvEnd - NvGetEnd();
211
77
}
212
213
//*** NvTestSpace()
214
// This function will test if there is enough space to add a new entity.
215
//  Return Type: BOOL
216
//      TRUE(1)         space available
217
//      FALSE(0)        no enough space
218
static BOOL NvTestSpace(UINT32 size,      // IN: size of the entity to be added
219
      BOOL   isIndex,   // IN: TRUE if the entity is an index
220
      BOOL   isCounter  // IN: TRUE if the index is a counter
221
      )
222
75
{
223
75
    UINT32 remainBytes = NvGetFreeBytes();
224
75
    UINT32 reserved    = sizeof(UINT32)  // size of the forward pointer
225
75
       + sizeof(NV_LIST_TERMINATOR);
226
    //
227
    // Do a compile time sanity check on the setting for NV_MEMORY_SIZE
228
#if NV_MEMORY_SIZE < 1024
229
#  error "NV_MEMORY_SIZE probably isn't large enough"
230
#endif
231
232
    // For NV Index, need to make sure that we do not allocate an Index if this
233
    // would mean that the TPM cannot allocate the minimum number of evict
234
    // objects.
235
75
    if(isIndex)
236
75
  {
237
      // Get the number of persistent objects allocated
238
75
      UINT32 persistentNum = NvCapGetPersistentNumber();
239
240
      // If we have not allocated the requisite number of evict objects, then we
241
      // need to reserve space for them.
242
      // NOTE: some of this is not written as simply as it might seem because
243
      // the values are all unsigned and subtracting needs to be done carefully
244
      // so that an underflow doesn't cause problems.
245
75
      if(persistentNum < MIN_EVICT_OBJECTS)
246
75
    reserved += (MIN_EVICT_OBJECTS - persistentNum) * NV_EVICT_OBJECT_SIZE;
247
75
  }
248
    // If this is not an index or is not a counter, reserve space for the
249
    // required number of counter indexes
250
75
    if(!isIndex || !isCounter)
251
74
  {
252
      // Get the number of counters
253
74
      UINT32 counterNum = NvCapGetCounterNumber();
254
255
      // If the required number of counters have not been allocated, reserved
256
      // space for the extra needed counters
257
74
      if(counterNum < MIN_COUNTER_INDICES)
258
74
    reserved += (MIN_COUNTER_INDICES - counterNum) * NV_INDEX_COUNTER_SIZE;
259
74
  }
260
    // Check that the requested allocation will fit after making sure that there
261
    // will be no chance of overflow
262
75
    return ((reserved < remainBytes) && (size <= remainBytes)
263
75
      && (size + reserved <= remainBytes));
264
75
}
265
266
//*** NvWriteNvListEnd()
267
// Function to write the list terminator.
268
NV_REF
269
NvWriteNvListEnd(NV_REF end)
270
6.02k
{
271
    // Marker is initialized with zeros
272
6.02k
    BYTE   listEndMarker[sizeof(NV_LIST_TERMINATOR)] = {0};
273
6.02k
    UINT64 maxCount                                  = NvReadMaxCount();
274
    //
275
    // This is a constant check that can be resolved at compile time.
276
6.02k
    MUST_BE(sizeof(UINT64) <= sizeof(NV_LIST_TERMINATOR) - sizeof(UINT32));
277
278
    // Copy the maxCount value to the marker buffer
279
6.02k
    MemoryCopy(&listEndMarker[sizeof(UINT32)], &maxCount, sizeof(UINT64));
280
6.02k
    pAssert(end + sizeof(NV_LIST_TERMINATOR) <= s_evictNvEnd);
281
282
    // Write it to memory
283
6.02k
    NvWrite(end, sizeof(NV_LIST_TERMINATOR), &listEndMarker);
284
6.02k
    return end + sizeof(NV_LIST_TERMINATOR);
285
6.02k
}
286
287
//*** NvAdd()
288
// This function adds a new entity to NV.
289
//
290
// This function requires that there is enough space to add a new entity (i.e.,
291
// that NvTestSpace() has been called and the available space is at least as
292
// large as the required space).
293
//
294
// The 'totalSize' will be the size of 'entity'. If a handle is added, this
295
// function will increase the size accordingly.
296
static TPM_RC NvAdd(UINT32 totalSize,  // IN: total size needed for this entity For
297
        //     evict object, totalSize is the same as
298
        //     bufferSize.  For NV Index, totalSize is
299
        //     bufferSize plus index data size
300
        UINT32     bufferSize,  // IN: size of initial buffer
301
        TPM_HANDLE handle,      // IN: optional handle
302
        BYTE*      entity       // IN: initial buffer
303
        )
304
68
{
305
68
    NV_REF newAddr;  // IN: where the new entity will start
306
68
    NV_REF nextAddr;
307
    //
308
68
    RETURN_IF_NV_IS_NOT_AVAILABLE;
309
310
    // Get the end of data list
311
68
    newAddr = NvGetEnd();
312
313
    // Step over the forward pointer
314
68
    nextAddr = newAddr + sizeof(UINT32);
315
316
    // Optionally write the handle. For indexes, the handle is TPM_RH_UNASSIGNED
317
    // so that the handle in the nvIndex is used instead of writing this value
318
68
    if(handle != TPM_RH_UNASSIGNED)
319
0
  {
320
0
      NvWrite((UINT32)nextAddr, sizeof(TPM_HANDLE), &handle);
321
0
      nextAddr += sizeof(TPM_HANDLE);
322
0
  }
323
    // Write entity data
324
68
    NvWrite((UINT32)nextAddr, bufferSize, entity);
325
326
    // Advance the pointer by the amount of the total
327
68
    nextAddr += totalSize;
328
329
    // Finish by writing the link value
330
331
    // Write the next offset (relative addressing)
332
68
    totalSize = nextAddr - newAddr;
333
334
    // Write link value
335
68
    NvWrite((UINT32)newAddr, sizeof(UINT32), &totalSize);
336
337
    // Write the list terminator
338
68
    NvWriteNvListEnd(nextAddr);
339
340
68
    return TPM_RC_SUCCESS;
341
68
}
342
343
//*** NvDelete()
344
// This function is used to delete an NV Index or persistent object from NV memory.
345
static TPM_RC NvDelete(NV_REF entityRef  // IN: reference to entity to be deleted
346
           )
347
0
{
348
0
    UINT32 entrySize;
349
    // adjust entityAddr to back up and point to the forward pointer
350
0
    NV_REF entryRef = entityRef - sizeof(UINT32);
351
0
    NV_REF endRef   = NvGetEnd();
352
0
    NV_REF nextAddr;  // address of the next entry
353
    //
354
0
    RETURN_IF_NV_IS_NOT_AVAILABLE;
355
356
    // Get the offset of the next entry. That is, back up and point to the size
357
    // field of the entry
358
0
    NvRead(&entrySize, entryRef, sizeof(UINT32));
359
360
    // The next entry after the one being deleted is at a relative offset
361
    // from the current entry
362
0
    nextAddr = entryRef + entrySize;
363
364
    // If this is not the last entry, move everything up
365
0
    if(nextAddr < endRef)
366
0
  {
367
0
      pAssert(nextAddr > entryRef);
368
0
      _plat__NvMemoryMove(nextAddr, entryRef, (endRef - nextAddr));
369
0
  }
370
    // The end of the used space is now moved up by the amount of space we just
371
    // reclaimed
372
0
    endRef -= entrySize;
373
374
    // Write the end marker, and make the new end equal to the first byte after
375
    // the just added end value. This will automatically update the NV value for
376
    // maxCounter.
377
    // NOTE: This is the call that sets flag to cause NV to be updated
378
0
    endRef = NvWriteNvListEnd(endRef);
379
380
    // Clear the reclaimed memory
381
0
    _plat__NvMemoryClear(endRef, entrySize);
382
383
0
    return TPM_RC_SUCCESS;
384
0
}
385
386
//************************************************
387
//** RAM-based NV Index Data Access Functions
388
//************************************************
389
//*** Introduction
390
// The data layout in ram buffer is {size of(NV_handle + attributes + data
391
// NV_handle, attributes, data}
392
// for each NV Index data stored in RAM.
393
//
394
// NV storage associated with orderly data is updated when a NV Index is added
395
// but NOT when the data or attributes are changed. Orderly data is only updated
396
// to NV on an orderly shutdown (TPM2_Shutdown())
397
398
//*** NvRamNext()
399
// This function is used to iterate trough the list of Ram Index values. *iter needs
400
// to be initialized by calling
401
static NV_RAM_REF NvRamNext(NV_RAM_REF* iter,   // IN/OUT: the list iterator
402
          TPM_HANDLE* handle  // OUT: the handle of the next item.
403
          )
404
6.01k
{
405
6.01k
    NV_RAM_REF    currentAddr;
406
6.01k
    NV_RAM_HEADER header;
407
    //
408
    // If iterator is at the beginning of list
409
6.01k
    if(*iter == NV_RAM_REF_INIT)
410
6.01k
  {
411
      // Initialize iterator
412
6.01k
      *iter = &s_indexOrderlyRam[0];
413
6.01k
  }
414
    // if we are going to return what the iter is currently pointing to...
415
6.01k
    currentAddr = *iter;
416
417
    // If iterator reaches the end of NV space, then don't advance and return
418
    // that we are at the end of the list. The end of the list occurs when
419
    // we don't have space for a size and a handle
420
6.01k
    if(currentAddr + sizeof(NV_RAM_HEADER) > RAM_ORDERLY_END)
421
0
  return NULL;
422
    // read the header of the next entry
423
6.01k
    memcpy(&header, currentAddr, sizeof(NV_RAM_HEADER)); // libtpms: do not use MemoryCopy to avoid gcc warning
424
    // if the size field is zero, then we have hit the end of the list
425
6.01k
    if(header.size == 0)
426
  // leave the *iter pointing at the end of the list
427
6.01k
  return NULL;
428
    // advance the header by the size of the entry
429
0
    *iter = currentAddr + header.size;
430
431
    //    pAssert(*iter <= RAM_ORDERLY_END);
432
0
    if(handle != NULL)
433
0
  *handle = header.handle;
434
0
    return currentAddr;
435
6.01k
}
436
437
//*** NvRamGetEnd()
438
// This routine performs the same function as NvGetEnd() but for the RAM data.
439
static NV_RAM_REF NvRamGetEnd(void)
440
56
{
441
56
    NV_RAM_REF iter = NV_RAM_REF_INIT;
442
56
    NV_RAM_REF currentAddr;
443
    //
444
    // Scan until the next address is 0
445
56
    while((currentAddr = NvRamNext(&iter, NULL)) != 0)
446
0
  ;
447
56
    return iter;
448
56
}
449
450
//*** NvRamTestSpaceIndex()
451
// This function indicates if there is enough RAM space to add a data for a
452
// new NV Index.
453
//  Return Type: BOOL
454
//      TRUE(1)         space available
455
//      FALSE(0)        no enough space
456
static BOOL NvRamTestSpaceIndex(
457
        UINT32 size  // IN: size of the data to be added to RAM
458
        )
459
31
{
460
31
    UINT32 remaining = (UINT32)(RAM_ORDERLY_END - NvRamGetEnd());
461
31
    UINT32 needed    = sizeof(NV_RAM_HEADER) + size;
462
    //
463
    // NvRamGetEnd points to the next available byte.
464
31
    return remaining >= needed;
465
31
}
466
467
//*** NvRamGetIndex()
468
// This function returns the offset of NV data in the RAM buffer
469
//
470
// This function requires that NV Index is in RAM. That is, the
471
// index must be known to exist.
472
static NV_RAM_REF NvRamGetIndex(TPMI_RH_NV_INDEX handle  // IN: NV handle
473
        )
474
0
{
475
0
    NV_RAM_REF iter = NV_RAM_REF_INIT;
476
0
    NV_RAM_REF currentAddr;
477
0
    TPM_HANDLE foundHandle;
478
    //
479
0
    while((currentAddr = NvRamNext(&iter, &foundHandle)) != 0)
480
0
  {
481
0
      if(handle == foundHandle)
482
0
    break;
483
0
  }
484
0
    return currentAddr;
485
0
}
486
487
//*** NvUpdateIndexOrderlyData()
488
// This function is used to cause an update of the orderly data to the NV backing
489
// store.
490
void NvUpdateIndexOrderlyData(void)
491
5.98k
{
492
    // Write reserved RAM space to NV
493
5.98k
    NvWrite(NV_INDEX_RAM_DATA, sizeof(s_indexOrderlyRam), s_indexOrderlyRam);
494
5.98k
}
495
496
//*** NvAddRAM()
497
// This function adds a new data area to RAM.
498
//
499
// This function requires that enough free RAM space is available to add
500
// the new data.
501
//
502
// This function should be called after the NV Index space has been updated
503
// and the index removed. This insures that NV is available so that checking
504
// for NV availability is not required during this function.
505
static void NvAddRAM(TPMS_NV_PUBLIC* index  // IN: the index descriptor
506
         )
507
24
{
508
24
    NV_RAM_HEADER header;
509
24
    NV_RAM_REF    end = NvRamGetEnd();
510
    //
511
24
    header.size   = sizeof(NV_RAM_HEADER) + index->dataSize;
512
24
    header.handle = index->nvIndex;
513
24
    MemoryCopy(&header.attributes, &index->attributes, sizeof(TPMA_NV));
514
515
24
    pAssert(ORDERLY_RAM_ADDRESS_OK(end, header.size));
516
517
    // Copy the header to the memory
518
24
    MemoryCopy(end, &header, sizeof(NV_RAM_HEADER));
519
520
    // Clear the data area (just in case)
521
24
    MemorySet(end + sizeof(NV_RAM_HEADER), 0, index->dataSize);
522
523
    // Step over this new entry
524
24
    end += header.size;
525
526
    // If the end marker will fit, add it
527
24
    if(end + sizeof(UINT32) < RAM_ORDERLY_END)
528
19
  MemorySet(end, 0, sizeof(UINT32));
529
    // Write reserved RAM space to NV to reflect the newly added NV Index
530
24
    SET_NV_UPDATE(UT_ORDERLY);
531
532
24
    return;
533
24
}
534
535
//*** NvDeleteRAM()
536
// This function is used to delete a RAM-backed NV Index data area.
537
// The space used by the entry are overwritten by the contents of the
538
// Index data that comes after (the data is moved up to fill the hole left
539
// by removing this index. The reclaimed space is cleared to zeros.
540
// This function assumes the data of NV Index exists in RAM.
541
//
542
// This function should be called after the NV Index space has been updated
543
// and the index removed. This insures that NV is available so that checking
544
// for NV availability is not required during this function.
545
static void NvDeleteRAM(TPMI_RH_NV_INDEX handle  // IN: NV handle
546
      )
547
0
{
548
0
    NV_RAM_REF nodeAddress;
549
0
    NV_RAM_REF nextNode;
550
0
    UINT32     size;
551
0
    NV_RAM_REF lastUsed = NvRamGetEnd();
552
    //
553
0
    nodeAddress = NvRamGetIndex(handle);
554
555
0
    pAssert(nodeAddress != 0);
556
557
    // Get node size
558
0
    MemoryCopy(&size, nodeAddress, sizeof(size));
559
560
    // Get the offset of next node
561
0
    nextNode = nodeAddress + size;
562
563
    // Copy the data
564
0
    MemoryCopy(nodeAddress, nextNode, (int)(lastUsed - nextNode));
565
566
    // Clear out the reclaimed space
567
0
    MemorySet(lastUsed - size, 0, size);
568
569
    // Write reserved RAM space to NV to reflect the newly delete NV Index
570
0
    SET_NV_UPDATE(UT_ORDERLY);
571
572
0
    return;
573
0
}
574
575
//*** NvReadIndex()
576
// This function is used to read the NV Index NV_INDEX. This is used so that the
577
// index information can be compressed and only this function would be needed
578
// to decompress it. Mostly, compression would only be able to save the space
579
// needed by the policy.
580
void NvReadNvIndexInfo(NV_REF    ref,     // IN: points to NV where index is located
581
           NV_INDEX* nvIndex  // OUT: place to receive index data
582
           )
583
204
{
584
204
    pAssert(nvIndex != NULL);
585
204
    NvRead(nvIndex, ref, sizeof(NV_INDEX));
586
204
    return;
587
204
}
588
589
// Convert an OBJECT into a buffer to store in NVRAM  // libtpms added begin
590
UINT32 NvObjectToBuffer(OBJECT* object, BYTE* buffer, UINT32 size)
591
0
{
592
    // always use ANY_OBJECT_Marshal if StateFormatLevel >=2 (v0.10)
593
0
    BOOL marshalAnyObject = g_RuntimeProfile.stateFormatLevel >= 2;
594
595
0
    pAssert(size >= MAX_MARSHALLED_OBJECT_SIZE);
596
597
    // RSA 3072 objects and older are stored as RSA3072_OBJECT
598
0
    switch(object->publicArea.type) {
599
0
    case TPM_ALG_RSA:
600
0
        if (object->publicArea.parameters.rsaDetail.keyBits > 3072)
601
0
            marshalAnyObject = true;
602
0
        break;
603
0
    case TPM_ALG_ECC:
604
0
        break;
605
0
    case TPM_ALG_KEYEDHASH:
606
0
        break;
607
0
    case TPM_ALG_SYMCIPHER:
608
0
        break;
609
0
    default:
610
        // must never happen
611
0
        TPMLIB_LogTPM2Error("%s : Unhandled object type: %d\n",
612
0
                            __func__, object->publicArea.type);
613
0
        FAIL(FATAL_ERROR_INTERNAL);
614
0
    }
615
616
0
    if (marshalAnyObject) {
617
0
        return ANY_OBJECT_Marshal(object, &buffer, (INT32*)&size, &g_RuntimeProfile);
618
0
    }
619
0
    return OBJECT_To_Buffer_As_RSA3072_OBJECT(object, buffer, size);
620
0
}
621
622
// Convert a buffer to an OBJECT; the size of the buffer must have
623
// exactly the size consumed by ANY_OBJECT_Unmarshal, if the OBJECT
624
// can be unmarshaled from the buffer.
625
static void NvObjectFromBuffer(OBJECT* object, BYTE* buf, UINT32 buf_size)
626
0
{
627
0
    TPM_RC rc;
628
0
    BYTE*  buffer = buf;
629
0
    INT32  size = buf_size;
630
631
    /* Try to unmarshal it as an ANY_OBJECT; if this works, an OBJECT will
632
     * be passed back, otherwise fall back to copying from memory directly
633
     * as an RSA3072_OBJECT and have it converted to current OBJECT.
634
     */
635
0
    rc = ANY_OBJECT_Unmarshal(object, &buffer, &size, false);
636
0
    if (!rc) {
637
0
        pAssert(size == 0);
638
0
    } else {
639
        /* It could not be unmarshalled, it must be a plain RSA3072_OBJECT */
640
0
        rc = RSA3072_OBJECT_Buffer_To_OBJECT(object, buf, buf_size);
641
0
        pAssert(rc == TPM_RC_SUCCESS);
642
0
    }
643
0
}              // libtpms added end
644
645
//*** NvReadObject()
646
// This function is used to read a persistent object. This is used so that the
647
// object information can be compressed and only this function would be needed
648
// to uncompress it.
649
void NvReadObject(NV_REF  ref,    // IN: points to NV where index is located
650
      OBJECT* object  // OUT: place to receive the object data
651
      )
652
0
{
653
#if 0             // libtpms changed begin
654
    NvRead(object, (ref + sizeof(TPM_HANDLE)), sizeof(OBJECT));
655
#endif
656
0
    UINT32 entrysize;
657
0
    BYTE   buffer[MAX_MARSHALLED_OBJECT_SIZE];
658
659
    /* read size of object in NVRAM; this includes the NV_ENTRY_HEADER */
660
0
    NvRead(&entrysize, ref - sizeof(UINT32), sizeof(entrysize));
661
0
    entrysize -= sizeof(NV_ENTRY_HEADER);
662
663
    /* read the flat object into a buffer */
664
0
    pAssert(entrysize <= sizeof(buffer));
665
0
    NvRead(buffer, ref + sizeof(TPM_HANDLE), entrysize);
666
667
0
    NvObjectFromBuffer(object, buffer, entrysize);
668
669
0
    return;           // libtpms changed end
670
0
}
671
672
//*** NvFindEvict()
673
// This function will return the NV offset of an evict object
674
//  Return Type: UINT32
675
//      0               evict object not found
676
//      != 0            offset of evict object
677
static NV_REF NvFindEvict(TPM_HANDLE nvHandle, OBJECT* object)
678
78
{
679
78
    NV_REF found = NvFindHandle(nvHandle);
680
    //
681
    // If we found the handle and the request included an object pointer, fill it in
682
78
    if(found != 0 && object != NULL)
683
0
  NvReadObject(found, object);
684
78
    return found;
685
78
}
686
687
//*** NvIndexIsDefined()
688
// See if an index is already defined
689
BOOL NvIndexIsDefined(TPM_HANDLE nvHandle  // IN: Index to look for
690
          )
691
75
{
692
75
    return (NvFindHandle(nvHandle) != 0);
693
75
}
694
695
//*** NvConditionallyWrite()
696
// Function to check if the data to be written has changed
697
// and write it if it has
698
//  Return Type: TPM_RC
699
//      TPM_RC_NV_RATE           NV is unavailable because of rate limit
700
//      TPM_RC_NV_UNAVAILABLE    NV is inaccessible
701
static TPM_RC NvConditionallyWrite(NV_REF entryAddr,  // IN: stating address
702
           UINT32 size,       // IN: size of the data to write
703
           void*  data        // IN: the data to write
704
           )
705
0
{
706
    // If the index data is actually changed, then a write to NV is required
707
0
    int isDifferent = _plat__NvGetChangedStatus(entryAddr, size, data);
708
0
    if(isDifferent == NV_INVALID_LOCATION)
709
0
  {
710
      // invalid request, we should be in failure mode by now.
711
0
      return TPM_RC_FAILURE;
712
0
  }
713
0
    else if(isDifferent == NV_HAS_CHANGED)
714
0
  {
715
      // Write the data if NV is available
716
0
      if(g_NvStatus == TPM_RC_SUCCESS)
717
0
    {
718
0
        NvWrite(entryAddr, size, data);
719
0
    }
720
0
      return g_NvStatus;
721
0
  }
722
0
    else if(isDifferent == NV_IS_SAME)
723
0
  {
724
0
      return TPM_RC_SUCCESS;
725
0
  }
726
    // the platform gave us an invalid response.
727
0
    FAIL_RC(FATAL_ERROR_PLATFORM);
728
0
}
729
730
//*** NvReadNvIndexAttributes()
731
// This function returns the attributes of an NV Index.
732
static TPMA_NV NvReadNvIndexAttributes(NV_REF locator  // IN: reference to an NV index
733
               )
734
0
{
735
0
    TPMA_NV attributes;
736
    //
737
0
    NvRead(&attributes,
738
0
     locator + offsetof(NV_INDEX, publicArea.attributes),
739
0
     sizeof(TPMA_NV));
740
0
    return attributes;
741
0
}
742
743
//*** NvReadRamIndexAttributes()
744
// This function returns the attributes from the RAM header structure. This function
745
// is used to deal with the fact that the header structure is only byte aligned.
746
static TPMA_NV NvReadRamIndexAttributes(
747
          NV_RAM_REF ref  // IN: pointer to a NV_RAM_HEADER
748
          )
749
0
{
750
0
    TPMA_NV attributes;
751
    //
752
0
    MemoryCopy(
753
0
         &attributes, ref + offsetof(NV_RAM_HEADER, attributes), sizeof(TPMA_NV));
754
0
    return attributes;
755
0
}
756
757
//*** NvWriteNvIndexAttributes()
758
// This function is used to write just the attributes of an index to NV.
759
//  Return type: TPM_RC
760
//      TPM_RC_NV_RATE          NV is rate limiting so retry
761
//      TPM_RC_NV_UNAVAILABLE   NV is not available
762
static TPM_RC NvWriteNvIndexAttributes(NV_REF  locator,  // IN: location of the index
763
               TPMA_NV attributes  // IN: attributes to write
764
               )
765
0
{
766
0
    return NvConditionallyWrite(locator + offsetof(NV_INDEX, publicArea.attributes),
767
0
        sizeof(TPMA_NV),
768
0
        &attributes);
769
0
}
770
771
//*** NvWriteRamIndexAttributes()
772
// This function is used to write the index attributes into an unaligned structure
773
static void NvWriteRamIndexAttributes(
774
              NV_RAM_REF ref,        // IN: address of the header
775
              TPMA_NV    attributes  // IN: the attributes to write
776
              )
777
0
{
778
0
    MemoryCopy(
779
0
         ref + offsetof(NV_RAM_HEADER, attributes), &attributes, sizeof(TPMA_NV));
780
0
    return;
781
0
}
782
783
//************************************************
784
//** Externally Accessible Functions
785
//************************************************
786
787
//*** NvIsPlatformPersistentHandle()
788
// This function indicates if a handle references a persistent object in the
789
// range belonging to the platform.
790
//  Return Type: BOOL
791
//      TRUE(1)         handle references a platform persistent object
792
//      FALSE(0)        handle does not reference platform persistent object
793
BOOL NvIsPlatformPersistentHandle(TPM_HANDLE handle  // IN: handle
794
          )
795
0
{
796
0
    return (handle >= PLATFORM_PERSISTENT && handle <= PERSISTENT_LAST);
797
0
}
798
799
//*** NvIsOwnerPersistentHandle()
800
// This function indicates if a handle references a persistent object in the
801
// range belonging to the owner.
802
//  Return Type: BOOL
803
//      TRUE(1)         handle is owner persistent handle
804
//      FALSE(0)        handle is not owner persistent handle and may not be
805
//                      a persistent handle at all
806
BOOL NvIsOwnerPersistentHandle(TPM_HANDLE handle  // IN: handle
807
             )
808
0
{
809
0
    return (handle >= PERSISTENT_FIRST && handle < PLATFORM_PERSISTENT);
810
0
}
811
812
//*** NvIndexIsAccessible()
813
//
814
// This function validates that a handle references a defined NV Index and
815
// that the Index is currently accessible.
816
//  Return Type: TPM_RC
817
//      TPM_RC_HANDLE           the handle points to an undefined NV Index
818
//                              If shEnable is CLEAR, this would include an index
819
//                              created using ownerAuth. If phEnableNV is CLEAR,
820
//                              this would include and index created using
821
//                              platformAuth
822
//      TPM_RC_NV_READLOCKED    Index is present but locked for reading and command
823
//                              does not write to the index
824
//      TPM_RC_NV_WRITELOCKED   Index is present but locked for writing and command
825
//                              writes to the index
826
TPM_RC
827
NvIndexIsAccessible(TPMI_RH_NV_INDEX handle  // IN: handle
828
        )
829
40
{
830
40
    NV_INDEX* nvIndex = NvGetIndexInfo(handle, NULL);
831
    //
832
40
    if(nvIndex == NULL)
833
  // If index is not found, return TPM_RC_HANDLE
834
40
  return TPM_RC_HANDLE;
835
0
    if(gc.shEnable == FALSE || gc.phEnableNV == FALSE)
836
0
  {
837
      // if shEnable is CLEAR, an ownerCreate NV Index should not be
838
      // indicated as present
839
0
      if(!IS_ATTRIBUTE(nvIndex->publicArea.attributes, TPMA_NV, PLATFORMCREATE))
840
0
    {
841
0
        if(gc.shEnable == FALSE)
842
0
      return TPM_RC_HANDLE;
843
0
    }
844
      // if phEnableNV is CLEAR, a platform created Index should not
845
      // be visible
846
0
      else if(gc.phEnableNV == FALSE)
847
0
    return TPM_RC_HANDLE;
848
0
  }
849
#if 0  // Writelock test for debug
850
    // If the Index is write locked and this is an NV Write operation...
851
    if(IS_ATTRIBUTE(nvIndex->publicArea.attributes, TPMA_NV, WRITELOCKED)
852
       &&  IsWriteOperation(commandIndex))
853
  {
854
      // then return a locked indication unless the command is TPM2_NV_WriteLock
855
      if(GetCommandCode(commandIndex) != TPM_CC_NV_WriteLock)
856
    return TPM_RC_NV_LOCKED;
857
      return TPM_RC_SUCCESS;
858
  }
859
#endif
860
#if 0  // Readlock Test for debug
861
    // If the Index is read locked and this is an NV Read operation...
862
    if(IS_ATTRIBUTE(nvIndex->publicArea.attributes, TPMA_NV, READLOCKED)
863
       && IsReadOperation(commandIndex))
864
  {
865
      // then return a locked indication unless the command is TPM2_NV_ReadLock
866
      if(GetCommandCode(commandIndex) != TPM_CC_NV_ReadLock)
867
    return TPM_RC_NV_LOCKED;
868
  }
869
#endif
870
    // NV Index is accessible
871
0
    return TPM_RC_SUCCESS;
872
0
}
873
874
//*** NvGetEvictObject()
875
// This function is used to dereference an evict object handle and get a pointer
876
// to the object.
877
//  Return Type: TPM_RC
878
//      TPM_RC_HANDLE           the handle does not point to an existing
879
//                              persistent object
880
TPM_RC
881
NvGetEvictObject(TPM_HANDLE handle,  // IN: handle
882
     OBJECT*    object   // OUT: object data
883
     )
884
78
{
885
78
    NV_REF entityAddr;  // offset points to the entity
886
    //
887
    // Find the address of evict object and copy to object
888
78
    entityAddr = NvFindEvict(handle, object);
889
890
    // whether there is an error or not, make sure that the evict
891
    // status of the object is set so that the slot will get freed on exit
892
    // Must do this after NvFindEvict loads the object
893
78
    object->attributes.evict = SET;
894
895
    // If handle is not found, return an error
896
78
    if(entityAddr == 0)
897
78
  return TPM_RC_HANDLE;
898
0
    return TPM_RC_SUCCESS;
899
78
}
900
901
//*** NvIndexCacheInit()
902
// Function to initialize the Index cache
903
void NvIndexCacheInit(void)
904
11.7k
{
905
11.7k
    s_cachedNvRef                      = NV_REF_INIT;
906
11.7k
    s_cachedNvRamRef                   = NV_RAM_REF_INIT;
907
11.7k
    s_cachedNvIndex.publicArea.nvIndex = TPM_RH_UNASSIGNED;
908
11.7k
    return;
909
11.7k
}
910
911
//*** NvGetIndexData()
912
// This function is used to access the data in an NV Index. The data is returned
913
// as a byte sequence.
914
//
915
// This function requires that the NV Index be defined, and that the
916
// required data is within the data range.  It also requires that TPMA_NV_WRITTEN
917
// of the Index is SET.
918
void NvGetIndexData(NV_INDEX* nvIndex,  // IN: the in RAM index descriptor
919
        NV_REF    locator,  // IN: where the data is located
920
        UINT32    offset,   // IN: offset of NV data
921
        UINT16    size,     // IN: number of octets of NV data to read
922
        void*     data      // OUT: data buffer
923
        )
924
0
{
925
0
    TPMA_NV nvAttributes;
926
    //
927
0
    pAssert(nvIndex != NULL);
928
929
0
    nvAttributes = nvIndex->publicArea.attributes;
930
931
0
    pAssert(IS_ATTRIBUTE(nvAttributes, TPMA_NV, WRITTEN));
932
933
0
    if(IS_ATTRIBUTE(nvAttributes, TPMA_NV, ORDERLY))
934
0
  {
935
      // Get data from RAM buffer
936
0
      NV_RAM_REF ramAddr = NvRamGetIndex(nvIndex->publicArea.nvIndex);
937
0
      pAssert(ramAddr != 0
938
0
        && (size <= ((NV_RAM_HEADER*)ramAddr)->size - sizeof(NV_RAM_HEADER)
939
0
      - offset));
940
0
      MemoryCopy(data, ramAddr + sizeof(NV_RAM_HEADER) + offset, size);
941
0
  }
942
0
    else
943
0
  {
944
      // Validate that read falls within range of the index
945
0
      pAssert(offset <= nvIndex->publicArea.dataSize
946
0
        && size <= (nvIndex->publicArea.dataSize - offset));
947
0
      NvRead(data, locator + sizeof(NV_INDEX) + offset, size);
948
0
  }
949
0
    return;
950
0
}
951
952
//*** NvHashIndexData()
953
// This function adds Index data to a hash. It does this in parts to avoid large stack
954
// buffers.
955
void NvHashIndexData(HASH_STATE* hashState,  // IN: Initialized hash state
956
         NV_INDEX*   nvIndex,    // IN: Index
957
         NV_REF      locator,    // IN: where the data is located
958
         UINT32      offset,     // IN: starting offset
959
         UINT16      size        // IN: amount to hash
960
         )
961
0
{
962
0
#define BUFFER_SIZE 64
963
0
    BYTE buffer[BUFFER_SIZE];
964
0
    if(offset > nvIndex->publicArea.dataSize)
965
0
  return;
966
    // Make sure that we don't try to read off the end.
967
0
    if((offset + size) > nvIndex->publicArea.dataSize)
968
0
  size = nvIndex->publicArea.dataSize - (UINT16)offset;
969
#if BUFFER_SIZE >= MAX_NV_INDEX_SIZE
970
    NvGetIndexData(nvIndex, locator, offset, size, buffer);
971
    CryptDigestUpdate(hashState, size, buffer);
972
#else
973
0
    {
974
0
  INT16  i;
975
0
  UINT16 readSize;
976
  //
977
0
  for(i = size; i > 0; offset += readSize, i -= readSize)
978
0
      {
979
0
    readSize = (i < BUFFER_SIZE) ? i : BUFFER_SIZE;
980
0
    NvGetIndexData(nvIndex, locator, offset, readSize, buffer);
981
0
    CryptDigestUpdate(hashState, readSize, buffer);
982
0
      }
983
0
    }
984
0
#endif  // BUFFER_SIZE >= MAX_NV_INDEX_SIZE
985
0
#undef BUFFER_SIZE
986
0
}
987
988
//*** NvGetUINT64Data()
989
// Get data in integer format of a bit or counter NV Index.
990
//
991
// This function requires that the NV Index is defined and that the NV Index
992
// previously has been written.
993
UINT64
994
NvGetUINT64Data(NV_INDEX* nvIndex,  // IN: the in RAM index descriptor
995
    NV_REF    locator   // IN: where index exists in NV
996
    )
997
0
{
998
0
    UINT64 intVal;
999
    //
1000
    // Read the value and convert it to internal format
1001
0
    NvGetIndexData(nvIndex, locator, 0, 8, &intVal);
1002
0
    return BYTE_ARRAY_TO_UINT64(((BYTE*)&intVal));
1003
0
}
1004
1005
//*** NvWriteIndexAttributes()
1006
// This function is used to write just the attributes of an index.
1007
//  Return type: TPM_RC
1008
//      TPM_RC_NV_RATE          NV is rate limiting so retry
1009
//      TPM_RC_NV_UNAVAILABLE   NV is not available
1010
TPM_RC
1011
NvWriteIndexAttributes(TPM_HANDLE handle,
1012
           NV_REF     locator,    // IN: location of the index
1013
           TPMA_NV    attributes  // IN: attributes to write
1014
           )
1015
0
{
1016
0
    TPM_RC result;
1017
    //
1018
0
    if(IS_ATTRIBUTE(attributes, TPMA_NV, ORDERLY))
1019
0
  {
1020
0
      NV_RAM_REF ram = NvRamGetIndex(handle);
1021
0
      NvWriteRamIndexAttributes(ram, attributes);
1022
0
      result = TPM_RC_SUCCESS;
1023
0
  }
1024
0
    else
1025
0
  {
1026
0
      result = NvWriteNvIndexAttributes(locator, attributes);
1027
0
  }
1028
0
    return result;
1029
0
}
1030
1031
//*** NvWriteIndexAuth()
1032
// This function is used to write the authValue of an index. It is used by
1033
// TPM2_NV_ChangeAuth()
1034
//  Return type: TPM_RC
1035
//      TPM_RC_NV_RATE          NV is rate limiting so retry
1036
//      TPM_RC_NV_UNAVAILABLE   NV is not available
1037
TPM_RC
1038
NvWriteIndexAuth(NV_REF      locator,   // IN: location of the index
1039
     TPM2B_AUTH* authValue  // IN: the authValue to write
1040
     )
1041
0
{
1042
0
    TPM_RC result;
1043
    //
1044
    // If the locator is pointing to the cached index value...
1045
0
    if(locator == s_cachedNvRef)
1046
0
  {
1047
      // copy the authValue to the cached index so it will be there if we
1048
      // look for it. This is a safety thing.
1049
0
      MemoryCopy2B(&s_cachedNvIndex.authValue.b,
1050
0
       &authValue->b,
1051
0
       sizeof(s_cachedNvIndex.authValue.t.buffer));
1052
0
  }
1053
0
    result = NvConditionallyWrite(locator + offsetof(NV_INDEX, authValue),
1054
0
          sizeof(UINT16) + authValue->t.size,
1055
0
          authValue);
1056
0
    return result;
1057
0
}
1058
1059
//*** NvGetIndexInfo()
1060
// This function loads the nvIndex Info into the NV cache and returns a pointer
1061
// to the NV_INDEX. If the returned value is zero, the index was not found.
1062
// The 'locator' parameter, if not NULL, will be set to the offset in NV of the
1063
// Index (the location of the handle of the Index).
1064
//
1065
// This function will set the index cache. If the index is orderly, the attributes
1066
// from RAM are substituted for the attributes in the cached index
1067
NV_INDEX* NvGetIndexInfo(TPM_HANDLE nvHandle,  // IN: the index handle
1068
       NV_REF*    locator    // OUT: location of the index
1069
       )
1070
40
{
1071
40
    if(s_cachedNvIndex.publicArea.nvIndex != nvHandle)
1072
40
  {
1073
40
      s_cachedNvIndex.publicArea.nvIndex = TPM_RH_UNASSIGNED;
1074
40
      s_cachedNvRamRef                   = 0;
1075
40
      s_cachedNvRef                      = NvFindHandle(nvHandle);
1076
40
      if(s_cachedNvRef == 0)
1077
40
    return NULL;
1078
0
      NvReadNvIndexInfo(s_cachedNvRef, &s_cachedNvIndex);
1079
0
      if(IS_ATTRIBUTE(s_cachedNvIndex.publicArea.attributes, TPMA_NV, ORDERLY))
1080
0
    {
1081
0
        s_cachedNvRamRef = NvRamGetIndex(nvHandle);
1082
0
        s_cachedNvIndex.publicArea.attributes =
1083
0
      NvReadRamIndexAttributes(s_cachedNvRamRef);
1084
0
    }
1085
0
  }
1086
0
    if(locator != NULL)
1087
0
  *locator = s_cachedNvRef;
1088
0
    return &s_cachedNvIndex;
1089
40
}
1090
1091
//*** NvWriteIndexData()
1092
// This function is used to write NV index data. It is intended to be used to
1093
// update the data associated with the default index.
1094
//
1095
// This function requires that the NV Index is defined, and the data is
1096
// within the defined data range for the index.
1097
//
1098
// Index data is only written due to a command that modifies the data in a single
1099
// index. There is no case where changes are made to multiple indexes data at the
1100
// same time. Multiple attributes may be change but not multiple index data. This
1101
// is important because we will normally be handling the index for which we have
1102
// the cached pointer values.
1103
//  Return type: TPM_RC
1104
//      TPM_RC_NV_RATE          NV is rate limiting so retry
1105
//      TPM_RC_NV_UNAVAILABLE   NV is not available
1106
TPM_RC
1107
NvWriteIndexData(NV_INDEX* nvIndex,  // IN: the description of the index
1108
     UINT32    offset,   // IN: offset of NV data
1109
     UINT32    size,     // IN: size of NV data
1110
     void*     data      // IN: data buffer
1111
     )
1112
0
{
1113
0
    TPM_RC result = TPM_RC_SUCCESS;
1114
    //
1115
0
    pAssert(nvIndex != NULL);
1116
    // Make sure that this is dealing with the 'default' index.
1117
    // Note: it is tempting to change the calling sequence so that the 'default' is
1118
    // presumed.
1119
0
    pAssert(nvIndex->publicArea.nvIndex == s_cachedNvIndex.publicArea.nvIndex);
1120
1121
    // Validate that write falls within range of the index
1122
0
    pAssert(offset <= nvIndex->publicArea.dataSize
1123
0
      && size <= (nvIndex->publicArea.dataSize - offset));
1124
1125
    // Update TPMA_NV_WRITTEN bit if necessary
1126
0
    if(!IS_ATTRIBUTE(nvIndex->publicArea.attributes, TPMA_NV, WRITTEN))
1127
0
  {
1128
      // Update the in memory version of the attributes
1129
0
      SET_ATTRIBUTE(nvIndex->publicArea.attributes, TPMA_NV, WRITTEN);
1130
1131
      // If this is not orderly, then update the NV version of
1132
      // the attributes
1133
0
      if(!IS_ATTRIBUTE(nvIndex->publicArea.attributes, TPMA_NV, ORDERLY))
1134
0
    {
1135
0
        result = NvWriteNvIndexAttributes(s_cachedNvRef,
1136
0
                  nvIndex->publicArea.attributes);
1137
0
        if(result != TPM_RC_SUCCESS)
1138
0
      return result;
1139
        // If this is a partial write of an ordinary index, clear the whole
1140
        // index.
1141
0
        if(IsNvOrdinaryIndex(nvIndex->publicArea.attributes)
1142
0
           && (nvIndex->publicArea.dataSize > size))
1143
0
      _plat__NvMemoryClear(s_cachedNvRef + sizeof(NV_INDEX),
1144
0
               nvIndex->publicArea.dataSize);
1145
0
    }
1146
0
      else
1147
0
    {
1148
        // This is orderly so update the RAM version
1149
0
        MemoryCopy(s_cachedNvRamRef + offsetof(NV_RAM_HEADER, attributes),
1150
0
             &nvIndex->publicArea.attributes,
1151
0
             sizeof(TPMA_NV));
1152
        // If setting WRITTEN for an orderly counter, make sure that the
1153
        // state saved version of the counter is saved
1154
0
        if(IsNvCounterIndex(nvIndex->publicArea.attributes))
1155
0
      SET_NV_UPDATE(UT_ORDERLY);
1156
        // If setting the written attribute on an ordinary index, make sure that
1157
        // the data is all cleared out in case there is a partial write. This
1158
        // is only necessary for ordinary indexes because all of the other types
1159
        // are always written in total.
1160
0
        else if(IsNvOrdinaryIndex(nvIndex->publicArea.attributes))
1161
0
      MemorySet(s_cachedNvRamRef + sizeof(NV_RAM_HEADER),
1162
0
          0,
1163
0
          nvIndex->publicArea.dataSize);
1164
0
    }
1165
0
  }
1166
    // If this is orderly data, write it to RAM
1167
0
    if(IS_ATTRIBUTE(nvIndex->publicArea.attributes, TPMA_NV, ORDERLY))
1168
0
  {
1169
      // Note: if this is the first write to a counter, the code above will queue
1170
      // the write to NV of the RAM data in order to update TPMA_NV_WRITTEN. In
1171
      // process of doing that write, it will also write the initial counter value
1172
1173
      // Update RAM
1174
0
      MemoryCopy(s_cachedNvRamRef + sizeof(NV_RAM_HEADER) + offset, data, size);
1175
1176
      // And indicate that the TPM is no longer orderly
1177
0
      g_clearOrderly = TRUE;
1178
0
  }
1179
0
    else
1180
0
  {
1181
      // Offset into the index to the first byte of the data to be written to NV
1182
0
      result = NvConditionallyWrite(
1183
0
            s_cachedNvRef + sizeof(NV_INDEX) + offset, size, data);
1184
0
  }
1185
0
    return result;
1186
0
}
1187
1188
//*** NvWriteUINT64Data()
1189
// This function to write back a UINT64 value. The various UINT64 values (bits,
1190
// counters, and PINs) are kept in canonical format but manipulate in native
1191
// format. This takes a native format value converts it and saves it back as
1192
// in canonical format.
1193
//
1194
// This function will return the value from NV or RAM depending on the type of the
1195
// index (orderly or not)
1196
//
1197
TPM_RC
1198
NvWriteUINT64Data(NV_INDEX* nvIndex,  // IN: the description of the index
1199
      UINT64    intValue  // IN: the value to write
1200
      )
1201
0
{
1202
0
    BYTE bytes[8];
1203
0
    UINT64_TO_BYTE_ARRAY(intValue, bytes);
1204
    //
1205
0
    return NvWriteIndexData(nvIndex, 0, 8, &bytes);
1206
0
}
1207
1208
//*** NvGetNameByIndexHandle()
1209
// This function is used to compute the Name of an NV Index referenced by handle.
1210
//
1211
// The 'name' buffer receives the bytes of the Name and the return value
1212
// is the number of octets in the Name.
1213
//
1214
// This function requires that the NV Index is defined.
1215
TPM2B_NAME* NvGetNameByIndexHandle(
1216
           TPMI_RH_NV_INDEX handle,  // IN: handle of the index
1217
           TPM2B_NAME*      name     // OUT: name of the index
1218
           )
1219
0
{
1220
0
    NV_INDEX* nvIndex = NvGetIndexInfo(handle, NULL);
1221
    //
1222
0
    return NvGetIndexName(nvIndex, name);
1223
0
}
1224
1225
//*** NvDefineIndex()
1226
// This function is used to assign NV memory to an NV Index.
1227
//
1228
//  Return Type: TPM_RC
1229
//      TPM_RC_NV_SPACE         insufficient NV space
1230
TPM_RC
1231
NvDefineIndex(TPMS_NV_PUBLIC* publicArea,  // IN: A template for an area to create.
1232
        TPM2B_AUTH*     authValue    // IN: The initial authorization value
1233
        )
1234
75
{
1235
    // The buffer to be written to NV memory
1236
75
    NV_INDEX nvIndex;    // the index data
1237
75
    UINT16   entrySize;  // size of entry
1238
75
    TPM_RC   result;
1239
    //
1240
75
    entrySize = sizeof(NV_INDEX);
1241
1242
    // only allocate data space for indexes that are going to be written to NV.
1243
    // Orderly indexes don't need space.
1244
75
    if(!IS_ATTRIBUTE(publicArea->attributes, TPMA_NV, ORDERLY))
1245
44
  entrySize += publicArea->dataSize;
1246
    // Check if we have enough space to create the NV Index
1247
    // In this implementation, the only resource limitation is the available NV
1248
    // space (and possibly RAM space.)  Other implementation may have other
1249
    // limitation on counter or on NV slots
1250
75
    if(!NvTestSpace(entrySize, TRUE, IsNvCounterIndex(publicArea->attributes)))
1251
0
  return TPM_RC_NV_SPACE;
1252
1253
    // if the index to be defined is RAM backed, check RAM space availability
1254
    // as well
1255
75
    if(IS_ATTRIBUTE(publicArea->attributes, TPMA_NV, ORDERLY)
1256
75
       && !NvRamTestSpaceIndex(publicArea->dataSize))
1257
7
  return TPM_RC_NV_SPACE;
1258
    // Copy input value to nvBuffer
1259
68
    nvIndex.publicArea = *publicArea;
1260
1261
    // Copy the authValue
1262
68
    nvIndex.authValue = *authValue;
1263
1264
    // Add index to NV memory
1265
68
    result = NvAdd(entrySize, sizeof(NV_INDEX), TPM_RH_UNASSIGNED, (BYTE*)&nvIndex);
1266
68
    if(result == TPM_RC_SUCCESS)
1267
68
  {
1268
      // If the data of NV Index is RAM backed, add the data area in RAM as well
1269
68
      if(IS_ATTRIBUTE(publicArea->attributes, TPMA_NV, ORDERLY))
1270
24
    NvAddRAM(publicArea);
1271
68
  }
1272
68
    return result;
1273
75
}
1274
1275
static TPM_RC           // libtpms added begin
1276
NvWriteObject(OBJECT* object)
1277
0
{
1278
0
    UINT32 sizeOfObject;
1279
0
    BYTE   buffer[MAX_MARSHALLED_OBJECT_SIZE];
1280
1281
0
    sizeOfObject = NvObjectToBuffer(object, buffer, sizeof(buffer));
1282
1283
0
    if(!NvTestSpace(sizeOfObject + sizeof(TPM_HANDLE), FALSE, FALSE))
1284
0
  return TPM_RC_NV_SPACE;
1285
1286
    // Now put this in NV
1287
0
    return NvAdd(sizeOfObject, sizeOfObject, object->evictHandle, buffer);
1288
0
}              // libtpms added end
1289
1290
//*** NvAddEvictObject()
1291
// This function is used to assign NV memory to a persistent object.
1292
//  Return Type: TPM_RC
1293
//      TPM_RC_NV_HANDLE        the requested handle is already in use
1294
//      TPM_RC_NV_SPACE         insufficient NV space
1295
TPM_RC
1296
NvAddEvictObject(TPMI_DH_OBJECT evictHandle,  // IN: new evict handle
1297
     OBJECT*        object        // IN: object to be added
1298
     )
1299
0
{
1300
0
    TPM_HANDLE temp = object->evictHandle;
1301
0
    TPM_RC     result;
1302
#if 0             // libtpms added
1303
    //
1304
    // Check if we have enough space to add the evict object
1305
    // An evict object needs 8 bytes in index table + sizeof OBJECT
1306
    // In this implementation, the only resource limitation is the available NV
1307
    // space.  Other implementation may have other limitation on evict object
1308
    // handle space
1309
    if(!NvTestSpace(sizeof(OBJECT) + sizeof(TPM_HANDLE), FALSE, FALSE))
1310
  return TPM_RC_NV_SPACE;
1311
#endif              // libtpms added
1312
1313
    // Set evict attribute and handle
1314
0
    object->attributes.evict = SET;
1315
0
    object->evictHandle      = evictHandle;
1316
1317
    // Now put this in NV
1318
0
    result = NvWriteObject(object);     // libtpms changed
1319
1320
    // Put things back the way they were
1321
0
    object->attributes.evict = CLEAR;
1322
0
    object->evictHandle      = temp;
1323
1324
0
    return result;
1325
0
}
1326
1327
//*** NvDeleteIndex()
1328
// This function is used to delete an NV Index.
1329
//  Return Type: TPM_RC
1330
//      TPM_RC_NV_UNAVAILABLE   NV is not accessible
1331
//      TPM_RC_NV_RATE          NV is rate limiting
1332
TPM_RC
1333
NvDeleteIndex(NV_INDEX* nvIndex,    // IN: an in RAM index descriptor
1334
        NV_REF    entityAddr  // IN: location in NV
1335
        )
1336
0
{
1337
0
    TPM_RC result;
1338
    //
1339
0
    if(nvIndex != NULL)
1340
0
  {
1341
      // Whenever a counter is deleted, make sure that the MaxCounter value is
1342
      // updated to reflect the value
1343
0
      if(IsNvCounterIndex(nvIndex->publicArea.attributes)
1344
0
         && IS_ATTRIBUTE(nvIndex->publicArea.attributes, TPMA_NV, WRITTEN))
1345
0
    NvUpdateMaxCount(NvGetUINT64Data(nvIndex, entityAddr));
1346
0
      result = NvDelete(entityAddr);
1347
0
      if(result != TPM_RC_SUCCESS)
1348
0
    return result;
1349
      // If the NV Index is RAM backed, delete the RAM data as well
1350
0
      if(IS_ATTRIBUTE(nvIndex->publicArea.attributes, TPMA_NV, ORDERLY))
1351
0
    NvDeleteRAM(nvIndex->publicArea.nvIndex);
1352
0
      NvIndexCacheInit();
1353
0
  }
1354
0
    return TPM_RC_SUCCESS;
1355
0
}
1356
1357
//*** NvDeleteEvict()
1358
// This function will delete a NV evict object.
1359
// Will return success if object deleted or if it does not exist
1360
1361
TPM_RC
1362
NvDeleteEvict(TPM_HANDLE handle  // IN: handle of entity to be deleted
1363
        )
1364
0
{
1365
0
    NV_REF entityAddr = NvFindEvict(handle, NULL);  // pointer to entity
1366
0
    TPM_RC result     = TPM_RC_SUCCESS;
1367
    //
1368
0
    if(entityAddr != 0)
1369
0
  result = NvDelete(entityAddr);
1370
0
    return result;
1371
0
}
1372
1373
//*** NvFlushHierarchy()
1374
// This function will delete persistent objects belonging to the indicated hierarchy.
1375
// If the storage hierarchy is selected, the function will also delete any
1376
// NV Index defined using ownerAuth.
1377
//  Return Type: TPM_RC
1378
//      TPM_RC_NV_RATE           NV is unavailable because of rate limit
1379
//      TPM_RC_NV_UNAVAILABLE    NV is inaccessible
1380
TPM_RC
1381
NvFlushHierarchy(TPMI_RH_HIERARCHY hierarchy  // IN: hierarchy to be flushed.
1382
     )
1383
6
{
1384
6
    NV_REF     iter = NV_REF_INIT;
1385
6
    NV_REF     currentAddr;
1386
6
    TPM_HANDLE entityHandle;
1387
6
    TPM_RC     result = TPM_RC_SUCCESS;
1388
    //
1389
6
    while((currentAddr = NvNext(&iter, &entityHandle)) != 0)
1390
0
  {
1391
0
      if(HandleGetType(entityHandle) == TPM_HT_NV_INDEX)
1392
0
    {
1393
0
        NV_INDEX nvIndex;
1394
        //
1395
        // If flush endorsement or platform hierarchy, no NV Index would be
1396
        // flushed
1397
0
        if(hierarchy == TPM_RH_ENDORSEMENT || hierarchy == TPM_RH_PLATFORM)
1398
0
      continue;
1399
        // Get the index information
1400
0
        NvReadNvIndexInfo(currentAddr, &nvIndex);
1401
1402
        // For storage hierarchy, flush OwnerCreated index
1403
0
        if(!IS_ATTRIBUTE(nvIndex.publicArea.attributes, TPMA_NV, PLATFORMCREATE))
1404
0
      {
1405
          // Delete the index (including RAM for orderly)
1406
0
          result = NvDeleteIndex(&nvIndex, currentAddr);
1407
0
          if(result != TPM_RC_SUCCESS)
1408
0
        break;
1409
          // Re-iterate from beginning after a delete
1410
0
          iter = NV_REF_INIT;
1411
0
      }
1412
0
    }
1413
0
      else if(HandleGetType(entityHandle) == TPM_HT_PERSISTENT)
1414
0
    {
1415
0
        OBJECT_ATTRIBUTES attributes;
1416
        //
1417
0
        NvRead(&attributes,
1418
0
         (UINT32)(currentAddr + sizeof(TPM_HANDLE)
1419
0
            + offsetof(OBJECT, attributes)),
1420
0
         sizeof(OBJECT_ATTRIBUTES));
1421
        // If the evict object belongs to the hierarchy to be flushed...
1422
0
        if((hierarchy == TPM_RH_PLATFORM && attributes.ppsHierarchy == SET)
1423
0
           || (hierarchy == TPM_RH_OWNER && attributes.spsHierarchy == SET)
1424
0
           || (hierarchy == TPM_RH_ENDORSEMENT && attributes.epsHierarchy == SET))
1425
0
      {
1426
          // ...then delete the evict object
1427
0
          result = NvDelete(currentAddr);
1428
0
          if(result != TPM_RC_SUCCESS)
1429
0
        break;
1430
          // Re-iterate from beginning after a delete
1431
0
          iter = NV_REF_INIT;
1432
0
      }
1433
0
    }
1434
0
      else
1435
0
    {
1436
0
        FAIL(FATAL_ERROR_INTERNAL);
1437
0
    }
1438
0
  }
1439
6
    return result;
1440
6
}
1441
1442
//*** NvSetGlobalLock()
1443
// This function is used to SET the TPMA_NV_WRITELOCKED attribute for all
1444
// NV indexes that have TPMA_NV_GLOBALLOCK SET. This function is use by
1445
// TPM2_NV_GlobalWriteLock().
1446
//  Return Type: TPM_RC
1447
//      TPM_RC_NV_RATE           NV is unavailable because of rate limit
1448
//      TPM_RC_NV_UNAVAILABLE    NV is inaccessible
1449
TPM_RC
1450
NvSetGlobalLock(void)
1451
2
{
1452
2
    NV_REF     iter    = NV_REF_INIT;
1453
2
    NV_RAM_REF ramIter = NV_RAM_REF_INIT;
1454
2
    NV_REF     currentAddr;
1455
2
    NV_RAM_REF currentRamAddr;
1456
2
    TPM_RC     result = TPM_RC_SUCCESS;
1457
    //
1458
    // Check all normal indexes
1459
2
    while((currentAddr = NvNextIndex(NULL, &iter)) != 0)
1460
0
  {
1461
0
      TPMA_NV attributes = NvReadNvIndexAttributes(currentAddr);
1462
      //
1463
      // See if it should be locked
1464
0
      if(!IS_ATTRIBUTE(attributes, TPMA_NV, ORDERLY)
1465
0
         && IS_ATTRIBUTE(attributes, TPMA_NV, GLOBALLOCK))
1466
0
    {
1467
0
        SET_ATTRIBUTE(attributes, TPMA_NV, WRITELOCKED);
1468
0
        result = NvWriteNvIndexAttributes(currentAddr, attributes);
1469
0
        if(result != TPM_RC_SUCCESS)
1470
0
      return result;
1471
0
    }
1472
0
  }
1473
    // Now search all the orderly attributes
1474
2
    while((currentRamAddr = NvRamNext(&ramIter, NULL)) != 0)
1475
0
  {
1476
      // See if it should be locked
1477
0
      TPMA_NV attributes = NvReadRamIndexAttributes(currentRamAddr);
1478
0
      if(IS_ATTRIBUTE(attributes, TPMA_NV, GLOBALLOCK))
1479
0
    {
1480
0
        SET_ATTRIBUTE(attributes, TPMA_NV, WRITELOCKED);
1481
0
        NvWriteRamIndexAttributes(currentRamAddr, attributes);
1482
0
    }
1483
0
  }
1484
2
    return result;
1485
2
}
1486
1487
//***InsertSort()
1488
// Sort a handle into handle list in ascending order.  The total handle number in
1489
// the list should not exceed MAX_CAP_HANDLES
1490
static void InsertSort(TPML_HANDLE* handleList,  // IN/OUT: sorted handle list
1491
           UINT32       count,  // IN: maximum count in the handle list
1492
           TPM_HANDLE   entityHandle  // IN: handle to be inserted
1493
           )
1494
0
{
1495
0
    UINT32 i, j;
1496
0
    UINT32 originalCount;
1497
    //
1498
    // For a corner case that the maximum count is 0, do nothing
1499
0
    if(count == 0)
1500
0
  return;
1501
    // For empty list, add the handle at the beginning and return
1502
0
    if(handleList->count == 0)
1503
0
  {
1504
0
      handleList->handle[0] = entityHandle;
1505
0
      handleList->count++;
1506
0
      return;
1507
0
  }
1508
    // Check if the maximum of the list has been reached
1509
0
    originalCount = handleList->count;
1510
0
    if(originalCount < count)
1511
0
  handleList->count++;
1512
    // Insert the handle to the list
1513
0
    for(i = 0; i < originalCount; i++)
1514
0
  {
1515
0
      if(handleList->handle[i] > entityHandle)
1516
0
    {
1517
0
        for(j = handleList->count - 1; j > i; j--)
1518
0
      {
1519
0
          handleList->handle[j] = handleList->handle[j - 1];
1520
0
      }
1521
0
        break;
1522
0
    }
1523
0
  }
1524
    // If a slot was found, insert the handle in this position
1525
0
    if(i < originalCount || handleList->count > originalCount)
1526
0
  handleList->handle[i] = entityHandle;
1527
0
    return;
1528
0
}
1529
1530
//*** NvCapGetPersistent()
1531
// This function is used to get a list of handles of the persistent objects,
1532
// starting at 'handle'.
1533
//
1534
// 'Handle' must be in valid persistent object handle range, but does not
1535
// have to reference an existing persistent object.
1536
//  Return Type: TPMI_YES_NO
1537
//      YES         if there are more handles available
1538
//      NO          all the available handles has been returned
1539
TPMI_YES_NO
1540
NvCapGetPersistent(TPMI_DH_OBJECT handle,  // IN: start handle
1541
       UINT32         count,   // IN: maximum number of returned handles
1542
       TPML_HANDLE*   handleList  // OUT: list of handle
1543
       )
1544
35
{
1545
35
    TPMI_YES_NO more = NO;
1546
35
    NV_REF      iter = NV_REF_INIT;
1547
35
    NV_REF      currentAddr;
1548
35
    TPM_HANDLE  entityHandle;
1549
    //
1550
35
    pAssert(HandleGetType(handle) == TPM_HT_PERSISTENT);
1551
1552
    // Initialize output handle list
1553
35
    handleList->count = 0;
1554
1555
    // The maximum count of handles we may return is MAX_CAP_HANDLES
1556
35
    if(count > MAX_CAP_HANDLES)
1557
30
  count = MAX_CAP_HANDLES;
1558
1559
35
    while((currentAddr = NvNextEvict(&entityHandle, &iter)) != 0)
1560
0
  {
1561
      // Ignore persistent handles that have values less than the input handle
1562
0
      if(entityHandle < handle)
1563
0
    continue;
1564
      // if the handles in the list have reached the requested count, and there
1565
      // are still handles need to be inserted, indicate that there are more.
1566
0
      if(handleList->count == count)
1567
0
    more = YES;
1568
      // A handle with a value larger than start handle is a candidate
1569
      // for return. Insert sort it to the return list.  Insert sort algorithm
1570
      // is chosen here for simplicity based on the assumption that the total
1571
      // number of NV indexes is small.  For an implementation that may allow
1572
      // large number of NV indexes, a more efficient sorting algorithm may be
1573
      // used here.
1574
0
      InsertSort(handleList, count, entityHandle);
1575
0
  }
1576
35
    return more;
1577
35
}
1578
1579
//*** NvCapGetOnePersistent()
1580
// This function returns whether a given persistent handle exists.
1581
//
1582
// 'Handle' must be in valid persistent object handle range.
1583
BOOL NvCapGetOnePersistent(TPMI_DH_OBJECT handle)  // IN: handle
1584
0
{
1585
0
    NV_REF     iter = NV_REF_INIT;
1586
0
    NV_REF     currentAddr;
1587
0
    TPM_HANDLE entityHandle;
1588
1589
0
    pAssert(HandleGetType(handle) == TPM_HT_PERSISTENT);
1590
1591
0
    while((currentAddr = NvNextEvict(&entityHandle, &iter)) != 0)
1592
0
  {
1593
0
      if(entityHandle == handle)
1594
0
    {
1595
0
        return TRUE;
1596
0
    }
1597
0
  }
1598
0
    return FALSE;
1599
0
}
1600
1601
//*** NvCapGetIndex()
1602
// This function returns a list of handles of NV indexes, starting from 'handle'.
1603
// 'Handle' must be in the range of NV indexes, but does not have to reference
1604
// an existing NV Index.
1605
//  Return Type: TPMI_YES_NO
1606
//      YES         if there are more handles to report
1607
//      NO          all the available handles has been reported
1608
TPMI_YES_NO
1609
NvCapGetIndex(TPMI_DH_OBJECT handle,     // IN: start handle
1610
        UINT32         count,      // IN: max number of returned handles
1611
        TPML_HANDLE*   handleList  // OUT: list of handle
1612
        )
1613
46
{
1614
46
    TPMI_YES_NO more = NO;
1615
46
    NV_REF      iter = NV_REF_INIT;
1616
46
    NV_REF      currentAddr;
1617
46
    TPM_HANDLE  nvHandle;
1618
    //
1619
46
    pAssert(HandleGetType(handle) == TPM_HT_NV_INDEX);
1620
1621
    // Initialize output handle list
1622
46
    handleList->count = 0;
1623
1624
    // The maximum count of handles we may return is MAX_CAP_HANDLES
1625
46
    if(count > MAX_CAP_HANDLES)
1626
38
  count = MAX_CAP_HANDLES;
1627
1628
46
    while((currentAddr = NvNextIndex(&nvHandle, &iter)) != 0)
1629
0
  {
1630
      // Ignore index handles that have values less than the 'handle'
1631
0
      if(nvHandle < handle)
1632
0
    continue;
1633
      // if the count of handles in the list has reached the requested count,
1634
      // and there are still handles to report, set more.
1635
0
      if(handleList->count == count)
1636
0
    more = YES;
1637
      // A handle with a value larger than start handle is a candidate
1638
      // for return. Insert sort it to the return list.  Insert sort algorithm
1639
      // is chosen here for simplicity based on the assumption that the total
1640
      // number of NV indexes is small.  For an implementation that may allow
1641
      // large number of NV indexes, a more efficient sorting algorithm may be
1642
      // used here.
1643
0
      InsertSort(handleList, count, nvHandle);
1644
0
  }
1645
46
    return more;
1646
46
}
1647
1648
//*** NvCapGetOneIndex()
1649
// This function whether an NV index exists.
1650
BOOL NvCapGetOneIndex(TPMI_DH_OBJECT handle)  // IN: handle
1651
0
{
1652
0
    NV_REF     iter = NV_REF_INIT;
1653
0
    NV_REF     currentAddr;
1654
0
    TPM_HANDLE nvHandle;
1655
1656
0
    pAssert(HandleGetType(handle) == TPM_HT_NV_INDEX);
1657
1658
0
    while((currentAddr = NvNextIndex(&nvHandle, &iter)) != 0)
1659
0
  {
1660
0
      if(nvHandle == handle)
1661
0
    {
1662
0
        return TRUE;
1663
0
    }
1664
0
  }
1665
0
    return FALSE;
1666
0
}
1667
1668
//*** NvCapGetIndexNumber()
1669
// This function returns the count of NV Indexes currently defined.
1670
UINT32
1671
NvCapGetIndexNumber(void)
1672
1
{
1673
1
    UINT32 num  = 0;
1674
1
    NV_REF iter = NV_REF_INIT;
1675
    //
1676
1
    while(NvNextIndex(NULL, &iter) != 0)
1677
0
  num++;
1678
1
    return num;
1679
1
}
1680
1681
//*** NvCapGetPersistentNumber()
1682
// Function returns the count of persistent objects currently in NV memory.
1683
UINT32
1684
NvCapGetPersistentNumber(void)
1685
77
{
1686
77
    UINT32     num  = 0;
1687
77
    NV_REF     iter = NV_REF_INIT;
1688
77
    TPM_HANDLE handle;
1689
    //
1690
77
    while(NvNextEvict(&handle, &iter) != 0)
1691
0
  num++;
1692
77
    return num;
1693
77
}
1694
1695
//*** NvCapGetPersistentAvail()
1696
// This function returns an estimate of the number of additional persistent
1697
// objects that could be loaded into NV memory.
1698
UINT32
1699
NvCapGetPersistentAvail(void)
1700
1
{
1701
1
    UINT32 availNVSpace;
1702
1
    UINT32 counterNum = NvCapGetCounterNumber();
1703
1
    UINT32 reserved   = sizeof(NV_LIST_TERMINATOR);
1704
    //
1705
    // Get the available space in NV storage
1706
1
    availNVSpace = NvGetFreeBytes();
1707
1708
1
    if(counterNum < MIN_COUNTER_INDICES)
1709
1
  {
1710
      // Some space has to be reserved for counter objects.
1711
1
      reserved += (MIN_COUNTER_INDICES - counterNum) * NV_INDEX_COUNTER_SIZE;
1712
1
      if(reserved > availNVSpace)
1713
0
    availNVSpace = 0;
1714
1
      else
1715
1
    availNVSpace -= reserved;
1716
1
  }
1717
1
    return availNVSpace / NV_EVICT_OBJECT_SIZE;
1718
1
}
1719
1720
//*** NvCapGetCounterNumber()
1721
// Get the number of defined NV Indexes that are counter indexes.
1722
UINT32
1723
NvCapGetCounterNumber(void)
1724
76
{
1725
76
    NV_REF iter = NV_REF_INIT;
1726
76
    NV_REF currentAddr;
1727
76
    UINT32 num = 0;
1728
    //
1729
76
    while((currentAddr = NvNextIndex(NULL, &iter)) != 0)
1730
0
  {
1731
0
      TPMA_NV attributes = NvReadNvIndexAttributes(currentAddr);
1732
0
      if(IsNvCounterIndex(attributes))
1733
0
    num++;
1734
0
  }
1735
76
    return num;
1736
76
}
1737
1738
//*** NvSetStartupAttributes()
1739
// Local function to set the attributes of an Index at TPM Reset and TPM Restart.
1740
static TPMA_NV NvSetStartupAttributes(TPMA_NV attributes,  // IN: attributes to change
1741
              STARTUP_TYPE type    // IN: start up type
1742
              )
1743
0
{
1744
    // Clear read lock
1745
0
    CLEAR_ATTRIBUTE(attributes, TPMA_NV, READLOCKED);
1746
1747
    // Will change a non counter index to the unwritten state if:
1748
    // a) TPMA_NV_CLEAR_STCLEAR is SET
1749
    // b) orderly and TPM Reset
1750
0
    if(!IsNvCounterIndex(attributes))
1751
0
  {
1752
0
      if(IS_ATTRIBUTE(attributes, TPMA_NV, CLEAR_STCLEAR)
1753
0
         || (IS_ATTRIBUTE(attributes, TPMA_NV, ORDERLY) && (type == SU_RESET)))
1754
0
    CLEAR_ATTRIBUTE(attributes, TPMA_NV, WRITTEN);
1755
0
  }
1756
    // Unlock any index that is not written or that does not have
1757
    // TPMA_NV_WRITEDEFINE SET.
1758
0
    if(!IS_ATTRIBUTE(attributes, TPMA_NV, WRITTEN)
1759
0
       || !IS_ATTRIBUTE(attributes, TPMA_NV, WRITEDEFINE))
1760
0
  CLEAR_ATTRIBUTE(attributes, TPMA_NV, WRITELOCKED);
1761
0
    return attributes;
1762
0
}
1763
1764
//*** NvEntityStartup()
1765
//  This function is called at TPM_Startup(). If the startup completes
1766
//  a TPM Resume cycle, no action is taken. If the startup is a TPM Reset
1767
//  or a TPM Restart, then this function will:
1768
//  a) clear read/write lock;
1769
//  b) reset NV Index data that has TPMA_NV_CLEAR_STCLEAR SET; and
1770
//  c) set the lower bits in orderly counters to 1 for a non-orderly startup
1771
//
1772
//  It is a prerequisite that NV be available for writing before this
1773
//  function is called.
1774
BOOL NvEntityStartup(STARTUP_TYPE type  // IN: start up type
1775
         )
1776
5.96k
{
1777
5.96k
    NV_REF     iter    = NV_REF_INIT;
1778
5.96k
    NV_RAM_REF ramIter = NV_RAM_REF_INIT;
1779
5.96k
    NV_REF     currentAddr;  // offset points to the current entity
1780
5.96k
    NV_RAM_REF currentRamAddr;
1781
5.96k
    TPM_HANDLE nvHandle;
1782
5.96k
    TPMA_NV    attributes;
1783
    //
1784
    // Restore RAM index data
1785
5.96k
    NvRead(s_indexOrderlyRam, NV_INDEX_RAM_DATA, sizeof(s_indexOrderlyRam));
1786
1787
    // Initialize the max NV counter value
1788
5.96k
    NvSetMaxCount(NvGetMaxCount());
1789
1790
    // If recovering from state save, do nothing else
1791
5.96k
    if(type == SU_RESUME)
1792
0
  return TRUE;
1793
    // Iterate all the NV Index to clear the locks
1794
5.96k
    while((currentAddr = NvNextIndex(&nvHandle, &iter)) != 0)
1795
0
  {
1796
0
      attributes = NvReadNvIndexAttributes(currentAddr);
1797
1798
      // If this is an orderly index, defer processing until loop below
1799
0
      if(IS_ATTRIBUTE(attributes, TPMA_NV, ORDERLY))
1800
0
    continue;
1801
      // Set the attributes appropriate for this startup type
1802
0
      attributes = NvSetStartupAttributes(attributes, type);
1803
0
      NvWriteNvIndexAttributes(currentAddr, attributes);
1804
0
  }
1805
    // Iterate all the orderly indexes to clear the locks and initialize counters
1806
5.96k
    while((currentRamAddr = NvRamNext(&ramIter, NULL)) != 0)
1807
0
  {
1808
0
      attributes = NvReadRamIndexAttributes(currentRamAddr);
1809
1810
0
      attributes = NvSetStartupAttributes(attributes, type);
1811
1812
      // update attributes in RAM
1813
0
      NvWriteRamIndexAttributes(currentRamAddr, attributes);
1814
1815
      // Set the lower bits in an orderly counter to 1 for a non-orderly startup
1816
0
      if(IsNvCounterIndex(attributes) && (g_prevOrderlyState == SU_NONE_VALUE))
1817
0
    {
1818
0
        UINT64 counter;
1819
        //
1820
        // Read the counter value last saved to NV.
1821
0
        counter = BYTE_ARRAY_TO_UINT64(currentRamAddr + sizeof(NV_RAM_HEADER));
1822
1823
        // Set the lower bits of counter to 1's
1824
0
        counter |= MAX_ORDERLY_COUNT;
1825
1826
        // Write back to RAM
1827
        // NOTE: Do not want to force a write to NV here. The counter value will
1828
        // stay in RAM until the next shutdown or rollover.
1829
0
        UINT64_TO_BYTE_ARRAY(counter, currentRamAddr + sizeof(NV_RAM_HEADER));
1830
0
    }
1831
0
  }
1832
5.96k
    return TRUE;
1833
5.96k
}
1834
1835
//*** NvCapGetCounterAvail()
1836
// This function returns an estimate of the number of additional counter type
1837
// NV indexes that can be defined.
1838
UINT32
1839
NvCapGetCounterAvail(void)
1840
1
{
1841
1
    UINT32 availNVSpace;
1842
1
    UINT32 availRAMSpace;
1843
1
    UINT32 persistentNum = NvCapGetPersistentNumber();
1844
1
    UINT32 reserved      = sizeof(NV_LIST_TERMINATOR);
1845
    //
1846
    // Get the available space in NV storage
1847
1
    availNVSpace = NvGetFreeBytes();
1848
1849
1
    if(persistentNum < MIN_EVICT_OBJECTS)
1850
1
  {
1851
      // Some space has to be reserved for evict object. Adjust availNVSpace.
1852
1
      reserved += (MIN_EVICT_OBJECTS - persistentNum) * NV_EVICT_OBJECT_SIZE;
1853
1
      if(reserved > availNVSpace)
1854
0
    availNVSpace = 0;
1855
1
      else
1856
1
    availNVSpace -= reserved;
1857
1
  }
1858
    // Compute the available space in RAM
1859
1
    availRAMSpace = (RAM_ORDERLY_END - NvRamGetEnd());  /* kgold - removed cast */
1860
1861
    // Return the min of counter number in NV and in RAM
1862
1
    if(availNVSpace / NV_INDEX_COUNTER_SIZE
1863
1
       > availRAMSpace / NV_RAM_INDEX_COUNTER_SIZE)
1864
1
  return availRAMSpace / NV_RAM_INDEX_COUNTER_SIZE;
1865
0
    else
1866
0
  return availNVSpace / NV_INDEX_COUNTER_SIZE;
1867
1
}
1868
1869
//*** NvFindHandle()
1870
// this function returns the offset in NV memory of the entity associated
1871
// with the input handle.  A value of zero indicates that handle does not
1872
//  exist reference an existing persistent object or defined NV Index.
1873
NV_REF
1874
NvFindHandle(TPM_HANDLE handle)
1875
193
{
1876
193
    NV_REF     addr;
1877
193
    NV_REF     iter = NV_REF_INIT;
1878
193
    TPM_HANDLE nextHandle;
1879
    //
1880
193
    while((addr = NvNext(&iter, &nextHandle)) != 0)
1881
0
  {
1882
0
      if(nextHandle == handle)
1883
0
    break;
1884
0
  }
1885
193
    return addr;
1886
193
}
1887
1888
//** NV Max Counter
1889
//*** Introduction
1890
// The TPM keeps track of the highest value of a deleted counter index. When an
1891
// index is deleted, this value is updated if the deleted counter index is greater
1892
// than the previous value. When a new index is created and first incremented, it
1893
// will get a value that is at least one greater than any other index than any
1894
// previously deleted index. This insures that it is not possible to roll back an
1895
// index.
1896
//
1897
// The highest counter value is kept in NV in a special end-of-list marker. This
1898
// marker is only updated when an index is deleted. Otherwise it just moves.
1899
//
1900
// When the TPM starts up, it searches NV for the end of list marker and initializes
1901
// an in memory value (s_maxCounter).
1902
1903
//*** NvReadMaxCount()
1904
// This function returns the max NV counter value.
1905
//
1906
UINT64
1907
NvReadMaxCount(void)
1908
6.02k
{
1909
6.02k
    return s_maxCounter;
1910
6.02k
}
1911
1912
//*** NvUpdateMaxCount()
1913
// This function updates the max counter value to NV memory. This is just staging
1914
// for the actual write that will occur when the NV index memory is modified.
1915
//
1916
void NvUpdateMaxCount(UINT64 count)
1917
0
{
1918
0
    if(count > s_maxCounter)
1919
0
  s_maxCounter = count;
1920
0
}
1921
1922
//*** NvSetMaxCount()
1923
// This function is used at NV initialization time to set the initial value of
1924
// the maximum counter.
1925
void NvSetMaxCount(UINT64 value)
1926
11.9k
{
1927
11.9k
    s_maxCounter = value;
1928
11.9k
}
1929
1930
//*** NvGetMaxCount()
1931
// Function to get the NV max counter value from the end-of-list marker
1932
UINT64
1933
NvGetMaxCount(void)
1934
5.96k
{
1935
5.96k
    NV_REF iter = NV_REF_INIT;
1936
5.96k
    NV_REF currentAddr;
1937
5.96k
    UINT64 maxCount;
1938
    //
1939
    // Find the end of list marker and initialize the NV Max Counter value.
1940
5.96k
    while((currentAddr = NvNext(&iter, NULL)) != 0)
1941
0
  ;
1942
    // 'iter' should be pointing at the end of list marker so read in the current
1943
    // value of the s_maxCounter.
1944
5.96k
    NvRead(&maxCount, iter + sizeof(UINT32), sizeof(maxCount));
1945
1946
5.96k
    return maxCount;
1947
5.96k
}