From: oliviermartin Date: Sat, 11 Jun 2011 11:56:30 +0000 (+0000) Subject: ArmPkg/BdsLib: Upgrade the library to use natively the Device Path X-Git-Tag: edk2-stable201903~14708 X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=commitdiff_plain;h=a355a3654f0af22db9f68d988dbb4c72b835f414 ArmPkg/BdsLib: Upgrade the library to use natively the Device Path The previous version was using the string representation of the Device Path. This new version takes as paramater the binary representation of the Device Path It also tries to detect which kind of device support it refers by using the remaining part of the Device Path after it has been loaded by gBS->ConnectController() Lots of bug have been fixed as well in this new version. git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@11799 6f19259b-4bc3-4df7-8a09-765794883524 --- diff --git a/ArmPkg/ArmPkg.dec b/ArmPkg/ArmPkg.dec index 37fc7f2931..0357810c56 100644 --- a/ArmPkg/ArmPkg.dec +++ b/ArmPkg/ArmPkg.dec @@ -125,7 +125,8 @@ # BdsLib # gArmTokenSpaceGuid.PcdArmMachineType|0|UINT32|0x0000001E - gArmTokenSpaceGuid.PcdLinuxKernelDP|L""|VOID*|0x0000001F - gArmTokenSpaceGuid.PcdLinuxAtag|""|VOID*|0x00000020 - gArmTokenSpaceGuid.PcdFdtDP|L""|VOID*|0x00000021 + # The compressed Linux kernel is expected to be under 128MB from the beginning of the System Memory + gArmTokenSpaceGuid.PcdArmLinuxKernelMaxOffset|0x08000000|UINT32|0x0000001F + # The Linux ATAGs are expected to be under 0x4000 (16KB) from the beginning of the System Memory + gArmTokenSpaceGuid.PcdArmLinuxAtagMaxOffset|0x4000|UINT32|0x00000020 diff --git a/ArmPkg/Include/Library/BdsLib.h b/ArmPkg/Include/Library/BdsLib.h new file mode 100644 index 0000000000..a6ae2f108b --- /dev/null +++ b/ArmPkg/Include/Library/BdsLib.h @@ -0,0 +1,66 @@ +/** @file +* +* Copyright (c) 2011, ARM Limited. All rights reserved. +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the BSD License +* which accompanies this distribution. The full text of the license may be found at +* http://opensource.org/licenses/bsd-license.php +* +* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +* +**/ + +#ifndef __BDS_ENTRY_H__ +#define __BDS_ENTRY_H__ + +/** + Connect all DXE drivers + + @retval EFI_SUCCESS All drivers have been connected + @retval EFI_NOT_FOUND No handles match the search. + @retval EFI_OUT_OF_RESOURCES There is not resource pool memory to store the matching results. + +**/ +EFI_STATUS +BdsConnectAllDrivers ( + VOID + ); + +/** + Start a Linux kernel from a Device Path + + @param LinuxKernel Device Path to the Linux Kernel + @param Parameters Linux kernel agruments + @param Fdt Device Path to the Flat Device Tree + + @retval EFI_SUCCESS All drivers have been connected + @retval EFI_NOT_FOUND The Linux kernel Device Path has not been found + @retval EFI_OUT_OF_RESOURCES There is not enough resource memory to store the matching results. + +**/ +EFI_STATUS +BdsBootLinux ( + IN EFI_DEVICE_PATH_PROTOCOL* LinuxKernelDevicePath, + IN CONST CHAR8* Arguments, + IN EFI_DEVICE_PATH_PROTOCOL* FdtDevicePath + ); + +/** + Start an EFI Application from any Firmware Volume + + @param EfiApp EFI Application Name + + @retval EFI_SUCCESS All drivers have been connected + @retval EFI_NOT_FOUND The Linux kernel Device Path has not been found + @retval EFI_OUT_OF_RESOURCES There is not enough resource memory to store the matching results. + +**/ +EFI_STATUS +BdsLoadApplication ( + IN EFI_HANDLE ParentImageHandle, + IN CHAR16* EfiApp + ); + +#endif diff --git a/ArmPkg/Include/Library/BdsUnixLib.h b/ArmPkg/Include/Library/BdsUnixLib.h index 969f951124..d5f5ffa202 100644 --- a/ArmPkg/Include/Library/BdsUnixLib.h +++ b/ArmPkg/Include/Library/BdsUnixLib.h @@ -12,27 +12,26 @@ * **/ -#ifndef __BDS_ENTRY_H__ -#define __BDS_ENTRY_H__ +#ifndef _BDS_UNIX_LIB_H_ +#define _BDS_UNIX_LIB_H_ -EFI_STATUS -BdsConnectAllDrivers ( VOID ); +/** + Start a Linux kernel from a Device Path -EFI_STATUS -BdsBootLinux ( - IN CONST CHAR16* LinuxKernel, - IN CONST CHAR8* ATag, - IN CONST CHAR16* Fdt -); + @param LinuxKernel Device Path to the Linux Kernel + @param Parameters Linux kernel agruments + @param Fdt Device Path to the Flat Device Tree -EFI_STATUS -BdsLoadApplication ( - IN CHAR16* EfiApp -); + @retval EFI_SUCCESS All drivers have been connected + @retval EFI_NOT_FOUND The Linux kernel Device Path has not been found + @retval EFI_OUT_OF_RESOURCES There is not enough resource memory to store the matching results. +**/ EFI_STATUS -BdsLoadApplicationFromPath ( - IN CHAR16* EfiAppPath -); +BdsBootLinux ( + IN EFI_DEVICE_PATH_PROTOCOL* LinuxKernelDevicePath, + IN CONST CHAR8* Arguments, + IN EFI_DEVICE_PATH_PROTOCOL* FdtDevicePath + ); #endif diff --git a/ArmPkg/Library/BdsLib/BdsAppLoader.c b/ArmPkg/Library/BdsLib/BdsAppLoader.c index 16b45ceb4c..d14e3c5dcc 100644 --- a/ArmPkg/Library/BdsLib/BdsAppLoader.c +++ b/ArmPkg/Library/BdsLib/BdsAppLoader.c @@ -1,111 +1,217 @@ -/** @file -* -* Copyright (c) 2011, ARM Limited. All rights reserved. -* -* This program and the accompanying materials -* are licensed and made available under the terms and conditions of the BSD License -* which accompanies this distribution. The full text of the license may be found at -* http://opensource.org/licenses/bsd-license.php -* -* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. -* -**/ - -#include "BdsInternal.h" - -EFI_STATUS -BdsLoadPeCoff ( - IN BDS_FILE *EfiAppFile - ) -{ - EFI_STATUS Status; - EFI_HANDLE ImageHandle; - MEDIA_FW_VOL_FILEPATH_DEVICE_PATH NewNode; - EFI_DEVICE_PATH_PROTOCOL *DevicePath; - - // Only support loading from FV right now - ASSERT(EfiAppFile->Type == BDS_FILETYPE_FV); - - // Generate the Device Path for the file - DevicePath = DuplicateDevicePath(EfiAppFile->DevicePath); - EfiInitializeFwVolDevicepathNode (&NewNode, &(EfiAppFile->File.Fv.Guid)); - DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&NewNode); - - Status = gBS->LoadImage (TRUE, gImageHandle, DevicePath, NULL, 0, &ImageHandle); - if (!EFI_ERROR (Status)) { - // - // Before calling the image, enable the Watchdog Timer for - // the 5 Minute period - // - gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL); - Status = gBS->StartImage (ImageHandle, NULL, NULL); - // - // Clear the Watchdog Timer after the image returns - // - gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL); - } - - return Status; -} - -EFI_STATUS BdsLoadApplicationFromPath( - IN CHAR16* EfiAppPath -) { - EFI_STATUS Status; - BDS_FILE EfiAppFile; - - // Need to connect every drivers to ensure no dependencies are missing for the application - Status = BdsConnectAllDrivers(); - if (EFI_ERROR(Status)) { - DEBUG ((EFI_D_ERROR, "FAIL to connect all drivers\n")); - return Status; - } - - // Locate the application from a device path - Status = BdsLoadFilePath(EfiAppPath, &EfiAppFile); - if (EFI_ERROR(Status)) { - DEBUG ((EFI_D_ERROR, "ERROR: Do not find EFI application %s\n",EfiAppPath)); - return Status; - } - - // Start the application - Status = BdsLoadPeCoff(&EfiAppFile); - - return Status; -} - -EFI_STATUS BdsLoadApplication( - IN CHAR16* EfiApp -) { - EFI_STATUS Status; - UINTN NoHandles, HandleIndex; - EFI_HANDLE *Handles; - BDS_FILE EfiAppFile; - - // Need to connect every drivers to ensure no dependencies are missing for the application - Status = BdsConnectAllDrivers(); - if (EFI_ERROR(Status)) { - DEBUG ((EFI_D_ERROR, "FAIL to connect all drivers\n")); - return Status; - } - - // Search the application in any Firmware Volume - Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiFirmwareVolume2ProtocolGuid, NULL, &NoHandles, &Handles); - if (EFI_ERROR (Status) || (NoHandles == 0)) { - DEBUG ((EFI_D_ERROR, "FAIL to find Firmware Volume\n")); - return Status; - } - - // Search in all Firmware Volume for the EFI Application - for (HandleIndex = 0; HandleIndex < NoHandles; HandleIndex++) { - Status = BdsLoadFileFromFirmwareVolume(Handles[HandleIndex],EfiApp,EFI_FV_FILETYPE_APPLICATION,&EfiAppFile); - if (!EFI_ERROR (Status)) { - // Start the application - Status = BdsLoadPeCoff(&EfiAppFile); - return Status; - } - } - - return Status; -} +/** @file +* +* Copyright (c) 2011, ARM Limited. All rights reserved. +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the BSD License +* which accompanies this distribution. The full text of the license may be found at +* http://opensource.org/licenses/bsd-license.php +* +* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +* +**/ + +#include "BdsInternal.h" + +//#include +#include + +//TODO: RemoveMe +#include + +/** + Retrieves the magic value from the PE/COFF header. + + @param Hdr The buffer in which to return the PE32, PE32+, or TE header. + + @return EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC - Image is PE32 + @return EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC - Image is PE32+ + +**/ +UINT16 +PeCoffLoaderGetPeHeaderMagicValue ( + IN EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr + ) +{ + // + // NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value + // in the PE/COFF Header. If the MachineType is Itanium(IA64) and the + // Magic value in the OptionalHeader is EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC + // then override the returned value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC + // + if (Hdr.Pe32->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64 && Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + return EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC; + } + // + // Return the magic value from the PC/COFF Optional Header + // + return Hdr.Pe32->OptionalHeader.Magic; +} + +STATIC +BOOLEAN +IsLoadableImage ( + VOID* Image + ) +{ + UINT16 Magic; + EFI_IMAGE_DOS_HEADER *DosHeader; + EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Header; + + if (Image == NULL) { + return FALSE; + } + + DosHeader = (EFI_IMAGE_DOS_HEADER*)Image; + if (DosHeader->e_magic == EFI_IMAGE_DOS_SIGNATURE) { + Header.Pe32 = (EFI_IMAGE_NT_HEADERS32*)((UINT8*)Image + DosHeader->e_lfanew); + } else { + Header.Pe32 = (EFI_IMAGE_NT_HEADERS32*)(Image); + } + + if (Header.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) { + // It is a TE Image + return TRUE; + } else if (Header.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) { + Magic = PeCoffLoaderGetPeHeaderMagicValue (Header); + if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + // It is a PE32 Image + return TRUE; + } else if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) { + // It is a PE32+ Image + return TRUE; + } else { + DEBUG ((EFI_D_ERROR,"BdsLoadBinaryFromPath(): Fail unrecognized PE Image\n")); + } + } else { + DEBUG ((EFI_D_ERROR,"BdsLoadBinaryFromPath(): Fail unrecognize image\n")); + } + + return FALSE; +} + +STATIC +EFI_STATUS +BdsLoadFileFromFirmwareVolume ( + IN EFI_HANDLE FvHandle, + IN CHAR16 *FilePath, + IN EFI_FV_FILETYPE FileTypeFilter, + OUT EFI_DEVICE_PATH **EfiAppDevicePath + ) +{ + EFI_FIRMWARE_VOLUME2_PROTOCOL *FvProtocol; + VOID *Key; + EFI_STATUS Status, FileStatus; + EFI_GUID NameGuid; + EFI_FV_FILETYPE FileType; + EFI_FV_FILE_ATTRIBUTES Attributes; + UINTN Size; + UINTN UiStringLen; + CHAR16 *UiSection; + UINT32 Authentication; + EFI_DEVICE_PATH *FvDevicePath; + MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileDevicePath; + + Status = gBS->HandleProtocol (FvHandle,&gEfiFirmwareVolume2ProtocolGuid, (VOID **)&FvProtocol); + if (EFI_ERROR(Status)) { + return Status; + } + + // Length of FilePath + UiStringLen = StrLen (FilePath); + + // Allocate Key + Key = AllocatePool (FvProtocol->KeySize); + ASSERT (Key != NULL); + ZeroMem (Key, FvProtocol->KeySize); + + do { + // Search in all files + FileType = FileTypeFilter; + + Status = FvProtocol->GetNextFile (FvProtocol, Key, &FileType, &NameGuid, &Attributes, &Size); + if (!EFI_ERROR (Status)) { + UiSection = NULL; + FileStatus = FvProtocol->ReadSection ( + FvProtocol, + &NameGuid, + EFI_SECTION_USER_INTERFACE, + 0, + (VOID **)&UiSection, + &Size, + &Authentication + ); + if (!EFI_ERROR (FileStatus)) { + if (StrnCmp (FilePath, UiSection, UiStringLen) == 0) { + // + // We found a UiString match. + // + Status = gBS->HandleProtocol (FvHandle, &gEfiDevicePathProtocolGuid, (VOID **)&FvDevicePath); + + // Generate the Device Path for the file + //DevicePath = DuplicateDevicePath(FvDevicePath); + EfiInitializeFwVolDevicepathNode (&FileDevicePath, &NameGuid); + *EfiAppDevicePath = AppendDevicePathNode (FvDevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&FileDevicePath); + + FreePool (Key); + FreePool (UiSection); + return FileStatus; + } + FreePool (UiSection); + } + } + } while (!EFI_ERROR (Status)); + + FreePool(Key); + return Status; +} + +/** + Start an EFI Application from any Firmware Volume + + @param EfiApp EFI Application Name + + @retval EFI_SUCCESS All drivers have been connected + @retval EFI_NOT_FOUND The Linux kernel Device Path has not been found + @retval EFI_OUT_OF_RESOURCES There is not enough resource memory to store the matching results. + +**/ +EFI_STATUS +BdsLoadApplication ( + IN EFI_HANDLE ParentImageHandle, + IN CHAR16* EfiApp + ) +{ + EFI_STATUS Status; + UINTN NoHandles, HandleIndex; + EFI_HANDLE *Handles; + EFI_DEVICE_PATH *FvDevicePath; + EFI_DEVICE_PATH *EfiAppDevicePath; + + // Need to connect every drivers to ensure no dependencies are missing for the application + Status = BdsConnectAllDrivers(); + if (EFI_ERROR(Status)) { + DEBUG ((EFI_D_ERROR, "FAIL to connect all drivers\n")); + return Status; + } + + // Search the application in any Firmware Volume + Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiFirmwareVolume2ProtocolGuid, NULL, &NoHandles, &Handles); + if (EFI_ERROR (Status) || (NoHandles == 0)) { + DEBUG ((EFI_D_ERROR, "FAIL to find Firmware Volume\n")); + return Status; + } + + // Search in all Firmware Volume for the EFI Application + for (HandleIndex = 0; HandleIndex < NoHandles; HandleIndex++) { + Status = BdsLoadFileFromFirmwareVolume (Handles[HandleIndex], EfiApp, EFI_FV_FILETYPE_APPLICATION, &EfiAppDevicePath); + if (!EFI_ERROR (Status)) { + // Start the application + Status = BdsStartEfiApplication (ParentImageHandle, EfiAppDevicePath); + return Status; + } + } + + return Status; +} diff --git a/ArmPkg/Library/BdsLib/BdsFilePath.c b/ArmPkg/Library/BdsLib/BdsFilePath.c index b1460b9c9d..f7a06e5a89 100644 --- a/ArmPkg/Library/BdsLib/BdsFilePath.c +++ b/ArmPkg/Library/BdsLib/BdsFilePath.c @@ -14,169 +14,829 @@ #include "BdsInternal.h" -// Count the number of DevicePath Node -static UINTN NumberNodeFromDevicePath( - IN EFI_DEVICE_PATH_PROTOCOL* DevicePath -) { - UINTN NumberDevicePathNode = 0; - - while (!IsDevicePathEnd (DevicePath)) { - NumberDevicePathNode++; - DevicePath = NextDevicePathNode(DevicePath); +#include +#include + +#define IS_DEVICE_PATH_NODE(node,type,subtype) (((node)->Type == (type)) && ((node)->SubType == (subtype))) + +// Extract the FilePath from the Device Path +CHAR16* +BdsExtractFilePathFromDevicePath ( + IN CONST CHAR16 *StrDevicePath, + IN UINTN NumberDevicePathNode + ) +{ + UINTN Node; + CHAR16 *Str; + + Str = (CHAR16*)StrDevicePath; + Node = 0; + while ((Str != NULL) && (*Str != L'\0') && (Node < NumberDevicePathNode)) { + if ((*Str == L'/') || (*Str == L'\\')) { + Node++; } - return NumberDevicePathNode; + Str++; + } + + if (*Str == L'\0') { + return NULL; + } else { + return Str; + } } -// Extract the FilePath from the Device Path -CHAR16* BdsExtractFilePathFromDevicePath( - IN CONST CHAR16 *StrDevicePath, - IN UINTN NumberDevicePathNode -) { - UINTN Node; - CHAR16 *Str; - - Str = (CHAR16*)StrDevicePath; - Node = 0; - while ((Str != NULL) && (*Str != L'\0') && (Node < NumberDevicePathNode)) { - if ((*Str == L'/') || (*Str == L'\\')) { - Node++; +BOOLEAN +BdsIsRemovableUsb ( + IN EFI_DEVICE_PATH* DevicePath + ) +{ + return ((DevicePathType (DevicePath) == MESSAGING_DEVICE_PATH) && + ((DevicePathSubType (DevicePath) == MSG_USB_CLASS_DP) || + (DevicePathSubType (DevicePath) == MSG_USB_WWID_DP))); +} + +EFI_STATUS +BdsGetDeviceUsb ( + IN EFI_DEVICE_PATH* RemovableDevicePath, + OUT EFI_HANDLE* DeviceHandle, + OUT EFI_DEVICE_PATH** NewDevicePath + ) +{ + EFI_STATUS Status; + UINTN Index; + UINTN UsbIoHandleCount; + EFI_HANDLE *UsbIoBuffer; + EFI_DEVICE_PATH* UsbIoDevicePath; + EFI_DEVICE_PATH* TmpDevicePath; + USB_WWID_DEVICE_PATH* WwidDevicePath1; + USB_WWID_DEVICE_PATH* WwidDevicePath2; + USB_CLASS_DEVICE_PATH* UsbClassDevicePath1; + USB_CLASS_DEVICE_PATH* UsbClassDevicePath2; + + // Get all the UsbIo handles + UsbIoHandleCount = 0; + Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiUsbIoProtocolGuid, NULL, &UsbIoHandleCount, &UsbIoBuffer); + if (EFI_ERROR(Status) || (UsbIoHandleCount == 0)) { + return Status; + } + + // Check if one of the handles matches the USB description + for (Index = 0; Index < UsbIoHandleCount; Index++) { + Status = gBS->HandleProtocol (UsbIoBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID *) &UsbIoDevicePath); + if (!EFI_ERROR(Status)) { + TmpDevicePath = UsbIoDevicePath; + while (!IsDevicePathEnd (TmpDevicePath)) { + // Check if the Device Path node is a USB Removable device Path node + if (BdsIsRemovableUsb (TmpDevicePath)) { + if (TmpDevicePath->SubType == MSG_USB_WWID_DP) { + WwidDevicePath1 = (USB_WWID_DEVICE_PATH*)RemovableDevicePath; + WwidDevicePath2 = (USB_WWID_DEVICE_PATH*)TmpDevicePath; + if ((WwidDevicePath1->VendorId == WwidDevicePath2->VendorId) && + (WwidDevicePath1->ProductId == WwidDevicePath2->ProductId) && + (CompareMem (WwidDevicePath1+1, WwidDevicePath2+1, DevicePathNodeLength(WwidDevicePath1)-sizeof(USB_WWID_DEVICE_PATH)) == 0)) + { + *DeviceHandle = UsbIoBuffer[Index]; + // Add the additional original Device Path Nodes (eg: FilePath Device Path Node) to the new Device Path + *NewDevicePath = AppendDevicePath (UsbIoDevicePath, NextDevicePathNode(RemovableDevicePath)); + return EFI_SUCCESS; + } + } else { + UsbClassDevicePath1 = (USB_CLASS_DEVICE_PATH*)RemovableDevicePath; + UsbClassDevicePath2 = (USB_CLASS_DEVICE_PATH*)TmpDevicePath; + if ((UsbClassDevicePath1->VendorId != 0xFFFF) && (UsbClassDevicePath1->VendorId == UsbClassDevicePath2->VendorId) && + (UsbClassDevicePath1->ProductId != 0xFFFF) && (UsbClassDevicePath1->ProductId == UsbClassDevicePath2->ProductId) && + (UsbClassDevicePath1->DeviceClass != 0xFF) && (UsbClassDevicePath1->DeviceClass == UsbClassDevicePath2->DeviceClass) && + (UsbClassDevicePath1->DeviceSubClass != 0xFF) && (UsbClassDevicePath1->DeviceSubClass == UsbClassDevicePath2->DeviceSubClass) && + (UsbClassDevicePath1->DeviceProtocol != 0xFF) && (UsbClassDevicePath1->DeviceProtocol == UsbClassDevicePath2->DeviceProtocol)) + { + *DeviceHandle = UsbIoBuffer[Index]; + // Add the additional original Device Path Nodes (eg: FilePath Device Path Node) to the new Device Path + *NewDevicePath = AppendDevicePath (UsbIoDevicePath, NextDevicePathNode(RemovableDevicePath)); + return EFI_SUCCESS; + } + } } - Str++; - } + TmpDevicePath = NextDevicePathNode (TmpDevicePath); + } - if (*Str == L'\0') { - return NULL; - } else { - return Str; } + } + + return EFI_NOT_FOUND; +} + +BOOLEAN +BdsIsRemovableHd ( + IN EFI_DEVICE_PATH* DevicePath + ) +{ + return IS_DEVICE_PATH_NODE(DevicePath, MEDIA_DEVICE_PATH, MEDIA_HARDDRIVE_DP); } EFI_STATUS -BdsLoadDevicePath( - IN EFI_DEVICE_PATH_PROTOCOL* DevicePath, - OUT EFI_HANDLE *Handle -) { - EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath; - EFI_STATUS Status; - - if ((DevicePath == NULL) || (Handle == NULL)) { - return EFI_INVALID_PARAMETER; - } +BdsGetDeviceHd ( + IN EFI_DEVICE_PATH* RemovableDevicePath, + OUT EFI_HANDLE* DeviceHandle, + OUT EFI_DEVICE_PATH** NewDevicePath + ) +{ + EFI_STATUS Status; + UINTN Index; + UINTN PartitionHandleCount; + EFI_HANDLE *PartitionBuffer; + EFI_DEVICE_PATH* PartitionDevicePath; + EFI_DEVICE_PATH* TmpDevicePath; + HARDDRIVE_DEVICE_PATH* HardDriveDevicePath1; + HARDDRIVE_DEVICE_PATH* HardDriveDevicePath2; - do { - RemainingDevicePath = DevicePath; - // The LocateDevicePath() function locates all devices on DevicePath that support Protocol and returns - // the handle to the device that is closest to DevicePath. On output, the device path pointer is modified - // to point to the remaining part of the device path - Status = gBS->LocateDevicePath(&gEfiDevicePathProtocolGuid,&RemainingDevicePath,Handle); - if (!EFI_ERROR (Status)) { - // Recursive = FALSE: We do not want to start all the device tree - Status = gBS->ConnectController (*Handle, NULL, RemainingDevicePath, FALSE); - } + // Get all the DiskIo handles + PartitionHandleCount = 0; + Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiDiskIoProtocolGuid, NULL, &PartitionHandleCount, &PartitionBuffer); + if (EFI_ERROR(Status) || (PartitionHandleCount == 0)) { + return Status; + } - // We need to check if RemainingDevicePath does not point on the last node. Otherwise, calling - // NextDevicePathNode() will return an undetermined Device Path Node - if (!IsDevicePathEnd (RemainingDevicePath)) { - RemainingDevicePath = NextDevicePathNode (RemainingDevicePath); + // Check if one of the handles matches the Hard Disk Description + for (Index = 0; Index < PartitionHandleCount; Index++) { + Status = gBS->HandleProtocol (PartitionBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID *) &PartitionDevicePath); + if (!EFI_ERROR(Status)) { + TmpDevicePath = PartitionDevicePath; + while (!IsDevicePathEnd (TmpDevicePath)) { + // Check if the Device Path node is a HD Removable device Path node + if (BdsIsRemovableHd (TmpDevicePath)) { + HardDriveDevicePath1 = (HARDDRIVE_DEVICE_PATH*)RemovableDevicePath; + HardDriveDevicePath2 = (HARDDRIVE_DEVICE_PATH*)TmpDevicePath; + if ((HardDriveDevicePath1->SignatureType == HardDriveDevicePath2->SignatureType) && + (CompareGuid ((EFI_GUID *)HardDriveDevicePath1->Signature,(EFI_GUID *)HardDriveDevicePath2->Signature) == TRUE) && + (HardDriveDevicePath1->PartitionNumber == HardDriveDevicePath2->PartitionNumber)) + { + *DeviceHandle = PartitionBuffer[Index]; + // Add the additional original Device Path Nodes (eg: FilePath Device Path Node) to the new Device Path + *NewDevicePath = AppendDevicePath (PartitionDevicePath, NextDevicePathNode(RemovableDevicePath)); + return EFI_SUCCESS; + } } - } while (!EFI_ERROR (Status) && !IsDevicePathEnd (RemainingDevicePath)); + TmpDevicePath = NextDevicePathNode (TmpDevicePath); + } - if (!EFI_ERROR (Status)) { - // Now, we have got the whole Device Path connected, call again ConnectController to ensure all the supported Driver - // Binding Protocol are connected (such as DiskIo and SimpleFileSystem) - RemainingDevicePath = DevicePath; - Status = gBS->LocateDevicePath(&gEfiDevicePathProtocolGuid,&RemainingDevicePath,Handle); - if (!EFI_ERROR (Status)) { - Status = gBS->ConnectController (*Handle, NULL, RemainingDevicePath, FALSE); - if (EFI_ERROR (Status)) { - // If the last node is a Memory Map Device Path just return EFI_SUCCESS. - if ((RemainingDevicePath->Type == HARDWARE_DEVICE_PATH) && (RemainingDevicePath->SubType == HW_MEMMAP_DP)) { - Status = EFI_SUCCESS; - } - } - } - } else if (IsDevicePathEnd (RemainingDevicePath)) { - // Case when the DevicePath contains a MemoryMap Device Path Node and all drivers are connected. - // Ensure the Device Path exists - RemainingDevicePath = DevicePath; - Status = gBS->LocateDevicePath(&gEfiDevicePathProtocolGuid,&RemainingDevicePath,Handle); } + } - return Status; + return EFI_NOT_FOUND; } +/*BOOLEAN +BdsIsRemovableCdrom ( + IN EFI_DEVICE_PATH* DevicePath + ) +{ + return IS_DEVICE_PATH_NODE(DevicePath, MEDIA_DEVICE_PATH, MEDIA_CDROM_DP); +} EFI_STATUS -BdsLoadFilePath ( - IN CONST CHAR16 *DeviceFilePath, - OUT BDS_FILE *File -) { - EFI_DEVICE_PATH_PROTOCOL *DevicePath; - EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *EfiDevicePathFromTextProtocol; - EFI_STATUS Status; - EFI_HANDLE Handle; - UINTN NumberDevicePathNode; - CHAR16 *FilePath; - - //Do a sanity check on the Device file path - if (DeviceFilePath == NULL) { - return EFI_INVALID_PARAMETER; +BdsGetDeviceCdrom ( + IN EFI_DEVICE_PATH* RemovableDevicePath, + OUT EFI_HANDLE* DeviceHandle, + OUT EFI_DEVICE_PATH** DevicePath + ) +{ + ASSERT(0); + return EFI_UNSUPPORTED; +}*/ + +typedef BOOLEAN +(*BDS_IS_REMOVABLE) ( + IN EFI_DEVICE_PATH* DevicePath + ); + +typedef EFI_STATUS +(*BDS_GET_DEVICE) ( + IN EFI_DEVICE_PATH* RemovableDevicePath, + OUT EFI_HANDLE* DeviceHandle, + OUT EFI_DEVICE_PATH** DevicePath + ); + +typedef struct { + BDS_IS_REMOVABLE IsRemovable; + BDS_GET_DEVICE GetDevice; +} BDS_REMOVABLE_DEVICE_SUPPORT; + +BDS_REMOVABLE_DEVICE_SUPPORT RemovableDeviceSupport[] = { + { BdsIsRemovableUsb, BdsGetDeviceUsb }, + { BdsIsRemovableHd, BdsGetDeviceHd }, + //{ BdsIsRemovableCdrom, BdsGetDeviceCdrom } +}; + +STATIC +BOOLEAN +IsRemovableDevice ( + IN EFI_DEVICE_PATH* DevicePath + ) +{ + UINTN Index; + EFI_DEVICE_PATH* TmpDevicePath; + + TmpDevicePath = DevicePath; + while (!IsDevicePathEnd (TmpDevicePath)) { + for (Index = 0; Index < sizeof(RemovableDeviceSupport) / sizeof(BDS_REMOVABLE_DEVICE_SUPPORT); Index++) { + if (RemovableDeviceSupport[Index].IsRemovable(TmpDevicePath)) { + return TRUE; + } } + TmpDevicePath = NextDevicePathNode (TmpDevicePath); + } + + return FALSE; +} - // Convert the Device Path String into Device Path Protocol - Status = gBS->LocateProtocol(&gEfiDevicePathFromTextProtocolGuid, NULL, (VOID **)&EfiDevicePathFromTextProtocol); - ASSERT_EFI_ERROR(Status); - DevicePath = EfiDevicePathFromTextProtocol->ConvertTextToDevicePath(DeviceFilePath); +STATIC +EFI_STATUS +TryRemovableDevice ( + IN EFI_DEVICE_PATH* DevicePath, + OUT EFI_HANDLE* DeviceHandle, + OUT EFI_DEVICE_PATH** NewDevicePath + ) +{ + EFI_STATUS Status; + UINTN Index; + EFI_DEVICE_PATH* TmpDevicePath; + BDS_REMOVABLE_DEVICE_SUPPORT* RemovableDevice; + EFI_DEVICE_PATH* RemovableDevicePath; + BOOLEAN RemovableFound; - //Do a sanity check on the Device Path - if (DevicePath == NULL) { - return EFI_INVALID_PARAMETER; + RemovableFound = FALSE; + TmpDevicePath = DevicePath; + while (!IsDevicePathEnd (TmpDevicePath) && !RemovableFound) { + for (Index = 0; Index < sizeof(RemovableDeviceSupport) / sizeof(BDS_REMOVABLE_DEVICE_SUPPORT); Index++) { + RemovableDevice = &RemovableDeviceSupport[Index]; + if (RemovableDevice->IsRemovable(TmpDevicePath)) { + RemovableDevicePath = TmpDevicePath; + RemovableFound = TRUE; + break; + } } + TmpDevicePath = NextDevicePathNode (TmpDevicePath); + } - // Count the number of DevicePath Node - NumberDevicePathNode = NumberNodeFromDevicePath(DevicePath); - // Extract the FilePath from the Device Path - FilePath = BdsExtractFilePathFromDevicePath(DeviceFilePath,NumberDevicePathNode); + if (!RemovableFound) { + return EFI_NOT_FOUND; + } - Status = BdsLoadDevicePath(DevicePath,&Handle); - if (EFI_ERROR (Status)) { - return Status; + // Search into the current started drivers + Status = RemovableDevice->GetDevice (RemovableDevicePath, DeviceHandle, NewDevicePath); + if (Status == EFI_NOT_FOUND) { + // Connect all the drivers + BdsConnectAllDrivers (); + + // Search again into all the drivers + Status = RemovableDevice->GetDevice (RemovableDevicePath, DeviceHandle, NewDevicePath); + } + + return Status; +} + +EFI_STATUS +BdsConnectDevicePath ( + IN EFI_DEVICE_PATH_PROTOCOL* DevicePath, + OUT EFI_HANDLE *Handle, + OUT EFI_DEVICE_PATH_PROTOCOL **RemainingDevicePath + ) +{ + EFI_DEVICE_PATH* Remaining; + EFI_DEVICE_PATH* NewDevicePath; + EFI_STATUS Status; + + if ((DevicePath == NULL) || (Handle == NULL)) { + return EFI_INVALID_PARAMETER; + } + + do { + Remaining = DevicePath; + // The LocateDevicePath() function locates all devices on DevicePath that support Protocol and returns + // the handle to the device that is closest to DevicePath. On output, the device path pointer is modified + // to point to the remaining part of the device path + Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &Remaining, Handle); + if (!EFI_ERROR (Status)) { + // Recursive = FALSE: We do not want to start all the device tree + Status = gBS->ConnectController (*Handle, NULL, Remaining, FALSE); } - //If FilePath == NULL then let consider if a MemoryMap Device Path - if (FilePath == NULL) { - // Check if the Node is a MemoryMap Device Path - Status = BdsLoadFileFromMemMap(Handle,DevicePath,File); - } else { - Status = BdsLoadFileFromSimpleFileSystem(Handle,FilePath,File); - if (EFI_ERROR (Status)) { - Status = BdsLoadFileFromFirmwareVolume(Handle,FilePath,EFI_FV_FILETYPE_ALL,File); + /*// We need to check if RemainingDevicePath does not point on the last node. Otherwise, calling + // NextDevicePathNode() will return an undetermined Device Path Node + if (!IsDevicePathEnd (RemainingDevicePath)) { + RemainingDevicePath = NextDevicePathNode (RemainingDevicePath); + }*/ + } while (!EFI_ERROR (Status) && !IsDevicePathEnd (Remaining)); + + if (!EFI_ERROR (Status)) { + // Now, we have got the whole Device Path connected, call again ConnectController to ensure all the supported Driver + // Binding Protocol are connected (such as DiskIo and SimpleFileSystem) + Remaining = DevicePath; + Status = gBS->LocateDevicePath(&gEfiDevicePathProtocolGuid,&Remaining,Handle); + if (!EFI_ERROR (Status)) { + Status = gBS->ConnectController (*Handle, NULL, Remaining, FALSE); + if (EFI_ERROR (Status)) { + // If the last node is a Memory Map Device Path just return EFI_SUCCESS. + if ((Remaining->Type == HARDWARE_DEVICE_PATH) && (Remaining->SubType == HW_MEMMAP_DP)) { + Status = EFI_SUCCESS; } + } } + } else if (!IsDevicePathEnd (Remaining) && !IsRemovableDevice (Remaining)) { + + /*// If the remaining Device Path is a FilePath or MemoryMap then we consider the Device Path has been loaded correctly + if ((Remaining->Type == MEDIA_DEVICE_PATH) && (Remaining->SubType == MEDIA_FILEPATH_DP)) { + Status = EFI_SUCCESS; + } else if ((Remaining->Type == HARDWARE_DEVICE_PATH) && (Remaining->SubType == HW_MEMMAP_DP)) { + Status = EFI_SUCCESS; + }*/ + //TODO: Should we just return success and leave the caller decide if it is the expected RemainingPath + Status = EFI_SUCCESS; + } else { + Status = TryRemovableDevice (DevicePath, Handle, &NewDevicePath); if (!EFI_ERROR (Status)) { - File->DevicePath = DevicePath; + return BdsConnectDevicePath (NewDevicePath, Handle, RemainingDevicePath); + } + } + + if (RemainingDevicePath) { + *RemainingDevicePath = Remaining; + } + + return Status; +} + +BOOLEAN +BdsFileSystemSupport ( + IN EFI_DEVICE_PATH *DevicePath, + IN EFI_HANDLE Handle, + IN EFI_DEVICE_PATH *RemainingDevicePath + ) +{ + EFI_STATUS Status; + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FsProtocol; + + Status = gBS->HandleProtocol (Handle,&gEfiSimpleFileSystemProtocolGuid, (VOID **)&FsProtocol); + + return (!EFI_ERROR(Status) && IS_DEVICE_PATH_NODE(RemainingDevicePath,MEDIA_DEVICE_PATH,MEDIA_FILEPATH_DP)); +} + +EFI_STATUS +BdsFileSystemLoadImage ( + IN EFI_DEVICE_PATH *DevicePath, + IN EFI_HANDLE Handle, + IN EFI_DEVICE_PATH *RemainingDevicePath, + IN EFI_ALLOCATE_TYPE Type, + IN OUT EFI_PHYSICAL_ADDRESS* Image, + OUT UINTN *ImageSize + ) +{ + FILEPATH_DEVICE_PATH* FilePathDevicePath; + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FsProtocol; + EFI_FILE_PROTOCOL *Fs; + EFI_STATUS Status; + EFI_FILE_INFO *FileInfo; + EFI_FILE_PROTOCOL *File; + UINTN Size; + + ASSERT (IS_DEVICE_PATH_NODE(RemainingDevicePath,MEDIA_DEVICE_PATH,MEDIA_FILEPATH_DP)); + + FilePathDevicePath = (FILEPATH_DEVICE_PATH*)RemainingDevicePath; + + Status = gBS->HandleProtocol(Handle,&gEfiSimpleFileSystemProtocolGuid, (VOID **)&FsProtocol); + if (EFI_ERROR(Status)) { + return Status; + } + + //Try to Open the volume and get root directory + Status = FsProtocol->OpenVolume (FsProtocol, &Fs); + if (EFI_ERROR(Status)) { + return Status; + } + + File = NULL; + Status = Fs->Open(Fs, &File, FilePathDevicePath->PathName, EFI_FILE_MODE_READ, 0); + + Size = 0; + File->GetInfo(File, &gEfiFileInfoGuid, &Size, NULL); + FileInfo = AllocatePool (Size); + Status = File->GetInfo(File, &gEfiFileInfoGuid, &Size, FileInfo); + if (EFI_ERROR(Status)) { + return Status; + } + + // Get the file size + Size = FileInfo->FileSize; + if (ImageSize) { + *ImageSize = Size; + } + FreePool(FileInfo); + + Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(Size),Image); + if (!EFI_ERROR(Status)) { + Status = File->Read (File, &Size, (VOID*)(UINTN)(*Image)); + } + + return Status; +} + +BOOLEAN +BdsMemoryMapSupport ( + IN EFI_DEVICE_PATH *DevicePath, + IN EFI_HANDLE Handle, + IN EFI_DEVICE_PATH *RemainingDevicePath + ) +{ + return IS_DEVICE_PATH_NODE(RemainingDevicePath,HARDWARE_DEVICE_PATH,HW_MEMMAP_DP); +} + +EFI_STATUS +BdsMemoryMapLoadImage ( + IN EFI_DEVICE_PATH *DevicePath, + IN EFI_HANDLE Handle, + IN EFI_DEVICE_PATH *RemainingDevicePath, + IN EFI_ALLOCATE_TYPE Type, + IN OUT EFI_PHYSICAL_ADDRESS* Image, + OUT UINTN *ImageSize + ) +{ + EFI_STATUS Status; + MEMMAP_DEVICE_PATH* MemMapPathDevicePath; + UINTN Size; + + ASSERT (IS_DEVICE_PATH_NODE(RemainingDevicePath,HARDWARE_DEVICE_PATH,HW_MEMMAP_DP)); + + MemMapPathDevicePath = (MEMMAP_DEVICE_PATH*)RemainingDevicePath; + + Size = MemMapPathDevicePath->EndingAddress - MemMapPathDevicePath->StartingAddress; + if (Size == 0) { + return EFI_INVALID_PARAMETER; + } + + Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(Size),Image); + if (!EFI_ERROR(Status)) { + CopyMem ((VOID*)(UINTN)(*Image), (CONST VOID*)(UINTN)MemMapPathDevicePath->StartingAddress, Size); + + if (ImageSize != NULL) { + *ImageSize = Size; } + } + return Status; +} + +BOOLEAN +BdsFirmwareVolumeSupport ( + IN EFI_DEVICE_PATH *DevicePath, + IN EFI_HANDLE Handle, + IN EFI_DEVICE_PATH *RemainingDevicePath + ) +{ + return IS_DEVICE_PATH_NODE(RemainingDevicePath, MEDIA_DEVICE_PATH, MEDIA_PIWG_FW_FILE_DP); +} + +EFI_STATUS +BdsFirmwareVolumeLoadImage ( + IN EFI_DEVICE_PATH *DevicePath, + IN EFI_HANDLE Handle, + IN EFI_DEVICE_PATH *RemainingDevicePath, + IN EFI_ALLOCATE_TYPE Type, + IN OUT EFI_PHYSICAL_ADDRESS* Image, + OUT UINTN *ImageSize + ) +{ + EFI_STATUS Status; + EFI_FIRMWARE_VOLUME2_PROTOCOL *FwVol; + EFI_GUID *FvNameGuid; + EFI_SECTION_TYPE SectionType; + EFI_FV_FILETYPE FvType; + EFI_FV_FILE_ATTRIBUTES Attrib; + UINT32 AuthenticationStatus; + VOID* ImageBuffer; + + ASSERT (IS_DEVICE_PATH_NODE(RemainingDevicePath, MEDIA_DEVICE_PATH, MEDIA_PIWG_FW_FILE_DP)); + + Status = gBS->HandleProtocol(Handle,&gEfiFirmwareVolume2ProtocolGuid, (VOID **)&FwVol); + if (EFI_ERROR(Status)) { return Status; + } + + FvNameGuid = EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)RemainingDevicePath); + if (FvNameGuid == NULL) { + Status = EFI_INVALID_PARAMETER; + } + + SectionType = EFI_SECTION_PE32; + AuthenticationStatus = 0; + //Note: ReadSection at the opposite of ReadFile does not allow to pass ImageBuffer == NULL to get the size of the file. + ImageBuffer = NULL; + Status = FwVol->ReadSection ( + FwVol, + FvNameGuid, + SectionType, + 0, + &ImageBuffer, + ImageSize, + &AuthenticationStatus + ); + if (!EFI_ERROR (Status)) { +#if 0 + // In case the buffer has some address requirements, we must copy the buffer to a buffer following the requirements + if (Type != AllocateAnyPages) { + Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize),Image); + if (!EFI_ERROR(Status)) { + CopyMem ((VOID*)(UINTN)(*Image), ImageBuffer, *ImageSize); + FreePool (ImageBuffer); + } + } +#else + // We must copy the buffer into a page allocations. Otherwise, the caller could call gBS->FreePages() on the pool allocation + Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize), Image); + if (!EFI_ERROR(Status)) { + CopyMem ((VOID*)(UINTN)(*Image), ImageBuffer, *ImageSize); + FreePool (ImageBuffer); + } +#endif + } else { + // Try a raw file, since a PE32 SECTION does not exist + Status = FwVol->ReadFile ( + FwVol, + FvNameGuid, + NULL, + ImageSize, + &FvType, + &Attrib, + &AuthenticationStatus + ); + if (!EFI_ERROR(Status)) { + Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize),Image); + if (!EFI_ERROR(Status)) { + Status = FwVol->ReadFile ( + FwVol, + FvNameGuid, + (VOID*)(UINTN)(*Image), + ImageSize, + &FvType, + &Attrib, + &AuthenticationStatus + ); + } + } + } + return Status; } -EFI_STATUS BdsCopyRawFileToRuntimeMemory( - IN BDS_FILE *File, - OUT VOID **FileImage, - OUT UINTN *FileSize -) { - if (File == NULL) { - return EFI_INVALID_PARAMETER; +BOOLEAN +BdsPxeSupport ( + IN EFI_DEVICE_PATH* DevicePath, + IN EFI_HANDLE Handle, + IN EFI_DEVICE_PATH* RemainingDevicePath + ) +{ + EFI_STATUS Status; + EFI_PXE_BASE_CODE_PROTOCOL* PxeBcProtocol; + + if (!IsDevicePathEnd(RemainingDevicePath)) { + return FALSE; + } + + Status = gBS->HandleProtocol (Handle, &gEfiPxeBaseCodeProtocolGuid, (VOID **)&PxeBcProtocol); + if (EFI_ERROR (Status)) { + return FALSE; + } else { + return TRUE; + } +} + +EFI_STATUS +BdsPxeLoadImage ( + IN EFI_DEVICE_PATH* DevicePath, + IN EFI_HANDLE Handle, + IN EFI_DEVICE_PATH* RemainingDevicePath, + IN EFI_ALLOCATE_TYPE Type, + IN OUT EFI_PHYSICAL_ADDRESS *Image, + OUT UINTN *ImageSize + ) +{ + EFI_STATUS Status; + EFI_LOAD_FILE_PROTOCOL *LoadFileProtocol; + UINTN BufferSize; + + // Get Load File Protocol attached to the PXE protocol + Status = gBS->HandleProtocol (Handle, &gEfiLoadFileProtocolGuid, (VOID **)&LoadFileProtocol); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = LoadFileProtocol->LoadFile (LoadFileProtocol, DevicePath, TRUE, &BufferSize, NULL); + if (Status == EFI_BUFFER_TOO_SMALL) { + Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(BufferSize), Image); + if (EFI_ERROR(Status)) { + return Status; } - if (File->Type == BDS_FILETYPE_FS) { - return BdsCopyRawFileToRuntimeMemoryFS(File->File.Fs.Handle,FileImage,FileSize); - } else if (File->Type == BDS_FILETYPE_FV) { - return BdsCopyRawFileToRuntimeMemoryFV(&(File->File.Fv),FileImage,FileSize); - } else if (File->Type == BDS_FILETYPE_MEM) { - return BdsCopyRawFileToRuntimeMemoryMemMap(&(File->File.Mem),FileImage,FileSize); - } else { - return EFI_INVALID_PARAMETER; + Status = LoadFileProtocol->LoadFile (LoadFileProtocol, DevicePath, TRUE, &BufferSize, (VOID*)(UINTN)(*Image)); + if (!EFI_ERROR(Status) && (ImageSize != NULL)) { + *ImageSize = BufferSize; } + } + + return Status; +} + +BOOLEAN +BdsTftpSupport ( + IN EFI_DEVICE_PATH* DevicePath, + IN EFI_HANDLE Handle, + IN EFI_DEVICE_PATH* RemainingDevicePath + ) +{ + EFI_STATUS Status; + EFI_DEVICE_PATH *NextDevicePath; + EFI_PXE_BASE_CODE_PROTOCOL *PxeBcProtocol; + + // Validate the Remaining Device Path + if (IsDevicePathEnd(RemainingDevicePath)) { + return FALSE; + } + if (!IS_DEVICE_PATH_NODE(RemainingDevicePath,MESSAGING_DEVICE_PATH,MSG_IPv4_DP) && + !IS_DEVICE_PATH_NODE(RemainingDevicePath,MESSAGING_DEVICE_PATH,MSG_IPv6_DP)) { + return FALSE; + } + NextDevicePath = NextDevicePathNode (RemainingDevicePath); + if (IsDevicePathEnd(NextDevicePath)) { + return FALSE; + } + if (!IS_DEVICE_PATH_NODE(NextDevicePath,MEDIA_DEVICE_PATH,MEDIA_FILEPATH_DP)) { + return FALSE; + } + + Status = gBS->HandleProtocol (Handle, &gEfiPxeBaseCodeProtocolGuid, (VOID **)&PxeBcProtocol); + if (EFI_ERROR (Status)) { + return FALSE; + } else { + return TRUE; + } +} + +EFI_STATUS +BdsTftpLoadImage ( + IN EFI_DEVICE_PATH* DevicePath, + IN EFI_HANDLE Handle, + IN EFI_DEVICE_PATH* RemainingDevicePath, + IN EFI_ALLOCATE_TYPE Type, + IN OUT EFI_PHYSICAL_ADDRESS *Image, + OUT UINTN *ImageSize + ) +{ + EFI_STATUS Status; + EFI_PXE_BASE_CODE_PROTOCOL *Pxe; + UINT64 TftpBufferSize; + VOID* TftpBuffer; + EFI_IP_ADDRESS ServerIp; + IPv4_DEVICE_PATH* IPv4DevicePathNode; + FILEPATH_DEVICE_PATH* FilePathDevicePath; + EFI_IP_ADDRESS LocalIp; + + ASSERT(IS_DEVICE_PATH_NODE(RemainingDevicePath,MESSAGING_DEVICE_PATH,MSG_IPv4_DP)); + + IPv4DevicePathNode = (IPv4_DEVICE_PATH*)RemainingDevicePath; + FilePathDevicePath = (FILEPATH_DEVICE_PATH*)(IPv4DevicePathNode + 1); + + Status = gBS->LocateProtocol (&gEfiPxeBaseCodeProtocolGuid, NULL, (VOID **)&Pxe); + if (EFI_ERROR(Status)) { + return Status; + } + + Status = Pxe->Start (Pxe, FALSE); + if (EFI_ERROR(Status) && (Status != EFI_ALREADY_STARTED)) { + return Status; + } + + if (!IPv4DevicePathNode->StaticIpAddress) { + Status = Pxe->Dhcp(Pxe, TRUE); + } else { + CopyMem (&LocalIp.v4, &IPv4DevicePathNode->LocalIpAddress, sizeof (EFI_IPv4_ADDRESS)); + Status = Pxe->SetStationIp (Pxe, &LocalIp, NULL); + } + if (EFI_ERROR(Status)) { + return Status; + } + + CopyMem (&ServerIp.v4, &IPv4DevicePathNode->RemoteIpAddress, sizeof (EFI_IPv4_ADDRESS)); + + Status = Pxe->Mtftp ( + Pxe, + EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE, + NULL, + FALSE, + &TftpBufferSize, + NULL, + &ServerIp, + (UINT8 *)FilePathDevicePath->PathName, + NULL, + TRUE + ); + if (EFI_ERROR(Status)) { + return Status; + } + + // Allocate a buffer to hold the whole file. + TftpBuffer = AllocatePool(TftpBufferSize); + if (TftpBuffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Status = Pxe->Mtftp ( + Pxe, + EFI_PXE_BASE_CODE_TFTP_READ_FILE, + TftpBuffer, + FALSE, + &TftpBufferSize, + NULL, + &ServerIp, + (UINT8 *)FilePathDevicePath->PathName, + NULL, + FALSE + ); + if (EFI_ERROR(Status)) { + FreePool(TftpBuffer); + } else if (ImageSize != NULL) { + *ImageSize = (UINTN)TftpBufferSize; + } + + return Status; +} + +BDS_FILE_LOADER FileLoaders[] = { + { BdsFileSystemSupport, BdsFileSystemLoadImage }, + { BdsFirmwareVolumeSupport, BdsFirmwareVolumeLoadImage }, + //{ BdsLoadFileSupport, BdsLoadFileLoadImage }, + { BdsMemoryMapSupport, BdsMemoryMapLoadImage }, + { BdsPxeSupport, BdsPxeLoadImage }, + { BdsTftpSupport, BdsTftpLoadImage }, + { NULL, NULL } +}; + +EFI_STATUS +BdsLoadImage ( + IN EFI_DEVICE_PATH *DevicePath, + IN EFI_ALLOCATE_TYPE Type, + IN OUT EFI_PHYSICAL_ADDRESS* Image, + OUT UINTN *FileSize + ) +{ + EFI_STATUS Status; + EFI_HANDLE Handle; + EFI_DEVICE_PATH *RemainingDevicePath; + BDS_FILE_LOADER* FileLoader; + + Status = BdsConnectDevicePath (DevicePath, &Handle, &RemainingDevicePath); + if (EFI_ERROR (Status)) { + return Status; + } + + FileLoader = FileLoaders; + while (FileLoader->Support != NULL) { + if (FileLoader->Support (DevicePath, Handle, RemainingDevicePath)) { + return FileLoader->LoadImage (DevicePath, Handle, RemainingDevicePath, Type, Image, FileSize); + } + FileLoader++; + } + + return EFI_UNSUPPORTED; +} + +EFI_STATUS +BdsStartEfiApplication ( + IN EFI_HANDLE ParentImageHandle, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +{ + EFI_STATUS Status; + EFI_HANDLE ImageHandle; + EFI_PHYSICAL_ADDRESS BinaryBuffer; + UINTN BinarySize; + + // Find the nearest supported file loader + Status = BdsLoadImage (DevicePath, AllocateAnyPages,&BinaryBuffer,&BinarySize); + if (EFI_ERROR(Status)) { + return Status; + } + + // Load the image from the Buffer with Boot Services function + Status = gBS->LoadImage (TRUE, ParentImageHandle, DevicePath, (VOID*)(UINTN)BinaryBuffer, BinarySize, &ImageHandle); + if (EFI_ERROR(Status)) { + return Status; + } + + // Before calling the image, enable the Watchdog Timer for the 5 Minute period + gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL); + // Start the image + Status = gBS->StartImage (ImageHandle, NULL, NULL); + // Clear the Watchdog Timer after the image returns + gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL); + + return Status; } diff --git a/ArmPkg/Library/BdsLib/BdsFilePathFs.c b/ArmPkg/Library/BdsLib/BdsFilePathFs.c deleted file mode 100644 index 0b7f9d39a5..0000000000 --- a/ArmPkg/Library/BdsLib/BdsFilePathFs.c +++ /dev/null @@ -1,86 +0,0 @@ -/** @file -* -* Copyright (c) 2011, ARM Limited. All rights reserved. -* -* This program and the accompanying materials -* are licensed and made available under the terms and conditions of the BSD License -* which accompanies this distribution. The full text of the license may be found at -* http://opensource.org/licenses/bsd-license.php -* -* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. -* -**/ - -#include "BdsInternal.h" - -EFI_STATUS BdsLoadFileFromSimpleFileSystem( - IN EFI_HANDLE Handle, - IN CHAR16 *FilePath, - OUT BDS_FILE *File -) { - EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FsProtocol; - EFI_FILE_PROTOCOL *Fs; - EFI_STATUS Status; - EFI_FILE_PROTOCOL *FileHandle = NULL; - - if (File == NULL) { - return EFI_INVALID_PARAMETER; - } - - Status = gBS->HandleProtocol(Handle,&gEfiSimpleFileSystemProtocolGuid, (VOID **)&FsProtocol); - if (EFI_ERROR(Status)) { - return Status; - } - - //Try to Open the volume and get root directory - Status = FsProtocol->OpenVolume(FsProtocol, &Fs); - if (EFI_ERROR(Status)) { - return Status; - } - - Status = Fs->Open(Fs, &FileHandle, FilePath, EFI_FILE_MODE_READ, 0); - - File->Type = BDS_FILETYPE_FS; - File->FilePath = FilePath; - File->File.Fs.Handle = FileHandle; - - return Status; -} - -EFI_STATUS BdsCopyRawFileToRuntimeMemoryFS( - IN EFI_FILE_PROTOCOL *File, - OUT VOID **FileImage, - OUT UINTN *FileSize -) { - EFI_FILE_INFO *FileInfo; - UINTN Size; - VOID* Image; - EFI_STATUS Status; - - Size = 0; - File->GetInfo(File, &gEfiFileInfoGuid, &Size, NULL); - FileInfo = AllocatePool (Size); - Status = File->GetInfo(File, &gEfiFileInfoGuid, &Size, FileInfo); - if (EFI_ERROR(Status)) { - return Status; - } - - // Get the file size - Size = FileInfo->FileSize; - if (FileSize) { - *FileSize = Size; - } - FreePool(FileInfo); - - Image = AllocateRuntimePool(Size); - if (Image == NULL) { - return EFI_OUT_OF_RESOURCES; - } - - Status = File->Read(File, &Size, Image); - if (!EFI_ERROR(Status)) { - *FileImage = Image; - } - return Status; -} diff --git a/ArmPkg/Library/BdsLib/BdsFilePathFv.c b/ArmPkg/Library/BdsLib/BdsFilePathFv.c deleted file mode 100644 index f5b4e57cbf..0000000000 --- a/ArmPkg/Library/BdsLib/BdsFilePathFv.c +++ /dev/null @@ -1,136 +0,0 @@ -/** @file -* -* Copyright (c) 2011, ARM Limited. All rights reserved. -* -* This program and the accompanying materials -* are licensed and made available under the terms and conditions of the BSD License -* which accompanies this distribution. The full text of the license may be found at -* http://opensource.org/licenses/bsd-license.php -* -* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. -* -**/ - -#include "BdsInternal.h" - -EFI_STATUS BdsLoadFileFromFirmwareVolume( - IN EFI_HANDLE FvHandle, - IN CHAR16 *FilePath, - IN EFI_FV_FILETYPE FileTypeFilter, - OUT BDS_FILE *File -) { - EFI_FIRMWARE_VOLUME2_PROTOCOL *FvProtocol; - VOID *Key; - EFI_STATUS Status, FileStatus; - EFI_GUID NameGuid; - EFI_FV_FILETYPE FileType; - EFI_FV_FILE_ATTRIBUTES Attributes; - UINTN Size; - UINTN UiStringLen; - CHAR16 *UiSection; - UINT32 Authentication; - - if (File == NULL) { - return EFI_INVALID_PARAMETER; - } - - Status = gBS->HandleProtocol(FvHandle,&gEfiFirmwareVolume2ProtocolGuid, (VOID **)&FvProtocol); - if (EFI_ERROR(Status)) { - return Status; - } - - // Length of FilePath - UiStringLen = StrLen (FilePath); - - // Allocate Key - Key = AllocatePool (FvProtocol->KeySize); - ASSERT (Key != NULL); - ZeroMem (Key, FvProtocol->KeySize); - - do { - // Search in all files - FileType = FileTypeFilter; - - Status = FvProtocol->GetNextFile (FvProtocol, Key, &FileType, &NameGuid, &Attributes, &Size); - if (!EFI_ERROR (Status)) { - UiSection = NULL; - FileStatus = FvProtocol->ReadSection ( - FvProtocol, - &NameGuid, - EFI_SECTION_USER_INTERFACE, - 0, - (VOID **)&UiSection, - &Size, - &Authentication - ); - if (!EFI_ERROR (FileStatus)) { - if (StrnCmp (FilePath, UiSection, UiStringLen) == 0) { - - // - // We found a UiString match. - // - //*FileGuid = NameGuid; - File->Type = BDS_FILETYPE_FV; - File->FilePath = FilePath; - CopyGuid (&(File->File.Fv.Guid),&NameGuid); - File->File.Fv.FvProtocol = FvProtocol; - File->File.Fv.FileType = FileType; - - Status = gBS->HandleProtocol(FvHandle,&gEfiDevicePathProtocolGuid, (VOID **)&(File->DevicePath)); - - FreePool (Key); - FreePool (UiSection); - return FileStatus; - } - FreePool (UiSection); - } - } - } while (!EFI_ERROR (Status)); - - FreePool(Key); - return Status; -} - -EFI_STATUS BdsCopyRawFileToRuntimeMemoryFV( - IN BDS_FV_FILE *FvFile, - OUT VOID **FileImage, - OUT UINTN *FileSize -) { - EFI_STATUS Status = EFI_INVALID_PARAMETER; - EFI_FIRMWARE_VOLUME2_PROTOCOL *FvProtocol; - EFI_FV_FILETYPE FileType; - EFI_GUID* NameGuid; - EFI_FV_FILE_ATTRIBUTES Attributes; - UINT32 Authentication; - - FvProtocol = FvFile->FvProtocol; - FileType = FvFile->FileType; - NameGuid = &(FvFile->Guid); - - if (FileType == EFI_FV_FILETYPE_RAW) { - *FileImage = NULL; - *FileSize = 0; - Status = FvProtocol->ReadFile( - FvProtocol,NameGuid, // IN - FileImage,FileSize, // IN OUT - &FileType,&Attributes,&Authentication // OUT - ); - ASSERT_EFI_ERROR(Status); - - // This raw file also contains a header - *FileSize = *FileSize - 4; - *FileImage = (UINT8*)FileImage + 4; - } else if (FileType == EFI_FV_FILETYPE_FREEFORM) { - Status = FvProtocol->ReadSection ( - FvProtocol,NameGuid,EFI_SECTION_RAW,0, // IN - FileImage,FileSize, // IN OUT - &Authentication // OUT - ); - ASSERT_EFI_ERROR(Status); - } else { - ASSERT(0); //Maybe support application as well ??? - } - - return Status; -} diff --git a/ArmPkg/Library/BdsLib/BdsFilePathMem.c b/ArmPkg/Library/BdsLib/BdsFilePathMem.c deleted file mode 100644 index dddaa3d670..0000000000 --- a/ArmPkg/Library/BdsLib/BdsFilePathMem.c +++ /dev/null @@ -1,73 +0,0 @@ -/** @file -* -* Copyright (c) 2011, ARM Limited. All rights reserved. -* -* This program and the accompanying materials -* are licensed and made available under the terms and conditions of the BSD License -* which accompanies this distribution. The full text of the license may be found at -* http://opensource.org/licenses/bsd-license.php -* -* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. -* -**/ - -#include "BdsInternal.h" - - -EFI_STATUS BdsLoadFileFromMemMap ( - IN EFI_HANDLE Handle, - IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, - OUT BDS_FILE *File -) { - EFI_DEVICE_PATH_PROTOCOL *LastDevicePath; - - if ((File == NULL) || (DevicePath == NULL) || (IsDevicePathEnd (DevicePath))) { - return EFI_INVALID_PARAMETER; - } - - // Check if the last node of the device Path is a Memory Map Device Node - LastDevicePath = DevicePath; - DevicePath = NextDevicePathNode(DevicePath); - while (!IsDevicePathEnd (DevicePath)) { - LastDevicePath = DevicePath; - DevicePath = NextDevicePathNode(DevicePath); - } - if ((LastDevicePath->Type != HARDWARE_DEVICE_PATH) || (LastDevicePath->SubType != HW_MEMMAP_DP)) { - return EFI_UNSUPPORTED; - } - - File->Type = BDS_FILETYPE_MEM; - File->File.Mem.MemoryType = ((MEMMAP_DEVICE_PATH*)LastDevicePath)->MemoryType; - File->File.Mem.StartingAddress = ((MEMMAP_DEVICE_PATH*)LastDevicePath)->StartingAddress; - File->File.Mem.EndingAddress = ((MEMMAP_DEVICE_PATH*)LastDevicePath)->EndingAddress; - - return EFI_SUCCESS; -} - -EFI_STATUS BdsCopyRawFileToRuntimeMemoryMemMap( - IN BDS_MEM_FILE *MemFile, - OUT VOID **FileImage, - OUT UINTN *FileSize -) { - UINTN Size; - VOID* Image; - - Size = MemFile->EndingAddress - MemFile->StartingAddress; - - if ((Size == 0) || (FileImage == NULL)) { - return EFI_INVALID_PARAMETER; - } - if (FileSize != NULL) { - *FileSize = Size; - } - - Image = AllocateRuntimePool(Size); - if (Image == NULL) { - return EFI_OUT_OF_RESOURCES; - } - - *FileImage = CopyMem(Image,(CONST VOID*)(UINTN)MemFile->StartingAddress,Size); - - return EFI_SUCCESS; -} diff --git a/ArmPkg/Library/BdsLib/BdsHelper.c b/ArmPkg/Library/BdsLib/BdsHelper.c index 88e8fa3453..fa9483ea81 100644 --- a/ArmPkg/Library/BdsLib/BdsHelper.c +++ b/ArmPkg/Library/BdsLib/BdsHelper.c @@ -1,223 +1,285 @@ -/** @file -* -* Copyright (c) 2011, ARM Limited. All rights reserved. -* -* This program and the accompanying materials -* are licensed and made available under the terms and conditions of the BSD License -* which accompanies this distribution. The full text of the license may be found at -* http://opensource.org/licenses/bsd-license.php -* -* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. -* -**/ - -#include "BdsInternal.h" - -#include -#include - -EFI_STATUS -ShutdownUefiBootServices( VOID ) -{ - EFI_STATUS Status; - UINTN MemoryMapSize; - EFI_MEMORY_DESCRIPTOR *MemoryMap; - UINTN MapKey; - UINTN DescriptorSize; - UINT32 DescriptorVersion; - UINTN Pages; - - MemoryMap = NULL; - MemoryMapSize = 0; - do { - Status = gBS->GetMemoryMap ( - &MemoryMapSize, - MemoryMap, - &MapKey, - &DescriptorSize, - &DescriptorVersion - ); - if (Status == EFI_BUFFER_TOO_SMALL) { - - Pages = EFI_SIZE_TO_PAGES (MemoryMapSize) + 1; - MemoryMap = AllocatePages (Pages); - - // - // Get System MemoryMap - // - Status = gBS->GetMemoryMap ( - &MemoryMapSize, - MemoryMap, - &MapKey, - &DescriptorSize, - &DescriptorVersion - ); - // Don't do anything between the GetMemoryMap() and ExitBootServices() - if (!EFI_ERROR (Status)) { - Status = gBS->ExitBootServices (gImageHandle, MapKey); - if (EFI_ERROR (Status)) { - FreePages (MemoryMap, Pages); - MemoryMap = NULL; - MemoryMapSize = 0; - } - } - } - } while (EFI_ERROR (Status)); - - return Status; -} - -EFI_STATUS -BdsConnectAllDrivers( VOID ) { - UINTN HandleCount, Index; - EFI_HANDLE *HandleBuffer; - EFI_STATUS Status; - - do { - // Locate all the driver handles - Status = gBS->LocateHandleBuffer ( - AllHandles, - NULL, - NULL, - &HandleCount, - &HandleBuffer - ); - if (EFI_ERROR (Status)) { - break; - } - - // Connect every handles - for (Index = 0; Index < HandleCount; Index++) { - gBS->ConnectController(HandleBuffer[Index], NULL, NULL, TRUE); - } - - if (HandleBuffer != NULL) { - FreePool (HandleBuffer); - } - - // Check if new handles have been created after the start of the previous handles - Status = gDS->Dispatch (); - } while (!EFI_ERROR(Status)); - - return EFI_SUCCESS; -} - -STATIC -EFI_STATUS -InsertSystemMemoryResources ( - LIST_ENTRY *ResourceList, - EFI_HOB_RESOURCE_DESCRIPTOR *ResHob - ) -{ - BDS_SYSTEM_MEMORY_RESOURCE *NewResource; - LIST_ENTRY *Link; - LIST_ENTRY *NextLink; - LIST_ENTRY AttachedResources; - BDS_SYSTEM_MEMORY_RESOURCE *Resource; - EFI_PHYSICAL_ADDRESS NewResourceEnd; - - if (IsListEmpty (ResourceList)) { - NewResource = AllocateZeroPool (sizeof(BDS_SYSTEM_MEMORY_RESOURCE)); - NewResource->PhysicalStart = ResHob->PhysicalStart; - NewResource->ResourceLength = ResHob->ResourceLength; - InsertTailList (ResourceList, &NewResource->Link); - return EFI_SUCCESS; - } - - InitializeListHead (&AttachedResources); - - Link = ResourceList->ForwardLink; - ASSERT (Link != NULL); - while (Link != ResourceList) { - Resource = (BDS_SYSTEM_MEMORY_RESOURCE*)Link; - - // Sanity Check. The resources should not overlapped. - ASSERT(!((ResHob->PhysicalStart >= Resource->PhysicalStart) && (ResHob->PhysicalStart < (Resource->PhysicalStart + Resource->ResourceLength)))); - ASSERT(!((ResHob->PhysicalStart + ResHob->ResourceLength - 1 >= Resource->PhysicalStart) && - ((ResHob->PhysicalStart + ResHob->ResourceLength - 1) < (Resource->PhysicalStart + Resource->ResourceLength)))); - - // The new resource is attached after this resource descriptor - if (ResHob->PhysicalStart == Resource->PhysicalStart + Resource->ResourceLength) { - Resource->ResourceLength = Resource->ResourceLength + ResHob->ResourceLength; - - NextLink = RemoveEntryList (&Resource->Link); - InsertTailList (&AttachedResources, &Resource->Link); - Link = NextLink; - } - // The new resource is attached before this resource descriptor - else if (ResHob->PhysicalStart + ResHob->ResourceLength == Resource->PhysicalStart) { - Resource->PhysicalStart = ResHob->PhysicalStart; - Resource->ResourceLength = Resource->ResourceLength + ResHob->ResourceLength; - - NextLink = RemoveEntryList (&Resource->Link); - InsertTailList (&AttachedResources, &Resource->Link); - Link = NextLink; - } else { - Link = Link->ForwardLink; - } - } - - if (!IsListEmpty (&AttachedResources)) { - // See if we can merge the attached resource with other resources - - NewResource = (BDS_SYSTEM_MEMORY_RESOURCE*)GetFirstNode (&AttachedResources); - Link = RemoveEntryList (&NewResource->Link); - while (!IsListEmpty (&AttachedResources)) { - // Merge resources - Resource = (BDS_SYSTEM_MEMORY_RESOURCE*)Link; - - // Ensure they overlap each other - ASSERT( - ((NewResource->PhysicalStart >= Resource->PhysicalStart) && (NewResource->PhysicalStart < (Resource->PhysicalStart + Resource->ResourceLength))) || - (((NewResource->PhysicalStart + NewResource->ResourceLength) >= Resource->PhysicalStart) && ((NewResource->PhysicalStart + NewResource->ResourceLength) < (Resource->PhysicalStart + Resource->ResourceLength))) - ); - - NewResourceEnd = MAX (NewResource->PhysicalStart + NewResource->ResourceLength, Resource->PhysicalStart + Resource->ResourceLength); - NewResource->PhysicalStart = MIN (NewResource->PhysicalStart, Resource->PhysicalStart); - NewResource->ResourceLength = NewResourceEnd - NewResource->PhysicalStart; - - Link = RemoveEntryList (Link); - } - } else { - // None of the Resource of the list is attached to this ResHob. Create a new entry for it - NewResource = AllocateZeroPool (sizeof(BDS_SYSTEM_MEMORY_RESOURCE)); - NewResource->PhysicalStart = ResHob->PhysicalStart; - NewResource->ResourceLength = ResHob->ResourceLength; - } - InsertTailList (ResourceList, &NewResource->Link); - return EFI_SUCCESS; -} - -EFI_STATUS -GetSystemMemoryResources ( - IN LIST_ENTRY *ResourceList - ) -{ - EFI_HOB_RESOURCE_DESCRIPTOR *ResHob; - - InitializeListHead (ResourceList); - - // Find the first System Memory Resource Descriptor - ResHob = (EFI_HOB_RESOURCE_DESCRIPTOR *)GetFirstHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR); - while ((ResHob != NULL) && (ResHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY)) { - ResHob = (EFI_HOB_RESOURCE_DESCRIPTOR *)GetNextHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR,(VOID *)((UINTN)ResHob + ResHob->Header.HobLength)); - } - - // Did not find any - if (ResHob == NULL) { - return EFI_NOT_FOUND; - } else { - InsertSystemMemoryResources (ResourceList, ResHob); - } - - ResHob = (EFI_HOB_RESOURCE_DESCRIPTOR *)GetNextHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR,(VOID *)((UINTN)ResHob + ResHob->Header.HobLength)); - while (ResHob != NULL) { - if (ResHob->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) { - InsertSystemMemoryResources (ResourceList, ResHob); - } - ResHob = (EFI_HOB_RESOURCE_DESCRIPTOR *)GetNextHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR,(VOID *)((UINTN)ResHob + ResHob->Header.HobLength)); - } - - return EFI_SUCCESS; -} +/** @file +* +* Copyright (c) 2011, ARM Limited. All rights reserved. +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the BSD License +* which accompanies this distribution. The full text of the license may be found at +* http://opensource.org/licenses/bsd-license.php +* +* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +* +**/ + +#include "BdsInternal.h" + +#include +#include +#include +#include +#include + +STATIC CHAR8 *mTokenList[] = { + /*"SEC",*/ + "PEI", + "DXE", + "BDS", + NULL +}; + +EFI_STATUS +ShutdownUefiBootServices ( + VOID + ) +{ + EFI_STATUS Status; + UINTN MemoryMapSize; + EFI_MEMORY_DESCRIPTOR *MemoryMap; + UINTN MapKey; + UINTN DescriptorSize; + UINT32 DescriptorVersion; + UINTN Pages; + + MemoryMap = NULL; + MemoryMapSize = 0; + do { + Status = gBS->GetMemoryMap ( + &MemoryMapSize, + MemoryMap, + &MapKey, + &DescriptorSize, + &DescriptorVersion + ); + if (Status == EFI_BUFFER_TOO_SMALL) { + + Pages = EFI_SIZE_TO_PAGES (MemoryMapSize) + 1; + MemoryMap = AllocatePages (Pages); + + // + // Get System MemoryMap + // + Status = gBS->GetMemoryMap ( + &MemoryMapSize, + MemoryMap, + &MapKey, + &DescriptorSize, + &DescriptorVersion + ); + // Don't do anything between the GetMemoryMap() and ExitBootServices() + if (!EFI_ERROR (Status)) { + Status = gBS->ExitBootServices (gImageHandle, MapKey); + if (EFI_ERROR (Status)) { + FreePages (MemoryMap, Pages); + MemoryMap = NULL; + MemoryMapSize = 0; + } + } + } + } while (EFI_ERROR (Status)); + + return Status; +} + +/** + Connect all DXE drivers + + @retval EFI_SUCCESS All drivers have been connected + @retval EFI_NOT_FOUND No handles match the search. + @retval EFI_OUT_OF_RESOURCES There is not resource pool memory to store the matching results. + +**/ +EFI_STATUS +BdsConnectAllDrivers ( + VOID + ) +{ + UINTN HandleCount, Index; + EFI_HANDLE *HandleBuffer; + EFI_STATUS Status; + + do { + // Locate all the driver handles + Status = gBS->LocateHandleBuffer ( + AllHandles, + NULL, + NULL, + &HandleCount, + &HandleBuffer + ); + if (EFI_ERROR (Status)) { + break; + } + + // Connect every handles + for (Index = 0; Index < HandleCount; Index++) { + gBS->ConnectController (HandleBuffer[Index], NULL, NULL, TRUE); + } + + if (HandleBuffer != NULL) { + FreePool (HandleBuffer); + } + + // Check if new handles have been created after the start of the previous handles + Status = gDS->Dispatch (); + } while (!EFI_ERROR(Status)); + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +InsertSystemMemoryResources ( + LIST_ENTRY *ResourceList, + EFI_HOB_RESOURCE_DESCRIPTOR *ResHob + ) +{ + BDS_SYSTEM_MEMORY_RESOURCE *NewResource; + LIST_ENTRY *Link; + LIST_ENTRY *NextLink; + LIST_ENTRY AttachedResources; + BDS_SYSTEM_MEMORY_RESOURCE *Resource; + EFI_PHYSICAL_ADDRESS NewResourceEnd; + + if (IsListEmpty (ResourceList)) { + NewResource = AllocateZeroPool (sizeof(BDS_SYSTEM_MEMORY_RESOURCE)); + NewResource->PhysicalStart = ResHob->PhysicalStart; + NewResource->ResourceLength = ResHob->ResourceLength; + InsertTailList (ResourceList, &NewResource->Link); + return EFI_SUCCESS; + } + + InitializeListHead (&AttachedResources); + + Link = ResourceList->ForwardLink; + ASSERT (Link != NULL); + while (Link != ResourceList) { + Resource = (BDS_SYSTEM_MEMORY_RESOURCE*)Link; + + // Sanity Check. The resources should not overlapped. + ASSERT(!((ResHob->PhysicalStart >= Resource->PhysicalStart) && (ResHob->PhysicalStart < (Resource->PhysicalStart + Resource->ResourceLength)))); + ASSERT(!((ResHob->PhysicalStart + ResHob->ResourceLength - 1 >= Resource->PhysicalStart) && + ((ResHob->PhysicalStart + ResHob->ResourceLength - 1) < (Resource->PhysicalStart + Resource->ResourceLength)))); + + // The new resource is attached after this resource descriptor + if (ResHob->PhysicalStart == Resource->PhysicalStart + Resource->ResourceLength) { + Resource->ResourceLength = Resource->ResourceLength + ResHob->ResourceLength; + + NextLink = RemoveEntryList (&Resource->Link); + InsertTailList (&AttachedResources, &Resource->Link); + Link = NextLink; + } + // The new resource is attached before this resource descriptor + else if (ResHob->PhysicalStart + ResHob->ResourceLength == Resource->PhysicalStart) { + Resource->PhysicalStart = ResHob->PhysicalStart; + Resource->ResourceLength = Resource->ResourceLength + ResHob->ResourceLength; + + NextLink = RemoveEntryList (&Resource->Link); + InsertTailList (&AttachedResources, &Resource->Link); + Link = NextLink; + } else { + Link = Link->ForwardLink; + } + } + + if (!IsListEmpty (&AttachedResources)) { + // See if we can merge the attached resource with other resources + + NewResource = (BDS_SYSTEM_MEMORY_RESOURCE*)GetFirstNode (&AttachedResources); + Link = RemoveEntryList (&NewResource->Link); + while (!IsListEmpty (&AttachedResources)) { + // Merge resources + Resource = (BDS_SYSTEM_MEMORY_RESOURCE*)Link; + + // Ensure they overlap each other + ASSERT( + ((NewResource->PhysicalStart >= Resource->PhysicalStart) && (NewResource->PhysicalStart < (Resource->PhysicalStart + Resource->ResourceLength))) || + (((NewResource->PhysicalStart + NewResource->ResourceLength) >= Resource->PhysicalStart) && ((NewResource->PhysicalStart + NewResource->ResourceLength) < (Resource->PhysicalStart + Resource->ResourceLength))) + ); + + NewResourceEnd = MAX (NewResource->PhysicalStart + NewResource->ResourceLength, Resource->PhysicalStart + Resource->ResourceLength); + NewResource->PhysicalStart = MIN (NewResource->PhysicalStart, Resource->PhysicalStart); + NewResource->ResourceLength = NewResourceEnd - NewResource->PhysicalStart; + + Link = RemoveEntryList (Link); + } + } else { + // None of the Resource of the list is attached to this ResHob. Create a new entry for it + NewResource = AllocateZeroPool (sizeof(BDS_SYSTEM_MEMORY_RESOURCE)); + NewResource->PhysicalStart = ResHob->PhysicalStart; + NewResource->ResourceLength = ResHob->ResourceLength; + } + InsertTailList (ResourceList, &NewResource->Link); + return EFI_SUCCESS; +} + +EFI_STATUS +GetSystemMemoryResources ( + IN LIST_ENTRY *ResourceList + ) +{ + EFI_HOB_RESOURCE_DESCRIPTOR *ResHob; + + InitializeListHead (ResourceList); + + // Find the first System Memory Resource Descriptor + ResHob = (EFI_HOB_RESOURCE_DESCRIPTOR *)GetFirstHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR); + while ((ResHob != NULL) && (ResHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY)) { + ResHob = (EFI_HOB_RESOURCE_DESCRIPTOR *)GetNextHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR,(VOID *)((UINTN)ResHob + ResHob->Header.HobLength)); + } + + // Did not find any + if (ResHob == NULL) { + return EFI_NOT_FOUND; + } else { + InsertSystemMemoryResources (ResourceList, ResHob); + } + + ResHob = (EFI_HOB_RESOURCE_DESCRIPTOR *)GetNextHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR,(VOID *)((UINTN)ResHob + ResHob->Header.HobLength)); + while (ResHob != NULL) { + if (ResHob->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) { + InsertSystemMemoryResources (ResourceList, ResHob); + } + ResHob = (EFI_HOB_RESOURCE_DESCRIPTOR *)GetNextHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR,(VOID *)((UINTN)ResHob + ResHob->Header.HobLength)); + } + + return EFI_SUCCESS; +} + +VOID +PrintPerformance ( + VOID + ) +{ + UINTN Key; + CONST VOID *Handle; + CONST CHAR8 *Token, *Module; + UINT64 Start, Stop, TimeStamp; + UINT64 Delta, TicksPerSecond, Milliseconds; + UINTN Index; + CHAR8 Buffer[100]; + UINTN CharCount; + + TicksPerSecond = GetPerformanceCounterProperties (NULL, NULL); + + TimeStamp = 0; + Key = 0; + do { + Key = GetPerformanceMeasurement (Key, (CONST VOID **)&Handle, &Token, &Module, &Start, &Stop); + if (Key != 0) { + for (Index = 0; mTokenList[Index] != NULL; Index++) { + if (AsciiStriCmp (mTokenList[Index], Token) == 0) { + Delta = Start - Stop; + TimeStamp += Delta; + Milliseconds = DivU64x64Remainder (MultU64x32 (Delta, 1000), TicksPerSecond, NULL); + CharCount = AsciiSPrint (Buffer,sizeof (Buffer),"%6a %6ld ms\n", Token, Milliseconds); + SerialPortWrite ((UINT8 *) Buffer, CharCount); + break; + } + } + } + } while (Key != 0); + + CharCount = AsciiSPrint (Buffer,sizeof (Buffer),"Total Time = %ld ms\n\n", DivU64x64Remainder (MultU64x32 (TimeStamp, 1000), TicksPerSecond, NULL)); + SerialPortWrite ((UINT8 *) Buffer, CharCount); +} diff --git a/ArmPkg/Library/BdsLib/BdsInternal.h b/ArmPkg/Library/BdsLib/BdsInternal.h index 07f722e03f..a497df03ea 100644 --- a/ArmPkg/Library/BdsLib/BdsInternal.h +++ b/ArmPkg/Library/BdsLib/BdsInternal.h @@ -24,6 +24,7 @@ #include #include #include +#include #include @@ -31,106 +32,58 @@ #include #include #include +#include +#include -typedef enum { BDS_FILETYPE_MEM, BDS_FILETYPE_FS, BDS_FILETYPE_FV } BDS_FILE_TYPE; +typedef BOOLEAN (*BDS_FILE_LOADER_SUPPORT) ( + IN EFI_DEVICE_PATH *DevicePath, + IN EFI_HANDLE Handle, + IN EFI_DEVICE_PATH *RemainingDevicePath + ); -typedef struct { - UINT32 MemoryType; - EFI_PHYSICAL_ADDRESS StartingAddress; - EFI_PHYSICAL_ADDRESS EndingAddress; -} BDS_MEM_FILE; - -typedef struct { - EFI_FILE_PROTOCOL *Handle; -} BDS_FS_FILE; +typedef EFI_STATUS (*BDS_FILE_LOADER_LOAD_IMAGE) ( + IN EFI_DEVICE_PATH *DevicePath, + IN EFI_HANDLE Handle, + IN EFI_DEVICE_PATH *RemainingDevicePath, + IN EFI_ALLOCATE_TYPE Type, + IN OUT EFI_PHYSICAL_ADDRESS* Image, + OUT UINTN *ImageSize + ); typedef struct { - EFI_FIRMWARE_VOLUME2_PROTOCOL *FvProtocol; - EFI_FV_FILETYPE FileType; - EFI_GUID Guid; -} BDS_FV_FILE; - -typedef struct _BDS_FILE { - CHAR16* FilePath; - EFI_DEVICE_PATH_PROTOCOL *DevicePath; - BDS_FILE_TYPE Type; - union { - BDS_MEM_FILE Mem; - BDS_FS_FILE Fs; - BDS_FV_FILE Fv; - } File; -} BDS_FILE; + BDS_FILE_LOADER_SUPPORT Support; + BDS_FILE_LOADER_LOAD_IMAGE LoadImage; +} BDS_FILE_LOADER; typedef struct _BDS_SYSTEM_MEMORY_RESOURCE { - LIST_ENTRY Link; // This attribute must be the first entry of this structure (to avoid pointer computation) - EFI_PHYSICAL_ADDRESS PhysicalStart; - UINT64 ResourceLength; + LIST_ENTRY Link; // This attribute must be the first entry of this structure (to avoid pointer computation) + EFI_PHYSICAL_ADDRESS PhysicalStart; + UINT64 ResourceLength; } BDS_SYSTEM_MEMORY_RESOURCE; // BdsHelper.c EFI_STATUS -ShutdownUefiBootServices( VOID ); +ShutdownUefiBootServices ( + VOID + ); EFI_STATUS -GetSystemMemoryResources (LIST_ENTRY *ResourceList); - -// BdsFilePath.c -EFI_STATUS BdsLoadDevicePath( - IN EFI_DEVICE_PATH_PROTOCOL* DevicePath, - OUT EFI_HANDLE *Handle -); - -EFI_STATUS BdsLoadFilePath( - IN CONST CHAR16 *DeviceFilePath, - OUT BDS_FILE *File -); - -EFI_STATUS BdsCopyRawFileToRuntimeMemory( - IN BDS_FILE *File, - OUT VOID **FileImage, - OUT UINTN *FileSize -); - -// BdsFilePathFs.c -EFI_STATUS BdsLoadFileFromSimpleFileSystem( - IN EFI_HANDLE Handle, - IN CHAR16 *FilePath, - OUT BDS_FILE *File -); - -EFI_STATUS BdsCopyRawFileToRuntimeMemoryFS( - IN EFI_FILE_PROTOCOL *File, - OUT VOID **FileImage, - OUT UINTN *FileSize -); - -// BdsFilePathFv.c -EFI_STATUS BdsLoadFileFromFirmwareVolume( - IN EFI_HANDLE FvHandle, - IN CHAR16 *FilePath, - IN EFI_FV_FILETYPE FileTypeFilter, - OUT BDS_FILE *File -); - -EFI_STATUS BdsCopyRawFileToRuntimeMemoryFV( - IN BDS_FV_FILE *FvFile, - OUT VOID **FileImage, - OUT UINTN *FileSize -); - -// BdsFilePathMem.c -EFI_STATUS BdsLoadFileFromMemMap ( - IN EFI_HANDLE Handle, - IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, - OUT BDS_FILE *File -); - -EFI_STATUS BdsCopyRawFileToRuntimeMemoryMemMap( - IN BDS_MEM_FILE *MemFile, - OUT VOID **FileImage, - OUT UINTN *FileSize -); +GetSystemMemoryResources ( + LIST_ENTRY *ResourceList + ); + +VOID +PrintPerformance ( + VOID + ); +EFI_STATUS +BdsLoadImage ( + IN EFI_DEVICE_PATH *DevicePath, + IN EFI_ALLOCATE_TYPE Type, + IN OUT EFI_PHYSICAL_ADDRESS* Image, + OUT UINTN *FileSize + ); #endif diff --git a/ArmPkg/Library/BdsLib/BdsLib.inf b/ArmPkg/Library/BdsLib/BdsLib.inf index 223f47b3db..d74eeda3a1 100644 --- a/ArmPkg/Library/BdsLib/BdsLib.inf +++ b/ArmPkg/Library/BdsLib/BdsLib.inf @@ -15,15 +15,12 @@ INF_VERSION = 0x00010005 BASE_NAME = BdsLib FILE_GUID = ddbf73a0-bb25-11df-8e4e-0002a5d5c51b - MODULE_TYPE = UEFI_DRIVER + MODULE_TYPE = DXE_DRIVER VERSION_STRING = 1.0 LIBRARY_CLASS = BdsLib [Sources.common] BdsFilePath.c - BdsFilePathFs.c - BdsFilePathFv.c - BdsFilePathMem.c BdsLinuxLoader.c BdsAppLoader.c BdsHelper.c @@ -34,13 +31,12 @@ ArmPkg/ArmPkg.dec [LibraryClasses] - DevicePathLib + ArmLib BaseLib - HobLib DebugLib - UefiDriverEntryPoint - DxeServicesTableLib - ArmLib + DevicePathLib + HobLib + PerformanceLib [Guids] gEfiFileInfoGuid @@ -51,11 +47,20 @@ gEfiDevicePathFromTextProtocolGuid gEfiSimpleFileSystemProtocolGuid gEfiFirmwareVolume2ProtocolGuid + gEfiLoadFileProtocolGuid + gEfiPxeBaseCodeProtocolGuid + gEfiDiskIoProtocolGuid + gEfiUsbIoProtocolGuid [FeaturePcd] [FixedPcd] + gArmTokenSpaceGuid.PcdSystemMemoryBase + gArmTokenSpaceGuid.PcdSystemMemorySize + gArmTokenSpaceGuid.PcdArmMachineType + gArmTokenSpaceGuid.PcdArmLinuxKernelMaxOffset + gArmTokenSpaceGuid.PcdArmLinuxAtagMaxOffset [Pcd] diff --git a/ArmPkg/Library/BdsLib/BdsLinuxLoader.c b/ArmPkg/Library/BdsLib/BdsLinuxLoader.c index 69435936b7..ca5e547043 100644 --- a/ArmPkg/Library/BdsLib/BdsLinuxLoader.c +++ b/ArmPkg/Library/BdsLib/BdsLinuxLoader.c @@ -19,58 +19,53 @@ #include #include -STATIC -EFI_STATUS -GetARMLinuxMachineType ( - IN BOOLEAN FdtSupported, - OUT UINT32 *MachineType -) { - if (FdtSupported) - { - // FDT requires that the machine type is set to the maximum 32-bit number. - *MachineType = 0xFFFFFFFF; - } - else - { - // Non-FDT requires a specific machine type. - // This OS Boot loader supports just one machine type, - // but that could change in the future. - *MachineType = PcdGet32(PcdArmMachineType); - } +#define ALIGN32_BELOW(addr) ALIGN_POINTER(addr - 32,32) - return EFI_SUCCESS; -} +#define LINUX_ATAG_MAX_OFFSET (PcdGet32(PcdSystemMemoryBase) + PcdGet32(PcdArmLinuxAtagMaxOffset)) +#define LINUX_KERNEL_MAX_OFFSET (PcdGet32(PcdSystemMemoryBase) + PcdGet32(PcdArmLinuxKernelMaxOffset)) + +// Point to the current ATAG +STATIC LINUX_ATAG *mLinuxKernelCurrentAtag; STATIC VOID -SetupCoreTag( IN UINT32 PageSize ) +SetupCoreTag ( + IN UINT32 PageSize + ) { - Params->header.size = tag_size(atag_core); - Params->header.type = ATAG_CORE; + mLinuxKernelCurrentAtag->header.size = tag_size(LINUX_ATAG_CORE); + mLinuxKernelCurrentAtag->header.type = ATAG_CORE; - Params->body.core_tag.flags = 1; /* ensure read-only */ - Params->body.core_tag.pagesize = PageSize; /* systems PageSize (4k) */ - Params->body.core_tag.rootdev = 0; /* zero root device (typically overridden from kernel command line )*/ + mLinuxKernelCurrentAtag->body.core_tag.flags = 1; /* ensure read-only */ + mLinuxKernelCurrentAtag->body.core_tag.pagesize = PageSize; /* systems PageSize (4k) */ + mLinuxKernelCurrentAtag->body.core_tag.rootdev = 0; /* zero root device (typically overridden from kernel command line )*/ - Params = next_tag_address(Params); /* move pointer to next tag */ + // move pointer to next tag + mLinuxKernelCurrentAtag = next_tag_address(mLinuxKernelCurrentAtag); } STATIC VOID -SetupMemTag( IN UINTN StartAddress, IN UINT32 Size ) +SetupMemTag ( + IN UINTN StartAddress, + IN UINT32 Size + ) { - Params->header.size = tag_size(atag_mem); - Params->header.type = ATAG_MEM; + mLinuxKernelCurrentAtag->header.size = tag_size(LINUX_ATAG_MEM); + mLinuxKernelCurrentAtag->header.type = ATAG_MEM; - Params->body.mem_tag.start = StartAddress; /* Start of memory chunk for AtagMem */ - Params->body.mem_tag.size = Size; /* Size of memory chunk for AtagMem */ + mLinuxKernelCurrentAtag->body.mem_tag.start = StartAddress; /* Start of memory chunk for AtagMem */ + mLinuxKernelCurrentAtag->body.mem_tag.size = Size; /* Size of memory chunk for AtagMem */ - Params = next_tag_address(Params); /* move pointer to next tag */ + // move pointer to next tag + mLinuxKernelCurrentAtag = next_tag_address(mLinuxKernelCurrentAtag); } STATIC VOID -SetupCmdlineTag( IN CONST CHAR8 *CmdLine ) +SetupCmdlineTag ( + IN CONST CHAR8 *CmdLine + ) { UINT32 LineLength; @@ -81,98 +76,92 @@ SetupCmdlineTag( IN CONST CHAR8 *CmdLine ) * Do not insert a tag for an empty CommandLine, don't even modify the tag address pointer. * Remember, you have at least one null string terminator character. */ - if( LineLength > 1 ) - { - Params->header.size = ((UINT32)sizeof(struct atag_header) + LineLength + (UINT32)3) >> 2; - Params->header.type = ATAG_CMDLINE; + if(LineLength > 1) { + mLinuxKernelCurrentAtag->header.size = ((UINT32)sizeof(LINUX_ATAG_HEADER) + LineLength + (UINT32)3) >> 2; + mLinuxKernelCurrentAtag->header.type = ATAG_CMDLINE; /* place CommandLine into tag */ - AsciiStrCpy(Params->body.cmdline_tag.cmdline, CmdLine); + AsciiStrCpy(mLinuxKernelCurrentAtag->body.cmdline_tag.cmdline, CmdLine); - Params = next_tag_address(Params); /* move pointer to next tag */ + // move pointer to next tag + mLinuxKernelCurrentAtag = next_tag_address(mLinuxKernelCurrentAtag); } } STATIC VOID -SetupEndTag( VOID ) +SetupEndTag ( + VOID + ) { // Empty tag ends list; this has zero length and no body - Params->header.type = ATAG_NONE; - Params->header.size = 0; + mLinuxKernelCurrentAtag->header.type = ATAG_NONE; + mLinuxKernelCurrentAtag->header.size = 0; /* We can not calculate the next address by using the standard macro: * Params = next_tag_address(Params); * because it relies on the header.size, which here it is 0 (zero). - * The easiest way is to add the sizeof(Params->header). + * The easiest way is to add the sizeof(mLinuxKernelCurrentAtag->header). */ - Params = (struct atag *)((UINT32)Params + sizeof(Params->header)); + mLinuxKernelCurrentAtag = (LINUX_ATAG*)((UINT32)mLinuxKernelCurrentAtag + sizeof(mLinuxKernelCurrentAtag->header)); } STATIC EFI_STATUS -PrepareAtagList( - IN OUT struct atag **AtagStartAddress, - IN CONST CHAR8* CommandLineString, - OUT UINT32 *AtagSize -) { - LIST_ENTRY *ResourceLink; - LIST_ENTRY ResourceList; +PrepareAtagList ( + IN CONST CHAR8* CommandLineString, + OUT LINUX_ATAG **AtagBase, + OUT UINT32 *AtagSize + ) +{ + EFI_STATUS Status; + LIST_ENTRY *ResourceLink; + LIST_ENTRY ResourceList; + EFI_PHYSICAL_ADDRESS AtagStartAddress; BDS_SYSTEM_MEMORY_RESOURCE *Resource; - // If no address supplied then this function will decide where to put it - if( *AtagStartAddress == 0 ) - { - /* WARNING: At the time of writing (2010-July-30) the linux kernel expects - * the atag list it in the first 1MB of memory and preferably at address 0x100. - * This has a very high risk of overwriting UEFI code, but as - * the linux kernel does not expect any runtime services from uefi - * and there is no afterlife section following the linux kernel termination, - * it does not matter if we stamp over that memory area. - * - * The proposed workaround is to create the atag list somewhere in boot services memory - * and then transfer it to address 0x100 (or to runtime services memory) immediately - * before starting the kernel. - * An additional benefit of this is that when we copy the ATAG list to it's final place, - * we can trim down the memory allocation size. Before we create the list we don't know - * how much space it is going to take, so we are over-allocating space. - */ - *AtagStartAddress = (struct atag *) AllocatePool(ATAG_MAX_SIZE); + AtagStartAddress = LINUX_ATAG_MAX_OFFSET; + Status = gBS->AllocatePages (AllocateMaxAddress, EfiBootServicesData, EFI_SIZE_TO_PAGES(ATAG_MAX_SIZE), &AtagStartAddress); + if (EFI_ERROR(Status)) { + DEBUG ((EFI_D_ERROR,"Failed to allocate Atag at 0x%lX (%r)\n",AtagStartAddress,Status)); + Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesData, EFI_SIZE_TO_PAGES(ATAG_MAX_SIZE), &AtagStartAddress); + ASSERT_EFI_ERROR(Status); } - // Ensure the pointer is not NULL. - ASSERT( *AtagStartAddress != (struct atag *)NULL ); - // Ready to setup the atag list - Params = *AtagStartAddress; + mLinuxKernelCurrentAtag = (LINUX_ATAG*)(UINTN)AtagStartAddress; // Standard core tag 4k PageSize SetupCoreTag( (UINT32)SIZE_4KB ); // Physical memory setup - GetSystemMemoryResources(&ResourceList); + GetSystemMemoryResources (&ResourceList); ResourceLink = ResourceList.ForwardLink; while (ResourceLink != NULL && ResourceLink != &ResourceList) { - Resource = (BDS_SYSTEM_MEMORY_RESOURCE*)ResourceList.ForwardLink; + Resource = (BDS_SYSTEM_MEMORY_RESOURCE*)ResourceLink; + DEBUG((EFI_D_INFO,"- [0x%08X,0x%08X]\n",(UINT32)Resource->PhysicalStart,(UINT32)Resource->PhysicalStart+(UINT32)Resource->ResourceLength)); SetupMemTag( (UINT32)Resource->PhysicalStart, (UINT32)Resource->ResourceLength ); ResourceLink = ResourceLink->ForwardLink; } // CommandLine setting root device - SetupCmdlineTag( CommandLineString ); + SetupCmdlineTag (CommandLineString); // end of tags SetupEndTag(); // Calculate atag list size - *AtagSize = (UINT32)Params - (UINT32)*AtagStartAddress + 1; + *AtagBase = (LINUX_ATAG*)(UINTN)AtagStartAddress; + *AtagSize = (UINT32)mLinuxKernelCurrentAtag - (UINT32)AtagStartAddress + 1; return EFI_SUCCESS; } STATIC EFI_STATUS -PreparePlatformHardware( VOID ) +PreparePlatformHardware ( + VOID + ) { //Note: Interrupts will be disabled by the GIC driver when ExitBootServices() will be called. @@ -185,153 +174,131 @@ PreparePlatformHardware( VOID ) ArmDisableInstructionCache (); // turn off MMU - ArmInvalidateTlb(); ArmDisableMmu(); return EFI_SUCCESS; } -/************************************************* - * R0, R1, R2 correspond to registers R0, R1, R2 - *************************************************/ -//STATIC -EFI_STATUS -StartLinuxKernel( IN VOID* KernelAddress, IN UINTN R0, IN UINTN R1, IN UINTN R2 ) -{ - VOID (*Kernel)(UINT32 Zero, UINT32 Arch, UINTN AtagListParams); +/** + Start a Linux kernel from a Device Path - // set the kernel address - Kernel = (VOID (*)(UINT32, UINT32, UINTN)) KernelAddress; + @param LinuxKernel Device Path to the Linux Kernel + @param Parameters Linux kernel agruments + @param Fdt Device Path to the Flat Device Tree - // Outside BootServices, so can't use Print(); - DEBUG((EFI_D_ERROR, "\nStarting the kernel:\n\n")); + @retval EFI_SUCCESS All drivers have been connected + @retval EFI_NOT_FOUND The Linux kernel Device Path has not been found + @retval EFI_OUT_OF_RESOURCES There is not enough resource memory to store the matching results. - // jump to kernel with register set - Kernel( R0, R1, R2 ); +**/ +EFI_STATUS +BdsBootLinux ( + IN EFI_DEVICE_PATH_PROTOCOL* LinuxKernelDevicePath, + IN CONST CHAR8* Arguments, + IN EFI_DEVICE_PATH_PROTOCOL* FdtDevicePath + ) +{ + EFI_STATUS Status; + UINT32 LinuxImageSize; + UINT32 KernelParamsSize; + VOID* KernelParamsAddress = NULL; + UINT32 MachineType; + BOOLEAN FdtSupported = FALSE; + LINUX_KERNEL LinuxKernel; + EFI_PHYSICAL_ADDRESS LinuxImage;; + + + PERF_START (NULL, "BDS", NULL, 0); + + // Load the Linux kernel from a device path + LinuxImage = LINUX_KERNEL_MAX_OFFSET; + Status = BdsLoadImage (LinuxKernelDevicePath, AllocateMaxAddress, &LinuxImage, &LinuxImageSize); + if (EFI_ERROR(Status)) { + DEBUG ((EFI_D_ERROR, "ERROR: Do not find Linux kernel.\n")); + return Status; + } + LinuxKernel = (LINUX_KERNEL)(UINTN)LinuxImage; - // Kernel should never exit - // After Life services are not provided - ASSERT( FALSE ); + // Load the FDT binary from a device path + KernelParamsAddress = (VOID*)LINUX_ATAG_MAX_OFFSET; + Status = BdsLoadImage (FdtDevicePath, AllocateMaxAddress, (EFI_PHYSICAL_ADDRESS*)&KernelParamsAddress, &KernelParamsSize); + if (!EFI_ERROR(Status)) { + FdtSupported = TRUE; + } - return EFI_SUCCESS; -} + // + // Setup the Linux Kernel Parameters + // + if (!FdtSupported) { + // Non-FDT requires a specific machine type. + // This OS Boot loader supports just one machine type, + // but that could change in the future. + MachineType = PcdGet32(PcdArmMachineType); -EFI_STATUS BdsBootLinux( - IN CONST CHAR16* LinuxKernel, - IN CONST CHAR8* ATag, - IN CONST CHAR16* Fdt -) { - BDS_FILE LinuxKernelFile; - BDS_FILE FdtFile; - EFI_STATUS Status; - VOID* LinuxImage; - - UINT32 KernelParamsSize; - VOID* KernelParamsAddress = NULL; - UINTN KernelParamsNewAddress; - UINTN *AtagAddress; - UINT32 MachineType; - BOOLEAN FdtSupported = FALSE; - EFI_HOB_RESOURCE_DESCRIPTOR *ResHob; - - // Load the Linux kernel from a device path - Status = BdsLoadFilePath(LinuxKernel, &LinuxKernelFile); - if (EFI_ERROR(Status)) { - DEBUG ((EFI_D_ERROR, "ERROR: Do not find Linux kernel %s\n",LinuxKernel)); - return Status; + // By setting address=0 we leave the memory allocation to the function + Status = PrepareAtagList (Arguments, (LINUX_ATAG**)&KernelParamsAddress, &KernelParamsSize); + if(EFI_ERROR(Status)) { + Print(L"ERROR: Can not prepare ATAG list. Status=0x%X\n", Status); + goto Exit; } + } else { + MachineType = 0xFFFFFFFF; + } - // Copy the Linux Kernel from the raw file to Runtime memory - Status = BdsCopyRawFileToRuntimeMemory(&LinuxKernelFile,&LinuxImage,NULL); - if (EFI_ERROR(Status)) { - goto Exit; - } + // Shut down UEFI boot services. ExitBootServices() will notify every driver that created an event on + // ExitBootServices event. Example the Interrupt DXE driver will disable the interrupts on this event. + Status = ShutdownUefiBootServices (); + if(EFI_ERROR(Status)) { + DEBUG((EFI_D_ERROR,"ERROR: Can not shutdown UEFI boot services. Status=0x%X\n", Status)); + goto Exit; + } - // Load the FDT binary from a device path - Status = BdsLoadFilePath(Fdt, &FdtFile); - if (!EFI_ERROR(Status)) { - // Copy the FDT binary from the raw file to Runtime memory - Status = BdsCopyRawFileToRuntimeMemory(&FdtFile,&KernelParamsAddress,&KernelParamsSize); - if (EFI_ERROR(Status)) { - goto Exit; - } else { - FdtSupported = TRUE; - } - } + // Move the kernel parameters to any address inside the first 1MB. + // This is necessary because the ARM Linux kernel requires + // the FTD / ATAG List to reside entirely inside the first 1MB of + // physical memory. + if ((UINTN)KernelParamsAddress > LINUX_ATAG_MAX_OFFSET) { + //Note: There is no requirement on the alignment + KernelParamsAddress = CopyMem (ALIGN32_BELOW(LINUX_ATAG_MAX_OFFSET - KernelParamsSize), KernelParamsAddress, KernelParamsSize); + } - /********************************************************** - * Setup the platform type - **********************************************************/ - Status = GetARMLinuxMachineType(FdtSupported, &MachineType); - if(EFI_ERROR(Status)) - { - Print(L"ERROR : Can not prepare ARM Linux machine type. Status=0x%X\n", Status); - goto Exit; - } + if ((UINTN)LinuxImage > LINUX_KERNEL_MAX_OFFSET) { + //Note: There is no requirement on the alignment + LinuxKernel = (LINUX_KERNEL)CopyMem (ALIGN32_BELOW(LINUX_KERNEL_MAX_OFFSET - LinuxImageSize), (VOID*)(UINTN)LinuxImage, LinuxImageSize); + } - if (!FdtSupported) { - /********************************************************** - * Setup the ATAG list - **********************************************************/ - // By setting address=0 we leave the memory allocation to the function - AtagAddress = 0; - Status = PrepareAtagList( (struct atag **)&AtagAddress, ATag, &KernelParamsSize ); - KernelParamsAddress = (VOID*)AtagAddress; - if(EFI_ERROR(Status)) - { - Print(L"ERROR : Can not prepare ATAG list. Status=0x%X\n", Status); - goto Exit; - } - } + //TODO: Check there is no overlapping between kernel and Atag - /********************************************************** - * Switch off interrupts, caches, mmu, etc - **********************************************************/ - Status = PreparePlatformHardware(); - if(EFI_ERROR(Status)) - { - Print(L"ERROR : Can not prepare platform hardware. Status=0x%X\n", Status); - goto Exit; - } + // + // Switch off interrupts, caches, mmu, etc + // + Status = PreparePlatformHardware (); + ASSERT_EFI_ERROR(Status); - // Initialize the ATag destination - KernelParamsNewAddress = 0x100; - - // Update the ATag destination by finding the start address of the first System Memory Resource Descriptor Hob - ResHob = (EFI_HOB_RESOURCE_DESCRIPTOR *)GetFirstHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR); - while (ResHob != NULL) { - if (ResHob->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) { - KernelParamsNewAddress = (UINTN)ResHob->PhysicalStart + 0x100; - break; - } - ResHob = (EFI_HOB_RESOURCE_DESCRIPTOR *)GetNextHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR, (VOID *)((UINTN)ResHob + ResHob->Header.HobLength)); - } + // Register and print out performance information + PERF_END (NULL, "BDS", NULL, 0); + if (PerformanceMeasurementEnabled ()) { + PrintPerformance (); + } - // Shut down UEFI boot services. ExitBootServices() will notify every driver that created an event on - // ExitBootServices event. Example the Interrupt DXE driver will disable the interrupts on this event. - Status = ShutdownUefiBootServices(); - if(EFI_ERROR(Status)) - { - Print(L"ERROR : Can not shutdown UEFI boot services. Status=0x%X\n", Status); - goto Exit; - } + // + // Start the Linux Kernel + // - // Move the kernel parameters to any address inside the first 1MB. - // This is necessary because the ARM Linux kernel requires - // the FTD / ATAG List to reside entirely inside the first 1MB of - // physical memory. - CopyMem((VOID*)KernelParamsNewAddress, KernelParamsAddress, KernelParamsSize); + // Outside BootServices, so can't use Print(); + DEBUG((EFI_D_ERROR, "\nStarting the kernel:\n\n")); - //********************************************************** - // * Start the Linux Kernel - // ********************************************************** - // Lift off ... - Status = StartLinuxKernel(LinuxImage, (UINTN)0, (UINTN)MachineType, KernelParamsNewAddress ); + // jump to kernel with register set + LinuxKernel ((UINTN)0, (UINTN)MachineType, (UINTN)KernelParamsAddress); - // Only be here if we fail to start Linux - DEBUG((EFI_D_ERROR, "ERROR : Can not start the kernel. Status=0x%X\n", Status)); + // Kernel should never exit + // After Life services are not provided + ASSERT(FALSE); Exit: - // Free Runtimee Memory (kernel and FDT) - return Status; + // Only be here if we fail to start Linux + Print (L"ERROR : Can not start the kernel. Status=0x%X\n", Status); + + // Free Runtimee Memory (kernel and FDT) + return Status; } diff --git a/ArmPkg/Library/BdsLib/BdsLinuxLoader.h b/ArmPkg/Library/BdsLib/BdsLinuxLoader.h index 2869f652f8..82b7a4f081 100644 --- a/ArmPkg/Library/BdsLib/BdsLinuxLoader.h +++ b/ArmPkg/Library/BdsLib/BdsLinuxLoader.h @@ -15,8 +15,7 @@ #ifndef __BDSLINUXLOADER_H #define __BDSLINUXLOADER_H -#define ATAG_MAX_SIZE 0x4000 -//PcdKernelParamsMaxMemorySize +#define ATAG_MAX_SIZE 0x3000 /* ATAG : list of possible tags */ #define ATAG_NONE 0x00000000 @@ -31,64 +30,24 @@ #define ATAG_CMDLINE 0x54410009 #define ATAG_ARM_MP_CORE 0x5441000A -// Some system addresses -// These should probably come from the platform header file or from pcd values -#define DRAM_BASE 0x10000000 -#define ZIMAGE_LOAD_ADDRESS (DRAM_BASE + 0x8000) -#define INITRD_LOAD_ADDRESS (DRAM_BASE + 0x800000) - -#define SIZE_1B 0x00000001 -#define SIZE_2B 0x00000002 -#define SIZE_4B 0x00000004 -#define SIZE_8B 0x00000008 -#define SIZE_16B 0x00000010 -#define SIZE_32B 0x00000020 -#define SIZE_64B 0x00000040 -#define SIZE_128B 0x00000080 -#define SIZE_256B 0x00000100 -#define SIZE_512B 0x00000200 -#define SIZE_1KB 0x00000400 -#define SIZE_2KB 0x00000800 -#define SIZE_4KB 0x00001000 -#define SIZE_8KB 0x00002000 -#define SIZE_16KB 0x00004000 -#define SIZE_32KB 0x00008000 -#define SIZE_64KB 0x00010000 -#define SIZE_128KB 0x00020000 -#define SIZE_256KB 0x00040000 -#define SIZE_512KB 0x00080000 -#define SIZE_1MB 0x00100000 -#define SIZE_2MB 0x00200000 -#define SIZE_4MB 0x00400000 -#define SIZE_8MB 0x00800000 -#define SIZE_16MB 0x01000000 -#define SIZE_32MB 0x02000000 -#define SIZE_64MB 0x04000000 -#define SIZE_100MB 0x06400000 -#define SIZE_128MB 0x08000000 -#define SIZE_256MB 0x10000000 -#define SIZE_512MB 0x20000000 -#define SIZE_1GB 0x40000000 -#define SIZE_2GB 0x80000000 - /* structures for each atag */ -struct atag_header { +typedef struct { UINT32 size; /* length of tag in words including this header */ UINT32 type; /* tag type */ -}; +} LINUX_ATAG_HEADER; -struct atag_core { +typedef struct { UINT32 flags; UINT32 pagesize; UINT32 rootdev; -}; +} LINUX_ATAG_CORE; -struct atag_mem { +typedef struct { UINT32 size; UINTN start; -}; +} LINUX_ATAG_MEM; -struct atag_videotext { +typedef struct { UINT8 x; UINT8 y; UINT16 video_page; @@ -98,29 +57,29 @@ struct atag_videotext { UINT8 video_lines; UINT8 video_isvga; UINT16 video_points; -}; +} LINUX_ATAG_VIDEOTEXT; -struct atag_ramdisk { +typedef struct { UINT32 flags; UINT32 size; UINTN start; -}; +} LINUX_ATAG_RAMDISK; -struct atag_initrd2 { +typedef struct { UINT32 start; UINT32 size; -}; +} LINUX_ATAG_INITRD2; -struct atag_serialnr { +typedef struct { UINT32 low; UINT32 high; -}; +} LINUX_ATAG_SERIALNR; -struct atag_revision { +typedef struct { UINT32 rev; -}; +} LINUX_ATAG_REVISION; -struct atag_videolfb { +typedef struct { UINT16 lfb_width; UINT16 lfb_height; UINT16 lfb_depth; @@ -135,31 +94,30 @@ struct atag_videolfb { UINT8 blue_pos; UINT8 rsvd_size; UINT8 rsvd_pos; -}; +} LINUX_ATAG_VIDEOLFB; -struct atag_cmdline { +typedef struct { CHAR8 cmdline[1]; -}; +} LINUX_ATAG_CMDLINE; -struct atag { - struct atag_header header; +typedef struct { + LINUX_ATAG_HEADER header; union { - struct atag_core core_tag; - struct atag_mem mem_tag; - struct atag_videotext videotext_tag; - struct atag_ramdisk ramdisk_tag; - struct atag_initrd2 initrd2_tag; - struct atag_serialnr serialnr_tag; - struct atag_revision revision_tag; - struct atag_videolfb videolfb_tag; - struct atag_cmdline cmdline_tag; + LINUX_ATAG_CORE core_tag; + LINUX_ATAG_MEM mem_tag; + LINUX_ATAG_VIDEOTEXT videotext_tag; + LINUX_ATAG_RAMDISK ramdisk_tag; + LINUX_ATAG_INITRD2 initrd2_tag; + LINUX_ATAG_SERIALNR serialnr_tag; + LINUX_ATAG_REVISION revision_tag; + LINUX_ATAG_VIDEOLFB videolfb_tag; + LINUX_ATAG_CMDLINE cmdline_tag; } body; -}; +} LINUX_ATAG; -#define next_tag_address(t) ((struct atag *)((UINT32)(t) + (((t)->header.size) << 2) )) -#define tag_size(type) ((UINT32)((sizeof(struct atag_header) + sizeof(struct type)) >> 2)) +typedef VOID (*LINUX_KERNEL)(UINT32 Zero, UINT32 Arch, UINTN ParametersBase); -STATIC struct atag *Params; /* used to point at the current tag */ +#define next_tag_address(t) ((LINUX_ATAG*)((UINT32)(t) + (((t)->header.size) << 2) )) +#define tag_size(type) ((UINT32)((sizeof(LINUX_ATAG_HEADER) + sizeof(type)) >> 2)) #endif -