newline added at end
[people/mcb30/edk2.git] / edk2 / EdkUnixPkg / Library / EdkGenericBdsLib / BdsBoot.c
1 /*++\r
2 \r
3 Copyright (c) 2006, Intel Corporation                                                         \r
4 All rights reserved. This program and the accompanying materials                          \r
5 are licensed and made available under the terms and conditions of the BSD License         \r
6 which accompanies this distribution.  The full text of the license may be found at        \r
7 http://opensource.org/licenses/bsd-license.php                                            \r
8                                                                                           \r
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             \r
11 \r
12 Module Name:\r
13 \r
14   BdsBoot.c\r
15 \r
16 Abstract:\r
17 \r
18   BDS Lib functions which relate with create or process the boot\r
19   option.\r
20 \r
21 --*/\r
22 #include "Performance.h"\r
23 \r
24 BOOLEAN mEnumBootDevice = FALSE;\r
25 \r
26 EFI_STATUS\r
27 BdsLibDoLegacyBoot (\r
28   IN  BDS_COMMON_OPTION           *Option\r
29   )\r
30 /*++\r
31 \r
32 Routine Description:\r
33  \r
34   Boot the legacy system with the boot option\r
35 \r
36 Arguments:\r
37 \r
38   Option           - The legacy boot option which have BBS device path\r
39 \r
40 Returns:\r
41 \r
42   EFI_UNSUPPORTED  - There is no legacybios protocol, do not support\r
43                      legacy boot.\r
44                          \r
45   EFI_STATUS       - Return the status of LegacyBios->LegacyBoot ().\r
46 \r
47 --*/\r
48 {\r
49   EFI_STATUS                Status;\r
50   EFI_LEGACY_BIOS_PROTOCOL  *LegacyBios;\r
51 \r
52   Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL,
53                                 (void **)&LegacyBios);\r
54   if (EFI_ERROR (Status)) {\r
55     //\r
56     // If no LegacyBios protocol we do not support legacy boot\r
57     //\r
58     return EFI_UNSUPPORTED;\r
59   }\r
60   //\r
61   // Notes: if we seperate the int 19, then we don't need to refresh BBS\r
62   //\r
63   BdsRefreshBbsTableForBoot (Option);\r
64 \r
65   //\r
66   // Write boot to OS performance data to a file\r
67   //\r
68   PERF_CODE (\r
69     WriteBootToOsPerformanceData ();\r
70   );\r
71 \r
72 \r
73   DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Legacy Boot: %S\n", Option->Description));\r
74   return LegacyBios->LegacyBoot (\r
75                       LegacyBios,\r
76                       (BBS_BBS_DEVICE_PATH *) Option->DevicePath,\r
77                       Option->LoadOptionsSize,\r
78                       Option->LoadOptions\r
79                       );\r
80 }\r
81 \r
82 EFI_STATUS\r
83 BdsLibBootViaBootOption (\r
84   IN  BDS_COMMON_OPTION             * Option,\r
85   IN  EFI_DEVICE_PATH_PROTOCOL      * DevicePath,\r
86   OUT UINTN                         *ExitDataSize,\r
87   OUT CHAR16                        **ExitData OPTIONAL\r
88   )\r
89 /*++\r
90 \r
91 Routine Description:\r
92 \r
93   Process the boot option follow the EFI 1.1 specification and \r
94   special treat the legacy boot option with BBS_DEVICE_PATH.\r
95 \r
96 Arguments:\r
97 \r
98   Option       - The boot option need to be processed\r
99   \r
100   DevicePath   - The device path which describe where to load \r
101                  the boot image or the legcy BBS device path \r
102                  to boot the legacy OS\r
103 \r
104   ExitDataSize - Returned directly from gBS->StartImage ()\r
105 \r
106   ExitData     - Returned directly from gBS->StartImage ()\r
107 \r
108 Returns:\r
109 \r
110   EFI_SUCCESS   - Status from gBS->StartImage (),\r
111                   or BdsBootByDiskSignatureAndPartition ()\r
112 \r
113   EFI_NOT_FOUND - If the Device Path is not found in the system\r
114 \r
115 --*/\r
116 {\r
117   EFI_STATUS                Status;\r
118   EFI_HANDLE                Handle;\r
119   EFI_HANDLE                ImageHandle;\r
120   EFI_DEVICE_PATH_PROTOCOL  *TempDevicePath;\r
121   EFI_DEVICE_PATH_PROTOCOL  *FilePath;\r
122   EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;\r
123   EFI_ACPI_S3_SAVE_PROTOCOL *AcpiS3Save;\r
124   EFI_BLOCK_IO_PROTOCOL     *BlkIo;\r
125   VOID                      *Buffer;\r
126 \r
127   *ExitDataSize = 0;\r
128   *ExitData     = NULL;\r
129 \r
130   //\r
131   // Notes: put EFI64 ROM Shadow Solution\r
132   //\r
133   EFI64_SHADOW_ALL_LEGACY_ROM ();\r
134 \r
135   //\r
136   // Notes: this code can be remove after the s3 script table\r
137   // hook on the event EFI_EVENT_SIGNAL_READY_TO_BOOT or\r
138   // EFI_EVENT_SIGNAL_LEGACY_BOOT\r
139   //\r
140   Status = gBS->LocateProtocol (&gEfiAcpiS3SaveProtocolGuid, NULL,
141                                 (VOID **)&AcpiS3Save);\r
142   if (!EFI_ERROR (Status)) {\r
143     AcpiS3Save->S3Save (AcpiS3Save, NULL);\r
144   }\r
145   //\r
146   // If it's Device Path that starts with a hard drive path,\r
147   // this routine will do the booting.\r
148   //\r
149   Status = BdsBootByDiskSignatureAndPartition (\r
150             Option,\r
151             (HARDDRIVE_DEVICE_PATH *) DevicePath,\r
152             Option->LoadOptionsSize,\r
153             Option->LoadOptions,\r
154             ExitDataSize,\r
155             ExitData\r
156             );\r
157   if (!EFI_ERROR (Status)) {\r
158     //\r
159     // If we found a disk signature and partition device path return success\r
160     //\r
161     return EFI_SUCCESS;\r
162   }\r
163 \r
164   EfiSignalEventReadyToBoot ();\r
165 \r
166   //\r
167   // Set Boot Current\r
168   //\r
169   gRT->SetVariable (\r
170         L"BootCurrent",\r
171         &gEfiGlobalVariableGuid,\r
172         EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
173         sizeof (UINT16),\r
174         &Option->BootCurrent\r
175         );\r
176 \r
177   if ((DevicePathType (Option->DevicePath) == BBS_DEVICE_PATH) &&\r
178       (DevicePathSubType (Option->DevicePath) == BBS_BBS_DP)\r
179     ) {\r
180     //\r
181     // Check to see if we should legacy BOOT. If yes then do the legacy boot\r
182     //\r
183     return BdsLibDoLegacyBoot (Option);\r
184   }\r
185 \r
186   DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Booting EFI 1.1 way %S\n", Option->Description));\r
187 \r
188   Status = gBS->LoadImage (\r
189                   TRUE,\r
190                   mBdsImageHandle,\r
191                   DevicePath,\r
192                   NULL,\r
193                   0,\r
194                   &ImageHandle\r
195                   );\r
196 \r
197   //\r
198   // If we didn't find an image, we may need to load the default\r
199   // boot behavior for the device.\r
200   //\r
201   if (EFI_ERROR (Status)) {\r
202     //\r
203     // Find a Simple File System protocol on the device path. If the remaining\r
204     // device path is set to end then no Files are being specified, so try\r
205     // the removable media file name.\r
206     //\r
207     TempDevicePath = DevicePath;\r
208     Status = gBS->LocateDevicePath (\r
209                     &gEfiSimpleFileSystemProtocolGuid,\r
210                     &TempDevicePath,\r
211                     &Handle\r
212                     );\r
213     if (!EFI_ERROR (Status) && IsDevicePathEnd (TempDevicePath)) {\r
214       FilePath = FileDevicePath (Handle, EFI_REMOVABLE_MEDIA_FILE_NAME);\r
215       if (FilePath) {\r
216         //\r
217         // Issue a dummy read to the device to check for media change.\r
218         // When the removable media is changed, any Block IO read/write will\r
219         // cause the BlockIo protocol be reinstalled and EFI_MEDIA_CHANGED is\r
220         // returned. After the Block IO protocol is reinstalled, subsequent\r
221         // Block IO read/write will success.\r
222         //\r
223         Status = gBS->HandleProtocol (\r
224                         Handle,\r
225                         &gEfiBlockIoProtocolGuid,\r
226                         (VOID **) &BlkIo\r
227                         );\r
228         if (!EFI_ERROR (Status)) {\r
229           Buffer = AllocatePool (BlkIo->Media->BlockSize);\r
230           if (Buffer != NULL) {\r
231             BlkIo->ReadBlocks (\r
232                      BlkIo,\r
233                      BlkIo->Media->MediaId,\r
234                      0,\r
235                      BlkIo->Media->BlockSize,\r
236                      Buffer\r
237                      );\r
238             gBS->FreePool (Buffer);\r
239           }\r
240         }\r
241 \r
242         Status = gBS->LoadImage (\r
243                         TRUE,\r
244                         mBdsImageHandle,\r
245                         FilePath,\r
246                         NULL,\r
247                         0,\r
248                         &ImageHandle\r
249                         );\r
250         if (EFI_ERROR (Status)) {\r
251           //\r
252           // The DevicePath failed, and it's not a valid\r
253           // removable media device.\r
254           //\r
255           goto Done;\r
256         }\r
257       }\r
258     } else {\r
259       Status = EFI_NOT_FOUND;\r
260     }\r
261   }\r
262 \r
263   if (EFI_ERROR (Status)) {\r
264     //\r
265     // It there is any error from the Boot attempt exit now.\r
266     //\r
267     goto Done;\r
268   }\r
269   //\r
270   // Provide the image with it's load options\r
271   //\r
272   Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid,
273                                 (VOID **) &ImageInfo);\r
274   ASSERT_EFI_ERROR (Status);\r
275 \r
276   if (Option->LoadOptionsSize != 0) {\r
277     ImageInfo->LoadOptionsSize  = Option->LoadOptionsSize;\r
278     ImageInfo->LoadOptions      = Option->LoadOptions;\r
279   }\r
280   //\r
281   // Before calling the image, enable the Watchdog Timer for\r
282   // the 5 Minute period\r
283   //\r
284   gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);\r
285 \r
286   Status = gBS->StartImage (ImageHandle, ExitDataSize, ExitData);\r
287   DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Image Return Status = %r\n", Status));\r
288 \r
289   //\r
290   // Clear the Watchdog Timer after the image returns\r
291   //\r
292   gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);\r
293 \r
294 Done:\r
295   //\r
296   // Clear Boot Current\r
297   //\r
298   gRT->SetVariable (\r
299         L"BootCurrent",\r
300         &gEfiGlobalVariableGuid,\r
301         EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
302         0,\r
303         &Option->BootCurrent\r
304         );\r
305 \r
306   return Status;\r
307 }\r
308 \r
309 EFI_STATUS\r
310 BdsBootByDiskSignatureAndPartition (\r
311   IN  BDS_COMMON_OPTION          * Option,\r
312   IN  HARDDRIVE_DEVICE_PATH      * HardDriveDevicePath,\r
313   IN  UINT32                     LoadOptionsSize,\r
314   IN  VOID                       *LoadOptions,\r
315   OUT UINTN                      *ExitDataSize,\r
316   OUT CHAR16                     **ExitData OPTIONAL\r
317   )\r
318 /*++\r
319 \r
320 Routine Description:\r
321 \r
322   Check to see if a hard ware device path was passed in. If it was then search\r
323   all the block IO devices for the passed in hard drive device path. \r
324   \r
325 Arguments:\r
326 \r
327   Option - The current processing boot option.\r
328 \r
329   HardDriveDevicePath - EFI Device Path to boot, if it starts with a hard\r
330                         drive device path.\r
331 \r
332   LoadOptionsSize - Passed into gBS->StartImage ()\r
333                     via the loaded image protocol.\r
334 \r
335   LoadOptions     - Passed into gBS->StartImage ()\r
336                     via the loaded image protocol.\r
337 \r
338   ExitDataSize - returned directly from gBS->StartImage ()\r
339 \r
340   ExitData     - returned directly from gBS->StartImage ()\r
341 \r
342 Returns:\r
343 \r
344   EFI_SUCCESS   - Status from gBS->StartImage (),\r
345                   or BootByDiskSignatureAndPartition ()\r
346                   \r
347   EFI_NOT_FOUND - If the Device Path is not found in the system\r
348 \r
349 --*/\r
350 {\r
351   EFI_STATUS                Status;\r
352   UINTN                     BlockIoHandleCount;\r
353   EFI_HANDLE                *BlockIoBuffer;\r
354   EFI_DEVICE_PATH_PROTOCOL  *BlockIoDevicePath;\r
355   EFI_DEVICE_PATH_PROTOCOL  *BlockIoHdDevicePath;\r
356   HARDDRIVE_DEVICE_PATH     *TmpHdPath;\r
357   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;\r
358   EFI_DEVICE_PATH_PROTOCOL  *NewDevicePath;\r
359   UINTN                     Index;\r
360   BOOLEAN                   DevicePathMatch;\r
361   HARDDRIVE_DEVICE_PATH     *TempPath;\r
362 \r
363   *ExitDataSize = 0;\r
364   *ExitData     = NULL;\r
365 \r
366   if ( !((DevicePathType (&HardDriveDevicePath->Header) == MEDIA_DEVICE_PATH) &&\r
367           (DevicePathSubType (&HardDriveDevicePath->Header) == MEDIA_HARDDRIVE_DP))\r
368         ) {\r
369     //\r
370     // If the HardDriveDevicePath does not start with a Hard Drive Device Path\r
371     // exit.\r
372     //\r
373     return EFI_NOT_FOUND;\r
374   }\r
375   //\r
376   // The boot device have already been connected\r
377   //\r
378   Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiBlockIoProtocolGuid, NULL, &BlockIoHandleCount, &BlockIoBuffer);\r
379   if (EFI_ERROR (Status) || BlockIoHandleCount == 0) {\r
380     //\r
381     // If there was an error or there are no device handles that support\r
382     // the BLOCK_IO Protocol, then return.\r
383     //\r
384     return EFI_NOT_FOUND;\r
385   }\r
386   //\r
387   // Loop through all the device handles that support the BLOCK_IO Protocol\r
388   //\r
389   for (Index = 0; Index < BlockIoHandleCount; Index++) {\r
390 \r
391     Status = gBS->HandleProtocol (BlockIoBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID *) &BlockIoDevicePath);\r
392     if (EFI_ERROR (Status) || BlockIoDevicePath == NULL) {\r
393       continue;\r
394     }\r
395     //\r
396     // Make PreviousDevicePath == the device path node before the end node\r
397     //\r
398     DevicePath          = BlockIoDevicePath;\r
399     BlockIoHdDevicePath = NULL;\r
400 \r
401     //\r
402     // find HardDriver device path node\r
403     //\r
404     while (!IsDevicePathEnd (DevicePath)) {\r
405       if ((DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) && \r
406           (DevicePathSubType (DevicePath) == MEDIA_HARDDRIVE_DP)\r
407           ) {\r
408         BlockIoHdDevicePath = DevicePath;\r
409         break;\r
410       }\r
411 \r
412       DevicePath = NextDevicePathNode (DevicePath);\r
413     }\r
414 \r
415     if (BlockIoHdDevicePath == NULL) {\r
416       continue;\r
417     }\r
418     //\r
419     // See if the harddrive device path in blockio matches the orig Hard Drive Node\r
420     //\r
421     DevicePathMatch = FALSE;\r
422 \r
423     TmpHdPath       = (HARDDRIVE_DEVICE_PATH *) BlockIoHdDevicePath;\r
424     TempPath        = (HARDDRIVE_DEVICE_PATH *) BdsLibUnpackDevicePath ((EFI_DEVICE_PATH_PROTOCOL *) HardDriveDevicePath);\r
425 \r
426     //\r
427     // Only several fields will be checked. NOT whole NODE\r
428     //\r
429     if ( TmpHdPath->PartitionNumber == TempPath->PartitionNumber &&\r
430         TmpHdPath->MBRType == TempPath->MBRType &&\r
431         TmpHdPath->SignatureType == TempPath->SignatureType &&\r
432         CompareGuid ((EFI_GUID *) TmpHdPath->Signature, (EFI_GUID *) TempPath->Signature)) {\r
433       //\r
434       // Get the matched device path\r
435       //\r
436       DevicePathMatch = TRUE;\r
437     }\r
438     //\r
439     // Only do the boot, when devicepath match\r
440     //\r
441     if (DevicePathMatch) {\r
442       //\r
443       // Combine the Block IO and Hard Drive Device path together and try\r
444       // to boot from it.\r
445       //\r
446       DevicePath    = NextDevicePathNode ((EFI_DEVICE_PATH_PROTOCOL *) HardDriveDevicePath);\r
447       NewDevicePath = AppendDevicePath (BlockIoDevicePath, DevicePath);\r
448 \r
449       //\r
450       // Recursive boot with new device path\r
451       //\r
452       Status = BdsLibBootViaBootOption (Option, NewDevicePath, ExitDataSize, ExitData);\r
453       if (!EFI_ERROR (Status)) {\r
454         break;\r
455       }\r
456     }\r
457   }\r
458 \r
459   gBS->FreePool (BlockIoBuffer);\r
460   return Status;\r
461 }\r
462 \r
463 EFI_STATUS\r
464 BdsLibDeleteOptionFromHandle (\r
465   IN  EFI_HANDLE                 Handle\r
466   )\r
467 /*++\r
468 \r
469 Routine Description:\r
470 \r
471   Delete the boot option associated with the handle passed in\r
472 \r
473 Arguments:\r
474 \r
475   Handle - The handle which present the device path to create boot option\r
476 \r
477 Returns:\r
478 \r
479   EFI_SUCCESS           - Delete the boot option success\r
480 \r
481   EFI_NOT_FOUND         - If the Device Path is not found in the system\r
482 \r
483   EFI_OUT_OF_RESOURCES  - Lack of memory resource\r
484 \r
485   Other                 - Error return value from SetVariable()\r
486 \r
487 --*/\r
488 {\r
489   UINT16                    *BootOrder;\r
490   UINT8                     *BootOptionVar;\r
491   UINTN                     BootOrderSize;\r
492   UINTN                     BootOptionSize;\r
493   EFI_STATUS                Status;\r
494   UINTN                     Index;\r
495   UINT16                    BootOption[BOOT_OPTION_MAX_CHAR];\r
496   UINTN                     DevicePathSize;\r
497   UINTN                     OptionDevicePathSize;\r
498   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;\r
499   EFI_DEVICE_PATH_PROTOCOL  *OptionDevicePath;\r
500   UINT8                     *TempPtr;\r
501   CHAR16                    *Description;\r
502 \r
503   Status        = EFI_SUCCESS;\r
504   BootOrder     = NULL;\r
505   BootOrderSize = 0;\r
506 \r
507   BootOrder = BdsLibGetVariableAndSize (\r
508                 L"BootOrder",\r
509                 &gEfiGlobalVariableGuid,\r
510                 &BootOrderSize\r
511                 );\r
512   if (NULL == BootOrder) {\r
513     return EFI_NOT_FOUND;\r
514   }\r
515 \r
516   DevicePath = DevicePathFromHandle (Handle);\r
517   if (DevicePath == NULL) {\r
518     return EFI_NOT_FOUND;\r
519   }\r
520   DevicePathSize = GetDevicePathSize (DevicePath);\r
521 \r
522   Index = 0;\r
523   while (Index < BootOrderSize / sizeof (UINT16)) {\r
524     UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]);\r
525     BootOptionVar = BdsLibGetVariableAndSize (\r
526                       BootOption,\r
527                       &gEfiGlobalVariableGuid,\r
528                       &BootOptionSize\r
529                       );\r
530     if (NULL == BootOptionVar) {\r
531       gBS->FreePool (BootOrder);\r
532       return EFI_OUT_OF_RESOURCES;\r
533     }\r
534 \r
535     TempPtr = BootOptionVar;\r
536     TempPtr += sizeof (UINT32) + sizeof (UINT16);\r
537     Description = (CHAR16 *) TempPtr;\r
538     TempPtr += StrSize ((CHAR16 *) TempPtr);\r
539     OptionDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;\r
540     OptionDevicePathSize = GetDevicePathSize (OptionDevicePath);\r
541 \r
542     //\r
543     // Check whether the device path match\r
544     //\r
545     if ((OptionDevicePathSize == DevicePathSize) &&\r
546         (CompareMem (DevicePath, OptionDevicePath, DevicePathSize) == 0)) {\r
547       BdsDeleteBootOption (BootOrder[Index], BootOrder, &BootOrderSize);\r
548       gBS->FreePool (BootOptionVar);\r
549       break;\r
550     }\r
551 \r
552     gBS->FreePool (BootOptionVar);\r
553     Index++;\r
554   }\r
555 \r
556   Status = gRT->SetVariable (\r
557                   L"BootOrder",\r
558                   &gEfiGlobalVariableGuid,\r
559                   EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
560                   BootOrderSize,\r
561                   BootOrder\r
562                   );\r
563 \r
564   gBS->FreePool (BootOrder);\r
565 \r
566   return Status;\r
567 }\r
568 \r
569 EFI_STATUS\r
570 BdsDeleteAllInvalidEfiBootOption (\r
571   VOID\r
572   )\r
573 /*++\r
574 \r
575 Routine Description:\r
576 \r
577   Delete all invalid EFI boot options. The probable invalid boot option could\r
578   be Removable media or Network boot device.\r
579 \r
580 Arguments:\r
581 \r
582   VOID\r
583 \r
584 Returns:\r
585 \r
586   EFI_SUCCESS           - Delete all invalid boot option success\r
587 \r
588   EFI_NOT_FOUND         - Variable "BootOrder" is not found\r
589 \r
590   EFI_OUT_OF_RESOURCES  - Lack of memory resource\r
591 \r
592   Other                 - Error return value from SetVariable()\r
593 \r
594 --*/\r
595 {\r
596   UINT16                    *BootOrder;\r
597   UINT8                     *BootOptionVar;\r
598   UINTN                     BootOrderSize;\r
599   UINTN                     BootOptionSize;\r
600   EFI_STATUS                Status;\r
601   UINTN                     Index;\r
602   UINTN                     Index2;\r
603   UINT16                    BootOption[BOOT_OPTION_MAX_CHAR];\r
604   UINTN                     OptionDevicePathSize;\r
605   EFI_DEVICE_PATH_PROTOCOL  *TempDevicePath;\r
606   EFI_DEVICE_PATH_PROTOCOL  *LastDeviceNode;\r
607   EFI_DEVICE_PATH_PROTOCOL  *OptionDevicePath;\r
608   UINT8                     *TempPtr;\r
609   CHAR16                    *Description;\r
610   EFI_HANDLE                Handle;\r
611   BOOLEAN                   NeedDelete;\r
612 \r
613   Status        = EFI_SUCCESS;\r
614   BootOrder     = NULL;\r
615   BootOrderSize = 0;\r
616 \r
617   BootOrder = BdsLibGetVariableAndSize (\r
618                 L"BootOrder",\r
619                 &gEfiGlobalVariableGuid,\r
620                 &BootOrderSize\r
621                 );\r
622   if (NULL == BootOrder) {\r
623     return EFI_NOT_FOUND;\r
624   }\r
625 \r
626   Index = 0;\r
627   while (Index < BootOrderSize / sizeof (UINT16)) {\r
628     UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]);\r
629     BootOptionVar = BdsLibGetVariableAndSize (\r
630                       BootOption,\r
631                       &gEfiGlobalVariableGuid,\r
632                       &BootOptionSize\r
633                       );\r
634     if (NULL == BootOptionVar) {\r
635       gBS->FreePool (BootOrder);\r
636       return EFI_OUT_OF_RESOURCES;\r
637     }\r
638 \r
639     TempPtr = BootOptionVar;\r
640     TempPtr += sizeof (UINT32) + sizeof (UINT16);\r
641     Description = (CHAR16 *) TempPtr;\r
642     TempPtr += StrSize ((CHAR16 *) TempPtr);\r
643     OptionDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;\r
644     OptionDevicePathSize = GetDevicePathSize (OptionDevicePath);\r
645 \r
646     //\r
647     // Skip legacy boot option (BBS boot device)\r
648     //\r
649     if ((DevicePathType (OptionDevicePath) == BBS_DEVICE_PATH) &&\r
650         (DevicePathSubType (OptionDevicePath) == BBS_BBS_DP)) {\r
651       gBS->FreePool (BootOptionVar);\r
652       Index++;\r
653       continue;\r
654     }\r
655 \r
656     TempDevicePath = OptionDevicePath;\r
657     LastDeviceNode = OptionDevicePath;\r
658     while (!EfiIsDevicePathEnd (TempDevicePath)) {\r
659       LastDeviceNode = TempDevicePath;\r
660       TempDevicePath = EfiNextDevicePathNode (TempDevicePath);\r
661     }\r
662     //\r
663     // Skip the boot option that point to a file, since the device path in \r
664     // removable media boot option doesn't contains a file name.\r
665     //\r
666     if (((DevicePathType (LastDeviceNode) == MEDIA_DEVICE_PATH) &&\r
667          (DevicePathSubType (LastDeviceNode) == MEDIA_FILEPATH_DP)) ||\r
668         //\r
669         // Skip boot option for internal Shell, it's always valid\r
670         //\r
671         (EfiGetNameGuidFromFwVolDevicePathNode ((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) LastDeviceNode) != NULL)) {\r
672       gBS->FreePool (BootOptionVar);\r
673       Index++;\r
674       continue;\r
675     }\r
676 \r
677     NeedDelete = TRUE;\r
678     //\r
679     // Check if it's a valid boot option for removable media\r
680     //\r
681     TempDevicePath = OptionDevicePath;\r
682     Status = gBS->LocateDevicePath (\r
683                     &gEfiSimpleFileSystemProtocolGuid,\r
684                     &TempDevicePath,\r
685                     &Handle\r
686                     );\r
687     if (!EFI_ERROR (Status)) {\r
688       NeedDelete = FALSE;\r
689     }\r
690     //\r
691     // Check if it's a valid boot option for network boot device\r
692     //\r
693     TempDevicePath = OptionDevicePath;\r
694     Status = gBS->LocateDevicePath (\r
695                     &gEfiLoadFileProtocolGuid,\r
696                     &TempDevicePath,\r
697                     &Handle\r
698                     );\r
699     if (!EFI_ERROR (Status)) {\r
700       NeedDelete = FALSE;\r
701     }\r
702 \r
703     if (NeedDelete) {\r
704       //\r
705       // Delete this invalid boot option "Boot####"\r
706       //\r
707       Status = gRT->SetVariable (\r
708                       BootOption,\r
709                       &gEfiGlobalVariableGuid,\r
710                       EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
711                       0,\r
712                       NULL\r
713                       );\r
714       //\r
715       // Mark this boot option in boot order as deleted\r
716       //\r
717       BootOrder[Index] = 0xffff;\r
718     }\r
719 \r
720     gBS->FreePool (BootOptionVar);\r
721     Index++;\r
722   }\r
723 \r
724   //\r
725   // Adjust boot order array\r
726   //\r
727   Index2 = 0;\r
728   for (Index = 0; Index < BootOrderSize / sizeof (UINT16); Index++) {\r
729     if (BootOrder[Index] != 0xffff) {\r
730       BootOrder[Index2] = BootOrder[Index];\r
731       Index2 ++;\r
732     }\r
733   }\r
734   Status = gRT->SetVariable (\r
735                   L"BootOrder",\r
736                   &gEfiGlobalVariableGuid,\r
737                   EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
738                   Index2 * sizeof (UINT16),\r
739                   BootOrder\r
740                   );\r
741 \r
742   gBS->FreePool (BootOrder);\r
743 \r
744   return Status;\r
745 }\r
746 \r
747 EFI_STATUS\r
748 BdsLibEnumerateAllBootOption (\r
749   IN OUT LIST_ENTRY      *BdsBootOptionList\r
750   )\r
751 /*++\r
752 \r
753 Routine Description:\r
754 \r
755   This function will enumerate all possible boot device in the system,\r
756   it will only excute once of every boot.\r
757 \r
758 Arguments:\r
759 \r
760   BdsBootOptionList - The header of the link list which indexed all\r
761                       current boot options\r
762 \r
763 Returns:\r
764 \r
765   EFI_SUCCESS - Finished all the boot device enumerate and create\r
766                 the boot option base on that boot device\r
767 \r
768 --*/\r
769 {\r
770   EFI_STATUS                    Status;\r
771   UINT16                        BootOptionNumber;\r
772   UINTN                         NumberFileSystemHandles;\r
773   EFI_HANDLE                    *FileSystemHandles;\r
774   EFI_BLOCK_IO_PROTOCOL         *BlkIo;\r
775   UINTN                         Index;\r
776   UINTN                         NumberLoadFileHandles;\r
777   EFI_HANDLE                    *LoadFileHandles;\r
778   VOID                          *ProtocolInstance;\r
779   EFI_FIRMWARE_VOLUME_PROTOCOL  *Fv;\r
780   UINTN                         FvHandleCount;\r
781   EFI_HANDLE                    *FvHandleBuffer;\r
782   EFI_FV_FILETYPE               Type;\r
783   UINTN                         Size;\r
784   EFI_FV_FILE_ATTRIBUTES        Attributes;\r
785   UINT32                        AuthenticationStatus;\r
786   EFI_DEVICE_PATH_PROTOCOL      *FilePath;\r
787   EFI_HANDLE                    ImageHandle;\r
788   EFI_LOADED_IMAGE_PROTOCOL     *ImageInfo;\r
789   BOOLEAN                       NeedDelete;\r
790 \r
791   BootOptionNumber = 0;\r
792 \r
793   //\r
794   // If the boot device enumerate happened, just get the boot\r
795   // device from the boot order variable\r
796   //\r
797   if (mEnumBootDevice) {\r
798     BdsLibBuildOptionFromVar (BdsBootOptionList, L"BootOrder");\r
799     return EFI_SUCCESS;\r
800   }\r
801   //\r
802   // Notes: this dirty code is to get the legacy boot option from the\r
803   // BBS table and create to variable as the EFI boot option, it should\r
804   // be removed after the CSM can provide legacy boot option directly\r
805   //\r
806   REFRESH_LEGACY_BOOT_OPTIONS;\r
807 \r
808   //\r
809   // Delete invalid boot option\r
810   //\r
811   BdsDeleteAllInvalidEfiBootOption ();\r
812   //\r
813   // Parse removable media\r
814   //\r
815   gBS->LocateHandleBuffer (\r
816         ByProtocol,\r
817         &gEfiSimpleFileSystemProtocolGuid,\r
818         NULL,\r
819         &NumberFileSystemHandles,\r
820         &FileSystemHandles\r
821         );\r
822   for (Index = 0; Index < NumberFileSystemHandles; Index++) {\r
823     Status = gBS->HandleProtocol (\r
824                     FileSystemHandles[Index],\r
825                     &gEfiBlockIoProtocolGuid,\r
826                     (VOID **) &BlkIo\r
827                     );\r
828     if (!EFI_ERROR (Status)) {\r
829       if (!BlkIo->Media->RemovableMedia) {\r
830         //\r
831         // If the file system handle supports a BlkIo protocol,\r
832         // skip the removable media devices\r
833         //\r
834         continue;\r
835       }\r
836     }\r
837 \r
838     //\r
839     // Do the removable Media thing. \EFI\BOOT\boot{machinename}.EFI\r
840     //  machinename is ia32, ia64, x64, ...\r
841     //\r
842     FilePath = FileDevicePath (FileSystemHandles[Index], EFI_REMOVABLE_MEDIA_FILE_NAME);\r
843     NeedDelete = TRUE;\r
844     Status = gBS->LoadImage (\r
845                     TRUE,\r
846                     mBdsImageHandle,\r
847                     FilePath,\r
848                     NULL,\r
849                     0,\r
850                     &ImageHandle\r
851                     );\r
852     if (!EFI_ERROR(Status)) {\r
853       //\r
854       // Verify the image is a EFI application (and not a driver)\r
855       //\r
856       Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &ImageInfo);\r
857       ASSERT (!EFI_ERROR(Status));\r
858 \r
859       if (ImageInfo->ImageCodeType == EfiLoaderCode) {\r
860         NeedDelete = FALSE;\r
861       }\r
862     }\r
863 \r
864     if (NeedDelete) {\r
865       //\r
866       // No such file or the file is not a EFI application, delete this boot option\r
867       //\r
868       BdsLibDeleteOptionFromHandle (FileSystemHandles[Index]);\r
869     } else {\r
870       BdsLibBuildOptionFromHandle (FileSystemHandles[Index], BdsBootOptionList);\r
871       BootOptionNumber++;\r
872     }\r
873   }\r
874 \r
875   if (NumberFileSystemHandles) {\r
876     gBS->FreePool (FileSystemHandles);\r
877   }\r
878   //\r
879   // Parse Network Boot Device\r
880   //\r
881   gBS->LocateHandleBuffer (\r
882         ByProtocol,\r
883         &gEfiSimpleNetworkProtocolGuid,\r
884         NULL,\r
885         &NumberLoadFileHandles,\r
886         &LoadFileHandles\r
887         );\r
888   for (Index = 0; Index < NumberLoadFileHandles; Index++) {\r
889     Status = gBS->HandleProtocol (\r
890                     LoadFileHandles[Index],\r
891                     &gEfiLoadFileProtocolGuid,\r
892                     (VOID **) &ProtocolInstance\r
893                     );\r
894     if (EFI_ERROR (Status)) {\r
895       continue;\r
896     }\r
897 \r
898     BdsLibBuildOptionFromHandle (LoadFileHandles[Index], BdsBootOptionList);\r
899     BootOptionNumber++;\r
900   }\r
901 \r
902   if (NumberLoadFileHandles) {\r
903     gBS->FreePool (LoadFileHandles);\r
904   }\r
905   //\r
906   // Check if we have on flash shell\r
907   //\r
908   gBS->LocateHandleBuffer (\r
909         ByProtocol,\r
910         &gEfiFirmwareVolumeProtocolGuid,\r
911         NULL,\r
912         &FvHandleCount,\r
913         &FvHandleBuffer\r
914         );\r
915   for (Index = 0; Index < FvHandleCount; Index++) {\r
916     gBS->HandleProtocol (\r
917           FvHandleBuffer[Index],\r
918           &gEfiFirmwareVolumeProtocolGuid,\r
919           (VOID **) &Fv\r
920           );\r
921 \r
922     Status = Fv->ReadFile (\r
923                   Fv,\r
924                   &gEfiShellFileGuid,\r
925                   NULL,\r
926                   &Size,\r
927                   &Type,\r
928                   &Attributes,\r
929                   &AuthenticationStatus\r
930                   );\r
931     if (EFI_ERROR (Status)) {\r
932       //\r
933       // Skip if no shell file in the FV\r
934       //\r
935       continue;\r
936     }\r
937     //\r
938     // Build the shell boot option\r
939     //\r
940     BdsLibBuildOptionFromShell (FvHandleBuffer[Index], BdsBootOptionList);\r
941     BootOptionNumber++;\r
942   }\r
943 \r
944   if (FvHandleCount) {\r
945     gBS->FreePool (FvHandleBuffer);\r
946   }\r
947   //\r
948   // Make sure every boot only have one time\r
949   // boot device enumerate\r
950   //\r
951   BdsLibBuildOptionFromVar (BdsBootOptionList, L"BootOrder");\r
952   mEnumBootDevice = TRUE;\r
953 \r
954   return EFI_SUCCESS;\r
955 }\r
956 \r
957 VOID\r
958 BdsLibBuildOptionFromHandle (\r
959   IN  EFI_HANDLE             Handle,\r
960   IN  LIST_ENTRY             *BdsBootOptionList\r
961   )\r
962 /*++\r
963 \r
964 Routine Description:\r
965   \r
966   Build the boot option with the handle parsed in\r
967   \r
968 Arguments:\r
969 \r
970   Handle - The handle which present the device path to create boot option\r
971   \r
972   BdsBootOptionList - The header of the link list which indexed all current\r
973                       boot options\r
974 \r
975 Returns:\r
976 \r
977   VOID\r
978 \r
979 --*/\r
980 {\r
981   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;\r
982   CHAR16                    *TempString;\r
983 \r
984   DevicePath  = DevicePathFromHandle (Handle);\r
985   TempString  = DevicePathToStr (DevicePath);\r
986 \r
987   //\r
988   // Create and register new boot option\r
989   //\r
990   BdsLibRegisterNewOption (BdsBootOptionList, DevicePath, TempString, L"BootOrder");\r
991 }\r
992 \r
993 VOID\r
994 BdsLibBuildOptionFromShell (\r
995   IN EFI_HANDLE              Handle,\r
996   IN OUT LIST_ENTRY          *BdsBootOptionList\r
997   )\r
998 /*++\r
999 \r
1000 Routine Description:\r
1001   \r
1002   Build the on flash shell boot option with the handle parsed in\r
1003   \r
1004 Arguments:\r
1005 \r
1006   Handle - The handle which present the device path to create on flash shell\r
1007            boot option\r
1008   \r
1009   BdsBootOptionList - The header of the link list which indexed all current\r
1010                       boot options\r
1011 \r
1012 Returns:\r
1013 \r
1014   None\r
1015 \r
1016 --*/\r
1017 {\r
1018   EFI_DEVICE_PATH_PROTOCOL          *DevicePath;\r
1019   MEDIA_FW_VOL_FILEPATH_DEVICE_PATH ShellNode;\r
1020 \r
1021   DevicePath = DevicePathFromHandle (Handle);\r
1022 \r
1023   //\r
1024   // Build the shell device path\r
1025   //\r
1026   EfiInitializeFwVolDevicepathNode (&ShellNode, &gEfiShellFileGuid);\r
1027   DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *) &ShellNode);\r
1028 \r
1029   //\r
1030   // Create and register the shell boot option\r
1031   //\r
1032   BdsLibRegisterNewOption (BdsBootOptionList, DevicePath, L"Internal EFI Shell", L"BootOrder");\r
1033 \r
1034 }\r
1035 \r
1036 VOID\r
1037 BdsLibBootNext (\r
1038   VOID\r
1039   )\r
1040 /*++\r
1041 \r
1042 Routine Description:\r
1043   \r
1044   Boot from the EFI1.1 spec defined "BootNext" variable\r
1045   \r
1046 Arguments:\r
1047 \r
1048   None\r
1049   \r
1050 Returns:\r
1051 \r
1052   None\r
1053 \r
1054 --*/\r
1055 {\r
1056   UINT16            *BootNext;\r
1057   UINTN             BootNextSize;\r
1058   CHAR16            Buffer[20];\r
1059   BDS_COMMON_OPTION *BootOption;\r
1060   LIST_ENTRY        TempList;\r
1061   UINTN             ExitDataSize;\r
1062   CHAR16            *ExitData;\r
1063 \r
1064   //\r
1065   // Init the boot option name buffer and temp link list\r
1066   //\r
1067   InitializeListHead (&TempList);\r
1068   ZeroMem (Buffer, sizeof (Buffer));\r
1069 \r
1070   BootNext = BdsLibGetVariableAndSize (\r
1071               L"BootNext",\r
1072               &gEfiGlobalVariableGuid,\r
1073               &BootNextSize\r
1074               );\r
1075 \r
1076   //\r
1077   // Clear the boot next variable first\r
1078   //\r
1079   if (BootNext != NULL) {\r
1080     gRT->SetVariable (\r
1081           L"BootNext",\r
1082           &gEfiGlobalVariableGuid,\r
1083           EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
1084           0,\r
1085           BootNext\r
1086           );\r
1087 \r
1088     //\r
1089     // Start to build the boot option and try to boot\r
1090     //\r
1091     UnicodeSPrint (Buffer, sizeof (Buffer), L"Boot%04x", *BootNext);\r
1092     BootOption = BdsLibVariableToOption (&TempList, Buffer);\r
1093     BdsLibConnectDevicePath (BootOption->DevicePath);\r
1094     BdsLibBootViaBootOption (BootOption, BootOption->DevicePath, &ExitDataSize, &ExitData);\r
1095   }\r
1096 \r
1097 }\r