]> git.proxmox.com Git - mirror_edk2.git/blob - SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2Tis.c
Add TPM2 implementation.
[mirror_edk2.git] / SecurityPkg / Library / Tpm2DeviceLibDTpm / Tpm2Tis.c
1 /** @file
2 TIS (TPM Interface Specification) functions used by dTPM2.0 library.
3
4 Copyright (c) 2013, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include <IndustryStandard/Tpm20.h>
16
17 #include <Library/BaseLib.h>
18 #include <Library/BaseMemoryLib.h>
19 #include <Library/IoLib.h>
20 #include <Library/TimerLib.h>
21 #include <Library/DebugLib.h>
22 #include <Library/Tpm2DeviceLib.h>
23 #include <Library/PcdLib.h>
24
25 //
26 // Set structure alignment to 1-byte
27 //
28 #pragma pack (1)
29
30 //
31 // Register set map as specified in TIS specification Chapter 10
32 //
33 typedef struct {
34 ///
35 /// Used to gain ownership for this particular port.
36 ///
37 UINT8 Access; // 0
38 UINT8 Reserved1[7]; // 1
39 ///
40 /// Controls interrupts.
41 ///
42 UINT32 IntEnable; // 8
43 ///
44 /// SIRQ vector to be used by the TPM.
45 ///
46 UINT8 IntVector; // 0ch
47 UINT8 Reserved2[3]; // 0dh
48 ///
49 /// What caused interrupt.
50 ///
51 UINT32 IntSts; // 10h
52 ///
53 /// Shows which interrupts are supported by that particular TPM.
54 ///
55 UINT32 IntfCapability; // 14h
56 ///
57 /// Status Register. Provides status of the TPM.
58 ///
59 UINT8 Status; // 18h
60 ///
61 /// Number of consecutive writes that can be done to the TPM.
62 ///
63 UINT16 BurstCount; // 19h
64 ///
65 /// TPM2 support CANCEL at BIT[24] of STATUS register (WO)
66 ///
67 UINT8 StatusEx; // 1Bh
68 UINT8 Reserved3[8];
69 ///
70 /// Read or write FIFO, depending on transaction.
71 ///
72 UINT32 DataFifo; // 24h
73 UINT8 Reserved4[0xed8]; // 28h
74 ///
75 /// Vendor ID
76 ///
77 UINT16 Vid; // 0f00h
78 ///
79 /// Device ID
80 ///
81 UINT16 Did; // 0f02h
82 ///
83 /// Revision ID
84 ///
85 UINT8 Rid; // 0f04h
86 ///
87 /// TCG defined configuration registers.
88 ///
89 UINT8 TcgDefined[0x7b]; // 0f05h
90 ///
91 /// Alias to I/O legacy space.
92 ///
93 UINT32 LegacyAddress1; // 0f80h
94 ///
95 /// Additional 8 bits for I/O legacy space extension.
96 ///
97 UINT32 LegacyAddress1Ex; // 0f84h
98 ///
99 /// Alias to second I/O legacy space.
100 ///
101 UINT32 LegacyAddress2; // 0f88h
102 ///
103 /// Additional 8 bits for second I/O legacy space extension.
104 ///
105 UINT32 LegacyAddress2Ex; // 0f8ch
106 ///
107 /// Vendor-defined configuration registers.
108 ///
109 UINT8 VendorDefined[0x70];// 0f90h
110 } TIS_PC_REGISTERS;
111
112 //
113 // Restore original structure alignment
114 //
115 #pragma pack ()
116
117 //
118 // Define pointer types used to access TIS registers on PC
119 //
120 typedef TIS_PC_REGISTERS *TIS_PC_REGISTERS_PTR;
121
122 //
123 // Define bits of ACCESS and STATUS registers
124 //
125
126 ///
127 /// This bit is a 1 to indicate that the other bits in this register are valid.
128 ///
129 #define TIS_PC_VALID BIT7
130 ///
131 /// Indicate that this locality is active.
132 ///
133 #define TIS_PC_ACC_ACTIVE BIT5
134 ///
135 /// Set to 1 to indicate that this locality had the TPM taken away while
136 /// this locality had the TIS_PC_ACC_ACTIVE bit set.
137 ///
138 #define TIS_PC_ACC_SEIZED BIT4
139 ///
140 /// Set to 1 to indicate that TPM MUST reset the
141 /// TIS_PC_ACC_ACTIVE bit and remove ownership for localities less than the
142 /// locality that is writing this bit.
143 ///
144 #define TIS_PC_ACC_SEIZE BIT3
145 ///
146 /// When this bit is 1, another locality is requesting usage of the TPM.
147 ///
148 #define TIS_PC_ACC_PENDIND BIT2
149 ///
150 /// Set to 1 to indicate that this locality is requesting to use TPM.
151 ///
152 #define TIS_PC_ACC_RQUUSE BIT1
153 ///
154 /// A value of 1 indicates that a T/OS has not been established on the platform
155 ///
156 #define TIS_PC_ACC_ESTABLISH BIT0
157
158 ///
159 /// When this bit is 1, TPM is in the Ready state,
160 /// indicating it is ready to receive a new command.
161 ///
162 #define TIS_PC_STS_READY BIT6
163 ///
164 /// Write a 1 to this bit to cause the TPM to execute that command.
165 ///
166 #define TIS_PC_STS_GO BIT5
167 ///
168 /// This bit indicates that the TPM has data available as a response.
169 ///
170 #define TIS_PC_STS_DATA BIT4
171 ///
172 /// The TPM sets this bit to a value of 1 when it expects another byte of data for a command.
173 ///
174 #define TIS_PC_STS_EXPECT BIT3
175 ///
176 /// Writes a 1 to this bit to force the TPM to re-send the response.
177 ///
178 #define TIS_PC_STS_RETRY BIT1
179
180 //
181 // Default TimeOut value
182 //
183 #define TIS_TIMEOUT_A (1000 * 1000) // 1s
184 #define TIS_TIMEOUT_B (2000 * 1000) // 2s
185 #define TIS_TIMEOUT_C (1000 * 1000) // 1s
186 #define TIS_TIMEOUT_D (1000 * 1000) // 1s
187
188 #define TIS_TIMEOUT_MAX (90000 * 1000) // 90s
189
190 //
191 // Max TPM command/reponse length
192 //
193 #define TPMCMDBUFLENGTH 0x500
194
195 /**
196 Check whether TPM chip exist.
197
198 @param[in] TisReg Pointer to TIS register.
199
200 @retval TRUE TPM chip exists.
201 @retval FALSE TPM chip is not found.
202 **/
203 BOOLEAN
204 TisPcPresenceCheck (
205 IN TIS_PC_REGISTERS_PTR TisReg
206 )
207 {
208 UINT8 RegRead;
209
210 RegRead = MmioRead8 ((UINTN)&TisReg->Access);
211 return (BOOLEAN)(RegRead != (UINT8)-1);
212 }
213
214 /**
215 Check whether the value of a TPM chip register satisfies the input BIT setting.
216
217 @param[in] Register Address port of register to be checked.
218 @param[in] BitSet Check these data bits are set.
219 @param[in] BitClear Check these data bits are clear.
220 @param[in] TimeOut The max wait time (unit MicroSecond) when checking register.
221
222 @retval EFI_SUCCESS The register satisfies the check bit.
223 @retval EFI_TIMEOUT The register can't run into the expected status in time.
224 **/
225 EFI_STATUS
226 EFIAPI
227 TisPcWaitRegisterBits (
228 IN UINT8 *Register,
229 IN UINT8 BitSet,
230 IN UINT8 BitClear,
231 IN UINT32 TimeOut
232 )
233 {
234 UINT8 RegRead;
235 UINT32 WaitTime;
236
237 for (WaitTime = 0; WaitTime < TimeOut; WaitTime += 30){
238 RegRead = MmioRead8 ((UINTN)Register);
239 if ((RegRead & BitSet) == BitSet && (RegRead & BitClear) == 0)
240 return EFI_SUCCESS;
241 MicroSecondDelay (30);
242 }
243 return EFI_TIMEOUT;
244 }
245
246 /**
247 Get BurstCount by reading the burstCount field of a TIS regiger
248 in the time of default TIS_TIMEOUT_D.
249
250 @param[in] TisReg Pointer to TIS register.
251 @param[out] BurstCount Pointer to a buffer to store the got BurstConut.
252
253 @retval EFI_SUCCESS Get BurstCount.
254 @retval EFI_INVALID_PARAMETER TisReg is NULL or BurstCount is NULL.
255 @retval EFI_TIMEOUT BurstCount can't be got in time.
256 **/
257 EFI_STATUS
258 EFIAPI
259 TisPcReadBurstCount (
260 IN TIS_PC_REGISTERS_PTR TisReg,
261 OUT UINT16 *BurstCount
262 )
263 {
264 UINT32 WaitTime;
265 UINT8 DataByte0;
266 UINT8 DataByte1;
267
268 if (BurstCount == NULL || TisReg == NULL) {
269 return EFI_INVALID_PARAMETER;
270 }
271
272 WaitTime = 0;
273 do {
274 //
275 // TIS_PC_REGISTERS_PTR->burstCount is UINT16, but it is not 2bytes aligned,
276 // so it needs to use MmioRead8 to read two times
277 //
278 DataByte0 = MmioRead8 ((UINTN)&TisReg->BurstCount);
279 DataByte1 = MmioRead8 ((UINTN)&TisReg->BurstCount + 1);
280 *BurstCount = (UINT16)((DataByte1 << 8) + DataByte0);
281 if (*BurstCount != 0) {
282 return EFI_SUCCESS;
283 }
284 MicroSecondDelay (30);
285 WaitTime += 30;
286 } while (WaitTime < TIS_TIMEOUT_D);
287
288 return EFI_TIMEOUT;
289 }
290
291 /**
292 Set TPM chip to ready state by sending ready command TIS_PC_STS_READY
293 to Status Register in time.
294
295 @param[in] TisReg Pointer to TIS register.
296
297 @retval EFI_SUCCESS TPM chip enters into ready state.
298 @retval EFI_INVALID_PARAMETER TisReg is NULL.
299 @retval EFI_TIMEOUT TPM chip can't be set to ready state in time.
300 **/
301 EFI_STATUS
302 EFIAPI
303 TisPcPrepareCommand (
304 IN TIS_PC_REGISTERS_PTR TisReg
305 )
306 {
307 EFI_STATUS Status;
308
309 if (TisReg == NULL) {
310 return EFI_INVALID_PARAMETER;
311 }
312
313 MmioWrite8((UINTN)&TisReg->Status, TIS_PC_STS_READY);
314 Status = TisPcWaitRegisterBits (
315 &TisReg->Status,
316 TIS_PC_STS_READY,
317 0,
318 TIS_TIMEOUT_B
319 );
320 return Status;
321 }
322
323 /**
324 Get the control of TPM chip by sending requestUse command TIS_PC_ACC_RQUUSE
325 to ACCESS Register in the time of default TIS_TIMEOUT_A.
326
327 @param[in] TisReg Pointer to TIS register.
328
329 @retval EFI_SUCCESS Get the control of TPM chip.
330 @retval EFI_INVALID_PARAMETER TisReg is NULL.
331 @retval EFI_NOT_FOUND TPM chip doesn't exit.
332 @retval EFI_TIMEOUT Can't get the TPM control in time.
333 **/
334 EFI_STATUS
335 EFIAPI
336 TisPcRequestUseTpm (
337 IN TIS_PC_REGISTERS_PTR TisReg
338 )
339 {
340 EFI_STATUS Status;
341
342 if (TisReg == NULL) {
343 return EFI_INVALID_PARAMETER;
344 }
345
346 if (!TisPcPresenceCheck (TisReg)) {
347 return EFI_NOT_FOUND;
348 }
349
350 MmioWrite8((UINTN)&TisReg->Access, TIS_PC_ACC_RQUUSE);
351 Status = TisPcWaitRegisterBits (
352 &TisReg->Access,
353 (UINT8)(TIS_PC_ACC_ACTIVE |TIS_PC_VALID),
354 0,
355 TIS_TIMEOUT_A
356 );
357 return Status;
358 }
359
360 /**
361 Send a command to TPM for execution and return response data.
362
363 @param[in] TisReg TPM register space base address.
364 @param[in] BufferIn Buffer for command data.
365 @param[in] SizeIn Size of command data.
366 @param[in, out] BufferOut Buffer for response data.
367 @param[in, out] SizeOut Size of response data.
368
369 @retval EFI_SUCCESS Operation completed successfully.
370 @retval EFI_TIMEOUT The register can't run into the expected status in time.
371 @retval EFI_BUFFER_TOO_SMALL Response data buffer is too small.
372 @retval EFI_DEVICE_ERROR Unexpected device behavior.
373 @retval EFI_UNSUPPORTED Unsupported TPM version
374
375 **/
376 EFI_STATUS
377 TisTpmCommand (
378 IN TIS_PC_REGISTERS_PTR TisReg,
379 IN UINT8 *BufferIn,
380 IN UINT32 SizeIn,
381 IN OUT UINT8 *BufferOut,
382 IN OUT UINT32 *SizeOut
383 )
384 {
385 EFI_STATUS Status;
386 UINT16 BurstCount;
387 UINT32 Index;
388 UINT32 TpmOutSize;
389 UINT16 Data16;
390 UINT32 Data32;
391
392 DEBUG_CODE (
393 UINTN DebugSize;
394
395 DEBUG ((EFI_D_INFO, "TisTpmCommand Send - "));
396 if (SizeIn > 0x100) {
397 DebugSize = 0x40;
398 } else {
399 DebugSize = SizeIn;
400 }
401 for (Index = 0; Index < DebugSize; Index++) {
402 DEBUG ((EFI_D_INFO, "%02x ", BufferIn[Index]));
403 }
404 if (DebugSize != SizeIn) {
405 DEBUG ((EFI_D_INFO, "...... "));
406 for (Index = SizeIn - 0x20; Index < SizeIn; Index++) {
407 DEBUG ((EFI_D_INFO, "%02x ", BufferIn[Index]));
408 }
409 }
410 DEBUG ((EFI_D_INFO, "\n"));
411 );
412 TpmOutSize = 0;
413
414 Status = TisPcPrepareCommand (TisReg);
415 if (EFI_ERROR (Status)){
416 DEBUG ((DEBUG_ERROR, "Tpm is not ready for command!\n"));
417 return Status;
418 }
419 //
420 // Send the command data to Tpm
421 //
422 Index = 0;
423 while (Index < SizeIn) {
424 Status = TisPcReadBurstCount (TisReg, &BurstCount);
425 if (EFI_ERROR (Status)) {
426 Status = EFI_TIMEOUT;
427 goto Exit;
428 }
429 for (; BurstCount > 0 && Index < SizeIn; BurstCount--) {
430 MmioWrite8((UINTN)&TisReg->DataFifo, *(BufferIn + Index));
431 Index++;
432 }
433 }
434 //
435 // Check the Tpm status STS_EXPECT change from 1 to 0
436 //
437 Status = TisPcWaitRegisterBits (
438 &TisReg->Status,
439 (UINT8) TIS_PC_VALID,
440 TIS_PC_STS_EXPECT,
441 TIS_TIMEOUT_C
442 );
443 if (EFI_ERROR (Status)) {
444 DEBUG ((DEBUG_ERROR, "The send buffer too small!\n"));
445 Status = EFI_BUFFER_TOO_SMALL;
446 goto Exit;
447 }
448 //
449 // Executed the TPM command and waiting for the response data ready
450 //
451 MmioWrite8((UINTN)&TisReg->Status, TIS_PC_STS_GO);
452
453 //
454 // NOTE: That may take many seconds to minutes for certain commands, such as key generation.
455 //
456 Status = TisPcWaitRegisterBits (
457 &TisReg->Status,
458 (UINT8) (TIS_PC_VALID | TIS_PC_STS_DATA),
459 0,
460 TIS_TIMEOUT_MAX
461 );
462 if (EFI_ERROR (Status)) {
463 DEBUG ((DEBUG_ERROR, "Wait for Tpm response data time out!!\n"));
464 Status = EFI_TIMEOUT;
465 goto Exit;
466 }
467 //
468 // Get response data header
469 //
470 Index = 0;
471 BurstCount = 0;
472 while (Index < sizeof (TPM2_RESPONSE_HEADER)) {
473 Status = TisPcReadBurstCount (TisReg, &BurstCount);
474 if (EFI_ERROR (Status)) {
475 Status = EFI_TIMEOUT;
476 goto Exit;
477 }
478 for (; BurstCount > 0; BurstCount--) {
479 *(BufferOut + Index) = MmioRead8 ((UINTN)&TisReg->DataFifo);
480 Index++;
481 if (Index == sizeof (TPM2_RESPONSE_HEADER)) break;
482 }
483 }
484 DEBUG_CODE (
485 DEBUG ((EFI_D_INFO, "TisTpmCommand ReceiveHeader - "));
486 for (Index = 0; Index < sizeof (TPM2_RESPONSE_HEADER); Index++) {
487 DEBUG ((EFI_D_INFO, "%02x ", BufferOut[Index]));
488 }
489 DEBUG ((EFI_D_INFO, "\n"));
490 );
491 //
492 // Check the reponse data header (tag,parasize and returncode )
493 //
494 CopyMem (&Data16, BufferOut, sizeof (UINT16));
495 // TPM2 should not use this RSP_COMMAND
496 if (SwapBytes16 (Data16) == TPM_ST_RSP_COMMAND) {
497 DEBUG ((EFI_D_ERROR, "TPM_ST_RSP error - %x\n", TPM_ST_RSP_COMMAND));
498 Status = EFI_UNSUPPORTED;
499 goto Exit;
500 }
501
502 CopyMem (&Data32, (BufferOut + 2), sizeof (UINT32));
503 TpmOutSize = SwapBytes32 (Data32);
504 if (*SizeOut < TpmOutSize) {
505 Status = EFI_BUFFER_TOO_SMALL;
506 goto Exit;
507 }
508 *SizeOut = TpmOutSize;
509 //
510 // Continue reading the remaining data
511 //
512 while ( Index < TpmOutSize ) {
513 for (; BurstCount > 0; BurstCount--) {
514 *(BufferOut + Index) = MmioRead8 ((UINTN)&TisReg->DataFifo);
515 Index++;
516 if (Index == TpmOutSize) {
517 Status = EFI_SUCCESS;
518 goto Exit;
519 }
520 }
521 Status = TisPcReadBurstCount (TisReg, &BurstCount);
522 if (EFI_ERROR (Status)) {
523 Status = EFI_TIMEOUT;
524 goto Exit;
525 }
526 }
527 Exit:
528 DEBUG_CODE (
529 DEBUG ((EFI_D_INFO, "TisTpmCommand Receive - "));
530 for (Index = 0; Index < TpmOutSize; Index++) {
531 DEBUG ((EFI_D_INFO, "%02x ", BufferOut[Index]));
532 }
533 DEBUG ((EFI_D_INFO, "\n"));
534 );
535 MmioWrite8((UINTN)&TisReg->Status, TIS_PC_STS_READY);
536 return Status;
537 }
538
539 /**
540 This service enables the sending of commands to the TPM2.
541
542 @param[in] InputParameterBlockSize Size of the TPM2 input parameter block.
543 @param[in] InputParameterBlock Pointer to the TPM2 input parameter block.
544 @param[in,out] OutputParameterBlockSize Size of the TPM2 output parameter block.
545 @param[in] OutputParameterBlock Pointer to the TPM2 output parameter block.
546
547 @retval EFI_SUCCESS The command byte stream was successfully sent to the device and a response was successfully received.
548 @retval EFI_DEVICE_ERROR The command was not successfully sent to the device or a response was not successfully received from the device.
549 @retval EFI_BUFFER_TOO_SMALL The output parameter block is too small.
550 **/
551 EFI_STATUS
552 EFIAPI
553 DTpm2SubmitCommand (
554 IN UINT32 InputParameterBlockSize,
555 IN UINT8 *InputParameterBlock,
556 IN OUT UINT32 *OutputParameterBlockSize,
557 IN UINT8 *OutputParameterBlock
558 )
559 {
560 return TisTpmCommand (
561 (TIS_PC_REGISTERS_PTR) (UINTN) PcdGet64 (PcdTpmBaseAddress),
562 InputParameterBlock,
563 InputParameterBlockSize,
564 OutputParameterBlock,
565 OutputParameterBlockSize
566 );
567 }
568
569 /**
570 This service requests use TPM2.
571
572 @retval EFI_SUCCESS Get the control of TPM2 chip.
573 @retval EFI_NOT_FOUND TPM2 not found.
574 @retval EFI_DEVICE_ERROR Unexpected device behavior.
575 **/
576 EFI_STATUS
577 EFIAPI
578 DTpm2RequestUseTpm (
579 VOID
580 )
581 {
582 return TisPcRequestUseTpm ((TIS_PC_REGISTERS_PTR) (UINTN) PcdGet64 (PcdTpmBaseAddress));
583 }