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