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