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