]> git.proxmox.com Git - mirror_edk2.git/blobdiff - SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.c
SecurityPkg: Clean up source files
[mirror_edk2.git] / SecurityPkg / Tcg / MemoryOverwriteControl / TcgMor.c
index ce53112dc57070f11c3bc949a145713d551a1863..c16761bb3dd99cc71d807f4af625b2490352da3b 100644 (file)
 /** @file\r
   TCG MOR (Memory Overwrite Request) Control Driver.\r
 \r
-  This driver initilize MemoryOverwriteRequestControl variable. It \r
-  will clear MOR_CLEAR_MEMORY_BIT bit if it is set.\r
+  This driver initilize MemoryOverwriteRequestControl variable. It\r
+  will clear MOR_CLEAR_MEMORY_BIT bit if it is set. It will also do TPer Reset for\r
+  those encrypted drives through EFI_STORAGE_SECURITY_COMMAND_PROTOCOL at EndOfDxe.\r
 \r
-Copyright (c) 2009 - 2011, 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
+Copyright (c) 2009 - 2018, 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
+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 "TcgMor.h"\r
 \r
+UINT8    mMorControl;\r
+\r
+/**\r
+  Ready to Boot Event notification handler.\r
+\r
+  @param[in]  Event     Event whose notification function is being invoked\r
+  @param[in]  Context   Pointer to the notification function's context\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+OnReadyToBoot (\r
+  IN      EFI_EVENT                 Event,\r
+  IN      VOID                      *Context\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  UINTN       DataSize;\r
+\r
+  if (MOR_CLEAR_MEMORY_VALUE (mMorControl) == 0x0) {\r
+    //\r
+    // MorControl is expected, directly return to avoid unnecessary variable operation\r
+    //\r
+    return ;\r
+  }\r
+  //\r
+  // Clear MOR_CLEAR_MEMORY_BIT\r
+  //\r
+  DEBUG ((EFI_D_INFO, "TcgMor: Clear MorClearMemory bit\n"));\r
+  mMorControl &= 0xFE;\r
+\r
+  DataSize = sizeof (mMorControl);\r
+  Status   = gRT->SetVariable (\r
+               MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,\r
+               &gEfiMemoryOverwriteControlDataGuid,\r
+               EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
+               DataSize,\r
+               &mMorControl\r
+               );\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "TcgMor: Clear MOR_CLEAR_MEMORY_BIT failure, Status = %r\n"));\r
+  }\r
+}\r
+\r
+/**\r
+  Send TPer Reset command to reset eDrive to lock all protected bands.\r
+  Typically, there are 2 mechanism for resetting eDrive. They are:\r
+  1. TPer Reset through IEEE 1667 protocol.\r
+  2. TPer Reset through native TCG protocol.\r
+  This routine will detect what protocol the attached eDrive comform to, TCG or\r
+  IEEE 1667 protocol. Then send out TPer Reset command separately.\r
+\r
+  @param[in] Ssp      The pointer to EFI_STORAGE_SECURITY_COMMAND_PROTOCOL instance.\r
+  @param[in] MediaId  ID of the medium to receive data from or send data to.\r
+\r
+**/\r
+VOID\r
+InitiateTPerReset (\r
+  IN  EFI_STORAGE_SECURITY_COMMAND_PROTOCOL    *Ssp,\r
+  IN  UINT32                                   MediaId\r
+  )\r
+{\r
+\r
+  EFI_STATUS                                   Status;\r
+  UINT8                                        *Buffer;\r
+  UINTN                                        XferSize;\r
+  UINTN                                        Len;\r
+  UINTN                                        Index;\r
+  BOOLEAN                                      TcgFlag;\r
+  BOOLEAN                                      IeeeFlag;\r
+  SUPPORTED_SECURITY_PROTOCOLS_PARAMETER_DATA  *Data;\r
+\r
+  Buffer        = NULL;\r
+  TcgFlag       = FALSE;\r
+  IeeeFlag      = FALSE;\r
+\r
+  //\r
+  // ATA8-ACS 7.57.6.1 indicates the Transfer Length field requirements a multiple of 512.\r
+  // If the length of the TRUSTED RECEIVE parameter data is greater than the Transfer Length,\r
+  // then the device shall return the TRUSTED RECEIVE parameter data truncated to the requested Transfer Length.\r
+  //\r
+  Len           = ROUNDUP512(sizeof(SUPPORTED_SECURITY_PROTOCOLS_PARAMETER_DATA));\r
+  Buffer        = AllocateZeroPool(Len);\r
+\r
+  if (Buffer == NULL) {\r
+    return;\r
+  }\r
+\r
+  //\r
+  // When the Security Protocol field is set to 00h, and SP Specific is set to 0000h in a TRUSTED RECEIVE\r
+  // command, the device basic information data shall be returned.\r
+  //\r
+  Status = Ssp->ReceiveData (\r
+                  Ssp,\r
+                  MediaId,\r
+                  100000000,                    // Timeout 10-sec\r
+                  0,                            // SecurityProtocol\r
+                  0,                            // SecurityProtocolSpecifcData\r
+                  Len,                          // PayloadBufferSize,\r
+                  Buffer,                       // PayloadBuffer\r
+                  &XferSize\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    goto Exit;\r
+  }\r
+\r
+  //\r
+  // In returned data, the ListLength field indicates the total length, in bytes,\r
+  // of the supported security protocol list.\r
+  //\r
+  Data = (SUPPORTED_SECURITY_PROTOCOLS_PARAMETER_DATA*)Buffer;\r
+  Len  = ROUNDUP512(sizeof (SUPPORTED_SECURITY_PROTOCOLS_PARAMETER_DATA) +\r
+                    (Data->SupportedSecurityListLength[0] << 8) +\r
+                    (Data->SupportedSecurityListLength[1])\r
+                    );\r
+\r
+  //\r
+  // Free original buffer and allocate new buffer.\r
+  //\r
+  FreePool(Buffer);\r
+  Buffer = AllocateZeroPool(Len);\r
+  if (Buffer == NULL) {\r
+    return;\r
+  }\r
+\r
+  //\r
+  // Read full supported security protocol list from device.\r
+  //\r
+  Status = Ssp->ReceiveData (\r
+                  Ssp,\r
+                  MediaId,\r
+                  100000000,                    // Timeout 10-sec\r
+                  0,                            // SecurityProtocol\r
+                  0,                            // SecurityProtocolSpecifcData\r
+                  Len,                          // PayloadBufferSize,\r
+                  Buffer,                       // PayloadBuffer\r
+                  &XferSize\r
+                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    goto Exit;\r
+  }\r
+\r
+  Data = (SUPPORTED_SECURITY_PROTOCOLS_PARAMETER_DATA*)Buffer;\r
+  Len  = (Data->SupportedSecurityListLength[0] << 8) + Data->SupportedSecurityListLength[1];\r
+\r
+  //\r
+  // Iterate full supported security protocol list to check if TCG or IEEE 1667 protocol\r
+  // is supported.\r
+  //\r
+  for (Index = 0; Index < Len; Index++) {\r
+    if (Data->SupportedSecurityProtocol[Index] == SECURITY_PROTOCOL_TCG) {\r
+      //\r
+      // Found a  TCG device.\r
+      //\r
+      TcgFlag = TRUE;\r
+      DEBUG ((EFI_D_INFO, "This device is a TCG protocol device\n"));\r
+      break;\r
+    }\r
+\r
+    if (Data->SupportedSecurityProtocol[Index] == SECURITY_PROTOCOL_IEEE1667) {\r
+      //\r
+      // Found a IEEE 1667 device.\r
+      //\r
+      IeeeFlag = TRUE;\r
+      DEBUG ((EFI_D_INFO, "This device is a IEEE 1667 protocol device\n"));\r
+      break;\r
+    }\r
+  }\r
+\r
+  if (!TcgFlag && !IeeeFlag) {\r
+    DEBUG ((EFI_D_INFO, "Neither a TCG nor IEEE 1667 protocol device is found\n"));\r
+    goto Exit;\r
+  }\r
+\r
+  if (TcgFlag) {\r
+    //\r
+    // As long as TCG protocol is supported, send out a TPer Reset\r
+    // TCG command to the device via the TrustedSend command with a non-zero Transfer Length.\r
+    //\r
+    Status = Ssp->SendData (\r
+                    Ssp,\r
+                    MediaId,\r
+                    100000000,                    // Timeout 10-sec\r
+                    SECURITY_PROTOCOL_TCG,        // SecurityProtocol\r
+                    0x0400,                       // SecurityProtocolSpecifcData\r
+                    512,                          // PayloadBufferSize,\r
+                    Buffer                        // PayloadBuffer\r
+                    );\r
+\r
+    if (!EFI_ERROR (Status)) {\r
+      DEBUG ((EFI_D_INFO, "Send TPer Reset Command Successfully !\n"));\r
+    } else {\r
+      DEBUG ((EFI_D_INFO, "Send TPer Reset Command Fail !\n"));\r
+    }\r
+  }\r
+\r
+  if (IeeeFlag) {\r
+    //\r
+    // TBD : Perform a TPer Reset via IEEE 1667 Protocol\r
+    //\r
+    DEBUG ((EFI_D_INFO, "IEEE 1667 Protocol didn't support yet!\n"));\r
+  }\r
+\r
+Exit:\r
+\r
+  if (Buffer != NULL) {\r
+    FreePool(Buffer);\r
+  }\r
+}\r
+\r
+/**\r
+  Notification function of END_OF_DXE.\r
+\r
+  @param[in] Event      Event whose notification function is being invoked.\r
+  @param[in] Context    Pointer to the notification function's context.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+TPerResetAtEndOfDxe (\r
+  IN EFI_EVENT  Event,\r
+  IN VOID       *Context\r
+  )\r
+{\r
+  EFI_STORAGE_SECURITY_COMMAND_PROTOCOL   *Ssp;\r
+  EFI_BLOCK_IO_PROTOCOL                   *BlockIo;\r
+  EFI_STATUS                              Status;\r
+  UINTN                                   HandleCount;\r
+  EFI_HANDLE                              *HandleBuffer;\r
+  UINTN                                   Index;\r
+\r
+  //\r
+  // Locate all SSP protocol instances.\r
+  //\r
+  HandleCount  = 0;\r
+  HandleBuffer = NULL;\r
+\r
+  Status = gBS->LocateHandleBuffer (\r
+                  ByProtocol,\r
+                  &gEfiStorageSecurityCommandProtocolGuid,\r
+                  NULL,\r
+                  &HandleCount,\r
+                  &HandleBuffer\r
+                  );\r
+\r
+  if (EFI_ERROR (Status) || (HandleCount == 0) || (HandleBuffer == NULL)) {\r
+    return;\r
+  }\r
+\r
+  for (Index = 0; Index < HandleCount; Index ++) {\r
+    //\r
+    // Get the SSP interface.\r
+    //\r
+    Status = gBS->HandleProtocol(\r
+                    HandleBuffer[Index],\r
+                    &gEfiStorageSecurityCommandProtocolGuid,\r
+                    (VOID **) &Ssp\r
+                    );\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      continue;\r
+    }\r
+\r
+    Status = gBS->HandleProtocol(\r
+                    HandleBuffer[Index],\r
+                    &gEfiBlockIoProtocolGuid,\r
+                    (VOID **) &BlockIo\r
+                    );\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      continue;\r
+    }\r
+\r
+    InitiateTPerReset (Ssp, BlockIo->Media->MediaId);\r
+  }\r
+\r
+  FreePool (HandleBuffer);\r
+}\r
+\r
 /**\r
   Entry Point for TCG MOR Control driver.\r
 \r
   @param[in] ImageHandle  Image handle of this driver.\r
   @param[in] SystemTable  A Pointer to the EFI System Table.\r
 \r
-  @retval EFI_SUCEESS     \r
+  @retval EFI_SUCEESS\r
   @return Others          Some error occurs.\r
 **/\r
 EFI_STATUS\r
@@ -34,48 +315,66 @@ MorDriverEntryPoint (
   )\r
 {\r
   EFI_STATUS  Status;\r
-  UINT8       MorControl;\r
   UINTN       DataSize;\r
+  EFI_EVENT   Event;\r
 \r
   ///\r
   /// The firmware is required to create the MemoryOverwriteRequestControl UEFI variable.\r
   ///\r
 \r
-  DataSize = sizeof (MorControl);\r
+  DataSize = sizeof (mMorControl);\r
   Status = gRT->GetVariable (\r
-                  MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME, \r
-                  &gEfiMemoryOverwriteControlDataGuid, \r
-                  NULL, \r
-                  &DataSize, \r
-                  &MorControl\r
+                  MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,\r
+                  &gEfiMemoryOverwriteControlDataGuid,\r
+                  NULL,\r
+                  &DataSize,\r
+                  &mMorControl\r
                   );\r
   if (EFI_ERROR (Status)) {\r
     //\r
     // Set default value to 0\r
     //\r
-    MorControl = 0;\r
+    mMorControl = 0;\r
+    Status = gRT->SetVariable (\r
+                    MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,\r
+                    &gEfiMemoryOverwriteControlDataGuid,\r
+                    EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
+                    DataSize,\r
+                    &mMorControl\r
+                    );\r
+    DEBUG ((EFI_D_INFO, "TcgMor: Create MOR variable! Status = %r\n", Status));\r
   } else {\r
-    if (MOR_CLEAR_MEMORY_VALUE (MorControl) == 0x0) {\r
-      //\r
-      // MorControl is expected, directly return to avoid unnecessary variable operation\r
-      //\r
-      return EFI_SUCCESS;\r
+    //\r
+    // Create a Ready To Boot Event and Clear the MorControl bit in the call back function.\r
+    //\r
+    DEBUG ((EFI_D_INFO, "TcgMor: Create ReadyToBoot Event for MorControl Bit cleanning!\n"));\r
+    Status = EfiCreateEventReadyToBootEx (\r
+               TPL_CALLBACK,\r
+               OnReadyToBoot,\r
+               NULL,\r
+               &Event\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
     }\r
+\r
     //\r
-    // Clear MOR_CLEAR_MEMORY_BIT\r
+    // Register EFI_END_OF_DXE_EVENT_GROUP_GUID event.\r
     //\r
-    DEBUG ((EFI_D_INFO, "TcgMor: Clear MorClearMemory bit\n"));\r
-    MorControl &= 0xFE;\r
+    DEBUG ((EFI_D_INFO, "TcgMor: Create EndofDxe Event for Mor TPer Reset!\n"));\r
+    Status = gBS->CreateEventEx (\r
+                    EVT_NOTIFY_SIGNAL,\r
+                    TPL_CALLBACK,\r
+                    TPerResetAtEndOfDxe,\r
+                    NULL,\r
+                    &gEfiEndOfDxeEventGroupGuid,\r
+                    &Event\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
   }\r
-  \r
-  Status = gRT->SetVariable (\r
-                  MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME, \r
-                  &gEfiMemoryOverwriteControlDataGuid, \r
-                  EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
-                  DataSize, \r
-                  &MorControl\r
-                  );\r
-  ASSERT_EFI_ERROR (Status);\r
+\r
   return Status;\r
 }\r
 \r