]> git.proxmox.com Git - mirror_edk2.git/blame - QuarkPlatformPkg/Library/Tpm12DeviceLibAtmelI2c/TisPc.c
ShellPkg/Shell: Add double quotes to args with white space
[mirror_edk2.git] / QuarkPlatformPkg / Library / Tpm12DeviceLibAtmelI2c / TisPc.c
CommitLineData
df865245
MK
1/** @file\r
2 Basic TIS (TPM Interface Specification) functions for Atmel I2C TPM.\r
3\r
4 Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>\r
5 This program and the accompanying materials\r
6 are licensed and made available under the terms and conditions of the BSD License\r
7 which accompanies this distribution. The full text of the license may be found at\r
8 http://opensource.org/licenses/bsd-license.php\r
9\r
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
15#include <PiPei.h>\r
16#include <Library/Tpm12DeviceLib.h>\r
17#include <Library/BaseLib.h>\r
18#include <Library/TimerLib.h>\r
19#include <Library/DebugLib.h>\r
20#include <Library/I2cLib.h>\r
21#include <Library/Tpm12CommandLib.h>\r
22\r
23//\r
24// Atmel I2C TPM slave address\r
25//\r
26#define ATMEL_I2C_TPM_SLAVE_ADDRESS 0x29\r
27\r
28//\r
29// Maximum I2C transfer size for Atmel I2C TPM\r
30//\r
31#define ATMEL_I2C_TPM_MAX_TRANSFER_SIZE 0x10\r
32\r
33//\r
34// Default TimeOut values in microseconds\r
35//\r
36#define TIS_TIMEOUT_A ( 750 * 1000) // 750ms\r
37#define TIS_TIMEOUT_B (2000 * 1000) // 2s\r
38#define TIS_TIMEOUT_C ( 750 * 1000) // 750ms\r
39#define TIS_TIMEOUT_D ( 750 * 1000) // 750ms\r
40\r
41/**\r
42 Send command to Atmel I2c TPM breaking request up into multiple I2C transfers\r
43 if required.\r
44\r
45 @param[in] Buffer Pointer to TPM command data.\r
46 @param[in] Length Number of bytes of TPM command data.\r
47\r
48 @retval EFI_SUCCESS TPM command sent.\r
49 @retval EFI_NOT_FOUND TPM chip doesn't exit.\r
50 @retval EFI_TIMEOUT Can't get the TPM control in time.\r
51**/\r
52EFI_STATUS\r
53WriteTpmBufferMultiple (\r
54 IN UINT8 *Buffer,\r
55 IN UINTN Length\r
56 )\r
57{\r
58 EFI_STATUS Status;\r
59 EFI_I2C_DEVICE_ADDRESS I2CDeviceAddr;\r
60 UINTN Index;\r
61 UINTN PartialLength;\r
62\r
63 I2CDeviceAddr.I2CDeviceAddress = ATMEL_I2C_TPM_SLAVE_ADDRESS;\r
64\r
65 DEBUG ((EFI_D_VERBOSE, "WriteTpmBufferMultiple: Addr=%02x Length=%02x\n", I2CDeviceAddr.I2CDeviceAddress, Length));\r
66\r
67 for (PartialLength = 0; Length > 0; Length -= PartialLength, Buffer += PartialLength) {\r
68 //\r
69 // Write data to TPM.\r
70 //\r
71 PartialLength = MIN (Length, ATMEL_I2C_TPM_MAX_TRANSFER_SIZE);\r
72 Status = I2cWriteMultipleByte (\r
73 I2CDeviceAddr,\r
74 EfiI2CSevenBitAddrMode,\r
75 &PartialLength,\r
76 Buffer\r
77 );\r
78 DEBUG ((EFI_D_VERBOSE, " "));\r
79 for (Index = 0; Index < PartialLength; Index++) {\r
80 DEBUG ((EFI_D_VERBOSE, "%02x ", Buffer[Index]));\r
81 }\r
82 DEBUG ((EFI_D_VERBOSE, "\n"));\r
83 if (EFI_ERROR (Status)) {\r
84 DEBUG ((EFI_D_VERBOSE, " Status = %r\n", Status));\r
85 return Status;\r
86 }\r
87 }\r
88\r
89 DEBUG ((EFI_D_VERBOSE, " Status = %r\n", Status));\r
90 return Status;\r
91}\r
92\r
93/**\r
94 Receive a response to a command from Atmel I2c TPM breaking response into\r
95 multiple I2C transfers if required.\r
96\r
97 @param[out] Buffer Pointer to TPM response data.\r
98 @param[in] Length Maximum number of bytes to receive.\r
99\r
100 @retval EFI_SUCCESS TPM response received.\r
101 @retval EFI_NOT_FOUND TPM chip doesn't exit.\r
102 @retval EFI_TIMEOUT Can't get the TPM control in time.\r
103**/\r
104EFI_STATUS\r
105ReadTpmBufferMultiple (\r
106 OUT UINT8 *Buffer,\r
107 IN UINTN Length\r
108 )\r
109{\r
110 EFI_STATUS Status;\r
111 EFI_I2C_DEVICE_ADDRESS I2CDeviceAddr;\r
112 UINTN WriteLength;\r
113 UINTN Index;\r
114 UINTN PartialLength;\r
115\r
116 I2CDeviceAddr.I2CDeviceAddress = ATMEL_I2C_TPM_SLAVE_ADDRESS;\r
117 WriteLength = 0;\r
118\r
119 DEBUG ((EFI_D_VERBOSE, "ReadTpmBufferMultiple: Addr=%02x Length=%02x\n", I2CDeviceAddr.I2CDeviceAddress, Length));\r
120\r
121 for (PartialLength = 0; Length > 0; Length -= PartialLength, Buffer += PartialLength) {\r
122 //\r
123 // Read data from TPM.\r
124 //\r
125 PartialLength = MIN (Length, ATMEL_I2C_TPM_MAX_TRANSFER_SIZE);\r
126 Status = I2cReadMultipleByte (\r
127 I2CDeviceAddr,\r
128 EfiI2CSevenBitAddrMode,\r
129 &WriteLength,\r
130 &PartialLength,\r
131 Buffer\r
132 );\r
133 if (!EFI_ERROR (Status)) {\r
134 DEBUG ((EFI_D_VERBOSE, " "));\r
135 for (Index = 0; Index < PartialLength; Index++) {\r
136 DEBUG ((EFI_D_VERBOSE, "%02x ", Buffer[Index]));\r
137 }\r
138 DEBUG ((EFI_D_VERBOSE, "\n"));\r
139 }\r
140 if (EFI_ERROR (Status)) {\r
141 DEBUG ((EFI_D_VERBOSE, " Status = %r\n", Status));\r
142 return Status;\r
143 }\r
144 }\r
145\r
146 DEBUG ((EFI_D_VERBOSE, " Status = %r\n", Status));\r
147 return Status;\r
148}\r
149\r
150/**\r
151 This service requests use TPM12.\r
152\r
153 @retval EFI_SUCCESS Get the control of TPM12 chip.\r
154 @retval EFI_NOT_FOUND TPM12 not found.\r
155 @retval EFI_DEVICE_ERROR Unexpected device behavior.\r
156**/\r
157EFI_STATUS\r
158EFIAPI\r
159Tpm12RequestUseTpm (\r
160 VOID\r
161 )\r
162{\r
163 EFI_STATUS Status;\r
164 UINT8 Data;\r
165 UINT64 Current;\r
166 UINT64 Previous;\r
167 UINT64 Total;\r
168 UINT64 Start;\r
169 UINT64 End;\r
170 UINT64 Timeout;\r
171 INT64 Cycle;\r
172 INT64 Delta;\r
173\r
174 //\r
175 // Get the current timer value\r
176 //\r
177 Current = GetPerformanceCounter();\r
178\r
179 //\r
180 // Initialize local variables\r
181 //\r
182 Start = 0;\r
183 End = 0;\r
184 Total = 0;\r
185\r
186 //\r
187 // Retrieve the performance counter properties and compute the number of\r
188 // performance counter ticks required to reach the maximum TIS timeout of\r
189 // TIS_TIMEOUT_A. TIS_TIMEOUT_A is in microseconds.\r
190 //\r
191 Timeout = DivU64x32 (\r
192 MultU64x32 (\r
193 GetPerformanceCounterProperties (&Start, &End),\r
194 TIS_TIMEOUT_A\r
195 ),\r
196 1000000\r
197 );\r
198 Cycle = End - Start;\r
199 if (Cycle < 0) {\r
200 Cycle = -Cycle;\r
201 }\r
202 Cycle++;\r
203\r
204 //\r
205 // Attempt to read a byte from the Atmel I2C TPM\r
206 //\r
207 do {\r
208 Status = ReadTpmBufferMultiple (&Data, sizeof(Data));\r
209\r
210 Previous = Current;\r
211 Current = GetPerformanceCounter();\r
212 Delta = (INT64) (Current - Previous);\r
213 if (Start > End) {\r
214 Delta = -Delta;\r
215 }\r
216 if (Delta < 0) {\r
217 Delta += Cycle;\r
218 }\r
219 Total += Delta;\r
220 if (Total >= Timeout) {\r
221 Status = EFI_TIMEOUT;\r
222 DEBUG ((EFI_D_ERROR, "Atmel I2C TPM failed to read: %r\n", Status));\r
223 return Status;\r
224 }\r
225 } while (EFI_ERROR (Status));\r
226\r
227 //\r
228 // Send Physical Presence Command to Atmel I2C TPM\r
229 //\r
230 Status = Tpm12PhysicalPresence (TPM_PHYSICAL_PRESENCE_PRESENT);\r
231 if (EFI_ERROR (Status)) {\r
232 DEBUG ((EFI_D_ERROR, "Atmel I2C TPM failed to submit physical presence command: %r\n", Status));\r
233 return Status;\r
234 }\r
235\r
236 return EFI_SUCCESS;\r
237}\r
238\r
239/**\r
240 This service enables the sending of commands to the TPM12.\r
241\r
242 @param[in] InputParameterBlockSize Size of the TPM12 input parameter block.\r
243 @param[in] InputParameterBlock Pointer to the TPM12 input parameter block.\r
244 @param[in,out] OutputParameterBlockSize Size of the TPM12 output parameter block.\r
245 @param[in] OutputParameterBlock Pointer to the TPM12 output parameter block.\r
246\r
247 @retval EFI_SUCCESS The command byte stream was successfully sent to\r
248 the device and a response was successfully received.\r
249 @retval EFI_DEVICE_ERROR The command was not successfully sent to the\r
250 device or a response was not successfully received\r
251 from the device.\r
252 @retval EFI_BUFFER_TOO_SMALL The output parameter block is too small.\r
253**/\r
254EFI_STATUS\r
255EFIAPI\r
256Tpm12SubmitCommand (\r
257 IN UINT32 InputParameterBlockSize,\r
258 IN UINT8 *InputParameterBlock,\r
259 IN OUT UINT32 *OutputParameterBlockSize,\r
260 IN UINT8 *OutputParameterBlock\r
261 )\r
262{\r
263 EFI_STATUS Status;\r
264 UINT32 TpmOutSize;\r
265 TPM_RSP_COMMAND_HDR *ResponseHeader;\r
266 UINT64 Current;\r
267 UINT64 Previous;\r
268 UINT64 Total;\r
269 UINT64 Start;\r
270 UINT64 End;\r
271 UINT64 Timeout;\r
272 INT64 Cycle;\r
273 INT64 Delta;\r
274\r
275 //\r
276 // Make sure response buffer is big enough to hold a response header\r
277 //\r
278 if (*OutputParameterBlockSize < sizeof (TPM_RSP_COMMAND_HDR)) {\r
279 Status = EFI_BUFFER_TOO_SMALL;\r
280 goto Done;\r
281 }\r
282\r
283 //\r
284 // Get the current timer value\r
285 //\r
286 Current = GetPerformanceCounter();\r
287\r
288 //\r
289 // Initialize local variables\r
290 //\r
291 Start = 0;\r
292 End = 0;\r
293 Total = 0;\r
294\r
295 //\r
296 // Retrieve the performance counter properties and compute the number of\r
297 // performance counter ticks required to reach the maximum TIS timeout of\r
298 // TIS_TIMEOUT_A. TIS_TIMEOUT_A is in microseconds.\r
299 //\r
300 Timeout = DivU64x32 (\r
301 MultU64x32 (\r
302 GetPerformanceCounterProperties (&Start, &End),\r
303 TIS_TIMEOUT_A\r
304 ),\r
305 1000000\r
306 );\r
307 Cycle = End - Start;\r
308 if (Cycle < 0) {\r
309 Cycle = -Cycle;\r
310 }\r
311 Cycle++;\r
312\r
313 //\r
314 // Send command\r
315 //\r
316 do {\r
317 Status = WriteTpmBufferMultiple (InputParameterBlock, InputParameterBlockSize);\r
318\r
319 Previous = Current;\r
320 Current = GetPerformanceCounter();\r
321 Delta = (INT64) (Current - Previous);\r
322 if (Start > End) {\r
323 Delta = -Delta;\r
324 }\r
325 if (Delta < 0) {\r
326 Delta += Cycle;\r
327 }\r
328 Total += Delta;\r
329 if (Total >= Timeout) {\r
330 Status = EFI_TIMEOUT;\r
331 goto Done;\r
332 }\r
333 } while (EFI_ERROR (Status));\r
334\r
335 //\r
336 // Receive response header\r
337 //\r
338 do {\r
339 Status = ReadTpmBufferMultiple (OutputParameterBlock, sizeof (TPM_RSP_COMMAND_HDR));\r
340\r
341 Previous = Current;\r
342 Current = GetPerformanceCounter();\r
343 Delta = (INT64) (Current - Previous);\r
344 if (Start > End) {\r
345 Delta = -Delta;\r
346 }\r
347 if (Delta < 0) {\r
348 Delta += Cycle;\r
349 }\r
350 Total += Delta;\r
351 if (Total >= Timeout) {\r
352 Status = EFI_TIMEOUT;\r
353 goto Done;\r
354 }\r
355 } while (EFI_ERROR (Status));\r
356\r
357 //\r
358 // Check the response data header (tag, parasize and returncode)\r
359 //\r
360 ResponseHeader = (TPM_RSP_COMMAND_HDR *)OutputParameterBlock;\r
361 if (SwapBytes16 (ReadUnaligned16 (&ResponseHeader->tag)) != TPM_TAG_RSP_COMMAND) {\r
362 Status = EFI_DEVICE_ERROR;\r
363 goto Done;\r
364 }\r
365\r
366 TpmOutSize = SwapBytes32 (ReadUnaligned32 (&ResponseHeader->paramSize));\r
367 if (TpmOutSize == sizeof (TPM_RSP_COMMAND_HDR)) {\r
368 Status = EFI_SUCCESS;\r
369 goto Done;\r
370 }\r
371 if (TpmOutSize < sizeof (TPM_RSP_COMMAND_HDR)) {\r
372 Status = EFI_DEVICE_ERROR;\r
373 goto Done;\r
374 }\r
375 if (*OutputParameterBlockSize < TpmOutSize) {\r
376 Status = EFI_BUFFER_TOO_SMALL;\r
377 goto Done;\r
378 }\r
379 *OutputParameterBlockSize = TpmOutSize;\r
380\r
381 //\r
382 // Receive the remaining data in the response header\r
383 //\r
384 do {\r
385 Status = ReadTpmBufferMultiple (\r
386 OutputParameterBlock + sizeof (TPM_RSP_COMMAND_HDR),\r
387 TpmOutSize - sizeof (TPM_RSP_COMMAND_HDR)\r
388 );\r
389\r
390 Previous = Current;\r
391 Current = GetPerformanceCounter();\r
392 Delta = (INT64) (Current - Previous);\r
393 if (Start > End) {\r
394 Delta = -Delta;\r
395 }\r
396 if (Delta < 0) {\r
397 Delta += Cycle;\r
398 }\r
399 Total += Delta;\r
400 if (Total >= Timeout) {\r
401 Status = EFI_TIMEOUT;\r
402 goto Done;\r
403 }\r
404 } while (EFI_ERROR (Status));\r
405\r
406Done:\r
407 DEBUG ((\r
408 EFI_D_VERBOSE,\r
409 "Tpm12SubmitCommand() Status = %r Time = %ld ms\n",\r
410 Status,\r
411 DivU64x64Remainder (\r
412 MultU64x32 (Total, 1000),\r
413 GetPerformanceCounterProperties (NULL, NULL),\r
414 NULL\r
415 )\r
416 ));\r
417\r
418 return Status;\r
419}\r