microsoft/mu_feature_ffa

Public

mirrored from https://github.com/microsoft/mu_feature_ffaAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
ef8c8ffe3e9cd9f6fd3732ade9463d4841c3472e

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

FfaFeaturePkg/Library/TpmServiceStateTranslationLib/TpmServiceStateTranslationLib.c

668lines · modecode

1/** @file
2 Implementation for the TPM Service State Translation Library. This library's
3 main purpose is to translate the states of the TPM service's CRB states to
4 the main TPM's interface states. (i.e. TPM PC CRB -> TPM FIFO) A user of the
5 TPM service should only need to update this library with the proper TPM
6 interface type for their device.
7
8 Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
9 (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
10 Copyright (c), Microsoft Corporation.
11 SPDX-License-Identifier: BSD-2-Clause-Patent
12
13**/
14
15#include <Uefi.h>
16#include <Library/BaseLib.h>
17#include <Library/BaseMemoryLib.h>
18#include <Library/IoLib.h>
19#include <Library/TimerLib.h>
20#include <Library/DebugLib.h>
21#include <Library/TpmServiceStateTranslationLib.h>
22#include <IndustryStandard/Tpm20.h>
23
24/* TPM Service State Translation Library Defines */
25#define INTERFACE_TYPE_MASK (0x00F)
26#define IDLE_BYPASS_MASK (0x200)
27
28#define LOCALITY_OFFSET (0x1000)
29
30#define DELAY_AMOUNT (30)
31
32#define PTP_TIMEOUT_MAX (90000 * 1000) // 90s
33
34/* TPM Service State Translation Library Variables */
35STATIC BOOLEAN mIsCrbInterface;
36STATIC BOOLEAN mIsIdleBypassSupported;
37
38/* TPM Service State Translation Library Static Functions */
39
40/**
41 This function dumps as much information as possible about
42 a command being sent to the TPM for maximum user-readability.
43
44 @param[in] InputBlockSize Size of the input buffer.
45 @param[in] InputBlock Pointer to the input buffer itself.
46
47**/
48VOID
49EFIAPI
50DumpTpmInputBlock (
51 IN UINT32 InputBlockSize,
52 IN CONST UINT8 *InputBlock
53 )
54{
55 UINTN Index, DebugSize;
56
57 DEBUG ((DEBUG_INFO, "TpmCommand Send - "));
58
59 if (InputBlockSize > 0x100) {
60 DebugSize = 0x40;
61 } else {
62 DebugSize = InputBlockSize;
63 }
64
65 for (Index = 0; Index < DebugSize; Index++) {
66 DEBUG ((DEBUG_INFO, "%02x ", InputBlock[Index]));
67 }
68
69 if (DebugSize != InputBlockSize) {
70 DEBUG ((DEBUG_INFO, "...... "));
71
72 for (Index = InputBlockSize - 0x20; Index < InputBlockSize; Index++) {
73 DEBUG ((DEBUG_INFO, "%02x ", InputBlock[Index]));
74 }
75 }
76
77 DEBUG ((DEBUG_INFO, "\n"));
78
79 return;
80} // DumpTpmInputBlock()
81
82/**
83 This function dumps as much information as possible about
84 a response from the TPM for maximum user-readability.
85
86 @param[in] OutputBlockSize Size of the output buffer.
87 @param[in] OutputBlock Pointer to the output buffer itself.
88
89**/
90VOID
91EFIAPI
92DumpTpmOutputBlock (
93 IN UINT32 OutputBlockSize,
94 IN CONST UINT8 *OutputBlock
95 )
96{
97 UINTN Index;
98
99 DEBUG ((DEBUG_INFO, "TpmCommand Receive - "));
100
101 for (Index = 0; Index < OutputBlockSize; Index++) {
102 DEBUG ((DEBUG_INFO, "%02x ", OutputBlock[Index]));
103 }
104
105 DEBUG ((DEBUG_INFO, "\n"));
106
107 return;
108} // DumpTpmOutputBlock()
109
110/**
111 Returns the BurstCount from the ExternalFifo
112
113 @param ExternalFifo The Fifo registers to read from
114 @param BurstCount The value of the BurstCount to populate
115
116 @retval EFI_SUCCESS Success
117 @retval EFI_TIMEOUT Timeout
118
119**/
120STATIC
121EFI_STATUS
122FifoReadBurstCount (
123 PTP_FIFO_REGISTERS_PTR ExternalFifo,
124 UINT16 *BurstCount
125 )
126{
127 UINT32 Timeout;
128 UINT8 DataByte0;
129 UINT8 DataByte1;
130
131 Timeout = 0;
132 do {
133 DataByte0 = MmioRead8 ((UINTN)&ExternalFifo->BurstCount);
134 DataByte1 = MmioRead8 ((UINTN)&ExternalFifo->BurstCount + 1);
135 *BurstCount = (UINT16)((DataByte1 << 8) + DataByte0);
136 if (*BurstCount != 0) {
137 return EFI_SUCCESS;
138 }
139
140 MicroSecondDelay (DELAY_AMOUNT);
141 Timeout += DELAY_AMOUNT;
142 } while (Timeout < PTP_TIMEOUT_D);
143
144 return EFI_TIMEOUT;
145}
146
147/**
148 Determines whether the value of the provided register matches expectations.
149
150 @param Register The register to validate
151 @param BitSet Bits to check against that should be set
152 @param BitClear Bits to check against that should be clear
153 @param Timeout Amount of time to wait
154
155 @retval EFI_SUCCESS Success
156 @retval EFI_TIMEOUT Timeout
157
158**/
159STATIC
160EFI_STATUS
161WaitRegisterBits (
162 UINT32 *Register,
163 UINT32 BitSet,
164 UINT32 BitClear,
165 UINT32 Timeout
166 )
167{
168 UINT32 RegRead;
169 UINT32 WaitTime;
170
171 /* Attempt to read the register based on the TPM type. */
172 for (WaitTime = 0; WaitTime < Timeout; WaitTime += DELAY_AMOUNT) {
173 if (mIsCrbInterface) {
174 RegRead = MmioRead32 ((UINTN)Register);
175 } else {
176 RegRead = (UINT32)MmioRead8 ((UINTN)Register);
177 }
178
179 /* Verify the register contents. */
180 if (((RegRead & BitSet) == BitSet) && ((RegRead & BitClear) == 0)) {
181 return EFI_SUCCESS;
182 }
183
184 MicroSecondDelay (DELAY_AMOUNT);
185 }
186
187 return EFI_TIMEOUT;
188}
189
190/**
191 Copies command data to the TPM
192
193 @param Locality The locality to copy to
194 @param TpmCommandBuffer The command buffer containing the data
195 @param CommandDataLen The length of the command data
196
197 @retval EFI_SUCCESS Success
198 @retval EFI_TIMEOUT Timeout
199
200**/
201STATIC
202EFI_STATUS
203CopyCommandData (
204 UINT8 Locality,
205 UINT8 *TpmCommandBuffer,
206 UINT32 CommandDataLen
207 )
208{
209 EFI_STATUS Status;
210 PTP_CRB_REGISTERS_PTR ExternalCrb;
211 PTP_FIFO_REGISTERS_PTR ExternalFifo;
212 UINT32 Index;
213 UINT16 BurstCount;
214
215 /* Determine which TPM structure to access */
216 if (mIsCrbInterface) {
217 ExternalCrb = (PTP_CRB_REGISTERS_PTR)(UINTN)(PcdGet64 (PcdTpmBaseAddress) + (Locality * LOCALITY_OFFSET));
218
219 /* Copy the command data to the CRB buffer. */
220 for (Index = 0; Index < CommandDataLen; Index++) {
221 MmioWrite8 ((UINTN)&ExternalCrb->CrbDataBuffer[Index], TpmCommandBuffer[Index]);
222 }
223
224 Status = EFI_SUCCESS;
225 } else {
226 ExternalFifo = (PTP_FIFO_REGISTERS_PTR)(UINTN)(PcdGet64 (PcdTpmBaseAddress) + (Locality * LOCALITY_OFFSET));
227
228 /* Copy the command data to the FIFO depending on the burst count. */
229 Index = 0;
230 while (Index < CommandDataLen) {
231 Status = FifoReadBurstCount (ExternalFifo, &BurstCount);
232 if (EFI_ERROR (Status)) {
233 break;
234 }
235
236 while (BurstCount > 0 && Index < CommandDataLen) {
237 MmioWrite8 ((UINTN)&ExternalFifo->DataFifo, TpmCommandBuffer[Index]);
238 Index++;
239 BurstCount--;
240 }
241 }
242
243 /* Check to make sure the STS_EXPECT register changed from 1 to 0. */
244 Status = WaitRegisterBits (
245 (UINT32 *)&ExternalFifo->Status,
246 PTP_FIFO_STS_VALID,
247 PTP_FIFO_STS_EXPECT,
248 PTP_TIMEOUT_C
249 );
250 }
251
252 return Status;
253}
254
255/**
256 Initiates or starts the command execution
257
258 @param Locality The locality to begin command execution for
259
260 @retval EFI_SUCCESS Success
261 @retval EFI_TIMEOUT Timeout
262
263**/
264STATIC
265EFI_STATUS
266StartCommand (
267 UINT8 Locality
268 )
269{
270 EFI_STATUS Status;
271 PTP_CRB_REGISTERS_PTR ExternalCrb;
272 PTP_FIFO_REGISTERS_PTR ExternalFifo;
273
274 /* Determine which TPM structure to access */
275 if (mIsCrbInterface) {
276 ExternalCrb = (PTP_CRB_REGISTERS_PTR)(UINTN)(PcdGet64 (PcdTpmBaseAddress) + (Locality * LOCALITY_OFFSET));
277
278 MmioWrite32 ((UINTN)&ExternalCrb->CrbControlStart, PTP_CRB_CONTROL_START);
279 Status = WaitRegisterBits (
280 &ExternalCrb->CrbControlStart,
281 0,
282 PTP_CRB_CONTROL_START,
283 PTP_TIMEOUT_MAX
284 );
285 } else {
286 ExternalFifo = (PTP_FIFO_REGISTERS_PTR)(UINTN)(PcdGet64 (PcdTpmBaseAddress) + (Locality * LOCALITY_OFFSET));
287
288 /* Set the tpmGo bit in the Status register. */
289 MmioWrite8 ((UINTN)&ExternalFifo->Status, PTP_FIFO_STS_GO);
290 Status = WaitRegisterBits (
291 (UINT32 *)&ExternalFifo->Status,
292 (PTP_FIFO_STS_VALID | PTP_FIFO_STS_DATA),
293 0,
294 PTP_TIMEOUT_MAX
295 );
296 }
297
298 return Status;
299}
300
301/**
302 Retrieves the response data
303
304 @param Locality The locality to read from
305 @param TpmCommandBuffer The TPM command buffer to populate
306 @param ResponseDataLen The length of the response
307
308 @retval EFI_SUCCESS Success
309 @retval EFI_TIMEOUT Timeout
310
311**/
312STATIC
313EFI_STATUS
314CopyResponseData (
315 UINT8 Locality,
316 UINT8 *TpmCommandBuffer,
317 UINT32 ResponseDataLen
318 )
319{
320 EFI_STATUS Status;
321 PTP_CRB_REGISTERS_PTR ExternalCrb;
322 PTP_FIFO_REGISTERS_PTR ExternalFifo;
323 UINT32 Index;
324 UINT16 BurstCount;
325
326 /* Determine which TPM structure to access */
327 if (mIsCrbInterface) {
328 ExternalCrb = (PTP_CRB_REGISTERS_PTR)(UINTN)(PcdGet64 (PcdTpmBaseAddress) + (Locality * LOCALITY_OFFSET));
329
330 for (Index = 0; Index < ResponseDataLen; Index++) {
331 TpmCommandBuffer[Index] = MmioRead8 ((UINTN)&ExternalCrb->CrbDataBuffer[Index]);
332 }
333
334 Status = EFI_SUCCESS;
335 } else {
336 ExternalFifo = (PTP_FIFO_REGISTERS_PTR)(UINTN)(PcdGet64 (PcdTpmBaseAddress) + (Locality * LOCALITY_OFFSET));
337
338 Index = 0;
339 while (Index < ResponseDataLen) {
340 Status = FifoReadBurstCount (ExternalFifo, &BurstCount);
341 if (EFI_ERROR (Status)) {
342 break;
343 }
344
345 while (BurstCount > 0) {
346 TpmCommandBuffer[Index] = MmioRead8 ((UINTN)&ExternalFifo->DataFifo);
347 Index++;
348 BurstCount--;
349 if (Index == ResponseDataLen) {
350 Status = EFI_SUCCESS;
351 break;
352 }
353 }
354 }
355 }
356
357 return Status;
358}
359
360/* TPM Service State Translation Library Global Functions */
361
362/**
363 Initiates the transition to the Idle state
364
365 @param Locality The locality of the TPM to set into Idle
366
367 @retval EFI_SUCCESS Success
368 @retval EFI_TIMEOUT Timeout
369
370**/
371EFI_STATUS
372TpmSstGoIdle (
373 UINT8 Locality
374 )
375{
376 EFI_STATUS Status;
377 PTP_CRB_REGISTERS_PTR ExternalCrb;
378 PTP_FIFO_REGISTERS_PTR ExternalFifo;
379
380 /* Determine which TPM structure to access */
381 if (mIsCrbInterface) {
382 ExternalCrb = (PTP_CRB_REGISTERS_PTR)(UINTN)(PcdGet64 (PcdTpmBaseAddress) + (Locality * LOCALITY_OFFSET));
383
384 /* Set the goIdle bit in the CRB Control Request register. Wait for it to clear and then check
385 * the CRB Control Area Status register to make sure the tpmIdle bit was set. */
386 MmioWrite32 ((UINTN)&ExternalCrb->CrbControlRequest, PTP_CRB_CONTROL_AREA_REQUEST_GO_IDLE);
387 Status = WaitRegisterBits (
388 &ExternalCrb->CrbControlRequest,
389 0,
390 PTP_CRB_CONTROL_AREA_REQUEST_GO_IDLE,
391 PTP_TIMEOUT_C
392 );
393 if (Status == EFI_SUCCESS) {
394 Status = WaitRegisterBits (
395 &ExternalCrb->CrbControlStatus,
396 PTP_CRB_CONTROL_AREA_STATUS_TPM_IDLE,
397 0,
398 PTP_TIMEOUT_C
399 );
400 }
401
402 /* Note that there is no goIdle in the FIFO TPM implementation. Going idle is the same as commandReady. */
403 } else {
404 ExternalFifo = (PTP_FIFO_REGISTERS_PTR)(UINTN)(PcdGet64 (PcdTpmBaseAddress) + (Locality * LOCALITY_OFFSET));
405
406 /* Set the commandReady bit in the Status register. Read it back and verify it is set which
407 * indicates the TPM is ready. */
408 MmioWrite8 ((UINTN)&ExternalFifo->Status, PTP_FIFO_STS_READY);
409 Status = WaitRegisterBits (
410 (UINT32 *)&ExternalFifo->Status,
411 PTP_FIFO_STS_READY,
412 0,
413 PTP_TIMEOUT_B
414 );
415 }
416
417 return Status;
418}
419
420/**
421 Initiates the transition to the commandReady state
422
423 @param Locality The locality of the TPM to set to commandReady
424
425 @retval EFI_SUCCESS Success
426 @retval EFI_TIMEOUT Timeout
427
428**/
429EFI_STATUS
430TpmSstCmdReady (
431 UINT8 Locality
432 )
433{
434 EFI_STATUS Status;
435 PTP_CRB_REGISTERS_PTR ExternalCrb;
436 PTP_FIFO_REGISTERS_PTR ExternalFifo;
437
438 /* Determine which TPM structure to access */
439 if (mIsCrbInterface) {
440 ExternalCrb = (PTP_CRB_REGISTERS_PTR)(UINTN)(PcdGet64 (PcdTpmBaseAddress) + (Locality * LOCALITY_OFFSET));
441
442 /* Set the cmdReady bit in the CRB Control Request register. Wait for it to clear and then check
443 * the CRB Control Area Status register to make sure the tpmIdle bit was cleared. */
444 MmioWrite32 ((UINTN)&ExternalCrb->CrbControlRequest, PTP_CRB_CONTROL_AREA_REQUEST_COMMAND_READY);
445 Status = WaitRegisterBits (
446 &ExternalCrb->CrbControlRequest,
447 0,
448 PTP_CRB_CONTROL_AREA_REQUEST_COMMAND_READY,
449 PTP_TIMEOUT_C
450 );
451 if (Status == EFI_SUCCESS) {
452 Status = WaitRegisterBits (
453 &ExternalCrb->CrbControlStatus,
454 0,
455 PTP_CRB_CONTROL_AREA_STATUS_TPM_IDLE,
456 PTP_TIMEOUT_C
457 );
458 }
459 } else {
460 ExternalFifo = (PTP_FIFO_REGISTERS_PTR)(UINTN)(PcdGet64 (PcdTpmBaseAddress) + (Locality * LOCALITY_OFFSET));
461
462 /* Set the commandReady bit in the Status register. Read it back and verify it is set which
463 * indicates the TPM is ready. */
464 MmioWrite8 ((UINTN)&ExternalFifo->Status, PTP_FIFO_STS_READY);
465 Status = WaitRegisterBits (
466 (UINT32 *)&ExternalFifo->Status,
467 PTP_FIFO_STS_READY,
468 0,
469 PTP_TIMEOUT_B
470 );
471 }
472
473 return Status;
474}
475
476/**
477 Initiates command execution
478
479 @param Locality The locality of the TPM to initiate the command on
480 @param InternalTpmCrb The internal CRB to copy command data from
481
482 @retval EFI_SUCCESS Success
483 @retval EFI_TIMEOUT Timeout
484
485**/
486EFI_STATUS
487TpmSstStart (
488 UINT8 Locality,
489 PTP_CRB_REGISTERS_PTR InternalTpmCrb
490 )
491{
492 EFI_STATUS Status;
493 UINT8 TpmCommandBuffer[sizeof (InternalTpmCrb->CrbDataBuffer)];
494 UINT32 ResponseDataLen;
495 UINT32 CommandDataLen;
496
497 /* Init the local variables. */
498 ResponseDataLen = InternalTpmCrb->CrbControlResponseSize;
499 CommandDataLen = InternalTpmCrb->CrbControlCommandSize;
500 SetMem (TpmCommandBuffer, sizeof (InternalTpmCrb->CrbDataBuffer), 0);
501
502 /* Copy the CRB command data to the local buffer. */
503 CopyMem (TpmCommandBuffer, InternalTpmCrb->CrbDataBuffer, CommandDataLen);
504
505 DEBUG_CODE_BEGIN ();
506 DumpTpmInputBlock (CommandDataLen, TpmCommandBuffer);
507 DEBUG_CODE_END ();
508
509 /* Copy the command data. */
510 Status = CopyCommandData (Locality, TpmCommandBuffer, CommandDataLen);
511 if (EFI_ERROR (Status)) {
512 goto Exit;
513 }
514
515 /* Start command execution. */
516 Status = StartCommand (Locality);
517 if (EFI_ERROR (Status)) {
518 goto Exit;
519 }
520
521 /* Copy the response data. */
522 Status = CopyResponseData (Locality, TpmCommandBuffer, ResponseDataLen);
523 if (EFI_ERROR (Status)) {
524 goto Exit;
525 }
526
527 /* Copy the CRB response data from the local buffer. */
528 CopyMem (InternalTpmCrb->CrbDataBuffer, TpmCommandBuffer, ResponseDataLen);
529
530Exit:
531 DEBUG_CODE_BEGIN ();
532 DumpTpmOutputBlock (ResponseDataLen, TpmCommandBuffer);
533 DEBUG_CODE_END ();
534
535 return Status;
536}
537
538/**
539 Requests access to the given locality
540
541 @param Locality The locality to request access to
542
543 @retval EFI_SUCCESS Success
544 @retval EFI_TIMEOUT Timeout
545
546**/
547EFI_STATUS
548TpmSstLocalityRequest (
549 UINT8 Locality
550 )
551{
552 EFI_STATUS Status;
553 PTP_CRB_REGISTERS_PTR ExternalCrb;
554 PTP_FIFO_REGISTERS_PTR ExternalFifo;
555
556 /* Determine which TPM structure to access */
557 if (mIsCrbInterface) {
558 ExternalCrb = (PTP_CRB_REGISTERS_PTR)(UINTN)(PcdGet64 (PcdTpmBaseAddress) + (Locality * LOCALITY_OFFSET));
559
560 MmioWrite32 ((UINTN)&ExternalCrb->LocalityControl, PTP_CRB_LOCALITY_CONTROL_REQUEST_ACCESS);
561 Status = WaitRegisterBits (
562 &ExternalCrb->LocalityStatus,
563 PTP_CRB_LOCALITY_STATUS_GRANTED,
564 0,
565 PTP_TIMEOUT_A
566 );
567 } else {
568 ExternalFifo = (PTP_FIFO_REGISTERS_PTR)(UINTN)(PcdGet64 (PcdTpmBaseAddress) + (Locality * LOCALITY_OFFSET));
569
570 MmioWrite8 ((UINTN)&ExternalFifo->Access, PTP_FIFO_ACC_RQUUSE);
571 Status = WaitRegisterBits (
572 (UINT32 *)&ExternalFifo->Access,
573 (PTP_FIFO_ACC_ACTIVE | PTP_FIFO_VALID),
574 0,
575 PTP_TIMEOUT_A
576 );
577 }
578
579 return Status;
580}
581
582/**
583 Relinquish access to the given locality
584
585 @param Locality The locality to relinquish access to
586
587 @retval EFI_SUCCESS Success
588 @retval EFI_TIMEOUT Timeout
589
590**/
591EFI_STATUS
592TpmSstLocalityRelinquish (
593 UINT8 Locality
594 )
595{
596 EFI_STATUS Status;
597 PTP_CRB_REGISTERS_PTR ExternalCrb;
598 PTP_FIFO_REGISTERS_PTR ExternalFifo;
599
600 /* Determine which TPM structure to access */
601 if (mIsCrbInterface) {
602 ExternalCrb = (PTP_CRB_REGISTERS_PTR)(UINTN)(PcdGet64 (PcdTpmBaseAddress) + (Locality * LOCALITY_OFFSET));
603
604 MmioWrite32 ((UINTN)&ExternalCrb->LocalityControl, PTP_CRB_LOCALITY_CONTROL_RELINQUISH);
605 Status = WaitRegisterBits (
606 &ExternalCrb->LocalityStatus,
607 0,
608 PTP_CRB_LOCALITY_STATUS_GRANTED,
609 PTP_TIMEOUT_A
610 );
611 } else {
612 ExternalFifo = (PTP_FIFO_REGISTERS_PTR)(UINTN)(PcdGet64 (PcdTpmBaseAddress) + (Locality * LOCALITY_OFFSET));
613
614 MmioWrite8 ((UINTN)&ExternalFifo->Access, PTP_FIFO_ACC_ACTIVE);
615 Status = WaitRegisterBits (
616 (UINT32 *)&ExternalFifo->Access,
617 PTP_FIFO_VALID,
618 PTP_FIFO_ACC_ACTIVE,
619 PTP_TIMEOUT_A
620 );
621 }
622
623 return Status;
624}
625
626/**
627 Returns if IdleBypass is supported
628
629 @retval TRUE Supported
630 @retval FALSE Unsupported
631
632**/
633BOOLEAN
634TpmSstIsIdleBypassSupported (
635 VOID
636 )
637{
638 return mIsIdleBypassSupported;
639}
640
641/**
642 Initializes the TPM Service State Translation Library
643
644**/
645VOID
646TpmSstInit (
647 VOID
648 )
649{
650 /* Note that the register we are looking at is located at the same address
651 * regardless of if the TPM type is FIFO or CRB. */
652 PTP_CRB_REGISTERS_PTR ExternalCrb;
653
654 /* Need to determine the TPM interface type. */
655 ExternalCrb = (PTP_CRB_REGISTERS_PTR)(UINTN)PcdGet64 (PcdTpmBaseAddress);
656 if ((ExternalCrb->InterfaceId & INTERFACE_TYPE_MASK) == 1) {
657 mIsCrbInterface = TRUE;
658 } else {
659 mIsCrbInterface = FALSE;
660 }
661
662 /* Need to determine if idle bypass is supported. */
663 if (ExternalCrb->InterfaceId & IDLE_BYPASS_MASK) {
664 mIsIdleBypassSupported = TRUE;
665 } else {
666 mIsIdleBypassSupported = FALSE;
667 }
668}
669