3 * Copyright (c) 2014, ARM Limited. All rights reserved.
5 * This program and the accompanying materials
6 * are licensed and made available under the terms and conditions of the BSD License
7 * which accompanies this distribution. The full text of the license may be found at
8 * http://opensource.org/licenses/bsd-license.php
10 * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 #include "ArmJunoDxeInternal.h"
17 #include <Protocol/BlockIo.h>
18 #include <Protocol/DevicePathFromText.h>
19 #include <Protocol/DriverBinding.h>
20 #include <Protocol/SimpleFileSystem.h>
22 #include <Library/BaseMemoryLib.h>
23 #include <Library/BdsLib.h>
24 #include <Library/DevicePathLib.h>
25 #include <Library/MemoryAllocationLib.h>
26 #include <Library/PrintLib.h>
27 #include <Library/SerialPortLib.h>
28 #include <Library/UefiRuntimeServicesTableLib.h>
30 #include <Guid/ArmGlobalVariableHob.h>
31 #include <Guid/EventGroup.h>
33 #include <Guid/FileInfo.h>
37 #define FDT_DEFAULT_FILENAME L"juno"
39 #define IS_DEVICE_PATH_NODE(node,type,subtype) (((node)->Type == (type)) && ((node)->SubType == (subtype)))
41 // Hardware Vendor Device Path node for the Juno NOR Flash. We use the Juno NOR Flash if the user
42 // has not specified another filesystem location into the UEFI Variable 'Fdt'.
43 // The Juno NOR Flash has its own filesystem format (supported by ArmPlatformPkg/FileSystem/BootMonFs).
45 VENDOR_DEVICE_PATH NorGuid
;
47 } mJunoNorFlashDevicePath
= {
49 { HARDWARE_DEVICE_PATH
, HW_VENDOR_DP
, { sizeof (VENDOR_DEVICE_PATH
), 0 } },
50 {0xE7223039, 0x5836, 0x41E1, { 0xB5, 0x42, 0xD7, 0xEC, 0x73, 0x6C, 0x5E, 0x59} }
52 { END_DEVICE_PATH_TYPE
, END_ENTIRE_DEVICE_PATH_SUBTYPE
, { sizeof (EFI_DEVICE_PATH_PROTOCOL
), 0 } }
55 STATIC EFI_DEVICE_PATH
* mFdtFileSystemDevicePath
= NULL
;
56 STATIC CHAR16
* mFdtFileName
= NULL
;
58 STATIC BOOLEAN mFdtTableInstalled
= FALSE
;
61 See definition EFI_DRIVER_BINDING_PROTOCOL.Supported()
66 IN EFI_DRIVER_BINDING_PROTOCOL
*DriverBinding
,
67 IN EFI_HANDLE ControllerHandle
,
68 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
72 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
75 // Check if the Handle support the Simple File System Protocol
77 Status
= gBS
->OpenProtocol (
79 &gEfiSimpleFileSystemProtocolGuid
,
83 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
86 if (EFI_ERROR (Status
)) {
90 // Check if a DevicePath is attached to the handle
91 Status
= gBS
->OpenProtocol (
93 &gEfiDevicePathProtocolGuid
,
97 EFI_OPEN_PROTOCOL_BY_DRIVER
99 if (EFI_ERROR (Status
)) {
103 // Check if the Device Path is the one from the NOR Flash
104 if (CompareMem (mFdtFileSystemDevicePath
, DevicePath
, GetDevicePathSize (mFdtFileSystemDevicePath
)) != 0) {
105 return EFI_NOT_FOUND
;
108 gBS
->CloseProtocol (ControllerHandle
, &gEfiDevicePathProtocolGuid
, gImageHandle
, ControllerHandle
);
113 This function is used to print messages back to the user.
115 We use the Serial terminal for these messages as the gST->ConOut might not be initialized at this stage.
117 @param Message Message to display to the user
130 VA_START (Marker
, Message
);
131 CharCount
= AsciiVSPrint (Buffer
, sizeof (Buffer
), Message
, Marker
);
134 SerialPortWrite ((UINT8
*)Buffer
, CharCount
);
138 See definition EFI_DRIVER_BINDING_PROTOCOL.Start ()
143 IN EFI_DRIVER_BINDING_PROTOCOL
*DriverBinding
,
144 IN EFI_HANDLE ControllerHandle
,
145 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath OPTIONAL
149 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*BootMonFs
;
150 EFI_FILE_PROTOCOL
*Fs
;
151 EFI_FILE_PROTOCOL
*File
;
153 EFI_PHYSICAL_ADDRESS FdtBlob
;
154 EFI_FILE_INFO
*FileInfo
;
156 if (mFdtTableInstalled
) {
157 return EFI_ALREADY_STARTED
;
160 Status
= gBS
->OpenProtocol (
162 &gEfiSimpleFileSystemProtocolGuid
,
166 EFI_OPEN_PROTOCOL_BY_DRIVER
169 if (EFI_ERROR (Status
)) {
173 // Try to Open the volume and get root directory
174 Status
= BootMonFs
->OpenVolume (BootMonFs
, &Fs
);
175 if (EFI_ERROR (Status
)) {
176 PrintMessage ("Warning: Fail to open file system that should contain FDT file.\n");
177 goto UNLOAD_PROTOCOL
;
181 Status
= Fs
->Open (Fs
, &File
, mFdtFileName
, EFI_FILE_MODE_READ
, 0);
182 if (EFI_ERROR (Status
)) {
183 PrintMessage ("Warning: Fail to load FDT file '%s'.\n", mFdtFileName
);
184 goto UNLOAD_PROTOCOL
;
188 File
->GetInfo (File
, &gEfiFileInfoGuid
, &Size
, NULL
);
189 FileInfo
= AllocatePool (Size
);
190 Status
= File
->GetInfo (File
, &gEfiFileInfoGuid
, &Size
, FileInfo
);
191 if (EFI_ERROR (Status
)) {
192 goto UNLOAD_PROTOCOL
;
196 Size
= FileInfo
->FileSize
;
199 // The FDT blob is attached to the Configuration Table. It is better to load it as Runtime Service Data
200 // to prevent the kernel to overwrite its data
201 Status
= gBS
->AllocatePages (AllocateAnyPages
, EfiRuntimeServicesData
, EFI_SIZE_TO_PAGES (Size
), &FdtBlob
);
202 if (!EFI_ERROR (Status
)) {
203 Status
= File
->Read (File
, &Size
, (VOID
*)(UINTN
)(FdtBlob
));
204 if (EFI_ERROR (Status
)) {
205 gBS
->FreePages (FdtBlob
, EFI_SIZE_TO_PAGES (Size
));
207 // Check the FDT header is valid. We only make this check in DEBUG mode in case the FDT header change on
208 // production device and this ASSERT() becomes not valid.
209 ASSERT (fdt_check_header ((VOID
*)(UINTN
)(FdtBlob
)) == 0);
211 // Ensure the Size of the Device Tree is smaller than the size of the read file
212 ASSERT ((UINTN
)fdt_totalsize ((VOID
*)(UINTN
)FdtBlob
) <= Size
);
214 // Install the FDT into the Configuration Table
215 Status
= gBS
->InstallConfigurationTable (&gFdtTableGuid
, (VOID
*)(UINTN
)(FdtBlob
));
216 if (!EFI_ERROR (Status
)) {
217 mFdtTableInstalled
= TRUE
;
223 // We do not need the FileSystem protocol
226 &gEfiSimpleFileSystemProtocolGuid
,
227 DriverBinding
->ImageHandle
,
234 See definition EFI_DRIVER_BINDING_PROTOCOL.Stop()
239 IN EFI_DRIVER_BINDING_PROTOCOL
*DriverBinding
,
240 IN EFI_HANDLE ControllerHandle
,
241 IN UINTN NumberOfChildren
,
242 IN EFI_HANDLE
*ChildHandleBuffer OPTIONAL
249 // Look for FDT Table
250 for (Index
= 0; Index
< gST
->NumberOfTableEntries
; Index
++) {
251 // Check for correct GUID type
252 if (CompareGuid (&gFdtTableGuid
, &(gST
->ConfigurationTable
[Index
].VendorGuid
))) {
253 FdtBlob
= gST
->ConfigurationTable
[Index
].VendorTable
;
254 FdtSize
= (UINTN
)fdt_totalsize (FdtBlob
);
256 // Uninstall the FDT Configuration Table
257 gBS
->InstallConfigurationTable (&gFdtTableGuid
, NULL
);
260 gBS
->FreePages ((EFI_PHYSICAL_ADDRESS
)(UINTN
)FdtBlob
, EFI_SIZE_TO_PAGES (FdtSize
));
266 return EFI_NOT_FOUND
;
270 // Driver Binding Protocol for Juno FDT support
272 EFI_DRIVER_BINDING_PROTOCOL mJunoFdtBinding
= {
282 Notification function of EFI_END_OF_DXE_EVENT_GROUP_GUID event group.
284 This is a notification function registered on EFI_END_OF_DXE_EVENT_GROUP_GUID event group.
286 @param Event Event whose notification function is being invoked.
287 @param Context Pointer to the notification function's context.
298 EFI_DEVICE_PATH
*DevicePathNode
;
302 CHAR16
* FdtDevicePathStr
;
303 EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL
*EfiDevicePathFromTextProtocol
;
306 // Read the 'FDT' UEFI Variable to know where we should we read the blob from.
307 // The 'Fdt' variable contains either the full device path or only the filename of the FDT.
308 // If 'Fdt' only contains the filename then we assume its location is on the NOR Flash.
311 Status
= gRT
->GetVariable (L
"Fdt", &gArmGlobalVariableGuid
, NULL
, &VariableSize
, mFdtFileSystemDevicePath
);
312 if (Status
== EFI_BUFFER_TOO_SMALL
) {
313 // Get the environment variable value
314 mFdtFileSystemDevicePath
= AllocatePool (VariableSize
);
315 if (mFdtFileSystemDevicePath
!= NULL
) {
316 Status
= gRT
->GetVariable (L
"Fdt", &gArmGlobalVariableGuid
, NULL
, &VariableSize
, mFdtFileSystemDevicePath
);
317 if (EFI_ERROR (Status
)) {
318 FreePool (mFdtFileSystemDevicePath
);
319 ASSERT_EFI_ERROR (Status
);
323 ASSERT_EFI_ERROR (EFI_OUT_OF_RESOURCES
);
326 } else if (Status
== EFI_NOT_FOUND
) {
327 // If the 'Fdt' variable does not exist then we get the FDT location from the PCD
328 FdtDevicePathStr
= (CHAR16
*)PcdGetPtr (PcdFdtDevicePath
);
330 Status
= gBS
->LocateProtocol (&gEfiDevicePathFromTextProtocolGuid
, NULL
, (VOID
**)&EfiDevicePathFromTextProtocol
);
331 if (EFI_ERROR (Status
)) {
332 ASSERT_EFI_ERROR (Status
);
336 // Conversion of the Device Path string into EFI Device Path
337 mFdtFileSystemDevicePath
= EfiDevicePathFromTextProtocol
->ConvertTextToDevicePath (FdtDevicePathStr
);
340 if (mFdtFileSystemDevicePath
!= NULL
) {
341 // Look for the FDT filename that should be contained into the FilePath device path node
342 DevicePathNode
= mFdtFileSystemDevicePath
;
343 while (!IsDevicePathEnd (DevicePathNode
)) {
344 if (IS_DEVICE_PATH_NODE (DevicePathNode
, MEDIA_DEVICE_PATH
, MEDIA_FILEPATH_DP
)) {
345 // Extract the name from the File Path Node. The name of the Filename is the size of the
346 // device path node minus the size of the device path node header.
347 mFdtFileName
= AllocateCopyPool (
348 DevicePathNodeLength (DevicePathNode
) - sizeof(EFI_DEVICE_PATH_PROTOCOL
),
349 ((FILEPATH_DEVICE_PATH
*)DevicePathNode
)->PathName
);
350 if (mFdtFileName
== NULL
) {
351 ASSERT_EFI_ERROR (EFI_OUT_OF_RESOURCES
);
355 // We remove the FilePath device path node from the FileSystem Device Path
356 // because it will never match a device path installed by the FileSystem driver
357 SetDevicePathEndNode (DevicePathNode
);
360 DevicePathNode
= NextDevicePathNode (DevicePathNode
);
363 // The UEFI Variable might just contain the FDT filename. In this case we assume the FileSystem is
364 // the NOR Flash based one (ie: BootMonFs).
365 // If it was only containing the FilePath device node then the previous condition should have
366 // replaced it by the End Device Path Node.
367 if (IsDevicePathEndType (mFdtFileSystemDevicePath
)) {
368 mFdtFileSystemDevicePath
= (EFI_DEVICE_PATH
*)&mJunoNorFlashDevicePath
;
371 // Fallback on the NOR Flash filesystem
372 mFdtFileSystemDevicePath
= (EFI_DEVICE_PATH
*)&mJunoNorFlashDevicePath
;
375 // If the FDT FileName has been provided during the FileSystem identification
376 if (mFdtFileName
== NULL
) {
377 mFdtFileName
= AllocateCopyPool (StrSize (FDT_DEFAULT_FILENAME
), FDT_DEFAULT_FILENAME
);
378 if (mFdtFileName
== NULL
) {
379 ASSERT_EFI_ERROR (Status
);
384 // Install the Binding protocol to verify when the FileSystem that contains the FDT has been installed
385 Status
= gBS
->InstallMultipleProtocolInterfaces (
387 &gEfiDriverBindingProtocolGuid
, &mJunoFdtBinding
,
390 if (EFI_ERROR (Status
)) {
391 ASSERT_EFI_ERROR (Status
);
396 // Force to connect the FileSystem that contains the FDT
398 BdsConnectDevicePath (mFdtFileSystemDevicePath
, &Handle
, NULL
);
403 IN EFI_HANDLE ImageHandle
407 EFI_EVENT EndOfDxeEvent
;
409 // Register the event handling function to set the End Of DXE flag.
410 // We wait until the end of the DXE phase to load the FDT to make sure
411 // all the required drivers (NOR Flash, UEFI Variable, BootMonFs) are dispatched
412 Status
= gBS
->CreateEventEx (
417 &gEfiEndOfDxeEventGroupGuid
,
420 ASSERT_EFI_ERROR (Status
);