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