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.
16 #include <Library/DebugLib.h>
17 #include <Library/FdtLoadLib.h>
18 #include <Library/MemoryAllocationLib.h>
19 #include <Library/UefiBootServicesTableLib.h>
21 #include <Protocol/DevicePath.h>
22 #include <Protocol/FirmwareVolume2.h>
23 #include <Protocol/SimpleFileSystem.h>
26 #include <Guid/FileInfo.h>
31 // Device path for SemiHosting
34 VENDOR_DEVICE_PATH Guid
;
35 EFI_DEVICE_PATH_PROTOCOL End
;
36 } mSemihostingDevicePath
= {
38 { HARDWARE_DEVICE_PATH
, HW_VENDOR_DP
, { sizeof (VENDOR_DEVICE_PATH
), 0 } },
39 { 0xC5B9C74A, 0x6D72, 0x4719, { 0x99, 0xAB, 0xC5, 0x9F, 0x19, 0x90, 0x91, 0xEB } }
41 { END_DEVICE_PATH_TYPE
, END_ENTIRE_DEVICE_PATH_SUBTYPE
, { sizeof (EFI_DEVICE_PATH_PROTOCOL
), 0 } }
46 This function declares the passed FDT into the UEFI Configuration Table
48 @param FdtBlob Base address of the Fdt Blob in System Memory
49 @param FdtSize Size of the Fdt Blob in System Memory
51 @return EFI_SUCCESS Fdt Blob was successfully installed into the configuration table
52 @return !EFI_SUCCESS Error returned by BS.InstallConfigurationTable()
57 InstallFdtIntoConfigurationTable (
64 // Check the FDT header is valid. We only make this check in DEBUG mode in case the FDT header change on
65 // production device and this ASSERT() becomes not valid.
66 ASSERT (fdt_check_header (FdtBlob
) == 0);
68 // Ensure the Size of the Device Tree is smaller than the size of the read file
69 ASSERT ((UINTN
)fdt_totalsize (FdtBlob
) <= FdtSize
);
71 // Install the FDT into the Configuration Table
72 Status
= gBS
->InstallConfigurationTable (&gFdtTableGuid
, FdtBlob
);
79 Load and Install FDT from Semihosting
81 @param Filename Name of the file to load from semihosting
83 @return EFI_SUCCESS Fdt Blob was successfully installed into the configuration table
85 @return EFI_NOT_FOUND Fail to locate the file in semihosting
86 @return EFI_OUT_OF_RESOURCES Fail to allocate memory to contain the blob
89 InstallFdtFromSemihosting (
90 IN CONST CHAR16
* FileName
94 EFI_DEVICE_PATH
* Remaining
;
96 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*SemihostingFs
;
97 EFI_FILE_PROTOCOL
*Fs
;
98 EFI_FILE_PROTOCOL
*File
;
99 EFI_PHYSICAL_ADDRESS FdtBase
;
100 EFI_FILE_INFO
*FileInfo
;
104 // Ensure the Semihosting driver is initialized
105 Remaining
= (EFI_DEVICE_PATH
*)&mSemihostingDevicePath
;
106 // The LocateDevicePath() function locates all devices on DevicePath that support Protocol and returns
107 // the handle to the device that is closest to DevicePath. On output, the device path pointer is modified
108 // to point to the remaining part of the device path
109 Status
= gBS
->LocateDevicePath (&gEfiDevicePathProtocolGuid
, &Remaining
, &Handle
);
110 if (EFI_ERROR (Status
)) {
111 ASSERT_EFI_ERROR (Status
);
115 // Recursive = FALSE: We do not want to start the whole device tree
116 Status
= gBS
->ConnectController (Handle
, NULL
, Remaining
, FALSE
);
117 if (EFI_ERROR (Status
)) {
121 // Locate the FileSystem
122 Status
= gBS
->HandleProtocol (Handle
, &gEfiSimpleFileSystemProtocolGuid
, (VOID
**)&SemihostingFs
);
123 if (EFI_ERROR (Status
)) {
124 ASSERT_EFI_ERROR (Status
);
128 // Try to Open the volume and get root directory
129 Status
= SemihostingFs
->OpenVolume (SemihostingFs
, &Fs
);
130 if (EFI_ERROR (Status
)) {
131 DEBUG ((EFI_D_WARN
, "Warning: Fail to open semihosting filesystem that should contain FDT file.\n"));
136 Status
= Fs
->Open (Fs
, &File
, (CHAR16
*)FileName
, EFI_FILE_MODE_READ
, 0);
137 if (EFI_ERROR (Status
)) {
138 DEBUG ((EFI_D_WARN
, "Warning: Fail to load FDT file '%s'.\n", FileName
));
144 File
->GetInfo (File
, &gEfiFileInfoGuid
, &FileInfoSize
, NULL
);
145 FileInfo
= AllocatePool (FileInfoSize
);
146 if (FileInfo
== NULL
) {
147 Status
= EFI_OUT_OF_RESOURCES
;
150 Status
= File
->GetInfo (File
, &gEfiFileInfoGuid
, &FileInfoSize
, FileInfo
);
151 if (EFI_ERROR (Status
)) {
157 FdtSize
= FileInfo
->FileSize
;
160 // The FDT blob is attached to the Configuration Table. It is recommended to load it as Runtime Service Data
161 // to prevent the kernel to overwrite its data
162 Status
= gBS
->AllocatePages (AllocateAnyPages
, EfiRuntimeServicesData
, EFI_SIZE_TO_PAGES (FdtSize
), &FdtBase
);
163 if (!EFI_ERROR (Status
)) {
164 Status
= File
->Read (File
, &FdtSize
, (VOID
*)(UINTN
)(FdtBase
));
165 if (EFI_ERROR (Status
)) {
166 gBS
->FreePages (FdtBase
, EFI_SIZE_TO_PAGES (FdtSize
));
168 // Install the FDT as part of the UEFI Configuration Table
169 Status
= InstallFdtIntoConfigurationTable ((VOID
*)(UINTN
)FdtBase
, FdtSize
);
170 if (EFI_ERROR (Status
)) {
171 gBS
->FreePages (FdtBase
, EFI_SIZE_TO_PAGES (FdtSize
));
183 Load and Install FDT from Firmware Volume
185 @param Filename Guid of the FDT blob to load from firmware volume
187 @return EFI_SUCCESS Fdt Blob was successfully installed into the configuration table
189 @return EFI_NOT_FOUND Fail to locate the file in firmware volume
190 @return EFI_OUT_OF_RESOURCES Fail to allocate memory to contain the blob
194 IN CONST EFI_GUID
*FileName
198 EFI_HANDLE
*HandleBuffer
;
199 UINTN NumberOfHandles
;
202 EFI_FIRMWARE_VOLUME2_PROTOCOL
*FvInstance
;
203 INTN SectionInstance
;
206 EFI_PHYSICAL_ADDRESS FdtBase
;
211 // Locate all the Firmware Volume protocols.
212 Status
= gBS
->LocateHandleBuffer (
214 &gEfiFirmwareVolume2ProtocolGuid
,
219 if (EFI_ERROR (Status
)) {
223 // Looking for FV that contains the FDT blob
224 for (Index
= 0; Index
< NumberOfHandles
; Index
++) {
226 // Get the protocol on this handle
227 // This should not fail because of LocateHandleBuffer
229 Status
= gBS
->HandleProtocol (
231 &gEfiFirmwareVolume2ProtocolGuid
,
234 if (EFI_ERROR (Status
)) {
235 goto FREE_HANDLE_BUFFER
;
238 while (Status
== EFI_SUCCESS
) {
239 // FdtBlob must be allocated by ReadSection
242 // See if it contains the FDT file
243 Status
= FvInstance
->ReadSection (
252 if (!EFI_ERROR (Status
)) {
253 // When the FDT blob is attached to the Configuration Table it is recommended to load it as Runtime Service Data
254 // to prevent the kernel to overwrite its data
255 Status
= gBS
->AllocatePages (AllocateAnyPages
, EfiRuntimeServicesData
, EFI_SIZE_TO_PAGES (FdtSize
), &FdtBase
);
256 if (EFI_ERROR (Status
)) {
257 goto FREE_HANDLE_BUFFER
;
260 // Copy the FDT to the Runtime memory
261 gBS
->CopyMem ((VOID
*)(UINTN
)FdtBase
, FdtBlob
, FdtSize
);
262 // Free the buffer allocated by FvInstance->ReadSection()
263 gBS
->FreePool (FdtBlob
);
265 // Install the FDT as part of the UEFI Configuration Table
266 Status
= InstallFdtIntoConfigurationTable ((VOID
*)(UINTN
)FdtBase
, FdtSize
);
267 if (EFI_ERROR (Status
)) {
268 gBS
->FreePages (FdtBase
, EFI_SIZE_TO_PAGES (FdtSize
));
276 // Free any allocated buffers
277 gBS
->FreePool (HandleBuffer
);