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