]> git.proxmox.com Git - mirror_edk2.git/blob - QuarkPlatformPkg/Library/Tpm12DeviceLibInfineonI2c/TisPc.c
ShellPkg: Add FileSize member to shell memory file structure.
[mirror_edk2.git] / QuarkPlatformPkg / Library / Tpm12DeviceLibInfineonI2c / TisPc.c
1 /** @file
2 Basic TIS (TPM Interface Specification) functions for Infineon I2C TPM.
3
4 Copyright (c) 2013 - 2016, 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 <PiPei.h>
16 #include <Library/Tpm12DeviceLib.h>
17 #include <Library/BaseLib.h>
18 #include <Library/TimerLib.h>
19 #include <Library/DebugLib.h>
20 #include <Library/I2cLib.h>
21
22 //
23 // Default TPM (Infineon SLB9645) I2C Slave Device Address on Crosshill board.
24 //
25 #define TPM_I2C_SLAVE_DEVICE_ADDRESS 0x20
26
27 //
28 // Default Infineon SLB9645 TPM I2C mapped registers (SLB9645 I2C Comm. Protocol Application Note).
29 //
30 #define INFINEON_TPM_ACCESS_0_ADDRESS_DEFAULT 0x0
31 #define INFINEON_TPM_STS_0_ADDRESS_DEFAULT 0x01
32 #define INFINEON_TPM_BURST0_COUNT_0_DEFAULT 0x02
33 #define INFINEON_TPM_BURST1_COUNT_0_DEFAULT 0x03
34 #define INFINEON_TPM_DATA_FIFO_0_ADDRESS_DEFAULT 0x05
35 #define INFINEON_TPM_DID_VID_0_DEFAULT 0x09
36
37 //
38 // Max. retry count for read transfers (as recommended by Infineon).
39 //
40 #define READ_RETRY 3
41
42 //
43 // Guard time of 250us between I2C read and next I2C write transfer (as recommended by Infineon).
44 //
45 #define GUARD_TIME 250
46
47 //
48 // Define bits of ACCESS and STATUS registers
49 //
50
51 ///
52 /// This bit is a 1 to indicate that the other bits in this register are valid.
53 ///
54 #define TIS_PC_VALID BIT7
55 ///
56 /// Indicate that this locality is active.
57 ///
58 #define TIS_PC_ACC_ACTIVE BIT5
59 ///
60 /// Set to 1 to indicate that this locality had the TPM taken away while
61 /// this locality had the TIS_PC_ACC_ACTIVE bit set.
62 ///
63 #define TIS_PC_ACC_SEIZED BIT4
64 ///
65 /// Set to 1 to indicate that TPM MUST reset the
66 /// TIS_PC_ACC_ACTIVE bit and remove ownership for localities less than the
67 /// locality that is writing this bit.
68 ///
69 #define TIS_PC_ACC_SEIZE BIT3
70 ///
71 /// When this bit is 1, another locality is requesting usage of the TPM.
72 ///
73 #define TIS_PC_ACC_PENDIND BIT2
74 ///
75 /// Set to 1 to indicate that this locality is requesting to use TPM.
76 ///
77 #define TIS_PC_ACC_RQUUSE BIT1
78 ///
79 /// A value of 1 indicates that a T/OS has not been established on the platform
80 ///
81 #define TIS_PC_ACC_ESTABLISH BIT0
82
83 ///
84 /// When this bit is 1, TPM is in the Ready state,
85 /// indicating it is ready to receive a new command.
86 ///
87 #define TIS_PC_STS_READY BIT6
88 ///
89 /// Write a 1 to this bit to cause the TPM to execute that command.
90 ///
91 #define TIS_PC_STS_GO BIT5
92 ///
93 /// This bit indicates that the TPM has data available as a response.
94 ///
95 #define TIS_PC_STS_DATA BIT4
96 ///
97 /// The TPM sets this bit to a value of 1 when it expects another byte of data for a command.
98 ///
99 #define TIS_PC_STS_EXPECT BIT3
100 ///
101 /// Writes a 1 to this bit to force the TPM to re-send the response.
102 ///
103 #define TIS_PC_STS_RETRY BIT1
104
105 //
106 // Default TimeOut values in microseconds
107 //
108 #define TIS_TIMEOUT_A (750 * 1000) // 750ms
109 #define TIS_TIMEOUT_B (2000 * 1000) // 2s
110 #define TIS_TIMEOUT_C (750 * 1000) // 750ms
111 #define TIS_TIMEOUT_D (750 * 1000) // 750ms
112
113 //
114 // Global variable to indicate if TPM I2C Read Transfer has previously occurred.
115 // NOTE: Given the GUARD_TIME requirement (TpmAccess.h), if this library loaded
116 // by PEI Drivers this global variable required to be resident in R/W memory
117 //
118 BOOLEAN mI2CPrevReadTransfer = FALSE;
119
120 /**
121 Writes single byte data to TPM specified by I2C register address.
122
123 @param[in] TpmAddress The register to write.
124 @param[in] Data The data to write to the register.
125
126 **/
127 VOID
128 TpmWriteByte (
129 IN UINTN TpmAddress,
130 IN UINT8 Data
131 )
132 {
133 EFI_STATUS Status;
134 UINTN WriteLength;
135 UINT8 WriteData[2];
136 EFI_I2C_DEVICE_ADDRESS I2CDeviceAddr;
137
138 //
139 // Setup I2C Slave device address and address mode (7-bit).
140 //
141 I2CDeviceAddr.I2CDeviceAddress = TPM_I2C_SLAVE_DEVICE_ADDRESS;
142
143 //
144 // As recommended by Infineon (SLB9645 I2C Communication protocol application
145 // note revision 1.0) wait 250 microseconds between a read and a write transfer.
146 //
147 if (mI2CPrevReadTransfer) {
148 MicroSecondDelay (GUARD_TIME);
149 }
150
151 //
152 // Write to TPM register.
153 //
154 WriteLength = 2;
155 WriteData[0] = (UINT8)TpmAddress;
156 WriteData[1] = Data;
157
158 Status = I2cWriteMultipleByte (
159 I2CDeviceAddr,
160 EfiI2CSevenBitAddrMode,
161 &WriteLength,
162 &WriteData
163 );
164 if (EFI_ERROR(Status)) {
165 DEBUG ((EFI_D_ERROR, "TpmWriteByte(): I2C Write to TPM address %0x failed (%r)\n", TpmAddress, Status));
166 ASSERT (FALSE); // Writes to TPM should always succeed.
167 }
168
169 mI2CPrevReadTransfer = FALSE;
170 }
171
172 /**
173 Reads single byte data from TPM specified by I2C register address.
174
175 Due to stability issues when using I2C combined write/read transfers (with
176 RESTART) to TPM (specifically read from status register), a single write is
177 performed followed by single read (with STOP condition in between).
178
179 @param[in] TpmAddress Address of register to read.
180
181 @return The value register read.
182
183 **/
184 UINT8
185 TpmReadByte (
186 IN UINTN TpmAddress
187 )
188 {
189 UINT8 Data[1];
190 UINT8 ReadData;
191 UINT8 ReadCount;
192
193 EFI_I2C_DEVICE_ADDRESS I2CDeviceAddr;
194 EFI_I2C_ADDR_MODE I2CAddrMode;
195
196 EFI_STATUS Status;
197
198 Status = EFI_SUCCESS;
199 ReadData = 0xFF;
200 ReadCount = 0;
201
202 //
203 // Locate I2C protocol for TPM I2C access.
204 //
205 I2CDeviceAddr.I2CDeviceAddress = TPM_I2C_SLAVE_DEVICE_ADDRESS;
206 I2CAddrMode = EfiI2CSevenBitAddrMode;
207
208 //
209 // As recommended by Infineon (SLB9645 I2C Communication protocol application
210 // note revision 1.0) retry up to 3 times if TPM status, access or burst count
211 // registers return 0xFF.
212 //
213 while ((ReadData == 0xFF) && (ReadCount < READ_RETRY)) {
214 //
215 // As recommended by Infineon (SLB9645 I2C Communication protocol application
216 // note revision 1.0) wait 250 microseconds between a read and a write transfer.
217 //
218 if (mI2CPrevReadTransfer) {
219 MicroSecondDelay (GUARD_TIME);
220 }
221
222 //
223 // Write address to TPM.
224 //
225 Data[0] = (UINT8)TpmAddress;
226 Status = I2cWriteByte (
227 I2CDeviceAddr,
228 I2CAddrMode,
229 &Data
230 );
231
232 if (EFI_ERROR(Status)) {
233 DEBUG ((EFI_D_INFO, "TpmReadByte(): write to TPM address %0x failed (%r)\n", TpmAddress, Status));
234 }
235
236 mI2CPrevReadTransfer = FALSE;
237
238 //
239 // Read data from TPM.
240 //
241 Data[0] = (UINT8)TpmAddress;
242 Status = I2cReadByte (
243 I2CDeviceAddr,
244 I2CAddrMode,
245 &Data
246 );
247
248 if (EFI_ERROR(Status)) {
249 DEBUG ((EFI_D_INFO, "TpmReadByte(): read from TPM address %0x failed (%r)\n", TpmAddress, Status));
250 ReadData = 0xFF;
251 } else {
252 ReadData = Data[0];
253 }
254
255 //
256 // Only need to retry 3 times for TPM status, access, and burst count registers.
257 // If read transfer is to TPM Data FIFO, do not retry, exit loop.
258 //
259 if (TpmAddress == INFINEON_TPM_DATA_FIFO_0_ADDRESS_DEFAULT) {
260 ReadCount = READ_RETRY;
261 } else {
262 ReadCount++;
263 }
264
265 mI2CPrevReadTransfer = TRUE;
266 }
267
268 if (EFI_ERROR(Status)) {
269 //
270 // Only reads to access register allowed to fail.
271 //
272 if (TpmAddress != INFINEON_TPM_ACCESS_0_ADDRESS_DEFAULT) {
273 DEBUG ((EFI_D_ERROR, "TpmReadByte(): read from TPM address %0x failed\n", TpmAddress));
274 ASSERT_EFI_ERROR (Status);
275 }
276 }
277 return ReadData;
278 }
279
280 /**
281 Check whether the value of a TPM chip register satisfies the input BIT setting.
282
283 @param[in] Register TPM register to be checked.
284 @param[in] BitSet Check these data bits are set.
285 @param[in] BitClear Check these data bits are clear.
286 @param[in] TimeOut The max wait time (unit MicroSecond) when checking register.
287
288 @retval EFI_SUCCESS The register satisfies the check bit.
289 @retval EFI_TIMEOUT The register can't run into the expected status in time.
290 **/
291 EFI_STATUS
292 TisPcWaitRegisterBits (
293 IN UINTN Register,
294 IN UINT8 BitSet,
295 IN UINT8 BitClear,
296 IN UINT32 TimeOut
297 )
298 {
299 UINT8 RegRead;
300 UINT32 WaitTime;
301
302 for (WaitTime = 0; WaitTime < TimeOut; WaitTime += 30){
303 RegRead = TpmReadByte (Register);
304 if ((RegRead & BitSet) == BitSet && (RegRead & BitClear) == 0)
305 return EFI_SUCCESS;
306 MicroSecondDelay (30);
307 }
308 return EFI_TIMEOUT;
309 }
310
311 /**
312 Get BurstCount by reading the burstCount field of a TIS register
313 in the time of default TIS_TIMEOUT_D.
314
315 @param[out] BurstCount Pointer to a buffer to store the got BurstConut.
316
317 @retval EFI_SUCCESS Get BurstCount.
318 @retval EFI_INVALID_PARAMETER BurstCount is NULL.
319 @retval EFI_TIMEOUT BurstCount can't be got in time.
320 **/
321 EFI_STATUS
322 TisPcReadBurstCount (
323 OUT UINT16 *BurstCount
324 )
325 {
326 UINT32 WaitTime;
327 UINT8 DataByte0;
328 UINT8 DataByte1;
329
330 if (BurstCount == NULL) {
331 return EFI_INVALID_PARAMETER;
332 }
333
334 WaitTime = 0;
335 do {
336 //
337 // BurstCount is UINT16, but it is not 2bytes aligned,
338 // so it needs to use TpmReadByte to read two times
339 //
340 DataByte0 = TpmReadByte (INFINEON_TPM_BURST0_COUNT_0_DEFAULT);
341 DataByte1 = TpmReadByte (INFINEON_TPM_BURST1_COUNT_0_DEFAULT);
342 *BurstCount = (UINT16)((DataByte1 << 8) + DataByte0);
343 if (*BurstCount != 0) {
344 return EFI_SUCCESS;
345 }
346 MicroSecondDelay (30);
347 WaitTime += 30;
348 } while (WaitTime < TIS_TIMEOUT_D);
349
350 return EFI_TIMEOUT;
351 }
352
353 /**
354 Set TPM chip to ready state by sending ready command TIS_PC_STS_READY
355 to Status Register in time.
356
357 @retval EFI_SUCCESS TPM chip enters into ready state.
358 @retval EFI_TIMEOUT TPM chip can't be set to ready state in time.
359 **/
360 EFI_STATUS
361 TisPcPrepareCommand (
362 VOID
363 )
364 {
365 EFI_STATUS Status;
366
367 TpmWriteByte (INFINEON_TPM_STS_0_ADDRESS_DEFAULT, TIS_PC_STS_READY);
368 Status = TisPcWaitRegisterBits (
369 INFINEON_TPM_STS_0_ADDRESS_DEFAULT,
370 TIS_PC_STS_READY,
371 0,
372 TIS_TIMEOUT_B
373 );
374 return Status;
375 }
376
377 /**
378 This service requests use TPM12.
379
380 @retval EFI_SUCCESS Get the control of TPM12 chip.
381 @retval EFI_NOT_FOUND TPM12 not found.
382 @retval EFI_DEVICE_ERROR Unexpected device behavior.
383 **/
384 EFI_STATUS
385 EFIAPI
386 Tpm12RequestUseTpm (
387 VOID
388 )
389 {
390 EFI_STATUS Status;
391
392 //
393 // Check to see if TPM exists
394 //
395 if (TpmReadByte (INFINEON_TPM_ACCESS_0_ADDRESS_DEFAULT) == 0xFF) {
396 return EFI_NOT_FOUND;
397 }
398
399 TpmWriteByte (INFINEON_TPM_ACCESS_0_ADDRESS_DEFAULT, TIS_PC_ACC_RQUUSE);
400
401 //
402 // No locality set before, ACCESS_X.activeLocality MUST be valid within TIMEOUT_A
403 //
404 Status = TisPcWaitRegisterBits (
405 INFINEON_TPM_ACCESS_0_ADDRESS_DEFAULT,
406 (UINT8)(TIS_PC_ACC_ACTIVE |TIS_PC_VALID),
407 0,
408 TIS_TIMEOUT_A
409 );
410 return Status;
411 }
412
413 /**
414 Send command to TPM for execution.
415
416 @param[in] TpmBuffer Buffer for TPM command data.
417 @param[in] DataLength TPM command data length.
418
419 @retval EFI_SUCCESS Operation completed successfully.
420 @retval EFI_TIMEOUT The register can't run into the expected status in time.
421
422 **/
423 EFI_STATUS
424 TisPcSend (
425 IN UINT8 *TpmBuffer,
426 IN UINT32 DataLength
427 )
428 {
429 UINT16 BurstCount;
430 UINT32 Index;
431 EFI_STATUS Status;
432
433 Status = TisPcPrepareCommand ();
434 if (EFI_ERROR (Status)){
435 DEBUG ((DEBUG_ERROR, "The TPM is not ready!\n"));
436 goto Done;
437 }
438 Index = 0;
439 while (Index < DataLength) {
440 Status = TisPcReadBurstCount (&BurstCount);
441 if (EFI_ERROR (Status)) {
442 Status = EFI_TIMEOUT;
443 goto Done;
444 }
445 for (; BurstCount > 0 && Index < DataLength; BurstCount--) {
446 TpmWriteByte (INFINEON_TPM_DATA_FIFO_0_ADDRESS_DEFAULT, *(TpmBuffer + Index));
447 Index++;
448 }
449 }
450 //
451 // Ensure the TPM status STS_EXPECT change from 1 to 0
452 //
453 Status = TisPcWaitRegisterBits (
454 INFINEON_TPM_STS_0_ADDRESS_DEFAULT,
455 (UINT8) TIS_PC_VALID,
456 TIS_PC_STS_EXPECT,
457 TIS_TIMEOUT_C
458 );
459 if (EFI_ERROR (Status)) {
460 goto Done;
461 }
462
463 //
464 // Start the command
465 //
466 TpmWriteByte (INFINEON_TPM_STS_0_ADDRESS_DEFAULT, TIS_PC_STS_GO);
467
468 Done:
469 if (EFI_ERROR (Status)) {
470 //
471 // Ensure the TPM state change from "Reception" to "Idle/Ready"
472 //
473 TpmWriteByte (INFINEON_TPM_STS_0_ADDRESS_DEFAULT, TIS_PC_STS_READY);
474 }
475
476 return Status;
477 }
478
479 /**
480 Receive response data of last command from TPM.
481
482 @param[out] TpmBuffer Buffer for response data.
483 @param[out] RespSize Response data length.
484
485 @retval EFI_SUCCESS Operation completed successfully.
486 @retval EFI_TIMEOUT The register can't run into the expected status in time.
487 @retval EFI_DEVICE_ERROR Unexpected device status.
488 @retval EFI_BUFFER_TOO_SMALL Response data is too long.
489
490 **/
491 EFI_STATUS
492 TisPcReceive (
493 OUT UINT8 *TpmBuffer,
494 OUT UINT32 *RespSize
495 )
496 {
497 EFI_STATUS Status;
498 UINT16 BurstCount;
499 UINT32 Index;
500 UINT32 ResponseSize;
501 TPM_RSP_COMMAND_HDR *ResponseHeader;
502
503 //
504 // Wait for the command completion
505 //
506 Status = TisPcWaitRegisterBits (
507 INFINEON_TPM_STS_0_ADDRESS_DEFAULT,
508 (UINT8) (TIS_PC_VALID | TIS_PC_STS_DATA),
509 0,
510 TIS_TIMEOUT_B
511 );
512 if (EFI_ERROR (Status)) {
513 Status = EFI_TIMEOUT;
514 goto Done;
515 }
516 //
517 // Read the response data header and check it
518 //
519 Index = 0;
520 BurstCount = 0;
521 while (Index < sizeof (TPM_RSP_COMMAND_HDR)) {
522 Status = TisPcReadBurstCount (&BurstCount);
523 if (EFI_ERROR (Status)) {
524 Status = EFI_TIMEOUT;
525 goto Done;
526 }
527 for (; BurstCount > 0 ; BurstCount--) {
528 *(TpmBuffer + Index) = TpmReadByte (INFINEON_TPM_DATA_FIFO_0_ADDRESS_DEFAULT);
529 Index++;
530 if (Index == sizeof (TPM_RSP_COMMAND_HDR))
531 break;
532 }
533 }
534
535 //
536 // Check the response data header (tag, parasize and returncode)
537 //
538 ResponseHeader = (TPM_RSP_COMMAND_HDR *)TpmBuffer;
539 if (SwapBytes16 (ReadUnaligned16 (&ResponseHeader->tag)) != TPM_TAG_RSP_COMMAND) {
540 Status = EFI_DEVICE_ERROR;
541 goto Done;
542 }
543
544 ResponseSize = SwapBytes32 (ReadUnaligned32 (&ResponseHeader->paramSize));
545 if (ResponseSize == sizeof (TPM_RSP_COMMAND_HDR)) {
546 Status = EFI_SUCCESS;
547 goto Done;
548 }
549 if (ResponseSize < sizeof (TPM_RSP_COMMAND_HDR)) {
550 Status = EFI_DEVICE_ERROR;
551 goto Done;
552 }
553 if (*RespSize < ResponseSize) {
554 Status = EFI_BUFFER_TOO_SMALL;
555 goto Done;
556 }
557 *RespSize = ResponseSize;
558
559 //
560 // Continue reading the remaining data
561 //
562 while (Index < ResponseSize) {
563 for (; BurstCount > 0 ; BurstCount--) {
564 *(TpmBuffer + Index) = TpmReadByte (INFINEON_TPM_DATA_FIFO_0_ADDRESS_DEFAULT);
565 Index++;
566 if (Index == ResponseSize) {
567 Status = EFI_SUCCESS;
568 goto Done;
569 }
570 }
571 Status = TisPcReadBurstCount (&BurstCount);
572 if (EFI_ERROR (Status) && (Index < ResponseSize)) {
573 Status = EFI_DEVICE_ERROR;
574 goto Done;
575 }
576 }
577
578 Done:
579 //
580 // Ensure the TPM state change from "Execution" or "Completion" to "Idle/Ready"
581 //
582 TpmWriteByte (INFINEON_TPM_STS_0_ADDRESS_DEFAULT, TIS_PC_STS_READY);
583
584 return Status;
585 }
586
587 /**
588 This service enables the sending of commands to the TPM12.
589
590 @param[in] InputParameterBlockSize Size of the TPM12 input parameter block.
591 @param[in] InputParameterBlock Pointer to the TPM12 input parameter block.
592 @param[in,out] OutputParameterBlockSize Size of the TPM12 output parameter block.
593 @param[in] OutputParameterBlock Pointer to the TPM12 output parameter block.
594
595 @retval EFI_SUCCESS The command byte stream was successfully sent to
596 the device and a response was successfully received.
597 @retval EFI_DEVICE_ERROR The command was not successfully sent to the
598 device or a response was not successfully received
599 from the device.
600 @retval EFI_BUFFER_TOO_SMALL The output parameter block is too small.
601 **/
602 EFI_STATUS
603 EFIAPI
604 Tpm12SubmitCommand (
605 IN UINT32 InputParameterBlockSize,
606 IN UINT8 *InputParameterBlock,
607 IN OUT UINT32 *OutputParameterBlockSize,
608 IN UINT8 *OutputParameterBlock
609 )
610 {
611 EFI_STATUS Status;
612
613 Status = TisPcSend (InputParameterBlock, InputParameterBlockSize);
614 if (!EFI_ERROR (Status)) {
615 Status = TisPcReceive (OutputParameterBlock, OutputParameterBlockSize);
616 }
617 return Status;
618 }