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