1 /* Microsoft Reference Implementation for TPM 2.0
2 *
3 * The copyright in this software is being made available under the BSD License,
4 * included below. This software may be subject to other third party and
5 * contributor rights, including patent rights, and no such rights are granted
6 * under this license.
7 *
8 * Copyright (c) Microsoft Corporation
9 *
10 * All rights reserved.
11 *
12 * BSD License
13 *
14 * Redistribution and use in source and binary forms, with or without modification,
15 * are permitted provided that the following conditions are met:
16 *
17 * Redistributions of source code must retain the above copyright notice, this list
18 * of conditions and the following disclaimer.
19 *
20 * Redistributions in binary form must reproduce the above copyright notice, this
21 * list of conditions and the following disclaimer in the documentation and/or
22 * other materials provided with the distribution.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ""AS IS""
25 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
28 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
31 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 */
35 //** Description
36 //
37 // This file contains the NV read and write access methods. This implementation
38 // uses RAM/file and does not manage the RAM/file as NV blocks.
39 // The implementation may become more sophisticated over time.
40 //
41
42 #include "TpmError.h"
43 #include "Admin.h"
44 #include "VendorString.h"
45 #include "stdint.h"
46 #include "malloc.h"
47 #include "string.h"
48
49 #include <tee_internal_api.h>
50 #include <tee_internal_api_extensions.h>
51
52 //
53 // Overall size of NV, not just the TPM's NV storage
54 //
55 #define NV_CHIP_MEMORY_SIZE (NV_MEMORY_SIZE + NV_TPM_STATE_SIZE)
56
57 //
58 // OpTEE still has an all or nothing approach to reads/writes. To provide
59 // more performant access to storage, break up NV accross 1Kbyte blocks.
60 //
61 // Note that NV_CHIP_MEMORY_SIZE *MUST* be a factor of NV_BLOCK_SIZE.
62 //
63 #define NV_BLOCK_SIZE 0x200
64 #define NV_BLOCK_COUNT ((NV_CHIP_MEMORY_SIZE) / (NV_BLOCK_SIZE))
65
66 //
67 // For cleaner descriptor validation
68 //
69 #define IS_VALID(a) ((a) != (TEE_HANDLE_NULL))
70
71 //
72 // Storage flags
73 //
74 #define TA_STORAGE_FLAGS (TEE_DATA_FLAG_ACCESS_READ | \
75 TEE_DATA_FLAG_ACCESS_WRITE | \
76 TEE_DATA_FLAG_ACCESS_WRITE_META)
77
78 //
79 // The base Object ID for fTPM storage
80 //
81 static const UINT32 s_StorageObjectID = 0x54504D00; // 'TPM00'
82
83 //
84 // Object handle list for persistent storage objects containing NV
85 //
86 static TEE_ObjectHandle s_NVStore[NV_BLOCK_COUNT] = { TEE_HANDLE_NULL };
87
88 //
89 // Bitmap for NV blocks. Moving from UINT64 requires change to NV_DIRTY_ALL.
90 //
91 static UINT64 s_blockMap = 0x0ULL;
92
93 //
94 // Shortcut for 'dirty'ing all NV blocks. Note the type.
95 //
96 #if NV_BLOCK_COUNT < 64
97 #define NV_DIRTY_ALL ((UINT64)((0x1ULL << NV_BLOCK_COUNT) - 1))
98 #elif NV_BLOCK_COUNT == 64
99 #define NV_DIRTY_ALL (~(0x0ULL))
100 #else
101 #error "NV block count exceeds 64 bit block map. Adjust block or NV size."
102 #endif
103
104 //
105 // NV state
106 //
107 static BOOL s_NVChipFileNeedsManufacture = FALSE;
108 static BOOL s_NVInitialized = FALSE;
109 static UCHAR s_NV[NV_CHIP_MEMORY_SIZE];
110
111 //
112 // Firmware revision
113 //
114 static const UINT32 firmwareV1 = FIRMWARE_V1;
115 static const UINT32 firmwareV2 = FIRMWARE_V2;
116
117 //
118 // Revision fro NVChip
119 //
120 static UINT64 s_chipRevision = 0;
121
122 //
123 // This offset puts the revision field immediately following the TPM Admin
124 // state. The Admin space in NV is down to ~16 bytes but is padded out to
125 // 256bytes to avoid alignment issues and allow for growth.
126 //
127 #define NV_CHIP_REVISION_OFFSET ((NV_MEMORY_SIZE) + (TPM_STATE_SIZE))
128
129 VOID
_plat__NvInitFromStorage()130 _plat__NvInitFromStorage()
131 {
132 DMSG("_plat__NvInitFromStorage()");
133 UINT32 i;
134 BOOL initialized;
135 UINT32 objID;
136 UINT32 bytesRead;
137 TEE_Result Result;
138
139 // Don't re-initialize.
140 if (s_NVInitialized) {
141 return;
142 }
143
144 //
145 // If the NV file is successfully read from the storage then
146 // initialized must be set. We are setting initialized to true
147 // here but if an error is encountered reading the NV file it will
148 // be reset.
149 //
150
151 initialized = TRUE;
152
153 // Collect storage objects and init NV.
154 for (i = 0; i < NV_BLOCK_COUNT; i++) {
155
156 // Form storage object ID for this block.
157 objID = s_StorageObjectID + i;
158
159 // Attempt to open TEE persistent storage object.
160 Result = TEE_OpenPersistentObject(TEE_STORAGE_PRIVATE,
161 (void *)&objID,
162 sizeof(objID),
163 TA_STORAGE_FLAGS,
164 &s_NVStore[i]);
165
166 // If the open failed, try to create this storage object.
167 if (Result != TEE_SUCCESS) {
168
169 // There was an error, fail the init, NVEnable can retry.
170 if (Result != TEE_ERROR_ITEM_NOT_FOUND) {
171 #ifdef fTPMDebug
172 DMSG("Failed to open fTPM storage object");
173 #endif
174 goto Error;
175 }
176
177 // Storage object was not found, create it.
178 Result = TEE_CreatePersistentObject(TEE_STORAGE_PRIVATE,
179 (void *)&objID,
180 sizeof(objID),
181 TA_STORAGE_FLAGS,
182 NULL,
183 (void *)&(s_NV[i * NV_BLOCK_SIZE]),
184 NV_BLOCK_SIZE,
185 &s_NVStore[i]);
186
187 // There was an error, fail the init, NVEnable can retry.
188 if (Result != TEE_SUCCESS) {
189 #ifdef fTPMDebug
190 DMSG("Failed to create fTPM storage object");
191 #endif
192 goto Error;
193 }
194
195 // A clean storage object was created, we must (re)manufacture.
196 s_NVChipFileNeedsManufacture = TRUE;
197
198 // To ensure NV is consistent, force a write back of all NV blocks
199 s_blockMap = NV_DIRTY_ALL;
200
201 // Need to re-initialize
202 initialized = FALSE;
203
204 #ifdef fTPMDebug
205 IMSG("Created fTPM storage object, i: 0x%x, s: 0x%x, id: 0x%x, h:0x%x\n",
206 i, NV_BLOCK_SIZE, objID, s_NVStore[i]);
207 #endif
208 }
209 else {
210 // Successful open, now read fTPM storage object.
211 Result = TEE_ReadObjectData(s_NVStore[i],
212 (void *)&(s_NV[i * NV_BLOCK_SIZE]),
213 NV_BLOCK_SIZE,
214 &bytesRead);
215
216 // Give up on failed or incomplete reads.
217 if ((Result != TEE_SUCCESS) || (bytesRead != NV_BLOCK_SIZE)) {
218 #ifdef fTPMDebug
219 DMSG("Failed to read fTPM storage object");
220 #endif
221 goto Error;
222 }
223
224 #ifdef fTPMDebug
225 IMSG("Read fTPM storage object, i: 0x%x, s: 0x%x, id: 0x%x, h:0x%x\n",
226 i, bytesRead, objID, s_NVStore[i]);
227 #endif
228 }
229 }
230
231 // Storage objects are open and valid, next validate revision
232 s_chipRevision = ((((UINT64)firmwareV2) << 32) | (firmwareV1));
233 if ((s_chipRevision != *(UINT64*)&(s_NV[NV_CHIP_REVISION_OFFSET]))) {
234
235 // Failure to validate revision, re-init.
236 memset(s_NV, 0, NV_CHIP_MEMORY_SIZE);
237
238 // Dirty the block map, we're going to re-init.
239 s_blockMap = NV_DIRTY_ALL;
240
241 // Init with proper revision
242 s_chipRevision = ((((UINT64)firmwareV2) << 32) | (firmwareV1));
243 *(UINT64*)&(s_NV[NV_CHIP_REVISION_OFFSET]) = s_chipRevision;
244
245 #ifdef fTPMDebug
246 DMSG("Failed to validate revision.");
247 #endif
248
249 // Force (re)manufacture.
250 s_NVChipFileNeedsManufacture = TRUE;
251
252 // Need to re-initialize
253 initialized = FALSE;
254
255 return;
256 }
257
258 s_NVInitialized = initialized;
259
260 return;
261
262 Error:
263 s_NVInitialized = FALSE;
264 for (i = 0; i < NV_BLOCK_COUNT; i++) {
265 if (IS_VALID(s_NVStore[i])) {
266 TEE_CloseObject(s_NVStore[i]);
267 s_NVStore[i] = TEE_HANDLE_NULL;
268 }
269 }
270
271 return;
272 }
273
274
275 static void
_plat__NvWriteBack()276 _plat__NvWriteBack()
277 {
278 UINT32 i;
279 UINT32 objID;
280 TEE_Result Result;
281
282 // Exit if no dirty blocks.
283 if ((!s_blockMap) || (!s_NVInitialized)) {
284 return;
285 }
286
287 #ifdef fTPMDebug
288 DMSG("bMap: 0x%x\n", s_blockMap);
289 #endif
290
291 // Write dirty blocks.
292 for (i = 0; i < NV_BLOCK_COUNT; i++) {
293
294 if ((s_blockMap & (0x1ULL << i))) {
295
296 // Form storage object ID for this block.
297 objID = s_StorageObjectID + i;
298
299 // Move data position associated with handle to start of block.
300 Result = TEE_SeekObjectData(s_NVStore[i], 0, TEE_DATA_SEEK_SET);
301 if (Result != TEE_SUCCESS) {
302 goto Error;
303 }
304
305 // Write out this block.
306 Result = TEE_WriteObjectData(s_NVStore[i],
307 (void *)&(s_NV[i * NV_BLOCK_SIZE]),
308 NV_BLOCK_SIZE);
309 if (Result != TEE_SUCCESS) {
310 goto Error;
311 }
312
313 // Force storage stack to update its backing store
314 TEE_CloseObject(s_NVStore[i]);
315
316 Result = TEE_OpenPersistentObject(TEE_STORAGE_PRIVATE,
317 (void *)&objID,
318 sizeof(objID),
319 TA_STORAGE_FLAGS,
320 &s_NVStore[i]);
321 // Success?
322 if (Result != TEE_SUCCESS) {
323 goto Error;
324 }
325
326 // Clear dirty bit.
327 s_blockMap &= ~(0x1ULL << i);
328 }
329 }
330
331 return;
332
333 Error:
334 // Error path.
335 #ifdef fTPMDebug
336 DMSG("NV write back failed");
337 #endif
338 s_NVInitialized = FALSE;
339 for (i = 0; i < NV_BLOCK_COUNT; i++) {
340 if (IS_VALID(s_NVStore[i])) {
341 TEE_CloseObject(s_NVStore[i]);
342 s_NVStore[i] = TEE_HANDLE_NULL;
343 }
344 }
345
346 return;
347 }
348
349
350 BOOL
_plat__NvNeedsManufacture()351 _plat__NvNeedsManufacture()
352 {
353 return s_NVChipFileNeedsManufacture;
354 }
355
356 //***_plat__NVEnable()
357 // Enable NV memory.
358 //
359 // This version just pulls in data from a file. In a real TPM, with NV on chip,
360 // this function would verify the integrity of the saved context. If the NV
361 // memory was not on chip but was in something like RPMB, the NV state would be
362 // read in, decrypted and integrity checked.
363 //
364 // The recovery from an integrity failure depends on where the error occurred. It
365 // it was in the state that is discarded by TPM Reset, then the error is
366 // recoverable if the TPM is reset. Otherwise, the TPM must go into failure mode.
367 // return type: int
368 // 0 if success
369 // > 0 if receive recoverable error
370 // <0 if unrecoverable error
371 LIB_EXPORT int
_plat__NVEnable(void * platParameter)372 _plat__NVEnable(
373 void *platParameter // IN: platform specific parameters
374 )
375 {
376 UNREFERENCED_PARAMETER(platParameter);
377 DMSG("_plat__NVEnable()");
378
379
380 UINT32 retVal = 0;
381 UINT32 firmwareV1 = FIRMWARE_V1;
382 UINT32 firmwareV2 = FIRMWARE_V2;
383
384 // Don't re-open the backing store.
385 if (s_NVInitialized) {
386 return 0;
387 }
388
389 // Clear NV
390 memset(s_NV, 0, NV_CHIP_MEMORY_SIZE);
391
392 // Prepare for potential failure to retreieve NV from storage
393 s_chipRevision = ((((UINT64)firmwareV2) << 32) | (firmwareV1));
394 *(UINT64*)&(s_NV[NV_CHIP_REVISION_OFFSET]) = s_chipRevision;
395
396 // Pick up our NV memory.
397 _plat__NvInitFromStorage();
398
399 // Were we successful?
400 if (!s_NVInitialized) {
401 // Arriving here means one of two things: Either there existed no
402 // NV state before we came along and we just (re)initialized our
403 // storage. Or there is an error condition preventing us from
404 // accessing storage. Check which is the case.
405 if (s_NVChipFileNeedsManufacture == FALSE) {
406 // This condition means we cannot access storage. However, it
407 // isn't up to the platform layer to decide what to do in this
408 // case. The decision to proceed is made in the fTPM init code
409 // in TA_CreateEntryPoint. Here, we're going to make sure that,
410 // should we decide not to just TEE_Panic, we can continue
411 // execution after (re)manufacture. Later an attempt at re-init
412 // can be made by calling _plat__NvInitFromStorage again.
413 retVal = 0;
414 }
415 else {
416 retVal = 1;
417 }
418
419 // Going to manufacture, zero flags
420 g_chipFlags.flags = 0;
421
422 // Save flags
423 _admin__SaveChipFlags();
424
425 // Now we're done
426 s_NVInitialized = TRUE;
427
428 return retVal;
429 }
430 else {
431 // In the transition out of UEFI to Windows, we may not tear down
432 // the TA. We close out one session and start another. This means
433 // our s_NVChipFileNeedsManufacture flag, if set, will be stale.
434 // Make sure we don't re-manufacture.
435 s_NVChipFileNeedsManufacture = FALSE;
436
437 // We successfully initialized NV now pickup TPM state.
438 _admin__RestoreChipFlags();
439
440 // Success
441 retVal = 1;
442 }
443
444 return retVal;
445 }
446
447 //***_plat__NVDisable()
448 // Disable NV memory
449 LIB_EXPORT void
_plat__NVDisable(void)450 _plat__NVDisable(
451 void
452 )
453 {
454 UINT32 i;
455
456 if (!s_NVInitialized) {
457 return;
458 }
459
460 // Final write
461 _plat__NvWriteBack();
462
463 // Close out all handles
464 for (i = 0; i < NV_BLOCK_COUNT; i++) {
465 if (IS_VALID(s_NVStore[i])) {
466 TEE_CloseObject(s_NVStore[i]);
467 s_NVStore[i] = TEE_HANDLE_NULL;
468 }
469 }
470
471 // We're no longer init-ed
472 s_NVInitialized = FALSE;
473
474 return;
475 }
476
477 //***_plat__IsNvAvailable()
478 // Check if NV is available
479 // return type: int
480 // 0 NV is available
481 // 1 NV is not available due to write failure
482 // 2 NV is not available due to rate limit
483 LIB_EXPORT int
_plat__IsNvAvailable(void)484 _plat__IsNvAvailable(
485 void
486 )
487 {
488 // This is not enabled for OpTEE TA. Storage is always available.
489 return 0;
490 }
491
492
493
494 //***_plat__NvMemoryRead()
495 // Function: Read a chunk of NV memory
496 LIB_EXPORT void
_plat__NvMemoryRead(unsigned int startOffset,unsigned int size,void * data)497 _plat__NvMemoryRead(
498 unsigned int startOffset, // IN: read start
499 unsigned int size, // IN: size of bytes to read
500 void *data // OUT: data buffer
501 )
502 {
503 pAssert((startOffset + size) <= NV_CHIP_MEMORY_SIZE);
504 pAssert(s_NV != NULL);
505
506 memcpy(data, &s_NV[startOffset], size);
507 }
508
509 //*** _plat__NvIsDifferent()
510 // This function checks to see if the NV is different from the test value. This is
511 // so that NV will not be written if it has not changed.
512 // return value: int
513 // TRUE(1) the NV location is different from the test value
514 // FALSE(0) the NV location is the same as the test value
515 LIB_EXPORT int
_plat__NvIsDifferent(unsigned int startOffset,unsigned int size,void * data)516 _plat__NvIsDifferent(
517 unsigned int startOffset, // IN: read start
518 unsigned int size, // IN: size of bytes to read
519 void *data // IN: data buffer
520 )
521 {
522 return (memcmp(&s_NV[startOffset], data, size) != 0);
523 }
524
525 static
526 void
_plat__MarkDirtyBlocks(unsigned int startOffset,unsigned int size)527 _plat__MarkDirtyBlocks (
528 unsigned int startOffset,
529 unsigned int size
530 )
531 {
532 unsigned int blockEnd;
533 unsigned int blockStart;
534 unsigned int i;
535
536 //
537 // Integer math will round down to the start of the block.
538 // blockEnd is actually the last block + 1.
539 //
540
541 blockStart = startOffset / NV_BLOCK_SIZE;
542 blockEnd = (startOffset + size) / NV_BLOCK_SIZE;
543 if ((startOffset + size) % NV_BLOCK_SIZE != 0) {
544 blockEnd += 1;
545 }
546
547 for (i = blockStart; i < blockEnd; i++) {
548 s_blockMap |= (0x1ULL << i);
549 }
550 }
551
552 //***_plat__NvMemoryWrite()
553 // This function is used to update NV memory. The "write" is to a memory copy of
554 // NV. At the end of the current command, any changes are written to
555 // the actual NV memory.
556 // NOTE: A useful optimization would be for this code to compare the current
557 // contents of NV with the local copy and note the blocks that have changed. Then
558 // only write those blocks when _plat__NvCommit() is called.
559 LIB_EXPORT int
_plat__NvMemoryWrite(unsigned int startOffset,unsigned int size,void * data)560 _plat__NvMemoryWrite(
561 unsigned int startOffset, // IN: write start
562 unsigned int size, // IN: size of bytes to write
563 void *data // OUT: data buffer
564 )
565 {
566 pAssert(startOffset + size <= NV_CHIP_MEMORY_SIZE);
567 pAssert(s_NV != NULL);
568
569 _plat__MarkDirtyBlocks(startOffset, size);
570 memcpy(&s_NV[startOffset], data, size);
571 return TRUE;
572 }
573
574 //***_plat__NvMemoryClear()
575 // Function is used to set a range of NV memory bytes to an implementation-dependent
576 // value. The value represents the erase state of the memory.
577 LIB_EXPORT void
_plat__NvMemoryClear(unsigned int start,unsigned int size)578 _plat__NvMemoryClear(
579 unsigned int start, // IN: clear start
580 unsigned int size // IN: number of bytes to clear
581 )
582 {
583 pAssert(start + size <= NV_MEMORY_SIZE);
584
585 _plat__MarkDirtyBlocks(start, size);
586 memset(&s_NV[start], 0, size);
587 }
588
589 //***_plat__NvMemoryMove()
590 // Function: Move a chunk of NV memory from source to destination
591 // This function should ensure that if there overlap, the original data is
592 // copied before it is written
593 LIB_EXPORT void
_plat__NvMemoryMove(unsigned int sourceOffset,unsigned int destOffset,unsigned int size)594 _plat__NvMemoryMove(
595 unsigned int sourceOffset, // IN: source offset
596 unsigned int destOffset, // IN: destination offset
597 unsigned int size // IN: size of data being moved
598 )
599 {
600 pAssert(sourceOffset + size <= NV_CHIP_MEMORY_SIZE);
601 pAssert(destOffset + size <= NV_CHIP_MEMORY_SIZE);
602 pAssert(s_NV != NULL);
603
604 _plat__MarkDirtyBlocks(sourceOffset, size);
605 _plat__MarkDirtyBlocks(destOffset, size);
606
607 memmove(&s_NV[destOffset], &s_NV[sourceOffset], size);
608 }
609
610 //***_plat__NvCommit()
611 // This function writes the local copy of NV to NV for permanent store. It will write
612 // NV_MEMORY_SIZE bytes to NV. If a file is use, the entire file is written.
613 // return type: int
614 // 0 NV write success
615 // non-0 NV write fail
616 LIB_EXPORT int
_plat__NvCommit(void)617 _plat__NvCommit(
618 void
619 )
620 {
621 _plat__NvWriteBack();
622 return 0;
623 }
624
625 //***_plat__SetNvAvail()
626 // Set the current NV state to available. This function is for testing purpose
627 // only. It is not part of the platform NV logic
628 LIB_EXPORT void
_plat__SetNvAvail(void)629 _plat__SetNvAvail(
630 void
631 )
632 {
633 // NV will not be made unavailable on this platform
634 return;
635 }
636
637 //***_plat__ClearNvAvail()
638 // Set the current NV state to unavailable. This function is for testing purpose
639 // only. It is not part of the platform NV logic
640 LIB_EXPORT void
_plat__ClearNvAvail(void)641 _plat__ClearNvAvail(
642 void
643 )
644 {
645 // The anti-set; not on this platform.
646 return;
647 }
648