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