]> git.proxmox.com Git - mirror_edk2.git/blame - ArmPkg/Library/BdsLib/BdsFilePath.c
ArmPlatformPkg/Bds: Fix various bugs in the new BDS
[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
e862cd50 267 RemovableDevice = NULL;
268 RemovableDevicePath = NULL;
269 RemovableFound = FALSE;
270 TmpDevicePath = DevicePath;
271
a355a365 272 while (!IsDevicePathEnd (TmpDevicePath) && !RemovableFound) {
273 for (Index = 0; Index < sizeof(RemovableDeviceSupport) / sizeof(BDS_REMOVABLE_DEVICE_SUPPORT); Index++) {
274 RemovableDevice = &RemovableDeviceSupport[Index];
275 if (RemovableDevice->IsRemovable(TmpDevicePath)) {
276 RemovableDevicePath = TmpDevicePath;
277 RemovableFound = TRUE;
278 break;
279 }
1bfda055 280 }
a355a365 281 TmpDevicePath = NextDevicePathNode (TmpDevicePath);
282 }
1bfda055 283
a355a365 284 if (!RemovableFound) {
285 return EFI_NOT_FOUND;
286 }
1bfda055 287
a355a365 288 // Search into the current started drivers
289 Status = RemovableDevice->GetDevice (RemovableDevicePath, DeviceHandle, NewDevicePath);
290 if (Status == EFI_NOT_FOUND) {
291 // Connect all the drivers
292 BdsConnectAllDrivers ();
293
294 // Search again into all the drivers
295 Status = RemovableDevice->GetDevice (RemovableDevicePath, DeviceHandle, NewDevicePath);
296 }
297
298 return Status;
299}
300
6bab33c7 301/**
302 Connect a Device Path and return the handle of the driver that support this DevicePath
303
304 @param DevicePath Device Path of the File to connect
305 @param Handle Handle of the driver that support this DevicePath
306 @param RemainingDevicePath Remaining DevicePath nodes that do not match the driver DevicePath
307
308 @retval EFI_SUCCESS A driver that matches the Device Path has been found
309 @retval EFI_NOT_FOUND No handles match the search.
310 @retval EFI_INVALID_PARAMETER DevicePath or Handle is NULL
311
312**/
a355a365 313EFI_STATUS
314BdsConnectDevicePath (
315 IN EFI_DEVICE_PATH_PROTOCOL* DevicePath,
316 OUT EFI_HANDLE *Handle,
317 OUT EFI_DEVICE_PATH_PROTOCOL **RemainingDevicePath
318 )
319{
320 EFI_DEVICE_PATH* Remaining;
321 EFI_DEVICE_PATH* NewDevicePath;
322 EFI_STATUS Status;
323
324 if ((DevicePath == NULL) || (Handle == NULL)) {
325 return EFI_INVALID_PARAMETER;
326 }
327
328 do {
329 Remaining = DevicePath;
330 // The LocateDevicePath() function locates all devices on DevicePath that support Protocol and returns
331 // the handle to the device that is closest to DevicePath. On output, the device path pointer is modified
332 // to point to the remaining part of the device path
333 Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &Remaining, Handle);
334 if (!EFI_ERROR (Status)) {
335 // Recursive = FALSE: We do not want to start all the device tree
336 Status = gBS->ConnectController (*Handle, NULL, Remaining, FALSE);
1bfda055 337 }
338
a355a365 339 /*// We need to check if RemainingDevicePath does not point on the last node. Otherwise, calling
340 // NextDevicePathNode() will return an undetermined Device Path Node
341 if (!IsDevicePathEnd (RemainingDevicePath)) {
342 RemainingDevicePath = NextDevicePathNode (RemainingDevicePath);
343 }*/
344 } while (!EFI_ERROR (Status) && !IsDevicePathEnd (Remaining));
345
346 if (!EFI_ERROR (Status)) {
347 // Now, we have got the whole Device Path connected, call again ConnectController to ensure all the supported Driver
348 // Binding Protocol are connected (such as DiskIo and SimpleFileSystem)
349 Remaining = DevicePath;
6bab33c7 350 Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid,&Remaining,Handle);
a355a365 351 if (!EFI_ERROR (Status)) {
352 Status = gBS->ConnectController (*Handle, NULL, Remaining, FALSE);
353 if (EFI_ERROR (Status)) {
354 // If the last node is a Memory Map Device Path just return EFI_SUCCESS.
355 if ((Remaining->Type == HARDWARE_DEVICE_PATH) && (Remaining->SubType == HW_MEMMAP_DP)) {
356 Status = EFI_SUCCESS;
1bfda055 357 }
a355a365 358 }
1bfda055 359 }
a355a365 360 } else if (!IsDevicePathEnd (Remaining) && !IsRemovableDevice (Remaining)) {
361
362 /*// If the remaining Device Path is a FilePath or MemoryMap then we consider the Device Path has been loaded correctly
363 if ((Remaining->Type == MEDIA_DEVICE_PATH) && (Remaining->SubType == MEDIA_FILEPATH_DP)) {
364 Status = EFI_SUCCESS;
365 } else if ((Remaining->Type == HARDWARE_DEVICE_PATH) && (Remaining->SubType == HW_MEMMAP_DP)) {
366 Status = EFI_SUCCESS;
367 }*/
1bfda055 368
a355a365 369 //TODO: Should we just return success and leave the caller decide if it is the expected RemainingPath
370 Status = EFI_SUCCESS;
371 } else {
372 Status = TryRemovableDevice (DevicePath, Handle, &NewDevicePath);
1bfda055 373 if (!EFI_ERROR (Status)) {
a355a365 374 return BdsConnectDevicePath (NewDevicePath, Handle, RemainingDevicePath);
375 }
376 }
377
378 if (RemainingDevicePath) {
379 *RemainingDevicePath = Remaining;
380 }
381
382 return Status;
383}
384
385BOOLEAN
386BdsFileSystemSupport (
387 IN EFI_DEVICE_PATH *DevicePath,
388 IN EFI_HANDLE Handle,
389 IN EFI_DEVICE_PATH *RemainingDevicePath
390 )
391{
392 EFI_STATUS Status;
393 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FsProtocol;
394
395 Status = gBS->HandleProtocol (Handle,&gEfiSimpleFileSystemProtocolGuid, (VOID **)&FsProtocol);
396
397 return (!EFI_ERROR(Status) && IS_DEVICE_PATH_NODE(RemainingDevicePath,MEDIA_DEVICE_PATH,MEDIA_FILEPATH_DP));
398}
399
400EFI_STATUS
401BdsFileSystemLoadImage (
402 IN EFI_DEVICE_PATH *DevicePath,
403 IN EFI_HANDLE Handle,
404 IN EFI_DEVICE_PATH *RemainingDevicePath,
405 IN EFI_ALLOCATE_TYPE Type,
406 IN OUT EFI_PHYSICAL_ADDRESS* Image,
407 OUT UINTN *ImageSize
408 )
409{
410 FILEPATH_DEVICE_PATH* FilePathDevicePath;
411 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FsProtocol;
412 EFI_FILE_PROTOCOL *Fs;
413 EFI_STATUS Status;
414 EFI_FILE_INFO *FileInfo;
415 EFI_FILE_PROTOCOL *File;
416 UINTN Size;
417
418 ASSERT (IS_DEVICE_PATH_NODE(RemainingDevicePath,MEDIA_DEVICE_PATH,MEDIA_FILEPATH_DP));
419
420 FilePathDevicePath = (FILEPATH_DEVICE_PATH*)RemainingDevicePath;
421
422 Status = gBS->HandleProtocol(Handle,&gEfiSimpleFileSystemProtocolGuid, (VOID **)&FsProtocol);
423 if (EFI_ERROR(Status)) {
424 return Status;
425 }
426
427 //Try to Open the volume and get root directory
428 Status = FsProtocol->OpenVolume (FsProtocol, &Fs);
429 if (EFI_ERROR(Status)) {
430 return Status;
431 }
432
433 File = NULL;
434 Status = Fs->Open(Fs, &File, FilePathDevicePath->PathName, EFI_FILE_MODE_READ, 0);
6bab33c7 435 if (EFI_ERROR(Status)) {
436 return Status;
437 }
a355a365 438
439 Size = 0;
440 File->GetInfo(File, &gEfiFileInfoGuid, &Size, NULL);
441 FileInfo = AllocatePool (Size);
442 Status = File->GetInfo(File, &gEfiFileInfoGuid, &Size, FileInfo);
443 if (EFI_ERROR(Status)) {
444 return Status;
445 }
446
447 // Get the file size
448 Size = FileInfo->FileSize;
449 if (ImageSize) {
450 *ImageSize = Size;
451 }
452 FreePool(FileInfo);
453
454 Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(Size),Image);
455 if (!EFI_ERROR(Status)) {
456 Status = File->Read (File, &Size, (VOID*)(UINTN)(*Image));
457 }
458
459 return Status;
460}
461
462BOOLEAN
463BdsMemoryMapSupport (
464 IN EFI_DEVICE_PATH *DevicePath,
465 IN EFI_HANDLE Handle,
466 IN EFI_DEVICE_PATH *RemainingDevicePath
467 )
468{
469 return IS_DEVICE_PATH_NODE(RemainingDevicePath,HARDWARE_DEVICE_PATH,HW_MEMMAP_DP);
470}
471
472EFI_STATUS
473BdsMemoryMapLoadImage (
474 IN EFI_DEVICE_PATH *DevicePath,
475 IN EFI_HANDLE Handle,
476 IN EFI_DEVICE_PATH *RemainingDevicePath,
477 IN EFI_ALLOCATE_TYPE Type,
478 IN OUT EFI_PHYSICAL_ADDRESS* Image,
479 OUT UINTN *ImageSize
480 )
481{
482 EFI_STATUS Status;
483 MEMMAP_DEVICE_PATH* MemMapPathDevicePath;
484 UINTN Size;
485
486 ASSERT (IS_DEVICE_PATH_NODE(RemainingDevicePath,HARDWARE_DEVICE_PATH,HW_MEMMAP_DP));
487
488 MemMapPathDevicePath = (MEMMAP_DEVICE_PATH*)RemainingDevicePath;
489
490 Size = MemMapPathDevicePath->EndingAddress - MemMapPathDevicePath->StartingAddress;
491 if (Size == 0) {
492 return EFI_INVALID_PARAMETER;
493 }
494
495 Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(Size),Image);
496 if (!EFI_ERROR(Status)) {
497 CopyMem ((VOID*)(UINTN)(*Image), (CONST VOID*)(UINTN)MemMapPathDevicePath->StartingAddress, Size);
498
499 if (ImageSize != NULL) {
500 *ImageSize = Size;
1bfda055 501 }
a355a365 502 }
1bfda055 503
a355a365 504 return Status;
505}
506
507BOOLEAN
508BdsFirmwareVolumeSupport (
509 IN EFI_DEVICE_PATH *DevicePath,
510 IN EFI_HANDLE Handle,
511 IN EFI_DEVICE_PATH *RemainingDevicePath
512 )
513{
514 return IS_DEVICE_PATH_NODE(RemainingDevicePath, MEDIA_DEVICE_PATH, MEDIA_PIWG_FW_FILE_DP);
515}
516
517EFI_STATUS
518BdsFirmwareVolumeLoadImage (
519 IN EFI_DEVICE_PATH *DevicePath,
520 IN EFI_HANDLE Handle,
521 IN EFI_DEVICE_PATH *RemainingDevicePath,
522 IN EFI_ALLOCATE_TYPE Type,
523 IN OUT EFI_PHYSICAL_ADDRESS* Image,
524 OUT UINTN *ImageSize
525 )
526{
527 EFI_STATUS Status;
528 EFI_FIRMWARE_VOLUME2_PROTOCOL *FwVol;
529 EFI_GUID *FvNameGuid;
530 EFI_SECTION_TYPE SectionType;
531 EFI_FV_FILETYPE FvType;
532 EFI_FV_FILE_ATTRIBUTES Attrib;
533 UINT32 AuthenticationStatus;
534 VOID* ImageBuffer;
535
536 ASSERT (IS_DEVICE_PATH_NODE(RemainingDevicePath, MEDIA_DEVICE_PATH, MEDIA_PIWG_FW_FILE_DP));
537
538 Status = gBS->HandleProtocol(Handle,&gEfiFirmwareVolume2ProtocolGuid, (VOID **)&FwVol);
539 if (EFI_ERROR(Status)) {
1bfda055 540 return Status;
a355a365 541 }
542
543 FvNameGuid = EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)RemainingDevicePath);
544 if (FvNameGuid == NULL) {
545 Status = EFI_INVALID_PARAMETER;
546 }
547
548 SectionType = EFI_SECTION_PE32;
549 AuthenticationStatus = 0;
550 //Note: ReadSection at the opposite of ReadFile does not allow to pass ImageBuffer == NULL to get the size of the file.
551 ImageBuffer = NULL;
552 Status = FwVol->ReadSection (
553 FwVol,
554 FvNameGuid,
555 SectionType,
556 0,
557 &ImageBuffer,
558 ImageSize,
559 &AuthenticationStatus
560 );
561 if (!EFI_ERROR (Status)) {
562#if 0
563 // In case the buffer has some address requirements, we must copy the buffer to a buffer following the requirements
564 if (Type != AllocateAnyPages) {
565 Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize),Image);
566 if (!EFI_ERROR(Status)) {
567 CopyMem ((VOID*)(UINTN)(*Image), ImageBuffer, *ImageSize);
568 FreePool (ImageBuffer);
569 }
570 }
571#else
572 // We must copy the buffer into a page allocations. Otherwise, the caller could call gBS->FreePages() on the pool allocation
573 Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize), Image);
574 if (!EFI_ERROR(Status)) {
575 CopyMem ((VOID*)(UINTN)(*Image), ImageBuffer, *ImageSize);
576 FreePool (ImageBuffer);
577 }
578#endif
579 } else {
580 // Try a raw file, since a PE32 SECTION does not exist
581 Status = FwVol->ReadFile (
582 FwVol,
583 FvNameGuid,
584 NULL,
585 ImageSize,
586 &FvType,
587 &Attrib,
588 &AuthenticationStatus
589 );
590 if (!EFI_ERROR(Status)) {
591 Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize),Image);
592 if (!EFI_ERROR(Status)) {
593 Status = FwVol->ReadFile (
594 FwVol,
595 FvNameGuid,
596 (VOID*)(UINTN)(*Image),
597 ImageSize,
598 &FvType,
599 &Attrib,
600 &AuthenticationStatus
601 );
602 }
603 }
604 }
605 return Status;
1bfda055 606}
607
a355a365 608BOOLEAN
609BdsPxeSupport (
610 IN EFI_DEVICE_PATH* DevicePath,
611 IN EFI_HANDLE Handle,
612 IN EFI_DEVICE_PATH* RemainingDevicePath
613 )
614{
615 EFI_STATUS Status;
616 EFI_PXE_BASE_CODE_PROTOCOL* PxeBcProtocol;
617
618 if (!IsDevicePathEnd(RemainingDevicePath)) {
619 return FALSE;
620 }
621
622 Status = gBS->HandleProtocol (Handle, &gEfiPxeBaseCodeProtocolGuid, (VOID **)&PxeBcProtocol);
623 if (EFI_ERROR (Status)) {
624 return FALSE;
625 } else {
626 return TRUE;
627 }
628}
629
630EFI_STATUS
631BdsPxeLoadImage (
632 IN EFI_DEVICE_PATH* DevicePath,
633 IN EFI_HANDLE Handle,
634 IN EFI_DEVICE_PATH* RemainingDevicePath,
635 IN EFI_ALLOCATE_TYPE Type,
636 IN OUT EFI_PHYSICAL_ADDRESS *Image,
637 OUT UINTN *ImageSize
638 )
639{
640 EFI_STATUS Status;
641 EFI_LOAD_FILE_PROTOCOL *LoadFileProtocol;
642 UINTN BufferSize;
643
644 // Get Load File Protocol attached to the PXE protocol
645 Status = gBS->HandleProtocol (Handle, &gEfiLoadFileProtocolGuid, (VOID **)&LoadFileProtocol);
646 if (EFI_ERROR (Status)) {
647 return Status;
648 }
649
650 Status = LoadFileProtocol->LoadFile (LoadFileProtocol, DevicePath, TRUE, &BufferSize, NULL);
651 if (Status == EFI_BUFFER_TOO_SMALL) {
652 Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(BufferSize), Image);
653 if (EFI_ERROR(Status)) {
654 return Status;
1bfda055 655 }
656
a355a365 657 Status = LoadFileProtocol->LoadFile (LoadFileProtocol, DevicePath, TRUE, &BufferSize, (VOID*)(UINTN)(*Image));
658 if (!EFI_ERROR(Status) && (ImageSize != NULL)) {
659 *ImageSize = BufferSize;
1bfda055 660 }
a355a365 661 }
662
663 return Status;
664}
665
666BOOLEAN
667BdsTftpSupport (
668 IN EFI_DEVICE_PATH* DevicePath,
669 IN EFI_HANDLE Handle,
670 IN EFI_DEVICE_PATH* RemainingDevicePath
671 )
672{
673 EFI_STATUS Status;
674 EFI_DEVICE_PATH *NextDevicePath;
675 EFI_PXE_BASE_CODE_PROTOCOL *PxeBcProtocol;
676
677 // Validate the Remaining Device Path
678 if (IsDevicePathEnd(RemainingDevicePath)) {
679 return FALSE;
680 }
681 if (!IS_DEVICE_PATH_NODE(RemainingDevicePath,MESSAGING_DEVICE_PATH,MSG_IPv4_DP) &&
682 !IS_DEVICE_PATH_NODE(RemainingDevicePath,MESSAGING_DEVICE_PATH,MSG_IPv6_DP)) {
683 return FALSE;
684 }
685 NextDevicePath = NextDevicePathNode (RemainingDevicePath);
686 if (IsDevicePathEnd(NextDevicePath)) {
687 return FALSE;
688 }
689 if (!IS_DEVICE_PATH_NODE(NextDevicePath,MEDIA_DEVICE_PATH,MEDIA_FILEPATH_DP)) {
690 return FALSE;
691 }
692
693 Status = gBS->HandleProtocol (Handle, &gEfiPxeBaseCodeProtocolGuid, (VOID **)&PxeBcProtocol);
694 if (EFI_ERROR (Status)) {
695 return FALSE;
696 } else {
697 return TRUE;
698 }
699}
700
701EFI_STATUS
702BdsTftpLoadImage (
703 IN EFI_DEVICE_PATH* DevicePath,
704 IN EFI_HANDLE Handle,
705 IN EFI_DEVICE_PATH* RemainingDevicePath,
706 IN EFI_ALLOCATE_TYPE Type,
707 IN OUT EFI_PHYSICAL_ADDRESS *Image,
708 OUT UINTN *ImageSize
709 )
710{
711 EFI_STATUS Status;
712 EFI_PXE_BASE_CODE_PROTOCOL *Pxe;
713 UINT64 TftpBufferSize;
714 VOID* TftpBuffer;
715 EFI_IP_ADDRESS ServerIp;
716 IPv4_DEVICE_PATH* IPv4DevicePathNode;
717 FILEPATH_DEVICE_PATH* FilePathDevicePath;
718 EFI_IP_ADDRESS LocalIp;
719
720 ASSERT(IS_DEVICE_PATH_NODE(RemainingDevicePath,MESSAGING_DEVICE_PATH,MSG_IPv4_DP));
721
722 IPv4DevicePathNode = (IPv4_DEVICE_PATH*)RemainingDevicePath;
723 FilePathDevicePath = (FILEPATH_DEVICE_PATH*)(IPv4DevicePathNode + 1);
724
725 Status = gBS->LocateProtocol (&gEfiPxeBaseCodeProtocolGuid, NULL, (VOID **)&Pxe);
726 if (EFI_ERROR(Status)) {
727 return Status;
728 }
729
730 Status = Pxe->Start (Pxe, FALSE);
731 if (EFI_ERROR(Status) && (Status != EFI_ALREADY_STARTED)) {
732 return Status;
733 }
734
735 if (!IPv4DevicePathNode->StaticIpAddress) {
736 Status = Pxe->Dhcp(Pxe, TRUE);
737 } else {
738 CopyMem (&LocalIp.v4, &IPv4DevicePathNode->LocalIpAddress, sizeof (EFI_IPv4_ADDRESS));
739 Status = Pxe->SetStationIp (Pxe, &LocalIp, NULL);
740 }
741 if (EFI_ERROR(Status)) {
742 return Status;
743 }
744
745 CopyMem (&ServerIp.v4, &IPv4DevicePathNode->RemoteIpAddress, sizeof (EFI_IPv4_ADDRESS));
746
747 Status = Pxe->Mtftp (
748 Pxe,
749 EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE,
750 NULL,
751 FALSE,
752 &TftpBufferSize,
753 NULL,
754 &ServerIp,
755 (UINT8 *)FilePathDevicePath->PathName,
756 NULL,
757 TRUE
758 );
759 if (EFI_ERROR(Status)) {
760 return Status;
761 }
762
763 // Allocate a buffer to hold the whole file.
764 TftpBuffer = AllocatePool(TftpBufferSize);
765 if (TftpBuffer == NULL) {
766 return EFI_OUT_OF_RESOURCES;
767 }
768
769 Status = Pxe->Mtftp (
770 Pxe,
771 EFI_PXE_BASE_CODE_TFTP_READ_FILE,
772 TftpBuffer,
773 FALSE,
774 &TftpBufferSize,
775 NULL,
776 &ServerIp,
777 (UINT8 *)FilePathDevicePath->PathName,
778 NULL,
779 FALSE
780 );
781 if (EFI_ERROR(Status)) {
782 FreePool(TftpBuffer);
783 } else if (ImageSize != NULL) {
784 *ImageSize = (UINTN)TftpBufferSize;
785 }
786
787 return Status;
788}
789
790BDS_FILE_LOADER FileLoaders[] = {
791 { BdsFileSystemSupport, BdsFileSystemLoadImage },
792 { BdsFirmwareVolumeSupport, BdsFirmwareVolumeLoadImage },
793 //{ BdsLoadFileSupport, BdsLoadFileLoadImage },
794 { BdsMemoryMapSupport, BdsMemoryMapLoadImage },
795 { BdsPxeSupport, BdsPxeLoadImage },
796 { BdsTftpSupport, BdsTftpLoadImage },
797 { NULL, NULL }
798};
799
800EFI_STATUS
801BdsLoadImage (
802 IN EFI_DEVICE_PATH *DevicePath,
803 IN EFI_ALLOCATE_TYPE Type,
804 IN OUT EFI_PHYSICAL_ADDRESS* Image,
805 OUT UINTN *FileSize
806 )
807{
808 EFI_STATUS Status;
809 EFI_HANDLE Handle;
810 EFI_DEVICE_PATH *RemainingDevicePath;
811 BDS_FILE_LOADER* FileLoader;
812
813 Status = BdsConnectDevicePath (DevicePath, &Handle, &RemainingDevicePath);
814 if (EFI_ERROR (Status)) {
815 return Status;
816 }
817
818 FileLoader = FileLoaders;
819 while (FileLoader->Support != NULL) {
820 if (FileLoader->Support (DevicePath, Handle, RemainingDevicePath)) {
821 return FileLoader->LoadImage (DevicePath, Handle, RemainingDevicePath, Type, Image, FileSize);
822 }
823 FileLoader++;
824 }
825
826 return EFI_UNSUPPORTED;
827}
828
6bab33c7 829/**
830 Start an EFI Application from a Device Path
831
832 @param ParentImageHandle Handle of the calling image
833 @param DevicePath Location of the EFI Application
834
835 @retval EFI_SUCCESS All drivers have been connected
836 @retval EFI_NOT_FOUND The Linux kernel Device Path has not been found
837 @retval EFI_OUT_OF_RESOURCES There is not enough resource memory to store the matching results.
838
839**/
a355a365 840EFI_STATUS
841BdsStartEfiApplication (
842 IN EFI_HANDLE ParentImageHandle,
843 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
844 )
845{
846 EFI_STATUS Status;
847 EFI_HANDLE ImageHandle;
848 EFI_PHYSICAL_ADDRESS BinaryBuffer;
849 UINTN BinarySize;
850
851 // Find the nearest supported file loader
852 Status = BdsLoadImage (DevicePath, AllocateAnyPages,&BinaryBuffer,&BinarySize);
853 if (EFI_ERROR(Status)) {
854 return Status;
855 }
856
857 // Load the image from the Buffer with Boot Services function
858 Status = gBS->LoadImage (TRUE, ParentImageHandle, DevicePath, (VOID*)(UINTN)BinaryBuffer, BinarySize, &ImageHandle);
859 if (EFI_ERROR(Status)) {
860 return Status;
861 }
862
863 // Before calling the image, enable the Watchdog Timer for the 5 Minute period
864 gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);
865 // Start the image
866 Status = gBS->StartImage (ImageHandle, NULL, NULL);
867 // Clear the Watchdog Timer after the image returns
868 gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);
869
870 return Status;
1bfda055 871}