]>
Commit | Line | Data |
---|---|---|
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 | |
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++; | |
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 | 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 | } | |
1bfda055 | 118 | } |
a355a365 | 119 | TmpDevicePath = NextDevicePathNode (TmpDevicePath); |
120 | } | |
1bfda055 | 121 | |
1bfda055 | 122 | } |
a355a365 | 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); | |
1bfda055 | 134 | } |
135 | ||
136 | EFI_STATUS | |
a355a365 | 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; | |
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 |
189 | BdsIsRemovableCdrom ( | |
190 | IN EFI_DEVICE_PATH* DevicePath | |
191 | ) | |
192 | { | |
193 | return IS_DEVICE_PATH_NODE(DevicePath, MEDIA_DEVICE_PATH, MEDIA_CDROM_DP); | |
194 | } | |
1bfda055 | 195 | |
196 | EFI_STATUS | |
a355a365 | 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 | } | |
1bfda055 | 245 | } |
a355a365 | 246 | TmpDevicePath = NextDevicePathNode (TmpDevicePath); |
247 | } | |
248 | ||
249 | return FALSE; | |
250 | } | |
1bfda055 | 251 | |
a355a365 | 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; | |
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 | 313 | EFI_STATUS |
314 | BdsConnectDevicePath ( | |
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 | ||
385 | BOOLEAN | |
386 | BdsFileSystemSupport ( | |
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 | ||
400 | EFI_STATUS | |
401 | BdsFileSystemLoadImage ( | |
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 | ||
bd54c237 | 427 | // Try to Open the volume and get root directory |
a355a365 | 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 | ||
bd54c237 | 454 | Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(Size), Image); |
455 | // Try to allocate in any pages if failed to allocate memory at the defined location | |
456 | if ((Status == EFI_OUT_OF_RESOURCES) && (Type != AllocateAnyPages)) { | |
457 | Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesCode, EFI_SIZE_TO_PAGES(Size), Image); | |
458 | } | |
a355a365 | 459 | if (!EFI_ERROR(Status)) { |
460 | Status = File->Read (File, &Size, (VOID*)(UINTN)(*Image)); | |
461 | } | |
462 | ||
463 | return Status; | |
464 | } | |
465 | ||
466 | BOOLEAN | |
467 | BdsMemoryMapSupport ( | |
468 | IN EFI_DEVICE_PATH *DevicePath, | |
469 | IN EFI_HANDLE Handle, | |
470 | IN EFI_DEVICE_PATH *RemainingDevicePath | |
471 | ) | |
472 | { | |
473 | return IS_DEVICE_PATH_NODE(RemainingDevicePath,HARDWARE_DEVICE_PATH,HW_MEMMAP_DP); | |
474 | } | |
475 | ||
476 | EFI_STATUS | |
477 | BdsMemoryMapLoadImage ( | |
478 | IN EFI_DEVICE_PATH *DevicePath, | |
479 | IN EFI_HANDLE Handle, | |
480 | IN EFI_DEVICE_PATH *RemainingDevicePath, | |
481 | IN EFI_ALLOCATE_TYPE Type, | |
482 | IN OUT EFI_PHYSICAL_ADDRESS* Image, | |
483 | OUT UINTN *ImageSize | |
484 | ) | |
485 | { | |
486 | EFI_STATUS Status; | |
487 | MEMMAP_DEVICE_PATH* MemMapPathDevicePath; | |
488 | UINTN Size; | |
489 | ||
490 | ASSERT (IS_DEVICE_PATH_NODE(RemainingDevicePath,HARDWARE_DEVICE_PATH,HW_MEMMAP_DP)); | |
491 | ||
492 | MemMapPathDevicePath = (MEMMAP_DEVICE_PATH*)RemainingDevicePath; | |
493 | ||
494 | Size = MemMapPathDevicePath->EndingAddress - MemMapPathDevicePath->StartingAddress; | |
495 | if (Size == 0) { | |
496 | return EFI_INVALID_PARAMETER; | |
497 | } | |
498 | ||
bd54c237 | 499 | Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(Size), Image); |
500 | // Try to allocate in any pages if failed to allocate memory at the defined location | |
501 | if ((Status == EFI_OUT_OF_RESOURCES) && (Type != AllocateAnyPages)) { | |
502 | Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesCode, EFI_SIZE_TO_PAGES(Size), Image); | |
503 | } | |
a355a365 | 504 | if (!EFI_ERROR(Status)) { |
505 | CopyMem ((VOID*)(UINTN)(*Image), (CONST VOID*)(UINTN)MemMapPathDevicePath->StartingAddress, Size); | |
506 | ||
507 | if (ImageSize != NULL) { | |
508 | *ImageSize = Size; | |
1bfda055 | 509 | } |
a355a365 | 510 | } |
1bfda055 | 511 | |
a355a365 | 512 | return Status; |
513 | } | |
514 | ||
515 | BOOLEAN | |
516 | BdsFirmwareVolumeSupport ( | |
517 | IN EFI_DEVICE_PATH *DevicePath, | |
518 | IN EFI_HANDLE Handle, | |
519 | IN EFI_DEVICE_PATH *RemainingDevicePath | |
520 | ) | |
521 | { | |
522 | return IS_DEVICE_PATH_NODE(RemainingDevicePath, MEDIA_DEVICE_PATH, MEDIA_PIWG_FW_FILE_DP); | |
523 | } | |
524 | ||
525 | EFI_STATUS | |
526 | BdsFirmwareVolumeLoadImage ( | |
527 | IN EFI_DEVICE_PATH *DevicePath, | |
528 | IN EFI_HANDLE Handle, | |
529 | IN EFI_DEVICE_PATH *RemainingDevicePath, | |
530 | IN EFI_ALLOCATE_TYPE Type, | |
531 | IN OUT EFI_PHYSICAL_ADDRESS* Image, | |
532 | OUT UINTN *ImageSize | |
533 | ) | |
534 | { | |
535 | EFI_STATUS Status; | |
536 | EFI_FIRMWARE_VOLUME2_PROTOCOL *FwVol; | |
537 | EFI_GUID *FvNameGuid; | |
538 | EFI_SECTION_TYPE SectionType; | |
539 | EFI_FV_FILETYPE FvType; | |
540 | EFI_FV_FILE_ATTRIBUTES Attrib; | |
541 | UINT32 AuthenticationStatus; | |
542 | VOID* ImageBuffer; | |
543 | ||
544 | ASSERT (IS_DEVICE_PATH_NODE(RemainingDevicePath, MEDIA_DEVICE_PATH, MEDIA_PIWG_FW_FILE_DP)); | |
545 | ||
546 | Status = gBS->HandleProtocol(Handle,&gEfiFirmwareVolume2ProtocolGuid, (VOID **)&FwVol); | |
547 | if (EFI_ERROR(Status)) { | |
1bfda055 | 548 | return Status; |
a355a365 | 549 | } |
550 | ||
551 | FvNameGuid = EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)RemainingDevicePath); | |
552 | if (FvNameGuid == NULL) { | |
553 | Status = EFI_INVALID_PARAMETER; | |
554 | } | |
555 | ||
556 | SectionType = EFI_SECTION_PE32; | |
557 | AuthenticationStatus = 0; | |
558 | //Note: ReadSection at the opposite of ReadFile does not allow to pass ImageBuffer == NULL to get the size of the file. | |
559 | ImageBuffer = NULL; | |
560 | Status = FwVol->ReadSection ( | |
561 | FwVol, | |
562 | FvNameGuid, | |
563 | SectionType, | |
564 | 0, | |
565 | &ImageBuffer, | |
566 | ImageSize, | |
567 | &AuthenticationStatus | |
568 | ); | |
569 | if (!EFI_ERROR (Status)) { | |
570 | #if 0 | |
571 | // In case the buffer has some address requirements, we must copy the buffer to a buffer following the requirements | |
572 | if (Type != AllocateAnyPages) { | |
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 | } | |
579 | #else | |
580 | // We must copy the buffer into a page allocations. Otherwise, the caller could call gBS->FreePages() on the pool allocation | |
581 | Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize), Image); | |
bd54c237 | 582 | // Try to allocate in any pages if failed to allocate memory at the defined location |
583 | if ((Status == EFI_OUT_OF_RESOURCES) && (Type != AllocateAnyPages)) { | |
1c6f402c | 584 | Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize), Image); |
bd54c237 | 585 | } |
a355a365 | 586 | if (!EFI_ERROR(Status)) { |
587 | CopyMem ((VOID*)(UINTN)(*Image), ImageBuffer, *ImageSize); | |
588 | FreePool (ImageBuffer); | |
589 | } | |
590 | #endif | |
591 | } else { | |
592 | // Try a raw file, since a PE32 SECTION does not exist | |
593 | Status = FwVol->ReadFile ( | |
594 | FwVol, | |
595 | FvNameGuid, | |
596 | NULL, | |
597 | ImageSize, | |
598 | &FvType, | |
599 | &Attrib, | |
600 | &AuthenticationStatus | |
601 | ); | |
602 | if (!EFI_ERROR(Status)) { | |
bd54c237 | 603 | Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize), Image); |
604 | // Try to allocate in any pages if failed to allocate memory at the defined location | |
605 | if ((Status == EFI_OUT_OF_RESOURCES) && (Type != AllocateAnyPages)) { | |
1c6f402c | 606 | Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize), Image); |
bd54c237 | 607 | } |
a355a365 | 608 | if (!EFI_ERROR(Status)) { |
609 | Status = FwVol->ReadFile ( | |
610 | FwVol, | |
611 | FvNameGuid, | |
612 | (VOID*)(UINTN)(*Image), | |
613 | ImageSize, | |
614 | &FvType, | |
615 | &Attrib, | |
616 | &AuthenticationStatus | |
617 | ); | |
618 | } | |
619 | } | |
620 | } | |
621 | return Status; | |
1bfda055 | 622 | } |
623 | ||
a355a365 | 624 | BOOLEAN |
625 | BdsPxeSupport ( | |
626 | IN EFI_DEVICE_PATH* DevicePath, | |
627 | IN EFI_HANDLE Handle, | |
628 | IN EFI_DEVICE_PATH* RemainingDevicePath | |
629 | ) | |
630 | { | |
631 | EFI_STATUS Status; | |
632 | EFI_PXE_BASE_CODE_PROTOCOL* PxeBcProtocol; | |
633 | ||
634 | if (!IsDevicePathEnd(RemainingDevicePath)) { | |
635 | return FALSE; | |
636 | } | |
637 | ||
638 | Status = gBS->HandleProtocol (Handle, &gEfiPxeBaseCodeProtocolGuid, (VOID **)&PxeBcProtocol); | |
639 | if (EFI_ERROR (Status)) { | |
640 | return FALSE; | |
641 | } else { | |
642 | return TRUE; | |
643 | } | |
644 | } | |
645 | ||
646 | EFI_STATUS | |
647 | BdsPxeLoadImage ( | |
648 | IN EFI_DEVICE_PATH* DevicePath, | |
649 | IN EFI_HANDLE Handle, | |
650 | IN EFI_DEVICE_PATH* RemainingDevicePath, | |
651 | IN EFI_ALLOCATE_TYPE Type, | |
652 | IN OUT EFI_PHYSICAL_ADDRESS *Image, | |
653 | OUT UINTN *ImageSize | |
654 | ) | |
655 | { | |
656 | EFI_STATUS Status; | |
657 | EFI_LOAD_FILE_PROTOCOL *LoadFileProtocol; | |
658 | UINTN BufferSize; | |
659 | ||
660 | // Get Load File Protocol attached to the PXE protocol | |
661 | Status = gBS->HandleProtocol (Handle, &gEfiLoadFileProtocolGuid, (VOID **)&LoadFileProtocol); | |
662 | if (EFI_ERROR (Status)) { | |
663 | return Status; | |
664 | } | |
665 | ||
666 | Status = LoadFileProtocol->LoadFile (LoadFileProtocol, DevicePath, TRUE, &BufferSize, NULL); | |
667 | if (Status == EFI_BUFFER_TOO_SMALL) { | |
668 | Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(BufferSize), Image); | |
669 | if (EFI_ERROR(Status)) { | |
670 | return Status; | |
1bfda055 | 671 | } |
672 | ||
a355a365 | 673 | Status = LoadFileProtocol->LoadFile (LoadFileProtocol, DevicePath, TRUE, &BufferSize, (VOID*)(UINTN)(*Image)); |
674 | if (!EFI_ERROR(Status) && (ImageSize != NULL)) { | |
675 | *ImageSize = BufferSize; | |
1bfda055 | 676 | } |
a355a365 | 677 | } |
678 | ||
679 | return Status; | |
680 | } | |
681 | ||
682 | BOOLEAN | |
683 | BdsTftpSupport ( | |
684 | IN EFI_DEVICE_PATH* DevicePath, | |
685 | IN EFI_HANDLE Handle, | |
686 | IN EFI_DEVICE_PATH* RemainingDevicePath | |
687 | ) | |
688 | { | |
689 | EFI_STATUS Status; | |
690 | EFI_DEVICE_PATH *NextDevicePath; | |
691 | EFI_PXE_BASE_CODE_PROTOCOL *PxeBcProtocol; | |
692 | ||
693 | // Validate the Remaining Device Path | |
694 | if (IsDevicePathEnd(RemainingDevicePath)) { | |
695 | return FALSE; | |
696 | } | |
697 | if (!IS_DEVICE_PATH_NODE(RemainingDevicePath,MESSAGING_DEVICE_PATH,MSG_IPv4_DP) && | |
698 | !IS_DEVICE_PATH_NODE(RemainingDevicePath,MESSAGING_DEVICE_PATH,MSG_IPv6_DP)) { | |
699 | return FALSE; | |
700 | } | |
701 | NextDevicePath = NextDevicePathNode (RemainingDevicePath); | |
702 | if (IsDevicePathEnd(NextDevicePath)) { | |
703 | return FALSE; | |
704 | } | |
705 | if (!IS_DEVICE_PATH_NODE(NextDevicePath,MEDIA_DEVICE_PATH,MEDIA_FILEPATH_DP)) { | |
706 | return FALSE; | |
707 | } | |
708 | ||
709 | Status = gBS->HandleProtocol (Handle, &gEfiPxeBaseCodeProtocolGuid, (VOID **)&PxeBcProtocol); | |
710 | if (EFI_ERROR (Status)) { | |
711 | return FALSE; | |
712 | } else { | |
713 | return TRUE; | |
714 | } | |
715 | } | |
716 | ||
717 | EFI_STATUS | |
718 | BdsTftpLoadImage ( | |
719 | IN EFI_DEVICE_PATH* DevicePath, | |
720 | IN EFI_HANDLE Handle, | |
721 | IN EFI_DEVICE_PATH* RemainingDevicePath, | |
722 | IN EFI_ALLOCATE_TYPE Type, | |
723 | IN OUT EFI_PHYSICAL_ADDRESS *Image, | |
724 | OUT UINTN *ImageSize | |
725 | ) | |
726 | { | |
727 | EFI_STATUS Status; | |
728 | EFI_PXE_BASE_CODE_PROTOCOL *Pxe; | |
729 | UINT64 TftpBufferSize; | |
730 | VOID* TftpBuffer; | |
731 | EFI_IP_ADDRESS ServerIp; | |
732 | IPv4_DEVICE_PATH* IPv4DevicePathNode; | |
733 | FILEPATH_DEVICE_PATH* FilePathDevicePath; | |
734 | EFI_IP_ADDRESS LocalIp; | |
735 | ||
736 | ASSERT(IS_DEVICE_PATH_NODE(RemainingDevicePath,MESSAGING_DEVICE_PATH,MSG_IPv4_DP)); | |
737 | ||
738 | IPv4DevicePathNode = (IPv4_DEVICE_PATH*)RemainingDevicePath; | |
739 | FilePathDevicePath = (FILEPATH_DEVICE_PATH*)(IPv4DevicePathNode + 1); | |
740 | ||
741 | Status = gBS->LocateProtocol (&gEfiPxeBaseCodeProtocolGuid, NULL, (VOID **)&Pxe); | |
742 | if (EFI_ERROR(Status)) { | |
743 | return Status; | |
744 | } | |
745 | ||
746 | Status = Pxe->Start (Pxe, FALSE); | |
747 | if (EFI_ERROR(Status) && (Status != EFI_ALREADY_STARTED)) { | |
748 | return Status; | |
749 | } | |
750 | ||
751 | if (!IPv4DevicePathNode->StaticIpAddress) { | |
752 | Status = Pxe->Dhcp(Pxe, TRUE); | |
753 | } else { | |
754 | CopyMem (&LocalIp.v4, &IPv4DevicePathNode->LocalIpAddress, sizeof (EFI_IPv4_ADDRESS)); | |
755 | Status = Pxe->SetStationIp (Pxe, &LocalIp, NULL); | |
756 | } | |
757 | if (EFI_ERROR(Status)) { | |
758 | return Status; | |
759 | } | |
760 | ||
761 | CopyMem (&ServerIp.v4, &IPv4DevicePathNode->RemoteIpAddress, sizeof (EFI_IPv4_ADDRESS)); | |
762 | ||
763 | Status = Pxe->Mtftp ( | |
764 | Pxe, | |
765 | EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE, | |
766 | NULL, | |
767 | FALSE, | |
768 | &TftpBufferSize, | |
769 | NULL, | |
770 | &ServerIp, | |
771 | (UINT8 *)FilePathDevicePath->PathName, | |
772 | NULL, | |
773 | TRUE | |
774 | ); | |
775 | if (EFI_ERROR(Status)) { | |
776 | return Status; | |
777 | } | |
778 | ||
779 | // Allocate a buffer to hold the whole file. | |
780 | TftpBuffer = AllocatePool(TftpBufferSize); | |
781 | if (TftpBuffer == NULL) { | |
782 | return EFI_OUT_OF_RESOURCES; | |
783 | } | |
784 | ||
785 | Status = Pxe->Mtftp ( | |
786 | Pxe, | |
787 | EFI_PXE_BASE_CODE_TFTP_READ_FILE, | |
788 | TftpBuffer, | |
789 | FALSE, | |
790 | &TftpBufferSize, | |
791 | NULL, | |
792 | &ServerIp, | |
793 | (UINT8 *)FilePathDevicePath->PathName, | |
794 | NULL, | |
795 | FALSE | |
796 | ); | |
797 | if (EFI_ERROR(Status)) { | |
798 | FreePool(TftpBuffer); | |
799 | } else if (ImageSize != NULL) { | |
800 | *ImageSize = (UINTN)TftpBufferSize; | |
801 | } | |
802 | ||
803 | return Status; | |
804 | } | |
805 | ||
806 | BDS_FILE_LOADER FileLoaders[] = { | |
807 | { BdsFileSystemSupport, BdsFileSystemLoadImage }, | |
808 | { BdsFirmwareVolumeSupport, BdsFirmwareVolumeLoadImage }, | |
809 | //{ BdsLoadFileSupport, BdsLoadFileLoadImage }, | |
810 | { BdsMemoryMapSupport, BdsMemoryMapLoadImage }, | |
811 | { BdsPxeSupport, BdsPxeLoadImage }, | |
812 | { BdsTftpSupport, BdsTftpLoadImage }, | |
813 | { NULL, NULL } | |
814 | }; | |
815 | ||
816 | EFI_STATUS | |
817 | BdsLoadImage ( | |
818 | IN EFI_DEVICE_PATH *DevicePath, | |
819 | IN EFI_ALLOCATE_TYPE Type, | |
820 | IN OUT EFI_PHYSICAL_ADDRESS* Image, | |
821 | OUT UINTN *FileSize | |
822 | ) | |
823 | { | |
824 | EFI_STATUS Status; | |
825 | EFI_HANDLE Handle; | |
826 | EFI_DEVICE_PATH *RemainingDevicePath; | |
827 | BDS_FILE_LOADER* FileLoader; | |
828 | ||
829 | Status = BdsConnectDevicePath (DevicePath, &Handle, &RemainingDevicePath); | |
830 | if (EFI_ERROR (Status)) { | |
831 | return Status; | |
832 | } | |
833 | ||
834 | FileLoader = FileLoaders; | |
835 | while (FileLoader->Support != NULL) { | |
836 | if (FileLoader->Support (DevicePath, Handle, RemainingDevicePath)) { | |
837 | return FileLoader->LoadImage (DevicePath, Handle, RemainingDevicePath, Type, Image, FileSize); | |
838 | } | |
839 | FileLoader++; | |
840 | } | |
841 | ||
842 | return EFI_UNSUPPORTED; | |
843 | } | |
844 | ||
6bab33c7 | 845 | /** |
846 | Start an EFI Application from a Device Path | |
847 | ||
848 | @param ParentImageHandle Handle of the calling image | |
849 | @param DevicePath Location of the EFI Application | |
850 | ||
851 | @retval EFI_SUCCESS All drivers have been connected | |
852 | @retval EFI_NOT_FOUND The Linux kernel Device Path has not been found | |
853 | @retval EFI_OUT_OF_RESOURCES There is not enough resource memory to store the matching results. | |
854 | ||
855 | **/ | |
a355a365 | 856 | EFI_STATUS |
857 | BdsStartEfiApplication ( | |
858 | IN EFI_HANDLE ParentImageHandle, | |
859 | IN EFI_DEVICE_PATH_PROTOCOL *DevicePath | |
860 | ) | |
861 | { | |
862 | EFI_STATUS Status; | |
863 | EFI_HANDLE ImageHandle; | |
864 | EFI_PHYSICAL_ADDRESS BinaryBuffer; | |
865 | UINTN BinarySize; | |
866 | ||
867 | // Find the nearest supported file loader | |
868 | Status = BdsLoadImage (DevicePath, AllocateAnyPages,&BinaryBuffer,&BinarySize); | |
869 | if (EFI_ERROR(Status)) { | |
870 | return Status; | |
871 | } | |
872 | ||
873 | // Load the image from the Buffer with Boot Services function | |
874 | Status = gBS->LoadImage (TRUE, ParentImageHandle, DevicePath, (VOID*)(UINTN)BinaryBuffer, BinarySize, &ImageHandle); | |
875 | if (EFI_ERROR(Status)) { | |
876 | return Status; | |
877 | } | |
878 | ||
879 | // Before calling the image, enable the Watchdog Timer for the 5 Minute period | |
880 | gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL); | |
881 | // Start the image | |
882 | Status = gBS->StartImage (ImageHandle, NULL, NULL); | |
883 | // Clear the Watchdog Timer after the image returns | |
884 | gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL); | |
885 | ||
886 | return Status; | |
1bfda055 | 887 | } |