]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPkg/Library/BdsLib/BdsFilePath.c
ArmPkg/BdsLib: Upgrade the library to use natively the Device Path
[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 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 }
277 }
278 TmpDevicePath = NextDevicePathNode (TmpDevicePath);
279 }
280
281 if (!RemovableFound) {
282 return EFI_NOT_FOUND;
283 }
284
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
298 EFI_STATUS
299 BdsConnectDevicePath (
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);
322 }
323
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;
342 }
343 }
344 }
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 }*/
353
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);
358 if (!EFI_ERROR (Status)) {
359 return BdsConnectDevicePath (NewDevicePath, Handle, RemainingDevicePath);
360 }
361 }
362
363 if (RemainingDevicePath) {
364 *RemainingDevicePath = Remaining;
365 }
366
367 return Status;
368 }
369
370 BOOLEAN
371 BdsFileSystemSupport (
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
385 EFI_STATUS
386 BdsFileSystemLoadImage (
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
444 BOOLEAN
445 BdsMemoryMapSupport (
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
454 EFI_STATUS
455 BdsMemoryMapLoadImage (
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;
483 }
484 }
485
486 return Status;
487 }
488
489 BOOLEAN
490 BdsFirmwareVolumeSupport (
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
499 EFI_STATUS
500 BdsFirmwareVolumeLoadImage (
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)) {
522 return Status;
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;
588 }
589
590 BOOLEAN
591 BdsPxeSupport (
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
612 EFI_STATUS
613 BdsPxeLoadImage (
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;
637 }
638
639 Status = LoadFileProtocol->LoadFile (LoadFileProtocol, DevicePath, TRUE, &BufferSize, (VOID*)(UINTN)(*Image));
640 if (!EFI_ERROR(Status) && (ImageSize != NULL)) {
641 *ImageSize = BufferSize;
642 }
643 }
644
645 return Status;
646 }
647
648 BOOLEAN
649 BdsTftpSupport (
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
683 EFI_STATUS
684 BdsTftpLoadImage (
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
772 BDS_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
782 EFI_STATUS
783 BdsLoadImage (
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
811 EFI_STATUS
812 BdsStartEfiApplication (
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;
842 }