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