• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2 Variable operation that will be used by bootmaint
3 
4 Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution.  The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9 
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12 
13 **/
14 
15 #include "BootMaintenanceManager.h"
16 
17 /**
18   Delete Boot Option that represent a Deleted state in BootOptionMenu.
19   After deleting this boot option, call Var_ChangeBootOrder to
20   make sure BootOrder is in valid state.
21 
22   @retval EFI_SUCCESS   If all boot load option EFI Variables corresponding to
23                         BM_LOAD_CONTEXT marked for deletion is deleted.
24   @retval EFI_NOT_FOUND If can not find the boot option want to be deleted.
25   @return Others        If failed to update the "BootOrder" variable after deletion.
26 
27 **/
28 EFI_STATUS
Var_DelBootOption(VOID)29 Var_DelBootOption (
30   VOID
31   )
32 {
33   BM_MENU_ENTRY   *NewMenuEntry;
34   BM_LOAD_CONTEXT *NewLoadContext;
35   UINT16          BootString[10];
36   EFI_STATUS      Status;
37   UINTN           Index;
38   UINTN           Index2;
39 
40   Status  = EFI_SUCCESS;
41   Index2  = 0;
42   for (Index = 0; Index < BootOptionMenu.MenuNumber; Index++) {
43     NewMenuEntry = BOpt_GetMenuEntry (&BootOptionMenu, (Index - Index2));
44     if (NULL == NewMenuEntry) {
45       return EFI_NOT_FOUND;
46     }
47 
48     NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
49     if (!NewLoadContext->Deleted) {
50       continue;
51     }
52 
53     UnicodeSPrint (
54       BootString,
55       sizeof (BootString),
56       L"Boot%04x",
57       NewMenuEntry->OptionNumber
58       );
59 
60     EfiLibDeleteVariable (BootString, &gEfiGlobalVariableGuid);
61     Index2++;
62     //
63     // If current Load Option is the same as BootNext,
64     // must delete BootNext in order to make sure
65     // there will be no panic on next boot
66     //
67     if (NewLoadContext->IsBootNext) {
68       EfiLibDeleteVariable (L"BootNext", &gEfiGlobalVariableGuid);
69     }
70 
71     RemoveEntryList (&NewMenuEntry->Link);
72     BOpt_DestroyMenuEntry (NewMenuEntry);
73     NewMenuEntry = NULL;
74   }
75 
76   BootOptionMenu.MenuNumber -= Index2;
77 
78   Status = Var_ChangeBootOrder ();
79   return Status;
80 }
81 
82 /**
83   After any operation on Boot####, there will be a discrepancy in BootOrder.
84   Since some are missing but in BootOrder, while some are present but are
85   not reflected by BootOrder. Then a function rebuild BootOrder from
86   scratch by content from BootOptionMenu is needed.
87 
88 
89 
90 
91   @retval  EFI_SUCCESS  The boot order is updated successfully.
92   @return               EFI_STATUS other than EFI_SUCCESS if failed to
93                         Set the "BootOrder" EFI Variable.
94 
95 **/
96 EFI_STATUS
Var_ChangeBootOrder(VOID)97 Var_ChangeBootOrder (
98   VOID
99   )
100 {
101 
102   EFI_STATUS    Status;
103   BM_MENU_ENTRY *NewMenuEntry;
104   UINT16        *BootOrderList;
105   UINT16        *BootOrderListPtr;
106   UINTN         BootOrderListSize;
107   UINTN         Index;
108 
109   BootOrderList     = NULL;
110   BootOrderListSize = 0;
111   //
112   // First check whether BootOrder is present in current configuration
113   //
114   GetEfiGlobalVariable2 (L"BootOrder", (VOID **) &BootOrderList, &BootOrderListSize);
115 
116   //
117   // If exists, delete it to hold new BootOrder
118   //
119   if (BootOrderList != NULL) {
120     EfiLibDeleteVariable (L"BootOrder", &gEfiGlobalVariableGuid);
121     FreePool (BootOrderList);
122     BootOrderList = NULL;
123   }
124   //
125   // Maybe here should be some check method to ensure that
126   // no new added boot options will be added
127   // but the setup engine now will give only one callback
128   // that is to say, user are granted only one chance to
129   // decide whether the boot option will be added or not
130   // there should be no indictor to show whether this
131   // is a "new" boot option
132   //
133   BootOrderListSize = BootOptionMenu.MenuNumber;
134 
135   if (BootOrderListSize > 0) {
136     BootOrderList = AllocateZeroPool (BootOrderListSize * sizeof (UINT16));
137     ASSERT (BootOrderList != NULL);
138     BootOrderListPtr = BootOrderList;
139 
140     //
141     // Get all current used Boot#### from BootOptionMenu.
142     // OptionNumber in each BM_LOAD_OPTION is really its
143     // #### value.
144     //
145     for (Index = 0; Index < BootOrderListSize; Index++) {
146       NewMenuEntry    = BOpt_GetMenuEntry (&BootOptionMenu, Index);
147       *BootOrderList  = (UINT16) NewMenuEntry->OptionNumber;
148       BootOrderList++;
149     }
150 
151     BootOrderList = BootOrderListPtr;
152 
153     //
154     // After building the BootOrderList, write it back
155     //
156     Status = gRT->SetVariable (
157                     L"BootOrder",
158                     &gEfiGlobalVariableGuid,
159                     VAR_FLAG,
160                     BootOrderListSize * sizeof (UINT16),
161                     BootOrderList
162                     );
163     if (EFI_ERROR (Status)) {
164       return Status;
165     }
166   }
167   return EFI_SUCCESS;
168 }
169 
170 /**
171   Delete Load Option that represent a Deleted state in BootOptionMenu.
172   After deleting this Driver option, call Var_ChangeDriverOrder to
173   make sure DriverOrder is in valid state.
174 
175   @retval EFI_SUCCESS       Load Option is successfully updated.
176   @retval EFI_NOT_FOUND     Fail to find the driver option want to be deleted.
177   @return Other value than EFI_SUCCESS if failed to update "Driver Order" EFI
178           Variable.
179 
180 **/
181 EFI_STATUS
Var_DelDriverOption(VOID)182 Var_DelDriverOption (
183   VOID
184   )
185 {
186   BM_MENU_ENTRY   *NewMenuEntry;
187   BM_LOAD_CONTEXT *NewLoadContext;
188   UINT16          DriverString[12];
189   EFI_STATUS      Status;
190   UINTN           Index;
191   UINTN           Index2;
192 
193   Status  = EFI_SUCCESS;
194   Index2  = 0;
195   for (Index = 0; Index < DriverOptionMenu.MenuNumber; Index++) {
196     NewMenuEntry = BOpt_GetMenuEntry (&DriverOptionMenu, (Index - Index2));
197     if (NULL == NewMenuEntry) {
198       return EFI_NOT_FOUND;
199     }
200 
201     NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
202     if (!NewLoadContext->Deleted) {
203       continue;
204     }
205 
206     UnicodeSPrint (
207       DriverString,
208       sizeof (DriverString),
209       L"Driver%04x",
210       NewMenuEntry->OptionNumber
211       );
212 
213     EfiLibDeleteVariable (DriverString, &gEfiGlobalVariableGuid);
214     Index2++;
215 
216     RemoveEntryList (&NewMenuEntry->Link);
217     BOpt_DestroyMenuEntry (NewMenuEntry);
218     NewMenuEntry = NULL;
219   }
220 
221   DriverOptionMenu.MenuNumber -= Index2;
222 
223   Status = Var_ChangeDriverOrder ();
224   return Status;
225 }
226 
227 /**
228   After any operation on Driver####, there will be a discrepancy in
229   DriverOrder. Since some are missing but in DriverOrder, while some
230   are present but are not reflected by DriverOrder. Then a function
231   rebuild DriverOrder from scratch by content from DriverOptionMenu is
232   needed.
233 
234   @retval  EFI_SUCCESS  The driver order is updated successfully.
235   @return  Other status than EFI_SUCCESS if failed to set the "DriverOrder" EFI Variable.
236 
237 **/
238 EFI_STATUS
Var_ChangeDriverOrder(VOID)239 Var_ChangeDriverOrder (
240   VOID
241   )
242 {
243   EFI_STATUS    Status;
244   BM_MENU_ENTRY *NewMenuEntry;
245   UINT16        *DriverOrderList;
246   UINT16        *DriverOrderListPtr;
247   UINTN         DriverOrderListSize;
248   UINTN         Index;
249 
250   DriverOrderList     = NULL;
251   DriverOrderListSize = 0;
252 
253   //
254   // First check whether DriverOrder is present in current configuration
255   //
256   GetEfiGlobalVariable2 (L"DriverOrder", (VOID **) &DriverOrderList, &DriverOrderListSize);
257   //
258   // If exists, delete it to hold new DriverOrder
259   //
260   if (DriverOrderList != NULL) {
261     EfiLibDeleteVariable (L"DriverOrder", &gEfiGlobalVariableGuid);
262     FreePool (DriverOrderList);
263     DriverOrderList = NULL;
264   }
265 
266   DriverOrderListSize = DriverOptionMenu.MenuNumber;
267 
268   if (DriverOrderListSize > 0) {
269     DriverOrderList = AllocateZeroPool (DriverOrderListSize * sizeof (UINT16));
270     ASSERT (DriverOrderList != NULL);
271     DriverOrderListPtr = DriverOrderList;
272 
273     //
274     // Get all current used Driver#### from DriverOptionMenu.
275     // OptionNumber in each BM_LOAD_OPTION is really its
276     // #### value.
277     //
278     for (Index = 0; Index < DriverOrderListSize; Index++) {
279       NewMenuEntry      = BOpt_GetMenuEntry (&DriverOptionMenu, Index);
280       *DriverOrderList  = (UINT16) NewMenuEntry->OptionNumber;
281       DriverOrderList++;
282     }
283 
284     DriverOrderList = DriverOrderListPtr;
285 
286     //
287     // After building the DriverOrderList, write it back
288     //
289     Status = gRT->SetVariable (
290                     L"DriverOrder",
291                     &gEfiGlobalVariableGuid,
292                     VAR_FLAG,
293                     DriverOrderListSize * sizeof (UINT16),
294                     DriverOrderList
295                     );
296     if (EFI_ERROR (Status)) {
297       return Status;
298     }
299   }
300   return EFI_SUCCESS;
301 }
302 
303 /**
304   This function delete and build multi-instance device path for
305   specified type of console device.
306 
307   This function clear the EFI variable defined by ConsoleName and
308   gEfiGlobalVariableGuid. It then build the multi-instance device
309   path by appending the device path of the Console (In/Out/Err) instance
310   in ConsoleMenu. Then it scan all corresponding console device by
311   scanning Terminal (built from device supporting Serial I/O instances)
312   devices in TerminalMenu. At last, it save a EFI variable specifed
313   by ConsoleName and gEfiGlobalVariableGuid.
314 
315   @param ConsoleName     The name for the console device type. They are
316                          usually "ConIn", "ConOut" and "ErrOut".
317   @param ConsoleMenu     The console memu which is a list of console devices.
318   @param UpdatePageId    The flag specifying which type of console device
319                          to be processed.
320 
321   @retval EFI_SUCCESS    The function complete successfully.
322   @return The EFI variable can not be saved. See gRT->SetVariable for detail return information.
323 
324 **/
325 EFI_STATUS
Var_UpdateConsoleOption(IN UINT16 * ConsoleName,IN BM_MENU_OPTION * ConsoleMenu,IN UINT16 UpdatePageId)326 Var_UpdateConsoleOption (
327   IN UINT16                     *ConsoleName,
328   IN BM_MENU_OPTION             *ConsoleMenu,
329   IN UINT16                     UpdatePageId
330   )
331 {
332   EFI_DEVICE_PATH_PROTOCOL  *ConDevicePath;
333   BM_MENU_ENTRY             *NewMenuEntry;
334   BM_CONSOLE_CONTEXT        *NewConsoleContext;
335   BM_TERMINAL_CONTEXT       *NewTerminalContext;
336   EFI_STATUS                Status;
337   VENDOR_DEVICE_PATH        Vendor;
338   EFI_DEVICE_PATH_PROTOCOL  *TerminalDevicePath;
339   UINTN                     Index;
340 
341   GetEfiGlobalVariable2 (ConsoleName, (VOID**)&ConDevicePath, NULL);
342   if (ConDevicePath != NULL) {
343     EfiLibDeleteVariable (ConsoleName, &gEfiGlobalVariableGuid);
344     FreePool (ConDevicePath);
345     ConDevicePath = NULL;
346   };
347 
348   //
349   // First add all console input device from console input menu
350   //
351   for (Index = 0; Index < ConsoleMenu->MenuNumber; Index++) {
352     NewMenuEntry = BOpt_GetMenuEntry (ConsoleMenu, Index);
353 
354     NewConsoleContext = (BM_CONSOLE_CONTEXT *) NewMenuEntry->VariableContext;
355     if (NewConsoleContext->IsActive) {
356       ConDevicePath = AppendDevicePathInstance (
357                         ConDevicePath,
358                         NewConsoleContext->DevicePath
359                         );
360     }
361   }
362 
363   for (Index = 0; Index < TerminalMenu.MenuNumber; Index++) {
364     NewMenuEntry = BOpt_GetMenuEntry (&TerminalMenu, Index);
365 
366     NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext;
367     if (((NewTerminalContext->IsConIn != 0) && (UpdatePageId == FORM_CON_IN_ID)) ||
368         ((NewTerminalContext->IsConOut != 0)  && (UpdatePageId == FORM_CON_OUT_ID)) ||
369         ((NewTerminalContext->IsStdErr  != 0) && (UpdatePageId == FORM_CON_ERR_ID))
370         ) {
371       Vendor.Header.Type    = MESSAGING_DEVICE_PATH;
372       Vendor.Header.SubType = MSG_VENDOR_DP;
373 
374       ASSERT (NewTerminalContext->TerminalType < (ARRAY_SIZE (TerminalTypeGuid)));
375       CopyMem (
376         &Vendor.Guid,
377         &TerminalTypeGuid[NewTerminalContext->TerminalType],
378         sizeof (EFI_GUID)
379         );
380       SetDevicePathNodeLength (&Vendor.Header, sizeof (VENDOR_DEVICE_PATH));
381       TerminalDevicePath = AppendDevicePathNode (
382                             NewTerminalContext->DevicePath,
383                             (EFI_DEVICE_PATH_PROTOCOL *) &Vendor
384                             );
385       ASSERT (TerminalDevicePath != NULL);
386       ChangeTerminalDevicePath (TerminalDevicePath, TRUE);
387       ConDevicePath = AppendDevicePathInstance (
388                         ConDevicePath,
389                         TerminalDevicePath
390                         );
391     }
392   }
393 
394   if (ConDevicePath != NULL) {
395     Status = gRT->SetVariable (
396                     ConsoleName,
397                     &gEfiGlobalVariableGuid,
398                     VAR_FLAG,
399                     GetDevicePathSize (ConDevicePath),
400                     ConDevicePath
401                     );
402     if (EFI_ERROR (Status)) {
403       return Status;
404     }
405   }
406 
407   return EFI_SUCCESS;
408 
409 }
410 
411 /**
412   This function delete and build multi-instance device path ConIn
413   console device.
414 
415   @retval EFI_SUCCESS    The function complete successfully.
416   @return The EFI variable can not be saved. See gRT->SetVariable for detail return information.
417 **/
418 EFI_STATUS
Var_UpdateConsoleInpOption(VOID)419 Var_UpdateConsoleInpOption (
420   VOID
421   )
422 {
423   return Var_UpdateConsoleOption (L"ConIn", &ConsoleInpMenu, FORM_CON_IN_ID);
424 }
425 
426 /**
427   This function delete and build multi-instance device path ConOut
428   console device.
429 
430   @retval EFI_SUCCESS    The function complete successfully.
431   @return The EFI variable can not be saved. See gRT->SetVariable for detail return information.
432 **/
433 EFI_STATUS
Var_UpdateConsoleOutOption(VOID)434 Var_UpdateConsoleOutOption (
435   VOID
436   )
437 {
438   return Var_UpdateConsoleOption (L"ConOut", &ConsoleOutMenu, FORM_CON_OUT_ID);
439 }
440 
441 /**
442   This function delete and build multi-instance device path ErrOut
443   console device.
444 
445   @retval EFI_SUCCESS    The function complete successfully.
446   @return The EFI variable can not be saved. See gRT->SetVariable for detail return information.
447 **/
448 EFI_STATUS
Var_UpdateErrorOutOption(VOID)449 Var_UpdateErrorOutOption (
450   VOID
451   )
452 {
453   return Var_UpdateConsoleOption (L"ErrOut", &ConsoleErrMenu, FORM_CON_ERR_ID);
454 }
455 
456 /**
457   This function create a currently loaded Drive Option from
458   the BMM. It then appends this Driver Option to the end of
459   the "DriverOrder" list. It append this Driver Opotion to the end
460   of DriverOptionMenu.
461 
462   @param CallbackData    The BMM context data.
463   @param HiiHandle       The HII handle associated with the BMM formset.
464   @param DescriptionData The description of this driver option.
465   @param OptionalData    The optional load option.
466   @param ForceReconnect  If to force reconnect.
467 
468   @retval other                Contain some errors when excuting this function.See function
469                                EfiBootManagerInitializeLoadOption/EfiBootManagerAddLoadOptionVariabl
470                                for detail return information.
471   @retval EFI_SUCCESS          If function completes successfully.
472 
473 **/
474 EFI_STATUS
Var_UpdateDriverOption(IN BMM_CALLBACK_DATA * CallbackData,IN EFI_HII_HANDLE HiiHandle,IN UINT16 * DescriptionData,IN UINT16 * OptionalData,IN UINT8 ForceReconnect)475 Var_UpdateDriverOption (
476   IN  BMM_CALLBACK_DATA         *CallbackData,
477   IN  EFI_HII_HANDLE            HiiHandle,
478   IN  UINT16                    *DescriptionData,
479   IN  UINT16                    *OptionalData,
480   IN  UINT8                     ForceReconnect
481   )
482 {
483   UINT16          Index;
484   UINT16          DriverString[12];
485   BM_MENU_ENTRY   *NewMenuEntry;
486   BM_LOAD_CONTEXT *NewLoadContext;
487   BOOLEAN         OptionalDataExist;
488   EFI_STATUS      Status;
489   EFI_BOOT_MANAGER_LOAD_OPTION  LoadOption;
490   UINT8                         *OptionalDesData;
491   UINT32                        OptionalDataSize;
492 
493   OptionalDataExist = FALSE;
494   OptionalDesData = NULL;
495   OptionalDataSize = 0;
496 
497   Index             = BOpt_GetDriverOptionNumber ();
498   UnicodeSPrint (
499     DriverString,
500     sizeof (DriverString),
501     L"Driver%04x",
502     Index
503     );
504 
505   if (*DescriptionData == 0x0000) {
506     StrCpyS (DescriptionData, MAX_MENU_NUMBER, DriverString);
507   }
508 
509   if (*OptionalData != 0x0000) {
510     OptionalDataExist = TRUE;
511     OptionalDesData = (UINT8 *)OptionalData;
512     OptionalDataSize = (UINT32)StrSize (OptionalData);
513   }
514 
515   NewMenuEntry = BOpt_CreateMenuEntry (BM_LOAD_CONTEXT_SELECT);
516   if (NULL == NewMenuEntry) {
517     return EFI_OUT_OF_RESOURCES;
518   }
519 
520   Status = EfiBootManagerInitializeLoadOption (
521              &LoadOption,
522              Index,
523              LoadOptionTypeDriver,
524              LOAD_OPTION_ACTIVE | (ForceReconnect << 1),
525              DescriptionData,
526              CallbackData->LoadContext->FilePathList,
527              OptionalDesData,
528              OptionalDataSize
529            );
530   if (EFI_ERROR (Status)){
531     return Status;
532   }
533 
534   Status = EfiBootManagerAddLoadOptionVariable (&LoadOption,(UINTN) -1 );
535   if (EFI_ERROR (Status)) {
536     EfiBootManagerFreeLoadOption(&LoadOption);
537     return Status;
538   }
539 
540   NewLoadContext                  = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
541   NewLoadContext->Deleted         = FALSE;
542   NewLoadContext->Attributes = LoadOption.Attributes;
543   NewLoadContext->FilePathListLength = (UINT16)GetDevicePathSize (LoadOption.FilePath);
544 
545   NewLoadContext->Description = AllocateZeroPool (StrSize (DescriptionData));
546   ASSERT (NewLoadContext->Description != NULL);
547   NewMenuEntry->DisplayString = NewLoadContext->Description;
548   CopyMem (
549     NewLoadContext->Description,
550     LoadOption.Description,
551     StrSize (DescriptionData)
552     );
553 
554   NewLoadContext->FilePathList = AllocateZeroPool (GetDevicePathSize (CallbackData->LoadContext->FilePathList));
555   ASSERT (NewLoadContext->FilePathList != NULL);
556   CopyMem (
557     NewLoadContext->FilePathList,
558     LoadOption.FilePath,
559     GetDevicePathSize (CallbackData->LoadContext->FilePathList)
560     );
561 
562   NewMenuEntry->HelpString    = UiDevicePathToStr (NewLoadContext->FilePathList);
563   NewMenuEntry->OptionNumber  = Index;
564   NewMenuEntry->DisplayStringToken = HiiSetString (HiiHandle, 0, NewMenuEntry->DisplayString, NULL);
565   NewMenuEntry->HelpStringToken = HiiSetString (HiiHandle, 0, NewMenuEntry->HelpString, NULL);
566 
567   if (OptionalDataExist) {
568     NewLoadContext->OptionalData = AllocateZeroPool (LoadOption.OptionalDataSize);
569     ASSERT (NewLoadContext->OptionalData != NULL);
570     CopyMem (
571       NewLoadContext->OptionalData,
572       LoadOption.OptionalData,
573       LoadOption.OptionalDataSize
574       );
575   }
576 
577   InsertTailList (&DriverOptionMenu.Head, &NewMenuEntry->Link);
578   DriverOptionMenu.MenuNumber++;
579 
580   EfiBootManagerFreeLoadOption(&LoadOption);
581 
582   return EFI_SUCCESS;
583 }
584 
585 /**
586   This function create a currently loaded Boot Option from
587   the BMM. It then appends this Boot Option to the end of
588   the "BootOrder" list. It also append this Boot Opotion to the end
589   of BootOptionMenu.
590 
591   @param CallbackData    The BMM context data.
592 
593   @retval other                Contain some errors when excuting this function. See function
594                                EfiBootManagerInitializeLoadOption/EfiBootManagerAddLoadOptionVariabl
595                                for detail return information.
596   @retval EFI_SUCCESS          If function completes successfully.
597 
598 **/
599 EFI_STATUS
Var_UpdateBootOption(IN BMM_CALLBACK_DATA * CallbackData)600 Var_UpdateBootOption (
601   IN  BMM_CALLBACK_DATA              *CallbackData
602   )
603 {
604   UINT16          BootString[10];
605   UINT16          Index;
606   BM_MENU_ENTRY   *NewMenuEntry;
607   BM_LOAD_CONTEXT *NewLoadContext;
608   BOOLEAN         OptionalDataExist;
609   EFI_STATUS      Status;
610   BMM_FAKE_NV_DATA  *NvRamMap;
611   EFI_BOOT_MANAGER_LOAD_OPTION  LoadOption;
612   UINT8                         *OptionalData;
613   UINT32                        OptionalDataSize;
614 
615   OptionalDataExist = FALSE;
616   NvRamMap = &CallbackData->BmmFakeNvData;
617   OptionalData = NULL;
618   OptionalDataSize = 0;
619 
620   Index = BOpt_GetBootOptionNumber () ;
621   UnicodeSPrint (BootString, sizeof (BootString), L"Boot%04x", Index);
622 
623   if (NvRamMap->BootDescriptionData[0] == 0x0000) {
624     StrCpyS (NvRamMap->BootDescriptionData, sizeof (NvRamMap->BootDescriptionData) / sizeof (NvRamMap->BootDescriptionData[0]), BootString);
625   }
626 
627   if (NvRamMap->BootOptionalData[0] != 0x0000) {
628     OptionalDataExist = TRUE;
629     OptionalData = (UINT8 *)NvRamMap->BootOptionalData;
630     OptionalDataSize = (UINT32)StrSize (NvRamMap->BootOptionalData);
631   }
632 
633   NewMenuEntry = BOpt_CreateMenuEntry (BM_LOAD_CONTEXT_SELECT);
634   if (NULL == NewMenuEntry) {
635     return EFI_OUT_OF_RESOURCES;
636   }
637 
638   Status = EfiBootManagerInitializeLoadOption (
639              &LoadOption,
640              Index,
641              LoadOptionTypeBoot,
642              LOAD_OPTION_ACTIVE,
643              NvRamMap->BootDescriptionData,
644              CallbackData->LoadContext->FilePathList,
645              OptionalData,
646              OptionalDataSize
647            );
648   if (EFI_ERROR (Status)){
649     return Status;
650   }
651 
652   Status = EfiBootManagerAddLoadOptionVariable (&LoadOption,(UINTN) -1 );
653   if (EFI_ERROR (Status)) {
654     EfiBootManagerFreeLoadOption(&LoadOption);
655     return Status;
656   }
657 
658   NewLoadContext                  = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
659   NewLoadContext->Deleted         = FALSE;
660   NewLoadContext->Attributes = LoadOption.Attributes;
661   NewLoadContext->FilePathListLength = (UINT16) GetDevicePathSize (LoadOption.FilePath);
662 
663   NewLoadContext->Description = AllocateZeroPool (StrSize (NvRamMap->BootDescriptionData));
664   ASSERT (NewLoadContext->Description != NULL);
665 
666   NewMenuEntry->DisplayString = NewLoadContext->Description;
667 
668   CopyMem (
669     NewLoadContext->Description,
670     LoadOption.Description,
671     StrSize (NvRamMap->BootDescriptionData)
672     );
673 
674   NewLoadContext->FilePathList = AllocateZeroPool (GetDevicePathSize (CallbackData->LoadContext->FilePathList));
675   ASSERT (NewLoadContext->FilePathList != NULL);
676   CopyMem (
677     NewLoadContext->FilePathList,
678     LoadOption.FilePath,
679     GetDevicePathSize (CallbackData->LoadContext->FilePathList)
680     );
681 
682   NewMenuEntry->HelpString    = UiDevicePathToStr (NewLoadContext->FilePathList);
683   NewMenuEntry->OptionNumber  = Index;
684   NewMenuEntry->DisplayStringToken = HiiSetString (CallbackData->BmmHiiHandle, 0, NewMenuEntry->DisplayString, NULL);
685   NewMenuEntry->HelpStringToken = HiiSetString (CallbackData->BmmHiiHandle, 0, NewMenuEntry->HelpString, NULL);
686 
687   if (OptionalDataExist) {
688     NewLoadContext->OptionalData = AllocateZeroPool (LoadOption.OptionalDataSize);
689     ASSERT (NewLoadContext->OptionalData != NULL);
690     CopyMem (
691       NewLoadContext->OptionalData,
692       LoadOption.OptionalData,
693       LoadOption.OptionalDataSize
694       );
695   }
696 
697   InsertTailList (&BootOptionMenu.Head, &NewMenuEntry->Link);
698   BootOptionMenu.MenuNumber++;
699 
700   EfiBootManagerFreeLoadOption(&LoadOption);
701 
702   return EFI_SUCCESS;
703 }
704 
705 /**
706   This function update the "BootNext" EFI Variable. If there is
707   no "BootNext" specified in BMM, this EFI Variable is deleted.
708   It also update the BMM context data specified the "BootNext"
709   vaule.
710 
711   @param CallbackData    The BMM context data.
712 
713   @retval EFI_SUCCESS    The function complete successfully.
714   @return                The EFI variable can be saved. See gRT->SetVariable
715                          for detail return information.
716 
717 **/
718 EFI_STATUS
Var_UpdateBootNext(IN BMM_CALLBACK_DATA * CallbackData)719 Var_UpdateBootNext (
720   IN BMM_CALLBACK_DATA            *CallbackData
721   )
722 {
723   BM_MENU_ENTRY     *NewMenuEntry;
724   BM_LOAD_CONTEXT   *NewLoadContext;
725   BMM_FAKE_NV_DATA  *CurrentFakeNVMap;
726   UINT16            Index;
727   EFI_STATUS        Status;
728 
729   Status            = EFI_SUCCESS;
730   CurrentFakeNVMap  = &CallbackData->BmmFakeNvData;
731   for (Index = 0; Index < BootOptionMenu.MenuNumber; Index++) {
732     NewMenuEntry = BOpt_GetMenuEntry (&BootOptionMenu, Index);
733     ASSERT (NULL != NewMenuEntry);
734 
735     NewLoadContext              = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
736     NewLoadContext->IsBootNext  = FALSE;
737   }
738 
739   if (CurrentFakeNVMap->BootNext == NONE_BOOTNEXT_VALUE) {
740     EfiLibDeleteVariable (L"BootNext", &gEfiGlobalVariableGuid);
741     return EFI_SUCCESS;
742   }
743 
744   NewMenuEntry = BOpt_GetMenuEntry (
745                   &BootOptionMenu,
746                   CurrentFakeNVMap->BootNext
747                   );
748   ASSERT (NewMenuEntry != NULL);
749 
750   NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
751   Status = gRT->SetVariable (
752                   L"BootNext",
753                   &gEfiGlobalVariableGuid,
754                   VAR_FLAG,
755                   sizeof (UINT16),
756                   &NewMenuEntry->OptionNumber
757                   );
758   NewLoadContext->IsBootNext              = TRUE;
759   CallbackData->BmmOldFakeNVData.BootNext = CurrentFakeNVMap->BootNext;
760   return Status;
761 }
762 
763 /**
764   This function update the "BootOrder" EFI Variable based on
765   BMM Formset's NV map. It then refresh BootOptionMenu
766   with the new "BootOrder" list.
767 
768   @param CallbackData    The BMM context data.
769 
770   @retval EFI_SUCCESS             The function complete successfully.
771   @retval EFI_OUT_OF_RESOURCES    Not enough memory to complete the function.
772   @return The EFI variable can not be saved. See gRT->SetVariable for detail return information.
773 
774 **/
775 EFI_STATUS
Var_UpdateBootOrder(IN BMM_CALLBACK_DATA * CallbackData)776 Var_UpdateBootOrder (
777   IN BMM_CALLBACK_DATA            *CallbackData
778   )
779 {
780   EFI_STATUS  Status;
781   UINT16      Index;
782   UINT16      OrderIndex;
783   UINT16      *BootOrder;
784   UINTN       BootOrderSize;
785   UINT16      OptionNumber;
786 
787   //
788   // First check whether BootOrder is present in current configuration
789   //
790   GetEfiGlobalVariable2 (L"BootOrder", (VOID **) &BootOrder, &BootOrderSize);
791   if (BootOrder == NULL) {
792     return EFI_OUT_OF_RESOURCES;
793   }
794 
795   ASSERT (BootOptionMenu.MenuNumber <= (sizeof (CallbackData->BmmFakeNvData.BootOptionOrder) / sizeof (CallbackData->BmmFakeNvData.BootOptionOrder[0])));
796 
797   //
798   // OptionOrder is subset of BootOrder
799   //
800   for (OrderIndex = 0; (OrderIndex < BootOptionMenu.MenuNumber) && (CallbackData->BmmFakeNvData.BootOptionOrder[OrderIndex] != 0); OrderIndex++) {
801     for (Index = OrderIndex; Index < BootOrderSize / sizeof (UINT16); Index++) {
802       if ((BootOrder[Index] == (UINT16) (CallbackData->BmmFakeNvData.BootOptionOrder[OrderIndex] - 1)) && (OrderIndex != Index)) {
803         OptionNumber = BootOrder[Index];
804         CopyMem (&BootOrder[OrderIndex + 1], &BootOrder[OrderIndex], (Index - OrderIndex) * sizeof (UINT16));
805         BootOrder[OrderIndex] = OptionNumber;
806       }
807     }
808   }
809 
810   Status = gRT->SetVariable (
811                   L"BootOrder",
812                   &gEfiGlobalVariableGuid,
813                   VAR_FLAG,
814                   BootOrderSize,
815                   BootOrder
816                   );
817   FreePool (BootOrder);
818 
819   BOpt_FreeMenu (&BootOptionMenu);
820   BOpt_GetBootOptions (CallbackData);
821 
822   return Status;
823 
824 }
825 
826 /**
827   This function update the "DriverOrder" EFI Variable based on
828   BMM Formset's NV map. It then refresh DriverOptionMenu
829   with the new "DriverOrder" list.
830 
831   @param CallbackData    The BMM context data.
832 
833   @retval EFI_SUCCESS           The function complete successfully.
834   @retval EFI_OUT_OF_RESOURCES  Not enough memory to complete the function.
835   @return The EFI variable can not be saved. See gRT->SetVariable for detail return information.
836 
837 **/
838 EFI_STATUS
Var_UpdateDriverOrder(IN BMM_CALLBACK_DATA * CallbackData)839 Var_UpdateDriverOrder (
840   IN BMM_CALLBACK_DATA            *CallbackData
841   )
842 {
843   EFI_STATUS  Status;
844   UINT16      Index;
845   UINT16      *DriverOrderList;
846   UINT16      *NewDriverOrderList;
847   UINTN       DriverOrderListSize;
848 
849   DriverOrderList     = NULL;
850   DriverOrderListSize = 0;
851 
852   //
853   // First check whether DriverOrder is present in current configuration
854   //
855   GetEfiGlobalVariable2 (L"DriverOrder", (VOID **) &DriverOrderList, &DriverOrderListSize);
856   NewDriverOrderList = AllocateZeroPool (DriverOrderListSize);
857 
858   if (NewDriverOrderList == NULL) {
859     return EFI_OUT_OF_RESOURCES;
860   }
861   //
862   // If exists, delete it to hold new DriverOrder
863   //
864   if (DriverOrderList != NULL) {
865     EfiLibDeleteVariable (L"DriverOrder", &gEfiGlobalVariableGuid);
866     FreePool (DriverOrderList);
867   }
868 
869   ASSERT (DriverOptionMenu.MenuNumber <= (sizeof (CallbackData->BmmFakeNvData.DriverOptionOrder) / sizeof (CallbackData->BmmFakeNvData.DriverOptionOrder[0])));
870   for (Index = 0; Index < DriverOptionMenu.MenuNumber; Index++) {
871     NewDriverOrderList[Index] = (UINT16) (CallbackData->BmmFakeNvData.DriverOptionOrder[Index] - 1);
872   }
873 
874   Status = gRT->SetVariable (
875                   L"DriverOrder",
876                   &gEfiGlobalVariableGuid,
877                   VAR_FLAG,
878                   DriverOrderListSize,
879                   NewDriverOrderList
880                   );
881   if (EFI_ERROR (Status)) {
882     return Status;
883   }
884 
885   BOpt_FreeMenu (&DriverOptionMenu);
886   BOpt_GetDriverOptions (CallbackData);
887   return EFI_SUCCESS;
888 }
889 
890 /**
891   Update the Text Mode of Console.
892 
893   @param CallbackData  The context data for BMM.
894 
895   @retval EFI_SUCCSS If the Text Mode of Console is updated.
896   @return Other value if the Text Mode of Console is not updated.
897 
898 **/
899 EFI_STATUS
Var_UpdateConMode(IN BMM_CALLBACK_DATA * CallbackData)900 Var_UpdateConMode (
901   IN BMM_CALLBACK_DATA            *CallbackData
902   )
903 {
904   EFI_STATUS        Status;
905   UINTN             Mode;
906   CONSOLE_OUT_MODE  ModeInfo;
907 
908   Mode = CallbackData->BmmFakeNvData.ConsoleOutMode;
909 
910   Status = gST->ConOut->QueryMode (gST->ConOut, Mode, &(ModeInfo.Column), &(ModeInfo.Row));
911   if (!EFI_ERROR(Status)) {
912     Status = PcdSet32S (PcdSetupConOutColumn, (UINT32) ModeInfo.Column);
913     if (!EFI_ERROR (Status)) {
914       Status = PcdSet32S (PcdSetupConOutRow, (UINT32) ModeInfo.Row);
915     }
916   }
917 
918   return Status;
919 }
920