Remove unnecessary TPL operations in BDS module & library.
[people/mcb30/edk2.git] / edk2 / MdeModulePkg / Library / GenericBdsLib / BdsBoot.c
1 /** @file\r
2   BDS Lib functions which relate with create or process the boot\r
3   option.\r
4 \r
5 Copyright (c) 2004 - 2008, Intel Corporation. <BR>\r
6 All rights reserved. This program and the accompanying materials\r
7 are licensed and made available under the terms and conditions of the BSD License\r
8 which accompanies this distribution.  The full text of the license may be found at\r
9 http://opensource.org/licenses/bsd-license.php\r
10 \r
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13 \r
14 **/\r
15 \r
16 #include "InternalBdsLib.h"\r
17 \r
18 BOOLEAN 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
24 EFI_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
38 EFI_STATUS\r
39 BdsLibDoLegacyBoot (\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
90 EFI_STATUS\r
91 EFIAPI\r
92 BdsLibBootViaBootOption (\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     // free the temporary device path created by BdsLibUpdateFvFileDevicePath()\r
188     //\r
189     SafeFreePool (DevicePath); \r
190     DevicePath = Option->DevicePath;\r
191   }\r
192 \r
193   DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Booting %S\n", Option->Description));\r
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
221     FilePath = FileDevicePath (Handle, (CONST CHAR16*)PcdGetPtr(PcdDefaultBootFileName));\r
222     if (FilePath != NULL) {\r
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
271 Done:\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
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
301 EFI_DEVICE_PATH_PROTOCOL *\r
302 EFIAPI\r
303 BdsExpandPartitionPartialDevicePathToFull (\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
334                       \r
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
361       SafeFreePool(Instance);\r
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
369       DevicePath     = NextDevicePathNode ((EFI_DEVICE_PATH_PROTOCOL *) HardDriveDevicePath);\r
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
380         CachedDevicePath  = BdsLibDelPartMatchInstance (CachedDevicePath, Instance );\r
381         SafeFreePool (TempNewDevicePath);\r
382         \r
383         //\r
384         // Second, append the remaining parth after the matched instance\r
385         //\r
386         TempNewDevicePath = CachedDevicePath;\r
387         CachedDevicePath = AppendDevicePathInstance (Instance, CachedDevicePath );\r
388         SafeFreePool (TempNewDevicePath);\r
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
400       \r
401       SafeFreePool (Instance);\r
402       SafeFreePool (CachedDevicePath);\r
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
447           SafeFreePool(TempNewDevicePath);\r
448 \r
449           TempNewDevicePath = CachedDevicePath;\r
450           CachedDevicePath = AppendDevicePathInstance (BlockIoDevicePath, CachedDevicePath);\r
451           SafeFreePool(TempNewDevicePath);\r
452         } else {\r
453           TempNewDevicePath = CachedDevicePath;\r
454           CachedDevicePath = AppendDevicePathInstance (BlockIoDevicePath, CachedDevicePath);\r
455           SafeFreePool(TempNewDevicePath);\r
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
498   \r
499   SafeFreePool (CachedDevicePath);\r
500   SafeFreePool (BlockIoBuffer);\r
501   return FullDevicePath;\r
502 }\r
503 \r
504 /**\r
505   Check whether there is a instance in BlockIoDevicePath, which contain multi device path\r
506   instances, has the same partition node with HardDriveDevicePath device path\r
507 \r
508   @param  BlockIoDevicePath      Multi device path instances which need to check\r
509   @param  HardDriveDevicePath    A device path which starts with a hard drive media\r
510                                  device path.\r
511 \r
512   @retval TRUE                   There is a matched device path instance FALSE\r
513   @retval FALSE                  There is no matched device path instance\r
514 \r
515 **/\r
516 BOOLEAN\r
517 EFIAPI\r
518 MatchPartitionDevicePathNode (\r
519   IN  EFI_DEVICE_PATH_PROTOCOL   *BlockIoDevicePath,\r
520   IN  HARDDRIVE_DEVICE_PATH      *HardDriveDevicePath\r
521   )\r
522 {\r
523   HARDDRIVE_DEVICE_PATH     *TmpHdPath;\r
524   HARDDRIVE_DEVICE_PATH     *TempPath;\r
525   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;\r
526   BOOLEAN                   Match;\r
527   EFI_DEVICE_PATH_PROTOCOL  *BlockIoHdDevicePathNode;\r
528 \r
529   if ((BlockIoDevicePath == NULL) || (HardDriveDevicePath == NULL)) {\r
530     return FALSE;\r
531   }\r
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   //\r
564   // Check for the match\r
565   //\r
566   if ((TmpHdPath->MBRType == TempPath->MBRType) &&\r
567       (TmpHdPath->SignatureType == TempPath->SignatureType)) {\r
568     switch (TmpHdPath->SignatureType) {\r
569     case SIGNATURE_TYPE_GUID:\r
570       Match = CompareGuid ((EFI_GUID *)TmpHdPath->Signature, (EFI_GUID *)TempPath->Signature);\r
571       break;\r
572     case SIGNATURE_TYPE_MBR:\r
573       Match = (BOOLEAN)(*((UINT32 *)(&(TmpHdPath->Signature[0]))) == *(UINT32 *)(&(TempPath->Signature[0])));\r
574       break;\r
575     default:\r
576       Match = FALSE;\r
577       break;\r
578     }\r
579   }\r
580 \r
581   return Match;\r
582 }\r
583 \r
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
596 EFI_STATUS\r
597 BdsLibDeleteOptionFromHandle (\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   //\r
619   // Check "BootOrder" variable, if no, means there is no any boot order.\r
620   //\r
621   BootOrder = BdsLibGetVariableAndSize (\r
622                 L"BootOrder",\r
623                 &gEfiGlobalVariableGuid,\r
624                 &BootOrderSize\r
625                 );\r
626   if (BootOrder == NULL) {\r
627     return EFI_NOT_FOUND;\r
628   }\r
629 \r
630   //\r
631   // Convert device handle to device path protocol instance\r
632   //\r
633   DevicePath = DevicePathFromHandle (Handle);\r
634   if (DevicePath == NULL) {\r
635     return EFI_NOT_FOUND;\r
636   }\r
637   DevicePathSize = GetDevicePathSize (DevicePath);\r
638 \r
639   //\r
640   // Loop all boot order variable and find the matching device path\r
641   //\r
642   Index = 0;\r
643   while (Index < BootOrderSize / sizeof (UINT16)) {\r
644     UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]);\r
645     BootOptionVar = BdsLibGetVariableAndSize (\r
646                       BootOption,\r
647                       &gEfiGlobalVariableGuid,\r
648                       &BootOptionSize\r
649                       );\r
650                       \r
651     if (BootOptionVar == NULL) {\r
652       SafeFreePool (BootOrder);\r
653       return EFI_OUT_OF_RESOURCES;\r
654     }\r
655 \r
656     TempPtr = BootOptionVar;\r
657     TempPtr += sizeof (UINT32) + sizeof (UINT16);\r
658     TempPtr += StrSize ((CHAR16 *) TempPtr);\r
659     OptionDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;\r
660     OptionDevicePathSize = GetDevicePathSize (OptionDevicePath);\r
661 \r
662     //\r
663     // Check whether the device path match\r
664     //\r
665     if ((OptionDevicePathSize == DevicePathSize) &&\r
666         (CompareMem (DevicePath, OptionDevicePath, DevicePathSize) == 0)) {\r
667       BdsDeleteBootOption (BootOrder[Index], BootOrder, &BootOrderSize);\r
668       SafeFreePool (BootOptionVar);\r
669       break;\r
670     }\r
671 \r
672     SafeFreePool (BootOptionVar);\r
673     Index++;\r
674   }\r
675 \r
676   //\r
677   // Adjust number of boot option for "BootOrder" variable.\r
678   //\r
679   Status = gRT->SetVariable (\r
680                   L"BootOrder",\r
681                   &gEfiGlobalVariableGuid,\r
682                   EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
683                   BootOrderSize,\r
684                   BootOrder\r
685                   );\r
686 \r
687   SafeFreePool (BootOrder);\r
688 \r
689   return Status;\r
690 }\r
691 \r
692 \r
693 /**\r
694   Delete all invalid EFI boot options. The probable invalid boot option could\r
695   be Removable media or Network boot device.\r
696 \r
697   @retval EFI_SUCCESS            Delete all invalid boot option success\r
698   @retval EFI_NOT_FOUND          Variable "BootOrder" is not found\r
699   @retval EFI_OUT_OF_RESOURCES   Lack of memory resource\r
700   @retval Other                  Error return value from SetVariable()\r
701 \r
702 **/\r
703 EFI_STATUS\r
704 BdsDeleteAllInvalidEfiBootOption (\r
705   VOID\r
706   )\r
707 {\r
708   UINT16                    *BootOrder;\r
709   UINT8                     *BootOptionVar;\r
710   UINTN                     BootOrderSize;\r
711   UINTN                     BootOptionSize;\r
712   EFI_STATUS                Status;\r
713   UINTN                     Index;\r
714   UINTN                     Index2;\r
715   UINT16                    BootOption[BOOT_OPTION_MAX_CHAR];\r
716   EFI_DEVICE_PATH_PROTOCOL  *OptionDevicePath;\r
717   UINT8                     *TempPtr;\r
718 \r
719   Status        = EFI_SUCCESS;\r
720   BootOrder     = NULL;\r
721   BootOrderSize = 0;\r
722 \r
723   //\r
724   // Check "BootOrder" variable firstly, this variable hold the number of boot options\r
725   //\r
726   BootOrder = BdsLibGetVariableAndSize (\r
727                 L"BootOrder",\r
728                 &gEfiGlobalVariableGuid,\r
729                 &BootOrderSize\r
730                 );\r
731   if (NULL == BootOrder) {\r
732     return EFI_NOT_FOUND;\r
733   }\r
734 \r
735   Index = 0;\r
736   while (Index < BootOrderSize / sizeof (UINT16)) {\r
737     UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]);\r
738     BootOptionVar = BdsLibGetVariableAndSize (\r
739                       BootOption,\r
740                       &gEfiGlobalVariableGuid,\r
741                       &BootOptionSize\r
742                       );\r
743     if (NULL == BootOptionVar) {\r
744       SafeFreePool (BootOrder);\r
745       return EFI_OUT_OF_RESOURCES;\r
746     }\r
747 \r
748     TempPtr = BootOptionVar;\r
749     TempPtr += sizeof (UINT32) + sizeof (UINT16);\r
750     TempPtr += StrSize ((CHAR16 *) TempPtr);\r
751     OptionDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;\r
752 \r
753     //\r
754     // Skip legacy boot option (BBS boot device)\r
755     //\r
756     if ((DevicePathType (OptionDevicePath) == BBS_DEVICE_PATH) &&\r
757         (DevicePathSubType (OptionDevicePath) == BBS_BBS_DP)) {\r
758       SafeFreePool (BootOptionVar);\r
759       Index++;\r
760       continue;\r
761     }\r
762 \r
763     if (!BdsLibIsValidEFIBootOptDevicePath (OptionDevicePath, FALSE)) {\r
764       //\r
765       // Delete this invalid boot option "Boot####"\r
766       //\r
767       Status = gRT->SetVariable (\r
768                       BootOption,\r
769                       &gEfiGlobalVariableGuid,\r
770                       EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
771                       0,\r
772                       NULL\r
773                       );\r
774       //\r
775       // Mark this boot option in boot order as deleted\r
776       //\r
777       BootOrder[Index] = 0xffff;\r
778     }\r
779 \r
780     SafeFreePool (BootOptionVar);\r
781     Index++;\r
782   }\r
783 \r
784   //\r
785   // Adjust boot order array\r
786   //\r
787   Index2 = 0;\r
788   for (Index = 0; Index < BootOrderSize / sizeof (UINT16); Index++) {\r
789     if (BootOrder[Index] != 0xffff) {\r
790       BootOrder[Index2] = BootOrder[Index];\r
791       Index2 ++;\r
792     }\r
793   }\r
794   Status = gRT->SetVariable (\r
795                   L"BootOrder",\r
796                   &gEfiGlobalVariableGuid,\r
797                   EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
798                   Index2 * sizeof (UINT16),\r
799                   BootOrder\r
800                   );\r
801 \r
802   SafeFreePool (BootOrder);\r
803 \r
804   return Status;\r
805 }\r
806 \r
807 \r
808 /**\r
809   This function will enumerate all possible boot device in the system,\r
810   it will only excute once of every boot.\r
811 \r
812   @param  BdsBootOptionList      The header of the link list which indexed all\r
813                                  current boot options\r
814 \r
815   @retval EFI_SUCCESS            Finished all the boot device enumerate and create\r
816                                  the boot option base on that boot device\r
817 \r
818 **/\r
819 EFI_STATUS\r
820 EFIAPI\r
821 BdsLibEnumerateAllBootOption (\r
822   IN OUT LIST_ENTRY          *BdsBootOptionList\r
823   )\r
824 {\r
825   EFI_STATUS                    Status;\r
826   UINT16                        FloppyNumber;\r
827   UINT16                        CdromNumber;\r
828   UINT16                        UsbNumber;\r
829   UINT16                        MiscNumber;\r
830   UINT16                        NonBlockNumber;\r
831   UINTN                         NumberBlockIoHandles;\r
832   EFI_HANDLE                    *BlockIoHandles;\r
833   EFI_BLOCK_IO_PROTOCOL         *BlkIo;\r
834   UINTN                         Index;\r
835   UINTN                         NumberSimpleNetworkHandles;\r
836   EFI_HANDLE                    *SimpleNetworkHandles;\r
837   UINTN                         FvHandleCount;\r
838   EFI_HANDLE                    *FvHandleBuffer;\r
839   EFI_FV_FILETYPE               Type;\r
840   UINTN                         Size;\r
841   EFI_FV_FILE_ATTRIBUTES        Attributes;\r
842   UINT32                        AuthenticationStatus;\r
843   EFI_FIRMWARE_VOLUME2_PROTOCOL  *Fv;\r
844   EFI_DEVICE_PATH_PROTOCOL     *DevicePath;\r
845   UINTN                         DevicePathType;\r
846   CHAR16                        Buffer[40];\r
847   EFI_HANDLE                    *FileSystemHandles;\r
848   UINTN                         NumberFileSystemHandles;\r
849   BOOLEAN                       NeedDelete;\r
850   EFI_IMAGE_DOS_HEADER          DosHeader;\r
851   EFI_IMAGE_OPTIONAL_HEADER_UNION       HdrData;\r
852   EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION   Hdr;\r
853 \r
854   FloppyNumber  = 0;\r
855   CdromNumber   = 0;\r
856   UsbNumber     = 0;\r
857   MiscNumber    = 0;\r
858   ZeroMem (Buffer, sizeof (Buffer));\r
859   \r
860   //\r
861   // If the boot device enumerate happened, just get the boot\r
862   // device from the boot order variable\r
863   //\r
864   if (mEnumBootDevice) {\r
865     BdsLibBuildOptionFromVar (BdsBootOptionList, L"BootOrder");\r
866     return EFI_SUCCESS;\r
867   }\r
868   \r
869   //\r
870   // Notes: this dirty code is to get the legacy boot option from the\r
871   // BBS table and create to variable as the EFI boot option, it should\r
872   // be removed after the CSM can provide legacy boot option directly\r
873   //\r
874   REFRESH_LEGACY_BOOT_OPTIONS;\r
875 \r
876   //\r
877   // Delete invalid boot option\r
878   //\r
879   BdsDeleteAllInvalidEfiBootOption ();\r
880   \r
881   //\r
882   // Parse removable media\r
883   //\r
884   gBS->LocateHandleBuffer (\r
885         ByProtocol,\r
886         &gEfiBlockIoProtocolGuid,\r
887         NULL,\r
888         &NumberBlockIoHandles,\r
889         &BlockIoHandles\r
890         );\r
891         \r
892   for (Index = 0; Index < NumberBlockIoHandles; Index++) {\r
893     Status = gBS->HandleProtocol (\r
894                     BlockIoHandles[Index],\r
895                     &gEfiBlockIoProtocolGuid,\r
896                     (VOID **) &BlkIo\r
897                     );\r
898     if (!EFI_ERROR (Status)) {\r
899       if (!BlkIo->Media->RemovableMedia) {\r
900         //\r
901         // skip the non-removable block devices\r
902         //\r
903         continue;\r
904       }\r
905     }\r
906     DevicePath  = DevicePathFromHandle (BlockIoHandles[Index]);\r
907     DevicePathType = BdsGetBootTypeFromDevicePath (DevicePath);\r
908 \r
909     switch (DevicePathType) {\r
910     case BDS_EFI_ACPI_FLOPPY_BOOT:\r
911       if (FloppyNumber == 0) {\r
912         UnicodeSPrint (Buffer, sizeof (Buffer), L"EFI Floppy");\r
913       } else {\r
914         UnicodeSPrint (Buffer, sizeof (Buffer), L"EFI Floppy %d", FloppyNumber);\r
915       }\r
916       BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer);\r
917       FloppyNumber++;\r
918       break;\r
919 \r
920     case BDS_EFI_MESSAGE_ATAPI_BOOT:\r
921       if (CdromNumber == 0) {\r
922         UnicodeSPrint (Buffer, sizeof (Buffer), L"EFI DVD/CDROM");\r
923       } else {\r
924         UnicodeSPrint (Buffer, sizeof (Buffer), L"EFI DVD/CDROM %d", CdromNumber);\r
925       }\r
926       BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer);\r
927       CdromNumber++;\r
928       break;\r
929 \r
930     case BDS_EFI_MESSAGE_USB_DEVICE_BOOT:\r
931       if (UsbNumber == 0) {\r
932         UnicodeSPrint (Buffer, sizeof (Buffer), L"EFI USB Device");\r
933       } else {\r
934         UnicodeSPrint (Buffer, sizeof (Buffer), L"EFI USB Device %d", UsbNumber);\r
935       }\r
936       BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer);\r
937       UsbNumber++;\r
938       break;\r
939 \r
940     case BDS_EFI_MESSAGE_SCSI_BOOT:\r
941       if (UsbNumber == 0) {\r
942         UnicodeSPrint (Buffer, sizeof (Buffer), L"EFI SCSI Device");\r
943       } else {\r
944         UnicodeSPrint (Buffer, sizeof (Buffer), L"EFI SCSI Device %d", UsbNumber);\r
945       }\r
946       BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer);\r
947       UsbNumber++;\r
948       break;\r
949 \r
950     case BDS_EFI_MESSAGE_MISC_BOOT:\r
951       if (MiscNumber == 0) {\r
952         UnicodeSPrint (Buffer, sizeof (Buffer), L"EFI Misc Device");\r
953       } else {\r
954         UnicodeSPrint (Buffer, sizeof (Buffer), L"EFI Misc Device %d", MiscNumber);\r
955       }\r
956       BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer);\r
957       MiscNumber++;\r
958       break;\r
959 \r
960     default:\r
961       break;\r
962     }\r
963   }\r
964 \r
965   if (NumberBlockIoHandles != 0) {\r
966     SafeFreePool (BlockIoHandles);\r
967   }\r
968 \r
969   //\r
970   // If there is simple file protocol which does not consume block Io protocol, create a boot option for it here.\r
971   //\r
972   NonBlockNumber = 0;\r
973   gBS->LocateHandleBuffer (\r
974         ByProtocol,\r
975         &gEfiSimpleFileSystemProtocolGuid,\r
976         NULL,\r
977         &NumberFileSystemHandles,\r
978         &FileSystemHandles\r
979         );\r
980   for (Index = 0; Index < NumberFileSystemHandles; Index++) {\r
981     Status = gBS->HandleProtocol (\r
982                     FileSystemHandles[Index],\r
983                     &gEfiBlockIoProtocolGuid,\r
984                     (VOID **) &BlkIo\r
985                     );\r
986      if (!EFI_ERROR (Status)) {\r
987       //\r
988       //  Skip if the file system handle supports a BlkIo protocol,\r
989       //\r
990       continue;\r
991     }\r
992 \r
993     //\r
994     // Do the removable Media thing. \EFI\BOOT\boot{machinename}.EFI\r
995     //  machinename is ia32, ia64, x64, ...\r
996     //\r
997     Hdr.Union = &HdrData;\r
998     NeedDelete = TRUE;\r
999     Status     = BdsLibGetImageHeader (\r
1000                    FileSystemHandles[Index],\r
1001                    (CHAR16*)PcdGetPtr (PcdDefaultBootFileName),\r
1002                    &DosHeader,\r
1003                    Hdr\r
1004                    );\r
1005     if (!EFI_ERROR (Status) &&\r
1006         EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Hdr.Pe32->FileHeader.Machine) &&\r
1007         Hdr.Pe32->OptionalHeader.Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) {\r
1008       NeedDelete = FALSE;\r
1009     }\r
1010 \r
1011     if (NeedDelete) {\r
1012       //\r
1013       // No such file or the file is not a EFI application, delete this boot option\r
1014       //\r
1015       BdsLibDeleteOptionFromHandle (FileSystemHandles[Index]);\r
1016     } else {\r
1017       if (NonBlockNumber == 0) {\r
1018         UnicodeSPrint (Buffer, sizeof (Buffer), L"EFI Non-Block Boot Device");\r
1019       } else {\r
1020         UnicodeSPrint (Buffer, sizeof (Buffer), L"EFI Non-Block Boot Device %d", NonBlockNumber);\r
1021       }\r
1022       BdsLibBuildOptionFromHandle (FileSystemHandles[Index], BdsBootOptionList, Buffer);\r
1023       NonBlockNumber++;\r
1024     }\r
1025   }\r
1026 \r
1027   if (NumberFileSystemHandles != 0) {\r
1028     SafeFreePool (FileSystemHandles);\r
1029   }\r
1030 \r
1031   //\r
1032   // Parse Network Boot Device\r
1033   //\r
1034   gBS->LocateHandleBuffer (\r
1035         ByProtocol,\r
1036         &gEfiSimpleNetworkProtocolGuid,\r
1037         NULL,\r
1038         &NumberSimpleNetworkHandles,\r
1039         &SimpleNetworkHandles\r
1040         );\r
1041   for (Index = 0; Index < NumberSimpleNetworkHandles; Index++) {\r
1042     if (Index == 0) {\r
1043       UnicodeSPrint (Buffer, sizeof (Buffer), L"EFI Network");\r
1044     } else {\r
1045       UnicodeSPrint (Buffer, sizeof (Buffer), L"EFI Network %d", Index);\r
1046     }\r
1047     BdsLibBuildOptionFromHandle (SimpleNetworkHandles[Index], BdsBootOptionList, Buffer);\r
1048   }\r
1049 \r
1050   if (NumberSimpleNetworkHandles != 0) {\r
1051     SafeFreePool (SimpleNetworkHandles);\r
1052   }\r
1053 \r
1054   //\r
1055   // Check if we have on flash shell\r
1056   //\r
1057   gBS->LocateHandleBuffer (\r
1058         ByProtocol,\r
1059         &gEfiFirmwareVolume2ProtocolGuid,\r
1060         NULL,\r
1061         &FvHandleCount,\r
1062         &FvHandleBuffer\r
1063         );\r
1064   for (Index = 0; Index < FvHandleCount; Index++) {\r
1065     //\r
1066     // Only care the dispatched FV. If no dispatch protocol on the FV, it is not dispatched, then skip it.\r
1067     //\r
1068     Status = gBS->HandleProtocol (\r
1069                     FvHandleBuffer[Index],\r
1070                     &gEfiFirmwareVolumeDispatchProtocolGuid,\r
1071                     (VOID **) &Fv\r
1072                     );\r
1073     if (EFI_ERROR (Status)) {\r
1074       continue;\r
1075     }\r
1076     \r
1077     gBS->HandleProtocol (\r
1078           FvHandleBuffer[Index],\r
1079           &gEfiFirmwareVolume2ProtocolGuid,\r
1080           (VOID **) &Fv\r
1081           );\r
1082 \r
1083     Status = Fv->ReadFile (\r
1084                   Fv,\r
1085                   &gEfiShellFileGuid,\r
1086                   NULL,\r
1087                   &Size,\r
1088                   &Type,\r
1089                   &Attributes,\r
1090                   &AuthenticationStatus\r
1091                   );\r
1092     if (EFI_ERROR (Status)) {\r
1093       //\r
1094       // Skip if no shell file in the FV\r
1095       //\r
1096       continue;\r
1097     }\r
1098     //\r
1099     // Build the shell boot option\r
1100     //\r
1101     BdsLibBuildOptionFromShell (FvHandleBuffer[Index], BdsBootOptionList);\r
1102   }\r
1103 \r
1104   if (FvHandleCount != 0) {\r
1105     SafeFreePool (FvHandleBuffer);\r
1106   }\r
1107   //\r
1108   // Make sure every boot only have one time\r
1109   // boot device enumerate\r
1110   //\r
1111   BdsLibBuildOptionFromVar (BdsBootOptionList, L"BootOrder");\r
1112   mEnumBootDevice = TRUE;\r
1113 \r
1114   return EFI_SUCCESS;\r
1115 }\r
1116 \r
1117 /**\r
1118   Build the boot option with the handle parsed in.\r
1119 \r
1120   @param  Handle                 The handle which present the device path to create\r
1121                                  boot option\r
1122   @param  BdsBootOptionList      The header of the link list which indexed all\r
1123                                  current boot options\r
1124   @param  String                 Boot option name.\r
1125 \r
1126 **/\r
1127 VOID\r
1128 EFIAPI\r
1129 BdsLibBuildOptionFromHandle (\r
1130   IN  EFI_HANDLE                 Handle,\r
1131   IN  LIST_ENTRY                 *BdsBootOptionList,\r
1132   IN  CHAR16                     *String\r
1133   )\r
1134 {\r
1135   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;\r
1136 \r
1137   DevicePath  = DevicePathFromHandle (Handle);\r
1138 \r
1139   //\r
1140   // Create and register new boot option\r
1141   //\r
1142   BdsLibRegisterNewOption (BdsBootOptionList, DevicePath, String, L"BootOrder");\r
1143 }\r
1144 \r
1145 \r
1146 /**\r
1147   Build the on flash shell boot option with the handle parsed in.\r
1148 \r
1149   @param  Handle                 The handle which present the device path to create\r
1150                                  on flash shell boot option\r
1151   @param  BdsBootOptionList      The header of the link list which indexed all\r
1152                                  current boot options\r
1153 \r
1154 **/\r
1155 VOID\r
1156 EFIAPI\r
1157 BdsLibBuildOptionFromShell (\r
1158   IN EFI_HANDLE                  Handle,\r
1159   IN OUT LIST_ENTRY              *BdsBootOptionList\r
1160   )\r
1161 {\r
1162   EFI_DEVICE_PATH_PROTOCOL          *DevicePath;\r
1163   MEDIA_FW_VOL_FILEPATH_DEVICE_PATH ShellNode;\r
1164 \r
1165   DevicePath = DevicePathFromHandle (Handle);\r
1166 \r
1167   //\r
1168   // Build the shell device path\r
1169   //\r
1170   EfiInitializeFwVolDevicepathNode (&ShellNode, &gEfiShellFileGuid);\r
1171 \r
1172   DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *) &ShellNode);\r
1173 \r
1174   //\r
1175   // Create and register the shell boot option\r
1176   //\r
1177   BdsLibRegisterNewOption (BdsBootOptionList, DevicePath, L"EFI Internal Shell", L"BootOrder");\r
1178 \r
1179 }\r
1180 \r
1181 /**\r
1182   Boot from the EFI1.1 spec defined "BootNext" variable\r
1183 \r
1184 **/\r
1185 VOID\r
1186 EFIAPI\r
1187 BdsLibBootNext (\r
1188   VOID\r
1189   )\r
1190 {\r
1191   UINT16            *BootNext;\r
1192   UINTN             BootNextSize;\r
1193   CHAR16            Buffer[20];\r
1194   BDS_COMMON_OPTION *BootOption;\r
1195   LIST_ENTRY        TempList;\r
1196   UINTN             ExitDataSize;\r
1197   CHAR16            *ExitData;\r
1198 \r
1199   //\r
1200   // Init the boot option name buffer and temp link list\r
1201   //\r
1202   InitializeListHead (&TempList);\r
1203   ZeroMem (Buffer, sizeof (Buffer));\r
1204 \r
1205   BootNext = BdsLibGetVariableAndSize (\r
1206               L"BootNext",\r
1207               &gEfiGlobalVariableGuid,\r
1208               &BootNextSize\r
1209               );\r
1210 \r
1211   //\r
1212   // Clear the boot next variable first\r
1213   //\r
1214   if (BootNext != NULL) {\r
1215     gRT->SetVariable (\r
1216           L"BootNext",\r
1217           &gEfiGlobalVariableGuid,\r
1218           EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
1219           0,\r
1220           BootNext\r
1221           );\r
1222 \r
1223     //\r
1224     // Start to build the boot option and try to boot\r
1225     //\r
1226     UnicodeSPrint (Buffer, sizeof (Buffer), L"Boot%04x", *BootNext);\r
1227     BootOption = BdsLibVariableToOption (&TempList, Buffer);\r
1228     BdsLibConnectDevicePath (BootOption->DevicePath);\r
1229     BdsLibBootViaBootOption (BootOption, BootOption->DevicePath, &ExitDataSize, &ExitData);\r
1230   }\r
1231 \r
1232 }\r
1233 \r
1234 /**\r
1235   Return the bootable media handle.\r
1236   First, check the device is connected\r
1237   Second, check whether the device path point to a device which support SimpleFileSystemProtocol,\r
1238   Third, detect the the default boot file in the Media, and return the removable Media handle.\r
1239 \r
1240   @param  DevicePath             Device Path to a  bootable device\r
1241 \r
1242   @retval NULL                   The device path points to an EFI bootable Media\r
1243   @retval NULL                   The media on the DevicePath is not bootable\r
1244 \r
1245 **/\r
1246 EFI_HANDLE\r
1247 EFIAPI\r
1248 BdsLibGetBootableHandle (\r
1249   IN  EFI_DEVICE_PATH_PROTOCOL      *DevicePath\r
1250   )\r
1251 {\r
1252   EFI_STATUS                      Status;\r
1253   EFI_DEVICE_PATH_PROTOCOL        *UpdatedDevicePath;\r
1254   EFI_DEVICE_PATH_PROTOCOL        *DupDevicePath;\r
1255   EFI_HANDLE                      Handle;\r
1256   EFI_BLOCK_IO_PROTOCOL           *BlockIo;\r
1257   VOID                            *Buffer;\r
1258   EFI_DEVICE_PATH_PROTOCOL        *TempDevicePath;\r
1259   UINTN                           Size;\r
1260   UINTN                           TempSize;\r
1261   EFI_HANDLE                      ReturnHandle;\r
1262   EFI_HANDLE                      *SimpleFileSystemHandles;\r
1263 \r
1264   UINTN                           NumberSimpleFileSystemHandles;\r
1265   UINTN                           Index;\r
1266   EFI_IMAGE_DOS_HEADER            DosHeader;\r
1267   EFI_IMAGE_OPTIONAL_HEADER_UNION       HdrData;\r
1268   EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION   Hdr;\r
1269 \r
1270   UpdatedDevicePath = DevicePath;\r
1271   \r
1272   //\r
1273   // Check whether the device is connected\r
1274   //\r
1275   Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &UpdatedDevicePath, &Handle);\r
1276   if (EFI_ERROR (Status)) {\r
1277     //\r
1278     // Skip the case that the boot option point to a simple file protocol which does not consume block Io protocol,\r
1279     //\r
1280     Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &UpdatedDevicePath, &Handle);\r
1281     if (EFI_ERROR (Status)) {\r
1282       //\r
1283       // Fail to find the proper BlockIo and simple file protocol, maybe because device not present,  we need to connect it firstly\r
1284       //\r
1285       UpdatedDevicePath = DevicePath;\r
1286       Status            = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &UpdatedDevicePath, &Handle);\r
1287       gBS->ConnectController (Handle, NULL, NULL, TRUE);\r
1288     }\r
1289   } else {\r
1290     //\r
1291     // Get BlockIo protocal and check removable attribute\r
1292     //\r
1293     Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **)&BlockIo);\r
1294     //\r
1295     // Issue a dummy read to the device to check for media change.\r
1296     // When the removable media is changed, any Block IO read/write will\r
1297     // cause the BlockIo protocol be reinstalled and EFI_MEDIA_CHANGED is\r
1298     // returned. After the Block IO protocol is reinstalled, subsequent\r
1299     // Block IO read/write will success.\r
1300     //\r
1301     Buffer = AllocatePool (BlockIo->Media->BlockSize);\r
1302     if (Buffer != NULL) {\r
1303       BlockIo->ReadBlocks (\r
1304                BlockIo,\r
1305                BlockIo->Media->MediaId,\r
1306                0,\r
1307                BlockIo->Media->BlockSize,\r
1308                Buffer\r
1309                );\r
1310       SafeFreePool(Buffer);\r
1311     }\r
1312   }\r
1313 \r
1314   //\r
1315   // Detect the the default boot file from removable Media\r
1316   //\r
1317 \r
1318   //\r
1319   // 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
1320   // Try to locate the USB node device path first, if fail then use its previour PCI node to search\r
1321   //\r
1322   DupDevicePath = DuplicateDevicePath (DevicePath);\r
1323   UpdatedDevicePath = DupDevicePath;\r
1324   Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &UpdatedDevicePath, &Handle);\r
1325   //\r
1326   // if the resulting device path point to a usb node, and the usb node is a dummy node, should only let device path only point to the previous Pci node\r
1327   // Acpi()/Pci()/Usb() --> Acpi()/Pci()\r
1328   //\r
1329   if ((DevicePathType (UpdatedDevicePath) == MESSAGING_DEVICE_PATH) &&\r
1330       (DevicePathSubType (UpdatedDevicePath) == MSG_USB_DP)) {\r
1331     //\r
1332     // Remove the usb node, let the device path only point to PCI node\r
1333     //\r
1334     SetDevicePathEndNode (UpdatedDevicePath);\r
1335     UpdatedDevicePath = DupDevicePath;\r
1336   } else {\r
1337     UpdatedDevicePath = DevicePath;\r
1338   }\r
1339 \r
1340   //\r
1341   // Get the device path size of boot option\r
1342   //\r
1343   Size = GetDevicePathSize(UpdatedDevicePath) - sizeof (EFI_DEVICE_PATH_PROTOCOL); // minus the end node\r
1344   ReturnHandle = NULL;\r
1345   gBS->LocateHandleBuffer (\r
1346       ByProtocol,\r
1347       &gEfiSimpleFileSystemProtocolGuid,\r
1348       NULL,\r
1349       &NumberSimpleFileSystemHandles,\r
1350       &SimpleFileSystemHandles\r
1351       );\r
1352   for (Index = 0; Index < NumberSimpleFileSystemHandles; Index++) {\r
1353     //\r
1354     // Get the device path size of SimpleFileSystem handle\r
1355     //\r
1356     TempDevicePath = DevicePathFromHandle (SimpleFileSystemHandles[Index]);\r
1357     TempSize = GetDevicePathSize (TempDevicePath)- sizeof (EFI_DEVICE_PATH_PROTOCOL); // minus the end node\r
1358     //\r
1359     // Check whether the device path of boot option is part of the  SimpleFileSystem handle's device path\r
1360     //\r
1361     if (Size <= TempSize && CompareMem (TempDevicePath, UpdatedDevicePath, Size)==0) {\r
1362       //\r
1363       // Load the default boot file \EFI\BOOT\boot{machinename}.EFI from removable Media\r
1364       //  machinename is ia32, ia64, x64, ...\r
1365       //\r
1366       Hdr.Union = &HdrData;\r
1367       Status = BdsLibGetImageHeader (\r
1368                  SimpleFileSystemHandles[Index],\r
1369                  (CHAR16*)PcdGetPtr(PcdDefaultBootFileName),\r
1370                  &DosHeader,\r
1371                  Hdr\r
1372                  );\r
1373       if (!EFI_ERROR (Status) &&\r
1374         EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Hdr.Pe32->FileHeader.Machine) &&\r
1375         Hdr.Pe32->OptionalHeader.Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) {\r
1376         ReturnHandle = SimpleFileSystemHandles[Index];\r
1377         break;\r
1378       }\r
1379     }\r
1380   }\r
1381 \r
1382   SafeFreePool(DupDevicePath);\r
1383 \r
1384   SafeFreePool(SimpleFileSystemHandles);\r
1385 \r
1386   return ReturnHandle;\r
1387 }\r
1388 \r
1389 /**\r
1390   Check to see if the network cable is plugged in. If the DevicePath is not\r
1391   connected it will be connected.\r
1392 \r
1393   @param  DevicePath             Device Path to check\r
1394 \r
1395   @retval TRUE                   DevicePath points to an Network that is connected\r
1396   @retval FALSE                  DevicePath does not point to a bootable network\r
1397 \r
1398 **/\r
1399 BOOLEAN\r
1400 BdsLibNetworkBootWithMediaPresent (\r
1401   IN  EFI_DEVICE_PATH_PROTOCOL      *DevicePath\r
1402   )\r
1403 {\r
1404   EFI_STATUS                      Status;\r
1405   EFI_DEVICE_PATH_PROTOCOL        *UpdatedDevicePath;\r
1406   EFI_HANDLE                      Handle;\r
1407   EFI_SIMPLE_NETWORK_PROTOCOL     *Snp;\r
1408   BOOLEAN                         MediaPresent;\r
1409 \r
1410   MediaPresent = FALSE;\r
1411 \r
1412   UpdatedDevicePath = DevicePath;\r
1413   Status = gBS->LocateDevicePath (&gEfiSimpleNetworkProtocolGuid, &UpdatedDevicePath, &Handle);\r
1414   if (EFI_ERROR (Status)) {\r
1415     //\r
1416     // Device not present so see if we need to connect it\r
1417     //\r
1418     Status = BdsLibConnectDevicePath (DevicePath);\r
1419     if (!EFI_ERROR (Status)) {\r
1420       //\r
1421       // This one should work after we did the connect\r
1422       //\r
1423       Status = gBS->LocateDevicePath (&gEfiSimpleNetworkProtocolGuid, &UpdatedDevicePath, &Handle);\r
1424     }\r
1425   }\r
1426 \r
1427   if (!EFI_ERROR (Status)) {\r
1428     Status = gBS->HandleProtocol (Handle, &gEfiSimpleNetworkProtocolGuid, (VOID **)&Snp);\r
1429     if (!EFI_ERROR (Status)) {\r
1430       if (Snp->Mode->MediaPresentSupported) {\r
1431         if (Snp->Mode->State == EfiSimpleNetworkInitialized) {\r
1432           //\r
1433           // In case some one else is using the SNP check to see if it's connected\r
1434           //\r
1435           MediaPresent = Snp->Mode->MediaPresent;\r
1436         } else {\r
1437           //\r
1438           // No one is using SNP so we need to Start and Initialize so\r
1439           // MediaPresent will be valid.\r
1440           //\r
1441           Status = Snp->Start (Snp);\r
1442           if (!EFI_ERROR (Status)) {\r
1443             Status = Snp->Initialize (Snp, 0, 0);\r
1444             if (!EFI_ERROR (Status)) {\r
1445               MediaPresent = Snp->Mode->MediaPresent;\r
1446               Snp->Shutdown (Snp);\r
1447             }\r
1448             Snp->Stop (Snp);\r
1449           }\r
1450         }\r
1451       } else {\r
1452         MediaPresent = TRUE;\r
1453       }\r
1454     }\r
1455   }\r
1456 \r
1457   return MediaPresent;\r
1458 }\r
1459 \r
1460 /**\r
1461   For a bootable Device path, return its boot type.\r
1462 \r
1463   @param  DevicePath                      The bootable device Path to check\r
1464 \r
1465   @retval BDS_EFI_MEDIA_HD_BOOT           If the device path contains any media deviec path node, it is media boot type\r
1466                                           For the floppy node, handle it as media node\r
1467   @retval BDS_EFI_MEDIA_CDROM_BOOT        If the device path contains any media deviec path node, it is media boot type\r
1468                                           For the floppy node, handle it as media node\r
1469   @retval BDS_EFI_ACPI_FLOPPY_BOOT        If the device path contains any media deviec path node, it is media boot type\r
1470                                           For the floppy node, handle it as media node\r
1471   @retval BDS_EFI_MESSAGE_ATAPI_BOOT      If the device path not contains any media deviec path node,  and\r
1472                                           its last device path node point to a message device path node, it is\r
1473   \r
1474   @retval BDS_EFI_MESSAGE_SCSI_BOOT       If the device path not contains any media deviec path node,  and\r
1475                                           its last device path node point to a message device path node, it is\r
1476   @retval BDS_EFI_MESSAGE_USB_DEVICE_BOOT If the device path not contains any media deviec path node,  and\r
1477                                           its last device path node point to a message device path node, it is\r
1478   @retval BDS_EFI_MESSAGE_MISC_BOOT       If the device path not contains any media deviec path node,  and\r
1479                                           its last device path node point to a message device path node, it is\r
1480   @retval BDS_LEGACY_BBS_BOOT             Legacy boot type\r
1481   @retval BDS_EFI_UNSUPPORT               An EFI Removable BlockIO device path not point to a media and message devie,   \r
1482 \r
1483 **/\r
1484 UINT32\r
1485 EFIAPI\r
1486 BdsGetBootTypeFromDevicePath (\r
1487   IN  EFI_DEVICE_PATH_PROTOCOL     *DevicePath\r
1488   )\r
1489 {\r
1490   ACPI_HID_DEVICE_PATH          *Acpi;\r
1491   EFI_DEVICE_PATH_PROTOCOL      *TempDevicePath;\r
1492   EFI_DEVICE_PATH_PROTOCOL      *LastDeviceNode;\r
1493 \r
1494 \r
1495   if (NULL == DevicePath) {\r
1496     return BDS_EFI_UNSUPPORT;\r
1497   }\r
1498 \r
1499   TempDevicePath = DevicePath;\r
1500 \r
1501   while (!IsDevicePathEndType (TempDevicePath)) {\r
1502     switch (DevicePathType (TempDevicePath)) {\r
1503       case BBS_DEVICE_PATH:\r
1504          return BDS_LEGACY_BBS_BOOT;\r
1505       case MEDIA_DEVICE_PATH:\r
1506         if (DevicePathSubType (TempDevicePath) == MEDIA_HARDDRIVE_DP) {\r
1507           return BDS_EFI_MEDIA_HD_BOOT;\r
1508         } else if (DevicePathSubType (TempDevicePath) == MEDIA_CDROM_DP) {\r
1509           return BDS_EFI_MEDIA_CDROM_BOOT;\r
1510         }\r
1511         break;\r
1512       case ACPI_DEVICE_PATH:\r
1513         Acpi = (ACPI_HID_DEVICE_PATH *) TempDevicePath;\r
1514         if (EISA_ID_TO_NUM (Acpi->HID) == 0x0604) {\r
1515           return BDS_EFI_ACPI_FLOPPY_BOOT;\r
1516         }\r
1517         break;\r
1518       case MESSAGING_DEVICE_PATH:\r
1519         //\r
1520         // Get the last device path node\r
1521         //\r
1522         LastDeviceNode = NextDevicePathNode (TempDevicePath);\r
1523         if (DevicePathSubType(LastDeviceNode) == MSG_DEVICE_LOGICAL_UNIT_DP) {\r
1524           //\r
1525           // if the next node type is Device Logical Unit, which specify the Logical Unit Number (LUN),\r
1526           // skit it\r
1527           //\r
1528           LastDeviceNode = NextDevicePathNode (LastDeviceNode);\r
1529         }\r
1530         //\r
1531         // if the device path not only point to driver device, it is not a messaging device path,\r
1532         //\r
1533         if (!IsDevicePathEndType (LastDeviceNode)) {\r
1534           break;        \r
1535         }\r
1536 \r
1537         if (DevicePathSubType(TempDevicePath) == MSG_ATAPI_DP) {\r
1538           return BDS_EFI_MESSAGE_ATAPI_BOOT;\r
1539         } else if (DevicePathSubType(TempDevicePath) == MSG_USB_DP) {\r
1540           return BDS_EFI_MESSAGE_USB_DEVICE_BOOT;\r
1541         } else if (DevicePathSubType(TempDevicePath) == MSG_SCSI_DP) {\r
1542           return BDS_EFI_MESSAGE_SCSI_BOOT;\r
1543         }\r
1544         return BDS_EFI_MESSAGE_MISC_BOOT;\r
1545       default:\r
1546         break;\r
1547     }\r
1548     TempDevicePath = NextDevicePathNode (TempDevicePath);\r
1549   }\r
1550 \r
1551   return BDS_EFI_UNSUPPORT;\r
1552 }\r
1553 \r
1554 /**\r
1555   Check whether the Device path in a boot option point to a valide bootable device,\r
1556   And if CheckMedia is true, check the device is ready to boot now.\r
1557 \r
1558   @param DevPath        the Device path in a boot option\r
1559   @param CheckMedia     if true, check the device is ready to boot now.\r
1560 \r
1561   @retval TRUE          the Device path  is valide\r
1562   @retval FALSE         the Device path  is invalide .\r
1563 \r
1564 **/\r
1565 BOOLEAN\r
1566 EFIAPI\r
1567 BdsLibIsValidEFIBootOptDevicePath (\r
1568   IN EFI_DEVICE_PATH_PROTOCOL     *DevPath,\r
1569   IN BOOLEAN                      CheckMedia\r
1570   )\r
1571 {\r
1572   EFI_STATUS                Status;\r
1573   EFI_HANDLE                Handle;\r
1574   EFI_DEVICE_PATH_PROTOCOL  *TempDevicePath;\r
1575   EFI_DEVICE_PATH_PROTOCOL  *LastDeviceNode;\r
1576   EFI_BLOCK_IO_PROTOCOL     *BlockIo;\r
1577 \r
1578   TempDevicePath = DevPath;\r
1579   LastDeviceNode = DevPath;\r
1580   \r
1581   //\r
1582   // Check if it's a valid boot option for network boot device\r
1583   // Only check if there is SimpleNetworkProtocol installed. If yes, that means\r
1584   // there is the network card there.\r
1585   //\r
1586   Status = gBS->LocateDevicePath (\r
1587                   &gEfiSimpleNetworkProtocolGuid,\r
1588                   &TempDevicePath,\r
1589                   &Handle\r
1590                   );\r
1591   if (EFI_ERROR (Status)) {\r
1592     //\r
1593     // Device not present so see if we need to connect it\r
1594     //\r
1595     TempDevicePath = DevPath;\r
1596     BdsLibConnectDevicePath (TempDevicePath);\r
1597     Status = gBS->LocateDevicePath (\r
1598                     &gEfiSimpleNetworkProtocolGuid,\r
1599                     &TempDevicePath,\r
1600                     &Handle\r
1601                     );\r
1602   }\r
1603   \r
1604   if (!EFI_ERROR (Status)) {\r
1605     if (CheckMedia) {\r
1606       //\r
1607       // Test if it is ready to boot now\r
1608       //\r
1609       if (BdsLibNetworkBootWithMediaPresent(DevPath)) {\r
1610         return TRUE;\r
1611       }\r
1612     } else {\r
1613       return TRUE;\r
1614     }\r
1615   }\r
1616 \r
1617   //\r
1618   // If the boot option point to a file, it is a valid EFI boot option,\r
1619   // and assume it is ready to boot now\r
1620   //\r
1621   while (!EfiIsDevicePathEnd (TempDevicePath)) {\r
1622      LastDeviceNode = TempDevicePath;\r
1623      TempDevicePath = EfiNextDevicePathNode (TempDevicePath);\r
1624   }\r
1625   if ((DevicePathType (LastDeviceNode) == MEDIA_DEVICE_PATH) &&\r
1626     (DevicePathSubType (LastDeviceNode) == MEDIA_FILEPATH_DP)) {\r
1627     return TRUE;\r
1628   }\r
1629 \r
1630   //\r
1631   // Check if it's a valid boot option for internal Shell\r
1632   //\r
1633   if (EfiGetNameGuidFromFwVolDevicePathNode ((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) LastDeviceNode) != NULL) {\r
1634     //\r
1635     // If the boot option point to Internal FV shell, make sure it is valid\r
1636     //\r
1637     TempDevicePath = DevPath; \r
1638     Status = BdsLibUpdateFvFileDevicePath (&TempDevicePath, &gEfiShellFileGuid);\r
1639     if (Status == EFI_ALREADY_STARTED) {\r
1640       return TRUE;\r
1641     } else {\r
1642       if (Status == EFI_SUCCESS) {\r
1643         SafeFreePool (TempDevicePath); \r
1644       }\r
1645       return FALSE;\r
1646     }\r
1647   }\r
1648   \r
1649   //\r
1650   // 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
1651   //\r
1652   TempDevicePath = DevPath;\r
1653   Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &TempDevicePath, &Handle);\r
1654   if (EFI_ERROR (Status)) {\r
1655     //\r
1656     // Device not present so see if we need to connect it\r
1657     //\r
1658     Status = BdsLibConnectDevicePath (DevPath);\r
1659     if (!EFI_ERROR (Status)) {\r
1660       //\r
1661       // Try again to get the Block Io protocol after we did the connect\r
1662       //\r
1663       TempDevicePath = DevPath;\r
1664       Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &TempDevicePath, &Handle);\r
1665     }\r
1666   }\r
1667   \r
1668   if (!EFI_ERROR (Status)) {\r
1669     Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **)&BlockIo);\r
1670     if (!EFI_ERROR (Status)) {\r
1671       if (CheckMedia) {\r
1672         //\r
1673         // Test if it is ready to boot now\r
1674         //\r
1675         if (BdsLibGetBootableHandle (DevPath) != NULL) {\r
1676           return TRUE;\r
1677         }\r
1678       } else {\r
1679         return TRUE;\r
1680       }\r
1681     }\r
1682   } else {\r
1683     //\r
1684     // 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
1685     //\r
1686     Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &TempDevicePath, &Handle);\r
1687     if (!EFI_ERROR (Status)) {\r
1688       if (CheckMedia) {\r
1689         //\r
1690         // Test if it is ready to boot now\r
1691         //\r
1692         if (BdsLibGetBootableHandle (DevPath) != NULL) {\r
1693           return TRUE;\r
1694         }\r
1695       } else {\r
1696         return TRUE;\r
1697       }\r
1698     }\r
1699   }\r
1700 \r
1701   return FALSE;\r
1702 }\r
1703 \r
1704 \r
1705 /**\r
1706   According to a file guild, check a Fv file device path is valid. If it is invalid,\r
1707   try to return the valid device path.\r
1708   FV address maybe changes for memory layout adjust from time to time, use this funciton\r
1709   could promise the Fv file device path is right.\r
1710 \r
1711   @param  DevicePath             on input, the Fv file device path need to check on\r
1712                                  output, the updated valid Fv file device path\r
1713   @param  FileGuid               the Fv file guild\r
1714 \r
1715   @retval EFI_INVALID_PARAMETER  the input DevicePath or FileGuid is invalid\r
1716                                  parameter\r
1717   @retval EFI_UNSUPPORTED        the input DevicePath does not contain Fv file\r
1718                                  guild at all\r
1719   @retval EFI_ALREADY_STARTED    the input DevicePath has pointed to Fv file, it is\r
1720                                  valid\r
1721   @retval EFI_SUCCESS            has successfully updated the invalid DevicePath,\r
1722                                  and return the updated device path in DevicePath\r
1723 \r
1724 **/\r
1725 EFI_STATUS\r
1726 EFIAPI\r
1727 BdsLibUpdateFvFileDevicePath (\r
1728   IN  OUT EFI_DEVICE_PATH_PROTOCOL      ** DevicePath,\r
1729   IN      EFI_GUID                      *FileGuid\r
1730   )\r
1731 {\r
1732   EFI_DEVICE_PATH_PROTOCOL      *TempDevicePath;\r
1733   EFI_DEVICE_PATH_PROTOCOL      *LastDeviceNode;\r
1734   EFI_STATUS                    Status;\r
1735   EFI_GUID                      *GuidPoint;\r
1736   UINTN                         Index;\r
1737   UINTN                         FvHandleCount;\r
1738   EFI_HANDLE                    *FvHandleBuffer;\r
1739   EFI_FV_FILETYPE               Type;\r
1740   UINTN                         Size;\r
1741   EFI_FV_FILE_ATTRIBUTES        Attributes;\r
1742   UINT32                        AuthenticationStatus;\r
1743   BOOLEAN                       FindFvFile;\r
1744   EFI_LOADED_IMAGE_PROTOCOL     *LoadedImage;\r
1745   EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;\r
1746   MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FvFileNode;\r
1747   EFI_HANDLE                    FoundFvHandle;\r
1748   EFI_DEVICE_PATH_PROTOCOL      *NewDevicePath;\r
1749 \r
1750   if ((DevicePath == NULL) || (*DevicePath == NULL)) {\r
1751     return EFI_INVALID_PARAMETER;\r
1752   }\r
1753   if (FileGuid == NULL) {\r
1754     return EFI_INVALID_PARAMETER;\r
1755   }\r
1756   \r
1757   //\r
1758   // Check whether the device path point to the default the input Fv file\r
1759   //\r
1760   TempDevicePath = *DevicePath;\r
1761   LastDeviceNode = TempDevicePath;\r
1762   while (!EfiIsDevicePathEnd (TempDevicePath)) {\r
1763      LastDeviceNode = TempDevicePath;\r
1764      TempDevicePath = EfiNextDevicePathNode (TempDevicePath);\r
1765   }\r
1766   GuidPoint = EfiGetNameGuidFromFwVolDevicePathNode (\r
1767                 (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) LastDeviceNode\r
1768                 );\r
1769   if (GuidPoint == NULL) {\r
1770     //\r
1771     // if this option does not points to a Fv file, just return EFI_UNSUPPORTED\r
1772     //\r
1773     return EFI_UNSUPPORTED;\r
1774   }\r
1775   if (!CompareGuid (GuidPoint, FileGuid)) {\r
1776     //\r
1777     // If the Fv file is not the input file guid, just return EFI_UNSUPPORTED\r
1778     //\r
1779     return EFI_UNSUPPORTED;\r
1780   }\r
1781 \r
1782   //\r
1783   // Check whether the input Fv file device path is valid\r
1784   //\r
1785   TempDevicePath = *DevicePath;\r
1786   FoundFvHandle = NULL;\r
1787   Status = gBS->LocateDevicePath (\r
1788                   &gEfiFirmwareVolume2ProtocolGuid,\r
1789                   &TempDevicePath,\r
1790                   &FoundFvHandle\r
1791                   );\r
1792   if (!EFI_ERROR (Status)) {\r
1793     Status = gBS->HandleProtocol (\r
1794                     FoundFvHandle,\r
1795                     &gEfiFirmwareVolume2ProtocolGuid,\r
1796                     (VOID **) &Fv\r
1797                     );\r
1798     if (!EFI_ERROR (Status)) {\r
1799       //\r
1800       // Set FV ReadFile Buffer as NULL, only need to check whether input Fv file exist there\r
1801       //\r
1802       Status = Fv->ReadFile (\r
1803                     Fv,\r
1804                     FileGuid,\r
1805                     NULL,\r
1806                     &Size,\r
1807                     &Type,\r
1808                     &Attributes,\r
1809                     &AuthenticationStatus\r
1810                     );\r
1811       if (!EFI_ERROR (Status)) {\r
1812         return EFI_ALREADY_STARTED;\r
1813       }\r
1814     }\r
1815   }\r
1816 \r
1817   //\r
1818   // Look for the input wanted FV file in current FV\r
1819   // First, try to look for in Bds own FV. Bds and input wanted FV file usually are in the same FV\r
1820   //\r
1821   FindFvFile = FALSE;\r
1822   FoundFvHandle = NULL;\r
1823   Status = gBS->HandleProtocol (\r
1824              mBdsImageHandle,\r
1825              &gEfiLoadedImageProtocolGuid,\r
1826              (VOID **) &LoadedImage\r
1827              );\r
1828   if (!EFI_ERROR (Status)) {\r
1829     Status = gBS->HandleProtocol (\r
1830                     LoadedImage->DeviceHandle,\r
1831                     &gEfiFirmwareVolume2ProtocolGuid,\r
1832                     (VOID **) &Fv\r
1833                     );\r
1834     if (!EFI_ERROR (Status)) {\r
1835       Status = Fv->ReadFile (\r
1836                     Fv,\r
1837                     FileGuid,\r
1838                     NULL,\r
1839                     &Size,\r
1840                     &Type,\r
1841                     &Attributes,\r
1842                     &AuthenticationStatus\r
1843                     );\r
1844       if (!EFI_ERROR (Status)) {\r
1845         FindFvFile = TRUE;\r
1846         FoundFvHandle = LoadedImage->DeviceHandle;\r
1847       }\r
1848     }\r
1849   }\r
1850   //\r
1851   // Second, if fail to find, try to enumerate all FV\r
1852   //\r
1853   if (!FindFvFile) {\r
1854     FvHandleBuffer = NULL;\r
1855     gBS->LocateHandleBuffer (\r
1856           ByProtocol,\r
1857           &gEfiFirmwareVolume2ProtocolGuid,\r
1858           NULL,\r
1859           &FvHandleCount,\r
1860           &FvHandleBuffer\r
1861           );\r
1862     for (Index = 0; Index < FvHandleCount; Index++) {\r
1863       gBS->HandleProtocol (\r
1864             FvHandleBuffer[Index],\r
1865             &gEfiFirmwareVolume2ProtocolGuid,\r
1866             (VOID **) &Fv\r
1867             );\r
1868 \r
1869       Status = Fv->ReadFile (\r
1870                     Fv,\r
1871                     FileGuid,\r
1872                     NULL,\r
1873                     &Size,\r
1874                     &Type,\r
1875                     &Attributes,\r
1876                     &AuthenticationStatus\r
1877                     );\r
1878       if (EFI_ERROR (Status)) {\r
1879         //\r
1880         // Skip if input Fv file not in the FV\r
1881         //\r
1882         continue;\r
1883       }\r
1884       FindFvFile = TRUE;\r
1885       FoundFvHandle = FvHandleBuffer[Index];\r
1886       break;\r
1887     }\r
1888     \r
1889     SafeFreePool (FvHandleBuffer);  \r
1890   }\r
1891 \r
1892   if (FindFvFile) {\r
1893     //\r
1894     // Build the shell device path\r
1895     //\r
1896     NewDevicePath = DevicePathFromHandle (FoundFvHandle);\r
1897     EfiInitializeFwVolDevicepathNode (&FvFileNode, FileGuid);\r
1898     NewDevicePath = AppendDevicePathNode (NewDevicePath, (EFI_DEVICE_PATH_PROTOCOL *) &FvFileNode);\r
1899     *DevicePath = NewDevicePath;\r
1900     return EFI_SUCCESS;\r
1901   }\r
1902   return EFI_NOT_FOUND;\r
1903 }\r