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