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