1 /** @file
2 Variable operation that will be used by bootmaint
3 
4 Copyright (c) 2004 - 2015, 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   Update the device path of "ConOut", "ConIn" and "ErrOut"
305   based on the new BaudRate, Data Bits, parity and Stop Bits
306   set.
307 
308 **/
309 VOID
Var_UpdateAllConsoleOption(VOID)310 Var_UpdateAllConsoleOption (
311   VOID
312   )
313 {
314   EFI_DEVICE_PATH_PROTOCOL  *OutDevicePath;
315   EFI_DEVICE_PATH_PROTOCOL  *InpDevicePath;
316   EFI_DEVICE_PATH_PROTOCOL  *ErrDevicePath;
317   EFI_STATUS                Status;
318 
319   GetEfiGlobalVariable2 (L"ConOut", (VOID**)&OutDevicePath, NULL);
320   GetEfiGlobalVariable2 (L"ConIn", (VOID**)&InpDevicePath, NULL);
321   GetEfiGlobalVariable2 (L"ErrOut", (VOID**)&ErrDevicePath, NULL);
322   if (OutDevicePath != NULL) {
323     ChangeVariableDevicePath (OutDevicePath);
324     Status = gRT->SetVariable (
325                     L"ConOut",
326                     &gEfiGlobalVariableGuid,
327                     VAR_FLAG,
328                     GetDevicePathSize (OutDevicePath),
329                     OutDevicePath
330                     );
331     ASSERT (!EFI_ERROR (Status));
332   }
333 
334   if (InpDevicePath != NULL) {
335     ChangeVariableDevicePath (InpDevicePath);
336     Status = gRT->SetVariable (
337                     L"ConIn",
338                     &gEfiGlobalVariableGuid,
339                     VAR_FLAG,
340                     GetDevicePathSize (InpDevicePath),
341                     InpDevicePath
342                     );
343     ASSERT (!EFI_ERROR (Status));
344   }
345 
346   if (ErrDevicePath != NULL) {
347     ChangeVariableDevicePath (ErrDevicePath);
348     Status = gRT->SetVariable (
349                     L"ErrOut",
350                     &gEfiGlobalVariableGuid,
351                     VAR_FLAG,
352                     GetDevicePathSize (ErrDevicePath),
353                     ErrDevicePath
354                     );
355     ASSERT (!EFI_ERROR (Status));
356   }
357 }
358 
359 /**
360   This function delete and build multi-instance device path for
361   specified type of console device.
362 
363   This function clear the EFI variable defined by ConsoleName and
364   gEfiGlobalVariableGuid. It then build the multi-instance device
365   path by appending the device path of the Console (In/Out/Err) instance
366   in ConsoleMenu. Then it scan all corresponding console device by
367   scanning Terminal (built from device supporting Serial I/O instances)
368   devices in TerminalMenu. At last, it save a EFI variable specifed
369   by ConsoleName and gEfiGlobalVariableGuid.
370 
371   @param ConsoleName     The name for the console device type. They are
372                          usually "ConIn", "ConOut" and "ErrOut".
373   @param ConsoleMenu     The console memu which is a list of console devices.
374   @param UpdatePageId    The flag specifying which type of console device
375                          to be processed.
376 
377   @retval EFI_SUCCESS    The function complete successfully.
378   @return The EFI variable can not be saved. See gRT->SetVariable for detail return information.
379 
380 **/
381 EFI_STATUS
Var_UpdateConsoleOption(IN UINT16 * ConsoleName,IN BM_MENU_OPTION * ConsoleMenu,IN UINT16 UpdatePageId)382 Var_UpdateConsoleOption (
383   IN UINT16                     *ConsoleName,
384   IN BM_MENU_OPTION             *ConsoleMenu,
385   IN UINT16                     UpdatePageId
386   )
387 {
388   EFI_DEVICE_PATH_PROTOCOL  *ConDevicePath;
389   BM_MENU_ENTRY             *NewMenuEntry;
390   BM_CONSOLE_CONTEXT        *NewConsoleContext;
391   BM_TERMINAL_CONTEXT       *NewTerminalContext;
392   EFI_STATUS                Status;
393   VENDOR_DEVICE_PATH        Vendor;
394   EFI_DEVICE_PATH_PROTOCOL  *TerminalDevicePath;
395   UINTN                     Index;
396 
397   GetEfiGlobalVariable2 (ConsoleName, (VOID**)&ConDevicePath, NULL);
398   if (ConDevicePath != NULL) {
399     EfiLibDeleteVariable (ConsoleName, &gEfiGlobalVariableGuid);
400     FreePool (ConDevicePath);
401     ConDevicePath = NULL;
402   };
403 
404   //
405   // First add all console input device from console input menu
406   //
407   for (Index = 0; Index < ConsoleMenu->MenuNumber; Index++) {
408     NewMenuEntry = BOpt_GetMenuEntry (ConsoleMenu, Index);
409 
410     NewConsoleContext = (BM_CONSOLE_CONTEXT *) NewMenuEntry->VariableContext;
411     if (NewConsoleContext->IsActive) {
412       ConDevicePath = AppendDevicePathInstance (
413                         ConDevicePath,
414                         NewConsoleContext->DevicePath
415                         );
416     }
417   }
418 
419   for (Index = 0; Index < TerminalMenu.MenuNumber; Index++) {
420     NewMenuEntry = BOpt_GetMenuEntry (&TerminalMenu, Index);
421 
422     NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext;
423     if (((NewTerminalContext->IsConIn != 0) && (UpdatePageId == FORM_CON_IN_ID)) ||
424         ((NewTerminalContext->IsConOut != 0)  && (UpdatePageId == FORM_CON_OUT_ID)) ||
425         ((NewTerminalContext->IsStdErr  != 0) && (UpdatePageId == FORM_CON_ERR_ID))
426         ) {
427       Vendor.Header.Type    = MESSAGING_DEVICE_PATH;
428       Vendor.Header.SubType = MSG_VENDOR_DP;
429 
430       ASSERT (NewTerminalContext->TerminalType < (sizeof (TerminalTypeGuid) / sizeof (TerminalTypeGuid[0])));
431       CopyMem (
432         &Vendor.Guid,
433         &TerminalTypeGuid[NewTerminalContext->TerminalType],
434         sizeof (EFI_GUID)
435         );
436       SetDevicePathNodeLength (&Vendor.Header, sizeof (VENDOR_DEVICE_PATH));
437       TerminalDevicePath = AppendDevicePathNode (
438                             NewTerminalContext->DevicePath,
439                             (EFI_DEVICE_PATH_PROTOCOL *) &Vendor
440                             );
441       ASSERT (TerminalDevicePath != NULL);
442       ChangeTerminalDevicePath (TerminalDevicePath, TRUE);
443       ConDevicePath = AppendDevicePathInstance (
444                         ConDevicePath,
445                         TerminalDevicePath
446                         );
447     }
448   }
449 
450   if (ConDevicePath != NULL) {
451     Status = gRT->SetVariable (
452                     ConsoleName,
453                     &gEfiGlobalVariableGuid,
454                     VAR_FLAG,
455                     GetDevicePathSize (ConDevicePath),
456                     ConDevicePath
457                     );
458     if (EFI_ERROR (Status)) {
459       return Status;
460     }
461   }
462 
463   return EFI_SUCCESS;
464 
465 }
466 
467 /**
468   This function delete and build multi-instance device path ConIn
469   console device.
470 
471   @retval EFI_SUCCESS    The function complete successfully.
472   @return The EFI variable can not be saved. See gRT->SetVariable for detail return information.
473 **/
474 EFI_STATUS
Var_UpdateConsoleInpOption(VOID)475 Var_UpdateConsoleInpOption (
476   VOID
477   )
478 {
479   return Var_UpdateConsoleOption (L"ConIn", &ConsoleInpMenu, FORM_CON_IN_ID);
480 }
481 
482 /**
483   This function delete and build multi-instance device path ConOut
484   console device.
485 
486   @retval EFI_SUCCESS    The function complete successfully.
487   @return The EFI variable can not be saved. See gRT->SetVariable for detail return information.
488 **/
489 EFI_STATUS
Var_UpdateConsoleOutOption(VOID)490 Var_UpdateConsoleOutOption (
491   VOID
492   )
493 {
494   return Var_UpdateConsoleOption (L"ConOut", &ConsoleOutMenu, FORM_CON_OUT_ID);
495 }
496 
497 /**
498   This function delete and build multi-instance device path ErrOut
499   console device.
500 
501   @retval EFI_SUCCESS    The function complete successfully.
502   @return The EFI variable can not be saved. See gRT->SetVariable for detail return information.
503 **/
504 EFI_STATUS
Var_UpdateErrorOutOption(VOID)505 Var_UpdateErrorOutOption (
506   VOID
507   )
508 {
509   return Var_UpdateConsoleOption (L"ErrOut", &ConsoleErrMenu, FORM_CON_ERR_ID);
510 }
511 
512 /**
513   This function create a currently loaded Drive Option from
514   the BMM. It then appends this Driver Option to the end of
515   the "DriverOrder" list. It append this Driver Opotion to the end
516   of DriverOptionMenu.
517 
518   @param CallbackData    The BMM context data.
519   @param HiiHandle       The HII handle associated with the BMM formset.
520   @param DescriptionData The description of this driver option.
521   @param OptionalData    The optional load option.
522   @param ForceReconnect  If to force reconnect.
523 
524   @retval EFI_OUT_OF_RESOURCES If not enought memory to complete the operation.
525   @retval EFI_SUCCESS          If function completes successfully.
526 
527 **/
528 EFI_STATUS
Var_UpdateDriverOption(IN BMM_CALLBACK_DATA * CallbackData,IN EFI_HII_HANDLE HiiHandle,IN UINT16 * DescriptionData,IN UINT16 * OptionalData,IN UINT8 ForceReconnect)529 Var_UpdateDriverOption (
530   IN  BMM_CALLBACK_DATA         *CallbackData,
531   IN  EFI_HII_HANDLE            HiiHandle,
532   IN  UINT16                    *DescriptionData,
533   IN  UINT16                    *OptionalData,
534   IN  UINT8                     ForceReconnect
535   )
536 {
537   UINT16          Index;
538   UINT16          *DriverOrderList;
539   UINT16          *NewDriverOrderList;
540   UINT16          DriverString[12];
541   UINTN           DriverOrderListSize;
542   VOID            *Buffer;
543   UINTN           BufferSize;
544   UINT8           *Ptr;
545   BM_MENU_ENTRY   *NewMenuEntry;
546   BM_LOAD_CONTEXT *NewLoadContext;
547   BOOLEAN         OptionalDataExist;
548   EFI_STATUS      Status;
549 
550   OptionalDataExist = FALSE;
551 
552   Index             = BOpt_GetDriverOptionNumber ();
553   UnicodeSPrint (
554     DriverString,
555     sizeof (DriverString),
556     L"Driver%04x",
557     Index
558     );
559 
560   if (*DescriptionData == 0x0000) {
561     StrCpyS (DescriptionData, MAX_MENU_NUMBER, DriverString);
562   }
563 
564   BufferSize = sizeof (UINT32) + sizeof (UINT16) + StrSize (DescriptionData);
565   BufferSize += GetDevicePathSize (CallbackData->LoadContext->FilePathList);
566 
567   if (*OptionalData != 0x0000) {
568     OptionalDataExist = TRUE;
569     BufferSize += StrSize (OptionalData);
570   }
571 
572   Buffer = AllocateZeroPool (BufferSize);
573   if (NULL == Buffer) {
574     return EFI_OUT_OF_RESOURCES;
575   }
576 
577   NewMenuEntry = BOpt_CreateMenuEntry (BM_LOAD_CONTEXT_SELECT);
578   if (NULL == NewMenuEntry) {
579     FreePool (Buffer);
580     return EFI_OUT_OF_RESOURCES;
581   }
582 
583   NewLoadContext                  = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
584   NewLoadContext->Deleted         = FALSE;
585   NewLoadContext->LoadOptionSize  = BufferSize;
586   Ptr = (UINT8 *) Buffer;
587   NewLoadContext->LoadOption = Ptr;
588   *((UINT32 *) Ptr) = LOAD_OPTION_ACTIVE | (ForceReconnect << 1);
589   NewLoadContext->Attributes = *((UINT32 *) Ptr);
590   NewLoadContext->IsActive = TRUE;
591   NewLoadContext->ForceReconnect = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_FORCE_RECONNECT);
592 
593   Ptr += sizeof (UINT32);
594   *((UINT16 *) Ptr) = (UINT16) GetDevicePathSize (CallbackData->LoadContext->FilePathList);
595   NewLoadContext->FilePathListLength = *((UINT16 *) Ptr);
596 
597   Ptr += sizeof (UINT16);
598   CopyMem (
599     Ptr,
600     DescriptionData,
601     StrSize (DescriptionData)
602     );
603 
604   NewLoadContext->Description = AllocateZeroPool (StrSize (DescriptionData));
605   ASSERT (NewLoadContext->Description != NULL);
606   NewMenuEntry->DisplayString = NewLoadContext->Description;
607   CopyMem (
608     NewLoadContext->Description,
609     (VOID *) Ptr,
610     StrSize (DescriptionData)
611     );
612 
613   Ptr += StrSize (DescriptionData);
614   CopyMem (
615     Ptr,
616     CallbackData->LoadContext->FilePathList,
617     GetDevicePathSize (CallbackData->LoadContext->FilePathList)
618     );
619 
620   NewLoadContext->FilePathList = AllocateZeroPool (GetDevicePathSize (CallbackData->LoadContext->FilePathList));
621   ASSERT (NewLoadContext->FilePathList != NULL);
622 
623   CopyMem (
624     NewLoadContext->FilePathList,
625     (VOID *) Ptr,
626     GetDevicePathSize (CallbackData->LoadContext->FilePathList)
627     );
628 
629   NewMenuEntry->HelpString    = UiDevicePathToStr (NewLoadContext->FilePathList);
630   NewMenuEntry->OptionNumber  = Index;
631   NewMenuEntry->DisplayStringToken = HiiSetString (HiiHandle, 0, NewMenuEntry->DisplayString, NULL);
632   NewMenuEntry->HelpStringToken = HiiSetString (HiiHandle, 0, NewMenuEntry->HelpString, NULL);
633 
634   if (OptionalDataExist) {
635     Ptr += (UINT8) GetDevicePathSize (CallbackData->LoadContext->FilePathList);
636 
637     CopyMem (
638       Ptr,
639       OptionalData,
640       StrSize (OptionalData)
641       );
642   }
643 
644   Status = gRT->SetVariable (
645                   DriverString,
646                   &gEfiGlobalVariableGuid,
647                   VAR_FLAG,
648                   BufferSize,
649                   Buffer
650                   );
651   ASSERT_EFI_ERROR (Status);
652   GetEfiGlobalVariable2 (L"DriverOrder", (VOID **) &DriverOrderList, &DriverOrderListSize);
653   NewDriverOrderList = AllocateZeroPool (DriverOrderListSize + sizeof (UINT16));
654   ASSERT (NewDriverOrderList != NULL);
655   if (DriverOrderList != NULL){
656     CopyMem (NewDriverOrderList, DriverOrderList, DriverOrderListSize);
657   }
658   NewDriverOrderList[DriverOrderListSize / sizeof (UINT16)] = Index;
659   if (DriverOrderList != NULL) {
660     EfiLibDeleteVariable (L"DriverOrder", &gEfiGlobalVariableGuid);
661   }
662 
663   Status = gRT->SetVariable (
664                   L"DriverOrder",
665                   &gEfiGlobalVariableGuid,
666                   VAR_FLAG,
667                   DriverOrderListSize + sizeof (UINT16),
668                   NewDriverOrderList
669                   );
670   ASSERT_EFI_ERROR (Status);
671   if (DriverOrderList != NULL) {
672     FreePool (DriverOrderList);
673   }
674   DriverOrderList = NULL;
675   FreePool (NewDriverOrderList);
676   InsertTailList (&DriverOptionMenu.Head, &NewMenuEntry->Link);
677   DriverOptionMenu.MenuNumber++;
678 
679   return EFI_SUCCESS;
680 }
681 
682 /**
683   This function create a currently loaded Boot Option from
684   the BMM. It then appends this Boot Option to the end of
685   the "BootOrder" list. It also append this Boot Opotion to the end
686   of BootOptionMenu.
687 
688   @param CallbackData    The BMM context data.
689 
690   @retval EFI_OUT_OF_RESOURCES If not enought memory to complete the operation.
691   @retval EFI_SUCCESS          If function completes successfully.
692 
693 **/
694 EFI_STATUS
Var_UpdateBootOption(IN BMM_CALLBACK_DATA * CallbackData)695 Var_UpdateBootOption (
696   IN  BMM_CALLBACK_DATA              *CallbackData
697   )
698 {
699   UINT16          *BootOrderList;
700   UINT16          *NewBootOrderList;
701   UINTN           BootOrderListSize;
702   UINT16          BootString[10];
703   VOID            *Buffer;
704   UINTN           BufferSize;
705   UINT8           *Ptr;
706   UINT16          Index;
707   BM_MENU_ENTRY   *NewMenuEntry;
708   BM_LOAD_CONTEXT *NewLoadContext;
709   BOOLEAN         OptionalDataExist;
710   EFI_STATUS      Status;
711   BMM_FAKE_NV_DATA  *NvRamMap;
712 
713   OptionalDataExist = FALSE;
714   NvRamMap = &CallbackData->BmmFakeNvData;
715 
716   Index = BOpt_GetBootOptionNumber () ;
717   UnicodeSPrint (BootString, sizeof (BootString), L"Boot%04x", Index);
718 
719   if (NvRamMap->BootDescriptionData[0] == 0x0000) {
720     StrCpyS (NvRamMap->BootDescriptionData, sizeof (NvRamMap->BootDescriptionData) / sizeof (NvRamMap->BootDescriptionData[0]), BootString);
721   }
722 
723   BufferSize = sizeof (UINT32) + sizeof (UINT16) + StrSize (NvRamMap->BootDescriptionData);
724   BufferSize += GetDevicePathSize (CallbackData->LoadContext->FilePathList);
725 
726   if (NvRamMap->BootOptionalData[0] != 0x0000) {
727     OptionalDataExist = TRUE;
728     BufferSize += StrSize (NvRamMap->BootOptionalData);
729   }
730 
731   Buffer = AllocateZeroPool (BufferSize);
732   if (NULL == Buffer) {
733     return EFI_OUT_OF_RESOURCES;
734   }
735 
736   NewMenuEntry = BOpt_CreateMenuEntry (BM_LOAD_CONTEXT_SELECT);
737   if (NULL == NewMenuEntry) {
738     return EFI_OUT_OF_RESOURCES;
739   }
740 
741   NewLoadContext                  = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
742   NewLoadContext->Deleted         = FALSE;
743   NewLoadContext->LoadOptionSize  = BufferSize;
744   Ptr = (UINT8 *) Buffer;
745   NewLoadContext->LoadOption = Ptr;
746   *((UINT32 *) Ptr) = LOAD_OPTION_ACTIVE;
747   NewLoadContext->Attributes = *((UINT32 *) Ptr);
748   NewLoadContext->IsActive = TRUE;
749   NewLoadContext->ForceReconnect = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_FORCE_RECONNECT);
750 
751   Ptr += sizeof (UINT32);
752   *((UINT16 *) Ptr) = (UINT16) GetDevicePathSize (CallbackData->LoadContext->FilePathList);
753   NewLoadContext->FilePathListLength = *((UINT16 *) Ptr);
754   Ptr += sizeof (UINT16);
755 
756   CopyMem (
757     Ptr,
758     NvRamMap->BootDescriptionData,
759     StrSize (NvRamMap->BootDescriptionData)
760     );
761 
762   NewLoadContext->Description = AllocateZeroPool (StrSize (NvRamMap->BootDescriptionData));
763   ASSERT (NewLoadContext->Description != NULL);
764 
765   NewMenuEntry->DisplayString = NewLoadContext->Description;
766   CopyMem (
767     NewLoadContext->Description,
768     (VOID *) Ptr,
769     StrSize (NvRamMap->BootDescriptionData)
770     );
771 
772   Ptr += StrSize (NvRamMap->BootDescriptionData);
773   CopyMem (
774     Ptr,
775     CallbackData->LoadContext->FilePathList,
776     GetDevicePathSize (CallbackData->LoadContext->FilePathList)
777     );
778 
779   NewLoadContext->FilePathList = AllocateZeroPool (GetDevicePathSize (CallbackData->LoadContext->FilePathList));
780   ASSERT (NewLoadContext->FilePathList != NULL);
781 
782   CopyMem (
783     NewLoadContext->FilePathList,
784     (VOID *) Ptr,
785     GetDevicePathSize (CallbackData->LoadContext->FilePathList)
786     );
787 
788   NewMenuEntry->HelpString    = UiDevicePathToStr (NewLoadContext->FilePathList);
789   NewMenuEntry->OptionNumber  = Index;
790   NewMenuEntry->DisplayStringToken = HiiSetString (CallbackData->BmmHiiHandle, 0, NewMenuEntry->DisplayString, NULL);
791   NewMenuEntry->HelpStringToken = HiiSetString (CallbackData->BmmHiiHandle, 0, NewMenuEntry->HelpString, NULL);
792 
793   if (OptionalDataExist) {
794     Ptr += (UINT8) GetDevicePathSize (CallbackData->LoadContext->FilePathList);
795 
796     CopyMem (Ptr, NvRamMap->BootOptionalData, StrSize (NvRamMap->BootOptionalData));
797   }
798 
799   Status = gRT->SetVariable (
800                   BootString,
801                   &gEfiGlobalVariableGuid,
802                   VAR_FLAG,
803                   BufferSize,
804                   Buffer
805                   );
806   ASSERT_EFI_ERROR (Status);
807 
808   GetEfiGlobalVariable2 (L"BootOrder", (VOID **) &BootOrderList, &BootOrderListSize);
809   NewBootOrderList = AllocateZeroPool (BootOrderListSize + sizeof (UINT16));
810   ASSERT (NewBootOrderList != NULL);
811   if (BootOrderList != NULL){
812     CopyMem (NewBootOrderList, BootOrderList, BootOrderListSize);
813   }
814   NewBootOrderList[BootOrderListSize / sizeof (UINT16)] = Index;
815 
816   if (BootOrderList != NULL) {
817     FreePool (BootOrderList);
818   }
819 
820   Status = gRT->SetVariable (
821                   L"BootOrder",
822                   &gEfiGlobalVariableGuid,
823                   VAR_FLAG,
824                   BootOrderListSize + sizeof (UINT16),
825                   NewBootOrderList
826                   );
827   ASSERT_EFI_ERROR (Status);
828 
829   FreePool (NewBootOrderList);
830   NewBootOrderList = NULL;
831   InsertTailList (&BootOptionMenu.Head, &NewMenuEntry->Link);
832   BootOptionMenu.MenuNumber++;
833 
834   return EFI_SUCCESS;
835 }
836 
837 /**
838   This function update the "BootNext" EFI Variable. If there is
839   no "BootNext" specified in BMM, this EFI Variable is deleted.
840   It also update the BMM context data specified the "BootNext"
841   vaule.
842 
843   @param CallbackData    The BMM context data.
844 
845   @retval EFI_SUCCESS    The function complete successfully.
846   @return                The EFI variable can be saved. See gRT->SetVariable
847                          for detail return information.
848 
849 **/
850 EFI_STATUS
Var_UpdateBootNext(IN BMM_CALLBACK_DATA * CallbackData)851 Var_UpdateBootNext (
852   IN BMM_CALLBACK_DATA            *CallbackData
853   )
854 {
855   BM_MENU_ENTRY     *NewMenuEntry;
856   BM_LOAD_CONTEXT   *NewLoadContext;
857   BMM_FAKE_NV_DATA  *CurrentFakeNVMap;
858   UINT16            Index;
859   EFI_STATUS        Status;
860 
861   Status            = EFI_SUCCESS;
862   CurrentFakeNVMap  = &CallbackData->BmmFakeNvData;
863   for (Index = 0; Index < BootOptionMenu.MenuNumber; Index++) {
864     NewMenuEntry = BOpt_GetMenuEntry (&BootOptionMenu, Index);
865     ASSERT (NULL != NewMenuEntry);
866 
867     NewLoadContext              = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
868     NewLoadContext->IsBootNext  = FALSE;
869   }
870 
871   if (CurrentFakeNVMap->BootNext == NONE_BOOTNEXT_VALUE) {
872     EfiLibDeleteVariable (L"BootNext", &gEfiGlobalVariableGuid);
873     return EFI_SUCCESS;
874   }
875 
876   NewMenuEntry = BOpt_GetMenuEntry (
877                   &BootOptionMenu,
878                   CurrentFakeNVMap->BootNext
879                   );
880   ASSERT (NewMenuEntry != NULL);
881 
882   NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
883   Status = gRT->SetVariable (
884                   L"BootNext",
885                   &gEfiGlobalVariableGuid,
886                   VAR_FLAG,
887                   sizeof (UINT16),
888                   &NewMenuEntry->OptionNumber
889                   );
890   NewLoadContext->IsBootNext              = TRUE;
891   CallbackData->BmmOldFakeNVData.BootNext = CurrentFakeNVMap->BootNext;
892   return Status;
893 }
894 
895 /**
896   This function update the "BootOrder" EFI Variable based on
897   BMM Formset's NV map. It then refresh BootOptionMenu
898   with the new "BootOrder" list.
899 
900   @param CallbackData    The BMM context data.
901 
902   @retval EFI_SUCCESS             The function complete successfully.
903   @retval EFI_OUT_OF_RESOURCES    Not enough memory to complete the function.
904   @return The EFI variable can not be saved. See gRT->SetVariable for detail return information.
905 
906 **/
907 EFI_STATUS
Var_UpdateBootOrder(IN BMM_CALLBACK_DATA * CallbackData)908 Var_UpdateBootOrder (
909   IN BMM_CALLBACK_DATA            *CallbackData
910   )
911 {
912   EFI_STATUS  Status;
913   UINT16      Index;
914   UINT16      OrderIndex;
915   UINT16      *BootOrder;
916   UINTN       BootOrderSize;
917   UINT16      OptionNumber;
918 
919   //
920   // First check whether BootOrder is present in current configuration
921   //
922   GetEfiGlobalVariable2 (L"BootOrder", (VOID **) &BootOrder, &BootOrderSize);
923   if (BootOrder == NULL) {
924     return EFI_OUT_OF_RESOURCES;
925   }
926 
927   ASSERT (BootOptionMenu.MenuNumber <= (sizeof (CallbackData->BmmFakeNvData.BootOptionOrder) / sizeof (CallbackData->BmmFakeNvData.BootOptionOrder[0])));
928 
929   //
930   // OptionOrder is subset of BootOrder
931   //
932   for (OrderIndex = 0; (OrderIndex < BootOptionMenu.MenuNumber) && (CallbackData->BmmFakeNvData.BootOptionOrder[OrderIndex] != 0); OrderIndex++) {
933     for (Index = OrderIndex; Index < BootOrderSize / sizeof (UINT16); Index++) {
934       if ((BootOrder[Index] == (UINT16) (CallbackData->BmmFakeNvData.BootOptionOrder[OrderIndex] - 1)) && (OrderIndex != Index)) {
935         OptionNumber = BootOrder[Index];
936         CopyMem (&BootOrder[OrderIndex + 1], &BootOrder[OrderIndex], (Index - OrderIndex) * sizeof (UINT16));
937         BootOrder[OrderIndex] = OptionNumber;
938       }
939     }
940   }
941 
942   Status = gRT->SetVariable (
943                   L"BootOrder",
944                   &gEfiGlobalVariableGuid,
945                   VAR_FLAG,
946                   BootOrderSize,
947                   BootOrder
948                   );
949   FreePool (BootOrder);
950 
951   BOpt_FreeMenu (&BootOptionMenu);
952   BOpt_GetBootOptions (CallbackData);
953 
954   return Status;
955 
956 }
957 
958 /**
959   This function update the "DriverOrder" EFI Variable based on
960   BMM Formset's NV map. It then refresh DriverOptionMenu
961   with the new "DriverOrder" list.
962 
963   @param CallbackData    The BMM context data.
964 
965   @retval EFI_SUCCESS           The function complete successfully.
966   @retval EFI_OUT_OF_RESOURCES  Not enough memory to complete the function.
967   @return The EFI variable can not be saved. See gRT->SetVariable for detail return information.
968 
969 **/
970 EFI_STATUS
Var_UpdateDriverOrder(IN BMM_CALLBACK_DATA * CallbackData)971 Var_UpdateDriverOrder (
972   IN BMM_CALLBACK_DATA            *CallbackData
973   )
974 {
975   EFI_STATUS  Status;
976   UINT16      Index;
977   UINT16      *DriverOrderList;
978   UINT16      *NewDriverOrderList;
979   UINTN       DriverOrderListSize;
980 
981   DriverOrderList     = NULL;
982   DriverOrderListSize = 0;
983 
984   //
985   // First check whether DriverOrder is present in current configuration
986   //
987   GetEfiGlobalVariable2 (L"DriverOrder", (VOID **) &DriverOrderList, &DriverOrderListSize);
988   NewDriverOrderList = AllocateZeroPool (DriverOrderListSize);
989 
990   if (NewDriverOrderList == NULL) {
991     return EFI_OUT_OF_RESOURCES;
992   }
993   //
994   // If exists, delete it to hold new DriverOrder
995   //
996   if (DriverOrderList != NULL) {
997     EfiLibDeleteVariable (L"DriverOrder", &gEfiGlobalVariableGuid);
998     FreePool (DriverOrderList);
999   }
1000 
1001   ASSERT (DriverOptionMenu.MenuNumber <= (sizeof (CallbackData->BmmFakeNvData.DriverOptionOrder) / sizeof (CallbackData->BmmFakeNvData.DriverOptionOrder[0])));
1002   for (Index = 0; Index < DriverOptionMenu.MenuNumber; Index++) {
1003     NewDriverOrderList[Index] = (UINT16) (CallbackData->BmmFakeNvData.DriverOptionOrder[Index] - 1);
1004   }
1005 
1006   Status = gRT->SetVariable (
1007                   L"DriverOrder",
1008                   &gEfiGlobalVariableGuid,
1009                   VAR_FLAG,
1010                   DriverOrderListSize,
1011                   NewDriverOrderList
1012                   );
1013   if (EFI_ERROR (Status)) {
1014     return Status;
1015   }
1016 
1017   BOpt_FreeMenu (&DriverOptionMenu);
1018   BOpt_GetDriverOptions (CallbackData);
1019   return EFI_SUCCESS;
1020 }
1021 
1022 /**
1023   Update the Text Mode of Console.
1024 
1025   @param CallbackData  The context data for BMM.
1026 
1027   @retval EFI_SUCCSS If the Text Mode of Console is updated.
1028   @return Other value if the Text Mode of Console is not updated.
1029 
1030 **/
1031 EFI_STATUS
Var_UpdateConMode(IN BMM_CALLBACK_DATA * CallbackData)1032 Var_UpdateConMode (
1033   IN BMM_CALLBACK_DATA            *CallbackData
1034   )
1035 {
1036   EFI_STATUS        Status;
1037   UINTN             Mode;
1038   CONSOLE_OUT_MODE  ModeInfo;
1039 
1040   Mode = CallbackData->BmmFakeNvData.ConsoleOutMode;
1041 
1042   Status = gST->ConOut->QueryMode (gST->ConOut, Mode, &(ModeInfo.Column), &(ModeInfo.Row));
1043   if (!EFI_ERROR(Status)) {
1044     Status = PcdSet32S (PcdSetupConOutColumn, (UINT32) ModeInfo.Column);
1045     if (!EFI_ERROR (Status)) {
1046       Status = PcdSet32S (PcdSetupConOutRow, (UINT32) ModeInfo.Row);
1047     }
1048   }
1049 
1050   return Status;
1051 }
1052