/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 | } |