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/MemoryAllocationLib.h>
18 #include <Library/UefiBootServicesTableLib.h>
20 #include <Protocol/DevicePath.h>
21 #include <Protocol/FirmwareVolume2.h>
22 #include <Protocol/SimpleFileSystem.h>
25 #include <Guid/FileInfo.h>
30 // Device path for SemiHosting
33 VENDOR_DEVICE_PATH Guid
;
34 EFI_DEVICE_PATH_PROTOCOL End
;
35 } mSemihostingDevicePath
= {
37 { HARDWARE_DEVICE_PATH
, HW_VENDOR_DP
, { sizeof (VENDOR_DEVICE_PATH
), 0 } },
38 { 0xC5B9C74A, 0x6D72, 0x4719, { 0x99, 0xAB, 0xC5, 0x9F, 0x19, 0x90, 0x91, 0xEB } }
40 { END_DEVICE_PATH_TYPE
, END_ENTIRE_DEVICE_PATH_SUBTYPE
, { sizeof (EFI_DEVICE_PATH_PROTOCOL
), 0 } }
45 This function declares the passed FDT into the UEFI Configuration Table
47 @param FdtBlob Base address of the Fdt Blob in System Memory
48 @param FdtSize Size of the Fdt Blob in System Memory
50 @return EFI_SUCCESS Fdt Blob was successfully installed into the configuration table
51 @return !EFI_SUCCESS Error returned by BS.InstallConfigurationTable()
56 InstallFdtIntoConfigurationTable (
63 // Check the FDT header is valid. We only make this check in DEBUG mode in case the FDT header change on
64 // production device and this ASSERT() becomes not valid.
65 ASSERT (fdt_check_header (FdtBlob
) == 0);
67 // Ensure the Size of the Device Tree is smaller than the size of the read file
68 ASSERT ((UINTN
)fdt_totalsize (FdtBlob
) <= FdtSize
);
70 // Install the FDT into the Configuration Table
71 Status
= gBS
->InstallConfigurationTable (&gFdtTableGuid
, FdtBlob
);
78 Load and Install FDT from Semihosting
80 @param Filename Name of the file to load from semihosting
82 @return EFI_SUCCESS Fdt Blob was successfully installed into the configuration table
84 @return EFI_NOT_FOUND Fail to locate the file in semihosting
85 @return EFI_OUT_OF_RESOURCES Fail to allocate memory to contain the blob
88 InstallFdtFromSemihosting (
89 IN CONST CHAR16
* FileName
93 EFI_DEVICE_PATH
* Remaining
;
95 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*SemihostingFs
;
96 EFI_FILE_PROTOCOL
*Fs
;
97 EFI_FILE_PROTOCOL
*File
;
98 EFI_PHYSICAL_ADDRESS FdtBase
;
99 EFI_FILE_INFO
*FileInfo
;
103 // Ensure the Semihosting driver is initialized
104 Remaining
= (EFI_DEVICE_PATH
*)&mSemihostingDevicePath
;
105 // The LocateDevicePath() function locates all devices on DevicePath that support Protocol and returns
106 // the handle to the device that is closest to DevicePath. On output, the device path pointer is modified
107 // to point to the remaining part of the device path
108 Status
= gBS
->LocateDevicePath (&gEfiDevicePathProtocolGuid
, &Remaining
, &Handle
);
109 if (EFI_ERROR (Status
)) {
110 ASSERT_EFI_ERROR (Status
);
114 // Recursive = FALSE: We do not want to start the whole device tree
115 Status
= gBS
->ConnectController (Handle
, NULL
, Remaining
, FALSE
);
116 if (EFI_ERROR (Status
)) {
120 // Locate the FileSystem
121 Status
= gBS
->HandleProtocol (Handle
, &gEfiSimpleFileSystemProtocolGuid
, (VOID
**)&SemihostingFs
);
122 if (EFI_ERROR (Status
)) {
123 ASSERT_EFI_ERROR (Status
);
127 // Try to Open the volume and get root directory
128 Status
= SemihostingFs
->OpenVolume (SemihostingFs
, &Fs
);
129 if (EFI_ERROR (Status
)) {
130 DEBUG ((EFI_D_WARN
, "Warning: Fail to open semihosting filesystem that should contain FDT file.\n"));
135 Status
= Fs
->Open (Fs
, &File
, (CHAR16
*)FileName
, EFI_FILE_MODE_READ
, 0);
136 if (EFI_ERROR (Status
)) {
137 DEBUG ((EFI_D_WARN
, "Warning: Fail to load FDT file '%s'.\n", FileName
));
143 File
->GetInfo (File
, &gEfiFileInfoGuid
, &FileInfoSize
, NULL
);
144 FileInfo
= AllocatePool (FileInfoSize
);
145 if (FileInfo
== NULL
) {
146 Status
= EFI_OUT_OF_RESOURCES
;
149 Status
= File
->GetInfo (File
, &gEfiFileInfoGuid
, &FileInfoSize
, FileInfo
);
150 if (EFI_ERROR (Status
)) {
156 FdtSize
= FileInfo
->FileSize
;
159 // The FDT blob is attached to the Configuration Table. It is recommended to load it as Runtime Service Data
160 // to prevent the kernel to overwrite its data
161 Status
= gBS
->AllocatePages (AllocateAnyPages
, EfiRuntimeServicesData
, EFI_SIZE_TO_PAGES (FdtSize
), &FdtBase
);
162 if (!EFI_ERROR (Status
)) {
163 Status
= File
->Read (File
, &FdtSize
, (VOID
*)(UINTN
)(FdtBase
));
164 if (EFI_ERROR (Status
)) {
165 gBS
->FreePages (FdtBase
, EFI_SIZE_TO_PAGES (FdtSize
));
167 // Install the FDT as part of the UEFI Configuration Table
168 Status
= InstallFdtIntoConfigurationTable ((VOID
*)(UINTN
)FdtBase
, FdtSize
);
169 if (EFI_ERROR (Status
)) {
170 gBS
->FreePages (FdtBase
, EFI_SIZE_TO_PAGES (FdtSize
));
182 Load and Install FDT from Firmware Volume
184 @param Filename Guid of the FDT blob to load from firmware volume
186 @return EFI_SUCCESS Fdt Blob was successfully installed into the configuration table
188 @return EFI_NOT_FOUND Fail to locate the file in firmware volume
189 @return EFI_OUT_OF_RESOURCES Fail to allocate memory to contain the blob
193 IN CONST EFI_GUID
*FileName
197 EFI_HANDLE
*HandleBuffer
;
198 UINTN NumberOfHandles
;
201 EFI_FIRMWARE_VOLUME2_PROTOCOL
*FvInstance
;
202 INTN SectionInstance
;
205 EFI_PHYSICAL_ADDRESS FdtBase
;
210 // Locate all the Firmware Volume protocols.
211 Status
= gBS
->LocateHandleBuffer (
213 &gEfiFirmwareVolume2ProtocolGuid
,
218 if (EFI_ERROR (Status
)) {
222 // Looking for FV that contains the FDT blob
223 for (Index
= 0; Index
< NumberOfHandles
; Index
++) {
225 // Get the protocol on this handle
226 // This should not fail because of LocateHandleBuffer
228 Status
= gBS
->HandleProtocol (
230 &gEfiFirmwareVolume2ProtocolGuid
,
233 if (EFI_ERROR (Status
)) {
234 goto FREE_HANDLE_BUFFER
;
237 while (Status
== EFI_SUCCESS
) {
238 // FdtBlob must be allocated by ReadSection
241 // See if it contains the FDT file
242 Status
= FvInstance
->ReadSection (
251 if (!EFI_ERROR (Status
)) {
252 // When the FDT blob is attached to the Configuration Table it is recommended to load it as Runtime Service Data
253 // to prevent the kernel to overwrite its data
254 Status
= gBS
->AllocatePages (AllocateAnyPages
, EfiRuntimeServicesData
, EFI_SIZE_TO_PAGES (FdtSize
), &FdtBase
);
255 if (EFI_ERROR (Status
)) {
256 goto FREE_HANDLE_BUFFER
;
259 // Copy the FDT to the Runtime memory
260 gBS
->CopyMem ((VOID
*)(UINTN
)FdtBase
, FdtBlob
, FdtSize
);
261 // Free the buffer allocated by FvInstance->ReadSection()
262 gBS
->FreePool (FdtBlob
);
264 // Install the FDT as part of the UEFI Configuration Table
265 Status
= InstallFdtIntoConfigurationTable ((VOID
*)(UINTN
)FdtBase
, FdtSize
);
266 if (EFI_ERROR (Status
)) {
267 gBS
->FreePages (FdtBase
, EFI_SIZE_TO_PAGES (FdtSize
));
275 // Free any allocated buffers
276 gBS
->FreePool (HandleBuffer
);