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