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