2 TIS (TPM Interface Specification) functions used by TPM Dxe driver.
4 Copyright (c) 2005 - 2012, 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
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.
15 #include <IndustryStandard/Tpm12.h>
16 #include <Library/TimerLib.h>
17 #include <Library/TpmCommLib.h>
18 #include <Library/DebugLib.h>
19 #include <Library/IoLib.h>
20 #include <Library/BaseLib.h>
21 #include <Library/BaseMemoryLib.h>
23 STATIC UINT8 TpmCommandBuf
[TPMCMDBUFLENGTH
];
26 Send command to TPM for execution.
28 @param[in] TisReg TPM register space base address.
29 @param[in] TpmBuffer Buffer for TPM command data.
30 @param[in] DataLength TPM command data length.
32 @retval EFI_SUCCESS Operation completed successfully.
33 @retval EFI_TIMEOUT The register can't run into the expected status in time.
38 IN TIS_PC_REGISTERS_PTR TisReg
,
47 Status
= TisPcPrepareCommand (TisReg
);
48 if (EFI_ERROR (Status
)){
49 DEBUG ((DEBUG_ERROR
, "The Tpm not ready!\n"));
53 while (Index
< DataLength
) {
54 Status
= TisPcReadBurstCount (TisReg
, &BurstCount
);
55 if (EFI_ERROR (Status
)) {
58 for (; BurstCount
> 0 && Index
< DataLength
; BurstCount
--) {
59 MmioWrite8 ((UINTN
) &TisReg
->DataFifo
, *(TpmBuffer
+ Index
));
64 // Ensure the Tpm status STS_EXPECT change from 1 to 0
66 Status
= TisPcWaitRegisterBits (
76 Receive response data of last command from TPM.
78 @param[in] TisReg TPM register space base address.
79 @param[out] TpmBuffer Buffer for response data.
80 @param[out] RespSize Response data length.
82 @retval EFI_SUCCESS Operation completed successfully.
83 @retval EFI_TIMEOUT The register can't run into the expected status in time.
84 @retval EFI_DEVICE_ERROR Unexpected device status.
85 @retval EFI_BUFFER_TOO_SMALL Response data is too long.
90 IN TIS_PC_REGISTERS_PTR TisReg
,
102 // Wait for the command completion
104 Status
= TisPcWaitRegisterBits (
106 (UINT8
) (TIS_PC_VALID
| TIS_PC_STS_DATA
),
110 if (EFI_ERROR (Status
)) {
114 // Read the response data header and check it
118 while (Index
< sizeof (TPM_RSP_COMMAND_HDR
)) {
119 Status
= TisPcReadBurstCount (TisReg
, &BurstCount
);
120 if (EFI_ERROR (Status
)) {
123 for (; BurstCount
> 0 ; BurstCount
--) {
124 *(TpmBuffer
+ Index
) = MmioRead8 ((UINTN
) &TisReg
->DataFifo
);
126 if (Index
== sizeof (TPM_RSP_COMMAND_HDR
))
131 // Check the reponse data header (tag,parasize and returncode )
133 CopyMem (&Data32
, (TpmBuffer
+ 2), sizeof (UINT32
));
134 ResponseSize
= SwapBytes32 (Data32
);
135 *RespSize
= ResponseSize
;
136 if (ResponseSize
== sizeof (TPM_RSP_COMMAND_HDR
)) {
139 if (ResponseSize
< sizeof (TPM_RSP_COMMAND_HDR
)) {
140 return EFI_DEVICE_ERROR
;
142 if (ResponseSize
> TPMCMDBUFLENGTH
) {
143 return EFI_BUFFER_TOO_SMALL
;
146 // Continue reading the remaining data
148 while (Index
< ResponseSize
) {
149 for (; BurstCount
> 0 ; BurstCount
--) {
150 *(TpmBuffer
+ Index
) = MmioRead8 ((UINTN
) &TisReg
->DataFifo
);
152 if (Index
== ResponseSize
) {
156 Status
= TisPcReadBurstCount (TisReg
, &BurstCount
);
157 if (EFI_ERROR (Status
) && (Index
< ResponseSize
)) {
158 return EFI_DEVICE_ERROR
;
165 Format TPM command data according to the format control character.
167 @param[in] FmtChar Format control character.
168 @param[in, out] ap List of arguments.
169 @param[in] TpmBuffer Buffer for TPM command data.
170 @param[out] DataLength TPM command data length.
172 @retval EFI_SUCCESS Operation completed successfully.
173 @retval EFI_INVALID_PARAMETER Invalid format control character.
174 @retval EFI_BUFFER_TOO_SMALL Buffer too small for command data.
188 TPM_RQU_COMMAND_HDR TpmCmdHdr
;
189 TPM_RQU_COMMAND_HDR
*TpmCmdPtr
;
196 DataByte
= VA_ARG (*ap
, UINT8
);
198 Size
= sizeof (DataByte
);
202 DataWord
= VA_ARG (*ap
, UINT16
);
203 DataWord
= SwapBytes16 (DataWord
);
204 Raw
= (UINT8
*)&DataWord
;
205 Size
= sizeof (DataWord
);
209 DataDword
= VA_ARG (*ap
, UINT32
);
210 DataDword
= SwapBytes32 (DataDword
);
211 Raw
= (UINT8
*)&DataDword
;
212 Size
= sizeof (DataDword
);
216 TpmCmdPtr
= VA_ARG (*ap
, TPM_RQU_COMMAND_HDR
*);
217 TpmCmdHdr
.tag
= SwapBytes16 (TpmCmdPtr
->tag
);
218 TpmCmdHdr
.paramSize
= SwapBytes32 (TpmCmdPtr
->paramSize
);
219 TpmCmdHdr
.ordinal
= SwapBytes32 (TpmCmdPtr
->ordinal
);
220 Raw
= (UINT8
*) &TpmCmdHdr
;
221 Size
= sizeof (TpmCmdHdr
);
225 Raw
= VA_ARG (*ap
, UINT8
*);
226 Size
= VA_ARG (*ap
, UINTN
);
230 return EFI_INVALID_PARAMETER
;
233 return EFI_INVALID_PARAMETER
;
237 // Check input to avoid overflow.
239 if ((UINT32
) (~0)- *DataLength
< (UINT32
)Size
) {
240 return EFI_INVALID_PARAMETER
;
243 if(*DataLength
+ (UINT32
) Size
> TPMCMDBUFLENGTH
) {
244 return EFI_BUFFER_TOO_SMALL
;
246 CopyMem (TpmBuffer
+ *DataLength
, Raw
, Size
);
247 *DataLength
+= (UINT32
) Size
;
252 Format reponse data according to the format control character.
254 @param[in] FmtChar Format control character.
255 @param[in, out] ap List of arguments.
256 @param[out] TpmBuffer Buffer for reponse data.
257 @param[in, out] DataIndex Data offset in reponse data buffer.
258 @param[in] RespSize Response data length.
259 @param[out] DataFinished Reach the end of Response data.
261 @retval EFI_SUCCESS Operation completed successfully.
262 @retval EFI_INVALID_PARAMETER Invalid format control character.
263 @retval EFI_BUFFER_TOO_SMALL Buffer too small for command data.
270 OUT UINT8
*TpmBuffer
,
271 IN OUT UINT32
*DataIndex
,
273 OUT BOOLEAN
*DataFinished
277 TPM_RSP_COMMAND_HDR
*TpmRspPtr
;
280 Raw
= VA_ARG (*ap
, UINT8
*);
284 Size
= sizeof (UINT8
);
288 Size
= sizeof (UINT16
);
292 Size
= sizeof (UINT32
);
296 Size
= sizeof (*TpmRspPtr
);
300 Size
= VA_ARG (*ap
, UINTN
);
302 // If overflowed, which means Size is big enough for Response data.
303 // skip this check. Copy the whole data
305 if ((UINT32
) (~0)- *DataIndex
>= (UINT32
)Size
) {
306 if(*DataIndex
+ (UINT32
) Size
<= RespSize
) {
311 *DataFinished
= TRUE
;
312 if (*DataIndex
>= RespSize
) {
315 CopyMem (Raw
, TpmBuffer
+ *DataIndex
, RespSize
- *DataIndex
);
316 *DataIndex
+= RespSize
- *DataIndex
;
320 return EFI_INVALID_PARAMETER
;
323 return EFI_WARN_UNKNOWN_GLYPH
;
326 if(*DataIndex
+ (UINT32
) Size
> RespSize
) {
327 *DataFinished
= TRUE
;
331 if( *DataIndex
+ (UINT32
) Size
> TPMCMDBUFLENGTH
)
332 return EFI_BUFFER_TOO_SMALL
;
334 CopyMem (Raw
, TpmBuffer
+ *DataIndex
, Size
);
335 *DataIndex
+= (UINT32
) Size
;
340 *(UINT16
*)Raw
= SwapBytes16 (*(UINT16
*) Raw
);
344 *(UINT32
*)Raw
= SwapBytes32 (*(UINT32
*) Raw
);
348 TpmRspPtr
= (TPM_RSP_COMMAND_HDR
*) Raw
;
349 TpmRspPtr
->tag
= SwapBytes16 (TpmRspPtr
->tag
);
350 TpmRspPtr
->paramSize
= SwapBytes32 (TpmRspPtr
->paramSize
);
351 TpmRspPtr
->returnCode
= SwapBytes32 (TpmRspPtr
->returnCode
);
358 Send formatted command to TPM for execution and return formatted data from response.
360 @param[in] TisReg TPM Handle.
361 @param[in] Fmt Format control string.
362 @param[in] ... The variable argument list.
364 @retval EFI_SUCCESS Operation completed successfully.
365 @retval EFI_TIMEOUT The register can't run into the expected status in time.
371 IN TIS_TPM_HANDLE TisReg
,
380 BOOLEAN DataFinished
;
385 // Put the formatted command to the TpmCommandBuf
388 while (*Fmt
!= '\0') {
389 if (*Fmt
== '%') Fmt
++;
390 if (*Fmt
== '/') break;
391 Status
= TisPcSendV (*Fmt
, &Ap
, TpmCommandBuf
, &BufSize
);
392 if (EFI_ERROR( Status
)) {
398 // Send the command to TPM
400 Status
= TisPcSend (TisReg
, TpmCommandBuf
, BufSize
);
401 if (EFI_ERROR (Status
)) {
403 // Ensure the TPM state change from "Reception" to "Idle/Ready"
405 MmioWrite8 ((UINTN
) &(((TIS_PC_REGISTERS_PTR
) TisReg
)->Status
), TIS_PC_STS_READY
);
409 MmioWrite8 ((UINTN
) &(((TIS_PC_REGISTERS_PTR
) TisReg
)->Status
), TIS_PC_STS_GO
);
412 // Receive the response data from TPM
414 ZeroMem (TpmCommandBuf
, TPMCMDBUFLENGTH
);
415 Status
= TisPcReceive (TisReg
, TpmCommandBuf
, &ResponseSize
);
417 // Ensure the TPM state change from "Execution" or "Completion" to "Idle/Ready"
419 MmioWrite8 ((UINTN
) &(((TIS_PC_REGISTERS_PTR
) TisReg
)->Status
), TIS_PC_STS_READY
);
420 if (EFI_ERROR (Status
)) {
425 // Get the formatted data from the TpmCommandBuf.
428 DataFinished
= FALSE
;
429 while (*Fmt
!= '\0') {
433 Status
= TisPcReceiveV (*Fmt
, &Ap
, TpmCommandBuf
, &BufSize
, ResponseSize
, &DataFinished
);
434 if (EFI_ERROR (Status
)) {