]> git.proxmox.com Git - mirror_edk2.git/blob - EmbeddedPkg/Library/FdtLib/FdtConfigurationTable.c
ArmPkg,ArmPlatformPkg: Allow dynamic PCDs for memory base and size
[mirror_edk2.git] / EmbeddedPkg / Library / FdtLib / FdtConfigurationTable.c
1 /** @file
2 *
3 * Copyright (c) 2014, ARM Limited. All rights reserved.
4 *
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
9 *
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.
12 *
13 **/
14
15 #include <PiDxe.h>
16 #include <Library/DebugLib.h>
17 #include <Library/MemoryAllocationLib.h>
18 #include <Library/UefiBootServicesTableLib.h>
19
20 #include <Protocol/DevicePath.h>
21 #include <Protocol/FirmwareVolume2.h>
22 #include <Protocol/SimpleFileSystem.h>
23
24 #include <Guid/Fdt.h>
25 #include <Guid/FileInfo.h>
26
27 #include <libfdt.h>
28
29 //
30 // Device path for SemiHosting
31 //
32 STATIC CONST struct {
33 VENDOR_DEVICE_PATH Guid;
34 EFI_DEVICE_PATH_PROTOCOL End;
35 } mSemihostingDevicePath = {
36 {
37 { HARDWARE_DEVICE_PATH, HW_VENDOR_DP, { sizeof (VENDOR_DEVICE_PATH), 0 } },
38 { 0xC5B9C74A, 0x6D72, 0x4719, { 0x99, 0xAB, 0xC5, 0x9F, 0x19, 0x90, 0x91, 0xEB } }
39 },
40 { END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 } }
41 };
42
43
44 /**
45 This function declares the passed FDT into the UEFI Configuration Table
46
47 @param FdtBlob Base address of the Fdt Blob in System Memory
48 @param FdtSize Size of the Fdt Blob in System Memory
49
50 @return EFI_SUCCESS Fdt Blob was successfully installed into the configuration table
51 @return !EFI_SUCCESS Error returned by BS.InstallConfigurationTable()
52
53 **/
54 STATIC
55 EFI_STATUS
56 InstallFdtIntoConfigurationTable (
57 IN VOID* FdtBlob,
58 IN UINTN FdtSize
59 )
60 {
61 EFI_STATUS Status;
62
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);
66
67 // Ensure the Size of the Device Tree is smaller than the size of the read file
68 ASSERT ((UINTN)fdt_totalsize (FdtBlob) <= FdtSize);
69
70 // Install the FDT into the Configuration Table
71 Status = gBS->InstallConfigurationTable (&gFdtTableGuid, FdtBlob);
72
73 return Status;
74 }
75
76
77 /**
78 Load and Install FDT from Semihosting
79
80 @param Filename Name of the file to load from semihosting
81
82 @return EFI_SUCCESS Fdt Blob was successfully installed into the configuration table
83 from semihosting
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
86 **/
87 EFI_STATUS
88 InstallFdtFromSemihosting (
89 IN CONST CHAR16* FileName
90 )
91 {
92 EFI_STATUS Status;
93 EFI_DEVICE_PATH* Remaining;
94 EFI_HANDLE Handle;
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;
100 UINTN FdtSize;
101 UINTN FileInfoSize;
102
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);
111 return Status;
112 }
113
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)) {
117 return Status;
118 }
119
120 // Locate the FileSystem
121 Status = gBS->HandleProtocol (Handle, &gEfiSimpleFileSystemProtocolGuid, (VOID **)&SemihostingFs);
122 if (EFI_ERROR (Status)) {
123 ASSERT_EFI_ERROR (Status);
124 return Status;
125 }
126
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"));
131 return Status;
132 }
133
134 File = NULL;
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));
138 Fs->Close (Fs);
139 return Status;
140 }
141
142 FileInfoSize = 0;
143 File->GetInfo (File, &gEfiFileInfoGuid, &FileInfoSize, NULL);
144 FileInfo = AllocatePool (FileInfoSize);
145 if (FileInfo == NULL) {
146 Status = EFI_OUT_OF_RESOURCES;
147 goto CLOSE_FILES;
148 }
149 Status = File->GetInfo (File, &gEfiFileInfoGuid, &FileInfoSize, FileInfo);
150 if (EFI_ERROR (Status)) {
151 FreePool (FileInfo);
152 goto CLOSE_FILES;
153 }
154
155 // Get the file size
156 FdtSize = FileInfo->FileSize;
157 FreePool (FileInfo);
158
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));
166 } else {
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));
171 }
172 }
173 }
174
175 CLOSE_FILES:
176 File->Close (File);
177 Fs->Close (Fs);
178 return Status;
179 }
180
181 /**
182 Load and Install FDT from Firmware Volume
183
184 @param Filename Guid of the FDT blob to load from firmware volume
185
186 @return EFI_SUCCESS Fdt Blob was successfully installed into the configuration table
187 from firmware volume
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
190 **/
191 EFI_STATUS
192 InstallFdtFromFv (
193 IN CONST EFI_GUID *FileName
194 )
195 {
196 EFI_STATUS Status;
197 EFI_HANDLE *HandleBuffer;
198 UINTN NumberOfHandles;
199 UINT32 FvStatus;
200 UINTN Index;
201 EFI_FIRMWARE_VOLUME2_PROTOCOL *FvInstance;
202 INTN SectionInstance;
203 UINTN FdtSize;
204 VOID* FdtBlob;
205 EFI_PHYSICAL_ADDRESS FdtBase;
206
207 FvStatus = 0;
208 SectionInstance = 0;
209
210 // Locate all the Firmware Volume protocols.
211 Status = gBS->LocateHandleBuffer (
212 ByProtocol,
213 &gEfiFirmwareVolume2ProtocolGuid,
214 NULL,
215 &NumberOfHandles,
216 &HandleBuffer
217 );
218 if (EFI_ERROR (Status)) {
219 return Status;
220 }
221
222 // Looking for FV that contains the FDT blob
223 for (Index = 0; Index < NumberOfHandles; Index++) {
224 //
225 // Get the protocol on this handle
226 // This should not fail because of LocateHandleBuffer
227 //
228 Status = gBS->HandleProtocol (
229 HandleBuffer[Index],
230 &gEfiFirmwareVolume2ProtocolGuid,
231 (VOID**) &FvInstance
232 );
233 if (EFI_ERROR (Status)) {
234 goto FREE_HANDLE_BUFFER;
235 }
236
237 while (Status == EFI_SUCCESS) {
238 // FdtBlob must be allocated by ReadSection
239 FdtBlob = NULL;
240
241 // See if it contains the FDT file
242 Status = FvInstance->ReadSection (
243 FvInstance,
244 FileName,
245 EFI_SECTION_RAW,
246 SectionInstance,
247 &FdtBlob,
248 &FdtSize,
249 &FvStatus
250 );
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;
257 }
258
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);
263
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));
268 }
269 break;
270 }
271 }
272 }
273
274 FREE_HANDLE_BUFFER:
275 // Free any allocated buffers
276 gBS->FreePool (HandleBuffer);
277
278 return Status;
279 }