microsoft/mu_feature_ffa

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
858d1559f5d2e1e97ccf62290e96060595aa2dfb

Branches

Tags

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

Clone

HTTPS

Download ZIP

FfaFeaturePkg/Library/TpmServiceStateTranslationLib/TpmServiceStateTranslationLib.c

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