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