]> git.proxmox.com Git - mirror_edk2.git/blame - EmbeddedPkg/Library/FdtLib/FdtConfigurationTable.c
EmbeddedPkg/FdtLib: Added support to load FDT from Firmware Volume
[mirror_edk2.git] / EmbeddedPkg / Library / FdtLib / FdtConfigurationTable.c
CommitLineData
af16798e
OM
1/** @file\r
2*\r
3* Copyright (c) 2014, ARM Limited. All rights reserved.\r
4*\r
5* This program and the accompanying materials\r
6* are licensed and made available under the terms and conditions of the BSD License\r
7* which accompanies this distribution. The full text of the license may be found at\r
8* http://opensource.org/licenses/bsd-license.php\r
9*\r
10* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12*\r
13**/\r
14\r
5b38a703 15#include <PiDxe.h>\r
af16798e
OM
16#include <Library/DebugLib.h>\r
17#include <Library/MemoryAllocationLib.h>\r
18#include <Library/UefiBootServicesTableLib.h>\r
19\r
20#include <Protocol/DevicePath.h>\r
5b38a703 21#include <Protocol/FirmwareVolume2.h>\r
af16798e
OM
22#include <Protocol/SimpleFileSystem.h>\r
23\r
24#include <Guid/Fdt.h>\r
25#include <Guid/FileInfo.h>\r
26\r
27#include <libfdt.h>\r
28\r
29//\r
30// Device path for SemiHosting\r
31//\r
32STATIC CONST struct {\r
33 VENDOR_DEVICE_PATH Guid;\r
34 EFI_DEVICE_PATH_PROTOCOL End;\r
35} mSemihostingDevicePath = {\r
36 {\r
37 { HARDWARE_DEVICE_PATH, HW_VENDOR_DP, { sizeof (VENDOR_DEVICE_PATH), 0 } },\r
38 { 0xC5B9C74A, 0x6D72, 0x4719, { 0x99, 0xAB, 0xC5, 0x9F, 0x19, 0x90, 0x91, 0xEB } }\r
39 },\r
40 { END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 } }\r
41};\r
42\r
43\r
44/**\r
45 This function declares the passed FDT into the UEFI Configuration Table\r
46\r
47 @param FdtBlob Base address of the Fdt Blob in System Memory\r
48 @param FdtSize Size of the Fdt Blob in System Memory\r
49\r
50 @return EFI_SUCCESS Fdt Blob was successfully installed into the configuration table\r
51 @return !EFI_SUCCESS Error returned by BS.InstallConfigurationTable()\r
52\r
53**/\r
54STATIC\r
55EFI_STATUS\r
56InstallFdtIntoConfigurationTable (\r
57 IN VOID* FdtBlob,\r
58 IN UINTN FdtSize\r
59 )\r
60{\r
61 EFI_STATUS Status;\r
62\r
63 // Check the FDT header is valid. We only make this check in DEBUG mode in case the FDT header change on\r
64 // production device and this ASSERT() becomes not valid.\r
65 ASSERT (fdt_check_header (FdtBlob) == 0);\r
66\r
67 // Ensure the Size of the Device Tree is smaller than the size of the read file\r
68 ASSERT ((UINTN)fdt_totalsize (FdtBlob) <= FdtSize);\r
69\r
70 // Install the FDT into the Configuration Table\r
71 Status = gBS->InstallConfigurationTable (&gFdtTableGuid, FdtBlob);\r
72\r
73 return Status;\r
74}\r
75\r
76\r
77/**\r
78 Load and Install FDT from Semihosting\r
79\r
80 @param Filename Name of the file to load from semihosting\r
81\r
82 @return EFI_SUCCESS Fdt Blob was successfully installed into the configuration table\r
83 from semihosting\r
84 @return EFI_NOT_FOUND Fail to locate the file in semihosting\r
85 @return EFI_OUT_OF_RESOURCES Fail to allocate memory to contain the blob\r
86**/\r
87EFI_STATUS\r
88InstallFdtFromSemihosting (\r
89 IN CONST CHAR16* FileName\r
90 )\r
91{\r
92 EFI_STATUS Status;\r
93 EFI_DEVICE_PATH* Remaining;\r
94 EFI_HANDLE Handle;\r
95 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SemihostingFs;\r
96 EFI_FILE_PROTOCOL *Fs;\r
97 EFI_FILE_PROTOCOL *File;\r
98 EFI_PHYSICAL_ADDRESS FdtBase;\r
99 EFI_FILE_INFO *FileInfo;\r
100 UINTN FdtSize;\r
101 UINTN FileInfoSize;\r
102\r
103 // Ensure the Semihosting driver is initialized\r
104 Remaining = (EFI_DEVICE_PATH*)&mSemihostingDevicePath;\r
105 // The LocateDevicePath() function locates all devices on DevicePath that support Protocol and returns\r
106 // the handle to the device that is closest to DevicePath. On output, the device path pointer is modified\r
107 // to point to the remaining part of the device path\r
108 Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &Remaining, &Handle);\r
109 if (EFI_ERROR (Status)) {\r
110 ASSERT_EFI_ERROR (Status);\r
111 return Status;\r
112 }\r
113\r
114 // Recursive = FALSE: We do not want to start the whole device tree\r
115 Status = gBS->ConnectController (Handle, NULL, Remaining, FALSE);\r
116 if (EFI_ERROR (Status)) {\r
117 return Status;\r
118 }\r
119\r
120 // Locate the FileSystem\r
121 Status = gBS->HandleProtocol (Handle, &gEfiSimpleFileSystemProtocolGuid, (VOID **)&SemihostingFs);\r
122 if (EFI_ERROR (Status)) {\r
123 ASSERT_EFI_ERROR (Status);\r
124 return Status;\r
125 }\r
126\r
127 // Try to Open the volume and get root directory\r
128 Status = SemihostingFs->OpenVolume (SemihostingFs, &Fs);\r
129 if (EFI_ERROR (Status)) {\r
130 DEBUG ((EFI_D_WARN, "Warning: Fail to open semihosting filesystem that should contain FDT file.\n"));\r
131 return Status;\r
132 }\r
133\r
134 File = NULL;\r
135 Status = Fs->Open (Fs, &File, (CHAR16*)FileName, EFI_FILE_MODE_READ, 0);\r
136 if (EFI_ERROR (Status)) {\r
137 DEBUG ((EFI_D_WARN, "Warning: Fail to load FDT file '%s'.\n", FileName));\r
138 Fs->Close (Fs);\r
139 return Status;\r
140 }\r
141\r
142 FileInfoSize = 0;\r
143 File->GetInfo (File, &gEfiFileInfoGuid, &FileInfoSize, NULL);\r
144 FileInfo = AllocatePool (FileInfoSize);\r
145 if (FileInfo == NULL) {\r
146 Status = EFI_OUT_OF_RESOURCES;\r
147 goto CLOSE_FILES;\r
148 }\r
149 Status = File->GetInfo (File, &gEfiFileInfoGuid, &FileInfoSize, FileInfo);\r
150 if (EFI_ERROR (Status)) {\r
151 FreePool (FileInfo);\r
152 goto CLOSE_FILES;\r
153 }\r
154\r
155 // Get the file size\r
156 FdtSize = FileInfo->FileSize;\r
157 FreePool (FileInfo);\r
158\r
159 // The FDT blob is attached to the Configuration Table. It is recommended to load it as Runtime Service Data\r
160 // to prevent the kernel to overwrite its data\r
161 Status = gBS->AllocatePages (AllocateAnyPages, EfiRuntimeServicesData, EFI_SIZE_TO_PAGES (FdtSize), &FdtBase);\r
162 if (!EFI_ERROR (Status)) {\r
163 Status = File->Read (File, &FdtSize, (VOID*)(UINTN)(FdtBase));\r
164 if (EFI_ERROR (Status)) {\r
165 gBS->FreePages (FdtBase, EFI_SIZE_TO_PAGES (FdtSize));\r
166 } else {\r
167 // Install the FDT as part of the UEFI Configuration Table\r
168 Status = InstallFdtIntoConfigurationTable ((VOID*)(UINTN)FdtBase, FdtSize);\r
169 if (EFI_ERROR (Status)) {\r
170 gBS->FreePages (FdtBase, EFI_SIZE_TO_PAGES (FdtSize));\r
171 }\r
172 }\r
173 }\r
174\r
175CLOSE_FILES:\r
176 File->Close (File);\r
177 Fs->Close (Fs);\r
178 return Status;\r
179}\r
5b38a703
OM
180\r
181/**\r
182 Load and Install FDT from Firmware Volume\r
183\r
184 @param Filename Guid of the FDT blob to load from firmware volume\r
185\r
186 @return EFI_SUCCESS Fdt Blob was successfully installed into the configuration table\r
187 from firmware volume\r
188 @return EFI_NOT_FOUND Fail to locate the file in firmware volume\r
189 @return EFI_OUT_OF_RESOURCES Fail to allocate memory to contain the blob\r
190**/\r
191EFI_STATUS\r
192InstallFdtFromFv (\r
193 IN CONST EFI_GUID *FileName\r
194 )\r
195{\r
196 EFI_STATUS Status;\r
197 EFI_HANDLE *HandleBuffer;\r
198 UINTN NumberOfHandles;\r
199 UINT32 FvStatus;\r
200 UINTN Index;\r
201 EFI_FIRMWARE_VOLUME2_PROTOCOL *FvInstance;\r
202 INTN SectionInstance;\r
203 UINTN FdtSize;\r
204 VOID* FdtBlob;\r
205 EFI_PHYSICAL_ADDRESS FdtBase;\r
206\r
207 FvStatus = 0;\r
208 SectionInstance = 0;\r
209\r
210 // Locate all the Firmware Volume protocols.\r
211 Status = gBS->LocateHandleBuffer (\r
212 ByProtocol,\r
213 &gEfiFirmwareVolume2ProtocolGuid,\r
214 NULL,\r
215 &NumberOfHandles,\r
216 &HandleBuffer\r
217 );\r
218 if (EFI_ERROR (Status)) {\r
219 return Status;\r
220 }\r
221\r
222 // Looking for FV that contains the FDT blob\r
223 for (Index = 0; Index < NumberOfHandles; Index++) {\r
224 //\r
225 // Get the protocol on this handle\r
226 // This should not fail because of LocateHandleBuffer\r
227 //\r
228 Status = gBS->HandleProtocol (\r
229 HandleBuffer[Index],\r
230 &gEfiFirmwareVolume2ProtocolGuid,\r
231 (VOID**) &FvInstance\r
232 );\r
233 if (EFI_ERROR (Status)) {\r
234 goto FREE_HANDLE_BUFFER;\r
235 }\r
236\r
237 while (Status == EFI_SUCCESS) {\r
238 // FdtBlob must be allocated by ReadSection\r
239 FdtBlob = NULL;\r
240\r
241 // See if it contains the FDT file\r
242 Status = FvInstance->ReadSection (\r
243 FvInstance,\r
244 FileName,\r
245 EFI_SECTION_RAW,\r
246 SectionInstance,\r
247 &FdtBlob,\r
248 &FdtSize,\r
249 &FvStatus\r
250 );\r
251 if (!EFI_ERROR (Status)) {\r
252 // When the FDT blob is attached to the Configuration Table it is recommended to load it as Runtime Service Data\r
253 // to prevent the kernel to overwrite its data\r
254 Status = gBS->AllocatePages (AllocateAnyPages, EfiRuntimeServicesData, EFI_SIZE_TO_PAGES (FdtSize), &FdtBase);\r
255 if (EFI_ERROR (Status)) {\r
256 goto FREE_HANDLE_BUFFER;\r
257 }\r
258\r
259 // Copy the FDT to the Runtime memory\r
260 gBS->CopyMem ((VOID*)(UINTN)FdtBase, FdtBlob, FdtSize);\r
261 // Free the buffer allocated by FvInstance->ReadSection()\r
262 gBS->FreePool (FdtBlob);\r
263\r
264 // Install the FDT as part of the UEFI Configuration Table\r
265 Status = InstallFdtIntoConfigurationTable ((VOID*)(UINTN)FdtBase, FdtSize);\r
266 if (EFI_ERROR (Status)) {\r
267 gBS->FreePages (FdtBase, EFI_SIZE_TO_PAGES (FdtSize));\r
268 }\r
269 break;\r
270 }\r
271 }\r
272 }\r
273\r
274FREE_HANDLE_BUFFER:\r
275 // Free any allocated buffers\r
276 gBS->FreePool (HandleBuffer);\r
277\r
278 return Status;\r
279}\r