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