]> git.proxmox.com Git - mirror_edk2.git/blob - SecurityPkg/Tcg/TcgDxe/TisDxe.c
SecurityPkg: TcgDxe,Tcg2Dxe,TrEEDxe: New PCD for TCG event log and TCG2 final event...
[mirror_edk2.git] / SecurityPkg / Tcg / TcgDxe / TisDxe.c
1 /** @file
2 TIS (TPM Interface Specification) functions used by TPM Dxe driver.
3
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
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/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>
22
23 STATIC UINT8 TpmCommandBuf[TPMCMDBUFLENGTH];
24
25 /**
26 Send command to TPM for execution.
27
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.
31
32 @retval EFI_SUCCESS Operation completed successfully.
33 @retval EFI_TIMEOUT The register can't run into the expected status in time.
34
35 **/
36 EFI_STATUS
37 TisPcSend (
38 IN TIS_PC_REGISTERS_PTR TisReg,
39 IN UINT8 *TpmBuffer,
40 IN UINT32 DataLength
41 )
42 {
43 UINT16 BurstCount;
44 UINT32 Index;
45 EFI_STATUS Status;
46
47 Status = TisPcPrepareCommand (TisReg);
48 if (EFI_ERROR (Status)){
49 DEBUG ((DEBUG_ERROR, "The Tpm not ready!\n"));
50 return Status;
51 }
52 Index = 0;
53 while (Index < DataLength) {
54 Status = TisPcReadBurstCount (TisReg, &BurstCount);
55 if (EFI_ERROR (Status)) {
56 return EFI_TIMEOUT;
57 }
58 for (; BurstCount > 0 && Index < DataLength; BurstCount--) {
59 MmioWrite8 ((UINTN) &TisReg->DataFifo, *(TpmBuffer + Index));
60 Index++;
61 }
62 }
63 //
64 // Ensure the Tpm status STS_EXPECT change from 1 to 0
65 //
66 Status = TisPcWaitRegisterBits (
67 &TisReg->Status,
68 (UINT8) TIS_PC_VALID,
69 TIS_PC_STS_EXPECT,
70 TIS_TIMEOUT_C
71 );
72 return Status;
73 }
74
75 /**
76 Receive response data of last command from TPM.
77
78 @param[in] TisReg TPM register space base address.
79 @param[out] TpmBuffer Buffer for response data.
80 @param[out] RespSize Response data length.
81
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.
86
87 **/
88 EFI_STATUS
89 TisPcReceive (
90 IN TIS_PC_REGISTERS_PTR TisReg,
91 OUT UINT8 *TpmBuffer,
92 OUT UINT32 *RespSize
93 )
94 {
95 EFI_STATUS Status;
96 UINT16 BurstCount;
97 UINT32 Index;
98 UINT32 ResponseSize;
99 UINT32 Data32;
100
101 //
102 // Wait for the command completion
103 //
104 Status = TisPcWaitRegisterBits (
105 &TisReg->Status,
106 (UINT8) (TIS_PC_VALID | TIS_PC_STS_DATA),
107 0,
108 TIS_TIMEOUT_B
109 );
110 if (EFI_ERROR (Status)) {
111 return EFI_TIMEOUT;
112 }
113 //
114 // Read the response data header and check it
115 //
116 Index = 0;
117 BurstCount = 0;
118 while (Index < sizeof (TPM_RSP_COMMAND_HDR)) {
119 Status = TisPcReadBurstCount (TisReg, &BurstCount);
120 if (EFI_ERROR (Status)) {
121 return EFI_TIMEOUT;
122 }
123 for (; BurstCount > 0 ; BurstCount--) {
124 *(TpmBuffer + Index) = MmioRead8 ((UINTN) &TisReg->DataFifo);
125 Index++;
126 if (Index == sizeof (TPM_RSP_COMMAND_HDR))
127 break;
128 }
129 }
130 //
131 // Check the reponse data header (tag,parasize and returncode )
132 //
133 CopyMem (&Data32, (TpmBuffer + 2), sizeof (UINT32));
134 ResponseSize = SwapBytes32 (Data32);
135 *RespSize = ResponseSize;
136 if (ResponseSize == sizeof (TPM_RSP_COMMAND_HDR)) {
137 return EFI_SUCCESS;
138 }
139 if (ResponseSize < sizeof (TPM_RSP_COMMAND_HDR)) {
140 return EFI_DEVICE_ERROR;
141 }
142 if (ResponseSize > TPMCMDBUFLENGTH) {
143 return EFI_BUFFER_TOO_SMALL;
144 }
145 //
146 // Continue reading the remaining data
147 //
148 while (Index < ResponseSize) {
149 for (; BurstCount > 0 ; BurstCount--) {
150 *(TpmBuffer + Index) = MmioRead8 ((UINTN) &TisReg->DataFifo);
151 Index++;
152 if (Index == ResponseSize) {
153 return EFI_SUCCESS;
154 }
155 }
156 Status = TisPcReadBurstCount (TisReg, &BurstCount);
157 if (EFI_ERROR (Status) && (Index < ResponseSize)) {
158 return EFI_DEVICE_ERROR;
159 }
160 }
161 return EFI_SUCCESS;
162 }
163
164 /**
165 Format TPM command data according to the format control character.
166
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.
171
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.
175
176 **/
177 EFI_STATUS
178 TisPcSendV (
179 IN UINT8 FmtChar,
180 IN OUT VA_LIST *ap,
181 UINT8 *TpmBuffer,
182 UINT32 *DataLength
183 )
184 {
185 UINT8 DataByte;
186 UINT16 DataWord;
187 UINT32 DataDword;
188 TPM_RQU_COMMAND_HDR TpmCmdHdr;
189 TPM_RQU_COMMAND_HDR *TpmCmdPtr;
190 UINTN Size;
191 UINT8 *Raw;
192
193 switch (FmtChar) {
194
195 case 'b':
196 DataByte = VA_ARG (*ap, UINT8);
197 Raw = &DataByte;
198 Size = sizeof (DataByte);
199 break;
200
201 case 'w':
202 DataWord = VA_ARG (*ap, UINT16);
203 DataWord = SwapBytes16 (DataWord);
204 Raw = (UINT8*)&DataWord;
205 Size = sizeof (DataWord);
206 break;
207
208 case 'd':
209 DataDword = VA_ARG (*ap, UINT32);
210 DataDword = SwapBytes32 (DataDword);
211 Raw = (UINT8*)&DataDword;
212 Size = sizeof (DataDword);
213 break;
214
215 case 'h':
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);
222 break;
223
224 case 'r':
225 Raw = VA_ARG (*ap, UINT8*);
226 Size = VA_ARG (*ap, UINTN);
227 break;
228
229 case '\0':
230 return EFI_INVALID_PARAMETER;
231
232 default:
233 return EFI_INVALID_PARAMETER;
234 }
235
236 //
237 // Check input to avoid overflow.
238 //
239 if ((UINT32) (~0)- *DataLength < (UINT32)Size) {
240 return EFI_INVALID_PARAMETER;
241 }
242
243 if(*DataLength + (UINT32) Size > TPMCMDBUFLENGTH) {
244 return EFI_BUFFER_TOO_SMALL;
245 }
246 CopyMem (TpmBuffer + *DataLength, Raw, Size);
247 *DataLength += (UINT32) Size;
248 return EFI_SUCCESS;
249 }
250
251 /**
252 Format reponse data according to the format control character.
253
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.
260
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.
264
265 **/
266 EFI_STATUS
267 TisPcReceiveV (
268 IN UINT8 FmtChar,
269 IN OUT VA_LIST *ap,
270 OUT UINT8 *TpmBuffer,
271 IN OUT UINT32 *DataIndex,
272 IN UINT32 RespSize,
273 OUT BOOLEAN *DataFinished
274 )
275 {
276 UINT8 *Raw;
277 TPM_RSP_COMMAND_HDR *TpmRspPtr;
278 UINTN Size;
279
280 Raw = VA_ARG (*ap, UINT8*);
281 switch (FmtChar) {
282
283 case 'b':
284 Size = sizeof (UINT8);
285 break;
286
287 case 'w':
288 Size = sizeof (UINT16);
289 break;
290
291 case 'd':
292 Size = sizeof (UINT32);
293 break;
294
295 case 'h':
296 Size = sizeof (*TpmRspPtr);
297 break;
298
299 case 'r':
300 Size = VA_ARG (*ap, UINTN);
301 //
302 // If overflowed, which means Size is big enough for Response data.
303 // skip this check. Copy the whole data
304 //
305 if ((UINT32) (~0)- *DataIndex >= (UINT32)Size) {
306 if(*DataIndex + (UINT32) Size <= RespSize) {
307 break;
308 }
309 }
310
311 *DataFinished = TRUE;
312 if (*DataIndex >= RespSize) {
313 return EFI_SUCCESS;
314 }
315 CopyMem (Raw, TpmBuffer + *DataIndex, RespSize - *DataIndex);
316 *DataIndex += RespSize - *DataIndex;
317 return EFI_SUCCESS;
318
319 case '\0':
320 return EFI_INVALID_PARAMETER;
321
322 default:
323 return EFI_WARN_UNKNOWN_GLYPH;
324 }
325
326 if(*DataIndex + (UINT32) Size > RespSize) {
327 *DataFinished = TRUE;
328 return EFI_SUCCESS;
329 }
330
331 if( *DataIndex + (UINT32) Size > TPMCMDBUFLENGTH )
332 return EFI_BUFFER_TOO_SMALL;
333
334 CopyMem (Raw, TpmBuffer + *DataIndex, Size);
335 *DataIndex += (UINT32) Size;
336
337 switch (FmtChar) {
338
339 case 'w':
340 *(UINT16*)Raw = SwapBytes16 (*(UINT16*) Raw);
341 break;
342
343 case 'd':
344 *(UINT32*)Raw = SwapBytes32 (*(UINT32*) Raw);
345 break;
346
347 case 'h':
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);
352 break;
353 }
354 return EFI_SUCCESS;
355 }
356
357 /**
358 Send formatted command to TPM for execution and return formatted data from response.
359
360 @param[in] TisReg TPM Handle.
361 @param[in] Fmt Format control string.
362 @param[in] ... The variable argument list.
363
364 @retval EFI_SUCCESS Operation completed successfully.
365 @retval EFI_TIMEOUT The register can't run into the expected status in time.
366
367 **/
368 EFI_STATUS
369 EFIAPI
370 TisPcExecute (
371 IN TIS_TPM_HANDLE TisReg,
372 IN CONST CHAR8 *Fmt,
373 ...
374 )
375 {
376 EFI_STATUS Status;
377 VA_LIST Ap;
378 UINT32 BufSize;
379 UINT32 ResponseSize;
380 BOOLEAN DataFinished;
381
382 VA_START (Ap, Fmt);
383
384 //
385 // Put the formatted command to the TpmCommandBuf
386 //
387 BufSize = 0;
388 while (*Fmt != '\0') {
389 if (*Fmt == '%') Fmt++;
390 if (*Fmt == '/') break;
391 Status = TisPcSendV (*Fmt, &Ap, TpmCommandBuf, &BufSize);
392 if (EFI_ERROR( Status )) {
393 goto Error;
394 }
395 Fmt++;
396 }
397 //
398 // Send the command to TPM
399 //
400 Status = TisPcSend (TisReg, TpmCommandBuf, BufSize);
401 if (EFI_ERROR (Status)) {
402 //
403 // Ensure the TPM state change from "Reception" to "Idle/Ready"
404 //
405 MmioWrite8 ((UINTN) &(((TIS_PC_REGISTERS_PTR) TisReg)->Status), TIS_PC_STS_READY);
406 goto Error;
407 }
408
409 MmioWrite8 ((UINTN) &(((TIS_PC_REGISTERS_PTR) TisReg)->Status), TIS_PC_STS_GO);
410 Fmt++;
411 //
412 // Receive the response data from TPM
413 //
414 ZeroMem (TpmCommandBuf, TPMCMDBUFLENGTH);
415 Status = TisPcReceive (TisReg, TpmCommandBuf, &ResponseSize);
416 //
417 // Ensure the TPM state change from "Execution" or "Completion" to "Idle/Ready"
418 //
419 MmioWrite8 ((UINTN) &(((TIS_PC_REGISTERS_PTR) TisReg)->Status), TIS_PC_STS_READY);
420 if (EFI_ERROR (Status)) {
421 goto Error;
422 }
423
424 //
425 // Get the formatted data from the TpmCommandBuf.
426 //
427 BufSize =0;
428 DataFinished = FALSE;
429 while (*Fmt != '\0') {
430 if (*Fmt == '%') {
431 Fmt++;
432 }
433 Status = TisPcReceiveV (*Fmt, &Ap, TpmCommandBuf, &BufSize, ResponseSize, &DataFinished);
434 if (EFI_ERROR (Status)) {
435 goto Error;
436 }
437 if (DataFinished) {
438 VA_END (Ap);
439 return EFI_SUCCESS;
440 }
441 Fmt++;
442 }
443
444 Error:
445 VA_END (Ap);
446 return Status;
447 }
448