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