]>
Commit | Line | Data |
---|---|---|
1bfda055 | 1 | /** @file |
2 | * | |
0a6653bc | 3 | * Copyright (c) 2011-2012, ARM Limited. All rights reserved. |
1bfda055 | 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 "BdsInternal.h" | |
16 | ||
a355a365 | 17 | #include <Protocol/UsbIo.h> |
18 | #include <Protocol/DiskIo.h> | |
2755d844 | 19 | #include <Protocol/LoadedImage.h> |
a355a365 | 20 | |
21 | #define IS_DEVICE_PATH_NODE(node,type,subtype) (((node)->Type == (type)) && ((node)->SubType == (subtype))) | |
22 | ||
23 | // Extract the FilePath from the Device Path | |
24 | CHAR16* | |
25 | BdsExtractFilePathFromDevicePath ( | |
26 | IN CONST CHAR16 *StrDevicePath, | |
27 | IN UINTN NumberDevicePathNode | |
28 | ) | |
29 | { | |
30 | UINTN Node; | |
31 | CHAR16 *Str; | |
32 | ||
33 | Str = (CHAR16*)StrDevicePath; | |
34 | Node = 0; | |
35 | while ((Str != NULL) && (*Str != L'\0') && (Node < NumberDevicePathNode)) { | |
36 | if ((*Str == L'/') || (*Str == L'\\')) { | |
37 | Node++; | |
1bfda055 | 38 | } |
a355a365 | 39 | Str++; |
40 | } | |
41 | ||
42 | if (*Str == L'\0') { | |
43 | return NULL; | |
44 | } else { | |
45 | return Str; | |
46 | } | |
1bfda055 | 47 | } |
48 | ||
a355a365 | 49 | BOOLEAN |
50 | BdsIsRemovableUsb ( | |
51 | IN EFI_DEVICE_PATH* DevicePath | |
52 | ) | |
53 | { | |
54 | return ((DevicePathType (DevicePath) == MESSAGING_DEVICE_PATH) && | |
55 | ((DevicePathSubType (DevicePath) == MSG_USB_CLASS_DP) || | |
56 | (DevicePathSubType (DevicePath) == MSG_USB_WWID_DP))); | |
57 | } | |
58 | ||
59 | EFI_STATUS | |
60 | BdsGetDeviceUsb ( | |
61 | IN EFI_DEVICE_PATH* RemovableDevicePath, | |
62 | OUT EFI_HANDLE* DeviceHandle, | |
63 | OUT EFI_DEVICE_PATH** NewDevicePath | |
64 | ) | |
65 | { | |
66 | EFI_STATUS Status; | |
67 | UINTN Index; | |
68 | UINTN UsbIoHandleCount; | |
69 | EFI_HANDLE *UsbIoBuffer; | |
70 | EFI_DEVICE_PATH* UsbIoDevicePath; | |
71 | EFI_DEVICE_PATH* TmpDevicePath; | |
72 | USB_WWID_DEVICE_PATH* WwidDevicePath1; | |
73 | USB_WWID_DEVICE_PATH* WwidDevicePath2; | |
74 | USB_CLASS_DEVICE_PATH* UsbClassDevicePath1; | |
75 | USB_CLASS_DEVICE_PATH* UsbClassDevicePath2; | |
76 | ||
77 | // Get all the UsbIo handles | |
78 | UsbIoHandleCount = 0; | |
79 | Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiUsbIoProtocolGuid, NULL, &UsbIoHandleCount, &UsbIoBuffer); | |
80 | if (EFI_ERROR(Status) || (UsbIoHandleCount == 0)) { | |
81 | return Status; | |
82 | } | |
83 | ||
84 | // Check if one of the handles matches the USB description | |
85 | for (Index = 0; Index < UsbIoHandleCount; Index++) { | |
7598f362 | 86 | Status = gBS->HandleProtocol (UsbIoBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **) &UsbIoDevicePath); |
a355a365 | 87 | if (!EFI_ERROR(Status)) { |
88 | TmpDevicePath = UsbIoDevicePath; | |
89 | while (!IsDevicePathEnd (TmpDevicePath)) { | |
90 | // Check if the Device Path node is a USB Removable device Path node | |
91 | if (BdsIsRemovableUsb (TmpDevicePath)) { | |
92 | if (TmpDevicePath->SubType == MSG_USB_WWID_DP) { | |
93 | WwidDevicePath1 = (USB_WWID_DEVICE_PATH*)RemovableDevicePath; | |
94 | WwidDevicePath2 = (USB_WWID_DEVICE_PATH*)TmpDevicePath; | |
95 | if ((WwidDevicePath1->VendorId == WwidDevicePath2->VendorId) && | |
96 | (WwidDevicePath1->ProductId == WwidDevicePath2->ProductId) && | |
97 | (CompareMem (WwidDevicePath1+1, WwidDevicePath2+1, DevicePathNodeLength(WwidDevicePath1)-sizeof(USB_WWID_DEVICE_PATH)) == 0)) | |
98 | { | |
99 | *DeviceHandle = UsbIoBuffer[Index]; | |
100 | // Add the additional original Device Path Nodes (eg: FilePath Device Path Node) to the new Device Path | |
101 | *NewDevicePath = AppendDevicePath (UsbIoDevicePath, NextDevicePathNode(RemovableDevicePath)); | |
102 | return EFI_SUCCESS; | |
103 | } | |
104 | } else { | |
105 | UsbClassDevicePath1 = (USB_CLASS_DEVICE_PATH*)RemovableDevicePath; | |
106 | UsbClassDevicePath2 = (USB_CLASS_DEVICE_PATH*)TmpDevicePath; | |
107 | if ((UsbClassDevicePath1->VendorId != 0xFFFF) && (UsbClassDevicePath1->VendorId == UsbClassDevicePath2->VendorId) && | |
108 | (UsbClassDevicePath1->ProductId != 0xFFFF) && (UsbClassDevicePath1->ProductId == UsbClassDevicePath2->ProductId) && | |
109 | (UsbClassDevicePath1->DeviceClass != 0xFF) && (UsbClassDevicePath1->DeviceClass == UsbClassDevicePath2->DeviceClass) && | |
110 | (UsbClassDevicePath1->DeviceSubClass != 0xFF) && (UsbClassDevicePath1->DeviceSubClass == UsbClassDevicePath2->DeviceSubClass) && | |
111 | (UsbClassDevicePath1->DeviceProtocol != 0xFF) && (UsbClassDevicePath1->DeviceProtocol == UsbClassDevicePath2->DeviceProtocol)) | |
112 | { | |
113 | *DeviceHandle = UsbIoBuffer[Index]; | |
114 | // Add the additional original Device Path Nodes (eg: FilePath Device Path Node) to the new Device Path | |
115 | *NewDevicePath = AppendDevicePath (UsbIoDevicePath, NextDevicePathNode(RemovableDevicePath)); | |
116 | return EFI_SUCCESS; | |
117 | } | |
118 | } | |
1bfda055 | 119 | } |
a355a365 | 120 | TmpDevicePath = NextDevicePathNode (TmpDevicePath); |
121 | } | |
1bfda055 | 122 | |
1bfda055 | 123 | } |
a355a365 | 124 | } |
125 | ||
126 | return EFI_NOT_FOUND; | |
127 | } | |
128 | ||
129 | BOOLEAN | |
130 | BdsIsRemovableHd ( | |
131 | IN EFI_DEVICE_PATH* DevicePath | |
132 | ) | |
133 | { | |
134 | return IS_DEVICE_PATH_NODE(DevicePath, MEDIA_DEVICE_PATH, MEDIA_HARDDRIVE_DP); | |
1bfda055 | 135 | } |
136 | ||
137 | EFI_STATUS | |
a355a365 | 138 | BdsGetDeviceHd ( |
139 | IN EFI_DEVICE_PATH* RemovableDevicePath, | |
140 | OUT EFI_HANDLE* DeviceHandle, | |
141 | OUT EFI_DEVICE_PATH** NewDevicePath | |
142 | ) | |
143 | { | |
144 | EFI_STATUS Status; | |
145 | UINTN Index; | |
146 | UINTN PartitionHandleCount; | |
147 | EFI_HANDLE *PartitionBuffer; | |
148 | EFI_DEVICE_PATH* PartitionDevicePath; | |
149 | EFI_DEVICE_PATH* TmpDevicePath; | |
150 | HARDDRIVE_DEVICE_PATH* HardDriveDevicePath1; | |
151 | HARDDRIVE_DEVICE_PATH* HardDriveDevicePath2; | |
1bfda055 | 152 | |
a355a365 | 153 | // Get all the DiskIo handles |
154 | PartitionHandleCount = 0; | |
155 | Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiDiskIoProtocolGuid, NULL, &PartitionHandleCount, &PartitionBuffer); | |
156 | if (EFI_ERROR(Status) || (PartitionHandleCount == 0)) { | |
157 | return Status; | |
158 | } | |
1bfda055 | 159 | |
a355a365 | 160 | // Check if one of the handles matches the Hard Disk Description |
161 | for (Index = 0; Index < PartitionHandleCount; Index++) { | |
7598f362 | 162 | Status = gBS->HandleProtocol (PartitionBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **) &PartitionDevicePath); |
a355a365 | 163 | if (!EFI_ERROR(Status)) { |
164 | TmpDevicePath = PartitionDevicePath; | |
165 | while (!IsDevicePathEnd (TmpDevicePath)) { | |
166 | // Check if the Device Path node is a HD Removable device Path node | |
167 | if (BdsIsRemovableHd (TmpDevicePath)) { | |
168 | HardDriveDevicePath1 = (HARDDRIVE_DEVICE_PATH*)RemovableDevicePath; | |
169 | HardDriveDevicePath2 = (HARDDRIVE_DEVICE_PATH*)TmpDevicePath; | |
170 | if ((HardDriveDevicePath1->SignatureType == HardDriveDevicePath2->SignatureType) && | |
171 | (CompareGuid ((EFI_GUID *)HardDriveDevicePath1->Signature,(EFI_GUID *)HardDriveDevicePath2->Signature) == TRUE) && | |
172 | (HardDriveDevicePath1->PartitionNumber == HardDriveDevicePath2->PartitionNumber)) | |
173 | { | |
174 | *DeviceHandle = PartitionBuffer[Index]; | |
175 | // Add the additional original Device Path Nodes (eg: FilePath Device Path Node) to the new Device Path | |
176 | *NewDevicePath = AppendDevicePath (PartitionDevicePath, NextDevicePathNode(RemovableDevicePath)); | |
177 | return EFI_SUCCESS; | |
178 | } | |
1bfda055 | 179 | } |
a355a365 | 180 | TmpDevicePath = NextDevicePathNode (TmpDevicePath); |
181 | } | |
1bfda055 | 182 | |
1bfda055 | 183 | } |
a355a365 | 184 | } |
1bfda055 | 185 | |
a355a365 | 186 | return EFI_NOT_FOUND; |
1bfda055 | 187 | } |
188 | ||
a355a365 | 189 | /*BOOLEAN |
190 | BdsIsRemovableCdrom ( | |
191 | IN EFI_DEVICE_PATH* DevicePath | |
192 | ) | |
193 | { | |
194 | return IS_DEVICE_PATH_NODE(DevicePath, MEDIA_DEVICE_PATH, MEDIA_CDROM_DP); | |
195 | } | |
1bfda055 | 196 | |
197 | EFI_STATUS | |
a355a365 | 198 | BdsGetDeviceCdrom ( |
199 | IN EFI_DEVICE_PATH* RemovableDevicePath, | |
200 | OUT EFI_HANDLE* DeviceHandle, | |
201 | OUT EFI_DEVICE_PATH** DevicePath | |
202 | ) | |
203 | { | |
204 | ASSERT(0); | |
205 | return EFI_UNSUPPORTED; | |
206 | }*/ | |
207 | ||
208 | typedef BOOLEAN | |
209 | (*BDS_IS_REMOVABLE) ( | |
210 | IN EFI_DEVICE_PATH* DevicePath | |
211 | ); | |
212 | ||
213 | typedef EFI_STATUS | |
214 | (*BDS_GET_DEVICE) ( | |
215 | IN EFI_DEVICE_PATH* RemovableDevicePath, | |
216 | OUT EFI_HANDLE* DeviceHandle, | |
217 | OUT EFI_DEVICE_PATH** DevicePath | |
218 | ); | |
219 | ||
220 | typedef struct { | |
221 | BDS_IS_REMOVABLE IsRemovable; | |
222 | BDS_GET_DEVICE GetDevice; | |
223 | } BDS_REMOVABLE_DEVICE_SUPPORT; | |
224 | ||
225 | BDS_REMOVABLE_DEVICE_SUPPORT RemovableDeviceSupport[] = { | |
226 | { BdsIsRemovableUsb, BdsGetDeviceUsb }, | |
227 | { BdsIsRemovableHd, BdsGetDeviceHd }, | |
228 | //{ BdsIsRemovableCdrom, BdsGetDeviceCdrom } | |
229 | }; | |
230 | ||
231 | STATIC | |
232 | BOOLEAN | |
233 | IsRemovableDevice ( | |
234 | IN EFI_DEVICE_PATH* DevicePath | |
235 | ) | |
236 | { | |
237 | UINTN Index; | |
238 | EFI_DEVICE_PATH* TmpDevicePath; | |
239 | ||
240 | TmpDevicePath = DevicePath; | |
241 | while (!IsDevicePathEnd (TmpDevicePath)) { | |
242 | for (Index = 0; Index < sizeof(RemovableDeviceSupport) / sizeof(BDS_REMOVABLE_DEVICE_SUPPORT); Index++) { | |
243 | if (RemovableDeviceSupport[Index].IsRemovable(TmpDevicePath)) { | |
244 | return TRUE; | |
245 | } | |
1bfda055 | 246 | } |
a355a365 | 247 | TmpDevicePath = NextDevicePathNode (TmpDevicePath); |
248 | } | |
249 | ||
250 | return FALSE; | |
251 | } | |
1bfda055 | 252 | |
a355a365 | 253 | STATIC |
254 | EFI_STATUS | |
255 | TryRemovableDevice ( | |
256 | IN EFI_DEVICE_PATH* DevicePath, | |
257 | OUT EFI_HANDLE* DeviceHandle, | |
258 | OUT EFI_DEVICE_PATH** NewDevicePath | |
259 | ) | |
260 | { | |
261 | EFI_STATUS Status; | |
262 | UINTN Index; | |
263 | EFI_DEVICE_PATH* TmpDevicePath; | |
264 | BDS_REMOVABLE_DEVICE_SUPPORT* RemovableDevice; | |
265 | EFI_DEVICE_PATH* RemovableDevicePath; | |
266 | BOOLEAN RemovableFound; | |
1bfda055 | 267 | |
e862cd50 | 268 | RemovableDevice = NULL; |
269 | RemovableDevicePath = NULL; | |
270 | RemovableFound = FALSE; | |
271 | TmpDevicePath = DevicePath; | |
272 | ||
a355a365 | 273 | while (!IsDevicePathEnd (TmpDevicePath) && !RemovableFound) { |
274 | for (Index = 0; Index < sizeof(RemovableDeviceSupport) / sizeof(BDS_REMOVABLE_DEVICE_SUPPORT); Index++) { | |
275 | RemovableDevice = &RemovableDeviceSupport[Index]; | |
276 | if (RemovableDevice->IsRemovable(TmpDevicePath)) { | |
277 | RemovableDevicePath = TmpDevicePath; | |
278 | RemovableFound = TRUE; | |
279 | break; | |
280 | } | |
1bfda055 | 281 | } |
a355a365 | 282 | TmpDevicePath = NextDevicePathNode (TmpDevicePath); |
283 | } | |
1bfda055 | 284 | |
a355a365 | 285 | if (!RemovableFound) { |
286 | return EFI_NOT_FOUND; | |
287 | } | |
1bfda055 | 288 | |
a355a365 | 289 | // Search into the current started drivers |
290 | Status = RemovableDevice->GetDevice (RemovableDevicePath, DeviceHandle, NewDevicePath); | |
291 | if (Status == EFI_NOT_FOUND) { | |
292 | // Connect all the drivers | |
293 | BdsConnectAllDrivers (); | |
294 | ||
295 | // Search again into all the drivers | |
296 | Status = RemovableDevice->GetDevice (RemovableDevicePath, DeviceHandle, NewDevicePath); | |
297 | } | |
298 | ||
299 | return Status; | |
300 | } | |
301 | ||
6bab33c7 | 302 | /** |
303 | Connect a Device Path and return the handle of the driver that support this DevicePath | |
304 | ||
305 | @param DevicePath Device Path of the File to connect | |
306 | @param Handle Handle of the driver that support this DevicePath | |
307 | @param RemainingDevicePath Remaining DevicePath nodes that do not match the driver DevicePath | |
308 | ||
309 | @retval EFI_SUCCESS A driver that matches the Device Path has been found | |
310 | @retval EFI_NOT_FOUND No handles match the search. | |
311 | @retval EFI_INVALID_PARAMETER DevicePath or Handle is NULL | |
312 | ||
313 | **/ | |
a355a365 | 314 | EFI_STATUS |
315 | BdsConnectDevicePath ( | |
316 | IN EFI_DEVICE_PATH_PROTOCOL* DevicePath, | |
317 | OUT EFI_HANDLE *Handle, | |
318 | OUT EFI_DEVICE_PATH_PROTOCOL **RemainingDevicePath | |
319 | ) | |
320 | { | |
321 | EFI_DEVICE_PATH* Remaining; | |
322 | EFI_DEVICE_PATH* NewDevicePath; | |
323 | EFI_STATUS Status; | |
324 | ||
325 | if ((DevicePath == NULL) || (Handle == NULL)) { | |
326 | return EFI_INVALID_PARAMETER; | |
327 | } | |
328 | ||
329 | do { | |
330 | Remaining = DevicePath; | |
331 | // The LocateDevicePath() function locates all devices on DevicePath that support Protocol and returns | |
332 | // the handle to the device that is closest to DevicePath. On output, the device path pointer is modified | |
333 | // to point to the remaining part of the device path | |
334 | Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &Remaining, Handle); | |
335 | if (!EFI_ERROR (Status)) { | |
336 | // Recursive = FALSE: We do not want to start all the device tree | |
337 | Status = gBS->ConnectController (*Handle, NULL, Remaining, FALSE); | |
1bfda055 | 338 | } |
339 | ||
a355a365 | 340 | /*// We need to check if RemainingDevicePath does not point on the last node. Otherwise, calling |
341 | // NextDevicePathNode() will return an undetermined Device Path Node | |
342 | if (!IsDevicePathEnd (RemainingDevicePath)) { | |
343 | RemainingDevicePath = NextDevicePathNode (RemainingDevicePath); | |
344 | }*/ | |
345 | } while (!EFI_ERROR (Status) && !IsDevicePathEnd (Remaining)); | |
346 | ||
347 | if (!EFI_ERROR (Status)) { | |
348 | // Now, we have got the whole Device Path connected, call again ConnectController to ensure all the supported Driver | |
349 | // Binding Protocol are connected (such as DiskIo and SimpleFileSystem) | |
350 | Remaining = DevicePath; | |
6bab33c7 | 351 | Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid,&Remaining,Handle); |
a355a365 | 352 | if (!EFI_ERROR (Status)) { |
353 | Status = gBS->ConnectController (*Handle, NULL, Remaining, FALSE); | |
354 | if (EFI_ERROR (Status)) { | |
355 | // If the last node is a Memory Map Device Path just return EFI_SUCCESS. | |
356 | if ((Remaining->Type == HARDWARE_DEVICE_PATH) && (Remaining->SubType == HW_MEMMAP_DP)) { | |
357 | Status = EFI_SUCCESS; | |
1bfda055 | 358 | } |
a355a365 | 359 | } |
1bfda055 | 360 | } |
a355a365 | 361 | } else if (!IsDevicePathEnd (Remaining) && !IsRemovableDevice (Remaining)) { |
362 | ||
363 | /*// If the remaining Device Path is a FilePath or MemoryMap then we consider the Device Path has been loaded correctly | |
364 | if ((Remaining->Type == MEDIA_DEVICE_PATH) && (Remaining->SubType == MEDIA_FILEPATH_DP)) { | |
365 | Status = EFI_SUCCESS; | |
366 | } else if ((Remaining->Type == HARDWARE_DEVICE_PATH) && (Remaining->SubType == HW_MEMMAP_DP)) { | |
367 | Status = EFI_SUCCESS; | |
368 | }*/ | |
1bfda055 | 369 | |
a355a365 | 370 | //TODO: Should we just return success and leave the caller decide if it is the expected RemainingPath |
371 | Status = EFI_SUCCESS; | |
372 | } else { | |
373 | Status = TryRemovableDevice (DevicePath, Handle, &NewDevicePath); | |
1bfda055 | 374 | if (!EFI_ERROR (Status)) { |
a355a365 | 375 | return BdsConnectDevicePath (NewDevicePath, Handle, RemainingDevicePath); |
376 | } | |
377 | } | |
378 | ||
379 | if (RemainingDevicePath) { | |
380 | *RemainingDevicePath = Remaining; | |
381 | } | |
382 | ||
383 | return Status; | |
384 | } | |
385 | ||
386 | BOOLEAN | |
387 | BdsFileSystemSupport ( | |
388 | IN EFI_DEVICE_PATH *DevicePath, | |
389 | IN EFI_HANDLE Handle, | |
390 | IN EFI_DEVICE_PATH *RemainingDevicePath | |
391 | ) | |
392 | { | |
393 | EFI_STATUS Status; | |
394 | EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FsProtocol; | |
395 | ||
396 | Status = gBS->HandleProtocol (Handle,&gEfiSimpleFileSystemProtocolGuid, (VOID **)&FsProtocol); | |
397 | ||
398 | return (!EFI_ERROR(Status) && IS_DEVICE_PATH_NODE(RemainingDevicePath,MEDIA_DEVICE_PATH,MEDIA_FILEPATH_DP)); | |
399 | } | |
400 | ||
401 | EFI_STATUS | |
402 | BdsFileSystemLoadImage ( | |
403 | IN EFI_DEVICE_PATH *DevicePath, | |
404 | IN EFI_HANDLE Handle, | |
405 | IN EFI_DEVICE_PATH *RemainingDevicePath, | |
406 | IN EFI_ALLOCATE_TYPE Type, | |
407 | IN OUT EFI_PHYSICAL_ADDRESS* Image, | |
408 | OUT UINTN *ImageSize | |
409 | ) | |
410 | { | |
411 | FILEPATH_DEVICE_PATH* FilePathDevicePath; | |
412 | EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FsProtocol; | |
413 | EFI_FILE_PROTOCOL *Fs; | |
414 | EFI_STATUS Status; | |
415 | EFI_FILE_INFO *FileInfo; | |
416 | EFI_FILE_PROTOCOL *File; | |
417 | UINTN Size; | |
418 | ||
419 | ASSERT (IS_DEVICE_PATH_NODE(RemainingDevicePath,MEDIA_DEVICE_PATH,MEDIA_FILEPATH_DP)); | |
420 | ||
421 | FilePathDevicePath = (FILEPATH_DEVICE_PATH*)RemainingDevicePath; | |
422 | ||
423 | Status = gBS->HandleProtocol(Handle,&gEfiSimpleFileSystemProtocolGuid, (VOID **)&FsProtocol); | |
424 | if (EFI_ERROR(Status)) { | |
425 | return Status; | |
426 | } | |
427 | ||
bd54c237 | 428 | // Try to Open the volume and get root directory |
a355a365 | 429 | Status = FsProtocol->OpenVolume (FsProtocol, &Fs); |
430 | if (EFI_ERROR(Status)) { | |
431 | return Status; | |
432 | } | |
433 | ||
434 | File = NULL; | |
435 | Status = Fs->Open(Fs, &File, FilePathDevicePath->PathName, EFI_FILE_MODE_READ, 0); | |
6bab33c7 | 436 | if (EFI_ERROR(Status)) { |
437 | return Status; | |
438 | } | |
a355a365 | 439 | |
440 | Size = 0; | |
441 | File->GetInfo(File, &gEfiFileInfoGuid, &Size, NULL); | |
442 | FileInfo = AllocatePool (Size); | |
443 | Status = File->GetInfo(File, &gEfiFileInfoGuid, &Size, FileInfo); | |
444 | if (EFI_ERROR(Status)) { | |
445 | return Status; | |
446 | } | |
447 | ||
448 | // Get the file size | |
449 | Size = FileInfo->FileSize; | |
450 | if (ImageSize) { | |
451 | *ImageSize = Size; | |
452 | } | |
453 | FreePool(FileInfo); | |
454 | ||
bd54c237 | 455 | Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(Size), Image); |
456 | // Try to allocate in any pages if failed to allocate memory at the defined location | |
457 | if ((Status == EFI_OUT_OF_RESOURCES) && (Type != AllocateAnyPages)) { | |
458 | Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesCode, EFI_SIZE_TO_PAGES(Size), Image); | |
459 | } | |
a355a365 | 460 | if (!EFI_ERROR(Status)) { |
461 | Status = File->Read (File, &Size, (VOID*)(UINTN)(*Image)); | |
462 | } | |
463 | ||
464 | return Status; | |
465 | } | |
466 | ||
467 | BOOLEAN | |
468 | BdsMemoryMapSupport ( | |
469 | IN EFI_DEVICE_PATH *DevicePath, | |
470 | IN EFI_HANDLE Handle, | |
471 | IN EFI_DEVICE_PATH *RemainingDevicePath | |
472 | ) | |
473 | { | |
aa863d35 | 474 | return IS_DEVICE_PATH_NODE(DevicePath,HARDWARE_DEVICE_PATH,HW_MEMMAP_DP) || |
475 | IS_DEVICE_PATH_NODE(RemainingDevicePath,HARDWARE_DEVICE_PATH,HW_MEMMAP_DP); | |
a355a365 | 476 | } |
477 | ||
478 | EFI_STATUS | |
479 | BdsMemoryMapLoadImage ( | |
480 | IN EFI_DEVICE_PATH *DevicePath, | |
481 | IN EFI_HANDLE Handle, | |
482 | IN EFI_DEVICE_PATH *RemainingDevicePath, | |
483 | IN EFI_ALLOCATE_TYPE Type, | |
484 | IN OUT EFI_PHYSICAL_ADDRESS* Image, | |
485 | OUT UINTN *ImageSize | |
486 | ) | |
487 | { | |
488 | EFI_STATUS Status; | |
489 | MEMMAP_DEVICE_PATH* MemMapPathDevicePath; | |
490 | UINTN Size; | |
491 | ||
aa863d35 | 492 | if (IS_DEVICE_PATH_NODE(RemainingDevicePath,HARDWARE_DEVICE_PATH,HW_MEMMAP_DP)) { |
493 | MemMapPathDevicePath = (MEMMAP_DEVICE_PATH*)RemainingDevicePath; | |
494 | } else { | |
495 | ASSERT (IS_DEVICE_PATH_NODE(DevicePath,HARDWARE_DEVICE_PATH,HW_MEMMAP_DP)); | |
496 | MemMapPathDevicePath = (MEMMAP_DEVICE_PATH*)DevicePath; | |
497 | } | |
a355a365 | 498 | |
499 | Size = MemMapPathDevicePath->EndingAddress - MemMapPathDevicePath->StartingAddress; | |
500 | if (Size == 0) { | |
501 | return EFI_INVALID_PARAMETER; | |
502 | } | |
503 | ||
bd54c237 | 504 | Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(Size), Image); |
505 | // Try to allocate in any pages if failed to allocate memory at the defined location | |
506 | if ((Status == EFI_OUT_OF_RESOURCES) && (Type != AllocateAnyPages)) { | |
507 | Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesCode, EFI_SIZE_TO_PAGES(Size), Image); | |
508 | } | |
a355a365 | 509 | if (!EFI_ERROR(Status)) { |
510 | CopyMem ((VOID*)(UINTN)(*Image), (CONST VOID*)(UINTN)MemMapPathDevicePath->StartingAddress, Size); | |
511 | ||
512 | if (ImageSize != NULL) { | |
513 | *ImageSize = Size; | |
1bfda055 | 514 | } |
a355a365 | 515 | } |
1bfda055 | 516 | |
a355a365 | 517 | return Status; |
518 | } | |
519 | ||
520 | BOOLEAN | |
521 | BdsFirmwareVolumeSupport ( | |
522 | IN EFI_DEVICE_PATH *DevicePath, | |
523 | IN EFI_HANDLE Handle, | |
524 | IN EFI_DEVICE_PATH *RemainingDevicePath | |
525 | ) | |
526 | { | |
527 | return IS_DEVICE_PATH_NODE(RemainingDevicePath, MEDIA_DEVICE_PATH, MEDIA_PIWG_FW_FILE_DP); | |
528 | } | |
529 | ||
530 | EFI_STATUS | |
531 | BdsFirmwareVolumeLoadImage ( | |
532 | IN EFI_DEVICE_PATH *DevicePath, | |
533 | IN EFI_HANDLE Handle, | |
534 | IN EFI_DEVICE_PATH *RemainingDevicePath, | |
535 | IN EFI_ALLOCATE_TYPE Type, | |
536 | IN OUT EFI_PHYSICAL_ADDRESS* Image, | |
537 | OUT UINTN *ImageSize | |
538 | ) | |
539 | { | |
540 | EFI_STATUS Status; | |
541 | EFI_FIRMWARE_VOLUME2_PROTOCOL *FwVol; | |
542 | EFI_GUID *FvNameGuid; | |
543 | EFI_SECTION_TYPE SectionType; | |
544 | EFI_FV_FILETYPE FvType; | |
545 | EFI_FV_FILE_ATTRIBUTES Attrib; | |
546 | UINT32 AuthenticationStatus; | |
547 | VOID* ImageBuffer; | |
548 | ||
549 | ASSERT (IS_DEVICE_PATH_NODE(RemainingDevicePath, MEDIA_DEVICE_PATH, MEDIA_PIWG_FW_FILE_DP)); | |
550 | ||
551 | Status = gBS->HandleProtocol(Handle,&gEfiFirmwareVolume2ProtocolGuid, (VOID **)&FwVol); | |
552 | if (EFI_ERROR(Status)) { | |
1bfda055 | 553 | return Status; |
a355a365 | 554 | } |
555 | ||
556 | FvNameGuid = EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)RemainingDevicePath); | |
557 | if (FvNameGuid == NULL) { | |
558 | Status = EFI_INVALID_PARAMETER; | |
559 | } | |
560 | ||
561 | SectionType = EFI_SECTION_PE32; | |
562 | AuthenticationStatus = 0; | |
563 | //Note: ReadSection at the opposite of ReadFile does not allow to pass ImageBuffer == NULL to get the size of the file. | |
564 | ImageBuffer = NULL; | |
565 | Status = FwVol->ReadSection ( | |
566 | FwVol, | |
567 | FvNameGuid, | |
568 | SectionType, | |
569 | 0, | |
570 | &ImageBuffer, | |
571 | ImageSize, | |
572 | &AuthenticationStatus | |
573 | ); | |
574 | if (!EFI_ERROR (Status)) { | |
575 | #if 0 | |
576 | // In case the buffer has some address requirements, we must copy the buffer to a buffer following the requirements | |
577 | if (Type != AllocateAnyPages) { | |
578 | Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize),Image); | |
579 | if (!EFI_ERROR(Status)) { | |
580 | CopyMem ((VOID*)(UINTN)(*Image), ImageBuffer, *ImageSize); | |
581 | FreePool (ImageBuffer); | |
582 | } | |
583 | } | |
584 | #else | |
585 | // We must copy the buffer into a page allocations. Otherwise, the caller could call gBS->FreePages() on the pool allocation | |
586 | Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize), Image); | |
bd54c237 | 587 | // Try to allocate in any pages if failed to allocate memory at the defined location |
588 | if ((Status == EFI_OUT_OF_RESOURCES) && (Type != AllocateAnyPages)) { | |
1c6f402c | 589 | Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize), Image); |
bd54c237 | 590 | } |
a355a365 | 591 | if (!EFI_ERROR(Status)) { |
592 | CopyMem ((VOID*)(UINTN)(*Image), ImageBuffer, *ImageSize); | |
593 | FreePool (ImageBuffer); | |
594 | } | |
595 | #endif | |
596 | } else { | |
597 | // Try a raw file, since a PE32 SECTION does not exist | |
598 | Status = FwVol->ReadFile ( | |
599 | FwVol, | |
600 | FvNameGuid, | |
601 | NULL, | |
602 | ImageSize, | |
603 | &FvType, | |
604 | &Attrib, | |
605 | &AuthenticationStatus | |
606 | ); | |
607 | if (!EFI_ERROR(Status)) { | |
bd54c237 | 608 | Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize), Image); |
609 | // Try to allocate in any pages if failed to allocate memory at the defined location | |
610 | if ((Status == EFI_OUT_OF_RESOURCES) && (Type != AllocateAnyPages)) { | |
1c6f402c | 611 | Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize), Image); |
bd54c237 | 612 | } |
a355a365 | 613 | if (!EFI_ERROR(Status)) { |
614 | Status = FwVol->ReadFile ( | |
615 | FwVol, | |
616 | FvNameGuid, | |
617 | (VOID*)(UINTN)(*Image), | |
618 | ImageSize, | |
619 | &FvType, | |
620 | &Attrib, | |
621 | &AuthenticationStatus | |
622 | ); | |
623 | } | |
624 | } | |
625 | } | |
626 | return Status; | |
1bfda055 | 627 | } |
628 | ||
a355a365 | 629 | BOOLEAN |
630 | BdsPxeSupport ( | |
631 | IN EFI_DEVICE_PATH* DevicePath, | |
632 | IN EFI_HANDLE Handle, | |
633 | IN EFI_DEVICE_PATH* RemainingDevicePath | |
634 | ) | |
635 | { | |
636 | EFI_STATUS Status; | |
637 | EFI_PXE_BASE_CODE_PROTOCOL* PxeBcProtocol; | |
638 | ||
639 | if (!IsDevicePathEnd(RemainingDevicePath)) { | |
640 | return FALSE; | |
641 | } | |
642 | ||
643 | Status = gBS->HandleProtocol (Handle, &gEfiPxeBaseCodeProtocolGuid, (VOID **)&PxeBcProtocol); | |
644 | if (EFI_ERROR (Status)) { | |
645 | return FALSE; | |
646 | } else { | |
647 | return TRUE; | |
648 | } | |
649 | } | |
650 | ||
651 | EFI_STATUS | |
652 | BdsPxeLoadImage ( | |
653 | IN EFI_DEVICE_PATH* DevicePath, | |
654 | IN EFI_HANDLE Handle, | |
655 | IN EFI_DEVICE_PATH* RemainingDevicePath, | |
656 | IN EFI_ALLOCATE_TYPE Type, | |
657 | IN OUT EFI_PHYSICAL_ADDRESS *Image, | |
658 | OUT UINTN *ImageSize | |
659 | ) | |
660 | { | |
661 | EFI_STATUS Status; | |
662 | EFI_LOAD_FILE_PROTOCOL *LoadFileProtocol; | |
663 | UINTN BufferSize; | |
664 | ||
665 | // Get Load File Protocol attached to the PXE protocol | |
666 | Status = gBS->HandleProtocol (Handle, &gEfiLoadFileProtocolGuid, (VOID **)&LoadFileProtocol); | |
667 | if (EFI_ERROR (Status)) { | |
668 | return Status; | |
669 | } | |
670 | ||
671 | Status = LoadFileProtocol->LoadFile (LoadFileProtocol, DevicePath, TRUE, &BufferSize, NULL); | |
672 | if (Status == EFI_BUFFER_TOO_SMALL) { | |
673 | Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(BufferSize), Image); | |
674 | if (EFI_ERROR(Status)) { | |
675 | return Status; | |
1bfda055 | 676 | } |
677 | ||
a355a365 | 678 | Status = LoadFileProtocol->LoadFile (LoadFileProtocol, DevicePath, TRUE, &BufferSize, (VOID*)(UINTN)(*Image)); |
679 | if (!EFI_ERROR(Status) && (ImageSize != NULL)) { | |
680 | *ImageSize = BufferSize; | |
1bfda055 | 681 | } |
a355a365 | 682 | } |
683 | ||
684 | return Status; | |
685 | } | |
686 | ||
687 | BOOLEAN | |
688 | BdsTftpSupport ( | |
689 | IN EFI_DEVICE_PATH* DevicePath, | |
690 | IN EFI_HANDLE Handle, | |
691 | IN EFI_DEVICE_PATH* RemainingDevicePath | |
692 | ) | |
693 | { | |
694 | EFI_STATUS Status; | |
695 | EFI_DEVICE_PATH *NextDevicePath; | |
696 | EFI_PXE_BASE_CODE_PROTOCOL *PxeBcProtocol; | |
697 | ||
698 | // Validate the Remaining Device Path | |
699 | if (IsDevicePathEnd(RemainingDevicePath)) { | |
700 | return FALSE; | |
701 | } | |
702 | if (!IS_DEVICE_PATH_NODE(RemainingDevicePath,MESSAGING_DEVICE_PATH,MSG_IPv4_DP) && | |
703 | !IS_DEVICE_PATH_NODE(RemainingDevicePath,MESSAGING_DEVICE_PATH,MSG_IPv6_DP)) { | |
704 | return FALSE; | |
705 | } | |
706 | NextDevicePath = NextDevicePathNode (RemainingDevicePath); | |
707 | if (IsDevicePathEnd(NextDevicePath)) { | |
708 | return FALSE; | |
709 | } | |
710 | if (!IS_DEVICE_PATH_NODE(NextDevicePath,MEDIA_DEVICE_PATH,MEDIA_FILEPATH_DP)) { | |
711 | return FALSE; | |
712 | } | |
713 | ||
714 | Status = gBS->HandleProtocol (Handle, &gEfiPxeBaseCodeProtocolGuid, (VOID **)&PxeBcProtocol); | |
715 | if (EFI_ERROR (Status)) { | |
716 | return FALSE; | |
717 | } else { | |
718 | return TRUE; | |
719 | } | |
720 | } | |
721 | ||
722 | EFI_STATUS | |
723 | BdsTftpLoadImage ( | |
724 | IN EFI_DEVICE_PATH* DevicePath, | |
725 | IN EFI_HANDLE Handle, | |
726 | IN EFI_DEVICE_PATH* RemainingDevicePath, | |
727 | IN EFI_ALLOCATE_TYPE Type, | |
728 | IN OUT EFI_PHYSICAL_ADDRESS *Image, | |
729 | OUT UINTN *ImageSize | |
730 | ) | |
731 | { | |
732 | EFI_STATUS Status; | |
733 | EFI_PXE_BASE_CODE_PROTOCOL *Pxe; | |
734 | UINT64 TftpBufferSize; | |
735 | VOID* TftpBuffer; | |
736 | EFI_IP_ADDRESS ServerIp; | |
737 | IPv4_DEVICE_PATH* IPv4DevicePathNode; | |
738 | FILEPATH_DEVICE_PATH* FilePathDevicePath; | |
739 | EFI_IP_ADDRESS LocalIp; | |
740 | ||
741 | ASSERT(IS_DEVICE_PATH_NODE(RemainingDevicePath,MESSAGING_DEVICE_PATH,MSG_IPv4_DP)); | |
742 | ||
743 | IPv4DevicePathNode = (IPv4_DEVICE_PATH*)RemainingDevicePath; | |
744 | FilePathDevicePath = (FILEPATH_DEVICE_PATH*)(IPv4DevicePathNode + 1); | |
745 | ||
746 | Status = gBS->LocateProtocol (&gEfiPxeBaseCodeProtocolGuid, NULL, (VOID **)&Pxe); | |
747 | if (EFI_ERROR(Status)) { | |
748 | return Status; | |
749 | } | |
750 | ||
751 | Status = Pxe->Start (Pxe, FALSE); | |
752 | if (EFI_ERROR(Status) && (Status != EFI_ALREADY_STARTED)) { | |
753 | return Status; | |
754 | } | |
755 | ||
756 | if (!IPv4DevicePathNode->StaticIpAddress) { | |
757 | Status = Pxe->Dhcp(Pxe, TRUE); | |
758 | } else { | |
759 | CopyMem (&LocalIp.v4, &IPv4DevicePathNode->LocalIpAddress, sizeof (EFI_IPv4_ADDRESS)); | |
760 | Status = Pxe->SetStationIp (Pxe, &LocalIp, NULL); | |
761 | } | |
762 | if (EFI_ERROR(Status)) { | |
763 | return Status; | |
764 | } | |
765 | ||
766 | CopyMem (&ServerIp.v4, &IPv4DevicePathNode->RemoteIpAddress, sizeof (EFI_IPv4_ADDRESS)); | |
767 | ||
768 | Status = Pxe->Mtftp ( | |
769 | Pxe, | |
770 | EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE, | |
771 | NULL, | |
772 | FALSE, | |
773 | &TftpBufferSize, | |
774 | NULL, | |
775 | &ServerIp, | |
776 | (UINT8 *)FilePathDevicePath->PathName, | |
777 | NULL, | |
778 | TRUE | |
779 | ); | |
780 | if (EFI_ERROR(Status)) { | |
781 | return Status; | |
782 | } | |
783 | ||
784 | // Allocate a buffer to hold the whole file. | |
785 | TftpBuffer = AllocatePool(TftpBufferSize); | |
786 | if (TftpBuffer == NULL) { | |
787 | return EFI_OUT_OF_RESOURCES; | |
788 | } | |
789 | ||
790 | Status = Pxe->Mtftp ( | |
791 | Pxe, | |
792 | EFI_PXE_BASE_CODE_TFTP_READ_FILE, | |
793 | TftpBuffer, | |
794 | FALSE, | |
795 | &TftpBufferSize, | |
796 | NULL, | |
797 | &ServerIp, | |
798 | (UINT8 *)FilePathDevicePath->PathName, | |
799 | NULL, | |
800 | FALSE | |
801 | ); | |
802 | if (EFI_ERROR(Status)) { | |
803 | FreePool(TftpBuffer); | |
804 | } else if (ImageSize != NULL) { | |
805 | *ImageSize = (UINTN)TftpBufferSize; | |
806 | } | |
807 | ||
808 | return Status; | |
809 | } | |
810 | ||
811 | BDS_FILE_LOADER FileLoaders[] = { | |
812 | { BdsFileSystemSupport, BdsFileSystemLoadImage }, | |
813 | { BdsFirmwareVolumeSupport, BdsFirmwareVolumeLoadImage }, | |
814 | //{ BdsLoadFileSupport, BdsLoadFileLoadImage }, | |
815 | { BdsMemoryMapSupport, BdsMemoryMapLoadImage }, | |
816 | { BdsPxeSupport, BdsPxeLoadImage }, | |
817 | { BdsTftpSupport, BdsTftpLoadImage }, | |
818 | { NULL, NULL } | |
819 | }; | |
820 | ||
821 | EFI_STATUS | |
822 | BdsLoadImage ( | |
823 | IN EFI_DEVICE_PATH *DevicePath, | |
824 | IN EFI_ALLOCATE_TYPE Type, | |
825 | IN OUT EFI_PHYSICAL_ADDRESS* Image, | |
826 | OUT UINTN *FileSize | |
827 | ) | |
828 | { | |
829 | EFI_STATUS Status; | |
830 | EFI_HANDLE Handle; | |
831 | EFI_DEVICE_PATH *RemainingDevicePath; | |
832 | BDS_FILE_LOADER* FileLoader; | |
833 | ||
834 | Status = BdsConnectDevicePath (DevicePath, &Handle, &RemainingDevicePath); | |
835 | if (EFI_ERROR (Status)) { | |
836 | return Status; | |
837 | } | |
838 | ||
839 | FileLoader = FileLoaders; | |
840 | while (FileLoader->Support != NULL) { | |
841 | if (FileLoader->Support (DevicePath, Handle, RemainingDevicePath)) { | |
842 | return FileLoader->LoadImage (DevicePath, Handle, RemainingDevicePath, Type, Image, FileSize); | |
843 | } | |
844 | FileLoader++; | |
845 | } | |
846 | ||
847 | return EFI_UNSUPPORTED; | |
848 | } | |
849 | ||
6bab33c7 | 850 | /** |
851 | Start an EFI Application from a Device Path | |
852 | ||
853 | @param ParentImageHandle Handle of the calling image | |
854 | @param DevicePath Location of the EFI Application | |
855 | ||
856 | @retval EFI_SUCCESS All drivers have been connected | |
857 | @retval EFI_NOT_FOUND The Linux kernel Device Path has not been found | |
858 | @retval EFI_OUT_OF_RESOURCES There is not enough resource memory to store the matching results. | |
859 | ||
860 | **/ | |
a355a365 | 861 | EFI_STATUS |
862 | BdsStartEfiApplication ( | |
863 | IN EFI_HANDLE ParentImageHandle, | |
2755d844 | 864 | IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, |
865 | IN UINTN LoadOptionsSize, | |
866 | IN VOID* LoadOptions | |
a355a365 | 867 | ) |
868 | { | |
869 | EFI_STATUS Status; | |
870 | EFI_HANDLE ImageHandle; | |
871 | EFI_PHYSICAL_ADDRESS BinaryBuffer; | |
872 | UINTN BinarySize; | |
2755d844 | 873 | EFI_LOADED_IMAGE_PROTOCOL* LoadedImage; |
a355a365 | 874 | |
875 | // Find the nearest supported file loader | |
2755d844 | 876 | Status = BdsLoadImage (DevicePath, AllocateAnyPages, &BinaryBuffer, &BinarySize); |
a355a365 | 877 | if (EFI_ERROR(Status)) { |
878 | return Status; | |
879 | } | |
880 | ||
881 | // Load the image from the Buffer with Boot Services function | |
882 | Status = gBS->LoadImage (TRUE, ParentImageHandle, DevicePath, (VOID*)(UINTN)BinaryBuffer, BinarySize, &ImageHandle); | |
883 | if (EFI_ERROR(Status)) { | |
884 | return Status; | |
885 | } | |
886 | ||
2755d844 | 887 | // Passed LoadOptions to the EFI Application |
888 | if (LoadOptionsSize != 0) { | |
889 | Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &LoadedImage); | |
890 | if (EFI_ERROR(Status)) { | |
891 | return Status; | |
892 | } | |
893 | ||
894 | LoadedImage->LoadOptionsSize = LoadOptionsSize; | |
895 | LoadedImage->LoadOptions = LoadOptions; | |
896 | } | |
897 | ||
a355a365 | 898 | // Before calling the image, enable the Watchdog Timer for the 5 Minute period |
899 | gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL); | |
900 | // Start the image | |
901 | Status = gBS->StartImage (ImageHandle, NULL, NULL); | |
902 | // Clear the Watchdog Timer after the image returns | |
903 | gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL); | |
904 | ||
905 | return Status; | |
1bfda055 | 906 | } |