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