/** Nonblocking I/O callback funtion when the event is signaled. @param[in] Event The Event this notify function registered to. @param[in] Context Pointer to the context data registered to the Event. **/ VOID EFIAPI AsyncIoCallback ( IN EFI_EVENT Event, IN VOID *Context ) { SD_REQUEST *Request; gBS->CloseEvent (Event); Request = (SD_REQUEST *) Context; DEBUG_CODE_BEGIN (); DEBUG ((EFI_D_INFO, "Sd Async Request: CmdIndex[%d] Arg[%08x] %r\n", Request->SdMmcCmdBlk.CommandIndex, Request->SdMmcCmdBlk.CommandArgument, Request->Packet.TransactionStatus)); DEBUG_CODE_END (); if (EFI_ERROR (Request->Packet.TransactionStatus)) { Request->Token->TransactionStatus = Request->Packet.TransactionStatus; } RemoveEntryList (&Request->Link); if (Request->IsEnd) { gBS->SignalEvent (Request->Token->Event); } FreePool (Request); }
/** Produces an EBC VM test protocol that can be used for regression tests. @param IHandle Handle on which to install the protocol. @retval EFI_OUT_OF_RESOURCES Memory allocation failed. @retval EFI_SUCCESS The function completed successfully. **/ EFI_STATUS InitEbcVmTestProtocol ( IN EFI_HANDLE *IHandle ) { EFI_HANDLE Handle; EFI_STATUS Status; EFI_EBC_VM_TEST_PROTOCOL *EbcVmTestProtocol; // // Allocate memory for the protocol, then fill in the fields // EbcVmTestProtocol = AllocatePool (sizeof (EFI_EBC_VM_TEST_PROTOCOL)); if (EbcVmTestProtocol == NULL) { return EFI_OUT_OF_RESOURCES; } EbcVmTestProtocol->Execute = (EBC_VM_TEST_EXECUTE) EbcExecuteInstructions; DEBUG_CODE_BEGIN (); EbcVmTestProtocol->Assemble = (EBC_VM_TEST_ASM) EbcVmTestUnsupported; EbcVmTestProtocol->Disassemble = (EBC_VM_TEST_DASM) EbcVmTestUnsupported; DEBUG_CODE_END (); // // Publish the protocol // Handle = NULL; Status = gBS->InstallProtocolInterface (&Handle, &gEfiEbcVmTestProtocolGuid, EFI_NATIVE_INTERFACE, EbcVmTestProtocol); if (EFI_ERROR (Status)) { FreePool (EbcVmTestProtocol); } return Status; }
/** Notify function for event group EFI_EVENT_GROUP_READY_TO_BOOT. This is used to install the Efi System Resource Table. @param[in] Event The Event that is being processed. @param[in] Context The Event Context. **/ VOID EFIAPI EsrtReadyToBootEventNotify ( IN EFI_EVENT Event, IN VOID *Context ) { EFI_STATUS Status; EFI_SYSTEM_RESOURCE_TABLE *Table; Table = CreateFmpBasedEsrt (); if (Table != NULL) { // // Print table on debug builds // DEBUG_CODE_BEGIN (); PrintTable (Table); DEBUG_CODE_END (); Status = InstallEfiSystemResourceTableInUefiConfigurationTable (Table); if (EFI_ERROR (Status)) { FreePool (Table); } } else { DEBUG ((DEBUG_ERROR, "EsrtFmpDxe: Can't install ESRT table because it is NULL. \n")); } // // Close the event to prevent it be signalled again. // gBS->CloseEvent (Event); }
/** Gets the pointer to the HOB List. @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation. @param HobList Pointer to the HOB List. @retval EFI_SUCCESS Get the pointer of HOB List @retval EFI_NOT_AVAILABLE_YET the HOB List is not yet published @retval EFI_INVALID_PARAMETER HobList is NULL (in debug mode) **/ EFI_STATUS EFIAPI PeiGetHobList ( IN CONST EFI_PEI_SERVICES **PeiServices, IN OUT VOID **HobList ) { PEI_CORE_INSTANCE *PrivateData; // // Only check this parameter in debug mode // DEBUG_CODE_BEGIN (); if (HobList == NULL) { return EFI_INVALID_PARAMETER; } DEBUG_CODE_END (); PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS(PeiServices); *HobList = PrivateData->HobList.Raw; return EFI_SUCCESS; }
/** Returns the handle of the ACPI object representing the specified ACPI path @param[in] HandleIn Points to the handle of the object representing the starting point for the path search. @param[in] AcpiPath Points to the ACPI path, which conforms to the ACPI encoded path format. @param[out] HandleOut On return, points to the ACPI object which represents AcpiPath, relative to HandleIn. @retval EFI_SUCCESS Success @retval EFI_INVALID_PARAMETER HandleIn is NULL or does not refer to a valid ACPI object. **/ EFI_STATUS EFIAPI FindPath ( IN EFI_ACPI_HANDLE HandleIn, IN VOID *AcpiPath, OUT EFI_ACPI_HANDLE *HandleOut ) { EFI_AML_HANDLE *AmlHandle; EFI_STATUS Status; UINT8 *AmlPath; // // Check for invalid input parameters // if (HandleIn == NULL) { return EFI_INVALID_PARAMETER; } AmlHandle = (EFI_AML_HANDLE *)HandleIn; // // Convert ASL path to AML path // AmlPath = AmlNameFromAslName (AcpiPath); if (AmlPath == NULL) { return EFI_INVALID_PARAMETER; } DEBUG_CODE_BEGIN (); DEBUG ((EFI_D_ERROR, "AcpiSdt: FindPath - ")); AmlPrintNameString (AmlPath); DEBUG ((EFI_D_ERROR, "\n")); DEBUG_CODE_END (); if (AmlHandle->Signature == EFI_AML_ROOT_HANDLE_SIGNATURE) { // // Root Handle // Status = SdtFindPathFromRoot (HandleIn, AmlPath, HandleOut); } else if (AmlHandle->Signature == EFI_AML_HANDLE_SIGNATURE) { // // Non-Root handle // Status = SdtFindPathFromNonRoot (HandleIn, AmlPath, HandleOut); } else { Status = EFI_INVALID_PARAMETER; } FreePool (AmlPath); return Status; }
/** Checks the CRC32 value in the table header. @param MaxSize Max Size limit @param Size The size of the table @param Hdr Table to check @return TRUE CRC Valid @return FALSE CRC Invalid **/ BOOLEAN PartitionCheckCrcAltSize ( IN UINTN MaxSize, IN UINTN Size, IN OUT EFI_TABLE_HEADER *Hdr ) { UINT32 Crc; UINT32 OrgCrc; EFI_STATUS Status; Crc = 0; if (Size == 0) { // // If header size is 0 CRC will pass so return FALSE here // return FALSE; } if ((MaxSize != 0) && (Size > MaxSize)) { DEBUG ((EFI_D_ERROR, "CheckCrc32: Size > MaxSize\n")); return FALSE; } // // clear old crc from header // OrgCrc = Hdr->CRC32; Hdr->CRC32 = 0; Status = gBS->CalculateCrc32 ((UINT8 *) Hdr, Size, &Crc); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "CheckCrc32: Crc calculation failed\n")); return FALSE; } // // set results // Hdr->CRC32 = Crc; // // return status // DEBUG_CODE_BEGIN (); if (OrgCrc != Crc) { DEBUG ((EFI_D_ERROR, "CheckCrc32: Crc check failed\n")); } DEBUG_CODE_END (); return (BOOLEAN) (OrgCrc == Crc); }
/** C routine that is called for all registered exceptions. This is the main exception dispatcher. Must be public because it's referenced from AsmFuncs.s. @param ExceptionType Specifies which processor exception. @param Context System Context. **/ VOID CommonHandler ( IN EFI_EXCEPTION_TYPE ExceptionType, IN EFI_SYSTEM_CONTEXT Context ) { DEBUG_CODE_BEGIN (); if (mInHandler) { DEBUG ((EFI_D_INFO, "ERROR: Re-entered debugger!\n" " ExceptionType == %X\n" " Context == %X\n" " Context.SystemContextIpf->CrIip == %LX\n" " Context.SystemContextIpf->CrIpsr == %LX\n" " mInHandler == %X\n", (INT32)ExceptionType, Context, Context.SystemContextIpf->CrIip, Context.SystemContextIpf->CrIpsr, mInHandler)); } DEBUG_CODE_END (); ASSERT (!mInHandler); mInHandler = TRUE; if (IvtEntryTable[ExceptionType].RegisteredCallback != NULL) { if (ExceptionType != EXCEPT_IPF_EXTERNAL_INTERRUPT) { IvtEntryTable[ExceptionType].RegisteredCallback (ExceptionType, Context.SystemContextIpf); } else { IvtEntryTable[ExceptionType].RegisteredCallback (Context.SystemContextIpf); } } else { ASSERT (0); } mInHandler = FALSE; }
EFIAPI OpenIniFile ( IN UINT8 *DataBuffer, IN UINTN BufferSize ) { EFI_STATUS Status; INI_PARSING_LIB_CONTEXT *IniContext; if (DataBuffer == NULL || BufferSize == 0) { return NULL; } IniContext = AllocateZeroPool(sizeof(INI_PARSING_LIB_CONTEXT)); if (IniContext == NULL) { return NULL; } // // First process the data buffer and get all sections and entries // Status = PreProcessDataFile ( DataBuffer, BufferSize, &IniContext->SectionHead, &IniContext->CommentHead ); if (EFI_ERROR(Status)) { FreePool(IniContext); return NULL; } DEBUG_CODE_BEGIN (); DumpIniSection(IniContext); DEBUG_CODE_END (); return IniContext; }
EFI_STATUS DefineDefaultBootEntries ( VOID ) { BDS_LOAD_OPTION* BdsLoadOption; UINTN Size; EFI_STATUS Status; EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL* EfiDevicePathFromTextProtocol; EFI_DEVICE_PATH* BootDevicePath; UINTN CmdLineSize; UINTN CmdLineAsciiSize; CHAR16* DefaultBootArgument; CHAR8* AsciiDefaultBootArgument; // // If Boot Order does not exist then create a default entry // Size = 0; Status = gRT->GetVariable (L"BootOrder", &gEfiGlobalVariableGuid, NULL, &Size, NULL); if (Status == EFI_NOT_FOUND) { if ((PcdGetPtr(PcdDefaultBootDevicePath) == NULL) || (StrLen ((CHAR16*)PcdGetPtr(PcdDefaultBootDevicePath)) == 0)) { return EFI_UNSUPPORTED; } Status = gBS->LocateProtocol (&gEfiDevicePathFromTextProtocolGuid, NULL, (VOID **)&EfiDevicePathFromTextProtocol); if (EFI_ERROR(Status)) { // You must provide an implementation of DevicePathFromTextProtocol in your firmware (eg: DevicePathDxe) DEBUG((EFI_D_ERROR,"Error: Bds requires DevicePathFromTextProtocol\n")); return Status; } BootDevicePath = EfiDevicePathFromTextProtocol->ConvertTextToDevicePath ((CHAR16*)PcdGetPtr(PcdDefaultBootDevicePath)); DEBUG_CODE_BEGIN(); // We convert back to the text representation of the device Path to see if the initial text is correct EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol; CHAR16* DevicePathTxt; Status = gBS->LocateProtocol(&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol); ASSERT_EFI_ERROR(Status); DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText (BootDevicePath, TRUE, TRUE); if (StrCmp ((CHAR16*)PcdGetPtr (PcdDefaultBootDevicePath), DevicePathTxt) != 0) { DEBUG ((EFI_D_ERROR, "Device Path given: '%s' Device Path expected: '%s'\n", (CHAR16*)PcdGetPtr (PcdDefaultBootDevicePath), DevicePathTxt)); ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER); } FreePool (DevicePathTxt); DEBUG_CODE_END(); // Create the entry is the Default values are correct if (BootDevicePath != NULL) { // We do not support NULL pointer ASSERT (PcdGetPtr (PcdDefaultBootArgument) != NULL); // // Logic to handle ASCII or Unicode default parameters // if (*(CHAR8*)PcdGetPtr (PcdDefaultBootArgument) == '\0') { CmdLineSize = 0; CmdLineAsciiSize = 0; DefaultBootArgument = NULL; AsciiDefaultBootArgument = NULL; } else if (IsUnicodeString ((CHAR16*)PcdGetPtr (PcdDefaultBootArgument))) { // The command line is a Unicode string DefaultBootArgument = (CHAR16*)PcdGetPtr (PcdDefaultBootArgument); CmdLineSize = StrSize (DefaultBootArgument); // Initialize ASCII variables CmdLineAsciiSize = CmdLineSize / 2; AsciiDefaultBootArgument = AllocatePool (CmdLineAsciiSize); if (AsciiDefaultBootArgument == NULL) { return EFI_OUT_OF_RESOURCES; } UnicodeStrToAsciiStr ((CHAR16*)PcdGetPtr (PcdDefaultBootArgument), AsciiDefaultBootArgument); } else { // The command line is a ASCII string AsciiDefaultBootArgument = (CHAR8*)PcdGetPtr (PcdDefaultBootArgument); CmdLineAsciiSize = AsciiStrSize (AsciiDefaultBootArgument); // Initialize ASCII variables CmdLineSize = CmdLineAsciiSize * 2; DefaultBootArgument = AllocatePool (CmdLineSize); if (DefaultBootArgument == NULL) { return EFI_OUT_OF_RESOURCES; } AsciiStrToUnicodeStr (AsciiDefaultBootArgument, DefaultBootArgument); } BootOptionCreate (LOAD_OPTION_ACTIVE | LOAD_OPTION_CATEGORY_BOOT, (CHAR16*)PcdGetPtr (PcdDefaultBootDescription), BootDevicePath, (UINT8 *)DefaultBootArgument, // OptionalData CmdLineSize, // OptionalDataSize &BdsLoadOption ); FreePool (BdsLoadOption); if (DefaultBootArgument == (CHAR16*)PcdGetPtr (PcdDefaultBootArgument)) { FreePool (AsciiDefaultBootArgument); } else if (DefaultBootArgument != NULL) { FreePool (DefaultBootArgument); } } else { Status = EFI_UNSUPPORTED; } } return Status; }
/** Create or update a String Token in a String Package. If *Reference == 0, a new String Token is created. @param This A pointer to the EFI_HII_PROTOCOL instance. @param Language Pointer to a NULL-terminated string containing a single ISO 639-2 language identifier, indicating the language to print. A string consisting of all spaces indicates that the string is applicable to all languages. @param Handle The handle of the language pack to which the string is to be added. @param Reference The string token assigned to the string. @param NewString The string to be added. @retval EFI_SUCCESS The string was effectively registered. @retval EFI_INVALID_PARAMETER The Handle was unknown. The string is not created or updated in the the string package. **/ EFI_STATUS EFIAPI HiiNewString ( IN EFI_HII_PROTOCOL *This, IN CHAR16 *Language, IN FRAMEWORK_EFI_HII_HANDLE Handle, IN OUT STRING_REF *Reference, IN CHAR16 *NewString ) { EFI_STATUS Status; HII_THUNK_PRIVATE_DATA *Private; EFI_GUID TagGuid; LIST_ENTRY *Link; HII_THUNK_CONTEXT *ThunkContext; HII_THUNK_CONTEXT *StringPackThunkContext; EFI_STRING_ID StringId; EFI_STRING_ID LastStringId; CHAR8 AsciiLanguage[ISO_639_2_ENTRY_SIZE + 1]; CHAR16 LanguageCopy[ISO_639_2_ENTRY_SIZE + 1]; CHAR8 *Rfc4646AsciiLanguage; LastStringId = (EFI_STRING_ID) 0; StringId = (EFI_STRING_ID) 0; Rfc4646AsciiLanguage = NULL; if (Language != NULL) { ZeroMem (AsciiLanguage, sizeof (AsciiLanguage));; ZeroMem (LanguageCopy, sizeof (LanguageCopy)); CopyMem (LanguageCopy, Language, ISO_639_2_ENTRY_SIZE * sizeof (CHAR16)); UnicodeStrToAsciiStr (LanguageCopy, AsciiLanguage); Rfc4646AsciiLanguage = ConvertLanguagesIso639ToRfc4646 (AsciiLanguage); ASSERT (Rfc4646AsciiLanguage != NULL); } Private = HII_THUNK_PRIVATE_DATA_FROM_THIS(This); StringPackThunkContext = FwHiiHandleToThunkContext (Private, Handle); if (StringPackThunkContext == NULL) { return EFI_INVALID_PARAMETER; } if (StringPackThunkContext->SharingStringPack) { Status = GetTagGuidByFwHiiHandle (Private, Handle, &TagGuid); ASSERT_EFI_ERROR (Status); Link = GetFirstNode (&Private->ThunkContextListHead); while (!IsNull (&Private->ThunkContextListHead, Link)) { ThunkContext = HII_THUNK_CONTEXT_FROM_LINK (Link); if (CompareGuid (&TagGuid, &ThunkContext->TagGuid)) { if (ThunkContext->SharingStringPack) { StringId = *Reference; Status = UpdateString (ThunkContext, Rfc4646AsciiLanguage, NewString, &StringId); if (EFI_ERROR (Status)) { break; } DEBUG_CODE_BEGIN (); if (*Reference == 0) { // // When creating new string token, make sure all created token is the same // for all string packages registered using FW HII interface. // if (LastStringId == (EFI_STRING_ID) 0) { LastStringId = StringId; } else { if (LastStringId != StringId) { ASSERT(FALSE); } } } DEBUG_CODE_END (); } } Link = GetNextNode (&Private->ThunkContextListHead, Link); } } else { StringId = *Reference; Status = UpdateString (StringPackThunkContext, Rfc4646AsciiLanguage, NewString, &StringId); } if (!EFI_ERROR (Status)) { if (*Reference == 0) { *Reference = StringId; } } else { // // Only EFI_INVALID_PARAMETER is defined in HII 0.92 specification. // Status = EFI_INVALID_PARAMETER; } return Status; }
STATIC EFI_STATUS InitializeConsolePipe ( IN EFI_DEVICE_PATH *ConsoleDevicePaths, IN EFI_GUID *Protocol, OUT EFI_HANDLE *Handle, OUT VOID* *Interface ) { EFI_STATUS Status; UINTN Size; UINTN NoHandles; EFI_HANDLE *Buffer; EFI_DEVICE_PATH_PROTOCOL* DevicePath; // Connect all the Device Path Consoles while (ConsoleDevicePaths != NULL) { DevicePath = GetNextDevicePathInstance (&ConsoleDevicePaths, &Size); Status = BdsConnectDevicePath (DevicePath, Handle, NULL); DEBUG_CODE_BEGIN(); if (EFI_ERROR(Status)) { // We convert back to the text representation of the device Path EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol; CHAR16* DevicePathTxt; EFI_STATUS Status; Status = gBS->LocateProtocol(&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol); if (!EFI_ERROR(Status)) { DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText (DevicePath, TRUE, TRUE); DEBUG((EFI_D_ERROR,"Fail to start the console with the Device Path '%s'. (Error '%r')\n", DevicePathTxt, Status)); FreePool (DevicePathTxt); } } DEBUG_CODE_END(); // If the console splitter driver is not supported by the platform then use the first Device Path // instance for the console interface. if (!EFI_ERROR(Status) && (*Interface == NULL)) { Status = gBS->HandleProtocol (*Handle, Protocol, Interface); } } // No Device Path has been defined for this console interface. We take the first protocol implementation if (*Interface == NULL) { Status = gBS->LocateHandleBuffer (ByProtocol, Protocol, NULL, &NoHandles, &Buffer); if (EFI_ERROR (Status)) { BdsConnectAllDrivers(); Status = gBS->LocateHandleBuffer (ByProtocol, Protocol, NULL, &NoHandles, &Buffer); } if (!EFI_ERROR(Status)) { *Handle = Buffer[0]; Status = gBS->HandleProtocol (*Handle, Protocol, Interface); ASSERT_EFI_ERROR(Status); FreePool (Buffer); } } else { Status = EFI_SUCCESS; } return Status; }
/** Sends an NVM Express Command Packet to an NVM Express controller or namespace. This function supports both blocking I/O and non-blocking I/O. The blocking I/O functionality is required, and the non-blocking I/O functionality is optional. @param[in] This A pointer to the EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL instance. @param[in] NamespaceId A 32 bit namespace ID as defined in the NVMe specification to which the NVM Express Command Packet will be sent. A value of 0 denotes the NVM Express controller, a value of all 0xFF's (all bytes are 0xFF) in the namespace ID specifies that the command packet should be sent to all valid namespaces. @param[in,out] Packet A pointer to the NVM Express Command Packet. @param[in] Event If non-blocking I/O is not supported then Event is ignored, and blocking I/O is performed. If Event is NULL, then blocking I/O is performed. If Event is not NULL and non-blocking I/O is supported, then non-blocking I/O is performed, and Event will be signaled when the NVM Express Command Packet completes. @retval EFI_SUCCESS The NVM Express Command Packet was sent by the host. TransferLength bytes were transferred to, or from DataBuffer. @retval EFI_BAD_BUFFER_SIZE The NVM Express Command Packet was not executed. The number of bytes that could be transferred is returned in TransferLength. @retval EFI_NOT_READY The NVM Express Command Packet could not be sent because the controller is not ready. The caller may retry again later. @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the NVM Express Command Packet. @retval EFI_INVALID_PARAMETER NamespaceId or the contents of EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET are invalid. The NVM Express Command Packet was not sent, so no additional status information is available. @retval EFI_UNSUPPORTED The command described by the NVM Express Command Packet is not supported by the NVM Express controller. The NVM Express Command Packet was not sent so no additional status information is available. @retval EFI_TIMEOUT A timeout occurred while waiting for the NVM Express Command Packet to execute. **/ EFI_STATUS EFIAPI NvmExpressPassThru ( IN EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *This, IN UINT32 NamespaceId, IN OUT EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET *Packet, IN EFI_EVENT Event OPTIONAL ) { NVME_CONTROLLER_PRIVATE_DATA *Private; EFI_STATUS Status; EFI_PCI_IO_PROTOCOL *PciIo; NVME_SQ *Sq; NVME_CQ *Cq; UINT16 QueueId; UINT32 Bytes; UINT16 Offset; EFI_EVENT TimerEvent; EFI_PCI_IO_PROTOCOL_OPERATION Flag; EFI_PHYSICAL_ADDRESS PhyAddr; VOID *MapData; VOID *MapMeta; VOID *MapPrpList; UINTN MapLength; UINT64 *Prp; VOID *PrpListHost; UINTN PrpListNo; UINT32 Attributes; UINT32 IoAlign; UINT32 MaxTransLen; UINT32 Data; NVME_PASS_THRU_ASYNC_REQ *AsyncRequest; EFI_TPL OldTpl; // // check the data fields in Packet parameter. // if ((This == NULL) || (Packet == NULL)) { return EFI_INVALID_PARAMETER; } if ((Packet->NvmeCmd == NULL) || (Packet->NvmeCompletion == NULL)) { return EFI_INVALID_PARAMETER; } if (Packet->QueueType != NVME_ADMIN_QUEUE && Packet->QueueType != NVME_IO_QUEUE) { return EFI_INVALID_PARAMETER; } // // 'Attributes' with neither EFI_NVM_EXPRESS_PASS_THRU_ATTRIBUTES_LOGICAL nor // EFI_NVM_EXPRESS_PASS_THRU_ATTRIBUTES_PHYSICAL set is an illegal // configuration. // Attributes = This->Mode->Attributes; if ((Attributes & (EFI_NVM_EXPRESS_PASS_THRU_ATTRIBUTES_PHYSICAL | EFI_NVM_EXPRESS_PASS_THRU_ATTRIBUTES_LOGICAL)) == 0) { return EFI_INVALID_PARAMETER; } // // Buffer alignment check for TransferBuffer & MetadataBuffer. // IoAlign = This->Mode->IoAlign; if (IoAlign > 0 && (((UINTN) Packet->TransferBuffer & (IoAlign - 1)) != 0)) { return EFI_INVALID_PARAMETER; } if (IoAlign > 0 && (((UINTN) Packet->MetadataBuffer & (IoAlign - 1)) != 0)) { return EFI_INVALID_PARAMETER; } Private = NVME_CONTROLLER_PRIVATE_DATA_FROM_PASS_THRU (This); // // Check NamespaceId is valid or not. // if ((NamespaceId > Private->ControllerData->Nn) && (NamespaceId != (UINT32) -1)) { return EFI_INVALID_PARAMETER; } // // Check whether TransferLength exceeds the maximum data transfer size. // if (Private->ControllerData->Mdts != 0) { MaxTransLen = (1 << (Private->ControllerData->Mdts)) * (1 << (Private->Cap.Mpsmin + 12)); if (Packet->TransferLength > MaxTransLen) { Packet->TransferLength = MaxTransLen; return EFI_BAD_BUFFER_SIZE; } } PciIo = Private->PciIo; MapData = NULL; MapMeta = NULL; MapPrpList = NULL; PrpListHost = NULL; PrpListNo = 0; Prp = NULL; TimerEvent = NULL; Status = EFI_SUCCESS; if (Packet->QueueType == NVME_ADMIN_QUEUE) { QueueId = 0; } else { if (Event == NULL) { QueueId = 1; } else { QueueId = 2; // // Submission queue full check. // if ((Private->SqTdbl[QueueId].Sqt + 1) % (NVME_ASYNC_CSQ_SIZE + 1) == Private->AsyncSqHead) { return EFI_NOT_READY; } } } Sq = Private->SqBuffer[QueueId] + Private->SqTdbl[QueueId].Sqt; Cq = Private->CqBuffer[QueueId] + Private->CqHdbl[QueueId].Cqh; if (Packet->NvmeCmd->Nsid != NamespaceId) { return EFI_INVALID_PARAMETER; } ZeroMem (Sq, sizeof (NVME_SQ)); Sq->Opc = (UINT8)Packet->NvmeCmd->Cdw0.Opcode; Sq->Fuse = (UINT8)Packet->NvmeCmd->Cdw0.FusedOperation; Sq->Cid = Private->Cid[QueueId]++; Sq->Nsid = Packet->NvmeCmd->Nsid; // // Currently we only support PRP for data transfer, SGL is NOT supported. // ASSERT (Sq->Psdt == 0); if (Sq->Psdt != 0) { DEBUG ((EFI_D_ERROR, "NvmExpressPassThru: doesn't support SGL mechanism\n")); return EFI_UNSUPPORTED; } Sq->Prp[0] = (UINT64)(UINTN)Packet->TransferBuffer; // // If the NVMe cmd has data in or out, then mapping the user buffer to the PCI controller specific addresses. // Note here we don't handle data buffer for CreateIOSubmitionQueue and CreateIOCompletionQueue cmds because // these two cmds are special which requires their data buffer must support simultaneous access by both the // processor and a PCI Bus Master. It's caller's responsbility to ensure this. // if (((Sq->Opc & (BIT0 | BIT1)) != 0) && (Sq->Opc != NVME_ADMIN_CRIOCQ_CMD) && (Sq->Opc != NVME_ADMIN_CRIOSQ_CMD)) { if ((Packet->TransferLength == 0) || (Packet->TransferBuffer == NULL)) { return EFI_INVALID_PARAMETER; } if ((Sq->Opc & BIT0) != 0) { Flag = EfiPciIoOperationBusMasterRead; } else { Flag = EfiPciIoOperationBusMasterWrite; } MapLength = Packet->TransferLength; Status = PciIo->Map ( PciIo, Flag, Packet->TransferBuffer, &MapLength, &PhyAddr, &MapData ); if (EFI_ERROR (Status) || (Packet->TransferLength != MapLength)) { return EFI_OUT_OF_RESOURCES; } Sq->Prp[0] = PhyAddr; Sq->Prp[1] = 0; if((Packet->MetadataLength != 0) && (Packet->MetadataBuffer != NULL)) { MapLength = Packet->MetadataLength; Status = PciIo->Map ( PciIo, Flag, Packet->MetadataBuffer, &MapLength, &PhyAddr, &MapMeta ); if (EFI_ERROR (Status) || (Packet->MetadataLength != MapLength)) { PciIo->Unmap ( PciIo, MapData ); return EFI_OUT_OF_RESOURCES; } Sq->Mptr = PhyAddr; } } // // If the buffer size spans more than two memory pages (page size as defined in CC.Mps), // then build a PRP list in the second PRP submission queue entry. // Offset = ((UINT16)Sq->Prp[0]) & (EFI_PAGE_SIZE - 1); Bytes = Packet->TransferLength; if ((Offset + Bytes) > (EFI_PAGE_SIZE * 2)) { // // Create PrpList for remaining data buffer. // PhyAddr = (Sq->Prp[0] + EFI_PAGE_SIZE) & ~(EFI_PAGE_SIZE - 1); Prp = NvmeCreatePrpList (PciIo, PhyAddr, EFI_SIZE_TO_PAGES(Offset + Bytes) - 1, &PrpListHost, &PrpListNo, &MapPrpList); if (Prp == NULL) { goto EXIT; } Sq->Prp[1] = (UINT64)(UINTN)Prp; } else if ((Offset + Bytes) > EFI_PAGE_SIZE) { Sq->Prp[1] = (Sq->Prp[0] + EFI_PAGE_SIZE) & ~(EFI_PAGE_SIZE - 1); } if(Packet->NvmeCmd->Flags & CDW2_VALID) { Sq->Rsvd2 = (UINT64)Packet->NvmeCmd->Cdw2; } if(Packet->NvmeCmd->Flags & CDW3_VALID) { Sq->Rsvd2 |= LShiftU64 ((UINT64)Packet->NvmeCmd->Cdw3, 32); } if(Packet->NvmeCmd->Flags & CDW10_VALID) { Sq->Payload.Raw.Cdw10 = Packet->NvmeCmd->Cdw10; } if(Packet->NvmeCmd->Flags & CDW11_VALID) { Sq->Payload.Raw.Cdw11 = Packet->NvmeCmd->Cdw11; } if(Packet->NvmeCmd->Flags & CDW12_VALID) { Sq->Payload.Raw.Cdw12 = Packet->NvmeCmd->Cdw12; } if(Packet->NvmeCmd->Flags & CDW13_VALID) { Sq->Payload.Raw.Cdw13 = Packet->NvmeCmd->Cdw13; } if(Packet->NvmeCmd->Flags & CDW14_VALID) { Sq->Payload.Raw.Cdw14 = Packet->NvmeCmd->Cdw14; } if(Packet->NvmeCmd->Flags & CDW15_VALID) { Sq->Payload.Raw.Cdw15 = Packet->NvmeCmd->Cdw15; } // // Ring the submission queue doorbell. // if ((Event != NULL) && (QueueId != 0)) { Private->SqTdbl[QueueId].Sqt = (Private->SqTdbl[QueueId].Sqt + 1) % (NVME_ASYNC_CSQ_SIZE + 1); } else { Private->SqTdbl[QueueId].Sqt ^= 1; } Data = ReadUnaligned32 ((UINT32*)&Private->SqTdbl[QueueId]); Status = PciIo->Mem.Write ( PciIo, EfiPciIoWidthUint32, NVME_BAR, NVME_SQTDBL_OFFSET(QueueId, Private->Cap.Dstrd), 1, &Data ); if (EFI_ERROR (Status)) { goto EXIT; } // // For non-blocking requests, return directly if the command is placed // in the submission queue. // if ((Event != NULL) && (QueueId != 0)) { AsyncRequest = AllocateZeroPool (sizeof (NVME_PASS_THRU_ASYNC_REQ)); if (AsyncRequest == NULL) { Status = EFI_DEVICE_ERROR; goto EXIT; } AsyncRequest->Signature = NVME_PASS_THRU_ASYNC_REQ_SIG; AsyncRequest->Packet = Packet; AsyncRequest->CommandId = Sq->Cid; AsyncRequest->CallerEvent = Event; AsyncRequest->MapData = MapData; AsyncRequest->MapMeta = MapMeta; AsyncRequest->MapPrpList = MapPrpList; AsyncRequest->PrpListNo = PrpListNo; AsyncRequest->PrpListHost = PrpListHost; OldTpl = gBS->RaiseTPL (TPL_NOTIFY); InsertTailList (&Private->AsyncPassThruQueue, &AsyncRequest->Link); gBS->RestoreTPL (OldTpl); return EFI_SUCCESS; } Status = gBS->CreateEvent ( EVT_TIMER, TPL_CALLBACK, NULL, NULL, &TimerEvent ); if (EFI_ERROR (Status)) { goto EXIT; } Status = gBS->SetTimer(TimerEvent, TimerRelative, Packet->CommandTimeout); if (EFI_ERROR(Status)) { goto EXIT; } // // Wait for completion queue to get filled in. // Status = EFI_TIMEOUT; while (EFI_ERROR (gBS->CheckEvent (TimerEvent))) { if (Cq->Pt != Private->Pt[QueueId]) { Status = EFI_SUCCESS; break; } } // // Check the NVMe cmd execution result // if (Status != EFI_TIMEOUT) { if ((Cq->Sct == 0) && (Cq->Sc == 0)) { Status = EFI_SUCCESS; } else { Status = EFI_DEVICE_ERROR; // // Copy the Respose Queue entry for this command to the callers response buffer // CopyMem(Packet->NvmeCompletion, Cq, sizeof(EFI_NVM_EXPRESS_COMPLETION)); // // Dump every completion entry status for debugging. // DEBUG_CODE_BEGIN(); NvmeDumpStatus(Cq); DEBUG_CODE_END(); } } else { // // Timeout occurs for an NVMe command. Reset the controller to abort the // outstanding commands. // DEBUG ((DEBUG_ERROR, "NvmExpressPassThru: Timeout occurs for an NVMe command.\n")); // // Disable the timer to trigger the process of async transfers temporarily. // Status = gBS->SetTimer (Private->TimerEvent, TimerCancel, 0); if (EFI_ERROR (Status)) { goto EXIT; } // // Reset the NVMe controller. // Status = NvmeControllerInit (Private); if (!EFI_ERROR (Status)) { Status = AbortAsyncPassThruTasks (Private); if (!EFI_ERROR (Status)) { // // Re-enable the timer to trigger the process of async transfers. // Status = gBS->SetTimer (Private->TimerEvent, TimerPeriodic, NVME_HC_ASYNC_TIMER); if (!EFI_ERROR (Status)) { // // Return EFI_TIMEOUT to indicate a timeout occurs for NVMe PassThru command. // Status = EFI_TIMEOUT; } } } else { Status = EFI_DEVICE_ERROR; } goto EXIT; } if ((Private->CqHdbl[QueueId].Cqh ^= 1) == 0) { Private->Pt[QueueId] ^= 1; } Data = ReadUnaligned32 ((UINT32*)&Private->CqHdbl[QueueId]); Status = PciIo->Mem.Write ( PciIo, EfiPciIoWidthUint32, NVME_BAR, NVME_CQHDBL_OFFSET(QueueId, Private->Cap.Dstrd), 1, &Data ); // // For now, the code does not support the non-blocking feature for admin queue. // If Event is not NULL for admin queue, signal the caller's event here. // if (Event != NULL) { ASSERT (QueueId == 0); gBS->SignalEvent (Event); } EXIT: if (MapData != NULL) { PciIo->Unmap ( PciIo, MapData ); } if (MapMeta != NULL) { PciIo->Unmap ( PciIo, MapMeta ); } if (MapPrpList != NULL) { PciIo->Unmap ( PciIo, MapPrpList ); } if (Prp != NULL) { PciIo->FreeBuffer (PciIo, PrpListNo, PrpListHost); } if (TimerEvent != NULL) { gBS->CloseEvent (TimerEvent); } return Status; }
EFI_STATUS LinuxLoaderConfig ( IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage ) { EFI_STATUS Status; LINUX_LOADER_ACTION Choice; UINTN BootOrderSize; UINT16* BootOrder; UINTN BootOrderCount; UINTN Index; CHAR16 Description[MAX_ASCII_INPUT]; CHAR8 CmdLine[MAX_ASCII_INPUT]; CHAR16 Initrd[MAX_STR_INPUT]; UINT16 InitrdPathListLength; UINT16 CmdLineLength; BDS_LOAD_OPTION* BdsLoadOption; BDS_LOAD_OPTION** SupportedBdsLoadOptions; UINTN SupportedBdsLoadOptionCount; LINUX_LOADER_OPTIONAL_DATA* LinuxOptionalData; EFI_DEVICE_PATH* DevicePathRoot; Choice = (LINUX_LOADER_ACTION)0; SupportedBdsLoadOptions = NULL; SupportedBdsLoadOptionCount = 0; do { Print (L"[%d] Create new Linux Boot Entry\n",LINUX_LOADER_NEW); Print (L"[%d] Update Linux Boot Entry\n",LINUX_LOADER_UPDATE); Print (L"Option: "); Status = GetHIInputInteger ((UINTN*)&Choice); if (Status == EFI_INVALID_PARAMETER) { Print (L"\n"); return Status; } else if ((Choice != LINUX_LOADER_NEW) && (Choice != LINUX_LOADER_UPDATE)) { Print (L"Error: the option should be either '%d' or '%d'\n",LINUX_LOADER_NEW,LINUX_LOADER_UPDATE); Status = EFI_INVALID_PARAMETER; } } while (EFI_ERROR(Status)); if (Choice == LINUX_LOADER_UPDATE) { // If no compatible entry then we just create a new entry Choice = LINUX_LOADER_NEW; // Scan the OptionalData of every entry for the correct signature Status = GetGlobalEnvironmentVariable (L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder); if (!EFI_ERROR(Status)) { BootOrderCount = BootOrderSize / sizeof(UINT16); // Allocate an array to handle maximum number of supported Boot Entry SupportedBdsLoadOptions = (BDS_LOAD_OPTION**)AllocatePool(sizeof(BDS_LOAD_OPTION*) * BootOrderCount); SupportedBdsLoadOptionCount = 0; // Check if the signature is present in the list of the current Boot entries for (Index = 0; Index < BootOrderCount; Index++) { Status = BootOptionFromLoadOptionIndex (BootOrder[Index], &BdsLoadOption); if (!EFI_ERROR(Status)) { if ((BdsLoadOption->OptionalDataSize >= sizeof(UINT32)) && (*(UINT32*)BdsLoadOption->OptionalData == LINUX_LOADER_SIGNATURE)) { SupportedBdsLoadOptions[SupportedBdsLoadOptionCount++] = BdsLoadOption; Choice = LINUX_LOADER_UPDATE; } } } } FreePool (BootOrder); } if (Choice == LINUX_LOADER_NEW) { Description[0] = '\0'; CmdLine[0] = '\0'; Initrd[0] = '\0'; BdsLoadOption = (BDS_LOAD_OPTION*)AllocateZeroPool (sizeof(BDS_LOAD_OPTION)); DEBUG_CODE_BEGIN(); CHAR16* DevicePathTxt; EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol; Status = gBS->LocateProtocol (&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol); ASSERT_EFI_ERROR(Status); DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText (LoadedImage->FilePath, TRUE, TRUE); Print(L"EFI OS Loader: %s\n",DevicePathTxt); FreePool(DevicePathTxt); DEBUG_CODE_END(); // // Fill the known fields of BdsLoadOption // BdsLoadOption->Attributes = LOAD_OPTION_ACTIVE | LOAD_OPTION_CATEGORY_BOOT; // Get the full Device Path for this file Status = gBS->HandleProtocol (LoadedImage->DeviceHandle, &gEfiDevicePathProtocolGuid, (VOID **)&DevicePathRoot); ASSERT_EFI_ERROR(Status); BdsLoadOption->FilePathList = AppendDevicePath (DevicePathRoot, LoadedImage->FilePath); BdsLoadOption->FilePathListLength = GetDevicePathSize (BdsLoadOption->FilePathList); } else { if (SupportedBdsLoadOptionCount > 1) { for (Index = 0; Index < SupportedBdsLoadOptionCount; Index++) { Print (L"[%d] %s\n",Index + 1,SupportedBdsLoadOptions[Index]->Description); } do { Print (L"Update Boot Entry: "); Status = GetHIInputInteger ((UINTN*)&Choice); if (Status == EFI_INVALID_PARAMETER) { Print (L"\n"); return Status; } else if ((Choice < 1) && (Choice > SupportedBdsLoadOptionCount)) { Print (L"Choose entry from 1 to %d\n",SupportedBdsLoadOptionCount); Status = EFI_INVALID_PARAMETER; } } while (EFI_ERROR(Status)); BdsLoadOption = SupportedBdsLoadOptions[Choice-1]; } StrnCpy (Description, BdsLoadOption->Description, MAX_STR_INPUT); LinuxOptionalData = (LINUX_LOADER_OPTIONAL_DATA*)BdsLoadOption->OptionalData; if (LinuxOptionalData->CmdLineLength > 0) { CopyMem (CmdLine, (CHAR8*)LinuxOptionalData + sizeof(LINUX_LOADER_OPTIONAL_DATA), LinuxOptionalData->CmdLineLength); } else { CmdLine[0] = '\0'; } if (LinuxOptionalData->InitrdPathListLength > 0) { CopyMem (Initrd, (CHAR8*)LinuxOptionalData + sizeof(LINUX_LOADER_OPTIONAL_DATA) + LinuxOptionalData->CmdLineLength, LinuxOptionalData->InitrdPathListLength); } else { Initrd[0] = L'\0'; } DEBUG((EFI_D_ERROR,"L\n")); } // Description Print (L"Description: "); Status = EditHIInputStr (Description, MAX_STR_INPUT); if (EFI_ERROR(Status)) { return Status; } if (StrLen (Description) == 0) { StrnCpy (Description, DEFAULT_BOOT_ENTRY_DESCRIPTION, MAX_STR_INPUT); } BdsLoadOption->Description = Description; // CmdLine Print (L"Command Line: "); Status = EditHIInputAscii (CmdLine, MAX_ASCII_INPUT); if (EFI_ERROR(Status)) { return Status; } // Initrd Print (L"Initrd name: "); Status = EditHIInputStr (Initrd, MAX_STR_INPUT); if (EFI_ERROR(Status)) { return Status; } CmdLineLength = AsciiStrLen (CmdLine); if (CmdLineLength > 0) { CmdLineLength += sizeof(CHAR8); } InitrdPathListLength = StrLen (Initrd) * sizeof(CHAR16); if (InitrdPathListLength > 0) { InitrdPathListLength += sizeof(CHAR16); } BdsLoadOption->OptionalDataSize = sizeof(LINUX_LOADER_OPTIONAL_DATA) + CmdLineLength + InitrdPathListLength; LinuxOptionalData = (LINUX_LOADER_OPTIONAL_DATA*)AllocatePool (BdsLoadOption->OptionalDataSize); BdsLoadOption->OptionalData = LinuxOptionalData; LinuxOptionalData->Signature = LINUX_LOADER_SIGNATURE; LinuxOptionalData->CmdLineLength = CmdLineLength; LinuxOptionalData->InitrdPathListLength = InitrdPathListLength; if (CmdLineLength > 0) { CopyMem (LinuxOptionalData + 1, CmdLine, CmdLineLength); } if (InitrdPathListLength > 0) { CopyMem ((UINT8*)(LinuxOptionalData + 1) + CmdLineLength, Initrd, InitrdPathListLength); } // Create or Update the boot entry Status = BootOptionToLoadOptionVariable (BdsLoadOption); return Status; }
/** Return the next parameter from a command line string. This function moves the next parameter from Walker into TempParameter and moves Walker up past that parameter for recursive calling. When the final parameter is moved *Walker will be set to NULL; Temp Parameter must be large enough to hold the parameter before calling this function. This will also remove all remaining ^ characters after processing. @param[in, out] Walker pointer to string of command line. Adjusted to reminaing command line on return @param[in, out] TempParameter pointer to string of command line item extracted. @param[in] Length buffer size of TempParameter. @return EFI_INALID_PARAMETER A required parameter was NULL or pointed to a NULL or empty string. @return EFI_NOT_FOUND A closing " could not be found on the specified string **/ EFI_STATUS EFIAPI GetNextParameter( IN OUT CHAR16 **Walker, IN OUT CHAR16 **TempParameter, IN CONST UINTN Length ) { CONST CHAR16 *NextDelim; if (Walker == NULL ||*Walker == NULL ||TempParameter == NULL ||*TempParameter == NULL ){ return (EFI_INVALID_PARAMETER); } // // make sure we dont have any leading spaces // while ((*Walker)[0] == L' ') { (*Walker)++; } // // make sure we still have some params now... // if (StrLen(*Walker) == 0) { DEBUG_CODE_BEGIN(); *Walker = NULL; DEBUG_CODE_END(); return (EFI_INVALID_PARAMETER); } NextDelim = FindEndOfParameter(*Walker); if (NextDelim == NULL){ DEBUG_CODE_BEGIN(); *Walker = NULL; DEBUG_CODE_END(); return (EFI_NOT_FOUND); } StrnCpyS(*TempParameter, Length / sizeof(CHAR16), (*Walker), NextDelim - *Walker); // // Add a CHAR_NULL if we didnt get one via the copy // if (*NextDelim != CHAR_NULL) { (*TempParameter)[NextDelim - *Walker] = CHAR_NULL; } // // Update Walker for the next iteration through the function // *Walker = (CHAR16*)NextDelim; // // Remove any non-escaped quotes in the string // Remove any remaining escape characters in the string // for (NextDelim = FindFirstCharacter(*TempParameter, L"\"^", CHAR_NULL) ; *NextDelim != CHAR_NULL ; NextDelim = FindFirstCharacter(NextDelim, L"\"^", CHAR_NULL) ) { if (*NextDelim == L'^') { // // eliminate the escape ^ // CopyMem ((CHAR16*)NextDelim, NextDelim + 1, StrSize (NextDelim + 1)); NextDelim++; } else if (*NextDelim == L'\"') { // // eliminate the unescaped quote // CopyMem ((CHAR16*)NextDelim, NextDelim + 1, StrSize (NextDelim + 1)); } } return EFI_SUCCESS; }
/** Loads an EFI image into SMRAM. @param DriverEntry EFI_SMM_DRIVER_ENTRY instance @return EFI_STATUS **/ EFI_STATUS EFIAPI SmmLoadImage ( IN OUT EFI_SMM_DRIVER_ENTRY *DriverEntry ) { UINT32 AuthenticationStatus; UINTN FilePathSize; VOID *Buffer; UINTN Size; UINTN PageCount; EFI_GUID *NameGuid; EFI_STATUS Status; EFI_STATUS SecurityStatus; EFI_HANDLE DeviceHandle; EFI_PHYSICAL_ADDRESS DstBuffer; EFI_DEVICE_PATH_PROTOCOL *FilePath; EFI_DEVICE_PATH_PROTOCOL *OriginalFilePath; EFI_DEVICE_PATH_PROTOCOL *HandleFilePath; EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv; PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; Buffer = NULL; Size = 0; Fv = DriverEntry->Fv; NameGuid = &DriverEntry->FileName; FilePath = DriverEntry->FvFileDevicePath; OriginalFilePath = FilePath; HandleFilePath = FilePath; DeviceHandle = NULL; SecurityStatus = EFI_SUCCESS; Status = EFI_SUCCESS; AuthenticationStatus = 0; // // Try to get the image device handle by checking the match protocol. // Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &HandleFilePath, &DeviceHandle); if (EFI_ERROR(Status)) { return Status; } // // If the Security Architectural Protocol has not been located yet, then attempt to locate it // if (mSecurity == NULL) { gBS->LocateProtocol (&gEfiSecurityArchProtocolGuid, NULL, (VOID**)&mSecurity); } // // Verify the Authentication Status through the Security Architectural Protocol // if ((mSecurity != NULL) && (OriginalFilePath != NULL)) { SecurityStatus = mSecurity->FileAuthenticationState ( mSecurity, AuthenticationStatus, OriginalFilePath ); if (EFI_ERROR (SecurityStatus) && SecurityStatus != EFI_SECURITY_VIOLATION) { Status = SecurityStatus; return Status; } } // // Pull out just the file portion of the DevicePath for the LoadedImage FilePath // FilePath = OriginalFilePath; Status = gBS->HandleProtocol (DeviceHandle, &gEfiDevicePathProtocolGuid, (VOID **)&HandleFilePath); if (!EFI_ERROR (Status)) { FilePathSize = GetDevicePathSize (HandleFilePath) - sizeof(EFI_DEVICE_PATH_PROTOCOL); FilePath = (EFI_DEVICE_PATH_PROTOCOL *) (((UINT8 *)FilePath) + FilePathSize ); } // // Try reading PE32 section firstly // Status = Fv->ReadSection ( Fv, NameGuid, EFI_SECTION_PE32, 0, &Buffer, &Size, &AuthenticationStatus ); if (EFI_ERROR (Status)) { // // Try reading TE section secondly // Buffer = NULL; Size = 0; Status = Fv->ReadSection ( Fv, NameGuid, EFI_SECTION_TE, 0, &Buffer, &Size, &AuthenticationStatus ); } if (EFI_ERROR (Status)) { if (Buffer != NULL) { Status = gBS->FreePool (Buffer); } return Status; } // // Initialize ImageContext // ImageContext.Handle = Buffer; ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory; // // Get information about the image being loaded // Status = PeCoffLoaderGetImageInfo (&ImageContext); if (EFI_ERROR (Status)) { if (Buffer != NULL) { Status = gBS->FreePool (Buffer); } return Status; } // // if Loading module at Fixed Address feature is enabled, then cut out a memory range started from TESG BASE // to hold the Smm driver code // if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) { // // Get the fixed loading address assigned by Build tool // Status = GetPeCoffImageFixLoadingAssignedAddress (&ImageContext); if (!EFI_ERROR (Status)) { // // Since the memory range to load Smm core alreay been cut out, so no need to allocate and free this range // following statements is to bypass SmmFreePages // PageCount = 0; DstBuffer = (UINTN)gLoadModuleAtFixAddressSmramBase; } else { DEBUG ((EFI_D_INFO|EFI_D_LOAD, "LOADING MODULE FIXED ERROR: Failed to load module at fixed address. \n")); // // allocate the memory to load the SMM driver // PageCount = (UINTN)EFI_SIZE_TO_PAGES((UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment); DstBuffer = (UINTN)(-1); Status = SmmAllocatePages ( AllocateMaxAddress, EfiRuntimeServicesCode, PageCount, &DstBuffer ); if (EFI_ERROR (Status)) { if (Buffer != NULL) { Status = gBS->FreePool (Buffer); } return Status; } ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)DstBuffer; } } else { PageCount = (UINTN)EFI_SIZE_TO_PAGES((UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment); DstBuffer = (UINTN)(-1); Status = SmmAllocatePages ( AllocateMaxAddress, EfiRuntimeServicesCode, PageCount, &DstBuffer ); if (EFI_ERROR (Status)) { if (Buffer != NULL) { Status = gBS->FreePool (Buffer); } return Status; } ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)DstBuffer; } // // Align buffer on section boundry // ImageContext.ImageAddress += ImageContext.SectionAlignment - 1; ImageContext.ImageAddress &= ~(ImageContext.SectionAlignment - 1); // // Load the image to our new buffer // Status = PeCoffLoaderLoadImage (&ImageContext); if (EFI_ERROR (Status)) { if (Buffer != NULL) { Status = gBS->FreePool (Buffer); } SmmFreePages (DstBuffer, PageCount); return Status; } // // Relocate the image in our new buffer // Status = PeCoffLoaderRelocateImage (&ImageContext); if (EFI_ERROR (Status)) { if (Buffer != NULL) { Status = gBS->FreePool (Buffer); } SmmFreePages (DstBuffer, PageCount); return Status; } // // Flush the instruction cache so the image data are written before we execute it // InvalidateInstructionCacheRange ((VOID *)(UINTN) ImageContext.ImageAddress, (UINTN) ImageContext.ImageSize); // // Save Image EntryPoint in DriverEntry // DriverEntry->ImageEntryPoint = ImageContext.EntryPoint; DriverEntry->ImageBuffer = DstBuffer; DriverEntry->NumberOfPage = PageCount; // // Allocate a Loaded Image Protocol in EfiBootServicesData // Status = gBS->AllocatePool (EfiBootServicesData, sizeof (EFI_LOADED_IMAGE_PROTOCOL), (VOID **)&DriverEntry->LoadedImage); if (EFI_ERROR (Status)) { if (Buffer != NULL) { Status = gBS->FreePool (Buffer); } SmmFreePages (DstBuffer, PageCount); return Status; } // // Fill in the remaining fields of the Loaded Image Protocol instance. // Note: ImageBase is an SMRAM address that can not be accessed outside of SMRAM if SMRAM window is closed. // DriverEntry->LoadedImage->Revision = EFI_LOADED_IMAGE_PROTOCOL_REVISION; DriverEntry->LoadedImage->ParentHandle = gSmmCorePrivate->SmmIplImageHandle; DriverEntry->LoadedImage->SystemTable = gST; DriverEntry->LoadedImage->DeviceHandle = DeviceHandle; // // Make an EfiBootServicesData buffer copy of FilePath // Status = gBS->AllocatePool (EfiBootServicesData, GetDevicePathSize (FilePath), (VOID **)&DriverEntry->LoadedImage->FilePath); if (EFI_ERROR (Status)) { if (Buffer != NULL) { Status = gBS->FreePool (Buffer); } SmmFreePages (DstBuffer, PageCount); return Status; } CopyMem (DriverEntry->LoadedImage->FilePath, FilePath, GetDevicePathSize (FilePath)); DriverEntry->LoadedImage->ImageBase = (VOID *)(UINTN)DriverEntry->ImageBuffer; DriverEntry->LoadedImage->ImageSize = ImageContext.ImageSize; DriverEntry->LoadedImage->ImageCodeType = EfiRuntimeServicesCode; DriverEntry->LoadedImage->ImageDataType = EfiRuntimeServicesData; // // Create a new image handle in the UEFI handle database for the SMM Driver // DriverEntry->ImageHandle = NULL; Status = gBS->InstallMultipleProtocolInterfaces ( &DriverEntry->ImageHandle, &gEfiLoadedImageProtocolGuid, DriverEntry->LoadedImage, NULL ); // // Print the load address and the PDB file name if it is available // DEBUG_CODE_BEGIN (); UINTN Index; UINTN StartIndex; CHAR8 EfiFileName[256]; DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Loading SMM driver at 0x%11p EntryPoint=0x%11p ", (VOID *)(UINTN) ImageContext.ImageAddress, FUNCTION_ENTRY_POINT (ImageContext.EntryPoint))); // // Print Module Name by Pdb file path. // Windows and Unix style file path are all trimmed correctly. // if (ImageContext.PdbPointer != NULL) { StartIndex = 0; for (Index = 0; ImageContext.PdbPointer[Index] != 0; Index++) { if ((ImageContext.PdbPointer[Index] == '\\') || (ImageContext.PdbPointer[Index] == '/')) { StartIndex = Index + 1; } } // // Copy the PDB file name to our temporary string, and replace .pdb with .efi // The PDB file name is limited in the range of 0~255. // If the length is bigger than 255, trim the redudant characters to avoid overflow in array boundary. // for (Index = 0; Index < sizeof (EfiFileName) - 4; Index++) { EfiFileName[Index] = ImageContext.PdbPointer[Index + StartIndex]; if (EfiFileName[Index] == 0) { EfiFileName[Index] = '.'; } if (EfiFileName[Index] == '.') { EfiFileName[Index + 1] = 'e'; EfiFileName[Index + 2] = 'f'; EfiFileName[Index + 3] = 'i'; EfiFileName[Index + 4] = 0; break; } } if (Index == sizeof (EfiFileName) - 4) { EfiFileName[Index] = 0; } DEBUG ((DEBUG_INFO | DEBUG_LOAD, "%a", EfiFileName)); // &Image->ImageContext.PdbPointer[StartIndex])); } DEBUG ((DEBUG_INFO | DEBUG_LOAD, "\n")); DEBUG_CODE_END (); // // Free buffer allocated by Fv->ReadSection. // // The UEFI Boot Services FreePool() function must be used because Fv->ReadSection // used the UEFI Boot Services AllocatePool() function // Status = gBS->FreePool(Buffer); return Status; }
/** Provides the DMA controller-specific addresses needed to access system memory. Operation is relative to the DMA bus master. @param Operation Indicates if the bus master is going to read or write to system memory. @param HostAddress The system memory address to map to the DMA controller. @param NumberOfBytes On input the number of bytes to map. On output the number of bytes that were mapped. @param DeviceAddress The resulting map address for the bus master controller to use to access the hosts HostAddress. @param Mapping A resulting value to pass to Unmap(). @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes. @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer. @retval EFI_INVALID_PARAMETER One or more parameters are invalid. @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. @retval EFI_DEVICE_ERROR The system hardware could not map the requested address. **/ EFI_STATUS EFIAPI DmaMap ( IN DMA_MAP_OPERATION Operation, IN VOID *HostAddress, IN OUT UINTN *NumberOfBytes, OUT PHYSICAL_ADDRESS *DeviceAddress, OUT VOID **Mapping ) { EFI_STATUS Status; MAP_INFO_INSTANCE *Map; VOID *Buffer; EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor; if (HostAddress == NULL || NumberOfBytes == NULL || DeviceAddress == NULL || Mapping == NULL ) { return EFI_INVALID_PARAMETER; } if (Operation >= MapOperationMaximum) { return EFI_INVALID_PARAMETER; } // // The debug implementation of UncachedMemoryAllocationLib in ArmPkg returns // a virtual uncached alias, and unmaps the cached ID mapping of the buffer, // in order to catch inadvertent references to the cached mapping. // Since HostToDeviceAddress () expects ID mapped input addresses, convert // the host address to an ID mapped address first. // *DeviceAddress = HostToDeviceAddress (ConvertToPhysicalAddress (HostAddress)); // Remember range so we can flush on the other side Map = AllocatePool (sizeof (MAP_INFO_INSTANCE)); if (Map == NULL) { return EFI_OUT_OF_RESOURCES; } if ((((UINTN)HostAddress & (mCpu->DmaBufferAlignment - 1)) != 0) || ((*NumberOfBytes & (mCpu->DmaBufferAlignment - 1)) != 0)) { // Get the cacheability of the region Status = gDS->GetMemorySpaceDescriptor ((UINTN)HostAddress, &GcdDescriptor); if (EFI_ERROR(Status)) { goto FreeMapInfo; } // If the mapped buffer is not an uncached buffer if ((GcdDescriptor.Attributes & (EFI_MEMORY_WB | EFI_MEMORY_WT)) != 0) { // // Operations of type MapOperationBusMasterCommonBuffer are only allowed // on uncached buffers. // if (Operation == MapOperationBusMasterCommonBuffer) { DEBUG ((EFI_D_ERROR, "%a: Operation type 'MapOperationBusMasterCommonBuffer' is only supported\n" "on memory regions that were allocated using DmaAllocateBuffer ()\n", __FUNCTION__)); Status = EFI_UNSUPPORTED; goto FreeMapInfo; } // // If the buffer does not fill entire cache lines we must double buffer into // uncached memory. Device (PCI) address becomes uncached page. // Map->DoubleBuffer = TRUE; Status = DmaAllocateBuffer (EfiBootServicesData, EFI_SIZE_TO_PAGES (*NumberOfBytes), &Buffer); if (EFI_ERROR (Status)) { goto FreeMapInfo; } if (Operation == MapOperationBusMasterRead) { CopyMem (Buffer, HostAddress, *NumberOfBytes); } *DeviceAddress = HostToDeviceAddress (ConvertToPhysicalAddress (Buffer)); Map->BufferAddress = Buffer; } else { Map->DoubleBuffer = FALSE; } } else { Map->DoubleBuffer = FALSE; DEBUG_CODE_BEGIN (); // // The operation type check above only executes if the buffer happens to be // misaligned with respect to CWG, but even if it is aligned, we should not // allow arbitrary buffers to be used for creating consistent mappings. // So duplicate the check here when running in DEBUG mode, just to assert // that we are not trying to create a consistent mapping for cached memory. // Status = gDS->GetMemorySpaceDescriptor ((UINTN)HostAddress, &GcdDescriptor); ASSERT_EFI_ERROR(Status); ASSERT (Operation != MapOperationBusMasterCommonBuffer || (GcdDescriptor.Attributes & (EFI_MEMORY_WB | EFI_MEMORY_WT)) == 0); DEBUG_CODE_END (); // Flush the Data Cache (should not have any effect if the memory region is uncached) mCpu->FlushDataCache (mCpu, (UINTN)HostAddress, *NumberOfBytes, EfiCpuFlushTypeWriteBackInvalidate); } Map->HostAddress = (UINTN)HostAddress; Map->NumberOfBytes = *NumberOfBytes; Map->Operation = Operation; *Mapping = Map; return EFI_SUCCESS; FreeMapInfo: FreePool (Map); return Status; }
/** Constructor for the Shell Level 2 Commands library. Install the handlers for level 2 UEFI Shell 2.0 commands. @param ImageHandle the image handle of the process @param SystemTable the EFI System Table pointer @retval EFI_SUCCESS the shell command handlers were installed sucessfully @retval EFI_UNSUPPORTED the shell level required was not found. **/ EFI_STATUS EFIAPI ShellLevel2CommandsLibConstructor ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { // // if shell level is less than 2 do nothing // if (PcdGet8(PcdShellSupportLevel) < 2) { return (EFI_SUCCESS); } gShellLevel2HiiHandle = HiiAddPackages (&gShellLevel2HiiGuid, gImageHandle, UefiShellLevel2CommandsLibStrings, NULL); if (gShellLevel2HiiHandle == NULL) { return (EFI_DEVICE_ERROR); } // // install our shell command handlers that are always installed // ShellCommandRegisterCommandName(L"attrib", ShellCommandRunAttrib , ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_ATTRIB) ); ShellCommandRegisterCommandName(L"cd", ShellCommandRunCd , ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_CD) ); ShellCommandRegisterCommandName(L"cp", ShellCommandRunCp , ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_CP) ); ShellCommandRegisterCommandName(L"load", ShellCommandRunLoad , ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_LOAD) ); ShellCommandRegisterCommandName(L"map", ShellCommandRunMap , ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_MAP) ); ShellCommandRegisterCommandName(L"mkdir", ShellCommandRunMkDir , ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_MKDIR) ); ShellCommandRegisterCommandName(L"mv", ShellCommandRunMv , ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_MV) ); ShellCommandRegisterCommandName(L"parse", ShellCommandRunParse , ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_PARSE) ); ShellCommandRegisterCommandName(L"reset", ShellCommandRunReset , ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_RESET) ); ShellCommandRegisterCommandName(L"set", ShellCommandRunSet , ShellCommandGetManFileNameLevel2, 2, L"",FALSE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_SET) ); ShellCommandRegisterCommandName(L"ls", ShellCommandRunLs , ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_LS) ); ShellCommandRegisterCommandName(L"rm", ShellCommandRunRm , ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_RM) ); ShellCommandRegisterCommandName(L"vol", ShellCommandRunVol , ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_VOL) ); // // support for permenant (built in) aliases // ShellCommandRegisterAlias(L"rm", L"del"); ShellCommandRegisterAlias(L"ls", L"dir"); ShellCommandRegisterAlias(L"cp", L"copy"); ShellCommandRegisterAlias(L"mkdir", L"md"); ShellCommandRegisterAlias(L"cd ..", L"cd.."); ShellCommandRegisterAlias(L"cd \\", L"cd\\"); ShellCommandRegisterAlias(L"ren", L"mv"); // // These are installed in level 2 or 3... // if (PcdGet8(PcdShellSupportLevel) == 2 || PcdGet8(PcdShellSupportLevel) == 3) { ShellCommandRegisterCommandName(L"date", ShellCommandRunDate , ShellCommandGetManFileNameLevel2, PcdGet8(PcdShellSupportLevel), L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_DATE) ); ShellCommandRegisterCommandName(L"time", ShellCommandRunTime , ShellCommandGetManFileNameLevel2, PcdGet8(PcdShellSupportLevel), L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_TIME) ); ShellCommandRegisterCommandName(L"timezone", ShellCommandRunTimeZone, ShellCommandGetManFileNameLevel2, PcdGet8(PcdShellSupportLevel), L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_TIMEZONE)); } else { DEBUG_CODE_BEGIN(); // // we want to be able to test these so install them under a different name in debug mode... // ShellCommandRegisterCommandName(L"l2date", ShellCommandRunDate , ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_DATE) ); ShellCommandRegisterCommandName(L"l2time", ShellCommandRunTime , ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_TIME) ); ShellCommandRegisterCommandName(L"l2timezone", ShellCommandRunTimeZone, ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_TIMEZONE)); DEBUG_CODE_END(); } return (EFI_SUCCESS); }
/** Loads a PEIM into memory for subsequent execution. If there are compressed images or images that need to be relocated into memory for performance reasons, this service performs that transformation. @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation @param FileHandle Pointer to the FFS file header of the image. @param ImageAddressArg Pointer to PE/TE image. @param ImageSizeArg Size of PE/TE image. @param EntryPoint Pointer to entry point of specified image file for output. @param AuthenticationState - Pointer to attestation authentication state of image. @retval EFI_SUCCESS Image is successfully loaded. @retval EFI_NOT_FOUND Fail to locate necessary PPI. @retval EFI_UNSUPPORTED Image Machine Type is not supported. @retval EFI_WARN_BUFFER_TOO_SMALL There is not enough heap to allocate the requested size. This will not prevent the XIP image from being invoked. **/ EFI_STATUS PeiLoadImageLoadImage ( IN CONST EFI_PEI_SERVICES **PeiServices, IN EFI_PEI_FILE_HANDLE FileHandle, OUT EFI_PHYSICAL_ADDRESS *ImageAddressArg, OPTIONAL OUT UINT64 *ImageSizeArg, OPTIONAL OUT EFI_PHYSICAL_ADDRESS *EntryPoint, OUT UINT32 *AuthenticationState ) { EFI_STATUS Status; VOID *Pe32Data; EFI_PHYSICAL_ADDRESS ImageAddress; UINT64 ImageSize; EFI_PHYSICAL_ADDRESS ImageEntryPoint; UINT16 Machine; EFI_SECTION_TYPE SearchType1; EFI_SECTION_TYPE SearchType2; *EntryPoint = 0; ImageSize = 0; *AuthenticationState = 0; if (FeaturePcdGet (PcdPeiCoreImageLoaderSearchTeSectionFirst)) { SearchType1 = EFI_SECTION_TE; SearchType2 = EFI_SECTION_PE32; } else { SearchType1 = EFI_SECTION_PE32; SearchType2 = EFI_SECTION_TE; } // // Try to find a first exe section (if PcdPeiCoreImageLoaderSearchTeSectionFirst // is true, TE will be searched first). // Status = PeiServicesFfsFindSectionData3 ( SearchType1, 0, FileHandle, &Pe32Data, AuthenticationState ); // // If we didn't find a first exe section, try to find the second exe section. // if (EFI_ERROR (Status)) { Status = PeiServicesFfsFindSectionData3 ( SearchType2, 0, FileHandle, &Pe32Data, AuthenticationState ); if (EFI_ERROR (Status)) { // // PEI core only carry the loader function for TE and PE32 executables // If this two section does not exist, just return. // return Status; } } // // If memory is installed, perform the shadow operations // Status = LoadAndRelocatePeCoffImage ( Pe32Data, &ImageAddress, &ImageSize, &ImageEntryPoint ); ASSERT_EFI_ERROR (Status); if (EFI_ERROR (Status)) { return Status; } // // Got the entry point from the loaded Pe32Data // Pe32Data = (VOID *) ((UINTN) ImageAddress); *EntryPoint = ImageEntryPoint; Machine = PeCoffLoaderGetMachineType (Pe32Data); if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Machine)) { if (!EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED (Machine)) { return EFI_UNSUPPORTED; } } if (ImageAddressArg != NULL) { *ImageAddressArg = ImageAddress; } if (ImageSizeArg != NULL) { *ImageSizeArg = ImageSize; } DEBUG_CODE_BEGIN (); CHAR8 *AsciiString; CHAR8 EfiFileName[512]; INT32 Index; INT32 StartIndex; // // Print debug message: Loading PEIM at 0x12345678 EntryPoint=0x12345688 Driver.efi // if (Machine != EFI_IMAGE_MACHINE_IA64) { DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Loading PEIM at 0x%11p EntryPoint=0x%11p ", (VOID *)(UINTN)ImageAddress, (VOID *)(UINTN)*EntryPoint)); } else { // // For IPF Image, the real entry point should be print. // DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Loading PEIM at 0x%11p EntryPoint=0x%11p ", (VOID *)(UINTN)ImageAddress, (VOID *)(UINTN)(*(UINT64 *)(UINTN)*EntryPoint))); } // // Print Module Name by PeImage PDB file name. // AsciiString = PeCoffLoaderGetPdbPointer (Pe32Data); if (AsciiString != NULL) { StartIndex = 0; for (Index = 0; AsciiString[Index] != 0; Index++) { if (AsciiString[Index] == '\\' || AsciiString[Index] == '/') { StartIndex = Index + 1; } } // // Copy the PDB file name to our temporary string, and replace .pdb with .efi // The PDB file name is limited in the range of 0~511. // If the length is bigger than 511, trim the redudant characters to avoid overflow in array boundary. // for (Index = 0; Index < sizeof (EfiFileName) - 4; Index++) { EfiFileName[Index] = AsciiString[Index + StartIndex]; if (EfiFileName[Index] == 0) { EfiFileName[Index] = '.'; } if (EfiFileName[Index] == '.') { EfiFileName[Index + 1] = 'e'; EfiFileName[Index + 2] = 'f'; EfiFileName[Index + 3] = 'i'; EfiFileName[Index + 4] = 0; break; } } if (Index == sizeof (EfiFileName) - 4) { EfiFileName[Index] = 0; } DEBUG ((EFI_D_INFO | EFI_D_LOAD, "%a", EfiFileName)); } DEBUG_CODE_END (); DEBUG ((EFI_D_INFO | EFI_D_LOAD, "\n")); return EFI_SUCCESS; }
EFI_STATUS DefineDefaultBootEntries ( VOID ) { BDS_LOAD_OPTION* BdsLoadOption; UINTN Size; EFI_STATUS Status; EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL* EfiDevicePathFromTextProtocol; EFI_DEVICE_PATH* BootDevicePath; UINT8* OptionalData; UINTN OptionalDataSize; ARM_BDS_LOADER_ARGUMENTS* BootArguments; ARM_BDS_LOADER_TYPE BootType; EFI_DEVICE_PATH* InitrdPath; UINTN InitrdSize; UINTN CmdLineSize; UINTN CmdLineAsciiSize; CHAR16* DefaultBootArgument; CHAR8* AsciiDefaultBootArgument; // // If Boot Order does not exist then create a default entry // Size = 0; Status = gRT->GetVariable (L"BootOrder", &gEfiGlobalVariableGuid, NULL, &Size, NULL); if (Status == EFI_NOT_FOUND) { if ((PcdGetPtr(PcdDefaultBootDevicePath) == NULL) || (StrLen ((CHAR16*)PcdGetPtr(PcdDefaultBootDevicePath)) == 0)) { return EFI_UNSUPPORTED; } Status = gBS->LocateProtocol (&gEfiDevicePathFromTextProtocolGuid, NULL, (VOID **)&EfiDevicePathFromTextProtocol); if (EFI_ERROR(Status)) { // You must provide an implementation of DevicePathFromTextProtocol in your firmware (eg: DevicePathDxe) DEBUG((EFI_D_ERROR,"Error: Bds requires DevicePathFromTextProtocol\n")); return Status; } BootDevicePath = EfiDevicePathFromTextProtocol->ConvertTextToDevicePath ((CHAR16*)PcdGetPtr(PcdDefaultBootDevicePath)); DEBUG_CODE_BEGIN(); // We convert back to the text representation of the device Path to see if the initial text is correct EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol; CHAR16* DevicePathTxt; Status = gBS->LocateProtocol(&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol); ASSERT_EFI_ERROR(Status); DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText (BootDevicePath, TRUE, TRUE); ASSERT (StrCmp ((CHAR16*)PcdGetPtr(PcdDefaultBootDevicePath), DevicePathTxt) == 0); FreePool (DevicePathTxt); DEBUG_CODE_END(); // Create the entry is the Default values are correct if (BootDevicePath != NULL) { BootType = (ARM_BDS_LOADER_TYPE)PcdGet32 (PcdDefaultBootType); // We do not support NULL pointer ASSERT (PcdGetPtr (PcdDefaultBootArgument) != NULL); // // Logic to handle ASCII or Unicode default parameters // if (*(CHAR8*)PcdGetPtr (PcdDefaultBootArgument) == '\0') { CmdLineSize = 0; CmdLineAsciiSize = 0; DefaultBootArgument = NULL; AsciiDefaultBootArgument = NULL; } else if (IsUnicodeString ((CHAR16*)PcdGetPtr (PcdDefaultBootArgument))) { // The command line is a Unicode string DefaultBootArgument = (CHAR16*)PcdGetPtr (PcdDefaultBootArgument); CmdLineSize = StrSize (DefaultBootArgument); // Initialize ASCII variables CmdLineAsciiSize = CmdLineSize / 2; AsciiDefaultBootArgument = AllocatePool (CmdLineAsciiSize); if (AsciiDefaultBootArgument == NULL) { return EFI_OUT_OF_RESOURCES; } UnicodeStrToAsciiStr ((CHAR16*)PcdGetPtr (PcdDefaultBootArgument), AsciiDefaultBootArgument); } else { // The command line is a ASCII string AsciiDefaultBootArgument = (CHAR8*)PcdGetPtr (PcdDefaultBootArgument); CmdLineAsciiSize = AsciiStrSize (AsciiDefaultBootArgument); // Initialize ASCII variables CmdLineSize = CmdLineAsciiSize * 2; DefaultBootArgument = AllocatePool (CmdLineSize); if (DefaultBootArgument == NULL) { return EFI_OUT_OF_RESOURCES; } AsciiStrToUnicodeStr (AsciiDefaultBootArgument, DefaultBootArgument); } if ((BootType == BDS_LOADER_KERNEL_LINUX_ATAG) || (BootType == BDS_LOADER_KERNEL_LINUX_FDT)) { InitrdPath = EfiDevicePathFromTextProtocol->ConvertTextToDevicePath ((CHAR16*)PcdGetPtr(PcdDefaultBootInitrdPath)); InitrdSize = GetDevicePathSize (InitrdPath); OptionalDataSize = sizeof(ARM_BDS_LOADER_ARGUMENTS) + CmdLineAsciiSize + InitrdSize; BootArguments = (ARM_BDS_LOADER_ARGUMENTS*)AllocatePool (OptionalDataSize); if (BootArguments == NULL) { return EFI_OUT_OF_RESOURCES; } BootArguments->LinuxArguments.CmdLineSize = CmdLineAsciiSize; BootArguments->LinuxArguments.InitrdSize = InitrdSize; CopyMem ((VOID*)(BootArguments + 1), AsciiDefaultBootArgument, CmdLineAsciiSize); CopyMem ((VOID*)((UINTN)(BootArguments + 1) + CmdLineAsciiSize), InitrdPath, InitrdSize); OptionalData = (UINT8*)BootArguments; } else { OptionalData = (UINT8*)DefaultBootArgument; OptionalDataSize = CmdLineSize; } BootOptionCreate (LOAD_OPTION_ACTIVE | LOAD_OPTION_CATEGORY_BOOT, (CHAR16*)PcdGetPtr(PcdDefaultBootDescription), BootDevicePath, BootType, OptionalData, OptionalDataSize, &BdsLoadOption ); FreePool (BdsLoadOption); if (DefaultBootArgument == (CHAR16*)PcdGetPtr (PcdDefaultBootArgument)) { FreePool (AsciiDefaultBootArgument); } else if (DefaultBootArgument != NULL) { FreePool (DefaultBootArgument); } } else { Status = EFI_UNSUPPORTED; } } return Status; }
/** Returns the handle of the ACPI object representing the specified ACPI AML path @param[in] AmlHandle Points to the handle of the object representing the starting point for the path search. @param[in] AmlPath Points to the ACPI AML path. @param[out] Buffer On return, points to the ACPI object which represents AcpiPath, relative to HandleIn. @param[in] FromRoot TRUE means to find AML path from \ (Root) Node. FALSE means to find AML path from this Node (The HandleIn). @retval EFI_SUCCESS Success @retval EFI_INVALID_PARAMETER HandleIn does not refer to a valid ACPI object. **/ EFI_STATUS AmlFindPath ( IN EFI_AML_HANDLE *AmlHandle, IN UINT8 *AmlPath, OUT VOID **Buffer, IN BOOLEAN FromRoot ) { EFI_AML_NODE_LIST *AmlRootNodeList; EFI_STATUS Status; EFI_AML_NODE_LIST *AmlNodeList; UINT8 RootNameSeg[AML_NAME_SEG_SIZE]; EFI_AML_NODE_LIST *CurrentAmlNodeList; LIST_ENTRY *CurrentLink; // // 1. create tree // // // Create root handle // RootNameSeg[0] = AML_ROOT_CHAR; RootNameSeg[1] = 0; AmlRootNodeList = AmlCreateNode (RootNameSeg, NULL, AmlHandle->AmlByteEncoding); Status = AmlConstructNodeList ( AmlHandle, AmlRootNodeList, // Root AmlRootNodeList // Parent ); if (EFI_ERROR (Status)) { return EFI_INVALID_PARAMETER; } DEBUG_CODE_BEGIN (); DEBUG ((EFI_D_ERROR, "AcpiSdt: NameSpace:\n")); AmlDumpNodeInfo (AmlRootNodeList, 0); DEBUG_CODE_END (); // // 2. Search the node in the tree // if (FromRoot) { // // Search from Root // CurrentAmlNodeList = AmlRootNodeList; } else { // // Search from this node, NOT ROOT. // Since we insert node to ROOT one by one, we just get the first node and search from it. // CurrentLink = AmlRootNodeList->Children.ForwardLink; if (CurrentLink != &AmlRootNodeList->Children) { // // First node // CurrentAmlNodeList = EFI_AML_NODE_LIST_FROM_LINK (CurrentLink); } else { // // No child // CurrentAmlNodeList = NULL; } } // // Search // if (CurrentAmlNodeList != NULL) { DEBUG_CODE_BEGIN (); DEBUG ((EFI_D_ERROR, "AcpiSdt: Search from: \\")); AmlPrintNameSeg (CurrentAmlNodeList->Name); DEBUG ((EFI_D_ERROR, "\n")); DEBUG_CODE_END (); AmlNodeList = AmlFindNodeInTheTree ( AmlPath, AmlRootNodeList, // Root CurrentAmlNodeList, // Parent FALSE ); } else { AmlNodeList = NULL; } *Buffer = NULL; Status = EFI_SUCCESS; if (AmlNodeList != NULL && AmlNodeList->Buffer != NULL) { *Buffer = AmlNodeList->Buffer; } // // 3. free the tree // AmlDestructNodeList (AmlRootNodeList); return Status; }
/** Perform a TLS/SSL handshake. This function will perform a TLS/SSL handshake. @param[in] Tls Pointer to the TLS object for handshake operation. @param[in] BufferIn Pointer to the most recently received TLS Handshake packet. @param[in] BufferInSize Packet size in bytes for the most recently received TLS Handshake packet. @param[out] BufferOut Pointer to the buffer to hold the built packet. @param[in, out] BufferOutSize Pointer to the buffer size in bytes. On input, it is the buffer size provided by the caller. On output, it is the buffer size in fact needed to contain the packet. @retval EFI_SUCCESS The required TLS packet is built successfully. @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: Tls is NULL. BufferIn is NULL but BufferInSize is NOT 0. BufferInSize is 0 but BufferIn is NOT NULL. BufferOutSize is NULL. BufferOut is NULL if *BufferOutSize is not zero. @retval EFI_BUFFER_TOO_SMALL BufferOutSize is too small to hold the response packet. @retval EFI_ABORTED Something wrong during handshake. **/ EFI_STATUS EFIAPI TlsDoHandshake ( IN VOID *Tls, IN UINT8 *BufferIn, OPTIONAL IN UINTN BufferInSize, OPTIONAL OUT UINT8 *BufferOut, OPTIONAL IN OUT UINTN *BufferOutSize ) { TLS_CONNECTION *TlsConn; UINTN PendingBufferSize; INTN Ret; UINTN ErrorCode; TlsConn = (TLS_CONNECTION *) Tls; PendingBufferSize = 0; Ret = 1; if (TlsConn == NULL || \ TlsConn->Ssl == NULL || TlsConn->InBio == NULL || TlsConn->OutBio == NULL || \ BufferOutSize == NULL || \ (BufferIn == NULL && BufferInSize != 0) || \ (BufferIn != NULL && BufferInSize == 0) || \ (BufferOut == NULL && *BufferOutSize != 0)) { return EFI_INVALID_PARAMETER; } if(BufferIn == NULL && BufferInSize == 0) { // // If RequestBuffer is NULL and RequestSize is 0, and TLS session // status is EfiTlsSessionNotStarted, the TLS session will be initiated // and the response packet needs to be ClientHello. // PendingBufferSize = (UINTN) BIO_ctrl_pending (TlsConn->OutBio); if (PendingBufferSize == 0) { SSL_set_connect_state (TlsConn->Ssl); Ret = SSL_do_handshake (TlsConn->Ssl); PendingBufferSize = (UINTN) BIO_ctrl_pending (TlsConn->OutBio); } } else { PendingBufferSize = (UINTN) BIO_ctrl_pending (TlsConn->OutBio); if (PendingBufferSize == 0) { BIO_write (TlsConn->InBio, BufferIn, (UINT32) BufferInSize); Ret = SSL_do_handshake (TlsConn->Ssl); PendingBufferSize = (UINTN) BIO_ctrl_pending (TlsConn->OutBio); } } if (Ret < 1) { Ret = SSL_get_error (TlsConn->Ssl, (int) Ret); if (Ret == SSL_ERROR_SSL || Ret == SSL_ERROR_SYSCALL || Ret == SSL_ERROR_ZERO_RETURN) { DEBUG (( DEBUG_ERROR, "%a SSL_HANDSHAKE_ERROR State=0x%x SSL_ERROR_%a\n", __FUNCTION__, SSL_get_state (TlsConn->Ssl), Ret == SSL_ERROR_SSL ? "SSL" : Ret == SSL_ERROR_SYSCALL ? "SYSCALL" : "ZERO_RETURN" )); DEBUG_CODE_BEGIN (); while (TRUE) { ErrorCode = ERR_get_error (); if (ErrorCode == 0) { break; } DEBUG (( DEBUG_ERROR, "%a ERROR 0x%x=L%x:F%x:R%x\n", __FUNCTION__, ErrorCode, ERR_GET_LIB (ErrorCode), ERR_GET_FUNC (ErrorCode), ERR_GET_REASON (ErrorCode) )); } DEBUG_CODE_END (); return EFI_ABORTED; } } if (PendingBufferSize > *BufferOutSize) { *BufferOutSize = PendingBufferSize; return EFI_BUFFER_TOO_SMALL; } if (PendingBufferSize > 0) { *BufferOutSize = BIO_read (TlsConn->OutBio, BufferOut, (UINT32) PendingBufferSize); } else { *BufferOutSize = 0; } return EFI_SUCCESS; }
/** Determine the flash size and description @param[in] PerformJedecIdOperation Callback routine to initiate the JEDEC ID operation using the SPI controller to identify the flash part. @param[in] Context Pointer to a context structure to pass to PerformJedecIdOperation @param[out] FlashDescription Pointer to a buffer to receive a pointer to a FLASH_PART_DESCRIPTION data structure containing the flash part information. @return This routine returns the size of the flash part if it is supported. Zero is returned if the flash part is not supported. **/ UINT64 EFIAPI FindFlashSupport ( IN PERFORM_JEDEC_ID_OPERATION PerformJedecIdOperation, IN VOID *Context, OUT CONST FLASH_PART_DESCRIPTION **FlashDescription ) { UINTN BufferLength; CONST FLASH_PART_DESCRIPTION *Description; UINT64 FlashSize; EFI_HANDLE *HandleArray; UINTN HandleCount; UINTN HandleIndex; UINT8 *JedecId; UINT32 MaxPriority; UINT32 Priority; SPI_FLASH_PART_PROTOCOL *Protocol; SPI_FLASH_PART_PROTOCOL **SpiFlashPartProtocol; EFI_STATUS Status; // // Assume failure // FlashSize = 0; HandleArray = NULL; JedecId = NULL; SpiFlashPartProtocol = NULL; // // Locate handles containing SPI_FLASH_PART_PROTOCOLS // Status = gBS->LocateHandleBuffer ( ByProtocol, &gSpiFlashPartProtocolGuid, NULL, &HandleCount, &HandleArray ); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "ERROR - Failed to locate SPI_FLASH_PART_PROTOCOL, Status: %r\r\n", Status)); } else { // // Allocate and fill in the protocol array // DEBUG ((DEBUG_INFO, "%d SPI flash part descriptions found\r\n", HandleCount)); SpiFlashPartProtocol = AllocatePool (HandleCount * sizeof (*SpiFlashPartProtocol)); if (SpiFlashPartProtocol == NULL) { DEBUG ((DEBUG_ERROR, "ERROR - Failed to allocate SpiFlashDataProtocol buffer\r\n")); } else { for (HandleIndex = 0; HandleCount > HandleIndex; HandleIndex++) { Status = gBS->OpenProtocol ( HandleArray [HandleIndex], &gSpiFlashPartProtocolGuid, (VOID **) &SpiFlashPartProtocol [HandleIndex], NULL, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL ); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "ERROR - Failed to open SPI_FLASH_DATA_PROTOCOL, Status: %r\r\n", Status)); break; } } if (!EFI_ERROR (Status)) { // // Allocate the JEDEC ID buffer // BufferLength = 0; for (HandleIndex = 0; HandleCount > HandleIndex; HandleIndex++) { // // Get the JEDEC ID opcode description // Protocol = SpiFlashPartProtocol [HandleIndex]; Description = Protocol->GetFlashDescription ( Protocol, NULL, NULL ); if (BufferLength < Description->JededIdResponseLengthInBytes) { BufferLength = Description->JededIdResponseLengthInBytes; } } JedecId = AllocatePool (BufferLength); if (JedecId == NULL) { DEBUG ((DEBUG_ERROR, "ERROR - Failed to allocate JedecId buffer\r\n")); } else { // // Start with the first flash type description; // MaxPriority = 0xffffffff; do { // // Determine the highest priority protocol // Priority = 0; for (HandleIndex = 0; HandleCount > HandleIndex; HandleIndex++) { Protocol = SpiFlashPartProtocol [HandleIndex]; if ((MaxPriority >= Protocol->Priority) && (Priority < Protocol->Priority)) Priority = Protocol->Priority; } if (Priority == 0) { // // The flash is not supported // break; } // // Walk the handles containing the SPI flash part protocol // HandleIndex = 0; do { // // Verify the description type matches and the opcode table // supports the minimum number of entries required for the code // Protocol = SpiFlashPartProtocol [HandleIndex]; if (Priority == Protocol->Priority) { // // Get the JEDEC ID opcode description // Description = Protocol->GetFlashDescription ( Protocol, NULL, NULL ); if ((Description == NULL) || (SPI_FLASH_PART_OPCODE_JEDEC_ID == Description->OpcodeTableEntries)) { DEBUG ((DEBUG_ERROR, "ERROR - JEDEC ID opcode not available\r\n")); } else { // // Display the flash part // DEBUG ((DEBUG_INFO, "Priority: 0x%08x, SPI Flash Part: %s\r\n", Priority, Description->PartNumber )); // // Attempt to read the JEDEC ID // Status = PerformJedecIdOperation ( Context, Description, Description->JededIdResponseLengthInBytes, JedecId ); if (!EFI_ERROR (Status)) { // // Display the JEDEC ID // DEBUG_CODE_BEGIN (); { UINTN Index; DEBUG ((DEBUG_INFO, "JEDEC ID:")); for (Index = 0; Description->JededIdResponseLengthInBytes > Index; Index++) { DEBUG ((DEBUG_INFO, " 0x%02x", JedecId [Index])); } DEBUG ((DEBUG_INFO, "\r\n")); } DEBUG_CODE_END (); // // Verify support and determine flash size // Description = Protocol->GetFlashDescription ( Protocol, JedecId, &FlashSize ); if (Description != NULL) { // // The flash device is supported // Return the table for this flash device // DEBUG ((DEBUG_INFO, "SPI flash device found: %s\r\n", Description->PartNumber)); *FlashDescription = Description; goto PartFound; } } } } // // Set next handle // HandleIndex += 1; } while (HandleCount > HandleIndex); // // Set the next priority // MaxPriority = Priority - 1; } while (Priority != 0); // // No flash device found // DEBUG ((DEBUG_ERROR, "Matching SPI flash description not found\r\n")); } } } } PartFound: // // Free the buffers // if (JedecId != NULL) { FreePool (JedecId); } if (SpiFlashPartProtocol != NULL) { FreePool (SpiFlashPartProtocol); } if (HandleArray != NULL) { FreePool (HandleArray); } // // Return the flash size // Zero (0) indicates flash not found or not supported // return FlashSize; }
/** Initialize the state information for the CPU Architectural Protocol @param ImageHandle of the loaded driver @param SystemTable Pointer to the System Table @retval EFI_SUCCESS Protocol registered @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure @retval EFI_DEVICE_ERROR Hardware problems **/ EFI_STATUS InterruptDxeInitialize ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_STATUS Status; UINTN Index; UINT32 RegOffset; UINTN RegShift; EFI_CPU_ARCH_PROTOCOL *Cpu; UINT32 CpuTarget; // Check PcdGicPrimaryCoreId has been set in case the Primary Core is not the core 0 of Cluster 0 DEBUG_CODE_BEGIN(); if ((PcdGet32(PcdArmPrimaryCore) != 0) && (PcdGet32 (PcdGicPrimaryCoreId) == 0)) { DEBUG((EFI_D_WARN,"Warning: the PCD PcdGicPrimaryCoreId does not seem to be set up for the configuration.\n")); } DEBUG_CODE_END(); // Make sure the Interrupt Controller Protocol is not already installed in the system. ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gHardwareInterruptProtocolGuid); mGicNumInterrupts = ArmGicGetMaxNumInterrupts (PcdGet32(PcdGicDistributorBase)); for (Index = 0; Index < mGicNumInterrupts; Index++) { DisableInterruptSource (&gHardwareInterruptProtocol, Index); // Set Priority RegOffset = Index / 4; RegShift = (Index % 4) * 8; MmioAndThenOr32 ( PcdGet32(PcdGicDistributorBase) + ARM_GIC_ICDIPR + (4*RegOffset), ~(0xff << RegShift), ARM_GIC_DEFAULT_PRIORITY << RegShift ); } // Configure interrupts for Primary Cpu CpuTarget = (1 << PcdGet32 (PcdGicPrimaryCoreId)); CpuTarget |= CpuTarget << 16; for (Index = 0; Index < (mGicNumInterrupts / 2); Index++) { MmioWrite32 (PcdGet32(PcdGicDistributorBase) + ARM_GIC_ICDIPTR + (Index*4), CpuTarget); } // Set binary point reg to 0x7 (no preemption) MmioWrite32 (PcdGet32(PcdGicInterruptInterfaceBase) + ARM_GIC_ICCBPR, 0x7); // Set priority mask reg to 0xff to allow all priorities through MmioWrite32 (PcdGet32(PcdGicInterruptInterfaceBase) + ARM_GIC_ICCPMR, 0xff); // Enable gic cpu interface MmioWrite32 (PcdGet32(PcdGicInterruptInterfaceBase) + ARM_GIC_ICCICR, 0x1); // Enable gic distributor MmioWrite32 (PcdGet32(PcdGicDistributorBase) + ARM_GIC_ICDDCR, 0x1); // Initialize the array for the Interrupt Handlers gRegisteredInterruptHandlers = (HARDWARE_INTERRUPT_HANDLER*)AllocateZeroPool (sizeof(HARDWARE_INTERRUPT_HANDLER) * mGicNumInterrupts); Status = gBS->InstallMultipleProtocolInterfaces ( &gHardwareInterruptHandle, &gHardwareInterruptProtocolGuid, &gHardwareInterruptProtocol, NULL ); ASSERT_EFI_ERROR (Status); // // Get the CPU protocol that this driver requires. // Status = gBS->LocateProtocol(&gEfiCpuArchProtocolGuid, NULL, (VOID **)&Cpu); ASSERT_EFI_ERROR(Status); // // Unregister the default exception handler. // Status = Cpu->RegisterInterruptHandler(Cpu, EXCEPT_ARM_IRQ, NULL); ASSERT_EFI_ERROR(Status); // // Register to receive interrupts // Status = Cpu->RegisterInterruptHandler(Cpu, EXCEPT_ARM_IRQ, IrqInterruptHandler); ASSERT_EFI_ERROR(Status); // Register for an ExitBootServicesEvent Status = gBS->CreateEvent (EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_NOTIFY, ExitBootServicesEvent, NULL, &EfiExitBootServicesEvent); ASSERT_EFI_ERROR (Status); return Status; }
/** Main entry point to DXE Core. @param HobStart Pointer to the beginning of the HOB List from PEI. @return This function should never return. **/ VOID EFIAPI DxeMain ( IN VOID *HobStart ) { EFI_STATUS Status; EFI_PHYSICAL_ADDRESS MemoryBaseAddress; UINT64 MemoryLength; PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; UINTN Index; EFI_HOB_GUID_TYPE *GuidHob; EFI_VECTOR_HANDOFF_INFO *VectorInfoList; EFI_VECTOR_HANDOFF_INFO *VectorInfo; VOID *EntryPoint; // // Setup the default exception handlers // VectorInfoList = NULL; GuidHob = GetNextGuidHob (&gEfiVectorHandoffInfoPpiGuid, HobStart); if (GuidHob != NULL) { VectorInfoList = (EFI_VECTOR_HANDOFF_INFO *) (GET_GUID_HOB_DATA(GuidHob)); } Status = InitializeCpuExceptionHandlers (VectorInfoList); ASSERT_EFI_ERROR (Status); // // Initialize Debug Agent to support source level debug in DXE phase // InitializeDebugAgent (DEBUG_AGENT_INIT_DXE_CORE, HobStart, NULL); // // Initialize Memory Services // CoreInitializeMemoryServices (&HobStart, &MemoryBaseAddress, &MemoryLength); MemoryProfileInit (HobStart); // // Allocate the EFI System Table and EFI Runtime Service Table from EfiRuntimeServicesData // Use the templates to initialize the contents of the EFI System Table and EFI Runtime Services Table // gDxeCoreST = AllocateRuntimeCopyPool (sizeof (EFI_SYSTEM_TABLE), &mEfiSystemTableTemplate); ASSERT (gDxeCoreST != NULL); gDxeCoreRT = AllocateRuntimeCopyPool (sizeof (EFI_RUNTIME_SERVICES), &mEfiRuntimeServicesTableTemplate); ASSERT (gDxeCoreRT != NULL); gDxeCoreST->RuntimeServices = gDxeCoreRT; // // Start the Image Services. // Status = CoreInitializeImageServices (HobStart); ASSERT_EFI_ERROR (Status); // // Initialize the Global Coherency Domain Services // Status = CoreInitializeGcdServices (&HobStart, MemoryBaseAddress, MemoryLength); ASSERT_EFI_ERROR (Status); // // Call constructor for all libraries // ProcessLibraryConstructorList (gDxeCoreImageHandle, gDxeCoreST); PERF_END (NULL,"PEI", NULL, 0) ; PERF_START (NULL,"DXE", NULL, 0) ; // // Report DXE Core image information to the PE/COFF Extra Action Library // ZeroMem (&ImageContext, sizeof (ImageContext)); ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)gDxeCoreLoadedImage->ImageBase; ImageContext.PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*)(UINTN)ImageContext.ImageAddress); ImageContext.SizeOfHeaders = PeCoffGetSizeOfHeaders ((VOID*)(UINTN)ImageContext.ImageAddress); Status = PeCoffLoaderGetEntryPoint ((VOID*)(UINTN)ImageContext.ImageAddress, &EntryPoint); if (Status == EFI_SUCCESS) { ImageContext.EntryPoint = (EFI_PHYSICAL_ADDRESS)(UINTN)EntryPoint; } ImageContext.Handle = (VOID *)(UINTN)gDxeCoreLoadedImage->ImageBase; ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory; PeCoffLoaderRelocateImageExtraAction (&ImageContext); // // Install the DXE Services Table into the EFI System Tables's Configuration Table // Status = CoreInstallConfigurationTable (&gEfiDxeServicesTableGuid, gDxeCoreDS); ASSERT_EFI_ERROR (Status); // // Install the HOB List into the EFI System Tables's Configuration Table // Status = CoreInstallConfigurationTable (&gEfiHobListGuid, HobStart); ASSERT_EFI_ERROR (Status); // // Install Memory Type Information Table into the EFI System Tables's Configuration Table // Status = CoreInstallConfigurationTable (&gEfiMemoryTypeInformationGuid, &gMemoryTypeInformation); ASSERT_EFI_ERROR (Status); // // If Loading modules At fixed address feature is enabled, install Load moduels at fixed address // Configuration Table so that user could easily to retrieve the top address to load Dxe and PEI // Code and Tseg base to load SMM driver. // if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) { Status = CoreInstallConfigurationTable (&gLoadFixedAddressConfigurationTableGuid, &gLoadModuleAtFixAddressConfigurationTable); ASSERT_EFI_ERROR (Status); } // // Report Status Code here for DXE_ENTRY_POINT once it is available // REPORT_STATUS_CODE ( EFI_PROGRESS_CODE, (EFI_SOFTWARE_DXE_CORE | EFI_SW_DXE_CORE_PC_ENTRY_POINT) ); // // Create the aligned system table pointer structure that is used by external // debuggers to locate the system table... Also, install debug image info // configuration table. // CoreInitializeDebugImageInfoTable (); CoreNewDebugImageInfoEntry ( EFI_DEBUG_IMAGE_INFO_TYPE_NORMAL, gDxeCoreLoadedImage, gDxeCoreImageHandle ); DEBUG ((DEBUG_INFO | DEBUG_LOAD, "HOBLIST address in DXE = 0x%p\n", HobStart)); DEBUG_CODE_BEGIN (); EFI_PEI_HOB_POINTERS Hob; for (Hob.Raw = HobStart; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) { if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_MEMORY_ALLOCATION) { DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Memory Allocation 0x%08x 0x%0lx - 0x%0lx\n", \ Hob.MemoryAllocation->AllocDescriptor.MemoryType, \ Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress, \ Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress + Hob.MemoryAllocation->AllocDescriptor.MemoryLength - 1)); } } for (Hob.Raw = HobStart; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) { if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_FV2) { DEBUG ((DEBUG_INFO | DEBUG_LOAD, "FV2 Hob 0x%0lx - 0x%0lx\n", Hob.FirmwareVolume2->BaseAddress, Hob.FirmwareVolume2->BaseAddress + Hob.FirmwareVolume2->Length - 1)); } else if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_FV) { DEBUG ((DEBUG_INFO | DEBUG_LOAD, "FV Hob 0x%0lx - 0x%0lx\n", Hob.FirmwareVolume->BaseAddress, Hob.FirmwareVolume->BaseAddress + Hob.FirmwareVolume->Length - 1)); } } DEBUG_CODE_END (); // // Initialize the Event Services // Status = CoreInitializeEventServices (); ASSERT_EFI_ERROR (Status); MemoryProfileInstallProtocol (); CoreInitializePropertiesTable (); CoreInitializeMemoryAttributesTable (); // // Get persisted vector hand-off info from GUIDeed HOB again due to HobStart may be updated, // and install configuration table // GuidHob = GetNextGuidHob (&gEfiVectorHandoffInfoPpiGuid, HobStart); if (GuidHob != NULL) { VectorInfoList = (EFI_VECTOR_HANDOFF_INFO *) (GET_GUID_HOB_DATA(GuidHob)); VectorInfo = VectorInfoList; Index = 1; while (VectorInfo->Attribute != EFI_VECTOR_HANDOFF_LAST_ENTRY) { VectorInfo ++; Index ++; } VectorInfo = AllocateCopyPool (sizeof (EFI_VECTOR_HANDOFF_INFO) * Index, (VOID *) VectorInfoList); ASSERT (VectorInfo != NULL); Status = CoreInstallConfigurationTable (&gEfiVectorHandoffTableGuid, (VOID *) VectorInfo); ASSERT_EFI_ERROR (Status); } // // Get the Protocols that were passed in from PEI to DXE through GUIDed HOBs // // These Protocols are not architectural. This implementation is sharing code between // PEI and DXE in order to save FLASH space. These Protocols could also be implemented // as part of the DXE Core. However, that would also require the DXE Core to be ported // each time a different CPU is used, a different Decompression algorithm is used, or a // different Image type is used. By placing these Protocols in PEI, the DXE Core remains // generic, and only PEI and the Arch Protocols need to be ported from Platform to Platform, // and from CPU to CPU. // // // Publish the EFI, Tiano, and Custom Decompress protocols for use by other DXE components // Status = CoreInstallMultipleProtocolInterfaces ( &mDecompressHandle, &gEfiDecompressProtocolGuid, &gEfiDecompress, NULL ); ASSERT_EFI_ERROR (Status); // // Register for the GUIDs of the Architectural Protocols, so the rest of the // EFI Boot Services and EFI Runtime Services tables can be filled in. // Also register for the GUIDs of optional protocols. // CoreNotifyOnProtocolInstallation (); // // Produce Firmware Volume Protocols, one for each FV in the HOB list. // Status = FwVolBlockDriverInit (gDxeCoreImageHandle, gDxeCoreST); ASSERT_EFI_ERROR (Status); Status = FwVolDriverInit (gDxeCoreImageHandle, gDxeCoreST); ASSERT_EFI_ERROR (Status); // // Produce the Section Extraction Protocol // Status = InitializeSectionExtraction (gDxeCoreImageHandle, gDxeCoreST); ASSERT_EFI_ERROR (Status); // // Initialize the DXE Dispatcher // PERF_START (NULL,"CoreInitializeDispatcher", "DxeMain", 0) ; CoreInitializeDispatcher (); PERF_END (NULL,"CoreInitializeDispatcher", "DxeMain", 0) ; // // Invoke the DXE Dispatcher // PERF_START (NULL, "CoreDispatcher", "DxeMain", 0); CoreDispatcher (); PERF_END (NULL, "CoreDispatcher", "DxeMain", 0); // // Display Architectural protocols that were not loaded if this is DEBUG build // DEBUG_CODE_BEGIN (); CoreDisplayMissingArchProtocols (); DEBUG_CODE_END (); // // Display any drivers that were not dispatched because dependency expression // evaluated to false if this is a debug build // DEBUG_CODE_BEGIN (); CoreDisplayDiscoveredNotDispatched (); DEBUG_CODE_END (); // // Assert if the Architectural Protocols are not present. // Status = CoreAllEfiServicesAvailable (); if (EFI_ERROR(Status)) { // // Report Status code that some Architectural Protocols are not present. // REPORT_STATUS_CODE ( EFI_ERROR_CODE | EFI_ERROR_MAJOR, (EFI_SOFTWARE_DXE_CORE | EFI_SW_DXE_CORE_EC_NO_ARCH) ); } ASSERT_EFI_ERROR (Status); // // Report Status code before transfer control to BDS // REPORT_STATUS_CODE ( EFI_PROGRESS_CODE, (EFI_SOFTWARE_DXE_CORE | EFI_SW_DXE_CORE_PC_HANDOFF_TO_NEXT) ); // // Transfer control to the BDS Architectural Protocol // gBds->Entry (gBds); // // BDS should never return // ASSERT (FALSE); CpuDeadLoop (); UNREACHABLE (); }
STATIC EFI_STATUS SelectBootDevice ( OUT BDS_SUPPORTED_DEVICE** SupportedBootDevice ) { EFI_STATUS Status; LIST_ENTRY SupportedDeviceList; UINTN SupportedDeviceCount; LIST_ENTRY* Entry; UINTN SupportedDeviceSelected; UINTN Index; // // List the Boot Devices supported // // Start all the drivers first BdsConnectAllDrivers (); // List the supported devices Status = BootDeviceListSupportedInit (&SupportedDeviceList); ASSERT_EFI_ERROR(Status); SupportedDeviceCount = 0; for (Entry = GetFirstNode (&SupportedDeviceList); !IsNull (&SupportedDeviceList,Entry); Entry = GetNextNode (&SupportedDeviceList,Entry) ) { *SupportedBootDevice = SUPPORTED_BOOT_DEVICE_FROM_LINK(Entry); Print(L"[%d] %s\n",SupportedDeviceCount+1,(*SupportedBootDevice)->Description); DEBUG_CODE_BEGIN(); CHAR16* DevicePathTxt; EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol; Status = gBS->LocateProtocol (&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol); ASSERT_EFI_ERROR(Status); DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText ((*SupportedBootDevice)->DevicePathProtocol,TRUE,TRUE); Print(L"\t- %s\n",DevicePathTxt); FreePool(DevicePathTxt); DEBUG_CODE_END(); SupportedDeviceCount++; } if (SupportedDeviceCount == 0) { Print(L"There is no supported device.\n"); Status = EFI_ABORTED; goto EXIT; } // // Select the Boot Device // SupportedDeviceSelected = 0; while (SupportedDeviceSelected == 0) { Print(L"Select the Boot Device: "); Status = GetHIInputInteger (&SupportedDeviceSelected); if (EFI_ERROR(Status)) { Status = EFI_ABORTED; goto EXIT; } else if ((SupportedDeviceSelected == 0) || (SupportedDeviceSelected > SupportedDeviceCount)) { Print(L"Invalid input (max %d)\n",SupportedDeviceCount); SupportedDeviceSelected = 0; } } // // Get the Device Path for the selected boot device // Index = 1; for (Entry = GetFirstNode (&SupportedDeviceList); !IsNull (&SupportedDeviceList,Entry); Entry = GetNextNode (&SupportedDeviceList,Entry) ) { if (Index == SupportedDeviceSelected) { *SupportedBootDevice = SUPPORTED_BOOT_DEVICE_FROM_LINK(Entry); break; } Index++; } EXIT: BootDeviceListSupportedFree (&SupportedDeviceList, *SupportedBootDevice); return Status; }
/** The security handler is used to abstract platform-specific policy from the DXE core response to an attempt to use a file that returns a given status for the authentication check from the section extraction protocol. The possible responses in a given SAP implementation may include locking flash upon failure to authenticate, attestation logging for all signed drivers, and other exception operations. The File parameter allows for possible logging within the SAP of the driver. If File is NULL, then EFI_INVALID_PARAMETER is returned. If the file specified by File with an authentication status specified by AuthenticationStatus is safe for the DXE Core to use, then EFI_SUCCESS is returned. If the file specified by File with an authentication status specified by AuthenticationStatus is not safe for the DXE Core to use under any circumstances, then EFI_ACCESS_DENIED is returned. If the file specified by File with an authentication status specified by AuthenticationStatus is not safe for the DXE Core to use right now, but it might be possible to use it at a future time, then EFI_SECURITY_VIOLATION is returned. @param[in] AuthenticationStatus This is the authentication status returned from the securitymeasurement services for the input file. @param[in] File This is a pointer to the device path of the file that is being dispatched. This will optionally be used for logging. @param[in] FileBuffer File buffer matches the input file device path. @param[in] FileSize Size of File buffer matches the input file device path. @param[in] BootPolicy A boot policy that was used to call LoadImage() UEFI service. @retval EFI_SUCCESS The file specified by DevicePath and non-NULL FileBuffer did authenticate, and the platform policy dictates that the DXE Foundation may use the file. @retval other error value **/ EFI_STATUS EFIAPI DxeTpmMeasureBootHandler ( IN UINT32 AuthenticationStatus, IN CONST EFI_DEVICE_PATH_PROTOCOL *File, IN VOID *FileBuffer, IN UINTN FileSize, IN BOOLEAN BootPolicy ) { EFI_TCG_PROTOCOL *TcgProtocol; EFI_STATUS Status; TCG_EFI_BOOT_SERVICE_CAPABILITY ProtocolCapability; UINT32 TCGFeatureFlags; EFI_PHYSICAL_ADDRESS EventLogLocation; EFI_PHYSICAL_ADDRESS EventLogLastEntry; EFI_DEVICE_PATH_PROTOCOL *DevicePathNode; EFI_DEVICE_PATH_PROTOCOL *OrigDevicePathNode; EFI_HANDLE Handle; EFI_HANDLE TempHandle; BOOLEAN ApplicationRequired; PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol; EFI_PHYSICAL_ADDRESS FvAddress; UINT32 Index; Status = gBS->LocateProtocol (&gEfiTcgProtocolGuid, NULL, (VOID **) &TcgProtocol); if (EFI_ERROR (Status)) { // // TCG protocol is not installed. So, TPM is not present. // Don't do any measurement, and directly return EFI_SUCCESS. // return EFI_SUCCESS; } ProtocolCapability.Size = (UINT8) sizeof (ProtocolCapability); Status = TcgProtocol->StatusCheck ( TcgProtocol, &ProtocolCapability, &TCGFeatureFlags, &EventLogLocation, &EventLogLastEntry ); if (EFI_ERROR (Status) || ProtocolCapability.TPMDeactivatedFlag) { // // TPM device doesn't work or activate. // return EFI_SUCCESS; } // // Copy File Device Path // OrigDevicePathNode = DuplicateDevicePath (File); // // 1. Check whether this device path support BlockIo protocol. // Is so, this device path may be a GPT device path. // DevicePathNode = OrigDevicePathNode; Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &DevicePathNode, &Handle); if (!EFI_ERROR (Status) && !mMeasureGptTableFlag) { // // Find the gpt partion on the given devicepath // DevicePathNode = OrigDevicePathNode; ASSERT (DevicePathNode != NULL); while (!IsDevicePathEnd (DevicePathNode)) { // // Find the Gpt partition // if (DevicePathType (DevicePathNode) == MEDIA_DEVICE_PATH && DevicePathSubType (DevicePathNode) == MEDIA_HARDDRIVE_DP) { // // Check whether it is a gpt partition or not // if (((HARDDRIVE_DEVICE_PATH *) DevicePathNode)->MBRType == MBR_TYPE_EFI_PARTITION_TABLE_HEADER && ((HARDDRIVE_DEVICE_PATH *) DevicePathNode)->SignatureType == SIGNATURE_TYPE_GUID) { // // Change the partition device path to its parent device path (disk) and get the handle. // DevicePathNode->Type = END_DEVICE_PATH_TYPE; DevicePathNode->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE; DevicePathNode = OrigDevicePathNode; Status = gBS->LocateDevicePath ( &gEfiDiskIoProtocolGuid, &DevicePathNode, &Handle ); if (!EFI_ERROR (Status)) { // // Measure GPT disk. // Status = TcgMeasureGptTable (TcgProtocol, Handle); if (!EFI_ERROR (Status)) { // // GPT disk check done. // mMeasureGptTableFlag = TRUE; } } FreePool (OrigDevicePathNode); OrigDevicePathNode = DuplicateDevicePath (File); ASSERT (OrigDevicePathNode != NULL); break; } } DevicePathNode = NextDevicePathNode (DevicePathNode); } } // // 2. Measure PE image. // ApplicationRequired = FALSE; // // Check whether this device path support FVB protocol. // DevicePathNode = OrigDevicePathNode; Status = gBS->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid, &DevicePathNode, &Handle); if (!EFI_ERROR (Status)) { // // Don't check FV image, and directly return EFI_SUCCESS. // It can be extended to the specific FV authentication according to the different requirement. // if (IsDevicePathEnd (DevicePathNode)) { return EFI_SUCCESS; } // // The PE image from unmeasured Firmware volume need be measured // The PE image from measured Firmware volume will be mearsured according to policy below. // If it is driver, do not measure // If it is application, still measure. // ApplicationRequired = TRUE; if (mCacheMeasuredHandle != Handle && mMeasuredHobData != NULL) { // // Search for Root FV of this PE image // TempHandle = Handle; do { Status = gBS->HandleProtocol( TempHandle, &gEfiFirmwareVolumeBlockProtocolGuid, (VOID**)&FvbProtocol ); TempHandle = FvbProtocol->ParentHandle; } while (!EFI_ERROR(Status) && FvbProtocol->ParentHandle != NULL); // // Search in measured FV Hob // Status = FvbProtocol->GetPhysicalAddress(FvbProtocol, &FvAddress); if (EFI_ERROR(Status)){ return Status; } ApplicationRequired = FALSE; for (Index = 0; Index < mMeasuredHobData->Num; Index++) { if(mMeasuredHobData->MeasuredFvBuf[Index].BlobBase == FvAddress) { // // Cache measured FV for next measurement // mCacheMeasuredHandle = Handle; ApplicationRequired = TRUE; break; } } } } // // File is not found. // if (FileBuffer == NULL) { Status = EFI_SECURITY_VIOLATION; goto Finish; } mImageSize = FileSize; mFileBuffer = FileBuffer; // // Measure PE Image // DevicePathNode = OrigDevicePathNode; ZeroMem (&ImageContext, sizeof (ImageContext)); ImageContext.Handle = (VOID *) FileBuffer; ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) DxeTpmMeasureBootLibImageRead; // // Get information about the image being loaded // Status = PeCoffLoaderGetImageInfo (&ImageContext); if (EFI_ERROR (Status)) { // // The information can't be got from the invalid PeImage // goto Finish; } // // Measure only application if Application flag is set // Measure drivers and applications if Application flag is not set // if ((!ApplicationRequired) || (ApplicationRequired && ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION)) { // // Print the image path to be measured. // DEBUG_CODE_BEGIN (); CHAR16 *ToText; ToText = ConvertDevicePathToText ( DevicePathNode, FALSE, TRUE ); if (ToText != NULL) { DEBUG ((DEBUG_INFO, "The measured image path is %s.\n", ToText)); FreePool (ToText); } DEBUG_CODE_END (); // // Measure PE image into TPM log. // Status = TcgMeasurePeImage ( TcgProtocol, (EFI_PHYSICAL_ADDRESS) (UINTN) FileBuffer, FileSize, (UINTN) ImageContext.ImageAddress, ImageContext.ImageType, DevicePathNode ); } // // Done, free the allocated resource. // Finish: if (OrigDevicePathNode != NULL) { FreePool (OrigDevicePathNode); } return Status; }
/** Worker function that displays the list of boot options that is passed in. The function loops over the entries of the list of boot options that is passed in. For each entry, the boot option description is displayed on a single line along with the position of the option in the list. In debug mode, the UEFI device path and the arguments of the boot option are displayed as well in subsequent lines. @param[in] BootOptionsList List of the boot options **/ STATIC VOID DisplayBootOptions ( IN LIST_ENTRY* BootOptionsList ) { EFI_STATUS Status; UINTN BootOptionCount; LIST_ENTRY *Entry; BDS_LOAD_OPTION *BdsLoadOption; BOOLEAN IsUnicode; BootOptionCount = 0 ; for (Entry = GetFirstNode (BootOptionsList); !IsNull (BootOptionsList, Entry); Entry = GetNextNode (BootOptionsList, Entry) ) { BdsLoadOption = LOAD_OPTION_FROM_LINK (Entry); Print (L"[%d] %s\n", ++BootOptionCount, BdsLoadOption->Description); DEBUG_CODE_BEGIN (); CHAR16* DevicePathTxt; EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol; ARM_BDS_LOADER_TYPE LoaderType; ARM_BDS_LOADER_OPTIONAL_DATA* OptionalData; Status = gBS->LocateProtocol ( &gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol ); ASSERT_EFI_ERROR (Status); DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText ( BdsLoadOption->FilePathList, TRUE, TRUE ); Print (L"\t- %s\n", DevicePathTxt); OptionalData = BdsLoadOption->OptionalData; if (IS_ARM_BDS_BOOTENTRY (BdsLoadOption)) { LoaderType = (ARM_BDS_LOADER_TYPE)ReadUnaligned32 ((CONST UINT32*)&OptionalData->Header.LoaderType); if ((LoaderType == BDS_LOADER_KERNEL_LINUX_ATAG) || (LoaderType == BDS_LOADER_KERNEL_LINUX_FDT ) ) { Print (L"\t- Arguments: %a\n", &OptionalData->Arguments.LinuxArguments + 1); } } else if (OptionalData != NULL) { if (IsPrintableString (OptionalData, &IsUnicode)) { if (IsUnicode) { Print (L"\t- Arguments: %s\n", OptionalData); } else { AsciiPrint ("\t- Arguments: %a\n", OptionalData); } } } FreePool (DevicePathTxt); DEBUG_CODE_END (); } }
EFI_STATUS BootMenuMain ( VOID ) { LIST_ENTRY BootOptionsList; UINTN OptionCount; UINTN BootOptionCount; EFI_STATUS Status; LIST_ENTRY* Entry; BDS_LOAD_OPTION* BootOption; UINTN BootOptionSelected; UINTN Index; UINTN BootMainEntryCount; BOOLEAN IsUnicode; BootOption = NULL; BootMainEntryCount = sizeof(BootMainEntries) / sizeof(struct BOOT_MAIN_ENTRY); while (TRUE) { // Get Boot#### list BootOptionList (&BootOptionsList); OptionCount = 1; // Display the Boot options for (Entry = GetFirstNode (&BootOptionsList); !IsNull (&BootOptionsList,Entry); Entry = GetNextNode (&BootOptionsList,Entry) ) { BootOption = LOAD_OPTION_FROM_LINK(Entry); Print(L"[%d] %s\n", OptionCount, BootOption->Description); DEBUG_CODE_BEGIN(); CHAR16* DevicePathTxt; EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol; ARM_BDS_LOADER_OPTIONAL_DATA* OptionalData; UINTN CmdLineSize; ARM_BDS_LOADER_TYPE LoaderType; Status = gBS->LocateProtocol (&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol); if (EFI_ERROR(Status)) { // You must provide an implementation of DevicePathToTextProtocol in your firmware (eg: DevicePathDxe) DEBUG((EFI_D_ERROR,"Error: Bds requires DevicePathToTextProtocol\n")); return Status; } DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText (BootOption->FilePathList, TRUE, TRUE); Print(L"\t- %s\n",DevicePathTxt); // If it is a supported BootEntry then print its details if (IS_ARM_BDS_BOOTENTRY (BootOption)) { OptionalData = BootOption->OptionalData; LoaderType = (ARM_BDS_LOADER_TYPE)ReadUnaligned32 ((CONST UINT32*)&OptionalData->Header.LoaderType); if ((LoaderType == BDS_LOADER_KERNEL_LINUX_ATAG) || (LoaderType == BDS_LOADER_KERNEL_LINUX_FDT)) { if (ReadUnaligned16 (&OptionalData->Arguments.LinuxArguments.InitrdSize) > 0) { CmdLineSize = ReadUnaligned16 (&OptionalData->Arguments.LinuxArguments.CmdLineSize); DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText ( GetAlignedDevicePath ((EFI_DEVICE_PATH*)((UINTN)(&OptionalData->Arguments.LinuxArguments + 1) + CmdLineSize)), TRUE, TRUE); Print(L"\t- Initrd: %s\n", DevicePathTxt); } if (ReadUnaligned16 (&OptionalData->Arguments.LinuxArguments.CmdLineSize) > 0) { Print(L"\t- Arguments: %a\n", (&OptionalData->Arguments.LinuxArguments + 1)); } } switch (LoaderType) { case BDS_LOADER_EFI_APPLICATION: Print(L"\t- LoaderType: EFI Application\n"); break; case BDS_LOADER_KERNEL_LINUX_ATAG: Print(L"\t- LoaderType: Linux kernel with ATAG support\n"); break; case BDS_LOADER_KERNEL_LINUX_FDT: Print(L"\t- LoaderType: Linux kernel with FDT support\n"); break; default: Print(L"\t- LoaderType: Not recognized (%d)\n", LoaderType); } } else if (BootOption->OptionalData != NULL) { if (IsPrintableString (BootOption->OptionalData, &IsUnicode)) { if (IsUnicode) { Print (L"\t- Arguments: %s\n", BootOption->OptionalData); } else { AsciiPrint ("\t- Arguments: %a\n", BootOption->OptionalData); } } } FreePool(DevicePathTxt); DEBUG_CODE_END(); OptionCount++; } BootOptionCount = OptionCount-1; // Display the hardcoded Boot entries for (Index = 0; Index < BootMainEntryCount; Index++) { Print(L"[%d] %s\n",OptionCount,BootMainEntries[Index]); OptionCount++; } // Request the boot entry from the user BootOptionSelected = 0; while (BootOptionSelected == 0) { Print(L"Start: "); Status = GetHIInputInteger (&BootOptionSelected); if (EFI_ERROR(Status) || (BootOptionSelected == 0) || (BootOptionSelected > OptionCount)) { Print(L"Invalid input (max %d)\n",(OptionCount-1)); BootOptionSelected = 0; } } // Start the selected entry if (BootOptionSelected > BootOptionCount) { // Start the hardcoded entry Status = BootMainEntries[BootOptionSelected - BootOptionCount - 1].Callback (&BootOptionsList); } else { // Find the selected entry from the Boot#### list Index = 1; for (Entry = GetFirstNode (&BootOptionsList); !IsNull (&BootOptionsList,Entry); Entry = GetNextNode (&BootOptionsList,Entry) ) { if (Index == BootOptionSelected) { BootOption = LOAD_OPTION_FROM_LINK(Entry); break; } Index++; } Status = BootOptionStart (BootOption); } } // Should never go here }
/** Initializes the VM EFI interface. Allocates memory for the VM interface and registers the VM protocol. @param ImageHandle EFI image handle. @param SystemTable Pointer to the EFI system table. @return Standard EFI status code. **/ EFI_STATUS EFIAPI InitializeEbcDriver ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_EBC_PROTOCOL *EbcProtocol; EFI_EBC_PROTOCOL *OldEbcProtocol; EFI_STATUS Status; EFI_DEBUG_SUPPORT_PROTOCOL *EbcDebugProtocol; EFI_HANDLE *HandleBuffer; UINTN NumHandles; UINTN Index; BOOLEAN Installed; EbcProtocol = NULL; EbcDebugProtocol = NULL; // // Allocate memory for our protocol. Then fill in the blanks. // EbcProtocol = AllocatePool (sizeof (EFI_EBC_PROTOCOL)); if (EbcProtocol == NULL) { return EFI_OUT_OF_RESOURCES; } EbcProtocol->CreateThunk = EbcCreateThunk; EbcProtocol->UnloadImage = EbcUnloadImage; EbcProtocol->RegisterICacheFlush = EbcRegisterICacheFlush; EbcProtocol->GetVersion = EbcGetVersion; mEbcICacheFlush = NULL; // // Find any already-installed EBC protocols and uninstall them // Installed = FALSE; HandleBuffer = NULL; Status = gBS->LocateHandleBuffer ( ByProtocol, &gEfiEbcProtocolGuid, NULL, &NumHandles, &HandleBuffer ); if (Status == EFI_SUCCESS) { // // Loop through the handles // for (Index = 0; Index < NumHandles; Index++) { Status = gBS->HandleProtocol ( HandleBuffer[Index], &gEfiEbcProtocolGuid, (VOID **) &OldEbcProtocol ); if (Status == EFI_SUCCESS) { if (gBS->ReinstallProtocolInterface ( HandleBuffer[Index], &gEfiEbcProtocolGuid, OldEbcProtocol, EbcProtocol ) == EFI_SUCCESS) { Installed = TRUE; } } } } if (HandleBuffer != NULL) { FreePool (HandleBuffer); HandleBuffer = NULL; } // // Add the protocol so someone can locate us if we haven't already. // if (!Installed) { Status = gBS->InstallProtocolInterface ( &ImageHandle, &gEfiEbcProtocolGuid, EFI_NATIVE_INTERFACE, EbcProtocol ); if (EFI_ERROR (Status)) { FreePool (EbcProtocol); return Status; } } Status = InitEBCStack(); if (EFI_ERROR(Status)) { goto ErrorExit; } // // Allocate memory for our debug protocol. Then fill in the blanks. // EbcDebugProtocol = AllocatePool (sizeof (EFI_DEBUG_SUPPORT_PROTOCOL)); if (EbcDebugProtocol == NULL) { goto ErrorExit; } EbcDebugProtocol->Isa = IsaEbc; EbcDebugProtocol->GetMaximumProcessorIndex = EbcDebugGetMaximumProcessorIndex; EbcDebugProtocol->RegisterPeriodicCallback = EbcDebugRegisterPeriodicCallback; EbcDebugProtocol->RegisterExceptionCallback = EbcDebugRegisterExceptionCallback; EbcDebugProtocol->InvalidateInstructionCache = EbcDebugInvalidateInstructionCache; // // Add the protocol so the debug agent can find us // Status = gBS->InstallProtocolInterface ( &ImageHandle, &gEfiDebugSupportProtocolGuid, EFI_NATIVE_INTERFACE, EbcDebugProtocol ); // // This is recoverable, so free the memory and continue. // if (EFI_ERROR (Status)) { FreePool (EbcDebugProtocol); goto ErrorExit; } // // Install EbcDebugSupport Protocol Successfully // Now we need to initialize the Ebc default Callback // Status = InitializeEbcCallback (EbcDebugProtocol); // // Produce a VM test interface protocol. Not required for execution. // DEBUG_CODE_BEGIN (); InitEbcVmTestProtocol (&ImageHandle); DEBUG_CODE_END (); EbcDebuggerHookInit (ImageHandle, EbcDebugProtocol); return EFI_SUCCESS; ErrorExit: FreeEBCStack(); HandleBuffer = NULL; Status = gBS->LocateHandleBuffer ( ByProtocol, &gEfiEbcProtocolGuid, NULL, &NumHandles, &HandleBuffer ); if (Status == EFI_SUCCESS) { // // Loop through the handles // for (Index = 0; Index < NumHandles; Index++) { Status = gBS->HandleProtocol ( HandleBuffer[Index], &gEfiEbcProtocolGuid, (VOID **) &OldEbcProtocol ); if (Status == EFI_SUCCESS) { gBS->UninstallProtocolInterface ( HandleBuffer[Index], &gEfiEbcProtocolGuid, OldEbcProtocol ); } } } if (HandleBuffer != NULL) { FreePool (HandleBuffer); HandleBuffer = NULL; } FreePool (EbcProtocol); return Status; }
/** Loads a PEIM into memory for subsequent execution. If there are compressed images or images that need to be relocated into memory for performance reasons, this service performs that transformation. @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation @param FileHandle Pointer to the FFS file header of the image. @param ImageAddressArg Pointer to PE/TE image. @param ImageSizeArg Size of PE/TE image. @param EntryPoint Pointer to entry point of specified image file for output. @param AuthenticationState - Pointer to attestation authentication state of image. @retval EFI_SUCCESS Image is successfully loaded. @retval EFI_NOT_FOUND Fail to locate necessary PPI. @retval EFI_UNSUPPORTED Image Machine Type is not supported. **/ EFI_STATUS PeiLoadImageLoadImage ( IN CONST EFI_PEI_SERVICES **PeiServices, IN EFI_PEI_FILE_HANDLE FileHandle, OUT EFI_PHYSICAL_ADDRESS *ImageAddressArg, OPTIONAL OUT UINT64 *ImageSizeArg, OPTIONAL OUT EFI_PHYSICAL_ADDRESS *EntryPoint, OUT UINT32 *AuthenticationState ) { EFI_STATUS Status; VOID *Pe32Data; EFI_PHYSICAL_ADDRESS ImageAddress; UINT64 ImageSize; EFI_PHYSICAL_ADDRESS ImageEntryPoint; UINT16 Machine; EFI_SECTION_TYPE SearchType1; EFI_SECTION_TYPE SearchType2; *EntryPoint = 0; ImageSize = 0; *AuthenticationState = 0; if (FeaturePcdGet (PcdPeiCoreImageLoaderSearchTeSectionFirst)) { SearchType1 = EFI_SECTION_TE; SearchType2 = EFI_SECTION_PE32; } else { SearchType1 = EFI_SECTION_PE32; SearchType2 = EFI_SECTION_TE; } // // Try to find a first exe section (if PcdPeiCoreImageLoaderSearchTeSectionFirst // is true, TE will be searched first). // Status = PeiServicesFfsFindSectionData ( SearchType1, FileHandle, &Pe32Data ); // // If we didn't find a first exe section, try to find the second exe section. // if (EFI_ERROR (Status)) { Status = PeiServicesFfsFindSectionData ( SearchType2, FileHandle, &Pe32Data ); if (EFI_ERROR (Status)) { // // PEI core only carry the loader function fro TE and PE32 executables // If this two section does not exist, just return. // return Status; } } // // If memory is installed, perform the shadow operations // Status = LoadAndRelocatePeCoffImage ( Pe32Data, &ImageAddress, &ImageSize, &ImageEntryPoint ); ASSERT_EFI_ERROR (Status); if (EFI_ERROR (Status)) { return Status; } // // Got the entry point from the loaded Pe32Data // Pe32Data = (VOID *) ((UINTN) ImageAddress); *EntryPoint = ImageEntryPoint; Machine = PeCoffLoaderGetMachineType (Pe32Data); if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Machine)) { if (!EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED (Machine)) { return EFI_UNSUPPORTED; } } if (ImageAddressArg != NULL) { *ImageAddressArg = ImageAddress; } if (ImageSizeArg != NULL) { *ImageSizeArg = ImageSize; } DEBUG_CODE_BEGIN (); CHAR8 *AsciiString; CHAR8 AsciiBuffer[512]; INT32 Index; INT32 Index1; // // Print debug message: Loading PEIM at 0x12345678 EntryPoint=0x12345688 Driver.efi // if (Machine != EFI_IMAGE_MACHINE_IA64) { DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Loading PEIM at 0x%11p EntryPoint=0x%11p ", (VOID *)(UINTN)ImageAddress, (VOID *)(UINTN)*EntryPoint)); } else { // // For IPF Image, the real entry point should be print. // DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Loading PEIM at 0x%11p EntryPoint=0x%11p ", (VOID *)(UINTN)ImageAddress, (VOID *)(UINTN)(*(UINT64 *)(UINTN)*EntryPoint))); } // // Print Module Name by PeImage PDB file name. // AsciiString = PeCoffLoaderGetPdbPointer (Pe32Data); if (AsciiString != NULL) { for (Index = (INT32) AsciiStrLen (AsciiString) - 1; Index >= 0; Index --) { if (AsciiString[Index] == '\\') { break; } } if (Index != 0) { for (Index1 = 0; AsciiString[Index + 1 + Index1] != '.'; Index1 ++) { AsciiBuffer [Index1] = AsciiString[Index + 1 + Index1]; } AsciiBuffer [Index1] = '\0'; DEBUG ((EFI_D_INFO | EFI_D_LOAD, "%a.efi", AsciiBuffer)); } } DEBUG_CODE_END (); DEBUG ((EFI_D_INFO | EFI_D_LOAD, "\n")); return EFI_SUCCESS; }