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