newline added at end
[people/mcb30/edk2.git] / edk2 / EdkUnixPkg / Dxe / PlatformBds / Generic / BootMaint / BootOption.c
1 /*++\r
2 Copyright (c) 2006, Intel Corporation                                                         \r
3 All rights reserved. This program and the accompanying materials                          \r
4 are licensed and made available under the terms and conditions of the BSD License         \r
5 which accompanies this distribution.  The full text of the license may be found at        \r
6 http://opensource.org/licenses/bsd-license.php                                            \r
7                                                                                           \r
8 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
9 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             \r
10 \r
11 Module Name:\r
12 \r
13   BootOption.c\r
14   \r
15 Abstract:\r
16 \r
17   Provide boot option support for Application "BootMaint"\r
18 \r
19   Include file system navigation, system handle selection\r
20 \r
21   Boot option manipulation\r
22   \r
23 Revision History\r
24 \r
25 --*/\r
26 \r
27 #include "BootMaint.h"\r
28 #include "BBSsupport.h"\r
29 \r
30 BM_MENU_ENTRY *\r
31 BOpt_CreateMenuEntry (\r
32   UINTN           MenuType\r
33   )\r
34 /*++\r
35 \r
36 Routine Description\r
37   Create Menu Entry for future use, make all types together\r
38   in order to reduce code size\r
39 \r
40 Arguments:\r
41   MenuType            Use this parameter to identify current\r
42                       Menu type\r
43 \r
44 Returns:\r
45   NULL                Cannot allocate memory for current menu \r
46                       entry\r
47   Others              A valid pointer pointing to the allocated\r
48                       memory pool for current menu entry\r
49 \r
50 --*/\r
51 {\r
52   BM_MENU_ENTRY *MenuEntry;\r
53   UINTN         ContextSize;\r
54 \r
55   switch (MenuType) {\r
56   case BM_LOAD_CONTEXT_SELECT:\r
57     ContextSize = sizeof (BM_LOAD_CONTEXT);\r
58     break;\r
59 \r
60   case BM_FILE_CONTEXT_SELECT:\r
61     ContextSize = sizeof (BM_FILE_CONTEXT);\r
62     break;\r
63 \r
64   case BM_CONSOLE_CONTEXT_SELECT:\r
65     ContextSize = sizeof (BM_CONSOLE_CONTEXT);\r
66     break;\r
67 \r
68   case BM_TERMINAL_CONTEXT_SELECT:\r
69     ContextSize = sizeof (BM_TERMINAL_CONTEXT);\r
70     break;\r
71 \r
72   case BM_HANDLE_CONTEXT_SELECT:\r
73     ContextSize = sizeof (BM_HANDLE_CONTEXT);\r
74     break;\r
75 \r
76   case BM_LEGACY_DEV_CONTEXT_SELECT:\r
77     ContextSize = sizeof (BM_LEGACY_DEVICE_CONTEXT);\r
78     break;\r
79 \r
80   default:\r
81     ContextSize = 0;\r
82     break;\r
83 \r
84   }\r
85 \r
86   if (0 == ContextSize) {\r
87     return NULL;\r
88   }\r
89 \r
90   MenuEntry = AllocateZeroPool (sizeof (BM_MENU_ENTRY));\r
91   if (NULL == MenuEntry) {\r
92     return MenuEntry;\r
93   }\r
94 \r
95   MenuEntry->VariableContext = AllocateZeroPool (ContextSize);\r
96   if (NULL == MenuEntry->VariableContext) {\r
97     SafeFreePool (MenuEntry);\r
98     MenuEntry = NULL;\r
99     return MenuEntry;\r
100   }\r
101 \r
102   MenuEntry->Signature        = BM_MENU_ENTRY_SIGNATURE;\r
103   MenuEntry->ContextSelection = MenuType;\r
104   return MenuEntry;\r
105 }\r
106 \r
107 VOID\r
108 BOpt_DestroyMenuEntry (\r
109   BM_MENU_ENTRY         *MenuEntry\r
110   )\r
111 /*++\r
112   Routine Description :\r
113     Destroy the menu entry passed in\r
114 \r
115   Arguments :\r
116     The menu entry need to be destroyed\r
117 \r
118   Returns :\r
119     None\r
120 \r
121 --*/\r
122 {\r
123   BM_LOAD_CONTEXT           *LoadContext;\r
124   BM_FILE_CONTEXT           *FileContext;\r
125   BM_CONSOLE_CONTEXT        *ConsoleContext;\r
126   BM_TERMINAL_CONTEXT       *TerminalContext;\r
127   BM_HANDLE_CONTEXT         *HandleContext;\r
128   BM_LEGACY_DEVICE_CONTEXT  *LegacyDevContext;\r
129 \r
130   //\r
131   //  Select by the type in Menu entry for current context type\r
132   //\r
133   switch (MenuEntry->ContextSelection) {\r
134   case BM_LOAD_CONTEXT_SELECT:\r
135     LoadContext = (BM_LOAD_CONTEXT *) MenuEntry->VariableContext;\r
136     SafeFreePool (LoadContext->FilePathList);\r
137     SafeFreePool (LoadContext->LoadOption);\r
138     SafeFreePool (LoadContext->OptionalData);\r
139     SafeFreePool (LoadContext);\r
140     break;\r
141 \r
142   case BM_FILE_CONTEXT_SELECT:\r
143     FileContext = (BM_FILE_CONTEXT *) MenuEntry->VariableContext;\r
144 \r
145     if (!FileContext->IsRoot) {\r
146       SafeFreePool (FileContext->DevicePath);\r
147     } else {\r
148       if (FileContext->FHandle != NULL) {\r
149         FileContext->FHandle->Close (FileContext->FHandle);\r
150       }\r
151     }\r
152 \r
153     SafeFreePool (FileContext->FileName);\r
154     SafeFreePool (FileContext->Info);\r
155     SafeFreePool (FileContext);\r
156     break;\r
157 \r
158   case BM_CONSOLE_CONTEXT_SELECT:\r
159     ConsoleContext = (BM_CONSOLE_CONTEXT *) MenuEntry->VariableContext;\r
160     SafeFreePool (ConsoleContext->DevicePath);\r
161     SafeFreePool (ConsoleContext);\r
162     break;\r
163 \r
164   case BM_TERMINAL_CONTEXT_SELECT:\r
165     TerminalContext = (BM_TERMINAL_CONTEXT *) MenuEntry->VariableContext;\r
166     SafeFreePool (TerminalContext->DevicePath);\r
167     SafeFreePool (TerminalContext);\r
168     break;\r
169 \r
170   case BM_HANDLE_CONTEXT_SELECT:\r
171     HandleContext = (BM_HANDLE_CONTEXT *) MenuEntry->VariableContext;\r
172     SafeFreePool (HandleContext);\r
173     break;\r
174 \r
175   case BM_LEGACY_DEV_CONTEXT_SELECT:\r
176     LegacyDevContext = (BM_LEGACY_DEVICE_CONTEXT *) MenuEntry->VariableContext;\r
177     SafeFreePool (LegacyDevContext);\r
178 \r
179   default:\r
180     break;\r
181   }\r
182 \r
183   SafeFreePool (MenuEntry->DisplayString);\r
184   if (NULL != MenuEntry->HelpString) {\r
185     SafeFreePool (MenuEntry->HelpString);\r
186   }\r
187 \r
188   SafeFreePool (MenuEntry);\r
189 }\r
190 \r
191 BM_MENU_ENTRY *\r
192 BOpt_GetMenuEntry (\r
193   BM_MENU_OPTION      *MenuOption,\r
194   UINTN               MenuNumber\r
195   )\r
196 /*++\r
197   Rountine Description :\r
198     Use this routine to get one particular menu entry in specified \r
199     menu\r
200 \r
201   Arguments :\r
202     MenuOption        The menu that we will search \r
203 \r
204     MenuNumber        The menunubmer that we want\r
205 \r
206   Returns :\r
207     The desired menu entry\r
208 \r
209 --*/\r
210 {\r
211   BM_MENU_ENTRY   *NewMenuEntry;\r
212   UINTN           Index;\r
213   LIST_ENTRY      *List;\r
214 \r
215   if (MenuNumber >= MenuOption->MenuNumber) {\r
216     return NULL;\r
217   }\r
218 \r
219   List = MenuOption->Head.ForwardLink;\r
220   for (Index = 0; Index < MenuNumber; Index++) {\r
221     List = List->ForwardLink;\r
222   }\r
223 \r
224   NewMenuEntry = CR (List, BM_MENU_ENTRY, Link, BM_MENU_ENTRY_SIGNATURE);\r
225 \r
226   return NewMenuEntry;\r
227 }\r
228 \r
229 EFI_STATUS\r
230 BOpt_FindFileSystem (\r
231   IN BMM_CALLBACK_DATA          *CallbackData\r
232   )\r
233 /*++\r
234 \r
235 Routine Description\r
236   Find file systems for current Extensible Firmware\r
237   Including Handles that support Simple File System\r
238   protocol, Load File protocol.\r
239 \r
240   Building up the FileSystem Menu for user selection\r
241   All file system will be stored in FsOptionMenu \r
242   for future use.\r
243 \r
244 Arguments:\r
245   CallbackData           -   BMM context data\r
246 \r
247 Returns:\r
248   EFI_SUCCESS            -   Success find the file system\r
249   EFI_OUT_OF_RESOURCES   -   Can not create menu entry\r
250 \r
251 --*/\r
252 {\r
253   UINTN                     NoSimpleFsHandles;\r
254   UINTN                     NoLoadFileHandles;\r
255   EFI_HANDLE                *SimpleFsHandle;\r
256   EFI_HANDLE                *LoadFileHandle;\r
257   UINT16                    *VolumeLabel;\r
258   EFI_BLOCK_IO_PROTOCOL     *BlkIo;\r
259   UINTN                     Index;\r
260   EFI_STATUS                Status;\r
261   BM_MENU_ENTRY             *MenuEntry;\r
262   BM_FILE_CONTEXT           *FileContext;\r
263   UINT16                    *TempStr;\r
264   UINTN                     OptionNumber;\r
265   EFI_LEGACY_BIOS_PROTOCOL  *LegacyBios;\r
266   UINT16                    DeviceType;\r
267   BBS_BBS_DEVICE_PATH       BbsDevicePathNode;\r
268   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;\r
269   BOOLEAN                   RemovableMedia;\r
270 \r
271 \r
272   NoSimpleFsHandles = 0;\r
273   NoLoadFileHandles = 0;\r
274   OptionNumber      = 0;\r
275   InitializeListHead (&FsOptionMenu.Head);\r
276 \r
277   //\r
278   // Locate Handles that support Simple File System protocol\r
279   //\r
280   Status = gBS->LocateHandleBuffer (\r
281                   ByProtocol,\r
282                   &gEfiSimpleFileSystemProtocolGuid,\r
283                   NULL,\r
284                   &NoSimpleFsHandles,\r
285                   &SimpleFsHandle\r
286                   );\r
287   if (!EFI_ERROR (Status)) {\r
288     //\r
289     // Find all the instances of the File System prototocol\r
290     //\r
291     for (Index = 0; Index < NoSimpleFsHandles; Index++) {\r
292       Status = gBS->HandleProtocol (\r
293                       SimpleFsHandle[Index],\r
294                       &gEfiBlockIoProtocolGuid,\r
295                       (VOID**) &BlkIo\r
296                       );\r
297       if (EFI_ERROR (Status)) {\r
298         //\r
299         // If no block IO exists assume it's NOT a removable media\r
300         //\r
301         RemovableMedia = FALSE;\r
302       } else {\r
303         //\r
304         // If block IO exists check to see if it's remobable media\r
305         //\r
306         RemovableMedia = BlkIo->Media->RemovableMedia; \r
307       }\r
308 \r
309       //\r
310       // Allocate pool for this load option\r
311       //\r
312       MenuEntry = BOpt_CreateMenuEntry (BM_FILE_CONTEXT_SELECT);\r
313       if (NULL == MenuEntry) {\r
314         SafeFreePool (SimpleFsHandle);    \r
315         return EFI_OUT_OF_RESOURCES;\r
316       }\r
317 \r
318       FileContext = (BM_FILE_CONTEXT *) MenuEntry->VariableContext;\r
319             \r
320       FileContext->Handle     = SimpleFsHandle[Index];\r
321       MenuEntry->OptionNumber = Index;\r
322       FileContext->FHandle    = EfiLibOpenRoot (FileContext->Handle);\r
323       if (!FileContext->FHandle) {\r
324         BOpt_DestroyMenuEntry (MenuEntry);\r
325         continue;\r
326       }\r
327 \r
328       MenuEntry->HelpString = DevicePathToStr (DevicePathFromHandle (FileContext->Handle));\r
329       FileContext->Info = EfiLibFileSystemVolumeLabelInfo (FileContext->FHandle);\r
330       FileContext->FileName = EfiStrDuplicate (L"\\");\r
331       FileContext->DevicePath = FileDevicePath (\r
332                                   FileContext->Handle,\r
333                                   FileContext->FileName\r
334                                   );\r
335       FileContext->IsDir            = TRUE;\r
336       FileContext->IsRoot           = TRUE;\r
337       FileContext->IsRemovableMedia = FALSE;\r
338       FileContext->IsLoadFile       = FALSE;\r
339 \r
340       //\r
341       // Get current file system's Volume Label\r
342       //\r
343       if (FileContext->Info == NULL) {\r
344         VolumeLabel = L"NO FILE SYSTEM INFO";\r
345       } else {\r
346         if (FileContext->Info->VolumeLabel == NULL) {\r
347           VolumeLabel = L"NULL VOLUME LABEL";\r
348         } else {\r
349           VolumeLabel = FileContext->Info->VolumeLabel;\r
350           if (*VolumeLabel == 0x0000) {\r
351             VolumeLabel = L"NO VOLUME LABEL";\r
352           }\r
353         }\r
354       }\r
355 \r
356       TempStr                   = MenuEntry->HelpString;\r
357       MenuEntry->DisplayString  = AllocateZeroPool (MAX_CHAR);\r
358       ASSERT (MenuEntry->DisplayString != NULL);\r
359       UnicodeSPrint (\r
360         MenuEntry->DisplayString,\r
361         MAX_CHAR,\r
362         L"%s, [%s]",\r
363         VolumeLabel,\r
364         TempStr\r
365         );\r
366       OptionNumber++;\r
367       InsertTailList (&FsOptionMenu.Head, &MenuEntry->Link);      \r
368     }\r
369   }\r
370 \r
371   if (NoSimpleFsHandles != 0) {\r
372     SafeFreePool (SimpleFsHandle);\r
373   }\r
374   //\r
375   // Searching for handles that support Load File protocol\r
376   //\r
377   Status = gBS->LocateHandleBuffer (\r
378                   ByProtocol,\r
379                   &gEfiLoadFileProtocolGuid,\r
380                   NULL,\r
381                   &NoLoadFileHandles,\r
382                   &LoadFileHandle\r
383                   );\r
384 \r
385   if (!EFI_ERROR (Status)) {\r
386     for (Index = 0; Index < NoLoadFileHandles; Index++) {\r
387       MenuEntry = BOpt_CreateMenuEntry (BM_FILE_CONTEXT_SELECT);\r
388       if (NULL == MenuEntry) {\r
389         SafeFreePool (LoadFileHandle);    \r
390         return EFI_OUT_OF_RESOURCES;\r
391       }\r
392 \r
393       FileContext                   = (BM_FILE_CONTEXT *) MenuEntry->VariableContext;\r
394       FileContext->IsRemovableMedia = FALSE;\r
395       FileContext->IsLoadFile       = TRUE;\r
396       FileContext->Handle           = LoadFileHandle[Index];\r
397       FileContext->IsRoot           = TRUE;\r
398 \r
399       FileContext->DevicePath = DevicePathFromHandle (FileContext->Handle);\r
400 \r
401       MenuEntry->HelpString     = DevicePathToStr (FileContext->DevicePath);\r
402 \r
403       TempStr                   = MenuEntry->HelpString;\r
404       MenuEntry->DisplayString  = AllocateZeroPool (MAX_CHAR);\r
405       ASSERT (MenuEntry->DisplayString != NULL);\r
406       UnicodeSPrint (\r
407         MenuEntry->DisplayString,\r
408         MAX_CHAR,\r
409         L"Load File [%s]",\r
410         TempStr\r
411         );\r
412 \r
413       MenuEntry->OptionNumber = OptionNumber;\r
414       OptionNumber++;\r
415       InsertTailList (&FsOptionMenu.Head, &MenuEntry->Link);\r
416     }\r
417   }\r
418 \r
419   if (NoLoadFileHandles != 0) {\r
420     SafeFreePool (LoadFileHandle);\r
421   }\r
422 \r
423   //\r
424   // Add Legacy Boot Option Support Here\r
425   //\r
426   Status = gBS->LocateProtocol (\r
427                   &gEfiLegacyBiosProtocolGuid,\r
428                   NULL,\r
429                   (VOID**) &LegacyBios\r
430                   );\r
431   if (!EFI_ERROR (Status)) {\r
432 \r
433     for (Index = BBS_TYPE_FLOPPY; Index <= BBS_TYPE_EMBEDDED_NETWORK; Index++) {\r
434       MenuEntry = BOpt_CreateMenuEntry (BM_FILE_CONTEXT_SELECT);\r
435       if (NULL == MenuEntry) {\r
436         return EFI_OUT_OF_RESOURCES;\r
437       }\r
438 \r
439       FileContext                       = (BM_FILE_CONTEXT *) MenuEntry->VariableContext;\r
440 \r
441       FileContext->IsRemovableMedia     = FALSE;\r
442       FileContext->IsLoadFile           = TRUE;\r
443       FileContext->IsBootLegacy         = TRUE;\r
444       DeviceType                        = (UINT16) Index;\r
445       BbsDevicePathNode.Header.Type     = BBS_DEVICE_PATH;\r
446       BbsDevicePathNode.Header.SubType  = BBS_BBS_DP;\r
447       SetDevicePathNodeLength (\r
448         &BbsDevicePathNode.Header,\r
449         sizeof (BBS_BBS_DEVICE_PATH)\r
450         );\r
451       BbsDevicePathNode.DeviceType  = DeviceType;\r
452       BbsDevicePathNode.StatusFlag  = 0;\r
453       BbsDevicePathNode.String[0]   = 0;\r
454       DevicePath = AppendDevicePathNode (\r
455                     EndDevicePath,\r
456                     (EFI_DEVICE_PATH_PROTOCOL *) &BbsDevicePathNode\r
457                     );\r
458 \r
459       FileContext->DevicePath   = DevicePath;\r
460       MenuEntry->HelpString     = DevicePathToStr (FileContext->DevicePath);\r
461 \r
462       TempStr                   = MenuEntry->HelpString;\r
463       MenuEntry->DisplayString  = AllocateZeroPool (MAX_CHAR);\r
464       ASSERT (MenuEntry->DisplayString != NULL);\r
465       UnicodeSPrint (\r
466         MenuEntry->DisplayString,\r
467         MAX_CHAR,\r
468         L"Boot Legacy [%s]",\r
469         TempStr\r
470         );\r
471       MenuEntry->OptionNumber = OptionNumber;\r
472       OptionNumber++;\r
473       InsertTailList (&FsOptionMenu.Head, &MenuEntry->Link);\r
474     }\r
475   }\r
476   //\r
477   // Remember how many file system options are here\r
478   //\r
479   FsOptionMenu.MenuNumber = OptionNumber;\r
480   return EFI_SUCCESS;\r
481 }\r
482 \r
483 VOID\r
484 BOpt_FreeMenu (\r
485   BM_MENU_OPTION        *FreeMenu\r
486   )\r
487 /*++\r
488 \r
489 Routine Description\r
490   Free resources allocated in Allocate Rountine\r
491 \r
492 Arguments:\r
493   FreeMenu        Menu to be freed\r
494 \r
495 Returns:\r
496   VOID\r
497   \r
498 --*/\r
499 {\r
500   BM_MENU_ENTRY *MenuEntry;\r
501   while (!IsListEmpty (&FreeMenu->Head)) {\r
502     MenuEntry = CR (\r
503                   FreeMenu->Head.ForwardLink,\r
504                   BM_MENU_ENTRY,\r
505                   Link,\r
506                   BM_MENU_ENTRY_SIGNATURE\r
507                   );\r
508     RemoveEntryList (&MenuEntry->Link);\r
509     BOpt_DestroyMenuEntry (MenuEntry);\r
510   }\r
511 }\r
512 \r
513 EFI_STATUS\r
514 BOpt_FindFiles (\r
515   IN BMM_CALLBACK_DATA          *CallbackData,\r
516   IN BM_MENU_ENTRY              *MenuEntry\r
517   )\r
518 /*++\r
519 \r
520 Routine Description\r
521   Find files under current directory\r
522   All files and sub-directories in current directory\r
523   will be stored in DirectoryMenu for future use.\r
524 \r
525 Arguments:\r
526   FileOption   -- Pointer for Dir to explore\r
527 \r
528 Returns:\r
529   TRUE         -- Get files from current dir successfully\r
530   FALSE        -- Can't get files from current dir\r
531 \r
532 --*/\r
533 {\r
534   EFI_FILE_HANDLE NewDir;\r
535   EFI_FILE_HANDLE Dir;\r
536   EFI_FILE_INFO   *DirInfo;\r
537   UINTN           BufferSize;\r
538   UINTN           DirBufferSize;\r
539   BM_MENU_ENTRY   *NewMenuEntry;\r
540   BM_FILE_CONTEXT *FileContext;\r
541   BM_FILE_CONTEXT *NewFileContext;\r
542   UINTN           Pass;\r
543   EFI_STATUS      Status;\r
544   UINTN           OptionNumber;\r
545 \r
546   FileContext   = (BM_FILE_CONTEXT *) MenuEntry->VariableContext;\r
547   Dir           = FileContext->FHandle;\r
548   OptionNumber  = 0;\r
549   //\r
550   // Open current directory to get files from it\r
551   //\r
552   Status = Dir->Open (\r
553                   Dir,\r
554                   &NewDir,\r
555                   FileContext->FileName,\r
556                   EFI_FILE_READ_ONLY,\r
557                   0\r
558                   );\r
559   if (!FileContext->IsRoot) {\r
560     Dir->Close (Dir);\r
561   }\r
562 \r
563   if (EFI_ERROR (Status)) {\r
564     return Status;\r
565   }\r
566 \r
567   DirInfo = EfiLibFileInfo (NewDir);\r
568   if (!DirInfo) {\r
569     return EFI_NOT_FOUND;\r
570   }\r
571 \r
572   if (!(DirInfo->Attribute & EFI_FILE_DIRECTORY)) {\r
573     return EFI_INVALID_PARAMETER;\r
574   }\r
575 \r
576   FileContext->DevicePath = FileDevicePath (\r
577                               FileContext->Handle,\r
578                               FileContext->FileName\r
579                               );\r
580 \r
581   DirBufferSize = sizeof (EFI_FILE_INFO) + 1024;\r
582   DirInfo       = AllocateZeroPool (DirBufferSize);\r
583   if (!DirInfo) {\r
584     return EFI_OUT_OF_RESOURCES;\r
585   }\r
586   //\r
587   // Get all files in current directory\r
588   // Pass 1 to get Directories\r
589   // Pass 2 to get files that are EFI images\r
590   //\r
591   for (Pass = 1; Pass <= 2; Pass++) {\r
592     NewDir->SetPosition (NewDir, 0);\r
593     for (;;) {\r
594       BufferSize  = DirBufferSize;\r
595       Status      = NewDir->Read (NewDir, &BufferSize, DirInfo);\r
596       if (EFI_ERROR (Status) || BufferSize == 0) {\r
597         break;\r
598       }\r
599 \r
600       if ((DirInfo->Attribute & EFI_FILE_DIRECTORY && Pass == 2) ||\r
601           (!(DirInfo->Attribute & EFI_FILE_DIRECTORY) && Pass == 1)\r
602           ) {\r
603         //\r
604         // Pass 1 is for Directories\r
605         // Pass 2 is for file names\r
606         //\r
607         continue;\r
608       }\r
609 \r
610       if (!(BOpt_IsEfiImageName (DirInfo->FileName) || DirInfo->Attribute & EFI_FILE_DIRECTORY)) {\r
611         //\r
612         // Slip file unless it is a directory entry or a .EFI file\r
613         //\r
614         continue;\r
615       }\r
616 \r
617       NewMenuEntry = BOpt_CreateMenuEntry (BM_FILE_CONTEXT_SELECT);\r
618       if (NULL == NewMenuEntry) {\r
619         return EFI_OUT_OF_RESOURCES;\r
620       }\r
621 \r
622       NewFileContext          = (BM_FILE_CONTEXT *) NewMenuEntry->VariableContext;\r
623       NewFileContext->Handle  = FileContext->Handle;\r
624       NewFileContext->FileName = BOpt_AppendFileName (\r
625                                   FileContext->FileName,\r
626                                   DirInfo->FileName\r
627                                   );\r
628       NewFileContext->FHandle = NewDir;\r
629       NewFileContext->DevicePath = FileDevicePath (\r
630                                     NewFileContext->Handle,\r
631                                     NewFileContext->FileName\r
632                                     );\r
633       NewMenuEntry->HelpString = NULL;\r
634 \r
635       MenuEntry->DisplayStringToken = GetStringTokenFromDepository (\r
636                                         CallbackData,\r
637                                         FileOptionStrDepository\r
638                                         );\r
639 \r
640       NewFileContext->IsDir = (BOOLEAN) ((DirInfo->Attribute & EFI_FILE_DIRECTORY) == EFI_FILE_DIRECTORY);\r
641 \r
642       if (NewFileContext->IsDir) {\r
643         BufferSize                  = StrLen (DirInfo->FileName) * 2 + 6;\r
644         NewMenuEntry->DisplayString = AllocateZeroPool (BufferSize);\r
645 \r
646         UnicodeSPrint (\r
647           NewMenuEntry->DisplayString,\r
648           BufferSize,\r
649           L"<%s>",\r
650           DirInfo->FileName\r
651           );\r
652 \r
653       } else {\r
654         NewMenuEntry->DisplayString = EfiStrDuplicate (DirInfo->FileName);\r
655       }\r
656 \r
657       NewFileContext->IsRoot            = FALSE;\r
658       NewFileContext->IsLoadFile        = FALSE;\r
659       NewFileContext->IsRemovableMedia  = FALSE;\r
660 \r
661       NewMenuEntry->OptionNumber        = OptionNumber;\r
662       OptionNumber++;\r
663       InsertTailList (&DirectoryMenu.Head, &NewMenuEntry->Link);\r
664     }\r
665   }\r
666 \r
667   DirectoryMenu.MenuNumber = OptionNumber;\r
668   SafeFreePool (DirInfo);\r
669   return TRUE;\r
670 }\r
671 \r
672 EFI_STATUS\r
673 BOpt_GetLegacyOptions (\r
674   VOID\r
675   )\r
676 /*++\r
677 Routine Description:\r
678   \r
679   Build the LegacyFDMenu LegacyHDMenu LegacyCDMenu according to LegacyBios.GetBbsInfo().\r
680     \r
681 Arguments:\r
682   None\r
683 \r
684 Returns:\r
685   The device info of legacy device.\r
686   \r
687 --*/\r
688 {\r
689   BM_MENU_ENTRY             *NewMenuEntry;\r
690   BM_LEGACY_DEVICE_CONTEXT  *NewLegacyDevContext;\r
691   EFI_STATUS                Status;\r
692   EFI_LEGACY_BIOS_PROTOCOL  *LegacyBios;\r
693   UINT16                    HddCount;\r
694   HDD_INFO                  *HddInfo;\r
695   UINT16                    BbsCount;\r
696   BBS_TABLE                 *BbsTable;\r
697   UINTN                     Index;\r
698   CHAR16                    DescString[100];\r
699   UINTN                     FDNum;\r
700   UINTN                     HDNum;\r
701   UINTN                     CDNum;\r
702   UINTN                     NETNum;\r
703   UINTN                     BEVNum;\r
704 \r
705   NewMenuEntry  = NULL;\r
706   HddInfo       = NULL;\r
707   BbsTable      = NULL;\r
708   BbsCount      = 0;\r
709 \r
710   //\r
711   // Initialize Bbs Table Context from BBS info data\r
712   //\r
713   InitializeListHead (&LegacyFDMenu.Head);\r
714   InitializeListHead (&LegacyHDMenu.Head);\r
715   InitializeListHead (&LegacyCDMenu.Head);\r
716   InitializeListHead (&LegacyNETMenu.Head);\r
717   InitializeListHead (&LegacyBEVMenu.Head);\r
718 \r
719   Status = gBS->LocateProtocol (\r
720                   &gEfiLegacyBiosProtocolGuid,\r
721                   NULL,\r
722                   (VOID**) &LegacyBios\r
723                   );\r
724   if (!EFI_ERROR (Status)) {\r
725     Status = LegacyBios->GetBbsInfo (\r
726                           LegacyBios,\r
727                           &HddCount,\r
728                           &HddInfo,\r
729                           &BbsCount,\r
730                           &BbsTable\r
731                           );\r
732     if (EFI_ERROR (Status)) {\r
733       return Status;\r
734     }\r
735   }\r
736 \r
737   FDNum   = 0;\r
738   HDNum   = 0;\r
739   CDNum   = 0;\r
740   NETNum  = 0;\r
741   BEVNum  = 0;\r
742 \r
743   for (Index = 0; Index < BbsCount; Index++) {\r
744     if ((BBS_IGNORE_ENTRY == BbsTable[Index].BootPriority) ||\r
745         (BBS_DO_NOT_BOOT_FROM == BbsTable[Index].BootPriority) ||\r
746         (BBS_LOWEST_PRIORITY == BbsTable[Index].BootPriority)\r
747         ) {\r
748       continue;\r
749     }\r
750 \r
751     NewMenuEntry = BOpt_CreateMenuEntry (BM_LEGACY_DEV_CONTEXT_SELECT);\r
752     if (NULL == NewMenuEntry) {\r
753       break;\r
754     }\r
755 \r
756     NewLegacyDevContext           = (BM_LEGACY_DEVICE_CONTEXT *) NewMenuEntry->VariableContext;\r
757     NewLegacyDevContext->BbsTable = &BbsTable[Index];\r
758     NewLegacyDevContext->Index    = Index;\r
759     NewLegacyDevContext->BbsCount = BbsCount;\r
760     BdsBuildLegacyDevNameString (\r
761       &BbsTable[Index],\r
762       Index,\r
763       sizeof (DescString),\r
764       DescString\r
765       );\r
766     NewLegacyDevContext->Description = AllocateZeroPool (StrSize (DescString));\r
767     if (NULL == NewLegacyDevContext->Description) {\r
768       break;\r
769     }\r
770 \r
771     CopyMem (NewLegacyDevContext->Description, DescString, StrSize (DescString));\r
772     NewMenuEntry->DisplayString = NewLegacyDevContext->Description;\r
773     NewMenuEntry->HelpString    = NULL;\r
774 \r
775     switch (BbsTable[Index].DeviceType) {\r
776     case BBS_FLOPPY:\r
777       InsertTailList (&LegacyFDMenu.Head, &NewMenuEntry->Link);\r
778       FDNum++;\r
779       break;\r
780 \r
781     case BBS_HARDDISK:\r
782       InsertTailList (&LegacyHDMenu.Head, &NewMenuEntry->Link);\r
783       HDNum++;\r
784       break;\r
785 \r
786     case BBS_CDROM:\r
787       InsertTailList (&LegacyCDMenu.Head, &NewMenuEntry->Link);\r
788       CDNum++;\r
789       break;\r
790 \r
791     case BBS_EMBED_NETWORK:\r
792       InsertTailList (&LegacyNETMenu.Head, &NewMenuEntry->Link);\r
793       NETNum++;\r
794       break;\r
795 \r
796     case BBS_BEV_DEVICE:\r
797       InsertTailList (&LegacyBEVMenu.Head, &NewMenuEntry->Link);\r
798       BEVNum++;\r
799       break;\r
800     }\r
801   }\r
802 \r
803   if (Index != BbsCount) {\r
804     BOpt_FreeLegacyOptions ();\r
805     return EFI_OUT_OF_RESOURCES;\r
806   }\r
807 \r
808   LegacyFDMenu.MenuNumber   = FDNum;\r
809   LegacyHDMenu.MenuNumber   = HDNum;\r
810   LegacyCDMenu.MenuNumber   = CDNum;\r
811   LegacyNETMenu.MenuNumber  = NETNum;\r
812   LegacyBEVMenu.MenuNumber  = BEVNum;\r
813   return EFI_SUCCESS;\r
814 }\r
815 \r
816 VOID\r
817 BOpt_FreeLegacyOptions (\r
818   VOID\r
819   )\r
820 {\r
821   BOpt_FreeMenu (&LegacyFDMenu);\r
822   BOpt_FreeMenu (&LegacyHDMenu);\r
823   BOpt_FreeMenu (&LegacyCDMenu);\r
824   BOpt_FreeMenu (&LegacyNETMenu);\r
825   BOpt_FreeMenu (&LegacyBEVMenu);\r
826 }\r
827 \r
828 EFI_STATUS\r
829 BOpt_GetBootOptions (\r
830   IN  BMM_CALLBACK_DATA         *CallbackData\r
831   )\r
832 /*++\r
833 \r
834 Routine Description:\r
835   \r
836   Build the BootOptionMenu according to BootOrder Variable.\r
837   This Routine will access the Boot#### to get EFI_LOAD_OPTION \r
838   \r
839 Arguments:\r
840   None\r
841 \r
842 Returns:\r
843   The number of the Var Boot####\r
844   \r
845 --*/\r
846 {\r
847   UINTN                     Index;\r
848   UINT16                    BootString[10];\r
849   UINT8                     *LoadOptionFromVar;\r
850   UINT8                     *LoadOption;\r
851   UINTN                     BootOptionSize;\r
852   BOOLEAN                   BootNextFlag;\r
853   UINT16                    *BootOrderList;\r
854   UINTN                     BootOrderListSize;\r
855   UINT16                    *BootNext;\r
856   UINTN                     BootNextSize;\r
857   BM_MENU_ENTRY             *NewMenuEntry;\r
858   BM_LOAD_CONTEXT           *NewLoadContext;\r
859   UINT8                     *LoadOptionPtr;\r
860   UINTN                     StringSize;\r
861   UINTN                     OptionalDataSize;\r
862   UINT8                     *LoadOptionEnd;\r
863   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;\r
864   UINTN                     MenuCount;\r
865   UINT8                     *Ptr;\r
866 \r
867   MenuCount         = 0;\r
868   BootOrderListSize = 0;\r
869   BootNextSize      = 0;\r
870   BootOrderList     = NULL;\r
871   BootNext          = NULL;\r
872   LoadOptionFromVar = NULL;\r
873   BOpt_FreeMenu (&BootOptionMenu);\r
874   InitializeListHead (&BootOptionMenu.Head);\r
875 \r
876   //\r
877   // Get the BootOrder from the Var\r
878   //\r
879   BootOrderList = BdsLibGetVariableAndSize (\r
880                     L"BootOrder",\r
881                     &gEfiGlobalVariableGuid,\r
882                     &BootOrderListSize\r
883                     );\r
884 \r
885   //\r
886   // Get the BootNext from the Var\r
887   //\r
888   BootNext = BdsLibGetVariableAndSize (\r
889               L"BootNext",\r
890               &gEfiGlobalVariableGuid,\r
891               &BootNextSize\r
892               );\r
893 \r
894   if (BootNext) {\r
895     if (BootNextSize != sizeof (UINT16)) {\r
896       SafeFreePool (BootNext);\r
897       BootNext = NULL;\r
898     }\r
899   }\r
900 \r
901   for (Index = 0; Index < BootOrderListSize / sizeof (UINT16); Index++) {\r
902     UnicodeSPrint (BootString, sizeof (BootString), L"Boot%04x", BootOrderList[Index]);\r
903     //\r
904     //  Get all loadoptions from the VAR\r
905     //\r
906     LoadOptionFromVar = BdsLibGetVariableAndSize (\r
907                           BootString,\r
908                           &gEfiGlobalVariableGuid,\r
909                           &BootOptionSize\r
910                           );\r
911     if (!LoadOptionFromVar) {\r
912       continue;\r
913     }\r
914 \r
915     LoadOption = AllocateZeroPool (BootOptionSize);\r
916     if (!LoadOption) {\r
917       continue;\r
918     }\r
919 \r
920     CopyMem (LoadOption, LoadOptionFromVar, BootOptionSize);\r
921     SafeFreePool (LoadOptionFromVar);\r
922 \r
923     if (BootNext) {\r
924       BootNextFlag = (BOOLEAN) (*BootNext == BootOrderList[Index]);\r
925     } else {\r
926       BootNextFlag = FALSE;\r
927     }\r
928 \r
929     if (0 == (*((UINT32 *) LoadOption) & LOAD_OPTION_ACTIVE)) {\r
930       SafeFreePool (LoadOption);\r
931       continue;\r
932     }\r
933     //\r
934     // BUGBUG: could not return EFI_OUT_OF_RESOURCES here directly.\r
935     // the buffer allocated already should be freed before returning.\r
936     //\r
937     NewMenuEntry = BOpt_CreateMenuEntry (BM_LOAD_CONTEXT_SELECT);\r
938     if (NULL == NewMenuEntry) {\r
939       return EFI_OUT_OF_RESOURCES;\r
940     }\r
941 \r
942     NewLoadContext                      = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;\r
943 \r
944     LoadOptionPtr                       = LoadOption;\r
945     LoadOptionEnd                       = LoadOption + BootOptionSize;\r
946 \r
947     NewMenuEntry->OptionNumber          = BootOrderList[Index];\r
948     NewLoadContext->LoadOptionModified  = FALSE;\r
949     NewLoadContext->Deleted             = FALSE;\r
950     NewLoadContext->IsBootNext          = BootNextFlag;\r
951 \r
952     //\r
953     // Is a Legacy Device?\r
954     //\r
955     Ptr = (UINT8 *) LoadOption;\r
956 \r
957     //\r
958     // Attribute = *(UINT32 *)Ptr;\r
959     //\r
960     Ptr += sizeof (UINT32);\r
961 \r
962     //\r
963     // FilePathSize = *(UINT16 *)Ptr;\r
964     //\r
965     Ptr += sizeof (UINT16);\r
966 \r
967     //\r
968     // Description = (CHAR16 *)Ptr;\r
969     //\r
970     Ptr += StrSize ((CHAR16 *) Ptr);\r
971 \r
972     //\r
973     // Now Ptr point to Device Path\r
974     //\r
975     DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) Ptr;\r
976     if ((BBS_DEVICE_PATH == DevicePath->Type) && (BBS_BBS_DP == DevicePath->SubType)) {\r
977       NewLoadContext->IsLegacy = TRUE;\r
978     } else {\r
979       NewLoadContext->IsLegacy = FALSE;\r
980     }\r
981     //\r
982     // LoadOption is a pointer type of UINT8\r
983     // for easy use with following LOAD_OPTION\r
984     // embedded in this struct\r
985     //\r
986     NewLoadContext->LoadOption      = LoadOption;\r
987     NewLoadContext->LoadOptionSize  = BootOptionSize;\r
988 \r
989     NewLoadContext->Attributes      = *(UINT32 *) LoadOptionPtr;\r
990     NewLoadContext->IsActive        = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_ACTIVE);\r
991 \r
992     NewLoadContext->ForceReconnect  = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_FORCE_RECONNECT);\r
993 \r
994     LoadOptionPtr += sizeof (UINT32);\r
995 \r
996     NewLoadContext->FilePathListLength = *(UINT16 *) LoadOptionPtr;\r
997     LoadOptionPtr += sizeof (UINT16);\r
998 \r
999     StringSize                  = StrSize ((UINT16 *) LoadOptionPtr);\r
1000     NewLoadContext->Description = AllocateZeroPool (StringSize);\r
1001     ASSERT (NewLoadContext->Description != NULL);\r
1002     CopyMem (\r
1003       NewLoadContext->Description,\r
1004       (UINT16 *) LoadOptionPtr,\r
1005       StringSize\r
1006       );\r
1007     NewMenuEntry->DisplayString = NewLoadContext->Description;\r
1008 \r
1009     LoadOptionPtr += StringSize;\r
1010 \r
1011     NewLoadContext->FilePathList = AllocateZeroPool (NewLoadContext->FilePathListLength);\r
1012     ASSERT (NewLoadContext->FilePathList != NULL);\r
1013     CopyMem (\r
1014       NewLoadContext->FilePathList,\r
1015       (EFI_DEVICE_PATH_PROTOCOL *) LoadOptionPtr,\r
1016       NewLoadContext->FilePathListLength\r
1017       );\r
1018 \r
1019     NewMenuEntry->HelpString = DevicePathToStr (NewLoadContext->FilePathList);\r
1020     NewMenuEntry->DisplayStringToken = GetStringTokenFromDepository (\r
1021                                         CallbackData,\r
1022                                         BootOptionStrDepository\r
1023                                         );\r
1024     NewMenuEntry->HelpStringToken = GetStringTokenFromDepository (\r
1025                                       CallbackData,\r
1026                                       BootOptionHelpStrDepository\r
1027                                       );\r
1028     LoadOptionPtr += NewLoadContext->FilePathListLength;\r
1029 \r
1030     if (LoadOptionPtr < LoadOptionEnd) {\r
1031       OptionalDataSize = BootOptionSize -\r
1032         sizeof (UINT32) -\r
1033         sizeof (UINT16) -\r
1034         StringSize -\r
1035         NewLoadContext->FilePathListLength;\r
1036 \r
1037       NewLoadContext->OptionalData = AllocateZeroPool (OptionalDataSize);\r
1038       ASSERT (NewLoadContext->OptionalData != NULL);\r
1039       CopyMem (\r
1040         NewLoadContext->OptionalData,\r
1041         LoadOptionPtr,\r
1042         OptionalDataSize\r
1043         );\r
1044 \r
1045       NewLoadContext->OptionalDataSize = OptionalDataSize;\r
1046     }\r
1047 \r
1048     InsertTailList (&BootOptionMenu.Head, &NewMenuEntry->Link);\r
1049     MenuCount++;\r
1050   }\r
1051 \r
1052   SafeFreePool (BootNext);\r
1053   SafeFreePool (BootOrderList);\r
1054   BootOptionMenu.MenuNumber = MenuCount;\r
1055   return MenuCount;\r
1056 }\r
1057 \r
1058 CHAR16 *\r
1059 BdsStrCpy (\r
1060   OUT     CHAR16                    *Destination,\r
1061   IN      CONST CHAR16              *Source\r
1062   )\r
1063 {\r
1064   CHAR16                            *ReturnValue;\r
1065 \r
1066   //\r
1067   // Destination cannot be NULL\r
1068   //\r
1069   ASSERT (Destination != NULL);\r
1070 \r
1071   ReturnValue = Destination;\r
1072   while (*Source) {\r
1073     *(Destination++) = *(Source++);\r
1074   }\r
1075   *Destination = 0;\r
1076   return ReturnValue;\r
1077 }\r
1078 \r
1079 CHAR16 *\r
1080 BOpt_AppendFileName (\r
1081   IN  CHAR16  *Str1,\r
1082   IN  CHAR16  *Str2\r
1083   )\r
1084 /*++\r
1085 \r
1086 Routine Description\r
1087   Append file name to existing file name.\r
1088 \r
1089 Arguments:\r
1090   Str1  -   existing file name\r
1091   Str2  -   file name to be appended\r
1092 \r
1093 Returns:\r
1094   Allocate a new string to hold the appended result.\r
1095   Caller is responsible to free the returned string.\r
1096 \r
1097 --*/\r
1098 {\r
1099   UINTN   Size1;\r
1100   UINTN   Size2;\r
1101   CHAR16  *Str;\r
1102   CHAR16  *Ptr;\r
1103   CHAR16  *LastSlash;\r
1104 \r
1105   Size1 = StrSize (Str1);\r
1106   Size2 = StrSize (Str2);\r
1107   Str   = AllocateZeroPool (Size1 + Size2 + sizeof (CHAR16));\r
1108   ASSERT (Str != NULL);\r
1109 \r
1110   StrCat (Str, Str1);\r
1111   if (!((*Str == '\\') && (*(Str + 1) == 0))) {\r
1112     StrCat (Str, L"\\");\r
1113   }\r
1114 \r
1115   StrCat (Str, Str2);\r
1116 \r
1117   Ptr       = Str;\r
1118   LastSlash = Str;\r
1119   while (*Ptr != 0) {\r
1120     if (*Ptr == '\\' && *(Ptr + 1) == '.' && *(Ptr + 2) == '.' && *(Ptr + 3) != 0) {\r
1121       //\r
1122       // Convert "\Name\..\" to "\"\r
1123       // DO NOT convert the .. if it is at the end of the string. This will\r
1124       // break the .. behavior in changing directories.\r
1125       //\r
1126       BdsStrCpy (LastSlash, Ptr + 3);\r
1127       Ptr = LastSlash;\r
1128     } else if (*Ptr == '\\' && *(Ptr + 1) == '.' && *(Ptr + 2) == '\\') {\r
1129       //\r
1130       // Convert a "\.\" to a "\"\r
1131       //\r
1132       BdsStrCpy (Ptr, Ptr + 2);\r
1133       Ptr = LastSlash;\r
1134     } else if (*Ptr == '\\') {\r
1135       LastSlash = Ptr;\r
1136     }\r
1137 \r
1138     Ptr++;\r
1139   }\r
1140 \r
1141   return Str;\r
1142 }\r
1143 \r
1144 BOOLEAN\r
1145 BOpt_IsEfiImageName (\r
1146   IN UINT16  *FileName\r
1147   )\r
1148 /*++\r
1149 \r
1150 Routine Description\r
1151   Check whether current FileName point to a valid \r
1152   Efi Image File.\r
1153 \r
1154 Arguments:\r
1155   FileName  -   File need to be checked.\r
1156 \r
1157 Returns:\r
1158   TRUE  -   Is Efi Image\r
1159   FALSE -   Not a valid Efi Image\r
1160   \r
1161 --*/\r
1162 {\r
1163   //\r
1164   // Search for ".efi" extension\r
1165   //\r
1166   while (*FileName) {\r
1167     if (FileName[0] == '.') {\r
1168       if (FileName[1] == 'e' || FileName[1] == 'E') {\r
1169         if (FileName[2] == 'f' || FileName[2] == 'F') {\r
1170           if (FileName[3] == 'i' || FileName[3] == 'I') {\r
1171             return TRUE;\r
1172           } else if (FileName[3] == 0x0000) {\r
1173             return FALSE;\r
1174           }\r
1175         } else if (FileName[2] == 0x0000) {\r
1176           return FALSE;\r
1177         }\r
1178       } else if (FileName[1] == 0x0000) {\r
1179         return FALSE;\r
1180       }\r
1181     }\r
1182 \r
1183     FileName += 1;\r
1184   }\r
1185 \r
1186   return FALSE;\r
1187 }\r
1188 \r
1189 \r
1190 RETURN_STATUS\r
1191 EFIAPI\r
1192 IsEfiAppReadFromFile (\r
1193   IN     VOID    *FileHandle,\r
1194   IN     UINTN   FileOffset,\r
1195   IN OUT UINTN   *ReadSize,\r
1196   OUT    VOID    *Buffer\r
1197   )\r
1198 {\r
1199   EFI_STATUS        Status;\r
1200   EFI_FILE_HANDLE   File;\r
1201     \r
1202   File = (EFI_FILE_HANDLE)FileHandle;\r
1203   Status = File->SetPosition (File, FileOffset);\r
1204   if (EFI_ERROR (Status)) {\r
1205     return Status;\r
1206   }\r
1207 \r
1208   return File->Read (File, ReadSize, Buffer);\r
1209 }\r
1210 \r
1211 \r
1212 \r
1213 BOOLEAN\r
1214 BOpt_IsEfiApp (\r
1215   IN EFI_FILE_HANDLE Dir,\r
1216   IN UINT16          *FileName\r
1217   )\r
1218 /*++\r
1219 \r
1220 Routine Description:\r
1221   Check whether current FileName point to a valid Efi Application\r
1222   \r
1223 Arguments:\r
1224   Dir       -   Pointer to current Directory\r
1225   FileName  -   Pointer to current File name.\r
1226   \r
1227 Returns:\r
1228   TRUE      -   Is a valid Efi Application\r
1229   FALSE     -   not a valid Efi Application\r
1230   \r
1231 --*/\r
1232 {\r
1233   EFI_STATUS                            Status;\r
1234   PE_COFF_LOADER_IMAGE_CONTEXT          ImageContext;\r
1235   EFI_FILE_HANDLE                       File;\r
1236 \r
1237   Status = Dir->Open (Dir, &File, FileName, EFI_FILE_MODE_READ, 0);\r
1238   if (EFI_ERROR (Status)) {\r
1239     return FALSE;\r
1240   }\r
1241 \r
1242   ZeroMem (&ImageContext, sizeof (ImageContext));\r
1243   ImageContext.Handle    = (VOID *)File;\r
1244   ImageContext.ImageRead = IsEfiAppReadFromFile;\r
1245 \r
1246   Status = PeCoffLoaderGetImageInfo (&ImageContext);\r
1247   File->Close (File);\r
1248   if (EFI_ERROR (Status)) {\r
1249     return FALSE;\r
1250   }\r
1251 \r
1252   if (ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) {\r
1253     return TRUE;\r
1254   } else {\r
1255     return FALSE;\r
1256   }\r
1257  }\r
1258 \r
1259 \r
1260 EFI_STATUS\r
1261 BOpt_FindDrivers (\r
1262   VOID\r
1263   )\r
1264 /*++\r
1265 \r
1266 Routine Description\r
1267   Find drivers that will be added as Driver#### variables from handles\r
1268   in current system environment\r
1269   All valid handles in the system except those consume SimpleFs, LoadFile\r
1270   are stored in DriverMenu for future use.\r
1271   \r
1272 Arguments:\r
1273   None\r
1274 \r
1275 Returns:\r
1276   EFI_SUCCESS\r
1277   Others\r
1278 \r
1279 --*/\r
1280 {\r
1281   UINTN                           NoDevicePathHandles;\r
1282   EFI_HANDLE                      *DevicePathHandle;\r
1283   UINTN                           Index;\r
1284   EFI_STATUS                      Status;\r
1285   BM_MENU_ENTRY                   *NewMenuEntry;\r
1286   BM_HANDLE_CONTEXT               *NewHandleContext;\r
1287   EFI_HANDLE                      CurHandle;\r
1288   UINTN                           OptionNumber;\r
1289   EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFs;\r
1290   EFI_LOAD_FILE_PROTOCOL          *LoadFile;\r
1291 \r
1292   SimpleFs  = NULL;\r
1293   LoadFile  = NULL;\r
1294 \r
1295   InitializeListHead (&DriverMenu.Head);\r
1296 \r
1297   //\r
1298   // At first, get all handles that support Device Path\r
1299   // protocol which is the basic requirement for\r
1300   // Driver####\r
1301   //\r
1302   Status = gBS->LocateHandleBuffer (\r
1303                   ByProtocol,\r
1304                   &gEfiDevicePathProtocolGuid,\r
1305                   NULL,\r
1306                   &NoDevicePathHandles,\r
1307                   &DevicePathHandle\r
1308                   );\r
1309   if (EFI_ERROR (Status)) {\r
1310     return Status;\r
1311   }\r
1312 \r
1313   OptionNumber = 0;\r
1314   for (Index = 0; Index < NoDevicePathHandles; Index++) {\r
1315     CurHandle = DevicePathHandle[Index];\r
1316 \r
1317     //\r
1318     //  Check whether this handle support\r
1319     //  driver binding\r
1320     //\r
1321     Status = gBS->HandleProtocol (\r
1322                     CurHandle,\r
1323                     &gEfiSimpleFileSystemProtocolGuid,\r
1324                     (VOID**) &SimpleFs\r
1325                     );\r
1326     if (Status == EFI_SUCCESS) {\r
1327       continue;\r
1328     }\r
1329 \r
1330     Status = gBS->HandleProtocol (\r
1331                     CurHandle,\r
1332                     &gEfiLoadFileProtocolGuid,\r
1333                     (VOID**) &LoadFile\r
1334                     );\r
1335     if (Status == EFI_SUCCESS) {\r
1336       continue;\r
1337     }\r
1338 \r
1339     NewMenuEntry = BOpt_CreateMenuEntry (BM_HANDLE_CONTEXT_SELECT);\r
1340     if (NULL == NewMenuEntry) {\r
1341       return EFI_OUT_OF_RESOURCES;\r
1342     }\r
1343 \r
1344     NewHandleContext              = (BM_HANDLE_CONTEXT *) NewMenuEntry->VariableContext;\r
1345     NewHandleContext->Handle      = CurHandle;\r
1346     NewHandleContext->DevicePath  = DevicePathFromHandle (CurHandle);\r
1347     NewMenuEntry->DisplayString = DevicePathToStr (NewHandleContext->DevicePath);\r
1348     NewMenuEntry->HelpString    = NULL;\r
1349     NewMenuEntry->OptionNumber  = OptionNumber;\r
1350     OptionNumber++;\r
1351     InsertTailList (&DriverMenu.Head, &NewMenuEntry->Link);\r
1352 \r
1353   }\r
1354 \r
1355   DriverMenu.MenuNumber = OptionNumber;\r
1356   return EFI_SUCCESS;\r
1357 }\r
1358 \r
1359 UINT16\r
1360 BOpt_GetBootOptionNumber (\r
1361   VOID\r
1362   )\r
1363 /*++\r
1364 \r
1365 Routine Description:\r
1366   Get the Option Number that does not used \r
1367   \r
1368 Arguments:\r
1369 \r
1370 Returns:\r
1371   The Option Number\r
1372   \r
1373 --*/\r
1374 {\r
1375   BM_MENU_ENTRY *NewMenuEntry;\r
1376   UINT16        *BootOrderList;\r
1377   UINTN         BootOrderListSize;\r
1378   UINT16        Number;\r
1379   UINTN         Index;\r
1380   UINTN         Index2;\r
1381   BOOLEAN       Found;\r
1382   CHAR16        StrTemp[100];\r
1383   UINT16        *OptionBuffer;\r
1384   UINTN         OptionSize;\r
1385 \r
1386   BootOrderListSize = 0;\r
1387   BootOrderList     = NULL;\r
1388 \r
1389   BootOrderList = BdsLibGetVariableAndSize (\r
1390                     L"BootOrder",\r
1391                     &gEfiGlobalVariableGuid,\r
1392                     &BootOrderListSize\r
1393                     );\r
1394   if (BootOrderList) {\r
1395     //\r
1396     // already have Boot####\r
1397     //\r
1398     // AlreadyBootNumbers = BootOrderListSize / sizeof(UINT16);\r
1399     //\r
1400     for (Index = 0; Index < BootOrderListSize / sizeof (UINT16); Index++) {\r
1401       Found = TRUE;\r
1402       for (Index2 = 0; Index2 < BootOptionMenu.MenuNumber; Index2++) {\r
1403         NewMenuEntry = BOpt_GetMenuEntry (&BootOptionMenu, Index2);\r
1404         if (Index == NewMenuEntry->OptionNumber) {\r
1405           Found = FALSE;\r
1406           break;\r
1407         }\r
1408       }\r
1409 \r
1410       if (Found) {\r
1411            UnicodeSPrint (StrTemp, 100, L"Boot%04x", Index);\r
1412            DEBUG((EFI_D_ERROR,"INdex= %s\n", StrTemp));\r
1413        OptionBuffer = BdsLibGetVariableAndSize (\r
1414                 StrTemp,\r
1415                 &gEfiGlobalVariableGuid,\r
1416                 &OptionSize\r
1417                 );\r
1418       if (NULL == OptionBuffer) \r
1419         break;\r
1420       }\r
1421     }\r
1422     //\r
1423     // end for Index\r
1424     //\r
1425     Number = (UINT16) Index;\r
1426   } else {\r
1427     //\r
1428     // No Boot####\r
1429     //\r
1430     Number = 0;\r
1431   }\r
1432 \r
1433   return Number;\r
1434 }\r
1435 \r
1436 UINT16\r
1437 BOpt_GetDriverOptionNumber (\r
1438   VOID\r
1439   )\r
1440 /*++\r
1441 \r
1442 Routine Description:\r
1443   Get the Option Number that does not used \r
1444   \r
1445 Arguments:\r
1446 \r
1447 Returns:\r
1448   The Option Number\r
1449   \r
1450 --*/\r
1451 {\r
1452   BM_MENU_ENTRY *NewMenuEntry;\r
1453   UINT16        *DriverOrderList;\r
1454   UINTN         DriverOrderListSize;\r
1455   UINT16        Number;\r
1456   UINTN         Index;\r
1457   UINTN         Index2;\r
1458   BOOLEAN       Found;\r
1459 \r
1460   DriverOrderListSize = 0;\r
1461   DriverOrderList     = NULL;\r
1462 \r
1463   DriverOrderList = BdsLibGetVariableAndSize (\r
1464                       L"DriverOrder",\r
1465                       &gEfiGlobalVariableGuid,\r
1466                       &DriverOrderListSize\r
1467                       );\r
1468   if (DriverOrderList) {\r
1469     //\r
1470     // already have Driver####\r
1471     //\r
1472     // AlreadyDriverNumbers = DriverOrderListSize / sizeof(UINT16);\r
1473     //\r
1474     for (Index = 0; Index < DriverOrderListSize / sizeof (UINT16); Index++) {\r
1475       Found = TRUE;\r
1476       for (Index2 = 0; Index2 < DriverOptionMenu.MenuNumber; Index2++) {\r
1477         NewMenuEntry = BOpt_GetMenuEntry (&DriverOptionMenu, Index2);\r
1478         if (Index == NewMenuEntry->OptionNumber) {\r
1479           Found = FALSE;\r
1480           break;\r
1481         }\r
1482       }\r
1483 \r
1484       if (Found) {\r
1485         break;\r
1486       }\r
1487     }\r
1488     //\r
1489     // end for Index\r
1490     //\r
1491     Number = (UINT16) Index;\r
1492   } else {\r
1493     //\r
1494     // No Driver####\r
1495     //\r
1496     Number = 0;\r
1497   }\r
1498 \r
1499   return Number;\r
1500 }\r
1501 \r
1502 EFI_STATUS\r
1503 BOpt_GetDriverOptions (\r
1504   IN  BMM_CALLBACK_DATA         *CallbackData\r
1505   )\r
1506 /*++\r
1507 \r
1508 Routine Description:\r
1509   Build up all DriverOptionMenu\r
1510   \r
1511 Arguments:\r
1512 \r
1513 Returns:\r
1514   The Option Number\r
1515   \r
1516 --*/\r
1517 {\r
1518   UINTN           Index;\r
1519   UINT16          DriverString[12];\r
1520   UINT8           *LoadOptionFromVar;\r
1521   UINT8           *LoadOption;\r
1522   UINTN           DriverOptionSize;\r
1523 \r
1524   UINT16          *DriverOrderList;\r
1525   UINTN           DriverOrderListSize;\r
1526   BM_MENU_ENTRY   *NewMenuEntry;\r
1527   BM_LOAD_CONTEXT *NewLoadContext;\r
1528   UINT8           *LoadOptionPtr;\r
1529   UINTN           StringSize;\r
1530   UINTN           OptionalDataSize;\r
1531   UINT8           *LoadOptionEnd;\r
1532 \r
1533   DriverOrderListSize = 0;\r
1534   DriverOrderList     = NULL;\r
1535   DriverOptionSize    = 0;\r
1536   LoadOptionFromVar   = NULL;\r
1537   BOpt_FreeMenu (&DriverOptionMenu);\r
1538   InitializeListHead (&DriverOptionMenu.Head);\r
1539   //\r
1540   // Get the DriverOrder from the Var\r
1541   //\r
1542   DriverOrderList = BdsLibGetVariableAndSize (\r
1543                       L"DriverOrder",\r
1544                       &gEfiGlobalVariableGuid,\r
1545                       &DriverOrderListSize\r
1546                       );\r
1547 \r
1548   for (Index = 0; Index < DriverOrderListSize / sizeof (UINT16); Index++) {\r
1549     UnicodeSPrint (\r
1550       DriverString,\r
1551       sizeof (DriverString),\r
1552       L"Driver%04x",\r
1553       DriverOrderList[Index]\r
1554       );\r
1555     //\r
1556     //  Get all loadoptions from the VAR\r
1557     //\r
1558     LoadOptionFromVar = BdsLibGetVariableAndSize (\r
1559                           DriverString,\r
1560                           &gEfiGlobalVariableGuid,\r
1561                           &DriverOptionSize\r
1562                           );\r
1563     if (!LoadOptionFromVar) {\r
1564       continue;\r
1565     }\r
1566 \r
1567     LoadOption = AllocateZeroPool (DriverOptionSize);\r
1568     if (!LoadOption) {\r
1569       continue;\r
1570     }\r
1571 \r
1572     CopyMem (LoadOption, LoadOptionFromVar, DriverOptionSize);\r
1573     SafeFreePool (LoadOptionFromVar);\r
1574 \r
1575     NewMenuEntry = BOpt_CreateMenuEntry (BM_LOAD_CONTEXT_SELECT);\r
1576     if (NULL == NewMenuEntry) {\r
1577       return EFI_OUT_OF_RESOURCES;\r
1578     }\r
1579 \r
1580     NewLoadContext                      = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;\r
1581     LoadOptionPtr                       = LoadOption;\r
1582     LoadOptionEnd                       = LoadOption + DriverOptionSize;\r
1583     NewMenuEntry->OptionNumber          = DriverOrderList[Index];\r
1584     NewLoadContext->LoadOptionModified  = FALSE;\r
1585     NewLoadContext->Deleted             = FALSE;\r
1586     NewLoadContext->IsLegacy            = FALSE;\r
1587 \r
1588     //\r
1589     // LoadOption is a pointer type of UINT8\r
1590     // for easy use with following LOAD_OPTION\r
1591     // embedded in this struct\r
1592     //\r
1593     NewLoadContext->LoadOption      = LoadOption;\r
1594     NewLoadContext->LoadOptionSize  = DriverOptionSize;\r
1595 \r
1596     NewLoadContext->Attributes      = *(UINT32 *) LoadOptionPtr;\r
1597     NewLoadContext->IsActive        = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_ACTIVE);\r
1598 \r
1599     NewLoadContext->ForceReconnect  = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_FORCE_RECONNECT);\r
1600 \r
1601     LoadOptionPtr += sizeof (UINT32);\r
1602 \r
1603     NewLoadContext->FilePathListLength = *(UINT16 *) LoadOptionPtr;\r
1604     LoadOptionPtr += sizeof (UINT16);\r
1605 \r
1606     StringSize                  = StrSize ((UINT16 *) LoadOptionPtr);\r
1607     NewLoadContext->Description = AllocateZeroPool (StringSize);\r
1608     ASSERT (NewLoadContext->Description != NULL);\r
1609     CopyMem (\r
1610       NewLoadContext->Description,\r
1611       (UINT16 *) LoadOptionPtr,\r
1612       StringSize\r
1613       );\r
1614     NewMenuEntry->DisplayString = NewLoadContext->Description;\r
1615 \r
1616     LoadOptionPtr += StringSize;\r
1617 \r
1618     NewLoadContext->FilePathList = AllocateZeroPool (NewLoadContext->FilePathListLength);\r
1619     ASSERT (NewLoadContext->FilePathList != NULL);\r
1620     CopyMem (\r
1621       NewLoadContext->FilePathList,\r
1622       (EFI_DEVICE_PATH_PROTOCOL *) LoadOptionPtr,\r
1623       NewLoadContext->FilePathListLength\r
1624       );\r
1625 \r
1626     NewMenuEntry->HelpString = DevicePathToStr (NewLoadContext->FilePathList);\r
1627     NewMenuEntry->DisplayStringToken = GetStringTokenFromDepository (\r
1628                                         CallbackData,\r
1629                                         DriverOptionStrDepository\r
1630                                         );\r
1631     NewMenuEntry->HelpStringToken = GetStringTokenFromDepository (\r
1632                                       CallbackData,\r
1633                                       DriverOptionHelpStrDepository\r
1634                                       );\r
1635     LoadOptionPtr += NewLoadContext->FilePathListLength;\r
1636 \r
1637     if (LoadOptionPtr < LoadOptionEnd) {\r
1638       OptionalDataSize = DriverOptionSize -\r
1639         sizeof (UINT32) -\r
1640         sizeof (UINT16) -\r
1641         StringSize -\r
1642         NewLoadContext->FilePathListLength;\r
1643 \r
1644       NewLoadContext->OptionalData = AllocateZeroPool (OptionalDataSize);\r
1645       ASSERT (NewLoadContext->OptionalData != NULL);\r
1646       CopyMem (\r
1647         NewLoadContext->OptionalData,\r
1648         LoadOptionPtr,\r
1649         OptionalDataSize\r
1650         );\r
1651 \r
1652       NewLoadContext->OptionalDataSize = OptionalDataSize;\r
1653     }\r
1654 \r
1655     InsertTailList (&DriverOptionMenu.Head, &NewMenuEntry->Link);\r
1656 \r
1657   }\r
1658 \r
1659   SafeFreePool (DriverOrderList);\r
1660   DriverOptionMenu.MenuNumber = Index;\r
1661   return EFI_SUCCESS;\r
1662 \r
1663 }\r
1664 \r
1665 VOID\r
1666 SafeFreePool (\r
1667   IN VOID    *Buffer\r
1668   )\r
1669 /*++\r
1670 \r
1671 Routine Description:\r
1672   Wrap original FreePool gBS call\r
1673   in order to decrease code length\r
1674   \r
1675 Arguments:\r
1676 \r
1677 Returns:\r
1678 \r
1679 --*/\r
1680 {\r
1681   if (Buffer != NULL) {\r
1682     gBS->FreePool (Buffer);\r
1683     Buffer = NULL;\r
1684   }\r
1685 }\r