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");
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
);
188 File
->GetInfo (File
, &gEfiFileInfoGuid
, &Size
, NULL
);
189 FileInfo
= AllocatePool (Size
);
190 Status
= File
->GetInfo (File
, &gEfiFileInfoGuid
, &Size
, FileInfo
);
191 if (EFI_ERROR (Status
)) {
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
;
226 // We do not need the FileSystem protocol
229 &gEfiSimpleFileSystemProtocolGuid
,
237 See definition EFI_DRIVER_BINDING_PROTOCOL.Stop()
242 IN EFI_DRIVER_BINDING_PROTOCOL
*DriverBinding
,
243 IN EFI_HANDLE ControllerHandle
,
244 IN UINTN NumberOfChildren
,
245 IN EFI_HANDLE
*ChildHandleBuffer OPTIONAL
252 // Look for FDT Table
253 for (Index
= 0; Index
< gST
->NumberOfTableEntries
; Index
++) {
254 // Check for correct GUID type
255 if (CompareGuid (&gFdtTableGuid
, &(gST
->ConfigurationTable
[Index
].VendorGuid
))) {
256 FdtBlob
= gST
->ConfigurationTable
[Index
].VendorTable
;
257 FdtSize
= (UINTN
)fdt_totalsize (FdtBlob
);
259 // Uninstall the FDT Configuration Table
260 gBS
->InstallConfigurationTable (&gFdtTableGuid
, NULL
);
263 gBS
->FreePages ((EFI_PHYSICAL_ADDRESS
)(UINTN
)FdtBlob
, EFI_SIZE_TO_PAGES (FdtSize
));
269 return EFI_NOT_FOUND
;
273 // Driver Binding Protocol for Juno FDT support
275 EFI_DRIVER_BINDING_PROTOCOL mJunoFdtBinding
= {
285 Notification function of EFI_END_OF_DXE_EVENT_GROUP_GUID event group.
287 This is a notification function registered on EFI_END_OF_DXE_EVENT_GROUP_GUID event group.
289 @param Event Event whose notification function is being invoked.
290 @param Context Pointer to the notification function's context.
301 EFI_DEVICE_PATH
*DevicePathNode
;
305 CHAR16
* FdtDevicePathStr
;
306 EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL
*EfiDevicePathFromTextProtocol
;
309 // Read the 'FDT' UEFI Variable to know where we should we read the blob from.
310 // The 'Fdt' variable contains either the full device path or only the filename of the FDT.
311 // If 'Fdt' only contains the filename then we assume its location is on the NOR Flash.
314 Status
= gRT
->GetVariable (L
"Fdt", &gArmGlobalVariableGuid
, NULL
, &VariableSize
, mFdtFileSystemDevicePath
);
315 if (Status
== EFI_BUFFER_TOO_SMALL
) {
316 // Get the environment variable value
317 mFdtFileSystemDevicePath
= AllocatePool (VariableSize
);
318 if (mFdtFileSystemDevicePath
!= NULL
) {
319 Status
= gRT
->GetVariable (L
"Fdt", &gArmGlobalVariableGuid
, NULL
, &VariableSize
, mFdtFileSystemDevicePath
);
320 if (EFI_ERROR (Status
)) {
321 FreePool (mFdtFileSystemDevicePath
);
322 ASSERT_EFI_ERROR (Status
);
326 ASSERT_EFI_ERROR (EFI_OUT_OF_RESOURCES
);
329 } else if (Status
== EFI_NOT_FOUND
) {
330 // If the 'Fdt' variable does not exist then we get the FDT location from the PCD
331 FdtDevicePathStr
= (CHAR16
*)PcdGetPtr (PcdFdtDevicePath
);
333 Status
= gBS
->LocateProtocol (&gEfiDevicePathFromTextProtocolGuid
, NULL
, (VOID
**)&EfiDevicePathFromTextProtocol
);
334 if (EFI_ERROR (Status
)) {
335 ASSERT_EFI_ERROR (Status
);
339 // Conversion of the Device Path string into EFI Device Path
340 mFdtFileSystemDevicePath
= EfiDevicePathFromTextProtocol
->ConvertTextToDevicePath (FdtDevicePathStr
);
343 if (mFdtFileSystemDevicePath
!= NULL
) {
344 // Look for the FDT filename that should be contained into the FilePath device path node
345 DevicePathNode
= mFdtFileSystemDevicePath
;
346 while (!IsDevicePathEnd (DevicePathNode
)) {
347 if (IS_DEVICE_PATH_NODE (DevicePathNode
, MEDIA_DEVICE_PATH
, MEDIA_FILEPATH_DP
)) {
348 // Extract the name from the File Path Node. The name of the Filename is the size of the
349 // device path node minus the size of the device path node header.
350 mFdtFileName
= AllocateCopyPool (
351 DevicePathNodeLength (DevicePathNode
) - sizeof(EFI_DEVICE_PATH_PROTOCOL
),
352 ((FILEPATH_DEVICE_PATH
*)DevicePathNode
)->PathName
);
353 if (mFdtFileName
== NULL
) {
354 ASSERT_EFI_ERROR (EFI_OUT_OF_RESOURCES
);
358 // We remove the FilePath device path node from the FileSystem Device Path
359 // because it will never match a device path installed by the FileSystem driver
360 SetDevicePathEndNode (DevicePathNode
);
363 DevicePathNode
= NextDevicePathNode (DevicePathNode
);
366 // The UEFI Variable might just contain the FDT filename. In this case we assume the FileSystem is
367 // the NOR Flash based one (ie: BootMonFs).
368 // If it was only containing the FilePath device node then the previous condition should have
369 // replaced it by the End Device Path Node.
370 if (IsDevicePathEndType (mFdtFileSystemDevicePath
)) {
371 mFdtFileSystemDevicePath
= (EFI_DEVICE_PATH
*)&mJunoNorFlashDevicePath
;
374 // Fallback on the NOR Flash filesystem
375 mFdtFileSystemDevicePath
= (EFI_DEVICE_PATH
*)&mJunoNorFlashDevicePath
;
378 // If the FDT FileName has been provided during the FileSystem identification
379 if (mFdtFileName
== NULL
) {
380 mFdtFileName
= AllocateCopyPool (StrSize (FDT_DEFAULT_FILENAME
), FDT_DEFAULT_FILENAME
);
381 if (mFdtFileName
== NULL
) {
382 ASSERT_EFI_ERROR (Status
);
387 // Install the Binding protocol to verify when the FileSystem that contains the FDT has been installed
388 Status
= gBS
->InstallMultipleProtocolInterfaces (
390 &gEfiDriverBindingProtocolGuid
, &mJunoFdtBinding
,
393 if (EFI_ERROR (Status
)) {
394 ASSERT_EFI_ERROR (Status
);
399 // Force to connect the FileSystem that contains the FDT
401 BdsConnectDevicePath (mFdtFileSystemDevicePath
, &Handle
, NULL
);
406 IN EFI_HANDLE ImageHandle
410 EFI_EVENT EndOfDxeEvent
;
412 // Register the event handling function to set the End Of DXE flag.
413 // We wait until the end of the DXE phase to load the FDT to make sure
414 // all the required drivers (NOR Flash, UEFI Variable, BootMonFs) are dispatched
415 Status
= gBS
->CreateEventEx (
420 &gEfiEndOfDxeEventGroupGuid
,
423 ASSERT_EFI_ERROR (Status
);