/**
  Dumps all the PEI performance log to DXE performance gauge array.

  This internal function dumps all the PEI performance log to the DXE performance gauge array.
  It retrieves the optional GUID HOB for PEI performance and then saves the performance data
  to DXE performance data structures.

**/
VOID
InternalGetPeiPerformance (
  VOID
  )
{
  EFI_HOB_GUID_TYPE                 *GuidHob;
  PEI_PERFORMANCE_LOG_HEADER        *LogHob;
  PEI_PERFORMANCE_LOG_ENTRY         *LogEntryArray;
  UINT32                            *LogIdArray;
  GAUGE_DATA_ENTRY_EX               *GaugeEntryExArray;
  UINT32                            Index;
  UINT32                            NumberOfEntries;

  NumberOfEntries = 0;
  GaugeEntryExArray = (GAUGE_DATA_ENTRY_EX *) (mGaugeData + 1);

  //
  // Dump PEI Log Entries to DXE Guage Data structure.
  //
  GuidHob = GetFirstGuidHob (&gPerformanceProtocolGuid);
  if (GuidHob != NULL) {
    LogHob          = GET_GUID_HOB_DATA (GuidHob);
    LogEntryArray   = (PEI_PERFORMANCE_LOG_ENTRY *) (LogHob + 1);

    NumberOfEntries = LogHob->NumberOfEntries;
    for (Index = 0; Index < NumberOfEntries; Index++) {
      GaugeEntryExArray[Index].Handle         = LogEntryArray[Index].Handle;
      AsciiStrnCpy (GaugeEntryExArray[Index].Token,  LogEntryArray[Index].Token,  DXE_PERFORMANCE_STRING_LENGTH);
      AsciiStrnCpy (GaugeEntryExArray[Index].Module, LogEntryArray[Index].Module, DXE_PERFORMANCE_STRING_LENGTH);
      GaugeEntryExArray[Index].StartTimeStamp = LogEntryArray[Index].StartTimeStamp;
      GaugeEntryExArray[Index].EndTimeStamp   = LogEntryArray[Index].EndTimeStamp;
      GaugeEntryExArray[Index].Identifier     = 0;
    }

    GuidHob = GetFirstGuidHob (&gPerformanceExProtocolGuid);
    if (GuidHob != NULL) {
      LogIdArray    = GET_GUID_HOB_DATA (GuidHob);
      for (Index = 0; Index < NumberOfEntries; Index++) {
        GaugeEntryExArray[Index].Identifier   = LogIdArray[Index];
      }
    }
  }
  mGaugeData->NumberOfEntries = NumberOfEntries;
}
Пример #2
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;
    AsciiStrnCpy (
      Private->Mode.TftpError.ErrorString,
      (CHAR8 *) Packet->Error.ErrorMessage,
      PXE_MTFTP_ERROR_STRING_LENGTH
      );
  }

  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;
}
Пример #3
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;

  InternalGetPerformanceHobLog (&PeiPerformanceLog, &PeiPerformanceIdArray);

  if (PeiPerformanceLog->NumberOfEntries >= PcdGet8 (PcdMaxPeiPerformanceLogEntries)) {
    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) {
    AsciiStrnCpy (LogEntryArray[Index].Token, Token, PEI_PERFORMANCE_STRING_LENGTH);
  }
  if (Module != NULL) {
    AsciiStrnCpy (LogEntryArray[Index].Module, Module, PEI_PERFORMANCE_STRING_LENGTH);
  }

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

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

  return RETURN_SUCCESS;
}
Пример #4
0
/**
  This is a callback function when packets received/transmitted in Mtftp driver.

  A callback function that is provided by the caller to intercept               
  the EFI_MTFTP4_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  This           Pointer to Mtftp protocol instance
  @param  Token          Pointer to Mtftp token
  @param  PacketLen      Length of Mtftp packet
  @param  Packet         Pointer to Mtftp packet

  @retval EFI_SUCCESS    Operation sucess
  @retval EFI_ABORTED    Abort transfer process 

**/
EFI_STATUS
EFIAPI
PxeBcCheckPacket (
  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) {
    Private->Mode.TftpErrorReceived = TRUE;
    Private->Mode.TftpError.ErrorCode = (UINT8) Packet->Error.ErrorCode;
    AsciiStrnCpy (Private->Mode.TftpError.ErrorString, (CHAR8 *) Packet->Error.ErrorMessage, 127);
  }

  if (Callback != NULL) {

    Status = Callback->Callback (
                        Callback,
                        Private->Function,
                        TRUE,
                        PacketLen,
                        (EFI_PXE_BASE_CODE_PACKET *) Packet
                        );
    if (Status != EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE) {

      Status = EFI_ABORTED;
    } else {

      Status = EFI_SUCCESS;
    }
  }

  return Status;
}
Пример #5
0
/**

  Allocates a block of memory and writes performance data of booting into it.
  OS can processing these record.

**/
VOID
WriteBootToOsPerformanceData (
    VOID
)
{
    EFI_STATUS                Status;
    UINT32                    AcpiLowMemoryLength;
    UINT32                    LimitCount;
    EFI_HANDLE                *Handles;
    UINTN                     NoHandles;
    CHAR8                     GaugeString[PERF_TOKEN_LENGTH];
    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;

    //
    // 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;
    }

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


    AcpiLowMemoryLength = 0x4000;
    if (mAcpiLowMemoryBase == 0x0FFFFFFFF) {
        //
        // Allocate a block of memory that contain performance data to OS
        //
        Status = gBS->AllocatePages (
                     AllocateMaxAddress,
                     EfiReservedMemoryType,
                     EFI_SIZE_TO_PAGES (AcpiLowMemoryLength),
                     &mAcpiLowMemoryBase
                 );
        if (EFI_ERROR (Status)) {
            FreePool (Handles);
            return ;
        }
    }


    Ptr        = (UINT8 *) ((UINT32) mAcpiLowMemoryBase + sizeof (PERF_HEADER));
    LimitCount = (AcpiLowMemoryLength - 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);

            AsciiStrCpy (mPerfData.Token, 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));

            AsciiStrnCpy (mPerfData.Token, 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)
    );

    gRT->SetVariable (
        L"PerfDataMemAddr",
        &gPerformanceProtocolGuid,
        EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
        sizeof (EFI_PHYSICAL_ADDRESS),
        &mAcpiLowMemoryBase
    );

    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;

  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) {
      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) {
    AsciiStrnCpy (GaugeEntryExArray[Index].Token, Token, DXE_PERFORMANCE_STRING_LENGTH);
  }
  if (Module != NULL) {
    AsciiStrnCpy (GaugeEntryExArray[Index].Module, Module, DXE_PERFORMANCE_STRING_LENGTH);
  }

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

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

  mGaugeData->NumberOfEntries++;

  return EFI_SUCCESS;
}
Пример #7
0
EFI_STATUS
BootMenuUpdateBootOption (
  IN LIST_ENTRY *BootOptionsList
  )
{
  EFI_STATUS                    Status;
  BDS_LOAD_OPTION_ENTRY         *BootOptionEntry;
  BDS_LOAD_OPTION               *BootOption;
  BDS_LOAD_OPTION_SUPPORT*      DeviceSupport;
  ARM_BDS_LOADER_ARGUMENTS*     BootArguments;
  CHAR16                        BootDescription[BOOT_DEVICE_DESCRIPTION_MAX];
  CHAR8                         CmdLine[BOOT_DEVICE_OPTION_MAX];
  CHAR16                        UnicodeCmdLine[BOOT_DEVICE_OPTION_MAX];
  EFI_DEVICE_PATH               *DevicePath;
  EFI_DEVICE_PATH               *TempInitrdPath;
  ARM_BDS_LOADER_TYPE           BootType;
  ARM_BDS_LOADER_OPTIONAL_DATA* LoaderOptionalData;
  ARM_BDS_LINUX_ARGUMENTS*      LinuxArguments;
  EFI_DEVICE_PATH               *InitrdPathNodes;
  EFI_DEVICE_PATH               *InitrdPath;
  UINTN                         InitrdSize;
  UINTN                         CmdLineSize;
  BOOLEAN                       InitrdSupport;
  UINT8*                        OptionalData;
  UINTN                         OptionalDataSize;
  BOOLEAN                       IsPrintable;
  BOOLEAN                       IsUnicode;

  DisplayBootOptions (BootOptionsList);
  Status = SelectBootOption (BootOptionsList, UPDATE_BOOT_ENTRY, &BootOptionEntry);
  if (EFI_ERROR (Status)) {
    return Status;
  }
  BootOption = BootOptionEntry->BdsLoadOption;

  // Get the device support for this Boot Option
  Status = BootDeviceGetDeviceSupport (BootOption->FilePathList, &DeviceSupport);
  if (EFI_ERROR(Status)) {
    Print(L"Not possible to retrieve the supported device for the update\n");
    return EFI_UNSUPPORTED;
  }

  Status = DeviceSupport->UpdateDevicePathNode (BootOption->FilePathList, L"EFI Application or the kernel", &DevicePath);
  if (EFI_ERROR(Status)) {
    Status = EFI_ABORTED;
    goto EXIT;
  }

  if (DeviceSupport->RequestBootType) {
    Status = BootDeviceGetType (DevicePath, &BootType, &BootOption->Attributes);
    if (EFI_ERROR(Status)) {
      Status = EFI_ABORTED;
      goto EXIT;
    }
  }

  LoaderOptionalData = BootOption->OptionalData;
  if (LoaderOptionalData != NULL) {
    BootType = (ARM_BDS_LOADER_TYPE)ReadUnaligned32 ((UINT32 *)(&LoaderOptionalData->Header.LoaderType));
  } else {
    BootType = BDS_LOADER_EFI_APPLICATION;
  }

  if ((BootType == BDS_LOADER_KERNEL_LINUX_ATAG) || (BootType == BDS_LOADER_KERNEL_LINUX_FDT)) {
    LinuxArguments = &LoaderOptionalData->Arguments.LinuxArguments;

    CmdLineSize = ReadUnaligned16 ((CONST UINT16*)&LinuxArguments->CmdLineSize);

    InitrdSize = ReadUnaligned16 ((CONST UINT16*)&LinuxArguments->InitrdSize);
    if (InitrdSize > 0) {
      Print(L"Keep the initrd: ");
    } else {
      Print(L"Add an initrd: ");
    }
    Status = GetHIInputBoolean (&InitrdSupport);
    if (EFI_ERROR(Status)) {
      Status = EFI_ABORTED;
      goto EXIT;
    }

    if (InitrdSupport) {
      if (InitrdSize > 0) {
        // Case we update the initrd device path
        Status = DeviceSupport->UpdateDevicePathNode ((EFI_DEVICE_PATH*)((UINTN)(LinuxArguments + 1) + CmdLineSize), L"initrd", &InitrdPath);
        if (EFI_ERROR(Status) && Status != EFI_NOT_FOUND) {// EFI_NOT_FOUND is returned on empty input string, but we can boot without an initrd
          Status = EFI_ABORTED;
          goto EXIT;
        }
        InitrdSize = GetDevicePathSize (InitrdPath);
      } else {
        // Case we create the initrd device path

        Status = DeviceSupport->CreateDevicePathNode (L"initrd", &InitrdPathNodes);
        if (EFI_ERROR(Status) && Status != EFI_NOT_FOUND) { // EFI_NOT_FOUND is returned on empty input string, but we can boot without an initrd
          Status = EFI_ABORTED;
          goto EXIT;
        }

        if (InitrdPathNodes != NULL) {
          // Duplicate Linux kernel Device Path
          TempInitrdPath = DuplicateDevicePath (BootOption->FilePathList);
          // Replace Linux kernel Node by EndNode
          SetDevicePathEndNode (GetLastDevicePathNode (TempInitrdPath));
          // Append the Device Path to the selected device path
          InitrdPath = AppendDevicePath (TempInitrdPath, (CONST EFI_DEVICE_PATH_PROTOCOL *)InitrdPathNodes);
          FreePool (TempInitrdPath);
          // Free the InitrdPathNodes created by Support->CreateDevicePathNode()
          FreePool (InitrdPathNodes);
          if (InitrdPath == NULL) {
            Status = EFI_OUT_OF_RESOURCES;
            goto EXIT;
          }
          InitrdSize = GetDevicePathSize (InitrdPath);
        } else {
          InitrdPath = NULL;
        }
      }
    } else {
      InitrdSize = 0;
    }

    Print(L"Arguments to pass to the binary: ");
    if (CmdLineSize > 0) {
      AsciiStrnCpy (CmdLine, (CONST CHAR8*)(LinuxArguments + 1), sizeof (CmdLine));
      CmdLine[sizeof (CmdLine) - 1] = '\0';
    } else {
      CmdLine[0] = '\0';
    }
    Status = EditHIInputAscii (CmdLine, BOOT_DEVICE_OPTION_MAX);
    if (EFI_ERROR(Status)) {
      Status = EFI_ABORTED;
      goto FREE_DEVICE_PATH;
    }

    CmdLineSize = AsciiStrSize (CmdLine);

    OptionalDataSize = sizeof(ARM_BDS_LOADER_ARGUMENTS) + CmdLineSize + InitrdSize;
    BootArguments = (ARM_BDS_LOADER_ARGUMENTS*)AllocatePool (OptionalDataSize);
    BootArguments->LinuxArguments.CmdLineSize = CmdLineSize;
    BootArguments->LinuxArguments.InitrdSize = InitrdSize;
    CopyMem (&BootArguments->LinuxArguments + 1, CmdLine, CmdLineSize);
    CopyMem ((VOID*)((UINTN)(&BootArguments->LinuxArguments + 1) + CmdLineSize), InitrdPath, InitrdSize);

    OptionalData = (UINT8*)BootArguments;
  } else {
    Print (L"Arguments to pass to the EFI Application: ");

    if (BootOption->OptionalDataSize > 0) {
      IsPrintable = IsPrintableString (BootOption->OptionalData, &IsUnicode);
      if (IsPrintable) {
          //
          // The size in bytes of the string, final zero included, should
          // be equal to or at least lower than "BootOption->OptionalDataSize"
          // and the "IsPrintableString()" has already tested that the length
          // in number of characters is smaller than BOOT_DEVICE_OPTION_MAX,
          // final '\0' included. We can thus copy the string for editing
          // using "CopyMem()". Furthermore, note that in the case of an Unicode
          // string "StrnCpy()" and "StrCpy()" can not be used to copy the
          // string because the data pointed to by "BootOption->OptionalData"
          // is not necessarily 2-byte aligned.
          //
        if (IsUnicode) {
          CopyMem (
            UnicodeCmdLine, BootOption->OptionalData,
            MIN (sizeof (UnicodeCmdLine),
                 BootOption->OptionalDataSize)
            );
        } else {
          CopyMem (
            CmdLine, BootOption->OptionalData,
            MIN (sizeof (CmdLine),
                 BootOption->OptionalDataSize)
            );
        }
      }
    } else {
      UnicodeCmdLine[0] = L'\0';
      IsPrintable = TRUE;
      IsUnicode = TRUE;
    }

    // We do not request arguments for OptionalData that cannot be printed
    if (IsPrintable) {
      if (IsUnicode) {
        Status = EditHIInputStr (UnicodeCmdLine, BOOT_DEVICE_OPTION_MAX);
        if (EFI_ERROR (Status)) {
          Status = EFI_ABORTED;
          goto FREE_DEVICE_PATH;
        }

        OptionalData = (UINT8*)UnicodeCmdLine;
        OptionalDataSize = StrSize (UnicodeCmdLine);
      } else {
        Status = EditHIInputAscii (CmdLine, BOOT_DEVICE_OPTION_MAX);
        if (EFI_ERROR (Status)) {
          Status = EFI_ABORTED;
          goto FREE_DEVICE_PATH;
        }

        OptionalData = (UINT8*)CmdLine;
        OptionalDataSize = AsciiStrSize (CmdLine);
      }
    } else {
      // We keep the former OptionalData
      OptionalData = BootOption->OptionalData;
      OptionalDataSize = BootOption->OptionalDataSize;
    }
  }

  Print(L"Description for this new Entry: ");
  StrnCpy (BootDescription, BootOption->Description, BOOT_DEVICE_DESCRIPTION_MAX);
  Status = EditHIInputStr (BootDescription, BOOT_DEVICE_DESCRIPTION_MAX);
  if (EFI_ERROR(Status)) {
    Status = EFI_ABORTED;
    goto FREE_DEVICE_PATH;
  }

  // Update the entry
  Status = BootOptionUpdate (BootOption, BootOption->Attributes, BootDescription, DevicePath, BootType, OptionalData, OptionalDataSize);

FREE_DEVICE_PATH:
  FreePool (DevicePath);

EXIT:
  if (Status == EFI_ABORTED) {
    Print(L"\n");
  }
  return Status;
}
Пример #8
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);
  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);
    OptCnt++;
  }

  Status = Mtftp4->GetInfo (
                     Mtftp4,
                     FALSE,
                     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;
      AsciiStrnCpy (
        Private->Mode.TftpError.ErrorString,
        (CHAR8 *) Packet->Error.ErrorMessage,
        PXE_MTFTP_ERROR_STRING_LENGTH
        );
    }
    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;
}
Пример #9
0
/**
  This function is to get size of a file by Tftp.
  
  @param  Private        Pointer to PxeBc private data
  @param  Config         Pointer to Mtftp configuration data
  @param  Filename       Pointer to file name
  @param  BlockSize      Pointer to block size
  @param  BufferSize     Pointer to buffer size

  @retval EFI_SUCCESS        Get the size of file success
  @retval EFI_NOT_FOUND      Parse the tftp ptions failed.
  @retval EFI_DEVICE_ERROR   The network device encountered an error during this operation.
  @retval Other              Has not get the size of the file.
  
**/
EFI_STATUS
PxeBcTftpGetFileSize (
  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;
  }

  ReqOpt[0].OptionStr = (UINT8*)mMtftpOptions[PXE_MTFTP_OPTION_TSIZE_INDEX];
  UtoA10 (0, (CHAR8 *) OptBuf);
  ReqOpt[0].ValueStr = OptBuf;

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

  Status = Mtftp4->GetInfo (
                    Mtftp4,
                    FALSE,
                    Filename,
                    NULL,
                    (UINT8) OptCnt,
                    ReqOpt,
                    &PktLen,
                    &Packet
                    );

  if (EFI_ERROR (Status)) {
    if (Status == EFI_TFTP_ERROR) {
      Private->Mode.TftpErrorReceived = TRUE;
      Private->Mode.TftpError.ErrorCode = (UINT8) Packet->Error.ErrorCode;
      AsciiStrnCpy (
        Private->Mode.TftpError.ErrorString, 
        (CHAR8 *) Packet->Error.ErrorMessage, 
        127
        );
    }
    goto ON_ERROR;
  }

  OptCnt = 0;

  Status = Mtftp4->ParseOptions (
                    Mtftp4,
                    PktLen,
                    Packet,
                    (UINT32 *) &OptCnt,
                    &Option
                    );

  if (EFI_ERROR (Status)) {

    goto ON_ERROR;
  }

  Status = EFI_NOT_FOUND;

  while (OptCnt != 0) {

    if (AsciiStrnCmp ((CHAR8 *) Option[OptCnt - 1].OptionStr, "tsize", 5) == 0) {

      *BufferSize = AtoU64 (Option[OptCnt - 1].ValueStr);
      Status      = EFI_SUCCESS;
    }

    OptCnt--;
  }

  FreePool (Option);

ON_ERROR:

  if (Packet != NULL) {
    FreePool (Packet);
  }

  Mtftp4->Configure (Mtftp4, NULL);

  return Status;
}
Пример #10
0
/**
  Performance measure function to get S3 detailed performance data.

  This function will getS3 detailed performance data and saved in pre-reserved ACPI memory.
**/
VOID
WriteToOsS3PerformanceData (
  VOID
  )
{
  EFI_STATUS                                    Status;
  EFI_PHYSICAL_ADDRESS                          mAcpiLowMemoryBase;
  PERF_HEADER                                   *PerfHeader;
  PERF_DATA                                     *PerfData;
  UINT64                                        Ticker;
  UINTN                                         Index;
  EFI_PEI_READ_ONLY_VARIABLE2_PPI               *VariableServices;
  UINTN                                         VarSize;
  UINTN                                         LogEntryKey;
  CONST VOID                                    *Handle;
  CONST CHAR8                                   *Token;
  CONST CHAR8                                   *Module;
  UINT64                                        StartTicker;
  UINT64                                        EndTicker;
  UINT64                                        StartValue;
  UINT64                                        EndValue;
  BOOLEAN                                       CountUp;
  UINT64                                        Freq;

  //
  // Retrive time stamp count as early as possilbe
  //
  Ticker = GetPerformanceCounter ();

  Freq   = GetPerformanceCounterProperties (&StartValue, &EndValue);

  Freq   = DivU64x32 (Freq, 1000);

  Status = PeiServicesLocatePpi (
             &gEfiPeiReadOnlyVariable2PpiGuid,
             0,
             NULL,
             (VOID **) &VariableServices
             );
  ASSERT_EFI_ERROR (Status);

  VarSize   = sizeof (EFI_PHYSICAL_ADDRESS);
  Status = VariableServices->GetVariable (
                               VariableServices,
                               L"PerfDataMemAddr",
                               &gPerformanceProtocolGuid,
                               NULL,
                               &VarSize,
                               &mAcpiLowMemoryBase
                               );
  if (EFI_ERROR (Status)) {
    DEBUG ((EFI_D_ERROR, "Fail to retrieve variable to log S3 performance data \n"));
    return;
  }

  PerfHeader = (PERF_HEADER *) (UINTN) mAcpiLowMemoryBase;

  if (PerfHeader->Signiture != PERFORMANCE_SIGNATURE) {
    DEBUG ((EFI_D_ERROR, "Performance data in ACPI memory get corrupted! \n"));
    return;
  }

  //
  // Record total S3 resume time.
  //
  if (EndValue >= StartValue) {
    PerfHeader->S3Resume = Ticker - StartValue;
    CountUp              = TRUE;
  } else {
    PerfHeader->S3Resume = StartValue - Ticker;
    CountUp              = FALSE;
  }

  //
  // Get S3 detailed performance data
  //
  Index = 0;
  LogEntryKey = 0;
  while ((LogEntryKey = GetPerformanceMeasurement (
                          LogEntryKey,
                          &Handle,
                          &Token,
                          &Module,
                          &StartTicker,
                          &EndTicker)) != 0) {
    if (EndTicker != 0) {
      PerfData = &PerfHeader->S3Entry[Index];

      //
      // Use File Handle to specify the different performance log for PEIM.
      // File Handle is the base address of PEIM FFS file.
      //
      if ((AsciiStrnCmp (Token, "PEIM", PEI_PERFORMANCE_STRING_SIZE) == 0) && (Handle != NULL)) {
        AsciiSPrint (PerfData->Token, PERF_TOKEN_LENGTH, "0x%11p", Handle);
      } else {
        AsciiStrnCpy (PerfData->Token, Token, PERF_TOKEN_LENGTH);
      }
      if (StartTicker == 1) {
        StartTicker = StartValue;
      }
      if (EndTicker == 1) {
        EndTicker = StartValue;
      }
      Ticker = CountUp? (EndTicker - StartTicker) : (StartTicker - EndTicker);
      PerfData->Duration = (UINT32) DivU64x32 (Ticker, (UINT32) Freq);

      //
      // Only Record > 1ms performance data so that more big performance can be recorded.
      //
      if ((Ticker > Freq) && (++Index >= PERF_PEI_ENTRY_MAX_NUM)) {
        //
        // Reach the maximum number of PEI performance log entries.
        //
        break;
      }
    }
  }
  PerfHeader->S3EntryNum = (UINT32) Index;
}