text: /** @file
    This library is used by other modules to measure data to TPM.
  
  Copyright (c) 2012 - 2018, Intel Corporation. All rights reserved. <BR>
  SPDX-License-Identifier: BSD-2-Clause-Patent
  
  **/
  
  #include <PiDxe.h>
  
  #include <Protocol/TcgService.h>
  #include <Protocol/Tcg2Protocol.h>
  
  #include <Library/BaseMemoryLib.h>
  #include <Library/MemoryAllocationLib.h>
  #include <Library/UefiBootServicesTableLib.h>
  #include <Library/DebugLib.h>
  #include <Library/TpmMeasurementLib.h>
  
  #include <Guid/Acpi.h>
  #include <IndustryStandard/Acpi.h>
  
  
  
  /**
    Tpm12 measure and log data, and extend the measurement result into a specific PCR.
  
    @param[in]  PcrIndex         PCR Index.
    @param[in]  EventType        Event type.
    @param[in]  EventLog         Measurement event log.
    @param[in]  LogLen           Event log length in bytes.
    @param[in]  HashData         The start of the data buffer to be hashed, extended.
    @param[in]  HashDataLen      The length, in bytes, of the buffer referenced by HashData
  
    @retval EFI_SUCCESS           Operation completed successfully.
    @retval EFI_UNSUPPORTED       TPM device not available.
    @retval EFI_OUT_OF_RESOURCES  Out of memory.
    @retval EFI_DEVICE_ERROR      The operation was unsuccessful.
  **/
  EFI_STATUS
  Tpm12MeasureAndLogData (
    IN UINT32             PcrIndex,
    IN UINT32             EventType,
    IN VOID               *EventLog,
    IN UINT32             LogLen,
    IN VOID               *HashData,
    IN UINT64             HashDataLen
    )
  {
    EFI_STATUS                Status;
    EFI_TCG_PROTOCOL          *TcgProtocol;
    TCG_PCR_EVENT             *TcgEvent;
    EFI_PHYSICAL_ADDRESS      EventLogLastEntry;
    UINT32                    EventNumber;
  
    TcgEvent = NULL;
  
    //
    // Tpm activation state is checked in HashLogExtendEvent
    //
    Status = gBS->LocateProtocol (&gEfiTcgProtocolGuid, NULL, (VOID **) &TcgProtocol);
    if (EFI_ERROR(Status)){
      return Status;
    }
  
    TcgEvent = (TCG_PCR_EVENT *)AllocateZeroPool (sizeof (TCG_PCR_EVENT_HDR) + LogLen);
    if(TcgEvent == NULL) {
      return EFI_OUT_OF_RESOURCES;
    }
  
    TcgEvent->PCRIndex  = PcrIndex;
    TcgEvent->EventType = EventType;
    TcgEvent->EventSize = LogLen;
    CopyMem (&TcgEvent->Event[0], EventLog, LogLen);
    EventNumber = 1;
    Status = TcgProtocol->HashLogExtendEvent (
                            TcgProtocol,
                            (EFI_PHYSICAL_ADDRESS)(UINTN)HashData,
                            HashDataLen,
                            TPM_ALG_SHA,
                            TcgEvent,
                            &EventNumber,
                            &EventLogLastEntry
                            );
  
    FreePool (TcgEvent);
  
    return Status;
  }
  
  /**
    Tpm20 measure and log data, and extend the measurement result into a specific PCR.
  
    @param[in]  PcrIndex         PCR Index.
    @param[in]  EventType        Event type.
    @param[in]  EventLog         Measurement event log.
    @param[in]  LogLen           Event log length in bytes.
    @param[in]  HashData         The start of the data buffer to be hashed, extended.
    @param[in]  HashDataLen      The length, in bytes, of the buffer referenced by HashData
  
    @retval EFI_SUCCESS           Operation completed successfully.
    @retval EFI_UNSUPPORTED       TPM device not available.
    @retval EFI_OUT_OF_RESOURCES  Out of memory.
    @retval EFI_DEVICE_ERROR      The operation was unsuccessful.
  **/
  EFI_STATUS
  Tpm20MeasureAndLogData (
    IN UINT32             PcrIndex,
    IN UINT32             EventType,
    IN VOID               *EventLog,
    IN UINT32             LogLen,
    IN VOID               *HashData,
    IN UINT64             HashDataLen
    )
  {
    EFI_STATUS                Status;
    EFI_TCG2_PROTOCOL         *Tcg2Protocol;
    EFI_TCG2_EVENT            *Tcg2Event;
  
    //
    // TPMPresentFlag is checked in HashLogExtendEvent
    //
    Status = gBS->LocateProtocol (&gEfiTcg2ProtocolGuid, NULL, (VOID **) &Tcg2Protocol);
    if (EFI_ERROR (Status)) {
      return Status;
    }
  
    Tcg2Event = (EFI_TCG2_EVENT *) AllocateZeroPool (LogLen + sizeof (EFI_TCG2_EVENT));
    if(Tcg2Event == NULL) {
      return EFI_OUT_OF_RESOURCES;
    }
  
    Tcg2Event->Size = (UINT32)LogLen + sizeof (EFI_TCG2_EVENT) - sizeof(Tcg2Event->Event);
    Tcg2Event->Header.HeaderSize    = sizeof(EFI_TCG2_EVENT_HEADER);
    Tcg2Event->Header.HeaderVersion = EFI_TCG2_EVENT_HEADER_VERSION;
    Tcg2Event->Header.PCRIndex      = PcrIndex;
    Tcg2Event->Header.EventType     = EventType;
    CopyMem (&Tcg2Event->Event[0], EventLog, LogLen);
  
    Status = Tcg2Protocol->HashLogExtendEvent (
                             Tcg2Protocol,
                             0,
                             (EFI_PHYSICAL_ADDRESS)(UINTN)HashData,
                             HashDataLen,
                             Tcg2Event
                             );
    FreePool (Tcg2Event);
  
    return Status;
  }
  
  /**
    Tpm measure and log data, and extend the measurement result into a specific PCR.
  
    @param[in]  PcrIndex         PCR Index.
    @param[in]  EventType        Event type.
    @param[in]  EventLog         Measurement event log.
    @param[in]  LogLen           Event log length in bytes.
    @param[in]  HashData         The start of the data buffer to be hashed, extended.
    @param[in]  HashDataLen      The length, in bytes, of the buffer referenced by HashData
  
    @retval EFI_SUCCESS               Operation completed successfully.
    @retval EFI_UNSUPPORTED       TPM device not available.
    @retval EFI_OUT_OF_RESOURCES  Out of memory.
    @retval EFI_DEVICE_ERROR      The operation was unsuccessful.
  **/
  EFI_STATUS
  EFIAPI
  TpmMeasureAndLogData (
    IN UINT32             PcrIndex,
    IN UINT32             EventType,
    IN VOID               *EventLog,
    IN UINT32             LogLen,
    IN VOID               *HashData,
    IN UINT64             HashDataLen
    )
  {
    EFI_STATUS  Status;
  
    //
    // Try to measure using Tpm20 protocol
    //
    Status = Tpm20MeasureAndLogData(
               PcrIndex,
               EventType,
               EventLog,
               LogLen,
               HashData,
               HashDataLen
               );
  
    if (EFI_ERROR (Status)) {
      //
      // Try to measure using Tpm1.2 protocol
      //
      Status = Tpm12MeasureAndLogData(
                 PcrIndex,
                 EventType,
                 EventLog,
                 LogLen,
                 HashData,
                 HashDataLen
                 );
    }
  
    return Status;
  }
  