3 * Copyright (c) 2014-2015, 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/ArmPlatformEvents.h>
32 #include <Guid/EventGroup.h>
34 #include <Guid/FileInfo.h>
38 #define FDT_DEFAULT_FILENAME L"juno"
40 #define IS_DEVICE_PATH_NODE(node,type,subtype) (((node)->Type == (type)) && ((node)->SubType == (subtype)))
42 // Hardware Vendor Device Path node for the Juno NOR Flash. We use the Juno NOR Flash if the user
43 // has not specified another filesystem location into the UEFI Variable 'Fdt'.
44 // The Juno NOR Flash has its own filesystem format (supported by ArmPlatformPkg/FileSystem/BootMonFs).
46 VENDOR_DEVICE_PATH NorGuid
;
48 } mJunoNorFlashDevicePath
= {
50 { HARDWARE_DEVICE_PATH
, HW_VENDOR_DP
, { sizeof (VENDOR_DEVICE_PATH
), 0 } },
51 {0xE7223039, 0x5836, 0x41E1, { 0xB5, 0x42, 0xD7, 0xEC, 0x73, 0x6C, 0x5E, 0x59} }
53 { END_DEVICE_PATH_TYPE
, END_ENTIRE_DEVICE_PATH_SUBTYPE
, { sizeof (EFI_DEVICE_PATH_PROTOCOL
), 0 } }
56 STATIC EFI_DEVICE_PATH
* mFdtFileSystemDevicePath
= NULL
;
57 STATIC CHAR16
* mFdtFileName
= NULL
;
59 STATIC BOOLEAN mFdtTableInstalled
= FALSE
;
62 See definition EFI_DRIVER_BINDING_PROTOCOL.Supported()
67 IN EFI_DRIVER_BINDING_PROTOCOL
*DriverBinding
,
68 IN EFI_HANDLE ControllerHandle
,
69 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
73 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
76 // Check if the Handle support the Simple File System Protocol
78 Status
= gBS
->OpenProtocol (
80 &gEfiSimpleFileSystemProtocolGuid
,
84 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
87 if (EFI_ERROR (Status
)) {
91 // Check if a DevicePath is attached to the handle
92 Status
= gBS
->OpenProtocol (
94 &gEfiDevicePathProtocolGuid
,
98 EFI_OPEN_PROTOCOL_BY_DRIVER
100 if (EFI_ERROR (Status
)) {
104 // Check if the Device Path is the one from the NOR Flash
105 if (CompareMem (mFdtFileSystemDevicePath
, DevicePath
, GetDevicePathSize (mFdtFileSystemDevicePath
)) != 0) {
106 return EFI_NOT_FOUND
;
109 gBS
->CloseProtocol (ControllerHandle
, &gEfiDevicePathProtocolGuid
, gImageHandle
, ControllerHandle
);
114 This function is used to print messages back to the user.
116 We use the Serial terminal for these messages as the gST->ConOut might not be initialized at this stage.
118 @param Message Message to display to the user
131 VA_START (Marker
, Message
);
132 CharCount
= AsciiVSPrint (Buffer
, sizeof (Buffer
), Message
, Marker
);
135 SerialPortWrite ((UINT8
*)Buffer
, CharCount
);
139 See definition EFI_DRIVER_BINDING_PROTOCOL.Start ()
144 IN EFI_DRIVER_BINDING_PROTOCOL
*DriverBinding
,
145 IN EFI_HANDLE ControllerHandle
,
146 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath OPTIONAL
150 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*BootMonFs
;
151 EFI_FILE_PROTOCOL
*Fs
;
152 EFI_FILE_PROTOCOL
*File
;
154 EFI_PHYSICAL_ADDRESS FdtBlob
;
155 EFI_FILE_INFO
*FileInfo
;
157 if (mFdtTableInstalled
) {
158 return EFI_ALREADY_STARTED
;
161 Status
= gBS
->OpenProtocol (
163 &gEfiSimpleFileSystemProtocolGuid
,
167 EFI_OPEN_PROTOCOL_BY_DRIVER
170 if (EFI_ERROR (Status
)) {
174 // Try to Open the volume and get root directory
175 Status
= BootMonFs
->OpenVolume (BootMonFs
, &Fs
);
176 if (EFI_ERROR (Status
)) {
177 PrintMessage ("Warning: Fail to open file system that should contain FDT file.\n");
182 Status
= Fs
->Open (Fs
, &File
, mFdtFileName
, EFI_FILE_MODE_READ
, 0);
183 if (EFI_ERROR (Status
)) {
184 PrintMessage ("Warning: Fail to load FDT file '%s'.\n", mFdtFileName
);
189 File
->GetInfo (File
, &gEfiFileInfoGuid
, &Size
, NULL
);
190 FileInfo
= AllocatePool (Size
);
191 Status
= File
->GetInfo (File
, &gEfiFileInfoGuid
, &Size
, FileInfo
);
192 if (EFI_ERROR (Status
)) {
197 Size
= FileInfo
->FileSize
;
200 // The FDT blob is attached to the Configuration Table. It is better to load it as Runtime Service Data
201 // to prevent the kernel to overwrite its data
202 Status
= gBS
->AllocatePages (AllocateAnyPages
, EfiRuntimeServicesData
, EFI_SIZE_TO_PAGES (Size
), &FdtBlob
);
203 if (!EFI_ERROR (Status
)) {
204 Status
= File
->Read (File
, &Size
, (VOID
*)(UINTN
)(FdtBlob
));
205 if (EFI_ERROR (Status
)) {
206 gBS
->FreePages (FdtBlob
, EFI_SIZE_TO_PAGES (Size
));
208 // Check the FDT header is valid. We only make this check in DEBUG mode in case the FDT header change on
209 // production device and this ASSERT() becomes not valid.
210 ASSERT (fdt_check_header ((VOID
*)(UINTN
)(FdtBlob
)) == 0);
212 // Ensure the Size of the Device Tree is smaller than the size of the read file
213 ASSERT ((UINTN
)fdt_totalsize ((VOID
*)(UINTN
)FdtBlob
) <= Size
);
215 // Install the FDT into the Configuration Table
216 Status
= gBS
->InstallConfigurationTable (&gFdtTableGuid
, (VOID
*)(UINTN
)(FdtBlob
));
217 if (!EFI_ERROR (Status
)) {
218 mFdtTableInstalled
= TRUE
;
227 // We do not need the FileSystem protocol
230 &gEfiSimpleFileSystemProtocolGuid
,
238 See definition EFI_DRIVER_BINDING_PROTOCOL.Stop()
243 IN EFI_DRIVER_BINDING_PROTOCOL
*DriverBinding
,
244 IN EFI_HANDLE ControllerHandle
,
245 IN UINTN NumberOfChildren
,
246 IN EFI_HANDLE
*ChildHandleBuffer OPTIONAL
253 // Look for FDT Table
254 for (Index
= 0; Index
< gST
->NumberOfTableEntries
; Index
++) {
255 // Check for correct GUID type
256 if (CompareGuid (&gFdtTableGuid
, &(gST
->ConfigurationTable
[Index
].VendorGuid
))) {
257 FdtBlob
= gST
->ConfigurationTable
[Index
].VendorTable
;
258 FdtSize
= (UINTN
)fdt_totalsize (FdtBlob
);
260 // Uninstall the FDT Configuration Table
261 gBS
->InstallConfigurationTable (&gFdtTableGuid
, NULL
);
264 gBS
->FreePages ((EFI_PHYSICAL_ADDRESS
)(UINTN
)FdtBlob
, EFI_SIZE_TO_PAGES (FdtSize
));
270 return EFI_NOT_FOUND
;
274 // Driver Binding Protocol for Juno FDT support
276 EFI_DRIVER_BINDING_PROTOCOL mJunoFdtBinding
= {
286 Notification function of EFI_END_OF_DXE_EVENT_GROUP_GUID event group.
288 This is a notification function registered on EFI_END_OF_DXE_EVENT_GROUP_GUID event group.
290 @param Event Event whose notification function is being invoked.
291 @param Context Pointer to the notification function's context.
302 EFI_DEVICE_PATH
*DevicePathNode
;
306 CHAR16
* FdtDevicePathStr
;
307 EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL
*EfiDevicePathFromTextProtocol
;
308 EFI_EVENT ArmPlatformUpdateFdtEvent
;
311 // Read the 'FDT' UEFI Variable to know where we should we read the blob from.
312 // The 'Fdt' variable contains either the full device path or only the filename of the FDT.
313 // If 'Fdt' only contains the filename then we assume its location is on the NOR Flash.
316 Status
= gRT
->GetVariable (L
"Fdt", &gArmGlobalVariableGuid
, NULL
, &VariableSize
, mFdtFileSystemDevicePath
);
317 if (Status
== EFI_BUFFER_TOO_SMALL
) {
318 // Get the environment variable value
319 mFdtFileSystemDevicePath
= AllocatePool (VariableSize
);
320 if (mFdtFileSystemDevicePath
!= NULL
) {
321 Status
= gRT
->GetVariable (L
"Fdt", &gArmGlobalVariableGuid
, NULL
, &VariableSize
, mFdtFileSystemDevicePath
);
322 if (EFI_ERROR (Status
)) {
323 FreePool (mFdtFileSystemDevicePath
);
324 ASSERT_EFI_ERROR (Status
);
328 ASSERT_EFI_ERROR (EFI_OUT_OF_RESOURCES
);
331 } else if (Status
== EFI_NOT_FOUND
) {
332 // If the 'Fdt' variable does not exist then we get the FDT location from the PCD
333 FdtDevicePathStr
= (CHAR16
*)PcdGetPtr (PcdFdtDevicePath
);
335 Status
= gBS
->LocateProtocol (&gEfiDevicePathFromTextProtocolGuid
, NULL
, (VOID
**)&EfiDevicePathFromTextProtocol
);
336 if (EFI_ERROR (Status
)) {
337 ASSERT_EFI_ERROR (Status
);
341 // Conversion of the Device Path string into EFI Device Path
342 mFdtFileSystemDevicePath
= EfiDevicePathFromTextProtocol
->ConvertTextToDevicePath (FdtDevicePathStr
);
345 if (mFdtFileSystemDevicePath
!= NULL
) {
346 // Look for the FDT filename that should be contained into the FilePath device path node
347 DevicePathNode
= mFdtFileSystemDevicePath
;
348 while (!IsDevicePathEnd (DevicePathNode
)) {
349 if (IS_DEVICE_PATH_NODE (DevicePathNode
, MEDIA_DEVICE_PATH
, MEDIA_FILEPATH_DP
)) {
350 // Extract the name from the File Path Node. The name of the Filename is the size of the
351 // device path node minus the size of the device path node header.
352 mFdtFileName
= AllocateCopyPool (
353 DevicePathNodeLength (DevicePathNode
) - sizeof(EFI_DEVICE_PATH_PROTOCOL
),
354 ((FILEPATH_DEVICE_PATH
*)DevicePathNode
)->PathName
);
355 if (mFdtFileName
== NULL
) {
356 ASSERT_EFI_ERROR (EFI_OUT_OF_RESOURCES
);
360 // We remove the FilePath device path node from the FileSystem Device Path
361 // because it will never match a device path installed by the FileSystem driver
362 SetDevicePathEndNode (DevicePathNode
);
365 DevicePathNode
= NextDevicePathNode (DevicePathNode
);
368 // The UEFI Variable might just contain the FDT filename. In this case we assume the FileSystem is
369 // the NOR Flash based one (ie: BootMonFs).
370 // If it was only containing the FilePath device node then the previous condition should have
371 // replaced it by the End Device Path Node.
372 if (IsDevicePathEndType (mFdtFileSystemDevicePath
)) {
373 mFdtFileSystemDevicePath
= (EFI_DEVICE_PATH
*)&mJunoNorFlashDevicePath
;
376 // Fallback on the NOR Flash filesystem
377 mFdtFileSystemDevicePath
= (EFI_DEVICE_PATH
*)&mJunoNorFlashDevicePath
;
380 // If the FDT FileName has been provided during the FileSystem identification
381 if (mFdtFileName
== NULL
) {
382 mFdtFileName
= AllocateCopyPool (StrSize (FDT_DEFAULT_FILENAME
), FDT_DEFAULT_FILENAME
);
383 if (mFdtFileName
== NULL
) {
384 ASSERT_EFI_ERROR (Status
);
389 // Context is not NULL when this function is called for a gEfiEndOfDxeEventGroupGuid event
391 // Install the Binding protocol to verify when the FileSystem that contains the FDT has been installed
392 Status
= gBS
->InstallMultipleProtocolInterfaces (
394 &gEfiDriverBindingProtocolGuid
, &mJunoFdtBinding
,
397 if (EFI_ERROR (Status
)) {
398 ASSERT_EFI_ERROR (Status
);
402 // Register the event triggered when the 'Fdt' variable is updated.
403 Status
= gBS
->CreateEventEx (
408 &gArmPlatformUpdateFdtEventGuid
,
409 &ArmPlatformUpdateFdtEvent
411 ASSERT_EFI_ERROR (Status
);
415 // Force to connect the FileSystem that contains the FDT
417 BdsConnectDevicePath (mFdtFileSystemDevicePath
, &Handle
, NULL
);
420 STATIC CONST BOOLEAN mIsEndOfDxeEvent
= TRUE
;
424 IN EFI_HANDLE ImageHandle
428 EFI_EVENT EndOfDxeEvent
;
430 // Register the event handling function to set the End Of DXE flag.
431 // We wait until the end of the DXE phase to load the FDT to make sure
432 // all the required drivers (NOR Flash, UEFI Variable, BootMonFs) are dispatched
433 Status
= gBS
->CreateEventEx (
438 &gEfiEndOfDxeEventGroupGuid
,
441 ASSERT_EFI_ERROR (Status
);