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