]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Library/GenericBdsLib/BdsBoot.c
Fix some typo.
[mirror_edk2.git] / MdeModulePkg / Library / GenericBdsLib / BdsBoot.c
CommitLineData
897f0eee 1/** @file\r
b0dd8108 2 BDS Lib functions which relate with create or process the boot option.\r
897f0eee 3\r
4Copyright (c) 2004 - 2008, Intel Corporation. <BR>\r
5All rights reserved. This program and the accompanying materials\r
6are licensed and made available under the terms and conditions of the BSD License\r
7which accompanies this distribution. The full text of the license may be found at\r
8http://opensource.org/licenses/bsd-license.php\r
9\r
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
15#include "InternalBdsLib.h"\r
16\r
17BOOLEAN mEnumBootDevice = FALSE;\r
18\r
ec8cd35c 19///\r
20/// This GUID is used for an EFI Variable that stores the front device pathes\r
21/// for a partial device path that starts with the HD node.\r
22///\r
897f0eee 23EFI_GUID mHdBootVariablePrivateGuid = { 0xfab7e9e1, 0x39dd, 0x4f2b, { 0x84, 0x8, 0xe2, 0xe, 0x90, 0x6c, 0xb6, 0xde } };\r
24\r
25\r
26\r
27/**\r
28 Boot the legacy system with the boot option\r
29\r
30 @param Option The legacy boot option which have BBS device path\r
31\r
32 @retval EFI_UNSUPPORTED There is no legacybios protocol, do not support\r
33 legacy boot.\r
34 @retval EFI_STATUS Return the status of LegacyBios->LegacyBoot ().\r
35\r
36**/\r
37EFI_STATUS\r
38BdsLibDoLegacyBoot (\r
39 IN BDS_COMMON_OPTION *Option\r
40 )\r
41{\r
42 EFI_STATUS Status;\r
43 EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;\r
44\r
45 Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);\r
46 if (EFI_ERROR (Status)) {\r
47 //\r
48 // If no LegacyBios protocol we do not support legacy boot\r
49 //\r
50 return EFI_UNSUPPORTED;\r
51 }\r
52 //\r
3fd8027e 53 // Notes: if we separate the int 19, then we don't need to refresh BBS\r
897f0eee 54 //\r
55 BdsRefreshBbsTableForBoot (Option);\r
56\r
57 //\r
58 // Write boot to OS performance data to a file\r
59 //\r
60 PERF_CODE (\r
61 WriteBootToOsPerformanceData ();\r
62 );\r
63\r
64 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Legacy Boot: %S\n", Option->Description));\r
65 return LegacyBios->LegacyBoot (\r
66 LegacyBios,\r
67 (BBS_BBS_DEVICE_PATH *) Option->DevicePath,\r
68 Option->LoadOptionsSize,\r
69 Option->LoadOptions\r
70 );\r
71}\r
72\r
73\r
74/**\r
262b0668 75 Process the boot option follow the UEFI specification and\r
897f0eee 76 special treat the legacy boot option with BBS_DEVICE_PATH.\r
77\r
78 @param Option The boot option need to be processed\r
79 @param DevicePath The device path which describe where to load the\r
3fd8027e 80 boot image or the legacy BBS device path to boot\r
897f0eee 81 the legacy OS\r
262b0668 82 @param ExitDataSize The size of exit data.\r
83 @param ExitData Data returned when Boot image failed.\r
897f0eee 84\r
262b0668 85 @retval EFI_SUCCESS Boot from the input boot option successfully.\r
897f0eee 86 @retval EFI_NOT_FOUND If the Device Path is not found in the system\r
87\r
88**/\r
89EFI_STATUS\r
90EFIAPI\r
91BdsLibBootViaBootOption (\r
92 IN BDS_COMMON_OPTION * Option,\r
93 IN EFI_DEVICE_PATH_PROTOCOL * DevicePath,\r
94 OUT UINTN *ExitDataSize,\r
95 OUT CHAR16 **ExitData OPTIONAL\r
96 )\r
97{\r
98 EFI_STATUS Status;\r
99 EFI_HANDLE Handle;\r
100 EFI_HANDLE ImageHandle;\r
101 EFI_DEVICE_PATH_PROTOCOL *FilePath;\r
102 EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;\r
103 EFI_DEVICE_PATH_PROTOCOL *WorkingDevicePath;\r
104 EFI_ACPI_S3_SAVE_PROTOCOL *AcpiS3Save;\r
105 LIST_ENTRY TempBootLists;\r
106\r
107 //\r
108 // Record the performance data for End of BDS\r
109 //\r
110 PERF_END (0, BDS_TOK, NULL, 0);\r
111\r
112 *ExitDataSize = 0;\r
113 *ExitData = NULL;\r
114\r
115 //\r
116 // Notes: put EFI64 ROM Shadow Solution\r
117 //\r
118 EFI64_SHADOW_ALL_LEGACY_ROM ();\r
119\r
120 //\r
121 // Notes: this code can be remove after the s3 script table\r
e53a6ea9 122 // hook on the event EVT_SIGNAL_READY_TO_BOOT or\r
123 // EVT_SIGNAL_LEGACY_BOOT\r
897f0eee 124 //\r
125 Status = gBS->LocateProtocol (&gEfiAcpiS3SaveProtocolGuid, NULL, (VOID **) &AcpiS3Save);\r
126 if (!EFI_ERROR (Status)) {\r
127 AcpiS3Save->S3Save (AcpiS3Save, NULL);\r
128 }\r
129 //\r
130 // If it's Device Path that starts with a hard drive path, append it with the front part to compose a\r
131 // full device path\r
132 //\r
133 WorkingDevicePath = NULL;\r
134 if ((DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) &&\r
135 (DevicePathSubType (DevicePath) == MEDIA_HARDDRIVE_DP)) {\r
136 WorkingDevicePath = BdsExpandPartitionPartialDevicePathToFull (\r
137 (HARDDRIVE_DEVICE_PATH *)DevicePath\r
138 );\r
139 if (WorkingDevicePath != NULL) {\r
140 DevicePath = WorkingDevicePath;\r
141 }\r
142 }\r
143 //\r
e53a6ea9 144 // Signal the EVT_SIGNAL_READY_TO_BOOT event\r
897f0eee 145 //\r
146 EfiSignalEventReadyToBoot();\r
147 \r
148 \r
149 //\r
150 // Set Boot Current\r
151 //\r
152 gRT->SetVariable (\r
153 L"BootCurrent",\r
154 &gEfiGlobalVariableGuid,\r
155 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
156 sizeof (UINT16),\r
157 &Option->BootCurrent\r
158 );\r
159\r
160 if ((DevicePathType (Option->DevicePath) == BBS_DEVICE_PATH) &&\r
161 (DevicePathSubType (Option->DevicePath) == BBS_BBS_DP)\r
162 ) {\r
163 //\r
164 // Check to see if we should legacy BOOT. If yes then do the legacy boot\r
165 //\r
166 return BdsLibDoLegacyBoot (Option);\r
167 }\r
168\r
169 //\r
170 // If the boot option point to Internal FV shell, make sure it is valid\r
171 //\r
172 Status = BdsLibUpdateFvFileDevicePath (&DevicePath, &gEfiShellFileGuid);\r
173 if (!EFI_ERROR(Status)) {\r
174 if (Option->DevicePath != NULL) {\r
676df92c 175 FreePool(Option->DevicePath);\r
897f0eee 176 }\r
177 Option->DevicePath = AllocateZeroPool (GetDevicePathSize (DevicePath));\r
3fd8027e 178 ASSERT(Option->DevicePath != NULL);\r
897f0eee 179 CopyMem (Option->DevicePath, DevicePath, GetDevicePathSize (DevicePath));\r
180 //\r
181 // Update the shell boot option\r
182 //\r
183 InitializeListHead (&TempBootLists);\r
184 BdsLibRegisterNewOption (&TempBootLists, DevicePath, L"EFI Internal Shell", L"BootOrder");\r
ec8cd35c 185 \r
a475bfa2 186 //\r
187 // free the temporary device path created by BdsLibUpdateFvFileDevicePath()\r
188 //\r
676df92c 189 FreePool (DevicePath); \r
a475bfa2 190 DevicePath = Option->DevicePath;\r
897f0eee 191 }\r
192\r
520c9369 193 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Booting %S\n", Option->Description));\r
897f0eee 194\r
195 Status = gBS->LoadImage (\r
196 TRUE,\r
197 mBdsImageHandle,\r
198 DevicePath,\r
199 NULL,\r
200 0,\r
201 &ImageHandle\r
202 );\r
203\r
204 //\r
205 // If we didn't find an image directly, we need to try as if it is a removable device boot opotion\r
206 // and load the image according to the default boot behavior for removable device.\r
207 //\r
208 if (EFI_ERROR (Status)) {\r
209 //\r
210 // check if there is a bootable removable media could be found in this device path ,\r
211 // and get the bootable media handle\r
212 //\r
213 Handle = BdsLibGetBootableHandle(DevicePath);\r
214 if (Handle == NULL) {\r
215 goto Done;\r
216 }\r
217 //\r
218 // Load the default boot file \EFI\BOOT\boot{machinename}.EFI from removable Media\r
219 // machinename is ia32, ia64, x64, ...\r
220 //\r
ec8cd35c 221 FilePath = FileDevicePath (Handle, (CONST CHAR16*)PcdGetPtr(PcdDefaultBootFileName));\r
11ef23f9 222 if (FilePath != NULL) {\r
897f0eee 223 Status = gBS->LoadImage (\r
224 TRUE,\r
225 mBdsImageHandle,\r
226 FilePath,\r
227 NULL,\r
228 0,\r
229 &ImageHandle\r
230 );\r
231 if (EFI_ERROR (Status)) {\r
232 //\r
233 // The DevicePath failed, and it's not a valid\r
234 // removable media device.\r
235 //\r
236 goto Done;\r
237 }\r
238 }\r
239 }\r
240\r
241 if (EFI_ERROR (Status)) {\r
242 //\r
243 // It there is any error from the Boot attempt exit now.\r
244 //\r
245 goto Done;\r
246 }\r
247 //\r
248 // Provide the image with it's load options\r
249 //\r
250 Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &ImageInfo);\r
251 ASSERT_EFI_ERROR (Status);\r
252\r
253 if (Option->LoadOptionsSize != 0) {\r
254 ImageInfo->LoadOptionsSize = Option->LoadOptionsSize;\r
255 ImageInfo->LoadOptions = Option->LoadOptions;\r
256 }\r
257 //\r
258 // Before calling the image, enable the Watchdog Timer for\r
259 // the 5 Minute period\r
260 //\r
261 gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);\r
262\r
263 Status = gBS->StartImage (ImageHandle, ExitDataSize, ExitData);\r
264 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Image Return Status = %r\n", Status));\r
265\r
266 //\r
267 // Clear the Watchdog Timer after the image returns\r
268 //\r
269 gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);\r
270\r
271Done:\r
272 //\r
273 // Clear Boot Current\r
274 //\r
275 gRT->SetVariable (\r
276 L"BootCurrent",\r
277 &gEfiGlobalVariableGuid,\r
278 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
279 0,\r
280 &Option->BootCurrent\r
281 );\r
282\r
897f0eee 283 return Status;\r
284}\r
285\r
286\r
287/**\r
288 Expand a device path that starts with a hard drive media device path node to be a\r
289 full device path that includes the full hardware path to the device. We need\r
3fd8027e 290 to do this so it can be booted. As an optimization the front match (the part point\r
897f0eee 291 to the partition node. E.g. ACPI() /PCI()/ATA()/Partition() ) is saved in a variable\r
292 so a connect all is not required on every boot. All successful history device path\r
293 which point to partition node (the front part) will be saved.\r
294\r
295 @param HardDriveDevicePath EFI Device Path to boot, if it starts with a hard\r
296 drive media device path.\r
297 @return A Pointer to the full device path or NULL if a valid Hard Drive devic path\r
298 cannot be found.\r
299\r
300**/\r
301EFI_DEVICE_PATH_PROTOCOL *\r
302EFIAPI\r
303BdsExpandPartitionPartialDevicePathToFull (\r
304 IN HARDDRIVE_DEVICE_PATH *HardDriveDevicePath\r
305 )\r
306{\r
307 EFI_STATUS Status;\r
308 UINTN BlockIoHandleCount;\r
309 EFI_HANDLE *BlockIoBuffer;\r
310 EFI_DEVICE_PATH_PROTOCOL *FullDevicePath;\r
311 EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath;\r
312 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
313 UINTN Index;\r
314 UINTN InstanceNum;\r
315 EFI_DEVICE_PATH_PROTOCOL *CachedDevicePath;\r
316 EFI_DEVICE_PATH_PROTOCOL *TempNewDevicePath;\r
317 UINTN CachedDevicePathSize;\r
318 BOOLEAN DeviceExist;\r
319 BOOLEAN NeedAdjust;\r
320 EFI_DEVICE_PATH_PROTOCOL *Instance;\r
321 UINTN Size;\r
322\r
323 FullDevicePath = NULL;\r
324 //\r
325 // Check if there is prestore 'HDDP' variable.\r
326 // If exist, search the front path which point to partition node in the variable instants.\r
327 // If fail to find or 'HDDP' not exist, reconnect all and search in all system\r
328 //\r
329 CachedDevicePath = BdsLibGetVariableAndSize (\r
330 L"HDDP",\r
331 &mHdBootVariablePrivateGuid,\r
332 &CachedDevicePathSize\r
333 );\r
ec8cd35c 334 \r
897f0eee 335 if (CachedDevicePath != NULL) {\r
336 TempNewDevicePath = CachedDevicePath;\r
337 DeviceExist = FALSE;\r
338 NeedAdjust = FALSE;\r
339 do {\r
340 //\r
341 // Check every instance of the variable\r
3fd8027e 342 // First, check whether the instance contain the partition node, which is needed for distinguishing multi\r
343 // partial partition boot option. Second, check whether the instance could be connected.\r
897f0eee 344 //\r
345 Instance = GetNextDevicePathInstance (&TempNewDevicePath, &Size);\r
346 if (MatchPartitionDevicePathNode (Instance, HardDriveDevicePath)) {\r
347 //\r
348 // Connect the device path instance, the device path point to hard drive media device path node\r
349 // e.g. ACPI() /PCI()/ATA()/Partition()\r
350 //\r
351 Status = BdsLibConnectDevicePath (Instance);\r
352 if (!EFI_ERROR (Status)) {\r
353 DeviceExist = TRUE;\r
354 break;\r
355 }\r
356 }\r
357 //\r
358 // Come here means the first instance is not matched\r
359 //\r
360 NeedAdjust = TRUE;\r
676df92c 361 FreePool(Instance);\r
897f0eee 362 } while (TempNewDevicePath != NULL);\r
363\r
364 if (DeviceExist) {\r
365 //\r
366 // Find the matched device path.\r
3fd8027e 367 // Append the file path information from the boot option and return the fully expanded device path.\r
897f0eee 368 //\r
ec8cd35c 369 DevicePath = NextDevicePathNode ((EFI_DEVICE_PATH_PROTOCOL *) HardDriveDevicePath);\r
897f0eee 370 FullDevicePath = AppendDevicePath (Instance, DevicePath);\r
371\r
372 //\r
3fd8027e 373 // Adjust the 'HDDP' instances sequence if the matched one is not first one.\r
897f0eee 374 //\r
375 if (NeedAdjust) {\r
376 //\r
377 // First delete the matched instance.\r
378 //\r
379 TempNewDevicePath = CachedDevicePath;\r
ec8cd35c 380 CachedDevicePath = BdsLibDelPartMatchInstance (CachedDevicePath, Instance );\r
676df92c 381 FreePool (TempNewDevicePath);\r
ec8cd35c 382 \r
897f0eee 383 //\r
3fd8027e 384 // Second, append the remaining path after the matched instance\r
897f0eee 385 //\r
386 TempNewDevicePath = CachedDevicePath;\r
ec8cd35c 387 CachedDevicePath = AppendDevicePathInstance (Instance, CachedDevicePath );\r
676df92c 388 FreePool (TempNewDevicePath);\r
897f0eee 389 //\r
390 // Save the matching Device Path so we don't need to do a connect all next time\r
391 //\r
392 Status = gRT->SetVariable (\r
393 L"HDDP",\r
394 &mHdBootVariablePrivateGuid,\r
395 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
396 GetDevicePathSize (CachedDevicePath),\r
397 CachedDevicePath\r
398 );\r
399 }\r
ec8cd35c 400 \r
676df92c 401 FreePool (Instance);\r
402 FreePool (CachedDevicePath);\r
897f0eee 403 return FullDevicePath;\r
404 }\r
405 }\r
406\r
407 //\r
408 // If we get here we fail to find or 'HDDP' not exist, and now we need\r
3fd8027e 409 // to search all devices in the system for a matched partition\r
897f0eee 410 //\r
411 BdsLibConnectAllDriversToAllControllers ();\r
412 Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiBlockIoProtocolGuid, NULL, &BlockIoHandleCount, &BlockIoBuffer);\r
413 if (EFI_ERROR (Status) || BlockIoHandleCount == 0) {\r
414 //\r
415 // If there was an error or there are no device handles that support\r
416 // the BLOCK_IO Protocol, then return.\r
417 //\r
418 return NULL;\r
419 }\r
420 //\r
421 // Loop through all the device handles that support the BLOCK_IO Protocol\r
422 //\r
423 for (Index = 0; Index < BlockIoHandleCount; Index++) {\r
424\r
425 Status = gBS->HandleProtocol (BlockIoBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID *) &BlockIoDevicePath);\r
426 if (EFI_ERROR (Status) || BlockIoDevicePath == NULL) {\r
427 continue;\r
428 }\r
429\r
430 if (MatchPartitionDevicePathNode (BlockIoDevicePath, HardDriveDevicePath)) {\r
431 //\r
432 // Find the matched partition device path\r
433 //\r
434 DevicePath = NextDevicePathNode ((EFI_DEVICE_PATH_PROTOCOL *) HardDriveDevicePath);\r
435 FullDevicePath = AppendDevicePath (BlockIoDevicePath, DevicePath);\r
436\r
437 //\r
3fd8027e 438 // Save the matched partition device path in 'HDDP' variable\r
897f0eee 439 //\r
440 if (CachedDevicePath != NULL) {\r
441 //\r
3fd8027e 442 // Save the matched partition device path as first instance of 'HDDP' variable\r
897f0eee 443 //\r
444 if (BdsLibMatchDevicePaths (CachedDevicePath, BlockIoDevicePath)) {\r
445 TempNewDevicePath = CachedDevicePath;\r
446 CachedDevicePath = BdsLibDelPartMatchInstance (CachedDevicePath, BlockIoDevicePath);\r
676df92c 447 FreePool(TempNewDevicePath);\r
897f0eee 448\r
449 TempNewDevicePath = CachedDevicePath;\r
450 CachedDevicePath = AppendDevicePathInstance (BlockIoDevicePath, CachedDevicePath);\r
676df92c 451 FreePool(TempNewDevicePath);\r
897f0eee 452 } else {\r
453 TempNewDevicePath = CachedDevicePath;\r
454 CachedDevicePath = AppendDevicePathInstance (BlockIoDevicePath, CachedDevicePath);\r
676df92c 455 FreePool(TempNewDevicePath);\r
897f0eee 456 }\r
457 //\r
458 // Here limit the device path instance number to 12, which is max number for a system support 3 IDE controller\r
3fd8027e 459 // If the user try to boot many OS in different HDs or partitions, in theory, the 'HDDP' variable maybe become larger and larger.\r
897f0eee 460 //\r
461 InstanceNum = 0;\r
462 TempNewDevicePath = CachedDevicePath;\r
463 while (!IsDevicePathEnd (TempNewDevicePath)) {\r
464 TempNewDevicePath = NextDevicePathNode (TempNewDevicePath);\r
465 //\r
466 // Parse one instance\r
467 //\r
468 while (!IsDevicePathEndType (TempNewDevicePath)) {\r
469 TempNewDevicePath = NextDevicePathNode (TempNewDevicePath);\r
470 }\r
471 InstanceNum++;\r
472 //\r
473 // If the CachedDevicePath variable contain too much instance, only remain 12 instances.\r
474 //\r
475 if (InstanceNum >= 12) {\r
476 SetDevicePathEndNode (TempNewDevicePath);\r
477 break;\r
478 }\r
479 }\r
480 } else {\r
481 CachedDevicePath = DuplicateDevicePath (BlockIoDevicePath);\r
482 }\r
483\r
484 //\r
485 // Save the matching Device Path so we don't need to do a connect all next time\r
486 //\r
487 Status = gRT->SetVariable (\r
488 L"HDDP",\r
489 &mHdBootVariablePrivateGuid,\r
490 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
491 GetDevicePathSize (CachedDevicePath),\r
492 CachedDevicePath\r
493 );\r
494\r
495 break;\r
496 }\r
497 }\r
ec8cd35c 498 \r
676df92c 499 FreePool (CachedDevicePath);\r
500 if (BlockIoBuffer != NULL) {\r
501 FreePool (BlockIoBuffer);\r
502 }\r
897f0eee 503 return FullDevicePath;\r
504}\r
505\r
897f0eee 506/**\r
507 Check whether there is a instance in BlockIoDevicePath, which contain multi device path\r
508 instances, has the same partition node with HardDriveDevicePath device path\r
509\r
510 @param BlockIoDevicePath Multi device path instances which need to check\r
511 @param HardDriveDevicePath A device path which starts with a hard drive media\r
512 device path.\r
513\r
262b0668 514 @retval TRUE There is a matched device path instance.\r
515 @retval FALSE There is no matched device path instance.\r
897f0eee 516\r
517**/\r
518BOOLEAN\r
519EFIAPI\r
520MatchPartitionDevicePathNode (\r
521 IN EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath,\r
522 IN HARDDRIVE_DEVICE_PATH *HardDriveDevicePath\r
523 )\r
524{\r
525 HARDDRIVE_DEVICE_PATH *TmpHdPath;\r
897f0eee 526 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
527 BOOLEAN Match;\r
528 EFI_DEVICE_PATH_PROTOCOL *BlockIoHdDevicePathNode;\r
529\r
530 if ((BlockIoDevicePath == NULL) || (HardDriveDevicePath == NULL)) {\r
531 return FALSE;\r
532 }\r
ec8cd35c 533 \r
897f0eee 534 //\r
535 // Make PreviousDevicePath == the device path node before the end node\r
536 //\r
ec8cd35c 537 DevicePath = BlockIoDevicePath;\r
897f0eee 538 BlockIoHdDevicePathNode = NULL;\r
539\r
540 //\r
541 // find the partition device path node\r
542 //\r
543 while (!IsDevicePathEnd (DevicePath)) {\r
544 if ((DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) &&\r
545 (DevicePathSubType (DevicePath) == MEDIA_HARDDRIVE_DP)\r
546 ) {\r
547 BlockIoHdDevicePathNode = DevicePath;\r
548 break;\r
549 }\r
550\r
551 DevicePath = NextDevicePathNode (DevicePath);\r
552 }\r
553\r
554 if (BlockIoHdDevicePathNode == NULL) {\r
555 return FALSE;\r
556 }\r
557 //\r
558 // See if the harddrive device path in blockio matches the orig Hard Drive Node\r
559 //\r
560 TmpHdPath = (HARDDRIVE_DEVICE_PATH *) BlockIoHdDevicePathNode;\r
897f0eee 561 Match = FALSE;\r
ec8cd35c 562 \r
897f0eee 563 //\r
564 // Check for the match\r
565 //\r
1232b214 566 if ((TmpHdPath->MBRType == HardDriveDevicePath->MBRType) &&\r
567 (TmpHdPath->SignatureType == HardDriveDevicePath->SignatureType)) {\r
897f0eee 568 switch (TmpHdPath->SignatureType) {\r
569 case SIGNATURE_TYPE_GUID:\r
1232b214 570 Match = CompareGuid ((EFI_GUID *)TmpHdPath->Signature, (EFI_GUID *)HardDriveDevicePath->Signature);\r
897f0eee 571 break;\r
572 case SIGNATURE_TYPE_MBR:\r
1232b214 573 Match = (BOOLEAN)(*((UINT32 *)(&(TmpHdPath->Signature[0]))) == ReadUnaligned32((UINT32 *)(&(HardDriveDevicePath->Signature[0]))));\r
897f0eee 574 break;\r
575 default:\r
576 Match = FALSE;\r
577 break;\r
578 }\r
579 }\r
580\r
581 return Match;\r
582}\r
583\r
897f0eee 584/**\r
11ef23f9 585 Delete the boot option associated with the handle passed in.\r
897f0eee 586\r
587 @param Handle The handle which present the device path to create\r
588 boot option\r
589\r
590 @retval EFI_SUCCESS Delete the boot option success\r
591 @retval EFI_NOT_FOUND If the Device Path is not found in the system\r
592 @retval EFI_OUT_OF_RESOURCES Lack of memory resource\r
593 @retval Other Error return value from SetVariable()\r
594\r
595**/\r
596EFI_STATUS\r
597BdsLibDeleteOptionFromHandle (\r
598 IN EFI_HANDLE Handle\r
599 )\r
600{\r
601 UINT16 *BootOrder;\r
602 UINT8 *BootOptionVar;\r
603 UINTN BootOrderSize;\r
604 UINTN BootOptionSize;\r
605 EFI_STATUS Status;\r
606 UINTN Index;\r
607 UINT16 BootOption[BOOT_OPTION_MAX_CHAR];\r
608 UINTN DevicePathSize;\r
609 UINTN OptionDevicePathSize;\r
610 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
611 EFI_DEVICE_PATH_PROTOCOL *OptionDevicePath;\r
612 UINT8 *TempPtr;\r
613\r
614 Status = EFI_SUCCESS;\r
615 BootOrder = NULL;\r
616 BootOrderSize = 0;\r
617\r
ec8cd35c 618 //\r
619 // Check "BootOrder" variable, if no, means there is no any boot order.\r
620 //\r
897f0eee 621 BootOrder = BdsLibGetVariableAndSize (\r
622 L"BootOrder",\r
623 &gEfiGlobalVariableGuid,\r
624 &BootOrderSize\r
625 );\r
ec8cd35c 626 if (BootOrder == NULL) {\r
897f0eee 627 return EFI_NOT_FOUND;\r
628 }\r
629\r
ec8cd35c 630 //\r
631 // Convert device handle to device path protocol instance\r
632 //\r
897f0eee 633 DevicePath = DevicePathFromHandle (Handle);\r
634 if (DevicePath == NULL) {\r
635 return EFI_NOT_FOUND;\r
636 }\r
637 DevicePathSize = GetDevicePathSize (DevicePath);\r
638\r
ec8cd35c 639 //\r
640 // Loop all boot order variable and find the matching device path\r
641 //\r
897f0eee 642 Index = 0;\r
643 while (Index < BootOrderSize / sizeof (UINT16)) {\r
644 UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]);\r
645 BootOptionVar = BdsLibGetVariableAndSize (\r
646 BootOption,\r
647 &gEfiGlobalVariableGuid,\r
648 &BootOptionSize\r
649 );\r
ec8cd35c 650 \r
651 if (BootOptionVar == NULL) {\r
676df92c 652 FreePool (BootOrder);\r
897f0eee 653 return EFI_OUT_OF_RESOURCES;\r
654 }\r
655\r
656 TempPtr = BootOptionVar;\r
657 TempPtr += sizeof (UINT32) + sizeof (UINT16);\r
658 TempPtr += StrSize ((CHAR16 *) TempPtr);\r
659 OptionDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;\r
660 OptionDevicePathSize = GetDevicePathSize (OptionDevicePath);\r
661\r
662 //\r
663 // Check whether the device path match\r
664 //\r
665 if ((OptionDevicePathSize == DevicePathSize) &&\r
666 (CompareMem (DevicePath, OptionDevicePath, DevicePathSize) == 0)) {\r
667 BdsDeleteBootOption (BootOrder[Index], BootOrder, &BootOrderSize);\r
676df92c 668 FreePool (BootOptionVar);\r
897f0eee 669 break;\r
670 }\r
671\r
676df92c 672 FreePool (BootOptionVar);\r
897f0eee 673 Index++;\r
674 }\r
675\r
ec8cd35c 676 //\r
677 // Adjust number of boot option for "BootOrder" variable.\r
678 //\r
897f0eee 679 Status = gRT->SetVariable (\r
680 L"BootOrder",\r
681 &gEfiGlobalVariableGuid,\r
682 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
683 BootOrderSize,\r
684 BootOrder\r
685 );\r
686\r
676df92c 687 FreePool (BootOrder);\r
897f0eee 688\r
689 return Status;\r
690}\r
691\r
692\r
693/**\r
694 Delete all invalid EFI boot options. The probable invalid boot option could\r
695 be Removable media or Network boot device.\r
696\r
897f0eee 697 @retval EFI_SUCCESS Delete all invalid boot option success\r
698 @retval EFI_NOT_FOUND Variable "BootOrder" is not found\r
699 @retval EFI_OUT_OF_RESOURCES Lack of memory resource\r
700 @retval Other Error return value from SetVariable()\r
701\r
702**/\r
703EFI_STATUS\r
704BdsDeleteAllInvalidEfiBootOption (\r
705 VOID\r
706 )\r
707{\r
708 UINT16 *BootOrder;\r
709 UINT8 *BootOptionVar;\r
710 UINTN BootOrderSize;\r
711 UINTN BootOptionSize;\r
712 EFI_STATUS Status;\r
713 UINTN Index;\r
714 UINTN Index2;\r
715 UINT16 BootOption[BOOT_OPTION_MAX_CHAR];\r
716 EFI_DEVICE_PATH_PROTOCOL *OptionDevicePath;\r
717 UINT8 *TempPtr;\r
718\r
719 Status = EFI_SUCCESS;\r
720 BootOrder = NULL;\r
721 BootOrderSize = 0;\r
722\r
ec8cd35c 723 //\r
724 // Check "BootOrder" variable firstly, this variable hold the number of boot options\r
725 //\r
897f0eee 726 BootOrder = BdsLibGetVariableAndSize (\r
727 L"BootOrder",\r
728 &gEfiGlobalVariableGuid,\r
729 &BootOrderSize\r
730 );\r
731 if (NULL == BootOrder) {\r
732 return EFI_NOT_FOUND;\r
733 }\r
734\r
735 Index = 0;\r
736 while (Index < BootOrderSize / sizeof (UINT16)) {\r
737 UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]);\r
738 BootOptionVar = BdsLibGetVariableAndSize (\r
739 BootOption,\r
740 &gEfiGlobalVariableGuid,\r
741 &BootOptionSize\r
742 );\r
743 if (NULL == BootOptionVar) {\r
676df92c 744 FreePool (BootOrder);\r
897f0eee 745 return EFI_OUT_OF_RESOURCES;\r
746 }\r
747\r
748 TempPtr = BootOptionVar;\r
749 TempPtr += sizeof (UINT32) + sizeof (UINT16);\r
750 TempPtr += StrSize ((CHAR16 *) TempPtr);\r
751 OptionDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;\r
752\r
753 //\r
754 // Skip legacy boot option (BBS boot device)\r
755 //\r
756 if ((DevicePathType (OptionDevicePath) == BBS_DEVICE_PATH) &&\r
757 (DevicePathSubType (OptionDevicePath) == BBS_BBS_DP)) {\r
676df92c 758 FreePool (BootOptionVar);\r
897f0eee 759 Index++;\r
760 continue;\r
761 }\r
762\r
763 if (!BdsLibIsValidEFIBootOptDevicePath (OptionDevicePath, FALSE)) {\r
764 //\r
765 // Delete this invalid boot option "Boot####"\r
766 //\r
767 Status = gRT->SetVariable (\r
768 BootOption,\r
769 &gEfiGlobalVariableGuid,\r
770 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
771 0,\r
772 NULL\r
773 );\r
774 //\r
775 // Mark this boot option in boot order as deleted\r
776 //\r
777 BootOrder[Index] = 0xffff;\r
778 }\r
779\r
676df92c 780 FreePool (BootOptionVar);\r
897f0eee 781 Index++;\r
782 }\r
783\r
784 //\r
785 // Adjust boot order array\r
786 //\r
787 Index2 = 0;\r
788 for (Index = 0; Index < BootOrderSize / sizeof (UINT16); Index++) {\r
789 if (BootOrder[Index] != 0xffff) {\r
790 BootOrder[Index2] = BootOrder[Index];\r
791 Index2 ++;\r
792 }\r
793 }\r
794 Status = gRT->SetVariable (\r
795 L"BootOrder",\r
796 &gEfiGlobalVariableGuid,\r
797 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
798 Index2 * sizeof (UINT16),\r
799 BootOrder\r
800 );\r
801\r
676df92c 802 FreePool (BootOrder);\r
897f0eee 803\r
804 return Status;\r
805}\r
806\r
807\r
808/**\r
809 This function will enumerate all possible boot device in the system,\r
3fd8027e 810 it will only execute once of every boot.\r
897f0eee 811\r
812 @param BdsBootOptionList The header of the link list which indexed all\r
813 current boot options\r
814\r
815 @retval EFI_SUCCESS Finished all the boot device enumerate and create\r
816 the boot option base on that boot device\r
817\r
818**/\r
819EFI_STATUS\r
820EFIAPI\r
821BdsLibEnumerateAllBootOption (\r
822 IN OUT LIST_ENTRY *BdsBootOptionList\r
823 )\r
824{\r
825 EFI_STATUS Status;\r
826 UINT16 FloppyNumber;\r
827 UINT16 CdromNumber;\r
828 UINT16 UsbNumber;\r
829 UINT16 MiscNumber;\r
830 UINT16 NonBlockNumber;\r
831 UINTN NumberBlockIoHandles;\r
832 EFI_HANDLE *BlockIoHandles;\r
833 EFI_BLOCK_IO_PROTOCOL *BlkIo;\r
834 UINTN Index;\r
835 UINTN NumberSimpleNetworkHandles;\r
836 EFI_HANDLE *SimpleNetworkHandles;\r
837 UINTN FvHandleCount;\r
838 EFI_HANDLE *FvHandleBuffer;\r
839 EFI_FV_FILETYPE Type;\r
840 UINTN Size;\r
841 EFI_FV_FILE_ATTRIBUTES Attributes;\r
842 UINT32 AuthenticationStatus;\r
843 EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;\r
844 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
845 UINTN DevicePathType;\r
846 CHAR16 Buffer[40];\r
847 EFI_HANDLE *FileSystemHandles;\r
848 UINTN NumberFileSystemHandles;\r
849 BOOLEAN NeedDelete;\r
850 EFI_IMAGE_DOS_HEADER DosHeader;\r
851 EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData;\r
852 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;\r
853\r
ec8cd35c 854 FloppyNumber = 0;\r
855 CdromNumber = 0;\r
856 UsbNumber = 0;\r
857 MiscNumber = 0;\r
897f0eee 858 ZeroMem (Buffer, sizeof (Buffer));\r
ec8cd35c 859 \r
897f0eee 860 //\r
861 // If the boot device enumerate happened, just get the boot\r
862 // device from the boot order variable\r
863 //\r
864 if (mEnumBootDevice) {\r
865 BdsLibBuildOptionFromVar (BdsBootOptionList, L"BootOrder");\r
866 return EFI_SUCCESS;\r
867 }\r
ec8cd35c 868 \r
897f0eee 869 //\r
870 // Notes: this dirty code is to get the legacy boot option from the\r
871 // BBS table and create to variable as the EFI boot option, it should\r
872 // be removed after the CSM can provide legacy boot option directly\r
873 //\r
874 REFRESH_LEGACY_BOOT_OPTIONS;\r
875\r
876 //\r
877 // Delete invalid boot option\r
878 //\r
879 BdsDeleteAllInvalidEfiBootOption ();\r
ec8cd35c 880 \r
897f0eee 881 //\r
882 // Parse removable media\r
883 //\r
884 gBS->LocateHandleBuffer (\r
885 ByProtocol,\r
886 &gEfiBlockIoProtocolGuid,\r
887 NULL,\r
888 &NumberBlockIoHandles,\r
889 &BlockIoHandles\r
890 );\r
ec8cd35c 891 \r
897f0eee 892 for (Index = 0; Index < NumberBlockIoHandles; Index++) {\r
893 Status = gBS->HandleProtocol (\r
894 BlockIoHandles[Index],\r
895 &gEfiBlockIoProtocolGuid,\r
896 (VOID **) &BlkIo\r
897 );\r
898 if (!EFI_ERROR (Status)) {\r
899 if (!BlkIo->Media->RemovableMedia) {\r
900 //\r
901 // skip the non-removable block devices\r
902 //\r
903 continue;\r
904 }\r
905 }\r
906 DevicePath = DevicePathFromHandle (BlockIoHandles[Index]);\r
907 DevicePathType = BdsGetBootTypeFromDevicePath (DevicePath);\r
908\r
909 switch (DevicePathType) {\r
910 case BDS_EFI_ACPI_FLOPPY_BOOT:\r
911 if (FloppyNumber == 0) {\r
912 UnicodeSPrint (Buffer, sizeof (Buffer), L"EFI Floppy");\r
913 } else {\r
914 UnicodeSPrint (Buffer, sizeof (Buffer), L"EFI Floppy %d", FloppyNumber);\r
915 }\r
916 BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer);\r
917 FloppyNumber++;\r
918 break;\r
919\r
920 case BDS_EFI_MESSAGE_ATAPI_BOOT:\r
921 if (CdromNumber == 0) {\r
922 UnicodeSPrint (Buffer, sizeof (Buffer), L"EFI DVD/CDROM");\r
923 } else {\r
924 UnicodeSPrint (Buffer, sizeof (Buffer), L"EFI DVD/CDROM %d", CdromNumber);\r
925 }\r
926 BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer);\r
927 CdromNumber++;\r
928 break;\r
929\r
930 case BDS_EFI_MESSAGE_USB_DEVICE_BOOT:\r
931 if (UsbNumber == 0) {\r
932 UnicodeSPrint (Buffer, sizeof (Buffer), L"EFI USB Device");\r
933 } else {\r
934 UnicodeSPrint (Buffer, sizeof (Buffer), L"EFI USB Device %d", UsbNumber);\r
935 }\r
936 BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer);\r
937 UsbNumber++;\r
938 break;\r
939\r
940 case BDS_EFI_MESSAGE_SCSI_BOOT:\r
941 if (UsbNumber == 0) {\r
942 UnicodeSPrint (Buffer, sizeof (Buffer), L"EFI SCSI Device");\r
943 } else {\r
944 UnicodeSPrint (Buffer, sizeof (Buffer), L"EFI SCSI Device %d", UsbNumber);\r
945 }\r
946 BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer);\r
947 UsbNumber++;\r
948 break;\r
949\r
950 case BDS_EFI_MESSAGE_MISC_BOOT:\r
951 if (MiscNumber == 0) {\r
952 UnicodeSPrint (Buffer, sizeof (Buffer), L"EFI Misc Device");\r
953 } else {\r
954 UnicodeSPrint (Buffer, sizeof (Buffer), L"EFI Misc Device %d", MiscNumber);\r
955 }\r
956 BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer);\r
957 MiscNumber++;\r
958 break;\r
959\r
960 default:\r
961 break;\r
962 }\r
963 }\r
964\r
11ef23f9 965 if (NumberBlockIoHandles != 0) {\r
676df92c 966 FreePool (BlockIoHandles);\r
897f0eee 967 }\r
968\r
969 //\r
970 // If there is simple file protocol which does not consume block Io protocol, create a boot option for it here.\r
971 //\r
972 NonBlockNumber = 0;\r
973 gBS->LocateHandleBuffer (\r
974 ByProtocol,\r
975 &gEfiSimpleFileSystemProtocolGuid,\r
976 NULL,\r
977 &NumberFileSystemHandles,\r
978 &FileSystemHandles\r
979 );\r
980 for (Index = 0; Index < NumberFileSystemHandles; Index++) {\r
981 Status = gBS->HandleProtocol (\r
982 FileSystemHandles[Index],\r
983 &gEfiBlockIoProtocolGuid,\r
984 (VOID **) &BlkIo\r
985 );\r
986 if (!EFI_ERROR (Status)) {\r
987 //\r
988 // Skip if the file system handle supports a BlkIo protocol,\r
989 //\r
990 continue;\r
991 }\r
992\r
993 //\r
994 // Do the removable Media thing. \EFI\BOOT\boot{machinename}.EFI\r
995 // machinename is ia32, ia64, x64, ...\r
996 //\r
997 Hdr.Union = &HdrData;\r
998 NeedDelete = TRUE;\r
999 Status = BdsLibGetImageHeader (\r
1000 FileSystemHandles[Index],\r
ec8cd35c 1001 (CHAR16*)PcdGetPtr (PcdDefaultBootFileName),\r
897f0eee 1002 &DosHeader,\r
1003 Hdr\r
1004 );\r
1005 if (!EFI_ERROR (Status) &&\r
1006 EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Hdr.Pe32->FileHeader.Machine) &&\r
1007 Hdr.Pe32->OptionalHeader.Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) {\r
1008 NeedDelete = FALSE;\r
1009 }\r
1010\r
1011 if (NeedDelete) {\r
1012 //\r
1013 // No such file or the file is not a EFI application, delete this boot option\r
1014 //\r
1015 BdsLibDeleteOptionFromHandle (FileSystemHandles[Index]);\r
1016 } else {\r
1017 if (NonBlockNumber == 0) {\r
1018 UnicodeSPrint (Buffer, sizeof (Buffer), L"EFI Non-Block Boot Device");\r
1019 } else {\r
1020 UnicodeSPrint (Buffer, sizeof (Buffer), L"EFI Non-Block Boot Device %d", NonBlockNumber);\r
1021 }\r
1022 BdsLibBuildOptionFromHandle (FileSystemHandles[Index], BdsBootOptionList, Buffer);\r
1023 NonBlockNumber++;\r
1024 }\r
1025 }\r
1026\r
11ef23f9 1027 if (NumberFileSystemHandles != 0) {\r
676df92c 1028 FreePool (FileSystemHandles);\r
897f0eee 1029 }\r
1030\r
1031 //\r
1032 // Parse Network Boot Device\r
1033 //\r
1034 gBS->LocateHandleBuffer (\r
1035 ByProtocol,\r
1036 &gEfiSimpleNetworkProtocolGuid,\r
1037 NULL,\r
1038 &NumberSimpleNetworkHandles,\r
1039 &SimpleNetworkHandles\r
1040 );\r
1041 for (Index = 0; Index < NumberSimpleNetworkHandles; Index++) {\r
1042 if (Index == 0) {\r
1043 UnicodeSPrint (Buffer, sizeof (Buffer), L"EFI Network");\r
1044 } else {\r
1045 UnicodeSPrint (Buffer, sizeof (Buffer), L"EFI Network %d", Index);\r
1046 }\r
1047 BdsLibBuildOptionFromHandle (SimpleNetworkHandles[Index], BdsBootOptionList, Buffer);\r
1048 }\r
1049\r
11ef23f9 1050 if (NumberSimpleNetworkHandles != 0) {\r
676df92c 1051 FreePool (SimpleNetworkHandles);\r
897f0eee 1052 }\r
1053\r
1054 //\r
1055 // Check if we have on flash shell\r
1056 //\r
1057 gBS->LocateHandleBuffer (\r
1058 ByProtocol,\r
1059 &gEfiFirmwareVolume2ProtocolGuid,\r
1060 NULL,\r
1061 &FvHandleCount,\r
1062 &FvHandleBuffer\r
1063 );\r
1064 for (Index = 0; Index < FvHandleCount; Index++) {\r
1065 //\r
1066 // Only care the dispatched FV. If no dispatch protocol on the FV, it is not dispatched, then skip it.\r
1067 //\r
1068 Status = gBS->HandleProtocol (\r
1069 FvHandleBuffer[Index],\r
1070 &gEfiFirmwareVolumeDispatchProtocolGuid,\r
1071 (VOID **) &Fv\r
1072 );\r
1073 if (EFI_ERROR (Status)) {\r
1074 continue;\r
1075 }\r
1076 \r
1077 gBS->HandleProtocol (\r
1078 FvHandleBuffer[Index],\r
1079 &gEfiFirmwareVolume2ProtocolGuid,\r
1080 (VOID **) &Fv\r
1081 );\r
1082\r
1083 Status = Fv->ReadFile (\r
1084 Fv,\r
1085 &gEfiShellFileGuid,\r
1086 NULL,\r
1087 &Size,\r
1088 &Type,\r
1089 &Attributes,\r
1090 &AuthenticationStatus\r
1091 );\r
1092 if (EFI_ERROR (Status)) {\r
1093 //\r
1094 // Skip if no shell file in the FV\r
1095 //\r
1096 continue;\r
1097 }\r
1098 //\r
1099 // Build the shell boot option\r
1100 //\r
1101 BdsLibBuildOptionFromShell (FvHandleBuffer[Index], BdsBootOptionList);\r
1102 }\r
1103\r
11ef23f9 1104 if (FvHandleCount != 0) {\r
676df92c 1105 FreePool (FvHandleBuffer);\r
897f0eee 1106 }\r
1107 //\r
1108 // Make sure every boot only have one time\r
1109 // boot device enumerate\r
1110 //\r
1111 BdsLibBuildOptionFromVar (BdsBootOptionList, L"BootOrder");\r
1112 mEnumBootDevice = TRUE;\r
1113\r
1114 return EFI_SUCCESS;\r
1115}\r
1116\r
897f0eee 1117/**\r
262b0668 1118 Build the boot option with the handle parsed in\r
897f0eee 1119\r
1120 @param Handle The handle which present the device path to create\r
1121 boot option\r
1122 @param BdsBootOptionList The header of the link list which indexed all\r
1123 current boot options\r
262b0668 1124 @param String The description of the boot option.\r
897f0eee 1125\r
1126**/\r
1127VOID\r
1128EFIAPI\r
1129BdsLibBuildOptionFromHandle (\r
1130 IN EFI_HANDLE Handle,\r
1131 IN LIST_ENTRY *BdsBootOptionList,\r
1132 IN CHAR16 *String\r
1133 )\r
1134{\r
1135 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
1136\r
1137 DevicePath = DevicePathFromHandle (Handle);\r
1138\r
1139 //\r
1140 // Create and register new boot option\r
1141 //\r
1142 BdsLibRegisterNewOption (BdsBootOptionList, DevicePath, String, L"BootOrder");\r
1143}\r
1144\r
1145\r
1146/**\r
11ef23f9 1147 Build the on flash shell boot option with the handle parsed in.\r
897f0eee 1148\r
1149 @param Handle The handle which present the device path to create\r
1150 on flash shell boot option\r
1151 @param BdsBootOptionList The header of the link list which indexed all\r
1152 current boot options\r
1153\r
897f0eee 1154**/\r
1155VOID\r
1156EFIAPI\r
1157BdsLibBuildOptionFromShell (\r
1158 IN EFI_HANDLE Handle,\r
1159 IN OUT LIST_ENTRY *BdsBootOptionList\r
1160 )\r
1161{\r
1162 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
1163 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH ShellNode;\r
1164\r
1165 DevicePath = DevicePathFromHandle (Handle);\r
1166\r
1167 //\r
1168 // Build the shell device path\r
1169 //\r
1170 EfiInitializeFwVolDevicepathNode (&ShellNode, &gEfiShellFileGuid);\r
ec8cd35c 1171\r
897f0eee 1172 DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *) &ShellNode);\r
1173\r
1174 //\r
1175 // Create and register the shell boot option\r
1176 //\r
1177 BdsLibRegisterNewOption (BdsBootOptionList, DevicePath, L"EFI Internal Shell", L"BootOrder");\r
1178\r
1179}\r
1180\r
897f0eee 1181/**\r
262b0668 1182 Boot from the UEFI spec defined "BootNext" variable.\r
897f0eee 1183\r
1184**/\r
1185VOID\r
1186EFIAPI\r
1187BdsLibBootNext (\r
1188 VOID\r
1189 )\r
1190{\r
1191 UINT16 *BootNext;\r
1192 UINTN BootNextSize;\r
1193 CHAR16 Buffer[20];\r
1194 BDS_COMMON_OPTION *BootOption;\r
1195 LIST_ENTRY TempList;\r
1196 UINTN ExitDataSize;\r
1197 CHAR16 *ExitData;\r
1198\r
1199 //\r
1200 // Init the boot option name buffer and temp link list\r
1201 //\r
1202 InitializeListHead (&TempList);\r
1203 ZeroMem (Buffer, sizeof (Buffer));\r
1204\r
1205 BootNext = BdsLibGetVariableAndSize (\r
1206 L"BootNext",\r
1207 &gEfiGlobalVariableGuid,\r
1208 &BootNextSize\r
1209 );\r
1210\r
1211 //\r
1212 // Clear the boot next variable first\r
1213 //\r
1214 if (BootNext != NULL) {\r
1215 gRT->SetVariable (\r
1216 L"BootNext",\r
1217 &gEfiGlobalVariableGuid,\r
1218 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
1219 0,\r
1220 BootNext\r
1221 );\r
1222\r
1223 //\r
1224 // Start to build the boot option and try to boot\r
1225 //\r
1226 UnicodeSPrint (Buffer, sizeof (Buffer), L"Boot%04x", *BootNext);\r
1227 BootOption = BdsLibVariableToOption (&TempList, Buffer);\r
1228 BdsLibConnectDevicePath (BootOption->DevicePath);\r
1229 BdsLibBootViaBootOption (BootOption, BootOption->DevicePath, &ExitDataSize, &ExitData);\r
1230 }\r
1231\r
1232}\r
1233\r
897f0eee 1234/**\r
1235 Return the bootable media handle.\r
1236 First, check the device is connected\r
1237 Second, check whether the device path point to a device which support SimpleFileSystemProtocol,\r
1238 Third, detect the the default boot file in the Media, and return the removable Media handle.\r
1239\r
1240 @param DevicePath Device Path to a bootable device\r
1241\r
897f0eee 1242 @retval NULL The media on the DevicePath is not bootable\r
1243\r
1244**/\r
1245EFI_HANDLE\r
1246EFIAPI\r
1247BdsLibGetBootableHandle (\r
1248 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
1249 )\r
1250{\r
1251 EFI_STATUS Status;\r
1252 EFI_DEVICE_PATH_PROTOCOL *UpdatedDevicePath;\r
1253 EFI_DEVICE_PATH_PROTOCOL *DupDevicePath;\r
1254 EFI_HANDLE Handle;\r
1255 EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
1256 VOID *Buffer;\r
1257 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;\r
1258 UINTN Size;\r
1259 UINTN TempSize;\r
1260 EFI_HANDLE ReturnHandle;\r
1261 EFI_HANDLE *SimpleFileSystemHandles;\r
1262\r
1263 UINTN NumberSimpleFileSystemHandles;\r
1264 UINTN Index;\r
1265 EFI_IMAGE_DOS_HEADER DosHeader;\r
1266 EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData;\r
1267 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;\r
1268\r
1269 UpdatedDevicePath = DevicePath;\r
ec8cd35c 1270 \r
897f0eee 1271 //\r
1272 // Check whether the device is connected\r
1273 //\r
1274 Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &UpdatedDevicePath, &Handle);\r
1275 if (EFI_ERROR (Status)) {\r
1276 //\r
1277 // Skip the case that the boot option point to a simple file protocol which does not consume block Io protocol,\r
1278 //\r
1279 Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &UpdatedDevicePath, &Handle);\r
1280 if (EFI_ERROR (Status)) {\r
1281 //\r
1282 // Fail to find the proper BlockIo and simple file protocol, maybe because device not present, we need to connect it firstly\r
1283 //\r
1284 UpdatedDevicePath = DevicePath;\r
ec8cd35c 1285 Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &UpdatedDevicePath, &Handle);\r
897f0eee 1286 gBS->ConnectController (Handle, NULL, NULL, TRUE);\r
1287 }\r
1288 } else {\r
1289 //\r
3fd8027e 1290 // Get BlockIo protocol and check removable attribute\r
897f0eee 1291 //\r
1292 Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **)&BlockIo);\r
1293 //\r
1294 // Issue a dummy read to the device to check for media change.\r
1295 // When the removable media is changed, any Block IO read/write will\r
1296 // cause the BlockIo protocol be reinstalled and EFI_MEDIA_CHANGED is\r
1297 // returned. After the Block IO protocol is reinstalled, subsequent\r
1298 // Block IO read/write will success.\r
1299 //\r
1300 Buffer = AllocatePool (BlockIo->Media->BlockSize);\r
1301 if (Buffer != NULL) {\r
1302 BlockIo->ReadBlocks (\r
1303 BlockIo,\r
1304 BlockIo->Media->MediaId,\r
1305 0,\r
1306 BlockIo->Media->BlockSize,\r
1307 Buffer\r
1308 );\r
676df92c 1309 FreePool(Buffer);\r
897f0eee 1310 }\r
1311 }\r
1312\r
1313 //\r
1314 // Detect the the default boot file from removable Media\r
1315 //\r
1316\r
1317 //\r
1318 // If fail to get bootable handle specified by a USB boot option, the BDS should try to find other bootable device in the same USB bus\r
3fd8027e 1319 // Try to locate the USB node device path first, if fail then use its previous PCI node to search\r
897f0eee 1320 //\r
1321 DupDevicePath = DuplicateDevicePath (DevicePath);\r
676df92c 1322 ASSERT (DupDevicePath != NULL);\r
1323 \r
897f0eee 1324 UpdatedDevicePath = DupDevicePath;\r
1325 Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &UpdatedDevicePath, &Handle);\r
1326 //\r
1327 // if the resulting device path point to a usb node, and the usb node is a dummy node, should only let device path only point to the previous Pci node\r
1328 // Acpi()/Pci()/Usb() --> Acpi()/Pci()\r
1329 //\r
1330 if ((DevicePathType (UpdatedDevicePath) == MESSAGING_DEVICE_PATH) &&\r
1331 (DevicePathSubType (UpdatedDevicePath) == MSG_USB_DP)) {\r
1332 //\r
1333 // Remove the usb node, let the device path only point to PCI node\r
1334 //\r
1335 SetDevicePathEndNode (UpdatedDevicePath);\r
1336 UpdatedDevicePath = DupDevicePath;\r
1337 } else {\r
1338 UpdatedDevicePath = DevicePath;\r
1339 }\r
1340\r
1341 //\r
1342 // Get the device path size of boot option\r
1343 //\r
1344 Size = GetDevicePathSize(UpdatedDevicePath) - sizeof (EFI_DEVICE_PATH_PROTOCOL); // minus the end node\r
1345 ReturnHandle = NULL;\r
1346 gBS->LocateHandleBuffer (\r
1347 ByProtocol,\r
1348 &gEfiSimpleFileSystemProtocolGuid,\r
1349 NULL,\r
1350 &NumberSimpleFileSystemHandles,\r
1351 &SimpleFileSystemHandles\r
1352 );\r
1353 for (Index = 0; Index < NumberSimpleFileSystemHandles; Index++) {\r
1354 //\r
1355 // Get the device path size of SimpleFileSystem handle\r
1356 //\r
1357 TempDevicePath = DevicePathFromHandle (SimpleFileSystemHandles[Index]);\r
1358 TempSize = GetDevicePathSize (TempDevicePath)- sizeof (EFI_DEVICE_PATH_PROTOCOL); // minus the end node\r
1359 //\r
1360 // Check whether the device path of boot option is part of the SimpleFileSystem handle's device path\r
1361 //\r
1362 if (Size <= TempSize && CompareMem (TempDevicePath, UpdatedDevicePath, Size)==0) {\r
1363 //\r
1364 // Load the default boot file \EFI\BOOT\boot{machinename}.EFI from removable Media\r
1365 // machinename is ia32, ia64, x64, ...\r
1366 //\r
1367 Hdr.Union = &HdrData;\r
1368 Status = BdsLibGetImageHeader (\r
1369 SimpleFileSystemHandles[Index],\r
ec8cd35c 1370 (CHAR16*)PcdGetPtr(PcdDefaultBootFileName),\r
897f0eee 1371 &DosHeader,\r
1372 Hdr\r
1373 );\r
1374 if (!EFI_ERROR (Status) &&\r
1375 EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Hdr.Pe32->FileHeader.Machine) &&\r
1376 Hdr.Pe32->OptionalHeader.Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) {\r
1377 ReturnHandle = SimpleFileSystemHandles[Index];\r
1378 break;\r
1379 }\r
1380 }\r
1381 }\r
1382\r
676df92c 1383 FreePool(DupDevicePath);\r
ec8cd35c 1384\r
676df92c 1385 if (SimpleFileSystemHandles != NULL) {\r
1386 FreePool(SimpleFileSystemHandles);\r
1387 }\r
897f0eee 1388\r
1389 return ReturnHandle;\r
1390}\r
1391\r
897f0eee 1392/**\r
1393 Check to see if the network cable is plugged in. If the DevicePath is not\r
1394 connected it will be connected.\r
1395\r
1396 @param DevicePath Device Path to check\r
1397\r
1398 @retval TRUE DevicePath points to an Network that is connected\r
1399 @retval FALSE DevicePath does not point to a bootable network\r
1400\r
1401**/\r
1402BOOLEAN\r
1403BdsLibNetworkBootWithMediaPresent (\r
1404 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
1405 )\r
1406{\r
1407 EFI_STATUS Status;\r
1408 EFI_DEVICE_PATH_PROTOCOL *UpdatedDevicePath;\r
1409 EFI_HANDLE Handle;\r
1410 EFI_SIMPLE_NETWORK_PROTOCOL *Snp;\r
1411 BOOLEAN MediaPresent;\r
1412\r
1413 MediaPresent = FALSE;\r
1414\r
1415 UpdatedDevicePath = DevicePath;\r
1416 Status = gBS->LocateDevicePath (&gEfiSimpleNetworkProtocolGuid, &UpdatedDevicePath, &Handle);\r
1417 if (EFI_ERROR (Status)) {\r
1418 //\r
1419 // Device not present so see if we need to connect it\r
1420 //\r
1421 Status = BdsLibConnectDevicePath (DevicePath);\r
1422 if (!EFI_ERROR (Status)) {\r
1423 //\r
1424 // This one should work after we did the connect\r
1425 //\r
1426 Status = gBS->LocateDevicePath (&gEfiSimpleNetworkProtocolGuid, &UpdatedDevicePath, &Handle);\r
1427 }\r
1428 }\r
1429\r
1430 if (!EFI_ERROR (Status)) {\r
1431 Status = gBS->HandleProtocol (Handle, &gEfiSimpleNetworkProtocolGuid, (VOID **)&Snp);\r
1432 if (!EFI_ERROR (Status)) {\r
1433 if (Snp->Mode->MediaPresentSupported) {\r
1434 if (Snp->Mode->State == EfiSimpleNetworkInitialized) {\r
1435 //\r
1436 // In case some one else is using the SNP check to see if it's connected\r
1437 //\r
1438 MediaPresent = Snp->Mode->MediaPresent;\r
1439 } else {\r
1440 //\r
1441 // No one is using SNP so we need to Start and Initialize so\r
1442 // MediaPresent will be valid.\r
1443 //\r
1444 Status = Snp->Start (Snp);\r
1445 if (!EFI_ERROR (Status)) {\r
1446 Status = Snp->Initialize (Snp, 0, 0);\r
1447 if (!EFI_ERROR (Status)) {\r
1448 MediaPresent = Snp->Mode->MediaPresent;\r
1449 Snp->Shutdown (Snp);\r
1450 }\r
1451 Snp->Stop (Snp);\r
1452 }\r
1453 }\r
1454 } else {\r
1455 MediaPresent = TRUE;\r
1456 }\r
1457 }\r
1458 }\r
1459\r
1460 return MediaPresent;\r
1461}\r
1462\r
897f0eee 1463/**\r
11ef23f9 1464 For a bootable Device path, return its boot type.\r
897f0eee 1465\r
1466 @param DevicePath The bootable device Path to check\r
1467\r
3fd8027e 1468 @retval BDS_EFI_MEDIA_HD_BOOT If the device path contains any media device path node, it is media boot type\r
897f0eee 1469 For the floppy node, handle it as media node\r
3fd8027e 1470 @retval BDS_EFI_MEDIA_CDROM_BOOT If the device path contains any media device path node, it is media boot type\r
897f0eee 1471 For the floppy node, handle it as media node\r
3fd8027e 1472 @retval BDS_EFI_ACPI_FLOPPY_BOOT If the device path contains any media device path node, it is media boot type\r
897f0eee 1473 For the floppy node, handle it as media node\r
3fd8027e 1474 @retval BDS_EFI_MESSAGE_ATAPI_BOOT If the device path not contains any media device path node, and\r
897f0eee 1475 its last device path node point to a message device path node, it is\r
1476 \r
3fd8027e 1477 @retval BDS_EFI_MESSAGE_SCSI_BOOT If the device path not contains any media device path node, and\r
897f0eee 1478 its last device path node point to a message device path node, it is\r
3fd8027e 1479 @retval BDS_EFI_MESSAGE_USB_DEVICE_BOOT If the device path not contains any media device path node, and\r
897f0eee 1480 its last device path node point to a message device path node, it is\r
3fd8027e 1481 @retval BDS_EFI_MESSAGE_MISC_BOOT If the device path not contains any media device path node, and\r
897f0eee 1482 its last device path node point to a message device path node, it is\r
1483 @retval BDS_LEGACY_BBS_BOOT Legacy boot type\r
3fd8027e 1484 @retval BDS_EFI_UNSUPPORT An EFI Removable BlockIO device path not point to a media and message device, \r
897f0eee 1485\r
1486**/\r
1487UINT32\r
1488EFIAPI\r
1489BdsGetBootTypeFromDevicePath (\r
1490 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
1491 )\r
1492{\r
1493 ACPI_HID_DEVICE_PATH *Acpi;\r
1494 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;\r
1495 EFI_DEVICE_PATH_PROTOCOL *LastDeviceNode;\r
1496\r
1497\r
1498 if (NULL == DevicePath) {\r
1499 return BDS_EFI_UNSUPPORT;\r
1500 }\r
1501\r
1502 TempDevicePath = DevicePath;\r
1503\r
1504 while (!IsDevicePathEndType (TempDevicePath)) {\r
1505 switch (DevicePathType (TempDevicePath)) {\r
1506 case BBS_DEVICE_PATH:\r
1507 return BDS_LEGACY_BBS_BOOT;\r
1508 case MEDIA_DEVICE_PATH:\r
1509 if (DevicePathSubType (TempDevicePath) == MEDIA_HARDDRIVE_DP) {\r
1510 return BDS_EFI_MEDIA_HD_BOOT;\r
1511 } else if (DevicePathSubType (TempDevicePath) == MEDIA_CDROM_DP) {\r
1512 return BDS_EFI_MEDIA_CDROM_BOOT;\r
1513 }\r
1514 break;\r
1515 case ACPI_DEVICE_PATH:\r
1516 Acpi = (ACPI_HID_DEVICE_PATH *) TempDevicePath;\r
1517 if (EISA_ID_TO_NUM (Acpi->HID) == 0x0604) {\r
1518 return BDS_EFI_ACPI_FLOPPY_BOOT;\r
1519 }\r
1520 break;\r
1521 case MESSAGING_DEVICE_PATH:\r
1522 //\r
a475bfa2 1523 // Get the last device path node\r
897f0eee 1524 //\r
1525 LastDeviceNode = NextDevicePathNode (TempDevicePath);\r
a475bfa2 1526 if (DevicePathSubType(LastDeviceNode) == MSG_DEVICE_LOGICAL_UNIT_DP) {\r
1527 //\r
1528 // if the next node type is Device Logical Unit, which specify the Logical Unit Number (LUN),\r
1529 // skit it\r
1530 //\r
1531 LastDeviceNode = NextDevicePathNode (LastDeviceNode);\r
1532 }\r
1533 //\r
1534 // if the device path not only point to driver device, it is not a messaging device path,\r
1535 //\r
897f0eee 1536 if (!IsDevicePathEndType (LastDeviceNode)) {\r
a475bfa2 1537 break; \r
897f0eee 1538 }\r
1539\r
1540 if (DevicePathSubType(TempDevicePath) == MSG_ATAPI_DP) {\r
1541 return BDS_EFI_MESSAGE_ATAPI_BOOT;\r
1542 } else if (DevicePathSubType(TempDevicePath) == MSG_USB_DP) {\r
1543 return BDS_EFI_MESSAGE_USB_DEVICE_BOOT;\r
1544 } else if (DevicePathSubType(TempDevicePath) == MSG_SCSI_DP) {\r
1545 return BDS_EFI_MESSAGE_SCSI_BOOT;\r
1546 }\r
1547 return BDS_EFI_MESSAGE_MISC_BOOT;\r
1548 default:\r
1549 break;\r
1550 }\r
1551 TempDevicePath = NextDevicePathNode (TempDevicePath);\r
1552 }\r
1553\r
1554 return BDS_EFI_UNSUPPORT;\r
1555}\r
1556\r
897f0eee 1557/**\r
3fd8027e 1558 Check whether the Device path in a boot option point to a valid bootable device,\r
897f0eee 1559 And if CheckMedia is true, check the device is ready to boot now.\r
1560\r
262b0668 1561 @param DevPath the Device path in a boot option\r
1562 @param CheckMedia if true, check the device is ready to boot now.\r
897f0eee 1563\r
3fd8027e 1564 @retval TRUE the Device path is valid\r
1565 @retval FALSE the Device path is invalid .\r
897f0eee 1566\r
1567**/\r
1568BOOLEAN\r
1569EFIAPI\r
1570BdsLibIsValidEFIBootOptDevicePath (\r
1571 IN EFI_DEVICE_PATH_PROTOCOL *DevPath,\r
1572 IN BOOLEAN CheckMedia\r
1573 )\r
1574{\r
1575 EFI_STATUS Status;\r
1576 EFI_HANDLE Handle;\r
1577 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;\r
1578 EFI_DEVICE_PATH_PROTOCOL *LastDeviceNode;\r
1579 EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
1580\r
1581 TempDevicePath = DevPath;\r
1582 LastDeviceNode = DevPath;\r
ec8cd35c 1583 \r
897f0eee 1584 //\r
1585 // Check if it's a valid boot option for network boot device\r
1586 // Only check if there is SimpleNetworkProtocol installed. If yes, that means\r
1587 // there is the network card there.\r
1588 //\r
1589 Status = gBS->LocateDevicePath (\r
1590 &gEfiSimpleNetworkProtocolGuid,\r
1591 &TempDevicePath,\r
1592 &Handle\r
1593 );\r
1594 if (EFI_ERROR (Status)) {\r
1595 //\r
1596 // Device not present so see if we need to connect it\r
1597 //\r
1598 TempDevicePath = DevPath;\r
1599 BdsLibConnectDevicePath (TempDevicePath);\r
1600 Status = gBS->LocateDevicePath (\r
1601 &gEfiSimpleNetworkProtocolGuid,\r
1602 &TempDevicePath,\r
1603 &Handle\r
1604 );\r
1605 }\r
ec8cd35c 1606 \r
897f0eee 1607 if (!EFI_ERROR (Status)) {\r
1608 if (CheckMedia) {\r
1609 //\r
1610 // Test if it is ready to boot now\r
1611 //\r
1612 if (BdsLibNetworkBootWithMediaPresent(DevPath)) {\r
1613 return TRUE;\r
1614 }\r
1615 } else {\r
1616 return TRUE;\r
1617 }\r
1618 }\r
1619\r
1620 //\r
1621 // If the boot option point to a file, it is a valid EFI boot option,\r
1622 // and assume it is ready to boot now\r
1623 //\r
1232b214 1624 while (!IsDevicePathEnd (TempDevicePath)) {\r
897f0eee 1625 LastDeviceNode = TempDevicePath;\r
1232b214 1626 TempDevicePath = NextDevicePathNode (TempDevicePath);\r
897f0eee 1627 }\r
1628 if ((DevicePathType (LastDeviceNode) == MEDIA_DEVICE_PATH) &&\r
1629 (DevicePathSubType (LastDeviceNode) == MEDIA_FILEPATH_DP)) {\r
1630 return TRUE;\r
1631 }\r
1632\r
1633 //\r
a475bfa2 1634 // Check if it's a valid boot option for internal Shell\r
897f0eee 1635 //\r
1636 if (EfiGetNameGuidFromFwVolDevicePathNode ((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) LastDeviceNode) != NULL) {\r
a475bfa2 1637 //\r
1638 // If the boot option point to Internal FV shell, make sure it is valid\r
1639 //\r
1640 TempDevicePath = DevPath; \r
1641 Status = BdsLibUpdateFvFileDevicePath (&TempDevicePath, &gEfiShellFileGuid);\r
1642 if (Status == EFI_ALREADY_STARTED) {\r
1643 return TRUE;\r
1644 } else {\r
1645 if (Status == EFI_SUCCESS) {\r
676df92c 1646 FreePool (TempDevicePath); \r
a475bfa2 1647 }\r
1648 return FALSE;\r
1649 }\r
897f0eee 1650 }\r
a475bfa2 1651 \r
897f0eee 1652 //\r
1653 // If the boot option point to a blockIO device, no matter whether or not it is a removeable device, it is a valid EFI boot option\r
1654 //\r
1655 TempDevicePath = DevPath;\r
1656 Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &TempDevicePath, &Handle);\r
1657 if (EFI_ERROR (Status)) {\r
1658 //\r
1659 // Device not present so see if we need to connect it\r
1660 //\r
1661 Status = BdsLibConnectDevicePath (DevPath);\r
1662 if (!EFI_ERROR (Status)) {\r
1663 //\r
1664 // Try again to get the Block Io protocol after we did the connect\r
1665 //\r
1666 TempDevicePath = DevPath;\r
1667 Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &TempDevicePath, &Handle);\r
1668 }\r
1669 }\r
ec8cd35c 1670 \r
897f0eee 1671 if (!EFI_ERROR (Status)) {\r
1672 Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **)&BlockIo);\r
1673 if (!EFI_ERROR (Status)) {\r
1674 if (CheckMedia) {\r
1675 //\r
1676 // Test if it is ready to boot now\r
1677 //\r
1678 if (BdsLibGetBootableHandle (DevPath) != NULL) {\r
1679 return TRUE;\r
1680 }\r
1681 } else {\r
1682 return TRUE;\r
1683 }\r
1684 }\r
1685 } else {\r
1686 //\r
1687 // if the boot option point to a simple file protocol which does not consume block Io protocol, it is also a valid EFI boot option,\r
1688 //\r
1689 Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &TempDevicePath, &Handle);\r
1690 if (!EFI_ERROR (Status)) {\r
1691 if (CheckMedia) {\r
1692 //\r
1693 // Test if it is ready to boot now\r
1694 //\r
1695 if (BdsLibGetBootableHandle (DevPath) != NULL) {\r
1696 return TRUE;\r
1697 }\r
1698 } else {\r
1699 return TRUE;\r
1700 }\r
1701 }\r
1702 }\r
1703\r
1704 return FALSE;\r
1705}\r
1706\r
1707\r
1708/**\r
1709 According to a file guild, check a Fv file device path is valid. If it is invalid,\r
1710 try to return the valid device path.\r
3fd8027e 1711 FV address maybe changes for memory layout adjust from time to time, use this function\r
897f0eee 1712 could promise the Fv file device path is right.\r
1713\r
1714 @param DevicePath on input, the Fv file device path need to check on\r
1715 output, the updated valid Fv file device path\r
1716 @param FileGuid the Fv file guild\r
1717\r
1718 @retval EFI_INVALID_PARAMETER the input DevicePath or FileGuid is invalid\r
1719 parameter\r
1720 @retval EFI_UNSUPPORTED the input DevicePath does not contain Fv file\r
1721 guild at all\r
1722 @retval EFI_ALREADY_STARTED the input DevicePath has pointed to Fv file, it is\r
1723 valid\r
1724 @retval EFI_SUCCESS has successfully updated the invalid DevicePath,\r
1725 and return the updated device path in DevicePath\r
1726\r
1727**/\r
1728EFI_STATUS\r
1729EFIAPI\r
1730BdsLibUpdateFvFileDevicePath (\r
1731 IN OUT EFI_DEVICE_PATH_PROTOCOL ** DevicePath,\r
262b0668 1732 IN EFI_GUID *FileGuid\r
897f0eee 1733 )\r
1734{\r
1735 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;\r
1736 EFI_DEVICE_PATH_PROTOCOL *LastDeviceNode;\r
1737 EFI_STATUS Status;\r
1738 EFI_GUID *GuidPoint;\r
1739 UINTN Index;\r
1740 UINTN FvHandleCount;\r
1741 EFI_HANDLE *FvHandleBuffer;\r
1742 EFI_FV_FILETYPE Type;\r
1743 UINTN Size;\r
1744 EFI_FV_FILE_ATTRIBUTES Attributes;\r
1745 UINT32 AuthenticationStatus;\r
1746 BOOLEAN FindFvFile;\r
1747 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;\r
1748 EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;\r
1749 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FvFileNode;\r
1750 EFI_HANDLE FoundFvHandle;\r
1751 EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;\r
1752\r
1753 if ((DevicePath == NULL) || (*DevicePath == NULL)) {\r
1754 return EFI_INVALID_PARAMETER;\r
1755 }\r
1756 if (FileGuid == NULL) {\r
1757 return EFI_INVALID_PARAMETER;\r
1758 }\r
ec8cd35c 1759 \r
897f0eee 1760 //\r
1761 // Check whether the device path point to the default the input Fv file\r
1762 //\r
1763 TempDevicePath = *DevicePath;\r
1764 LastDeviceNode = TempDevicePath;\r
1232b214 1765 while (!IsDevicePathEnd (TempDevicePath)) {\r
897f0eee 1766 LastDeviceNode = TempDevicePath;\r
1232b214 1767 TempDevicePath = NextDevicePathNode (TempDevicePath);\r
897f0eee 1768 }\r
1769 GuidPoint = EfiGetNameGuidFromFwVolDevicePathNode (\r
1770 (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) LastDeviceNode\r
1771 );\r
1772 if (GuidPoint == NULL) {\r
1773 //\r
1774 // if this option does not points to a Fv file, just return EFI_UNSUPPORTED\r
1775 //\r
1776 return EFI_UNSUPPORTED;\r
1777 }\r
1778 if (!CompareGuid (GuidPoint, FileGuid)) {\r
1779 //\r
1780 // If the Fv file is not the input file guid, just return EFI_UNSUPPORTED\r
1781 //\r
1782 return EFI_UNSUPPORTED;\r
1783 }\r
1784\r
1785 //\r
1786 // Check whether the input Fv file device path is valid\r
1787 //\r
1788 TempDevicePath = *DevicePath;\r
1789 FoundFvHandle = NULL;\r
1790 Status = gBS->LocateDevicePath (\r
1791 &gEfiFirmwareVolume2ProtocolGuid,\r
1792 &TempDevicePath,\r
1793 &FoundFvHandle\r
1794 );\r
1795 if (!EFI_ERROR (Status)) {\r
1796 Status = gBS->HandleProtocol (\r
1797 FoundFvHandle,\r
1798 &gEfiFirmwareVolume2ProtocolGuid,\r
1799 (VOID **) &Fv\r
1800 );\r
1801 if (!EFI_ERROR (Status)) {\r
1802 //\r
1803 // Set FV ReadFile Buffer as NULL, only need to check whether input Fv file exist there\r
1804 //\r
1805 Status = Fv->ReadFile (\r
1806 Fv,\r
1807 FileGuid,\r
1808 NULL,\r
1809 &Size,\r
1810 &Type,\r
1811 &Attributes,\r
1812 &AuthenticationStatus\r
1813 );\r
1814 if (!EFI_ERROR (Status)) {\r
1815 return EFI_ALREADY_STARTED;\r
1816 }\r
1817 }\r
1818 }\r
1819\r
1820 //\r
1821 // Look for the input wanted FV file in current FV\r
1822 // First, try to look for in Bds own FV. Bds and input wanted FV file usually are in the same FV\r
1823 //\r
1824 FindFvFile = FALSE;\r
1825 FoundFvHandle = NULL;\r
1826 Status = gBS->HandleProtocol (\r
1827 mBdsImageHandle,\r
1828 &gEfiLoadedImageProtocolGuid,\r
1829 (VOID **) &LoadedImage\r
1830 );\r
1831 if (!EFI_ERROR (Status)) {\r
1832 Status = gBS->HandleProtocol (\r
1833 LoadedImage->DeviceHandle,\r
1834 &gEfiFirmwareVolume2ProtocolGuid,\r
1835 (VOID **) &Fv\r
1836 );\r
1837 if (!EFI_ERROR (Status)) {\r
1838 Status = Fv->ReadFile (\r
1839 Fv,\r
1840 FileGuid,\r
1841 NULL,\r
1842 &Size,\r
1843 &Type,\r
1844 &Attributes,\r
1845 &AuthenticationStatus\r
1846 );\r
1847 if (!EFI_ERROR (Status)) {\r
1848 FindFvFile = TRUE;\r
1849 FoundFvHandle = LoadedImage->DeviceHandle;\r
1850 }\r
1851 }\r
1852 }\r
1853 //\r
1854 // Second, if fail to find, try to enumerate all FV\r
1855 //\r
1856 if (!FindFvFile) {\r
a475bfa2 1857 FvHandleBuffer = NULL;\r
897f0eee 1858 gBS->LocateHandleBuffer (\r
1859 ByProtocol,\r
1860 &gEfiFirmwareVolume2ProtocolGuid,\r
1861 NULL,\r
1862 &FvHandleCount,\r
1863 &FvHandleBuffer\r
1864 );\r
1865 for (Index = 0; Index < FvHandleCount; Index++) {\r
1866 gBS->HandleProtocol (\r
1867 FvHandleBuffer[Index],\r
1868 &gEfiFirmwareVolume2ProtocolGuid,\r
1869 (VOID **) &Fv\r
1870 );\r
1871\r
1872 Status = Fv->ReadFile (\r
1873 Fv,\r
1874 FileGuid,\r
1875 NULL,\r
1876 &Size,\r
1877 &Type,\r
1878 &Attributes,\r
1879 &AuthenticationStatus\r
1880 );\r
1881 if (EFI_ERROR (Status)) {\r
1882 //\r
1883 // Skip if input Fv file not in the FV\r
1884 //\r
1885 continue;\r
1886 }\r
1887 FindFvFile = TRUE;\r
1888 FoundFvHandle = FvHandleBuffer[Index];\r
1889 break;\r
1890 }\r
676df92c 1891\r
1892 if (FvHandleBuffer != NULL) {\r
1893 FreePool (FvHandleBuffer); \r
1894 }\r
897f0eee 1895 }\r
1896\r
1897 if (FindFvFile) {\r
1898 //\r
1899 // Build the shell device path\r
1900 //\r
1901 NewDevicePath = DevicePathFromHandle (FoundFvHandle);\r
1902 EfiInitializeFwVolDevicepathNode (&FvFileNode, FileGuid);\r
1903 NewDevicePath = AppendDevicePathNode (NewDevicePath, (EFI_DEVICE_PATH_PROTOCOL *) &FvFileNode);\r
1904 *DevicePath = NewDevicePath;\r
1905 return EFI_SUCCESS;\r
1906 }\r
1907 return EFI_NOT_FOUND;\r
1908}\r