+++ /dev/null
-/** @file\r
-*\r
-* Copyright (c) 2014-2015, ARM Limited. All rights reserved.\r
-*\r
-* This program and the accompanying materials\r
-* are licensed and made available under the terms and conditions of the BSD License\r
-* which accompanies this distribution. The full text of the license may be found at\r
-* http://opensource.org/licenses/bsd-license.php\r
-*\r
-* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
-*\r
-**/\r
-\r
-#include "ArmJunoDxeInternal.h"\r
-\r
-#include <Protocol/BlockIo.h>\r
-#include <Protocol/DevicePathFromText.h>\r
-#include <Protocol/DriverBinding.h>\r
-#include <Protocol/SimpleFileSystem.h>\r
-\r
-#include <Library/BaseMemoryLib.h>\r
-#include <Library/BdsLib.h>\r
-#include <Library/DevicePathLib.h>\r
-#include <Library/MemoryAllocationLib.h>\r
-#include <Library/PrintLib.h>\r
-#include <Library/SerialPortLib.h>\r
-#include <Library/UefiRuntimeServicesTableLib.h>\r
-\r
-#include <Guid/ArmGlobalVariableHob.h>\r
-#include <Guid/ArmPlatformEvents.h>\r
-#include <Guid/EventGroup.h>\r
-#include <Guid/Fdt.h>\r
-#include <Guid/FileInfo.h>\r
-\r
-#include <libfdt.h>\r
-\r
-#define FDT_DEFAULT_FILENAME L"juno"\r
-\r
-#define IS_DEVICE_PATH_NODE(node,type,subtype) (((node)->Type == (type)) && ((node)->SubType == (subtype)))\r
-\r
-// Hardware Vendor Device Path node for the Juno NOR Flash. We use the Juno NOR Flash if the user\r
-// has not specified another filesystem location into the UEFI Variable 'Fdt'.\r
-// The Juno NOR Flash has its own filesystem format (supported by ArmPlatformPkg/FileSystem/BootMonFs).\r
-STATIC CONST struct {\r
- VENDOR_DEVICE_PATH NorGuid;\r
- EFI_DEVICE_PATH End;\r
-} mJunoNorFlashDevicePath = {\r
- {\r
- { HARDWARE_DEVICE_PATH, HW_VENDOR_DP, { sizeof (VENDOR_DEVICE_PATH), 0 } },\r
- {0xE7223039, 0x5836, 0x41E1, { 0xB5, 0x42, 0xD7, 0xEC, 0x73, 0x6C, 0x5E, 0x59} }\r
- },\r
- { END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 } }\r
-};\r
-\r
-STATIC EFI_DEVICE_PATH* mFdtFileSystemDevicePath = NULL;\r
-STATIC CHAR16* mFdtFileName = NULL;\r
-\r
-STATIC BOOLEAN mFdtTableInstalled = FALSE;\r
-\r
-/**\r
- See definition EFI_DRIVER_BINDING_PROTOCOL.Supported()\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-JunoFdtSupported (\r
- IN EFI_DRIVER_BINDING_PROTOCOL *DriverBinding,\r
- IN EFI_HANDLE ControllerHandle,\r
- IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
-\r
- //\r
- // Check if the Handle support the Simple File System Protocol\r
- //\r
- Status = gBS->OpenProtocol (\r
- ControllerHandle,\r
- &gEfiSimpleFileSystemProtocolGuid,\r
- NULL,\r
- gImageHandle,\r
- ControllerHandle,\r
- EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
- );\r
-\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- // Check if a DevicePath is attached to the handle\r
- Status = gBS->OpenProtocol (\r
- ControllerHandle,\r
- &gEfiDevicePathProtocolGuid,\r
- (VOID **)&DevicePath,\r
- gImageHandle,\r
- ControllerHandle,\r
- EFI_OPEN_PROTOCOL_BY_DRIVER\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- // Check if the Device Path is the one from the NOR Flash\r
- if (CompareMem (mFdtFileSystemDevicePath, DevicePath, GetDevicePathSize (mFdtFileSystemDevicePath)) != 0) {\r
- return EFI_NOT_FOUND;\r
- }\r
-\r
- gBS->CloseProtocol (ControllerHandle, &gEfiDevicePathProtocolGuid, gImageHandle, ControllerHandle);\r
- return Status;\r
-}\r
-\r
-/**\r
- This function is used to print messages back to the user.\r
-\r
- We use the Serial terminal for these messages as the gST->ConOut might not be initialized at this stage.\r
-\r
- @param Message Message to display to the user\r
-**/\r
-STATIC\r
-VOID\r
-PrintMessage (\r
- IN CHAR8* Message,\r
- ...\r
- )\r
-{\r
- UINTN CharCount;\r
- CHAR8 Buffer[100];\r
- VA_LIST Marker;\r
-\r
- VA_START (Marker, Message);\r
- CharCount = AsciiVSPrint (Buffer, sizeof (Buffer), Message, Marker);\r
- VA_END (Marker);\r
-\r
- SerialPortWrite ((UINT8*)Buffer, CharCount);\r
-}\r
-\r
-/**\r
- See definition EFI_DRIVER_BINDING_PROTOCOL.Start ()\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-JunoFdtStart (\r
- IN EFI_DRIVER_BINDING_PROTOCOL *DriverBinding,\r
- IN EFI_HANDLE ControllerHandle,\r
- IN EFI_DEVICE_PATH_PROTOCOL *DevicePath OPTIONAL\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *BootMonFs;\r
- EFI_FILE_PROTOCOL *Fs;\r
- EFI_FILE_PROTOCOL *File;\r
- UINTN Size;\r
- EFI_PHYSICAL_ADDRESS FdtBlob;\r
- EFI_FILE_INFO *FileInfo;\r
-\r
- if (mFdtTableInstalled) {\r
- return EFI_ALREADY_STARTED;\r
- }\r
-\r
- Status = gBS->OpenProtocol (\r
- ControllerHandle,\r
- &gEfiSimpleFileSystemProtocolGuid,\r
- (VOID**)&BootMonFs,\r
- gImageHandle,\r
- ControllerHandle,\r
- EFI_OPEN_PROTOCOL_BY_DRIVER\r
- );\r
-\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- // Try to Open the volume and get root directory\r
- Status = BootMonFs->OpenVolume (BootMonFs, &Fs);\r
- if (EFI_ERROR (Status)) {\r
- PrintMessage ("Warning: Fail to open file system that should contain FDT file.\n");\r
- goto CLOSE_PROTOCOL;\r
- }\r
-\r
- File = NULL;\r
- Status = Fs->Open (Fs, &File, mFdtFileName, EFI_FILE_MODE_READ, 0);\r
- if (EFI_ERROR (Status)) {\r
- PrintMessage ("Warning: Fail to load FDT file '%s'.\n", mFdtFileName);\r
- goto CLOSE_PROTOCOL;\r
- }\r
-\r
- Size = 0;\r
- File->GetInfo (File, &gEfiFileInfoGuid, &Size, NULL);\r
- FileInfo = AllocatePool (Size);\r
- Status = File->GetInfo (File, &gEfiFileInfoGuid, &Size, FileInfo);\r
- if (EFI_ERROR (Status)) {\r
- goto CLOSE_FILE;\r
- }\r
-\r
- // Get the file size\r
- Size = FileInfo->FileSize;\r
- FreePool (FileInfo);\r
-\r
- // The FDT blob is attached to the Configuration Table. It is better to load it as Runtime Service Data\r
- // to prevent the kernel to overwrite its data\r
- Status = gBS->AllocatePages (AllocateAnyPages, EfiRuntimeServicesData, EFI_SIZE_TO_PAGES (Size), &FdtBlob);\r
- if (!EFI_ERROR (Status)) {\r
- Status = File->Read (File, &Size, (VOID*)(UINTN)(FdtBlob));\r
- if (EFI_ERROR (Status)) {\r
- gBS->FreePages (FdtBlob, EFI_SIZE_TO_PAGES (Size));\r
- } else {\r
- // Check the FDT header is valid. We only make this check in DEBUG mode in case the FDT header change on\r
- // production device and this ASSERT() becomes not valid.\r
- ASSERT (fdt_check_header ((VOID*)(UINTN)(FdtBlob)) == 0);\r
-\r
- // Ensure the Size of the Device Tree is smaller than the size of the read file\r
- ASSERT ((UINTN)fdt_totalsize ((VOID*)(UINTN)FdtBlob) <= Size);\r
-\r
- // Install the FDT into the Configuration Table\r
- Status = gBS->InstallConfigurationTable (&gFdtTableGuid, (VOID*)(UINTN)(FdtBlob));\r
- if (!EFI_ERROR (Status)) {\r
- mFdtTableInstalled = TRUE;\r
- }\r
- }\r
- }\r
-\r
-CLOSE_FILE:\r
- File->Close (File);\r
-\r
-CLOSE_PROTOCOL:\r
- // We do not need the FileSystem protocol\r
- gBS->CloseProtocol (\r
- ControllerHandle,\r
- &gEfiSimpleFileSystemProtocolGuid,\r
- gImageHandle,\r
- ControllerHandle);\r
-\r
- return Status;\r
-}\r
-\r
-/**\r
- See definition EFI_DRIVER_BINDING_PROTOCOL.Stop()\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-JunoFdtStop (\r
- IN EFI_DRIVER_BINDING_PROTOCOL *DriverBinding,\r
- IN EFI_HANDLE ControllerHandle,\r
- IN UINTN NumberOfChildren,\r
- IN EFI_HANDLE *ChildHandleBuffer OPTIONAL\r
- )\r
-{\r
- UINTN Index;\r
- VOID* FdtBlob;\r
- UINTN FdtSize;\r
-\r
- // Look for FDT Table\r
- for (Index = 0; Index < gST->NumberOfTableEntries; Index++) {\r
- // Check for correct GUID type\r
- if (CompareGuid (&gFdtTableGuid, &(gST->ConfigurationTable[Index].VendorGuid))) {\r
- FdtBlob = gST->ConfigurationTable[Index].VendorTable;\r
- FdtSize = (UINTN)fdt_totalsize (FdtBlob);\r
-\r
- // Uninstall the FDT Configuration Table\r
- gBS->InstallConfigurationTable (&gFdtTableGuid, NULL);\r
-\r
- // Free the memory\r
- gBS->FreePages ((EFI_PHYSICAL_ADDRESS)(UINTN)FdtBlob, EFI_SIZE_TO_PAGES (FdtSize));\r
-\r
- return EFI_SUCCESS;\r
- }\r
- }\r
-\r
- return EFI_NOT_FOUND;\r
-}\r
-\r
-//\r
-// Driver Binding Protocol for Juno FDT support\r
-//\r
-EFI_DRIVER_BINDING_PROTOCOL mJunoFdtBinding = {\r
- JunoFdtSupported,\r
- JunoFdtStart,\r
- JunoFdtStop,\r
- 0xa,\r
- NULL,\r
- NULL\r
-};\r
-\r
-/**\r
- Notification function of EFI_END_OF_DXE_EVENT_GROUP_GUID event group.\r
-\r
- This is a notification function registered on EFI_END_OF_DXE_EVENT_GROUP_GUID event group.\r
-\r
- @param Event Event whose notification function is being invoked.\r
- @param Context Pointer to the notification function's context.\r
-\r
-**/\r
-STATIC\r
-VOID\r
-EFIAPI\r
-LoadFdtOnEvent (\r
- EFI_EVENT Event,\r
- VOID *Context\r
- )\r
-{\r
- EFI_DEVICE_PATH *DevicePathNode;\r
- EFI_HANDLE Handle;\r
- EFI_STATUS Status;\r
- UINTN VariableSize;\r
- CHAR16* FdtDevicePathStr;\r
- EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *EfiDevicePathFromTextProtocol;\r
- EFI_EVENT ArmPlatformUpdateFdtEvent;\r
-\r
- //\r
- // Read the 'FDT' UEFI Variable to know where we should we read the blob from.\r
- // The 'Fdt' variable contains either the full device path or only the filename of the FDT.\r
- // If 'Fdt' only contains the filename then we assume its location is on the NOR Flash.\r
- //\r
- VariableSize = 0;\r
- Status = gRT->GetVariable (L"Fdt", &gArmGlobalVariableGuid, NULL, &VariableSize, mFdtFileSystemDevicePath);\r
- if (Status == EFI_BUFFER_TOO_SMALL) {\r
- // Get the environment variable value\r
- mFdtFileSystemDevicePath = AllocatePool (VariableSize);\r
- if (mFdtFileSystemDevicePath != NULL) {\r
- Status = gRT->GetVariable (L"Fdt", &gArmGlobalVariableGuid, NULL, &VariableSize, mFdtFileSystemDevicePath);\r
- if (EFI_ERROR (Status)) {\r
- FreePool (mFdtFileSystemDevicePath);\r
- ASSERT_EFI_ERROR (Status);\r
- return;\r
- }\r
- } else {\r
- ASSERT_EFI_ERROR (EFI_OUT_OF_RESOURCES);\r
- return;\r
- }\r
- } else if (Status == EFI_NOT_FOUND) {\r
- // If the 'Fdt' variable does not exist then we get the FDT location from the PCD\r
- FdtDevicePathStr = (CHAR16*)PcdGetPtr (PcdFdtDevicePath);\r
-\r
- Status = gBS->LocateProtocol (&gEfiDevicePathFromTextProtocolGuid, NULL, (VOID **)&EfiDevicePathFromTextProtocol);\r
- if (EFI_ERROR (Status)) {\r
- ASSERT_EFI_ERROR (Status);\r
- return;\r
- }\r
-\r
- // Conversion of the Device Path string into EFI Device Path\r
- mFdtFileSystemDevicePath = EfiDevicePathFromTextProtocol->ConvertTextToDevicePath (FdtDevicePathStr);\r
- }\r
-\r
- if (mFdtFileSystemDevicePath != NULL) {\r
- // Look for the FDT filename that should be contained into the FilePath device path node\r
- DevicePathNode = mFdtFileSystemDevicePath;\r
- while (!IsDevicePathEnd (DevicePathNode)) {\r
- if (IS_DEVICE_PATH_NODE (DevicePathNode, MEDIA_DEVICE_PATH, MEDIA_FILEPATH_DP)) {\r
- // Extract the name from the File Path Node. The name of the Filename is the size of the\r
- // device path node minus the size of the device path node header.\r
- mFdtFileName = AllocateCopyPool (\r
- DevicePathNodeLength (DevicePathNode) - sizeof(EFI_DEVICE_PATH_PROTOCOL),\r
- ((FILEPATH_DEVICE_PATH*)DevicePathNode)->PathName);\r
- if (mFdtFileName == NULL) {\r
- ASSERT_EFI_ERROR (EFI_OUT_OF_RESOURCES);\r
- return;\r
- }\r
-\r
- // We remove the FilePath device path node from the FileSystem Device Path\r
- // because it will never match a device path installed by the FileSystem driver\r
- SetDevicePathEndNode (DevicePathNode);\r
- break;\r
- }\r
- DevicePathNode = NextDevicePathNode (DevicePathNode);\r
- }\r
-\r
- // The UEFI Variable might just contain the FDT filename. In this case we assume the FileSystem is\r
- // the NOR Flash based one (ie: BootMonFs).\r
- // If it was only containing the FilePath device node then the previous condition should have\r
- // replaced it by the End Device Path Node.\r
- if (IsDevicePathEndType (mFdtFileSystemDevicePath)) {\r
- mFdtFileSystemDevicePath = (EFI_DEVICE_PATH*)&mJunoNorFlashDevicePath;\r
- }\r
- } else {\r
- // Fallback on the NOR Flash filesystem\r
- mFdtFileSystemDevicePath = (EFI_DEVICE_PATH*)&mJunoNorFlashDevicePath;\r
- }\r
-\r
- // If the FDT FileName has been provided during the FileSystem identification\r
- if (mFdtFileName == NULL) {\r
- mFdtFileName = AllocateCopyPool (StrSize (FDT_DEFAULT_FILENAME), FDT_DEFAULT_FILENAME);\r
- if (mFdtFileName == NULL) {\r
- ASSERT_EFI_ERROR (Status);\r
- return;\r
- }\r
- }\r
-\r
- // Context is not NULL when this function is called for a gEfiEndOfDxeEventGroupGuid event\r
- if (Context) {\r
- // Install the Binding protocol to verify when the FileSystem that contains the FDT has been installed\r
- Status = gBS->InstallMultipleProtocolInterfaces (\r
- &gImageHandle,\r
- &gEfiDriverBindingProtocolGuid, &mJunoFdtBinding,\r
- NULL\r
- );\r
- if (EFI_ERROR (Status)) {\r
- ASSERT_EFI_ERROR (Status);\r
- return;\r
- }\r
-\r
- // Register the event triggered when the 'Fdt' variable is updated.\r
- Status = gBS->CreateEventEx (\r
- EVT_NOTIFY_SIGNAL,\r
- TPL_CALLBACK,\r
- LoadFdtOnEvent,\r
- NULL,\r
- &gArmPlatformUpdateFdtEventGuid,\r
- &ArmPlatformUpdateFdtEvent\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
- }\r
-\r
- //\r
- // Force to connect the FileSystem that contains the FDT\r
- //\r
- BdsConnectDevicePath (mFdtFileSystemDevicePath, &Handle, NULL);\r
-}\r
-\r
-STATIC CONST BOOLEAN mIsEndOfDxeEvent = TRUE;\r
-\r
-EFI_STATUS\r
-JunoFdtInstall (\r
- IN EFI_HANDLE ImageHandle\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_EVENT EndOfDxeEvent;\r
-\r
- // Register the event handling function to set the End Of DXE flag.\r
- // We wait until the end of the DXE phase to load the FDT to make sure\r
- // all the required drivers (NOR Flash, UEFI Variable, BootMonFs) are dispatched\r
- Status = gBS->CreateEventEx (\r
- EVT_NOTIFY_SIGNAL,\r
- TPL_CALLBACK,\r
- LoadFdtOnEvent,\r
- &mIsEndOfDxeEvent,\r
- &gEfiEndOfDxeEventGroupGuid,\r
- &EndOfDxeEvent\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- return Status;\r
-}\r