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