diff --git a/QuarkPlatformPkg/Library/Tpm12DeviceLibAtmelI2c/TisPc.c b/QuarkPlatformPkg/Library/Tpm12DeviceLibAtmelI2c/TisPc.c new file mode 100644 index 0000000000..4e5aa41370 --- /dev/null +++ b/QuarkPlatformPkg/Library/Tpm12DeviceLibAtmelI2c/TisPc.c @@ -0,0 +1,419 @@ +/** @file + Basic TIS (TPM Interface Specification) functions for Atmel I2C TPM. + + Copyright (c) 2016, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include +#include +#include +#include +#include +#include + +// +// Atmel I2C TPM slave address +// +#define ATMEL_I2C_TPM_SLAVE_ADDRESS 0x29 + +// +// Maximum I2C transfer size for Atmel I2C TPM +// +#define ATMEL_I2C_TPM_MAX_TRANSFER_SIZE 0x10 + +// +// Default TimeOut values in microseconds +// +#define TIS_TIMEOUT_A ( 750 * 1000) // 750ms +#define TIS_TIMEOUT_B (2000 * 1000) // 2s +#define TIS_TIMEOUT_C ( 750 * 1000) // 750ms +#define TIS_TIMEOUT_D ( 750 * 1000) // 750ms + +/** + Send command to Atmel I2c TPM breaking request up into multiple I2C transfers + if required. + + @param[in] Buffer Pointer to TPM command data. + @param[in] Length Number of bytes of TPM command data. + + @retval EFI_SUCCESS TPM command sent. + @retval EFI_NOT_FOUND TPM chip doesn't exit. + @retval EFI_TIMEOUT Can't get the TPM control in time. +**/ +EFI_STATUS +WriteTpmBufferMultiple ( + IN UINT8 *Buffer, + IN UINTN Length + ) +{ + EFI_STATUS Status; + EFI_I2C_DEVICE_ADDRESS I2CDeviceAddr; + UINTN Index; + UINTN PartialLength; + + I2CDeviceAddr.I2CDeviceAddress = ATMEL_I2C_TPM_SLAVE_ADDRESS; + + DEBUG ((EFI_D_VERBOSE, "WriteTpmBufferMultiple: Addr=%02x Length=%02x\n", I2CDeviceAddr.I2CDeviceAddress, Length)); + + for (PartialLength = 0; Length > 0; Length -= PartialLength, Buffer += PartialLength) { + // + // Write data to TPM. + // + PartialLength = MIN (Length, ATMEL_I2C_TPM_MAX_TRANSFER_SIZE); + Status = I2cWriteMultipleByte ( + I2CDeviceAddr, + EfiI2CSevenBitAddrMode, + &PartialLength, + Buffer + ); + DEBUG ((EFI_D_VERBOSE, " ")); + for (Index = 0; Index < PartialLength; Index++) { + DEBUG ((EFI_D_VERBOSE, "%02x ", Buffer[Index])); + } + DEBUG ((EFI_D_VERBOSE, "\n")); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_VERBOSE, " Status = %r\n", Status)); + return Status; + } + } + + DEBUG ((EFI_D_VERBOSE, " Status = %r\n", Status)); + return Status; +} + +/** + Receive a response to a command from Atmel I2c TPM breaking response into + multiple I2C transfers if required. + + @param[out] Buffer Pointer to TPM response data. + @param[in] Length Maximum number of bytes to receive. + + @retval EFI_SUCCESS TPM response received. + @retval EFI_NOT_FOUND TPM chip doesn't exit. + @retval EFI_TIMEOUT Can't get the TPM control in time. +**/ +EFI_STATUS +ReadTpmBufferMultiple ( + OUT UINT8 *Buffer, + IN UINTN Length + ) +{ + EFI_STATUS Status; + EFI_I2C_DEVICE_ADDRESS I2CDeviceAddr; + UINTN WriteLength; + UINTN Index; + UINTN PartialLength; + + I2CDeviceAddr.I2CDeviceAddress = ATMEL_I2C_TPM_SLAVE_ADDRESS; + WriteLength = 0; + + DEBUG ((EFI_D_VERBOSE, "ReadTpmBufferMultiple: Addr=%02x Length=%02x\n", I2CDeviceAddr.I2CDeviceAddress, Length)); + + for (PartialLength = 0; Length > 0; Length -= PartialLength, Buffer += PartialLength) { + // + // Read data from TPM. + // + PartialLength = MIN (Length, ATMEL_I2C_TPM_MAX_TRANSFER_SIZE); + Status = I2cReadMultipleByte ( + I2CDeviceAddr, + EfiI2CSevenBitAddrMode, + &WriteLength, + &PartialLength, + Buffer + ); + if (!EFI_ERROR (Status)) { + DEBUG ((EFI_D_VERBOSE, " ")); + for (Index = 0; Index < PartialLength; Index++) { + DEBUG ((EFI_D_VERBOSE, "%02x ", Buffer[Index])); + } + DEBUG ((EFI_D_VERBOSE, "\n")); + } + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_VERBOSE, " Status = %r\n", Status)); + return Status; + } + } + + DEBUG ((EFI_D_VERBOSE, " Status = %r\n", Status)); + return Status; +} + +/** + This service requests use TPM12. + + @retval EFI_SUCCESS Get the control of TPM12 chip. + @retval EFI_NOT_FOUND TPM12 not found. + @retval EFI_DEVICE_ERROR Unexpected device behavior. +**/ +EFI_STATUS +EFIAPI +Tpm12RequestUseTpm ( + VOID + ) +{ + EFI_STATUS Status; + UINT8 Data; + UINT64 Current; + UINT64 Previous; + UINT64 Total; + UINT64 Start; + UINT64 End; + UINT64 Timeout; + INT64 Cycle; + INT64 Delta; + + // + // Get the current timer value + // + Current = GetPerformanceCounter(); + + // + // Initialize local variables + // + Start = 0; + End = 0; + Total = 0; + + // + // Retrieve the performance counter properties and compute the number of + // performance counter ticks required to reach the maximum TIS timeout of + // TIS_TIMEOUT_A. TIS_TIMEOUT_A is in microseconds. + // + Timeout = DivU64x32 ( + MultU64x32 ( + GetPerformanceCounterProperties (&Start, &End), + TIS_TIMEOUT_A + ), + 1000000 + ); + Cycle = End - Start; + if (Cycle < 0) { + Cycle = -Cycle; + } + Cycle++; + + // + // Attempt to read a byte from the Atmel I2C TPM + // + do { + Status = ReadTpmBufferMultiple (&Data, sizeof(Data)); + + Previous = Current; + Current = GetPerformanceCounter(); + Delta = (INT64) (Current - Previous); + if (Start > End) { + Delta = -Delta; + } + if (Delta < 0) { + Delta += Cycle; + } + Total += Delta; + if (Total >= Timeout) { + Status = EFI_TIMEOUT; + DEBUG ((EFI_D_ERROR, "Atmel I2C TPM failed to read: %r\n", Status)); + return Status; + } + } while (EFI_ERROR (Status)); + + // + // Send Physical Presence Command to Atmel I2C TPM + // + Status = Tpm12PhysicalPresence (TPM_PHYSICAL_PRESENCE_PRESENT); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Atmel I2C TPM failed to submit physical presence command: %r\n", Status)); + return Status; + } + + return EFI_SUCCESS; +} + +/** + This service enables the sending of commands to the TPM12. + + @param[in] InputParameterBlockSize Size of the TPM12 input parameter block. + @param[in] InputParameterBlock Pointer to the TPM12 input parameter block. + @param[in,out] OutputParameterBlockSize Size of the TPM12 output parameter block. + @param[in] OutputParameterBlock Pointer to the TPM12 output parameter block. + + @retval EFI_SUCCESS The command byte stream was successfully sent to + the device and a response was successfully received. + @retval EFI_DEVICE_ERROR The command was not successfully sent to the + device or a response was not successfully received + from the device. + @retval EFI_BUFFER_TOO_SMALL The output parameter block is too small. +**/ +EFI_STATUS +EFIAPI +Tpm12SubmitCommand ( + IN UINT32 InputParameterBlockSize, + IN UINT8 *InputParameterBlock, + IN OUT UINT32 *OutputParameterBlockSize, + IN UINT8 *OutputParameterBlock + ) +{ + EFI_STATUS Status; + UINT32 TpmOutSize; + TPM_RSP_COMMAND_HDR *ResponseHeader; + UINT64 Current; + UINT64 Previous; + UINT64 Total; + UINT64 Start; + UINT64 End; + UINT64 Timeout; + INT64 Cycle; + INT64 Delta; + + // + // Make sure response buffer is big enough to hold a response header + // + if (*OutputParameterBlockSize < sizeof (TPM_RSP_COMMAND_HDR)) { + Status = EFI_BUFFER_TOO_SMALL; + goto Done; + } + + // + // Get the current timer value + // + Current = GetPerformanceCounter(); + + // + // Initialize local variables + // + Start = 0; + End = 0; + Total = 0; + + // + // Retrieve the performance counter properties and compute the number of + // performance counter ticks required to reach the maximum TIS timeout of + // TIS_TIMEOUT_A. TIS_TIMEOUT_A is in microseconds. + // + Timeout = DivU64x32 ( + MultU64x32 ( + GetPerformanceCounterProperties (&Start, &End), + TIS_TIMEOUT_A + ), + 1000000 + ); + Cycle = End - Start; + if (Cycle < 0) { + Cycle = -Cycle; + } + Cycle++; + + // + // Send command + // + do { + Status = WriteTpmBufferMultiple (InputParameterBlock, InputParameterBlockSize); + + Previous = Current; + Current = GetPerformanceCounter(); + Delta = (INT64) (Current - Previous); + if (Start > End) { + Delta = -Delta; + } + if (Delta < 0) { + Delta += Cycle; + } + Total += Delta; + if (Total >= Timeout) { + Status = EFI_TIMEOUT; + goto Done; + } + } while (EFI_ERROR (Status)); + + // + // Receive response header + // + do { + Status = ReadTpmBufferMultiple (OutputParameterBlock, sizeof (TPM_RSP_COMMAND_HDR)); + + Previous = Current; + Current = GetPerformanceCounter(); + Delta = (INT64) (Current - Previous); + if (Start > End) { + Delta = -Delta; + } + if (Delta < 0) { + Delta += Cycle; + } + Total += Delta; + if (Total >= Timeout) { + Status = EFI_TIMEOUT; + goto Done; + } + } while (EFI_ERROR (Status)); + + // + // Check the response data header (tag, parasize and returncode) + // + ResponseHeader = (TPM_RSP_COMMAND_HDR *)OutputParameterBlock; + if (SwapBytes16 (ReadUnaligned16 (&ResponseHeader->tag)) != TPM_TAG_RSP_COMMAND) { + Status = EFI_DEVICE_ERROR; + goto Done; + } + + TpmOutSize = SwapBytes32 (ReadUnaligned32 (&ResponseHeader->paramSize)); + if (TpmOutSize == sizeof (TPM_RSP_COMMAND_HDR)) { + Status = EFI_SUCCESS; + goto Done; + } + if (TpmOutSize < sizeof (TPM_RSP_COMMAND_HDR)) { + Status = EFI_DEVICE_ERROR; + goto Done; + } + if (*OutputParameterBlockSize < TpmOutSize) { + Status = EFI_BUFFER_TOO_SMALL; + goto Done; + } + *OutputParameterBlockSize = TpmOutSize; + + // + // Receive the remaining data in the response header + // + do { + Status = ReadTpmBufferMultiple ( + OutputParameterBlock + sizeof (TPM_RSP_COMMAND_HDR), + TpmOutSize - sizeof (TPM_RSP_COMMAND_HDR) + ); + + Previous = Current; + Current = GetPerformanceCounter(); + Delta = (INT64) (Current - Previous); + if (Start > End) { + Delta = -Delta; + } + if (Delta < 0) { + Delta += Cycle; + } + Total += Delta; + if (Total >= Timeout) { + Status = EFI_TIMEOUT; + goto Done; + } + } while (EFI_ERROR (Status)); + +Done: + DEBUG (( + EFI_D_VERBOSE, + "Tpm12SubmitCommand() Status = %r Time = %ld ms\n", + Status, + DivU64x64Remainder ( + MultU64x32 (Total, 1000), + GetPerformanceCounterProperties (NULL, NULL), + NULL + ) + )); + + return Status; +} diff --git a/QuarkPlatformPkg/Library/Tpm12DeviceLibAtmelI2c/Tpm12DeviceLibAtmelI2c.inf b/QuarkPlatformPkg/Library/Tpm12DeviceLibAtmelI2c/Tpm12DeviceLibAtmelI2c.inf new file mode 100644 index 0000000000..5a8734f4c6 --- /dev/null +++ b/QuarkPlatformPkg/Library/Tpm12DeviceLibAtmelI2c/Tpm12DeviceLibAtmelI2c.inf @@ -0,0 +1,45 @@ +## @file +# Provides some common functions for the TCG feature for Atmel I2C TPM. +# +# This instance provides basic TPM Interface Specification (TIS) functions +# or Atmel I2C TPM. +# +# Copyright (c) 2016, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = Tpm12DeviceLibAtmelI2c + MODULE_UNI_FILE = Tpm12DeviceLibAtmelI2c.uni + FILE_GUID = A0C0B7EF-99FF-417F-8B9F-5AD4701D90D6 + MODULE_TYPE = PEIM + VERSION_STRING = 1.0 + LIBRARY_CLASS = Tpm12DeviceLib|PEIM DXE_DRIVER DXE_SMM_DRIVER UEFI_DRIVER + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + TisPc.c + +[Packages] + MdePkg/MdePkg.dec + SecurityPkg/SecurityPkg.dec + QuarkSocPkg/QuarkSocPkg.dec + +[LibraryClasses] + BaseLib + TimerLib + DebugLib + I2cLib + Tpm12CommandLib diff --git a/QuarkPlatformPkg/Library/Tpm12DeviceLibAtmelI2c/Tpm12DeviceLibAtmelI2c.uni b/QuarkPlatformPkg/Library/Tpm12DeviceLibAtmelI2c/Tpm12DeviceLibAtmelI2c.uni new file mode 100644 index 0000000000..aaee1e2779 --- /dev/null +++ b/QuarkPlatformPkg/Library/Tpm12DeviceLibAtmelI2c/Tpm12DeviceLibAtmelI2c.uni @@ -0,0 +1,21 @@ +// /** @file +// Provides some common functions for the TCG feature for Atmel I2C TPM. +// +// This instance provides basic TPM Interface Specification (TIS) functions +// for Atmel I2C TPM. +// +// Copyright (c) 2016, Intel Corporation. All rights reserved.
+// +// This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +// **/ + +#string STR_MODULE_ABSTRACT #language en-US "Provides some common functions for the TCG feature for Atmel I2C TPM." + +#string STR_MODULE_DESCRIPTION #language en-US "This instance provides basic TPM Interface Specification (TIS) functions for Atmel I2C TPM." +