Example #1
0
/**
  Save this command in the circular history buffer. Older commands are
  overwritten with newer commands.

  @param  Cmd   Command line to archive the history of.

  @return None

**/
VOID
SetCmdHistory (
  IN  CHAR8 *Cmd
  )
{
  // Don't bother adding empty commands to the list
  if (AsciiStrLen(Cmd) != 0) {

    // First entry
    if (mCmdHistoryStart == -1) {
      mCmdHistoryStart   = 0;
      mCmdHistoryEnd     = 0;
    } else {
      // Record the new command at the next index
      RingBufferIncrement(&mCmdHistoryStart);

      // If the next index runs into the end index, shuffle end back by one
      if (mCmdHistoryStart == mCmdHistoryEnd) {
        RingBufferIncrement(&mCmdHistoryEnd);
      }
    }

    // Copy the new command line into the ring buffer
    AsciiStrnCpyS (&mCmdHistory[mCmdHistoryStart][0], MAX_CMD_LINE, Cmd, MAX_CMD_LINE);
  }

  // Reset the command history for the next up arrow press
  mCmdHistoryCurrent = mCmdHistoryStart;
}
Example #2
0
/**
  Creates a record for the beginning of a performance measurement.

  Creates a record that contains the Handle, Token, Module and Identifier.
  If TimeStamp is not zero, then TimeStamp is added to the record as the start time.
  If TimeStamp is zero, then this function reads the current time stamp
  and adds that time stamp value to the record as the start time.

  @param  Handle                  Pointer to environment specific context used
                                  to identify the component being measured.
  @param  Token                   Pointer to a Null-terminated ASCII string
                                  that identifies the component being measured.
  @param  Module                  Pointer to a Null-terminated ASCII string
                                  that identifies the module being measured.
  @param  TimeStamp               64-bit time stamp.
  @param  Identifier              32-bit identifier. If the value is 0, the created record
                                  is same as the one created by StartPerformanceMeasurement.

  @retval RETURN_SUCCESS          The start of the measurement was recorded.
  @retval RETURN_OUT_OF_RESOURCES There are not enough resources to record the measurement.

**/
RETURN_STATUS
EFIAPI
StartPerformanceMeasurementEx (
  IN CONST VOID   *Handle,  OPTIONAL
  IN CONST CHAR8  *Token,   OPTIONAL
  IN CONST CHAR8  *Module,  OPTIONAL
  IN UINT64       TimeStamp,
  IN UINT32       Identifier
  )
{
  PEI_PERFORMANCE_LOG_HEADER  *PeiPerformanceLog;
  UINT32                      *PeiPerformanceIdArray;
  PEI_PERFORMANCE_LOG_ENTRY   *LogEntryArray;
  UINT32                      Index;
  UINT16                      PeiPerformanceLogEntries;

  PeiPerformanceLogEntries = (UINT16) (PcdGet16 (PcdMaxPeiPerformanceLogEntries16) != 0 ?
                                       PcdGet16 (PcdMaxPeiPerformanceLogEntries16) :
                                       PcdGet8 (PcdMaxPeiPerformanceLogEntries));

  InternalGetPerformanceHobLog (&PeiPerformanceLog, &PeiPerformanceIdArray);

  if (PeiPerformanceLog->NumberOfEntries >= PeiPerformanceLogEntries) {
    DEBUG ((DEBUG_ERROR, "PEI performance log array out of resources\n"));
    return RETURN_OUT_OF_RESOURCES;
  }
  Index                       = PeiPerformanceLog->NumberOfEntries++;
  LogEntryArray               = (PEI_PERFORMANCE_LOG_ENTRY *) (PeiPerformanceLog + 1);
  LogEntryArray[Index].Handle = (EFI_PHYSICAL_ADDRESS) (UINTN) Handle;

  if (Token != NULL) {
    AsciiStrnCpyS (LogEntryArray[Index].Token, PEI_PERFORMANCE_STRING_SIZE, Token, PEI_PERFORMANCE_STRING_LENGTH);
  }
  if (Module != NULL) {
    AsciiStrnCpyS (LogEntryArray[Index].Module, PEI_PERFORMANCE_STRING_SIZE, Module, PEI_PERFORMANCE_STRING_LENGTH);
  }

  LogEntryArray[Index].EndTimeStamp = 0;
  PeiPerformanceIdArray[Index] = Identifier;

  if (TimeStamp == 0) {
    TimeStamp = GetPerformanceCounter ();
  }
  LogEntryArray[Index].StartTimeStamp = TimeStamp;

  return RETURN_SUCCESS;
}
Example #3
0
/**
  This is a callback function when packets are received or transmitted in Mtftp driver.

  A callback function that is provided by the caller to intercept
  the EFI_MTFTP6_OPCODE_DATA or EFI_MTFTP4_OPCODE_DATA8 packets processed in the
  EFI_MTFTP4_PROTOCOL.ReadFile() function, and alternatively to intercept
  EFI_MTFTP4_OPCODE_OACK or EFI_MTFTP4_OPCODE_ERROR packets during a call to
  EFI_MTFTP4_PROTOCOL.ReadFile(), WriteFile() or ReadDirectory().

  @param[in]  This           Pointer to EFI_MTFTP4_PROTOCOL.
  @param[in]  Token          Pointer to EFI_MTFTP4_TOKEN.
  @param[in]  PacketLen      Length of EFI_MTFTP4_PACKET.
  @param[in]  Packet         Pointer to EFI_MTFTP4_PACKET to be checked.

  @retval EFI_SUCCESS    The current operation succeeeded.
  @retval EFI_ABORTED    Abort the current transfer process.

**/
EFI_STATUS
EFIAPI
PxeBcMtftp4CheckPacket (
    IN EFI_MTFTP4_PROTOCOL        *This,
    IN EFI_MTFTP4_TOKEN           *Token,
    IN UINT16                     PacketLen,
    IN EFI_MTFTP4_PACKET          *Packet
)
{
    PXEBC_PRIVATE_DATA                  *Private;
    EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL *Callback;
    EFI_STATUS                          Status;

    Private   = (PXEBC_PRIVATE_DATA *) Token->Context;
    Callback  = Private->PxeBcCallback;
    Status    = EFI_SUCCESS;

    if (Packet->OpCode == EFI_MTFTP4_OPCODE_ERROR) {
        //
        // Store the tftp error message into mode data and set the received flag.
        //
        Private->Mode.TftpErrorReceived   = TRUE;
        Private->Mode.TftpError.ErrorCode = (UINT8) Packet->Error.ErrorCode;
        AsciiStrnCpyS (
            Private->Mode.TftpError.ErrorString,
            PXE_MTFTP_ERROR_STRING_LENGTH,
            (CHAR8 *) Packet->Error.ErrorMessage,
            PXE_MTFTP_ERROR_STRING_LENGTH - 1
        );
        Private->Mode.TftpError.ErrorString[PXE_MTFTP_ERROR_STRING_LENGTH - 1] = '\0';
    }

    if (Callback != NULL) {
        //
        // Callback to user if has when received any tftp packet.
        //
        Status = Callback->Callback (
                     Callback,
                     Private->Function,
                     TRUE,
                     PacketLen,
                     (EFI_PXE_BASE_CODE_PACKET *) Packet
                 );
        if (Status != EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE) {
            //
            // User wants to abort current process if not EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE.
            //
            Status = EFI_ABORTED;
        } else {
            //
            // User wants to continue current process if EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE.
            //
            Status = EFI_SUCCESS;
        }
    }

    return Status;
}
Example #4
0
/**
  Collect the keyboard input for a cmd line. Carriage Return, New Line, or ESC
  terminates the command line. You can edit the command line via left arrow,
  delete and backspace and they all back up and erase the command line.
  No edit of command line is possible without deletion at this time!
  The up arrow and down arrow fill Cmd with information from the history
  buffer.

  @param  Cmd         Command line to return
  @param  CmdMaxSize  Maximum size of Cmd

  @return The Status of EblGetCharKey()

**/
EFI_STATUS
GetCmd (
  IN OUT  CHAR8   *Cmd,
  IN      UINTN   CmdMaxSize
  )
{
  EFI_STATUS    Status;
  UINTN         Index;
  UINTN         Index2;
  CHAR8         Char;
  CHAR8         *History;
  EFI_INPUT_KEY Key;

  for (Index = 0; Index < CmdMaxSize - 1;) {
    Status = EblGetCharKey (&Key, 0, NULL);
    if (EFI_ERROR (Status)) {
      Cmd[Index] = '\0';
      AsciiPrint ("\n");
      return Status;
    }

    Char = (CHAR8)Key.UnicodeChar;
    if ((Char == '\n') || (Char == '\r') || (Char == 0x7f)) {
      Cmd[Index] = '\0';
      if (FixedPcdGetBool(PcdEmbeddedShellCharacterEcho) == TRUE) {
        AsciiPrint ("\n\r");
      }
      return EFI_SUCCESS;
    } else if ((Char == '\b') || (Key.ScanCode == SCAN_LEFT) || (Key.ScanCode == SCAN_DELETE)){
      if (Index != 0) {
        Index--;
        //
        // Update the display
        //
        AsciiPrint ("\b \b");
      }
    } else if ((Key.ScanCode == SCAN_UP) || Key.ScanCode == SCAN_DOWN) {
      History = GetCmdHistory (Key.ScanCode);
      //
      // Clear display line
      //
      for (Index2 = 0; Index2 < Index; Index2++) {
        AsciiPrint ("\b \b");
      }
      AsciiPrint (History);
      Index = AsciiStrLen (History);
      AsciiStrnCpyS (Cmd, CmdMaxSize, History, CmdMaxSize);
    } else {
      Cmd[Index++] = Char;
      if (FixedPcdGetBool(PcdEmbeddedShellCharacterEcho) == TRUE) {
        AsciiPrint ("%c", Char);
      }
    }
  }

  return EFI_SUCCESS;
}
/**
  Get the file name portion of the Pdb File Name.

  The portion of the Pdb File Name between the last backslash and
  either a following period or the end of the string is copied into
  AsciiBuffer.  The name is truncated, if necessary, to ensure that
  AsciiBuffer is not overrun.

  @param[in]  PdbFileName     Pdb file name.
  @param[out] AsciiBuffer     The resultant Ascii File Name.

**/
VOID
GetShortPdbFileName (
  IN  CHAR8     *PdbFileName,
  OUT CHAR8     *AsciiBuffer
  )
{
  UINTN IndexPdb;     // Current work location within a Pdb string.
  UINTN IndexBuffer;  // Current work location within a Buffer string.
  UINTN StartIndex;
  UINTN EndIndex;

  ZeroMem (AsciiBuffer, PROFILE_NAME_STRING_LENGTH + 1);

  if (PdbFileName == NULL) {
    AsciiStrnCpyS (AsciiBuffer, PROFILE_NAME_STRING_LENGTH + 1, " ", 1);
  } else {
    StartIndex = 0;
    for (EndIndex = 0; PdbFileName[EndIndex] != 0; EndIndex++);
    for (IndexPdb = 0; PdbFileName[IndexPdb] != 0; IndexPdb++) {
      if ((PdbFileName[IndexPdb] == '\\') || (PdbFileName[IndexPdb] == '/')) {
        StartIndex = IndexPdb + 1;
      }

      if (PdbFileName[IndexPdb] == '.') {
        EndIndex = IndexPdb;
      }
    }

    IndexBuffer = 0;
    for (IndexPdb = StartIndex; IndexPdb < EndIndex; IndexPdb++) {
      AsciiBuffer[IndexBuffer] = PdbFileName[IndexPdb];
      IndexBuffer++;
      if (IndexBuffer >= PROFILE_NAME_STRING_LENGTH) {
        AsciiBuffer[PROFILE_NAME_STRING_LENGTH] = 0;
        break;
      }
    }
  }
}
Example #6
0
/**
  This function is to get size of a file using Tftp.

  @param[in]      Private        Pointer to PxeBc private data.
  @param[in]      Config         Pointer to EFI_MTFTP4_CONFIG_DATA.
  @param[in]      Filename       Pointer to boot file name.
  @param[in]      BlockSize      Pointer to required block size.
  @param[in, out] BufferSize     Pointer to buffer size.

  @retval EFI_SUCCESS        Successfully obtained the size of file.
  @retval EFI_NOT_FOUND      Parse the tftp options failed.
  @retval EFI_DEVICE_ERROR   The network device encountered an error during this operation.
  @retval Others             Did not obtain the size of the file.

**/
EFI_STATUS
PxeBcMtftp4GetFileSize (
    IN     PXEBC_PRIVATE_DATA         *Private,
    IN     EFI_MTFTP4_CONFIG_DATA     *Config,
    IN     UINT8                      *Filename,
    IN     UINTN                      *BlockSize,
    IN OUT UINT64                     *BufferSize
)
{
    EFI_MTFTP4_PROTOCOL *Mtftp4;
    EFI_MTFTP4_OPTION   ReqOpt[2];
    EFI_MTFTP4_PACKET   *Packet;
    EFI_MTFTP4_OPTION   *Option;
    UINT32              PktLen;
    UINT8               OptBuf[128];
    UINT32              OptCnt;
    EFI_STATUS          Status;

    *BufferSize               = 0;
    Status                    = EFI_DEVICE_ERROR;
    Mtftp4                    = Private->Mtftp4;
    Packet                    = NULL;
    Option                    = NULL;
    PktLen                    = 0;
    OptCnt                    = 1;
    Config->InitialServerPort = PXEBC_BS_DOWNLOAD_PORT;

    Status = Mtftp4->Configure (Mtftp4, Config);
    if (EFI_ERROR (Status)) {
        return Status;
    }

    //
    // Build the required options for get info.
    //
    ReqOpt[0].OptionStr = (UINT8 *) mMtftpOptions[PXE_MTFTP_OPTION_TSIZE_INDEX];
    PxeBcUintnToAscDec (0, OptBuf, PXE_MTFTP_OPTBUF_MAXNUM_INDEX);
    ReqOpt[0].ValueStr  = OptBuf;

    if (BlockSize != NULL) {
        ReqOpt[1].OptionStr = (UINT8 *) mMtftpOptions[PXE_MTFTP_OPTION_BLKSIZE_INDEX];
        ReqOpt[1].ValueStr  = (UINT8 *) (ReqOpt[0].ValueStr + AsciiStrLen ((CHAR8 *) ReqOpt[0].ValueStr) + 1);
        PxeBcUintnToAscDec (*BlockSize, ReqOpt[1].ValueStr, PXE_MTFTP_OPTBUF_MAXNUM_INDEX - (AsciiStrLen ((CHAR8 *) ReqOpt[0].ValueStr) + 1));
        OptCnt++;
    }

    Status = Mtftp4->GetInfo (
                 Mtftp4,
                 NULL,
                 Filename,
                 NULL,
                 (UINT8) OptCnt,
                 ReqOpt,
                 &PktLen,
                 &Packet
             );
    if (EFI_ERROR (Status)) {
        if (Status == EFI_TFTP_ERROR) {
            //
            // Store the tftp error message into mode data and set the received flag.
            //
            Private->Mode.TftpErrorReceived   = TRUE;
            Private->Mode.TftpError.ErrorCode = (UINT8) Packet->Error.ErrorCode;
            AsciiStrnCpyS (
                Private->Mode.TftpError.ErrorString,
                PXE_MTFTP_ERROR_STRING_LENGTH,
                (CHAR8 *) Packet->Error.ErrorMessage,
                PXE_MTFTP_ERROR_STRING_LENGTH - 1
            );
            Private->Mode.TftpError.ErrorString[PXE_MTFTP_ERROR_STRING_LENGTH - 1] = '\0';
        }
        goto ON_ERROR;
    }

    //
    // Parse the options in the reply packet.
    //
    OptCnt = 0;
    Status = Mtftp4->ParseOptions (
                 Mtftp4,
                 PktLen,
                 Packet,
                 (UINT32 *) &OptCnt,
                 &Option
             );
    if (EFI_ERROR (Status)) {
        goto ON_ERROR;
    }

    //
    // Parse out the value of "tsize" option.
    //
    Status = EFI_NOT_FOUND;
    while (OptCnt != 0) {
        if (AsciiStrnCmp ((CHAR8 *) Option[OptCnt - 1].OptionStr, "tsize", 5) == 0) {
            *BufferSize = AsciiStrDecimalToUint64 ((CHAR8 *) (Option[OptCnt - 1].ValueStr));
            Status      = EFI_SUCCESS;
        }
        OptCnt--;
    }
    FreePool (Option);

ON_ERROR:
    if (Packet != NULL) {
        FreePool (Packet);
    }
    Mtftp4->Configure (Mtftp4, NULL);

    return Status;
}
Example #7
0
/**

  Writes performance data of booting into the allocated memory.
  OS can process these records.

  @param  Event                 The triggered event.
  @param  Context               Context for this event.

**/
VOID
EFIAPI
WriteBootToOsPerformanceData (
  IN EFI_EVENT  Event,
  IN VOID       *Context
  )
{
  EFI_STATUS                Status;
  UINT32                    LimitCount;
  EFI_HANDLE                *Handles;
  UINTN                     NoHandles;
  CHAR8                     GaugeString[PERF_TOKEN_SIZE];
  UINT8                     *Ptr;
  UINT32                    Index;
  UINT64                    Ticker;
  UINT64                    Freq;
  UINT32                    Duration;
  UINTN                     LogEntryKey;
  CONST VOID                *Handle;
  CONST CHAR8               *Token;
  CONST CHAR8               *Module;
  UINT64                    StartTicker;
  UINT64                    EndTicker;
  UINT64                    StartValue;
  UINT64                    EndValue;
  BOOLEAN                   CountUp;
  UINTN                     EntryIndex;
  UINTN                     NumPerfEntries;
  //
  // List of flags indicating PerfEntry contains DXE handle
  //
  BOOLEAN                   *PerfEntriesAsDxeHandle;
  UINTN                     VarSize;

  //
  // Record the performance data for End of BDS
  //
  PERF_END(NULL, "BDS", NULL, 0);

  //
  // Retrieve time stamp count as early as possible
  //
  Ticker  = GetPerformanceCounter ();

  Freq    = GetPerformanceCounterProperties (&StartValue, &EndValue);
  
  Freq    = DivU64x32 (Freq, 1000);

  mPerfHeader.CpuFreq = Freq;

  //
  // Record BDS raw performance data
  //
  if (EndValue >= StartValue) {
    mPerfHeader.BDSRaw = Ticker - StartValue;
    CountUp            = TRUE;
  } else {
    mPerfHeader.BDSRaw = StartValue - Ticker;
    CountUp            = FALSE;
  }

  if (mAcpiLowMemoryBase == 0x0FFFFFFFF) {
    VarSize = sizeof (EFI_PHYSICAL_ADDRESS);
    Status = gRT->GetVariable (
                    L"PerfDataMemAddr",
                    &gPerformanceProtocolGuid,
                    NULL,
                    &VarSize,
                    &mAcpiLowMemoryBase
                    );
    if (EFI_ERROR (Status)) {
      //
      // Fail to get the variable, return.
      //
      return;
    }
  }

  //
  // Put Detailed performance data into memory
  //
  Handles = NULL;
  Status = gBS->LocateHandleBuffer (
                  AllHandles,
                  NULL,
                  NULL,
                  &NoHandles,
                  &Handles
                  );
  if (EFI_ERROR (Status)) {
    return ;
  }

  Ptr        = (UINT8 *) ((UINT32) mAcpiLowMemoryBase + sizeof (PERF_HEADER));
  LimitCount = (UINT32) (PERF_DATA_MAX_LENGTH - sizeof (PERF_HEADER)) / sizeof (PERF_DATA);

  NumPerfEntries = 0;
  LogEntryKey    = 0;
  while ((LogEntryKey = GetPerformanceMeasurement (
                          LogEntryKey,
                          &Handle,
                          &Token,
                          &Module,
                          &StartTicker,
                          &EndTicker)) != 0) {
    NumPerfEntries++;
  }
  PerfEntriesAsDxeHandle = AllocateZeroPool (NumPerfEntries * sizeof (BOOLEAN));
  ASSERT (PerfEntriesAsDxeHandle != NULL);
  
  //
  // Get DXE drivers performance
  //
  for (Index = 0; Index < NoHandles; Index++) {
    Ticker = 0;
    LogEntryKey = 0;
    EntryIndex  = 0;
    while ((LogEntryKey = GetPerformanceMeasurement (
                            LogEntryKey,
                            &Handle,
                            &Token,
                            &Module,
                            &StartTicker,
                            &EndTicker)) != 0) {
      if (Handle == Handles[Index] && !PerfEntriesAsDxeHandle[EntryIndex]) {
        PerfEntriesAsDxeHandle[EntryIndex] = TRUE;
      }
      EntryIndex++;
      if ((Handle == Handles[Index]) && (EndTicker != 0)) {
        if (StartTicker == 1) {
          StartTicker = StartValue;
        }
        if (EndTicker == 1) {
          EndTicker = StartValue;
        }
        Ticker += CountUp ? (EndTicker - StartTicker) : (StartTicker - EndTicker);
      }
    }

    Duration = (UINT32) DivU64x32 (Ticker, (UINT32) Freq);

    if (Duration > 0) {

      GetNameFromHandle (Handles[Index], GaugeString);

      AsciiStrCpyS (mPerfData.Token, PERF_TOKEN_SIZE, GaugeString);
      mPerfData.Duration = Duration;

      CopyMem (Ptr, &mPerfData, sizeof (PERF_DATA));
      Ptr += sizeof (PERF_DATA);

      mPerfHeader.Count++;
      if (mPerfHeader.Count == LimitCount) {
        goto Done;
      }
    }
  }

  //
  // Get inserted performance data
  //
  LogEntryKey = 0;
  EntryIndex  = 0;
  while ((LogEntryKey = GetPerformanceMeasurement (
                          LogEntryKey,
                          &Handle,
                          &Token,
                          &Module,
                          &StartTicker,
                          &EndTicker)) != 0) {
    if (!PerfEntriesAsDxeHandle[EntryIndex] && EndTicker != 0) {

      ZeroMem (&mPerfData, sizeof (PERF_DATA));

      AsciiStrnCpyS (mPerfData.Token, PERF_TOKEN_SIZE, Token, PERF_TOKEN_LENGTH);
      if (StartTicker == 1) {
        StartTicker = StartValue;
      }
      if (EndTicker == 1) {
        EndTicker = StartValue;
      }
      Ticker = CountUp ? (EndTicker - StartTicker) : (StartTicker - EndTicker);

      mPerfData.Duration = (UINT32) DivU64x32 (Ticker, (UINT32) Freq);

      CopyMem (Ptr, &mPerfData, sizeof (PERF_DATA));
      Ptr += sizeof (PERF_DATA);

      mPerfHeader.Count++;
      if (mPerfHeader.Count == LimitCount) {
        goto Done;
      }
    }
    EntryIndex++;
  }

Done:

  FreePool (Handles);
  FreePool (PerfEntriesAsDxeHandle);

  mPerfHeader.Signiture = PERFORMANCE_SIGNATURE;

  //
  // Put performance data to Reserved memory
  //
  CopyMem (
    (UINTN *) (UINTN) mAcpiLowMemoryBase,
    &mPerfHeader,
    sizeof (PERF_HEADER)
    );

  return ;
}
/**
  Adds a record at the end of the performance measurement log
  that records the start time of a performance measurement.

  Adds a record to the end of the performance measurement log
  that contains the Handle, Token, Module and Identifier.
  The end time of the new record must be set to zero.
  If TimeStamp is not zero, then TimeStamp is used to fill in the start time in the record.
  If TimeStamp is zero, the start time in the record is filled in with the value
  read from the current time stamp.

  @param  Handle                  Pointer to environment specific context used
                                  to identify the component being measured.
  @param  Token                   Pointer to a Null-terminated ASCII string
                                  that identifies the component being measured.
  @param  Module                  Pointer to a Null-terminated ASCII string
                                  that identifies the module being measured.
  @param  TimeStamp               64-bit time stamp.
  @param  Identifier              32-bit identifier. If the value is 0, the created record
                                  is same as the one created by StartGauge of PERFORMANCE_PROTOCOL.

  @retval EFI_SUCCESS             The data was read correctly from the device.
  @retval EFI_OUT_OF_RESOURCES    There are not enough resources to record the measurement.

**/
EFI_STATUS
EFIAPI
StartGaugeEx (
  IN CONST VOID   *Handle,  OPTIONAL
  IN CONST CHAR8  *Token,   OPTIONAL
  IN CONST CHAR8  *Module,  OPTIONAL
  IN UINT64       TimeStamp,
  IN UINT32       Identifier
  )
{
  GAUGE_DATA_ENTRY_EX       *GaugeEntryExArray;
  UINTN                     GaugeDataSize;
  GAUGE_DATA_HEADER         *NewGaugeData;
  UINTN                     OldGaugeDataSize;
  GAUGE_DATA_HEADER         *OldGaugeData;
  UINT32                    Index;

  AcquireSpinLock (&mSmmPerfLock);

  Index = mGaugeData->NumberOfEntries;
  if (Index >= mMaxGaugeRecords) {
    //
    // Try to enlarge the scale of gauge array.
    //
    OldGaugeData      = mGaugeData;
    OldGaugeDataSize  = sizeof (GAUGE_DATA_HEADER) + sizeof (GAUGE_DATA_ENTRY_EX) * mMaxGaugeRecords;

    GaugeDataSize     = sizeof (GAUGE_DATA_HEADER) + sizeof (GAUGE_DATA_ENTRY_EX) * mMaxGaugeRecords * 2;

    NewGaugeData = AllocateZeroPool (GaugeDataSize);
    if (NewGaugeData == NULL) {
      ReleaseSpinLock (&mSmmPerfLock);
      return EFI_OUT_OF_RESOURCES;
    }

    mGaugeData = NewGaugeData;
    mMaxGaugeRecords *= 2;

    //
    // Initialize new data array and migrate old data one.
    //
    mGaugeData = CopyMem (mGaugeData, OldGaugeData, OldGaugeDataSize);

    FreePool (OldGaugeData);
  }

  GaugeEntryExArray               = (GAUGE_DATA_ENTRY_EX *) (mGaugeData + 1);
  GaugeEntryExArray[Index].Handle = (EFI_PHYSICAL_ADDRESS) (UINTN) Handle;

  if (Token != NULL) {
    AsciiStrnCpyS (GaugeEntryExArray[Index].Token, SMM_PERFORMANCE_STRING_SIZE, Token, SMM_PERFORMANCE_STRING_LENGTH);
  }
  if (Module != NULL) {
    AsciiStrnCpyS (GaugeEntryExArray[Index].Module, SMM_PERFORMANCE_STRING_SIZE, Module, SMM_PERFORMANCE_STRING_LENGTH);
  }

  GaugeEntryExArray[Index].EndTimeStamp = 0;
  GaugeEntryExArray[Index].Identifier = Identifier;

  if (TimeStamp == 0) {
    TimeStamp = GetPerformanceCounter ();
  }
  GaugeEntryExArray[Index].StartTimeStamp = TimeStamp;

  mGaugeData->NumberOfEntries++;

  ReleaseSpinLock (&mSmmPerfLock);

  return EFI_SUCCESS;
}
Example #9
0
/**
  Convert PEI performance log to FPDT String boot record.

  @param  IsStart                 TRUE if the performance log is start log.
  @param  Handle                  Pointer to environment specific context used
                                  to identify the component being measured.
  @param  Token                   Pointer to a Null-terminated ASCII string
                                  that identifies the component being measured.
  @param  Module                  Pointer to a Null-terminated ASCII string
                                  that identifies the module being measured.
  @param  Ticker                  64-bit time stamp.
  @param  Identifier              32-bit identifier. If the value is 0, the created record
                                  is same as the one created by StartGauge of PERFORMANCE_PROTOCOL.

  @retval EFI_SUCCESS              Add FPDT boot record.
  @retval EFI_OUT_OF_RESOURCES     There are not enough resources to record the measurement.
  @retval EFI_UNSUPPORTED          No matched FPDT record.

**/
EFI_STATUS
InsertPeiFpdtMeasurement (
  IN BOOLEAN      IsStart,
  IN CONST VOID   *Handle,  OPTIONAL
  IN CONST CHAR8  *Token,   OPTIONAL
  IN CONST CHAR8  *Module,  OPTIONAL
  IN UINT64       Ticker,
  IN UINT32       Identifier
  )
{
  EFI_HOB_GUID_TYPE                     *GuidHob;
  UINTN                                 PeiPerformanceSize;
  UINT8                                 *PeiFirmwarePerformance;
  FPDT_PEI_EXT_PERF_HEADER              *PeiPerformanceLogHeader;
  FPDT_RECORD_PTR                       FpdtRecordPtr;
  FPDT_BASIC_RECORD_INFO                RecordInfo;
  CONST VOID                            *ModuleGuid;
  UINTN                                 DestMax;
  UINTN                                 StrLength;
  CONST CHAR8                           *StringPtr;
  EFI_STATUS                            Status;
  UINT16                                PeiPerformanceLogEntries;
  UINT64                                TimeStamp;

  StringPtr = NULL;
  FpdtRecordPtr.RecordHeader = NULL;
  PeiPerformanceLogHeader = NULL;

  //
  // Get record info (type, size, ProgressID and Module Guid).
  //
  Status = GetFpdtRecordInfo (IsStart, Handle, Token, Module, &RecordInfo);
  if (EFI_ERROR (Status)) {
    return Status;
  }

  //
  // If PERF_START()/PERF_END() have specified the ProgressID,it has high priority.
  // !!! Note: If the Perf is not the known Token used in the core but have same
  // ID with the core Token, this case will not be supported.
  // And in currtnt usage mode, for the unkown ID, there is a general rule:
  // If it is start pref: the lower 4 bits of the ID should be 0.
  // If it is end pref: the lower 4 bits of the ID should not be 0.
  // If input ID doesn't follow the rule, we will adjust it.
  //
  if ((Identifier != 0) && (IsKnownID (Identifier)) && (!IsKnownTokens (Token))) {
    return EFI_UNSUPPORTED;
  } else if ((Identifier != 0) && (!IsKnownID (Identifier)) && (!IsKnownTokens (Token))) {
    if (IsStart && ((Identifier & 0x000F) != 0)) {
      Identifier &= 0xFFF0;
    } else if ((!IsStart) && ((Identifier & 0x000F) == 0)) {
      Identifier += 1;
    }
    RecordInfo.ProgressID = (UINT16)Identifier;
  }

  //
  // Get the number of PeiPerformanceLogEntries form PCD.
  //
  PeiPerformanceLogEntries = (UINT16) (PcdGet16 (PcdMaxPeiPerformanceLogEntries16) != 0 ?
                                       PcdGet16 (PcdMaxPeiPerformanceLogEntries16) :
                                       PcdGet8 (PcdMaxPeiPerformanceLogEntries));

  //
  // Create GUID HOB Data.
  //
  GuidHob = GetFirstGuidHob (&gEdkiiFpdtExtendedFirmwarePerformanceGuid);
  PeiFirmwarePerformance = NULL;
  while (GuidHob != NULL) {
    //
    // PEI Performance HOB was found, then return the existing one.
    //
    PeiFirmwarePerformance  = (UINT8*)GET_GUID_HOB_DATA (GuidHob);
    PeiPerformanceLogHeader = (FPDT_PEI_EXT_PERF_HEADER *)PeiFirmwarePerformance;
    if (!PeiPerformanceLogHeader->HobIsFull && PeiPerformanceLogHeader->SizeOfAllEntries + RecordInfo.RecordSize > PeiPerformanceLogEntries * MAX_RECORD_SIZE) {
      PeiPerformanceLogHeader->HobIsFull = TRUE;
    }
    if (!PeiPerformanceLogHeader->HobIsFull && PeiPerformanceLogHeader->SizeOfAllEntries + RecordInfo.RecordSize <= PeiPerformanceLogEntries * MAX_RECORD_SIZE) {
      FpdtRecordPtr.RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)(PeiFirmwarePerformance + sizeof (FPDT_PEI_EXT_PERF_HEADER) + PeiPerformanceLogHeader->SizeOfAllEntries);
      break;
    }
    //
    // Previous HOB is used, then find next one.
    //
    GuidHob = GetNextGuidHob (&gEdkiiFpdtExtendedFirmwarePerformanceGuid, GET_NEXT_HOB (GuidHob));
  }

  if (GuidHob == NULL) {
    //
    // PEI Performance HOB was not found, then build one.
    //
    PeiPerformanceSize      = sizeof (FPDT_PEI_EXT_PERF_HEADER) +
                              MAX_RECORD_SIZE * PeiPerformanceLogEntries;
    PeiFirmwarePerformance  = (UINT8*)BuildGuidHob (&gEdkiiFpdtExtendedFirmwarePerformanceGuid, PeiPerformanceSize);
    if (PeiFirmwarePerformance != NULL) {
      ZeroMem (PeiFirmwarePerformance, PeiPerformanceSize);
    }
    PeiPerformanceLogHeader = (FPDT_PEI_EXT_PERF_HEADER *)PeiFirmwarePerformance;
    FpdtRecordPtr.RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)(PeiFirmwarePerformance + sizeof (FPDT_PEI_EXT_PERF_HEADER));
  }

  if (PeiFirmwarePerformance == NULL) {
    //
    // there is no enough resource to store performance data
    //
    return EFI_OUT_OF_RESOURCES;
  }

  //
  // Get the TimeStamp.
  //
  if (Ticker == 0) {
    Ticker    = GetPerformanceCounter ();
    TimeStamp = GetTimeInNanoSecond (Ticker);
  } else if (Ticker == 1) {
    TimeStamp = 0;
  } else {
    TimeStamp = GetTimeInNanoSecond (Ticker);
  }

  //
  // Get the ModuleGuid.
  //
  if (Handle != NULL) {
    ModuleGuid = Handle;
  } else {
    ModuleGuid = &gEfiCallerIdGuid;
  }

  switch (RecordInfo.Type) {
  case FPDT_GUID_EVENT_TYPE:
    FpdtRecordPtr.GuidEvent->Header.Type       = FPDT_GUID_EVENT_TYPE;
    FpdtRecordPtr.GuidEvent->Header.Length     = RecordInfo.RecordSize;;
    FpdtRecordPtr.GuidEvent->Header.Revision   = FPDT_RECORD_REVISION_1;
    FpdtRecordPtr.GuidEvent->ProgressID        = RecordInfo.ProgressID;
    FpdtRecordPtr.GuidEvent->Timestamp         = TimeStamp;
    CopyMem (&FpdtRecordPtr.GuidEvent->Guid, ModuleGuid, sizeof (EFI_GUID));
    PeiPerformanceLogHeader->SizeOfAllEntries += RecordInfo.RecordSize;
    break;

  case FPDT_GUID_QWORD_EVENT_TYPE:
    FpdtRecordPtr.GuidQwordEvent->Header.Type     = FPDT_GUID_QWORD_EVENT_TYPE;
    FpdtRecordPtr.GuidQwordEvent->Header.Length   = RecordInfo.RecordSize;;
    FpdtRecordPtr.GuidQwordEvent->Header.Revision = FPDT_RECORD_REVISION_1;
    FpdtRecordPtr.GuidQwordEvent->ProgressID      = RecordInfo.ProgressID;
    FpdtRecordPtr.GuidQwordEvent->Timestamp       = TimeStamp;
    PeiPerformanceLogHeader->LoadImageCount++;
    FpdtRecordPtr.GuidQwordEvent->Qword           = PeiPerformanceLogHeader->LoadImageCount;
    CopyMem (&FpdtRecordPtr.GuidQwordEvent->Guid, ModuleGuid, sizeof (EFI_GUID));
    PeiPerformanceLogHeader->SizeOfAllEntries += RecordInfo.RecordSize;
    break;

  case FPDT_DYNAMIC_STRING_EVENT_TYPE:
    FpdtRecordPtr.DynamicStringEvent->Header.Type       = FPDT_DYNAMIC_STRING_EVENT_TYPE;
    FpdtRecordPtr.DynamicStringEvent->Header.Length     = RecordInfo.RecordSize;
    FpdtRecordPtr.DynamicStringEvent->Header.Revision   = FPDT_RECORD_REVISION_1;
    FpdtRecordPtr.DynamicStringEvent->ProgressID        = RecordInfo.ProgressID;
    FpdtRecordPtr.DynamicStringEvent->Timestamp         = TimeStamp;
    CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, ModuleGuid, sizeof (EFI_GUID));
    PeiPerformanceLogHeader->SizeOfAllEntries += RecordInfo.RecordSize;

    if (Token != NULL) {
      StringPtr                     = Token;
    } else if (Module != NULL) {
      StringPtr                     = Module;
    }
    if (StringPtr != NULL && AsciiStrLen (StringPtr) != 0) {
      DestMax                       = (RecordInfo.RecordSize - sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD)) / sizeof (CHAR8);
      StrLength                     = AsciiStrLen (StringPtr);
      if (StrLength >= DestMax) {
        StrLength                   = DestMax -1;
      }
      AsciiStrnCpyS (FpdtRecordPtr.DynamicStringEvent->String, DestMax, StringPtr, StrLength);
    } else {
      AsciiStrCpyS (FpdtRecordPtr.DynamicStringEvent->String, FPDT_STRING_EVENT_RECORD_NAME_LENGTH, "unknown name");
    }
    break;

  default:
    //
    // Record is not supported in current PEI phase, return EFI_ABORTED
    //
    return EFI_UNSUPPORTED;
  }

  return EFI_SUCCESS;
}