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