]> git.proxmox.com Git - mirror_edk2.git/blobdiff - SecurityPkg/Tcg/TcgDxe/TisDxe.c
Add security package to repository.
[mirror_edk2.git] / SecurityPkg / Tcg / TcgDxe / TisDxe.c
diff --git a/SecurityPkg/Tcg/TcgDxe/TisDxe.c b/SecurityPkg/Tcg/TcgDxe/TisDxe.c
new file mode 100644 (file)
index 0000000..635ff77
--- /dev/null
@@ -0,0 +1,432 @@
+/** @file  \r
+  TIS (TPM Interface Specification) functions used by TPM Dxe driver.\r
+  \r
+Copyright (c) 2005 - 2010, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include <IndustryStandard/Tpm12.h>\r
+#include <Library/TimerLib.h>\r
+#include <Library/TpmCommLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/IoLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+\r
+STATIC UINT8                        TpmCommandBuf[TPMCMDBUFLENGTH];\r
+\r
+/**\r
+  Send command to TPM for execution.\r
+\r
+  @param[in] TisReg     TPM register space base address.  \r
+  @param[in] TpmBuffer  Buffer for TPM command data.  \r
+  @param[in] DataLength TPM command data length.  \r
\r
+  @retval EFI_SUCCESS   Operation completed successfully.\r
+  @retval EFI_TIMEOUT   The register can't run into the expected status in time.\r
+\r
+**/\r
+EFI_STATUS\r
+TisPcSend (\r
+  IN     TIS_PC_REGISTERS_PTR       TisReg,\r
+  IN     UINT8                      *TpmBuffer,\r
+  IN     UINT32                     DataLength\r
+  )\r
+{\r
+  UINT16                            BurstCount;\r
+  UINT32                            Index;\r
+  EFI_STATUS                        Status;\r
+\r
+  Status = TisPcPrepareCommand (TisReg);\r
+  if (EFI_ERROR (Status)){\r
+    DEBUG ((DEBUG_ERROR, "The Tpm not ready!\n"));\r
+    return Status;\r
+  }\r
+  Index = 0;\r
+  while (Index < DataLength) {\r
+    Status = TisPcReadBurstCount (TisReg, &BurstCount);\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_TIMEOUT;\r
+    }\r
+    for (; BurstCount > 0 && Index < DataLength; BurstCount--) {\r
+      MmioWrite8 ((UINTN) &TisReg->DataFifo, *(TpmBuffer + Index));\r
+      Index++;\r
+    }\r
+  }\r
+  //\r
+  // Ensure the Tpm status STS_EXPECT change from 1 to 0\r
+  //\r
+  Status = TisPcWaitRegisterBits (\r
+             &TisReg->Status,\r
+             (UINT8) TIS_PC_VALID,\r
+             TIS_PC_STS_EXPECT,\r
+             TIS_TIMEOUT_C\r
+             );\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Receive response data of last command from TPM.\r
+\r
+  @param[in]  TisReg            TPM register space base address.  \r
+  @param[out] TpmBuffer         Buffer for response data.  \r
+  @param[out] RespSize          Response data length.  \r
\r
+  @retval EFI_SUCCESS           Operation completed successfully.\r
+  @retval EFI_TIMEOUT           The register can't run into the expected status in time.\r
+  @retval EFI_DEVICE_ERROR      Unexpected device status.\r
+  @retval EFI_BUFFER_TOO_SMALL  Response data is too long.\r
+\r
+**/\r
+EFI_STATUS\r
+TisPcReceive (\r
+  IN      TIS_PC_REGISTERS_PTR      TisReg,\r
+     OUT  UINT8                     *TpmBuffer,\r
+     OUT  UINT32                    *RespSize\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  UINT16                            BurstCount;\r
+  UINT32                            Index;\r
+  UINT32                            ResponseSize;\r
+  UINT32                            Data32;\r
+\r
+  //\r
+  // Wait for the command completion\r
+  //\r
+  Status = TisPcWaitRegisterBits (\r
+             &TisReg->Status,\r
+             (UINT8) (TIS_PC_VALID | TIS_PC_STS_DATA),\r
+             0,\r
+             TIS_TIMEOUT_B\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_TIMEOUT;\r
+  }\r
+  //\r
+  // Read the response data header and check it\r
+  //\r
+  Index = 0;\r
+  BurstCount = 0;\r
+  while (Index < sizeof (TPM_RSP_COMMAND_HDR)) {\r
+    Status = TisPcReadBurstCount (TisReg, &BurstCount);\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_TIMEOUT;\r
+    }\r
+    for (; BurstCount > 0 ; BurstCount--) {\r
+      *(TpmBuffer + Index) = MmioRead8 ((UINTN) &TisReg->DataFifo);\r
+      Index++;\r
+      if (Index == sizeof (TPM_RSP_COMMAND_HDR))\r
+        break;\r
+    }\r
+  }\r
+  //\r
+  // Check the reponse data header (tag,parasize and returncode )\r
+  //\r
+  CopyMem (&Data32, (TpmBuffer + 2), sizeof (UINT32));\r
+  ResponseSize = SwapBytes32 (Data32);\r
+  *RespSize =  ResponseSize;\r
+  if (ResponseSize == sizeof (TPM_RSP_COMMAND_HDR)) {\r
+    return EFI_SUCCESS;\r
+  }\r
+  if (ResponseSize < sizeof (TPM_RSP_COMMAND_HDR)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  if (ResponseSize > TPMCMDBUFLENGTH) {\r
+    return EFI_BUFFER_TOO_SMALL;\r
+  }\r
+  //\r
+  // Continue reading the remaining data\r
+  //\r
+  while (Index < ResponseSize) {\r
+    for (; BurstCount > 0 ; BurstCount--) {\r
+      *(TpmBuffer + Index) = MmioRead8 ((UINTN) &TisReg->DataFifo);\r
+      Index++;\r
+      if (Index == ResponseSize) {\r
+        return EFI_SUCCESS;\r
+      }\r
+    }\r
+    Status = TisPcReadBurstCount (TisReg, &BurstCount);\r
+    if (EFI_ERROR (Status) && (Index < ResponseSize)) {\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+  }\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Format TPM command data according to the format control character.\r
+\r
+  @param[in]      FmtChar       Format control character.  \r
+  @param[in, out] ap            List of arguments.  \r
+  @param[in]      TpmBuffer     Buffer for TPM command data.  \r
+  @param[out]     DataLength    TPM command data length. \r
\r
+  @retval EFI_SUCCESS           Operation completed successfully.\r
+  @retval EFI_INVALID_PARAMETER Invalid format control character.\r
+  @retval EFI_BUFFER_TOO_SMALL  Buffer too small for command data.\r
+\r
+**/\r
+EFI_STATUS\r
+TisPcSendV (\r
+  IN      UINT8                     FmtChar,\r
+  IN OUT  VA_LIST                   *ap,\r
+  UINT8                             *TpmBuffer,\r
+  UINT32                            *DataLength\r
+  )\r
+{\r
+  UINT8                             DataByte;\r
+  UINT16                            DataWord;\r
+  UINT32                            DataDword;\r
+  TPM_RQU_COMMAND_HDR               TpmCmdHdr;\r
+  TPM_RQU_COMMAND_HDR               *TpmCmdPtr;\r
+  UINTN                             Size;\r
+  UINT8                             *Raw;\r
+\r
+  switch (FmtChar) {\r
+\r
+    case 'b':\r
+      DataByte  = VA_ARG (*ap, UINT8);\r
+      Raw = &DataByte;\r
+      Size = sizeof (DataByte);\r
+      break;\r
+\r
+    case 'w':\r
+      DataWord  = VA_ARG (*ap, UINT16);\r
+      DataWord  = SwapBytes16 (DataWord);\r
+      Raw = (UINT8*)&DataWord;\r
+      Size = sizeof (DataWord);\r
+      break;\r
+\r
+    case 'd':\r
+      DataDword  = VA_ARG (*ap, UINT32);\r
+      DataDword  = SwapBytes32 (DataDword);\r
+      Raw = (UINT8*)&DataDword;\r
+      Size = sizeof (DataDword);\r
+      break;\r
+\r
+    case 'h':\r
+      TpmCmdPtr           = VA_ARG (*ap, TPM_RQU_COMMAND_HDR*);\r
+      TpmCmdHdr.tag       = SwapBytes16 (TpmCmdPtr->tag);\r
+      TpmCmdHdr.paramSize = SwapBytes32 (TpmCmdPtr->paramSize);\r
+      TpmCmdHdr.ordinal   = SwapBytes32 (TpmCmdPtr->ordinal);\r
+      Raw                 = (UINT8*) &TpmCmdHdr;\r
+      Size                = sizeof (TpmCmdHdr);\r
+      break;\r
+\r
+    case 'r':\r
+      Raw  = VA_ARG (*ap, UINT8*);\r
+      Size = VA_ARG (*ap, UINTN);\r
+      break;\r
+\r
+    case '\0':\r
+      return EFI_INVALID_PARAMETER;\r
+\r
+    default:\r
+      return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if(*DataLength + (UINT32) Size > TPMCMDBUFLENGTH) {\r
+    return EFI_BUFFER_TOO_SMALL;\r
+  }\r
+  CopyMem (TpmBuffer + *DataLength, Raw, Size);\r
+  *DataLength += (UINT32) Size;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Format reponse data according to the format control character.\r
+\r
+  @param[in]      FmtChar       Format control character.  \r
+  @param[in, out] ap            List of arguments.  \r
+  @param[out]     TpmBuffer     Buffer for reponse data.  \r
+  @param[in, out] DataIndex     Data offset in reponse data buffer. \r
+  @param[in]      RespSize      Response data length.  \r
+  @param[out]     DataFinished  Reach the end of Response data.  \r
\r
+  @retval EFI_SUCCESS           Operation completed successfully.\r
+  @retval EFI_INVALID_PARAMETER Invalid format control character.\r
+  @retval EFI_BUFFER_TOO_SMALL  Buffer too small for command data.\r
+\r
+**/\r
+EFI_STATUS\r
+TisPcReceiveV (\r
+  IN      UINT8                     FmtChar,\r
+  IN OUT  VA_LIST                   *ap,\r
+     OUT  UINT8                     *TpmBuffer,\r
+  IN OUT  UINT32                    *DataIndex,\r
+  IN      UINT32                    RespSize,\r
+     OUT  BOOLEAN                   *DataFinished\r
+  )\r
+{\r
+  UINT8                             *Raw;\r
+  TPM_RSP_COMMAND_HDR               *TpmRspPtr;\r
+  UINTN                             Size;\r
+\r
+  Raw = VA_ARG (*ap, UINT8*);\r
+  switch (FmtChar) {\r
+\r
+    case 'b':\r
+      Size = sizeof (UINT8);\r
+      break;\r
+\r
+    case 'w':\r
+      Size = sizeof (UINT16);\r
+      break;\r
+\r
+    case 'd':\r
+      Size = sizeof (UINT32);\r
+      break;\r
+\r
+    case 'h':\r
+      Size = sizeof (*TpmRspPtr);\r
+      break;\r
+\r
+    case 'r':\r
+      Size = VA_ARG (*ap, UINTN);\r
+      if(*DataIndex + (UINT32) Size <= RespSize) {\r
+        break;\r
+      }\r
+      *DataFinished = TRUE;\r
+      if (*DataIndex >= RespSize) {\r
+        return EFI_SUCCESS;\r
+      }\r
+      CopyMem (Raw, TpmBuffer + *DataIndex, RespSize - *DataIndex);\r
+      *DataIndex += RespSize - *DataIndex;\r
+      return EFI_SUCCESS;\r
+\r
+    case '\0':\r
+      return EFI_INVALID_PARAMETER;\r
+\r
+    default:\r
+      return EFI_WARN_UNKNOWN_GLYPH;\r
+  }\r
+\r
+  if(*DataIndex + (UINT32) Size > RespSize) {\r
+    *DataFinished = TRUE;\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  if( *DataIndex + (UINT32) Size > TPMCMDBUFLENGTH )\r
+    return EFI_BUFFER_TOO_SMALL;\r
+\r
+  CopyMem (Raw, TpmBuffer + *DataIndex, Size);\r
+  *DataIndex += (UINT32) Size;\r
+\r
+  switch (FmtChar) {\r
+\r
+    case 'w':\r
+      *(UINT16*)Raw = SwapBytes16 (*(UINT16*) Raw);\r
+      break;\r
+\r
+    case 'd':\r
+      *(UINT32*)Raw = SwapBytes32 (*(UINT32*) Raw);\r
+      break;\r
+\r
+    case 'h':\r
+      TpmRspPtr = (TPM_RSP_COMMAND_HDR*) Raw;\r
+      TpmRspPtr->tag = SwapBytes16 (TpmRspPtr->tag);\r
+      TpmRspPtr->paramSize = SwapBytes32 (TpmRspPtr->paramSize);\r
+      TpmRspPtr->returnCode = SwapBytes32 (TpmRspPtr->returnCode);\r
+      break;\r
+  }\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Send formatted command to TPM for execution and return formatted data from response.\r
+\r
+  @param[in] TisReg    TPM Handle.  \r
+  @param[in] Fmt       Format control string.  \r
+  @param[in] ...       The variable argument list.\r
\r
+  @retval EFI_SUCCESS  Operation completed successfully.\r
+  @retval EFI_TIMEOUT  The register can't run into the expected status in time.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+TisPcExecute (\r
+  IN      TIS_TPM_HANDLE            TisReg,\r
+  IN      CONST CHAR8               *Fmt,\r
+  ...\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  VA_LIST                           Ap;\r
+  UINT32                            BufSize;\r
+  UINT32                            ResponseSize;\r
+  BOOLEAN                           DataFinished;\r
+\r
+  VA_START (Ap, Fmt);\r
+\r
+  //\r
+  // Put the formatted command to the TpmCommandBuf\r
+  //\r
+  BufSize = 0;\r
+  while (*Fmt != '\0') {\r
+    if (*Fmt == '%') Fmt++;\r
+    if (*Fmt == '/') break;\r
+    Status = TisPcSendV (*Fmt, &Ap, TpmCommandBuf, &BufSize);\r
+    if (EFI_ERROR( Status )) {\r
+      return Status;\r
+    }\r
+    Fmt++;\r
+  }\r
+  //\r
+  // Send the command to TPM\r
+  //\r
+  Status = TisPcSend (TisReg, TpmCommandBuf, BufSize);\r
+  if (EFI_ERROR (Status))  {\r
+    //\r
+    // Ensure the TPM state change from "Reception" to "Idle/Ready"\r
+    //\r
+    MmioWrite8 ((UINTN) &(((TIS_PC_REGISTERS_PTR) TisReg)->Status), TIS_PC_STS_READY);\r
+    return Status; \r
+  }\r
+\r
+  MmioWrite8 ((UINTN) &(((TIS_PC_REGISTERS_PTR) TisReg)->Status), TIS_PC_STS_GO);\r
+  Fmt++;\r
+  //\r
+  // Receive the response data from TPM\r
+  //\r
+  ZeroMem (TpmCommandBuf, TPMCMDBUFLENGTH);\r
+  Status = TisPcReceive (TisReg, TpmCommandBuf, &ResponseSize);\r
+  //\r
+  // Ensure the TPM state change from "Execution" or "Completion" to "Idle/Ready"\r
+  //\r
+  MmioWrite8 ((UINTN) &(((TIS_PC_REGISTERS_PTR) TisReg)->Status), TIS_PC_STS_READY);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  \r
+  //\r
+  // Get the formatted data from the TpmCommandBuf.\r
+  //\r
+  BufSize =0;\r
+  DataFinished = FALSE;\r
+  while (*Fmt != '\0') {\r
+    if (*Fmt == '%') {\r
+      Fmt++;\r
+    }\r
+    Status = TisPcReceiveV (*Fmt, &Ap, TpmCommandBuf, &BufSize, ResponseSize, &DataFinished);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+    if (DataFinished) {\r
+      return EFI_SUCCESS;\r
+    }\r
+    Fmt++;\r
+  }\r
+\r
+  VA_END (Ap);\r
+  return Status;\r
+}\r
+\r