/** Common function which returns vendor details. @param[in] MessageId SCMI_MESSAGE_ID_BASE_DISCOVER_VENDOR OR SCMI_MESSAGE_ID_BASE_DISCOVER_SUB_VENDOR @param[out] VendorIdentifier ASCII name of the vendor/subvendor. @retval EFI_SUCCESS VendorIdentifier is returned. @retval EFI_DEVICE_ERROR SCP returns an SCMI error. @retval !(EFI_SUCCESS) Other errors. **/ STATIC EFI_STATUS BaseDiscoverVendorDetails ( IN SCMI_MESSAGE_ID_BASE MessageId, OUT UINT8 VendorIdentifier[SCMI_MAX_STR_LEN] ) { EFI_STATUS Status; UINT32 *ReturnValues; SCMI_COMMAND Cmd; UINT32 PayloadLength; Cmd.ProtocolId = SCMI_PROTOCOL_ID_BASE; Cmd.MessageId = MessageId; PayloadLength = 0; Status = ScmiCommandExecute ( &Cmd, &PayloadLength, &ReturnValues ); if (EFI_ERROR (Status)) { return Status; } AsciiStrCpyS ( (CHAR8*)VendorIdentifier, SCMI_MAX_STR_LEN, (CONST CHAR8*)ReturnValues ); return EFI_SUCCESS; }
STATIC VOID SetupCmdlineTag ( IN CONST CHAR8 *CmdLine ) { UINT32 LineLength; // Increment the line length by 1 to account for the null string terminator character LineLength = AsciiStrLen (CmdLine) + 1; /* Check for NULL strings. * Do not insert a tag for an empty CommandLine, don't even modify the tag address pointer. * Remember, you have at least one null string terminator character. */ if (LineLength > 1) { mLinuxKernelCurrentAtag->header.size = ((UINT32)sizeof (LINUX_ATAG_HEADER) + LineLength + (UINT32)3) >> 2; mLinuxKernelCurrentAtag->header.type = ATAG_CMDLINE; /* place CommandLine into tag */ AsciiStrCpyS (mLinuxKernelCurrentAtag->body.cmdline_tag.cmdline, LineLength, CmdLine); // move pointer to next tag mLinuxKernelCurrentAtag = next_tag_address (mLinuxKernelCurrentAtag); }
/** 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; AsciiStrCpyS (GaugeEntryExArray[Index].Token, DXE_PERFORMANCE_STRING_SIZE, LogEntryArray[Index].Token); AsciiStrCpyS (GaugeEntryExArray[Index].Module, DXE_PERFORMANCE_STRING_SIZE, LogEntryArray[Index].Module); 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; }
/** Get the name from the Driver handle, which can be a handle with EFI_LOADED_IMAGE_PROTOCOL or EFI_DRIVER_BINDING_PROTOCOL installed. This name can be used in performance data logging. @param Handle Driver handle. @param GaugeString The output string to be logged by performance logger. **/ VOID GetNameFromHandle ( IN EFI_HANDLE Handle, OUT CHAR8 *GaugeString ) { EFI_STATUS Status; EFI_LOADED_IMAGE_PROTOCOL *Image; CHAR8 *PdbFileName; EFI_DRIVER_BINDING_PROTOCOL *DriverBinding; AsciiStrCpyS (GaugeString, PERF_TOKEN_SIZE, " "); // // Get handle name from image protocol // Status = gBS->HandleProtocol ( Handle, &gEfiLoadedImageProtocolGuid, (VOID **) &Image ); if (EFI_ERROR (Status)) { Status = gBS->OpenProtocol ( Handle, &gEfiDriverBindingProtocolGuid, (VOID **) &DriverBinding, NULL, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL ); if (EFI_ERROR (Status)) { return ; } // // Get handle name from image protocol // Status = gBS->HandleProtocol ( DriverBinding->ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &Image ); } PdbFileName = PeCoffLoaderGetPdbPointer (Image->ImageBase); if (PdbFileName != NULL) { GetShortPdbFileName (PdbFileName, GaugeString); } return ; }
/** Get the short verion of PDB file name to be used in performance data logging. @param PdbFileName The long PDB file name. @param GaugeString The output string to be logged by performance logger. **/ VOID GetShortPdbFileName ( IN CONST CHAR8 *PdbFileName, OUT CHAR8 *GaugeString ) { UINTN Index; UINTN Index1; UINTN StartIndex; UINTN EndIndex; if (PdbFileName == NULL) { AsciiStrCpyS (GaugeString, PERF_TOKEN_SIZE, " "); } else { StartIndex = 0; for (EndIndex = 0; PdbFileName[EndIndex] != 0; EndIndex++) ; for (Index = 0; PdbFileName[Index] != 0; Index++) { if (PdbFileName[Index] == '\\') { StartIndex = Index + 1; } if (PdbFileName[Index] == '.') { EndIndex = Index; } } Index1 = 0; for (Index = StartIndex; Index < EndIndex; Index++) { GaugeString[Index1] = PdbFileName[Index]; Index1++; if (Index1 == PERF_TOKEN_LENGTH) { break; } } GaugeString[Index1] = 0; } return ; }
/** Convert unsigned int number to decimal number. @param Number The unsigned int number will be converted. @param Buffer Pointer to the buffer to store the decimal number after transform. @param[in] BufferSize The maxsize of the buffer. @return the length of the number after transform. **/ UINTN UtoA10 ( IN UINTN Number, IN CHAR8 *Buffer, IN UINTN BufferSize ) { UINTN Index; CHAR8 TempStr[64]; Index = 63; TempStr[Index] = 0; do { Index--; TempStr[Index] = (CHAR8) ('0' + (Number % 10)); Number = Number / 10; } while (Number != 0); AsciiStrCpyS (Buffer, BufferSize, &TempStr[Index]); return AsciiStrLen (Buffer); }
/** Patch version string of Physical Presence interface supported by platform. The initial string tag in TPM ACPI table is "$PV". @param[in, out] Table The TPM item in ACPI table. @param[in] PPVer Version string of Physical Presence interface supported by platform. @return The allocated address for the found region. **/ EFI_STATUS UpdatePPVersion ( EFI_ACPI_DESCRIPTION_HEADER *Table, CHAR8 *PPVer ) { EFI_STATUS Status; UINT8 *DataPtr; // // Patch some pointers for the ASL code before loading the SSDT. // for (DataPtr = (UINT8 *)(Table + 1); DataPtr <= (UINT8 *) ((UINT8 *) Table + Table->Length - PHYSICAL_PRESENCE_VERSION_SIZE); DataPtr += 1) { if (AsciiStrCmp((CHAR8 *)DataPtr, PHYSICAL_PRESENCE_VERSION_TAG) == 0) { Status = AsciiStrCpyS((CHAR8 *)DataPtr, PHYSICAL_PRESENCE_VERSION_SIZE, PPVer); DEBUG((EFI_D_INFO, "TPM2 Physical Presence Interface Version update status 0x%x\n", Status)); return Status; } } return EFI_NOT_FOUND; }
/** 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; }
/** 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 ; }
/** Embedded Boot Loader (EBL) - A simple EFI command line application for embedded devices. PcdEmbeddedAutomaticBootCommand is a complied in command line that gets executed automatically. The ; separator allows multiple commands for each command line. @param ImageHandle EFI ImageHandle for this application. @param SystemTable EFI system table @return EFI status of the application **/ EFI_STATUS EFIAPI EdkBootLoaderEntry ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_STATUS Status; CHAR8 CmdLine[MAX_CMD_LINE]; CHAR16 *CommandLineVariable = NULL; CHAR16 *CommandLineVariableName = L"default-cmdline"; UINTN CommandLineVariableSize = 0; EFI_GUID VendorGuid; // Initialize tables of commands EblInitializeCmdTable (); EblInitializeDeviceCmd (); EblInitializemdHwDebugCmds (); EblInitializemdHwIoDebugCmds (); EblInitializeDirCmd (); EblInitializeHobCmd (); EblInitializeScriptCmd (); EblInitializeExternalCmd (); EblInitializeNetworkCmd(); EblInitializeVariableCmds (); if (gST->ConOut == NULL) { DEBUG((EFI_D_ERROR,"Error: No Console Output\n")); return EFI_NOT_READY; } // Disable the 5 minute EFI watchdog time so we don't get automatically reset gBS->SetWatchdogTimer (0, 0, 0, NULL); if (FeaturePcdGet (PcdEmbeddedMacBoot)) { // A MAC will boot in graphics mode, so turn it back to text here // This protocol was removed from edk2. It is only an edk thing. We need to make our own copy. // DisableQuietBoot (); // Enable the biggest output screen size possible gST->ConOut->SetMode (gST->ConOut, (UINTN)gST->ConOut->Mode->MaxMode - 1); } // Save current screen mode gST->ConOut->QueryMode (gST->ConOut, gST->ConOut->Mode->Mode, &gScreenColumns, &gScreenRows); EblPrintStartupBanner (); // Parse command line and handle commands separated by ; // The loop prints the prompt gets user input and saves history // Look for a variable with a default command line, otherwise use the Pcd ZeroMem(&VendorGuid, sizeof(EFI_GUID)); Status = gRT->GetVariable(CommandLineVariableName, &VendorGuid, NULL, &CommandLineVariableSize, CommandLineVariable); if (Status == EFI_BUFFER_TOO_SMALL) { CommandLineVariable = AllocatePool(CommandLineVariableSize); Status = gRT->GetVariable(CommandLineVariableName, &VendorGuid, NULL, &CommandLineVariableSize, CommandLineVariable); if (!EFI_ERROR(Status)) { UnicodeStrToAsciiStrS (CommandLineVariable, CmdLine, MAX_CMD_LINE); } FreePool(CommandLineVariable); } if (EFI_ERROR(Status)) { AsciiStrCpyS (CmdLine, MAX_CMD_LINE, (CHAR8 *)PcdGetPtr (PcdEmbeddedAutomaticBootCommand)); } for (;;) { Status = ProcessCmdLine (CmdLine, MAX_CMD_LINE); if (Status == EFI_ABORTED) { // if a command returns EFI_ABORTED then exit the EBL EblShutdownExternalCmdTable (); return EFI_SUCCESS; } // get the command line from the user EblPrompt (); GetCmd (CmdLine, MAX_CMD_LINE); SetCmdHistory (CmdLine); if (FeaturePcdGet (PcdEmbeddedProbeRemovable)) { // Probe removable media devices to see if media has been inserted or removed. EblProbeRemovableMedia (); } } }
/** Extract the Root Path option and get the required target information. @param[in] RootPath The RootPath. @param[in] Length Length of the RootPath option payload. @param[in, out] ConfigData The iSCSI attempt configuration data read from a nonvolatile device. @retval EFI_SUCCESS All required information is extracted from the RootPath option. @retval EFI_NOT_FOUND The RootPath is not an iSCSI RootPath. @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. @retval EFI_INVALID_PARAMETER The RootPath is malformatted. **/ EFI_STATUS IScsiDhcpExtractRootPath ( IN CHAR8 *RootPath, IN UINT8 Length, IN OUT ISCSI_ATTEMPT_CONFIG_NVDATA *ConfigData ) { EFI_STATUS Status; UINT8 IScsiRootPathIdLen; CHAR8 *TmpStr; ISCSI_ROOT_PATH_FIELD Fields[RP_FIELD_IDX_MAX]; ISCSI_ROOT_PATH_FIELD *Field; UINT32 FieldIndex; UINT8 Index; ISCSI_SESSION_CONFIG_NVDATA *ConfigNvData; EFI_IP_ADDRESS Ip; UINT8 IpMode; ConfigNvData = &ConfigData->SessionConfigData; // // "iscsi:"<servername>":"<protocol>":"<port>":"<LUN>":"<targetname> // IScsiRootPathIdLen = (UINT8) AsciiStrLen (ISCSI_ROOT_PATH_ID); if ((Length <= IScsiRootPathIdLen) || (CompareMem (RootPath, ISCSI_ROOT_PATH_ID, IScsiRootPathIdLen) != 0)) { return EFI_NOT_FOUND; } // // Skip the iSCSI RootPath ID "iscsi:". // RootPath += IScsiRootPathIdLen; Length = (UINT8) (Length - IScsiRootPathIdLen); TmpStr = (CHAR8 *) AllocatePool (Length + 1); if (TmpStr == NULL) { return EFI_OUT_OF_RESOURCES; } CopyMem (TmpStr, RootPath, Length); TmpStr[Length] = '\0'; Index = 0; FieldIndex = RP_FIELD_IDX_SERVERNAME; ZeroMem (&Fields[0], sizeof (Fields)); // // Extract the fields in the Root Path option string. // for (FieldIndex = RP_FIELD_IDX_SERVERNAME; (FieldIndex < RP_FIELD_IDX_MAX) && (Index < Length); FieldIndex++) { if (TmpStr[Index] != ISCSI_ROOT_PATH_FIELD_DELIMITER) { Fields[FieldIndex].Str = &TmpStr[Index]; } while ((TmpStr[Index] != ISCSI_ROOT_PATH_FIELD_DELIMITER) && (Index < Length)) { Index++; } if (TmpStr[Index] == ISCSI_ROOT_PATH_FIELD_DELIMITER) { if (FieldIndex != RP_FIELD_IDX_TARGETNAME) { TmpStr[Index] = '\0'; Index++; } if (Fields[FieldIndex].Str != NULL) { Fields[FieldIndex].Len = (UINT8) AsciiStrLen (Fields[FieldIndex].Str); } } } if (FieldIndex != RP_FIELD_IDX_MAX) { Status = EFI_INVALID_PARAMETER; goto ON_EXIT; } if ((Fields[RP_FIELD_IDX_SERVERNAME].Str == NULL) || (Fields[RP_FIELD_IDX_TARGETNAME].Str == NULL) || (Fields[RP_FIELD_IDX_PROTOCOL].Len > 1) ) { Status = EFI_INVALID_PARAMETER; goto ON_EXIT; } // // Get the IP address of the target. // Field = &Fields[RP_FIELD_IDX_SERVERNAME]; if (ConfigNvData->IpMode < IP_MODE_AUTOCONFIG) { IpMode = ConfigNvData->IpMode; } else { IpMode = ConfigData->AutoConfigureMode; } Status = IScsiAsciiStrToIp (Field->Str, IpMode, &Ip); CopyMem (&ConfigNvData->TargetIp, &Ip, sizeof (EFI_IP_ADDRESS)); if (EFI_ERROR (Status)) { goto ON_EXIT; } // // Check the protocol type. // Field = &Fields[RP_FIELD_IDX_PROTOCOL]; if ((Field->Str != NULL) && ((*(Field->Str) - '0') != EFI_IP_PROTO_TCP)) { Status = EFI_INVALID_PARAMETER; goto ON_EXIT; } // // Get the port of the iSCSI target. // Field = &Fields[RP_FIELD_IDX_PORT]; if (Field->Str != NULL) { ConfigNvData->TargetPort = (UINT16) AsciiStrDecimalToUintn (Field->Str); } else { ConfigNvData->TargetPort = ISCSI_WELL_KNOWN_PORT; } // // Get the LUN. // Field = &Fields[RP_FIELD_IDX_LUN]; if (Field->Str != NULL) { Status = IScsiAsciiStrToLun (Field->Str, ConfigNvData->BootLun); if (EFI_ERROR (Status)) { goto ON_EXIT; } } else { ZeroMem (ConfigNvData->BootLun, sizeof (ConfigNvData->BootLun)); } // // Get the target iSCSI Name. // Field = &Fields[RP_FIELD_IDX_TARGETNAME]; if (AsciiStrLen (Field->Str) > ISCSI_NAME_MAX_SIZE - 1) { Status = EFI_INVALID_PARAMETER; goto ON_EXIT; } // // Validate the iSCSI name. // Status = IScsiNormalizeName (Field->Str, AsciiStrLen (Field->Str)); if (EFI_ERROR (Status)) { goto ON_EXIT; } AsciiStrCpyS (ConfigNvData->TargetName, ISCSI_NAME_MAX_SIZE, Field->Str); ON_EXIT: FreePool (TmpStr); return Status; }
/** Used to allocate and build a device path node for a SCSI device on a SCSI channel. @param[in] This A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance. @param[in] Target The Target is an array of size TARGET_MAX_BYTES and it specifies the Target ID of the SCSI device for which a device path node is to be allocated and built. Transport drivers may chose to utilize a subset of this size to suit the representation of targets. For example, a Fibre Channel driver may use only 8 bytes (WWN) in the array to represent a FC target. @param[in] Lun The LUN of the SCSI device for which a device path node is to be allocated and built. @param[in, out] DevicePath A pointer to a single device path node that describes the SCSI device specified by Target and Lun. This function is responsible for allocating the buffer DevicePath with the boot service AllocatePool(). It is the caller's responsibility to free DevicePath when the caller is finished with DevicePath. @retval EFI_SUCCESS The device path node that describes the SCSI device specified by Target and Lun was allocated and returned in DevicePath. @retval EFI_INVALID_PARAMETER DevicePath is NULL. @retval EFI_NOT_FOUND The SCSI devices specified by Target and Lun does not exist on the SCSI channel. @retval EFI_OUT_OF_RESOURCES There are not enough resources to allocate DevicePath. **/ EFI_STATUS EFIAPI IScsiExtScsiPassThruBuildDevicePath ( IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This, IN UINT8 *Target, IN UINT64 Lun, IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath ) { ISCSI_DRIVER_DATA *Private; ISCSI_SESSION *Session; ISCSI_SESSION_CONFIG_NVDATA *ConfigNvData; ISCSI_CHAP_AUTH_CONFIG_NVDATA *AuthConfig; EFI_DEV_PATH *Node; UINTN DevPathNodeLen; if (DevicePath == NULL) { return EFI_INVALID_PARAMETER; } if (Target[0] != 0) { return EFI_NOT_FOUND; } Private = ISCSI_DRIVER_DATA_FROM_EXT_SCSI_PASS_THRU (This); Session = &Private->Session; ConfigNvData = &Session->ConfigData.NvData; AuthConfig = &Session->AuthData.AuthConfig; if (CompareMem (&Lun, ConfigNvData->BootLun, sizeof (UINT64)) != 0) { return EFI_NOT_FOUND; } DevPathNodeLen = sizeof (ISCSI_DEVICE_PATH) + AsciiStrLen (ConfigNvData->TargetName) + 1; Node = AllocatePool (DevPathNodeLen); if (Node == NULL) { return EFI_OUT_OF_RESOURCES; } Node->DevPath.Type = MESSAGING_DEVICE_PATH; Node->DevPath.SubType = MSG_ISCSI_DP; SetDevicePathNodeLength (&Node->DevPath, (UINT16)DevPathNodeLen); // // 0 for TCP, others are reserved. // Node->Iscsi.NetworkProtocol = 0; Node->Iscsi.LoginOption = 0; switch (AuthConfig->CHAPType) { case ISCSI_CHAP_NONE: Node->Iscsi.LoginOption |= 0x0800; break; case ISCSI_CHAP_UNI: Node->Iscsi.LoginOption |= 0x1000; break; default: break; } CopyMem (&Node->Iscsi.Lun, ConfigNvData->BootLun, sizeof (UINT64)); Node->Iscsi.TargetPortalGroupTag = Session->TargetPortalGroupTag; AsciiStrCpyS ((CHAR8 *) Node + sizeof (ISCSI_DEVICE_PATH), AsciiStrLen (ConfigNvData->TargetName) + 1, ConfigNvData->TargetName); *DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) Node; return EFI_SUCCESS; }
/** Update the string associated with an existing SMBIOS record. @param This The EFI_SMBIOS_PROTOCOL instance. @param SmbiosHandle SMBIOS Handle of structure that will have its string updated. @param StringNumber The non-zero string number of the string to update @param String Update the StringNumber string with String. @retval EFI_SUCCESS SmbiosHandle had its StringNumber String updated. @retval EFI_INVALID_PARAMETER SmbiosHandle does not exist. @retval EFI_UNSUPPORTED String was not added because it is longer than the SMBIOS Table supports. @retval EFI_NOT_FOUND The StringNumber.is not valid for this SMBIOS record. **/ EFI_STATUS EFIAPI SmbiosUpdateString ( IN CONST EFI_SMBIOS_PROTOCOL *This, IN EFI_SMBIOS_HANDLE *SmbiosHandle, IN UINTN *StringNumber, IN CHAR8 *String ) { UINTN InputStrLen; UINTN TargetStrLen; UINTN StrIndex; UINTN TargetStrOffset; UINTN NewEntrySize; CHAR8 *StrStart; VOID *Raw; LIST_ENTRY *Link; LIST_ENTRY *Head; EFI_STATUS Status; SMBIOS_INSTANCE *Private; EFI_SMBIOS_ENTRY *SmbiosEntry; EFI_SMBIOS_ENTRY *ResizedSmbiosEntry; EFI_SMBIOS_HANDLE MaxSmbiosHandle; EFI_SMBIOS_TABLE_HEADER *Record; EFI_SMBIOS_RECORD_HEADER *InternalRecord; // // Check args validity // GetMaxSmbiosHandle(This, &MaxSmbiosHandle); if (*SmbiosHandle > MaxSmbiosHandle) { return EFI_INVALID_PARAMETER; } if (String == NULL) { return EFI_ABORTED; } if (*StringNumber == 0) { return EFI_NOT_FOUND; } InputStrLen = AsciiStrLen(String); if (This->MajorVersion < 2 || (This->MajorVersion == 2 && This->MinorVersion < 7)) { if (InputStrLen > SMBIOS_STRING_MAX_LENGTH) { return EFI_UNSUPPORTED; } } else if (This->MajorVersion < 3) { // // Reference SMBIOS 2.7, chapter 6.1.3, it will have no limit on the length of each individual text string. // However, the length of the entire structure table (including all strings) must be reported // in the Structure Table Length field of the SMBIOS Structure Table Entry Point, // which is a WORD field limited to 65,535 bytes. // if (InputStrLen > SMBIOS_TABLE_MAX_LENGTH) { return EFI_UNSUPPORTED; } } else { if (InputStrLen > SMBIOS_3_0_TABLE_MAX_LENGTH) { // // SMBIOS 3.0 defines the Structure table maximum size as DWORD field limited to 0xFFFFFFFF bytes. // The input string length should not exceed 0xFFFFFFFF bytes. // return EFI_UNSUPPORTED; } } Private = SMBIOS_INSTANCE_FROM_THIS (This); // // Enter into critical section // Status = EfiAcquireLockOrFail (&Private->DataLock); if (EFI_ERROR (Status)) { return Status; } Head = &Private->DataListHead; for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) { SmbiosEntry = SMBIOS_ENTRY_FROM_LINK(Link); Record = (EFI_SMBIOS_TABLE_HEADER*)(SmbiosEntry->RecordHeader + 1); if (Record->Handle == *SmbiosHandle) { // // Find out the specified SMBIOS record // if (*StringNumber > SmbiosEntry->RecordHeader->NumberOfStrings) { EfiReleaseLock (&Private->DataLock); return EFI_NOT_FOUND; } // // Point to unformed string section // StrStart = (CHAR8 *) Record + Record->Length; for (StrIndex = 1, TargetStrOffset = 0; StrIndex < *StringNumber; StrStart++, TargetStrOffset++) { // // A string ends in 00h // if (*StrStart == 0) { StrIndex++; } // // String section ends in double-null (0000h) // if (*StrStart == 0 && *(StrStart + 1) == 0) { EfiReleaseLock (&Private->DataLock); return EFI_NOT_FOUND; } } if (*StrStart == 0) { StrStart++; TargetStrOffset++; } // // Now we get the string target // TargetStrLen = AsciiStrLen(StrStart); if (InputStrLen == TargetStrLen) { AsciiStrCpyS(StrStart, TargetStrLen + 1, String); // // Some UEFI drivers (such as network) need some information in SMBIOS table. // Here we create SMBIOS table and publish it in // configuration table, so other UEFI drivers can get SMBIOS table from // configuration table without depending on PI SMBIOS protocol. // SmbiosTableConstruction (SmbiosEntry->Smbios32BitTable, SmbiosEntry->Smbios64BitTable); EfiReleaseLock (&Private->DataLock); return EFI_SUCCESS; } SmbiosEntry->Smbios32BitTable = FALSE; SmbiosEntry->Smbios64BitTable = FALSE; if ((This->MajorVersion < 0x3) || ((This->MajorVersion >= 0x3) && ((PcdGet32 (PcdSmbiosEntryPointProvideMethod) & BIT0) == BIT0))) { // // 32-bit table is produced, check the valid length. // if ((EntryPointStructure != NULL) && (EntryPointStructure->TableLength + InputStrLen - TargetStrLen > SMBIOS_TABLE_MAX_LENGTH)) { // // The length of the entire structure table (including all strings) must be reported // in the Structure Table Length field of the SMBIOS Structure Table Entry Point, // which is a WORD field limited to 65,535 bytes. // DEBUG ((EFI_D_INFO, "SmbiosUpdateString: Total length exceeds max 32-bit table length\n")); } else { DEBUG ((EFI_D_INFO, "SmbiosUpdateString: New smbios record add to 32-bit table\n")); SmbiosEntry->Smbios32BitTable = TRUE; } } if ((This->MajorVersion >= 0x3) && ((PcdGet32 (PcdSmbiosEntryPointProvideMethod) & BIT1) == BIT1)) { // // 64-bit table is produced, check the valid length. // if ((Smbios30EntryPointStructure != NULL) && (Smbios30EntryPointStructure->TableMaximumSize + InputStrLen - TargetStrLen > SMBIOS_3_0_TABLE_MAX_LENGTH)) { DEBUG ((EFI_D_INFO, "SmbiosUpdateString: Total length exceeds max 64-bit table length\n")); } else { DEBUG ((EFI_D_INFO, "SmbiosUpdateString: New smbios record add to 64-bit table\n")); SmbiosEntry->Smbios64BitTable = TRUE; } } if ((!SmbiosEntry->Smbios32BitTable) && (!SmbiosEntry->Smbios64BitTable)) { EfiReleaseLock (&Private->DataLock); return EFI_UNSUPPORTED; } // // Original string buffer size is not exactly match input string length. // Re-allocate buffer is needed. // NewEntrySize = SmbiosEntry->RecordSize + InputStrLen - TargetStrLen; ResizedSmbiosEntry = AllocateZeroPool (NewEntrySize); if (ResizedSmbiosEntry == NULL) { EfiReleaseLock (&Private->DataLock); return EFI_OUT_OF_RESOURCES; } InternalRecord = (EFI_SMBIOS_RECORD_HEADER *) (ResizedSmbiosEntry + 1); Raw = (VOID *) (InternalRecord + 1); // // Build internal record Header // InternalRecord->Version = EFI_SMBIOS_RECORD_HEADER_VERSION; InternalRecord->HeaderSize = (UINT16) sizeof (EFI_SMBIOS_RECORD_HEADER); InternalRecord->RecordSize = SmbiosEntry->RecordHeader->RecordSize + InputStrLen - TargetStrLen; InternalRecord->ProducerHandle = SmbiosEntry->RecordHeader->ProducerHandle; InternalRecord->NumberOfStrings = SmbiosEntry->RecordHeader->NumberOfStrings; // // Copy SMBIOS structure and optional strings. // CopyMem (Raw, SmbiosEntry->RecordHeader + 1, Record->Length + TargetStrOffset); CopyMem ((VOID*)((UINTN)Raw + Record->Length + TargetStrOffset), String, InputStrLen + 1); CopyMem ((CHAR8*)((UINTN)Raw + Record->Length + TargetStrOffset + InputStrLen + 1), (CHAR8*)Record + Record->Length + TargetStrOffset + TargetStrLen + 1, SmbiosEntry->RecordHeader->RecordSize - sizeof (EFI_SMBIOS_RECORD_HEADER) - Record->Length - TargetStrOffset - TargetStrLen - 1); // // Insert new record // ResizedSmbiosEntry->Signature = EFI_SMBIOS_ENTRY_SIGNATURE; ResizedSmbiosEntry->RecordHeader = InternalRecord; ResizedSmbiosEntry->RecordSize = NewEntrySize; ResizedSmbiosEntry->Smbios32BitTable = SmbiosEntry->Smbios32BitTable; ResizedSmbiosEntry->Smbios64BitTable = SmbiosEntry->Smbios64BitTable; InsertTailList (Link->ForwardLink, &ResizedSmbiosEntry->Link); // // Remove old record // RemoveEntryList(Link); FreePool(SmbiosEntry); // // Some UEFI drivers (such as network) need some information in SMBIOS table. // Here we create SMBIOS table and publish it in // configuration table, so other UEFI drivers can get SMBIOS table from // configuration table without depending on PI SMBIOS protocol. // SmbiosTableConstruction (ResizedSmbiosEntry->Smbios32BitTable, ResizedSmbiosEntry->Smbios64BitTable); EfiReleaseLock (&Private->DataLock); return EFI_SUCCESS; } } EfiReleaseLock (&Private->DataLock); return EFI_INVALID_PARAMETER; }
/** Prints a debug message to the debug output device if the specified error level is enabled. If any bit in ErrorLevel is also set in DebugPrintErrorLevelLib function GetDebugPrintErrorLevel (), then print the message specified by Format and the associated variable argument list to the debug output device. If Format is NULL, then ASSERT(). If the length of the message string specificed by Format is larger than the maximum allowable record length, then directly return and not print it. @param ErrorLevel The error level of the debug message. @param Format Format string for the debug message to print. @param ... Variable argument list whose contents are accessed based on the format string specified by Format. **/ VOID EFIAPI DebugPrint ( IN UINTN ErrorLevel, IN CONST CHAR8 *Format, ... ) { UINT64 Buffer[(EFI_STATUS_CODE_DATA_MAX_SIZE / sizeof (UINT64)) + 1]; EFI_DEBUG_INFO *DebugInfo; UINTN TotalSize; UINTN DestBufferSize; VA_LIST VaListMarker; BASE_LIST BaseListMarker; CHAR8 *FormatString; BOOLEAN Long; // // If Format is NULL, then ASSERT(). // ASSERT (Format != NULL); // // Check driver Debug Level value and global debug level // if ((ErrorLevel & GetDebugPrintErrorLevel ()) == 0) { return; } // // Compute the total size of the record. // Note that the passing-in format string and variable parameters will be constructed to // the following layout: // // Buffer->|------------------------| // | Padding | 4 bytes // DebugInfo->|------------------------| // | EFI_DEBUG_INFO | sizeof(EFI_DEBUG_INFO) // BaseListMarker->|------------------------| // | ... | // | variable arguments | 12 * sizeof (UINT64) // | ... | // |------------------------| // | Format String | // |------------------------|<- (UINT8 *)Buffer + sizeof(Buffer) // TotalSize = 4 + sizeof (EFI_DEBUG_INFO) + 12 * sizeof (UINT64) + AsciiStrSize (Format); // // If the TotalSize is larger than the maximum record size, then return // if (TotalSize > sizeof (Buffer)) { return; } // // Fill in EFI_DEBUG_INFO // // Here we skip the first 4 bytes of Buffer, because we must ensure BaseListMarker is // 64-bit aligned, otherwise retrieving 64-bit parameter from BaseListMarker will cause // exception on IPF. Buffer starts at 64-bit aligned address, so skipping 4 types (sizeof(EFI_DEBUG_INFO)) // just makes address of BaseListMarker, which follows DebugInfo, 64-bit aligned. // DebugInfo = (EFI_DEBUG_INFO *)(Buffer) + 1; DebugInfo->ErrorLevel = (UINT32)ErrorLevel; BaseListMarker = (BASE_LIST)(DebugInfo + 1); FormatString = (CHAR8 *)((UINT64 *)(DebugInfo + 1) + 12); // // Copy the Format string into the record // // According to the content structure of Buffer shown above, the size of // the FormatString buffer is the size of Buffer minus the Padding // (4 bytes), minus the size of EFI_DEBUG_INFO, minus the size of // variable arguments (12 * sizeof (UINT64)). // DestBufferSize = sizeof (Buffer) - 4 - sizeof (EFI_DEBUG_INFO) - 12 * sizeof (UINT64); AsciiStrCpyS (FormatString, DestBufferSize / sizeof (CHAR8), Format); // // The first 12 * sizeof (UINT64) bytes following EFI_DEBUG_INFO are for variable arguments // of format in DEBUG string, which is followed by the DEBUG format string. // Here we will process the variable arguments and pack them in this area. // VA_START (VaListMarker, Format); for (; *Format != '\0'; Format++) { // // Only format with prefix % is processed. // if (*Format != '%') { continue; } Long = FALSE; // // Parse Flags and Width // for (Format++; TRUE; Format++) { if (*Format == '.' || *Format == '-' || *Format == '+' || *Format == ' ') { // // These characters in format field are omitted. // continue; } if (*Format >= '0' && *Format <= '9') { // // These characters in format field are omitted. // continue; } if (*Format == 'L' || *Format == 'l') { // // 'L" or "l" in format field means the number being printed is a UINT64 // Long = TRUE; continue; } if (*Format == '*') { // // '*' in format field means the precision of the field is specified by // a UINTN argument in the argument list. // BASE_ARG (BaseListMarker, UINTN) = VA_ARG (VaListMarker, UINTN); continue; } if (*Format == '\0') { // // Make no output if Format string terminates unexpectedly when // looking up for flag, width, precision and type. // Format--; } // // When valid argument type detected or format string terminates unexpectedly, // the inner loop is done. // break; } // // Pack variable arguments into the storage area following EFI_DEBUG_INFO. // if ((*Format == 'p') && (sizeof (VOID *) > 4)) { Long = TRUE; } if (*Format == 'p' || *Format == 'X' || *Format == 'x' || *Format == 'd' || *Format == 'u') { if (Long) { BASE_ARG (BaseListMarker, INT64) = VA_ARG (VaListMarker, INT64); } else { BASE_ARG (BaseListMarker, int) = VA_ARG (VaListMarker, int); } } else if (*Format == 's' || *Format == 'S' || *Format == 'a' || *Format == 'g' || *Format == 't') { BASE_ARG (BaseListMarker, VOID *) = VA_ARG (VaListMarker, VOID *); } else if (*Format == 'c') {
/** Parse Config data file to get the updated data array. @param DataBuffer Config raw file buffer. @param BufferSize Size of raw buffer. @param NumOfUpdates Pointer to the number of update data. @param UpdateArray Pointer to the config of update data. @retval EFI_NOT_FOUND No config data is found. @retval EFI_OUT_OF_RESOURCES No enough memory is allocated. @retval EFI_SUCCESS Parse the config file successfully. **/ EFI_STATUS ParseUpdateDataFile ( IN UINT8 *DataBuffer, IN UINTN BufferSize, IN OUT UINTN *NumOfUpdates, IN OUT UPDATE_CONFIG_DATA **UpdateArray ) { EFI_STATUS Status; CHAR8 *Value; CHAR8 *SectionName; CHAR8 Entry[MAX_LINE_LENGTH]; SECTION_ITEM *SectionHead; COMMENT_LINE *CommentHead; UINTN Num; UINTN Index; EFI_GUID FileGuid; SectionHead = NULL; CommentHead = NULL; // // First process the data buffer and get all sections and entries // Status = PreProcessDataFile ( DataBuffer, BufferSize, &SectionHead, &CommentHead ); if (EFI_ERROR (Status)) { FreeAllList (SectionHead, CommentHead); return Status; } // // Now get NumOfUpdate // Value = NULL; Status = UpdateGetProfileString ( SectionHead, (UINT8 *) "Head", (UINT8 *) "NumOfUpdate", (UINT8 **) &Value ); if (Value == NULL) { FreeAllList (SectionHead, CommentHead); return EFI_NOT_FOUND; } Num = UpdateAtoi((UINT8 *) Value); if (Num <= 0) { FreeAllList (SectionHead, CommentHead); return EFI_NOT_FOUND; } *NumOfUpdates = Num; *UpdateArray = AllocatePool ((sizeof (UPDATE_CONFIG_DATA) * Num)); if (*UpdateArray == NULL) { FreeAllList (SectionHead, CommentHead); return EFI_OUT_OF_RESOURCES; } for ( Index = 0 ; Index < *NumOfUpdates ; Index++) { // // Get the section name of each update // AsciiStrCpyS (Entry, MAX_LINE_LENGTH, "Update"); UpdateStrCatNumber ((UINT8 *) Entry, Index); Value = NULL; Status = UpdateGetProfileString ( SectionHead, (UINT8 *) "Head", (UINT8 *) Entry, (UINT8 **) &Value ); if (Value == NULL) { FreeAllList (SectionHead, CommentHead); return EFI_NOT_FOUND; } // // The section name of this update has been found. // Now looks for all the config data of this update // SectionName = Value; // // UpdateType // Value = NULL; Status = UpdateGetProfileString ( SectionHead, (UINT8 *) SectionName, (UINT8 *) "UpdateType", (UINT8 **) &Value ); if (Value == NULL) { FreeAllList (SectionHead, CommentHead); return EFI_NOT_FOUND; } Num = UpdateAtoi((UINT8 *) Value); if (( Num >= (UINTN) UpdateOperationMaximum)) { FreeAllList (SectionHead, CommentHead); return Status; } (*UpdateArray)[Index].Index = Index; (*UpdateArray)[Index].UpdateType = (UPDATE_OPERATION_TYPE) Num; // // FvBaseAddress // Value = NULL; Status = UpdateGetProfileString ( SectionHead, (UINT8 *) SectionName, (UINT8 *) "FvBaseAddress", (UINT8 **) &Value ); if (Value == NULL) { FreeAllList (SectionHead, CommentHead); return EFI_NOT_FOUND; } Num = AsciiStrHexToUintn ((CONST CHAR8 *) Value); (*UpdateArray)[Index].BaseAddress = (EFI_PHYSICAL_ADDRESS) Num; // // FileBuid // Value = NULL; Status = UpdateGetProfileString ( SectionHead, (UINT8 *) SectionName, (UINT8 *) "FileGuid", (UINT8 **) &Value ); if (Value == NULL) { FreeAllList (SectionHead, CommentHead); return EFI_NOT_FOUND; } Status = UpdateStringToGuid ((UINT8 *) Value, &FileGuid); if (EFI_ERROR (Status)) { FreeAllList (SectionHead, CommentHead); return Status; } CopyMem (&((*UpdateArray)[Index].FileGuid), &FileGuid, sizeof(EFI_GUID)); // // FaultTolerant // Default value is FALSE // Value = NULL; (*UpdateArray)[Index].FaultTolerant = FALSE; Status = UpdateGetProfileString ( SectionHead, (UINT8 *) SectionName, (UINT8 *) "FaultTolerant", (UINT8 **) &Value ); if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) { FreeAllList (SectionHead, CommentHead); return Status; } else if (Value != NULL) { if (AsciiStriCmp ((CONST CHAR8 *) Value, (CONST CHAR8 *) "TRUE") == 0) { (*UpdateArray)[Index].FaultTolerant = TRUE; } else if (AsciiStriCmp ((CONST CHAR8 *) Value, (CONST CHAR8 *) "FALSE") == 0) { (*UpdateArray)[Index].FaultTolerant = FALSE; } } if ((*UpdateArray)[Index].UpdateType == UpdateFvRange) { // // Length // Value = NULL; Status = UpdateGetProfileString ( SectionHead, (UINT8 *) SectionName, (UINT8 *) "Length", (UINT8 **) &Value ); if (Value == NULL) { FreeAllList (SectionHead, CommentHead); return EFI_NOT_FOUND; } Num = AsciiStrHexToUintn ((CONST CHAR8 *) Value); (*UpdateArray)[Index].Length = (UINTN) Num; } } // // Now all configuration data got. Free those temporary buffers // FreeAllList (SectionHead, CommentHead); return EFI_SUCCESS; }
/** 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) { AsciiStrCpyS (GaugeEntryExArray[Index].Token, DXE_PERFORMANCE_STRING_SIZE, Token); } if (Module != NULL) { AsciiStrCpyS (GaugeEntryExArray[Index].Module, DXE_PERFORMANCE_STRING_SIZE, Module); } GaugeEntryExArray[Index].EndTimeStamp = 0; GaugeEntryExArray[Index].Identifier = Identifier; if (TimeStamp == 0) { TimeStamp = GetPerformanceCounter (); } GaugeEntryExArray[Index].StartTimeStamp = TimeStamp; mGaugeData->NumberOfEntries++; return EFI_SUCCESS; }
EFI_STATUS OutputData ( IN UINT8 *Address, IN UINTN Length, IN UINTN Width, IN UINTN Offset ) { UINT8 *EndAddress; UINTN Line; CHAR8 TextLine[0x11]; UINTN CurrentRow = 0; UINTN Bytes; UINTN Spaces = 0; CHAR8 Blanks[80]; AsciiStrCpyS (Blanks, sizeof Blanks, mBlanks); for (EndAddress = Address + Length; Address < EndAddress; Offset += Line) { AsciiPrint ("%08x: ", Offset); for (Line = 0; (Line < 0x10) && (Address < EndAddress);) { Bytes = EndAddress - Address; switch (Width) { case 4: if (Bytes >= 4) { AsciiPrint ("%08x ", *((UINT32 *)Address)); TextLine[Line++] = ConvertToTextLine(*Address++); TextLine[Line++] = ConvertToTextLine(*Address++); TextLine[Line++] = ConvertToTextLine(*Address++); TextLine[Line++] = ConvertToTextLine(*Address++); } else { AsciiPrint ("%08x ", GetBytes(Address, Bytes)); Address += Bytes; Line += Bytes; } break; case 2: if (Bytes >= 2) { AsciiPrint ("%04x ", *((UINT16 *)Address)); TextLine[Line++] = ConvertToTextLine(*Address++); TextLine[Line++] = ConvertToTextLine(*Address++); } else { AsciiPrint ("%04x ", GetBytes(Address, Bytes)); Address += Bytes; Line += Bytes; } break; case 1: AsciiPrint ("%02x ", *((UINT8 *)Address)); TextLine[Line++] = ConvertToTextLine(*Address++); break; default: AsciiPrint ("Width must be 1, 2, or 4!\n"); return EFI_INVALID_PARAMETER; } } // Pad spaces if (Line < 0x10) { switch (Width) { case 4: Spaces = 9 * ((0x10 - Line)/4); break; case 2: Spaces = 5 * ((0x10 - Line)/2); break; case 1: Spaces = 3 * (0x10 - Line); break; } Blanks[Spaces] = '\0'; AsciiPrint(Blanks); Blanks[Spaces] = ' '; } TextLine[Line] = 0; AsciiPrint ("|%a|\n", TextLine); if (EblAnyKeyToContinueQtoQuit (&CurrentRow, FALSE)) { return EFI_END_OF_FILE; } } if (Length % Width != 0) { AsciiPrint ("%08x\n", Offset); } return EFI_SUCCESS; }