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