]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Library/BootMaintenanceManagerUiLib/BootOption.c
MdeModulePkg: Refine the code in BootMaintenanceManagerUiLib
[mirror_edk2.git] / MdeModulePkg / Library / BootMaintenanceManagerUiLib / BootOption.c
CommitLineData
4af04335
DB
1/** @file\r
2 Provide boot option support for Application "BootMaint"\r
3\r
4 Include file system navigation, system handle selection\r
5\r
6 Boot option manipulation\r
7\r
2ba36b2f 8Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.<BR>\r
4af04335
DB
9This program and the accompanying materials\r
10are licensed and made available under the terms and conditions of the BSD License\r
11which accompanies this distribution. The full text of the license may be found at\r
12http://opensource.org/licenses/bsd-license.php\r
13\r
14THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
15WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
16\r
17**/\r
18\r
19#include "BootMaintenanceManager.h"\r
20\r
21///\r
22/// Define the maximum characters that will be accepted.\r
23///\r
24#define MAX_CHAR 480\r
25\r
26/**\r
27 Create a menu entry by given menu type.\r
28\r
29 @param MenuType The Menu type to be created.\r
30\r
31 @retval NULL If failed to create the menu.\r
32 @return the new menu entry.\r
33\r
34**/\r
35BM_MENU_ENTRY *\r
36BOpt_CreateMenuEntry (\r
37 UINTN MenuType\r
38 )\r
39{\r
40 BM_MENU_ENTRY *MenuEntry;\r
41 UINTN ContextSize;\r
42\r
43 //\r
44 // Get context size according to menu type\r
45 //\r
46 switch (MenuType) {\r
47 case BM_LOAD_CONTEXT_SELECT:\r
48 ContextSize = sizeof (BM_LOAD_CONTEXT);\r
49 break;\r
50\r
51 case BM_FILE_CONTEXT_SELECT:\r
52 ContextSize = sizeof (BM_FILE_CONTEXT);\r
53 break;\r
54\r
55 case BM_CONSOLE_CONTEXT_SELECT:\r
56 ContextSize = sizeof (BM_CONSOLE_CONTEXT);\r
57 break;\r
58\r
59 case BM_TERMINAL_CONTEXT_SELECT:\r
60 ContextSize = sizeof (BM_TERMINAL_CONTEXT);\r
61 break;\r
62\r
63 case BM_HANDLE_CONTEXT_SELECT:\r
64 ContextSize = sizeof (BM_HANDLE_CONTEXT);\r
65 break;\r
66\r
67 default:\r
68 ContextSize = 0;\r
69 break;\r
70 }\r
71\r
72 if (ContextSize == 0) {\r
73 return NULL;\r
74 }\r
75\r
76 //\r
77 // Create new menu entry\r
78 //\r
79 MenuEntry = AllocateZeroPool (sizeof (BM_MENU_ENTRY));\r
80 if (MenuEntry == NULL) {\r
81 return NULL;\r
82 }\r
83\r
84 MenuEntry->VariableContext = AllocateZeroPool (ContextSize);\r
85 if (MenuEntry->VariableContext == NULL) {\r
86 FreePool (MenuEntry);\r
87 return NULL;\r
88 }\r
89\r
90 MenuEntry->Signature = BM_MENU_ENTRY_SIGNATURE;\r
91 MenuEntry->ContextSelection = MenuType;\r
92 return MenuEntry;\r
93}\r
94\r
95/**\r
96 Free up all resource allocated for a BM_MENU_ENTRY.\r
97\r
98 @param MenuEntry A pointer to BM_MENU_ENTRY.\r
99\r
100**/\r
101VOID\r
102BOpt_DestroyMenuEntry (\r
103 BM_MENU_ENTRY *MenuEntry\r
104 )\r
105{\r
106 BM_LOAD_CONTEXT *LoadContext;\r
107 BM_FILE_CONTEXT *FileContext;\r
108 BM_CONSOLE_CONTEXT *ConsoleContext;\r
109 BM_TERMINAL_CONTEXT *TerminalContext;\r
110 BM_HANDLE_CONTEXT *HandleContext;\r
111\r
112 //\r
113 // Select by the type in Menu entry for current context type\r
114 //\r
115 switch (MenuEntry->ContextSelection) {\r
116 case BM_LOAD_CONTEXT_SELECT:\r
117 LoadContext = (BM_LOAD_CONTEXT *) MenuEntry->VariableContext;\r
118 FreePool (LoadContext->FilePathList);\r
4af04335
DB
119 if (LoadContext->OptionalData != NULL) {\r
120 FreePool (LoadContext->OptionalData);\r
121 }\r
122 FreePool (LoadContext);\r
123 break;\r
124\r
125 case BM_FILE_CONTEXT_SELECT:\r
126 FileContext = (BM_FILE_CONTEXT *) MenuEntry->VariableContext;\r
127\r
128 if (!FileContext->IsRoot) {\r
129 FreePool (FileContext->DevicePath);\r
130 } else {\r
131 if (FileContext->FHandle != NULL) {\r
132 FileContext->FHandle->Close (FileContext->FHandle);\r
133 }\r
134 }\r
135\r
136 if (FileContext->FileName != NULL) {\r
137 FreePool (FileContext->FileName);\r
138 }\r
139 if (FileContext->Info != NULL) {\r
140 FreePool (FileContext->Info);\r
141 }\r
142 FreePool (FileContext);\r
143 break;\r
144\r
145 case BM_CONSOLE_CONTEXT_SELECT:\r
146 ConsoleContext = (BM_CONSOLE_CONTEXT *) MenuEntry->VariableContext;\r
147 FreePool (ConsoleContext->DevicePath);\r
148 FreePool (ConsoleContext);\r
149 break;\r
150\r
151 case BM_TERMINAL_CONTEXT_SELECT:\r
152 TerminalContext = (BM_TERMINAL_CONTEXT *) MenuEntry->VariableContext;\r
153 FreePool (TerminalContext->DevicePath);\r
154 FreePool (TerminalContext);\r
155 break;\r
156\r
157 case BM_HANDLE_CONTEXT_SELECT:\r
158 HandleContext = (BM_HANDLE_CONTEXT *) MenuEntry->VariableContext;\r
159 FreePool (HandleContext);\r
160 break;\r
161\r
162 default:\r
163 break;\r
164 }\r
165\r
166 FreePool (MenuEntry->DisplayString);\r
167 if (MenuEntry->HelpString != NULL) {\r
168 FreePool (MenuEntry->HelpString);\r
169 }\r
170\r
171 FreePool (MenuEntry);\r
172}\r
173\r
174/**\r
175 Get the Menu Entry from the list in Menu Entry List.\r
176\r
177 If MenuNumber is great or equal to the number of Menu\r
178 Entry in the list, then ASSERT.\r
179\r
180 @param MenuOption The Menu Entry List to read the menu entry.\r
181 @param MenuNumber The index of Menu Entry.\r
182\r
183 @return The Menu Entry.\r
184\r
185**/\r
186BM_MENU_ENTRY *\r
187BOpt_GetMenuEntry (\r
188 BM_MENU_OPTION *MenuOption,\r
189 UINTN MenuNumber\r
190 )\r
191{\r
192 BM_MENU_ENTRY *NewMenuEntry;\r
193 UINTN Index;\r
194 LIST_ENTRY *List;\r
195\r
196 ASSERT (MenuNumber < MenuOption->MenuNumber);\r
197\r
198 List = MenuOption->Head.ForwardLink;\r
199 for (Index = 0; Index < MenuNumber; Index++) {\r
200 List = List->ForwardLink;\r
201 }\r
202\r
203 NewMenuEntry = CR (List, BM_MENU_ENTRY, Link, BM_MENU_ENTRY_SIGNATURE);\r
204\r
205 return NewMenuEntry;\r
206}\r
207\r
208/**\r
209 Free resources allocated in Allocate Rountine.\r
210\r
211 @param FreeMenu Menu to be freed\r
212**/\r
213VOID\r
214BOpt_FreeMenu (\r
215 BM_MENU_OPTION *FreeMenu\r
216 )\r
217{\r
218 BM_MENU_ENTRY *MenuEntry;\r
219 while (!IsListEmpty (&FreeMenu->Head)) {\r
220 MenuEntry = CR (\r
221 FreeMenu->Head.ForwardLink,\r
222 BM_MENU_ENTRY,\r
223 Link,\r
224 BM_MENU_ENTRY_SIGNATURE\r
225 );\r
226 RemoveEntryList (&MenuEntry->Link);\r
227 BOpt_DestroyMenuEntry (MenuEntry);\r
228 }\r
229 FreeMenu->MenuNumber = 0;\r
230}\r
231\r
232/**\r
233\r
234 Build the BootOptionMenu according to BootOrder Variable.\r
235 This Routine will access the Boot#### to get EFI_LOAD_OPTION.\r
236\r
237 @param CallbackData The BMM context data.\r
238\r
239 @return EFI_NOT_FOUND Fail to find "BootOrder" variable.\r
240 @return EFI_SUCESS Success build boot option menu.\r
241\r
242**/\r
243EFI_STATUS\r
244BOpt_GetBootOptions (\r
245 IN BMM_CALLBACK_DATA *CallbackData\r
246 )\r
247{\r
248 UINTN Index;\r
249 UINT16 BootString[10];\r
250 UINT8 *LoadOptionFromVar;\r
251 UINT8 *LoadOption;\r
252 UINTN BootOptionSize;\r
253 BOOLEAN BootNextFlag;\r
254 UINT16 *BootOrderList;\r
255 UINTN BootOrderListSize;\r
256 UINT16 *BootNext;\r
257 UINTN BootNextSize;\r
258 BM_MENU_ENTRY *NewMenuEntry;\r
259 BM_LOAD_CONTEXT *NewLoadContext;\r
260 UINT8 *LoadOptionPtr;\r
261 UINTN StringSize;\r
262 UINTN OptionalDataSize;\r
263 UINT8 *LoadOptionEnd;\r
264 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
265 UINTN MenuCount;\r
266 UINT8 *Ptr;\r
267 EFI_BOOT_MANAGER_LOAD_OPTION *BootOption;\r
268 UINTN BootOptionCount; \r
269 \r
270 MenuCount = 0;\r
271 BootOrderListSize = 0;\r
272 BootNextSize = 0;\r
273 BootOrderList = NULL;\r
274 BootNext = NULL;\r
275 LoadOptionFromVar = NULL;\r
276 BOpt_FreeMenu (&BootOptionMenu);\r
277 InitializeListHead (&BootOptionMenu.Head);\r
278\r
279 //\r
280 // Get the BootOrder from the Var\r
281 //\r
282 GetEfiGlobalVariable2 (L"BootOrder", (VOID **) &BootOrderList, &BootOrderListSize);\r
283 if (BootOrderList == NULL) {\r
284 return EFI_NOT_FOUND;\r
285 }\r
286 \r
287 //\r
288 // Get the BootNext from the Var\r
289 //\r
290 GetEfiGlobalVariable2 (L"BootNext", (VOID **) &BootNext, &BootNextSize);\r
291 if (BootNext != NULL) {\r
292 if (BootNextSize != sizeof (UINT16)) {\r
293 FreePool (BootNext);\r
294 BootNext = NULL;\r
295 }\r
296 }\r
297 BootOption = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);\r
298 for (Index = 0; Index < BootOrderListSize / sizeof (UINT16); Index++) {\r
299 //\r
300 // Don't display the hidden/inactive boot option\r
301 //\r
302 if (((BootOption[Index].Attributes & LOAD_OPTION_HIDDEN) != 0) || ((BootOption[Index].Attributes & LOAD_OPTION_ACTIVE) == 0)) {\r
303 continue;\r
304 }\r
305 \r
306 UnicodeSPrint (BootString, sizeof (BootString), L"Boot%04x", BootOrderList[Index]);\r
307 //\r
308 // Get all loadoptions from the VAR\r
309 //\r
310 GetEfiGlobalVariable2 (BootString, (VOID **) &LoadOptionFromVar, &BootOptionSize);\r
311 if (LoadOptionFromVar == NULL) {\r
312 continue;\r
313 }\r
314\r
315 LoadOption = AllocateZeroPool (BootOptionSize);\r
316 if (LoadOption == NULL) {\r
317 continue;\r
318 }\r
319\r
320 CopyMem (LoadOption, LoadOptionFromVar, BootOptionSize);\r
321 FreePool (LoadOptionFromVar);\r
322\r
323 if (BootNext != NULL) {\r
324 BootNextFlag = (BOOLEAN) (*BootNext == BootOrderList[Index]);\r
325 } else {\r
326 BootNextFlag = FALSE;\r
327 }\r
328\r
329 NewMenuEntry = BOpt_CreateMenuEntry (BM_LOAD_CONTEXT_SELECT);\r
330 ASSERT (NULL != NewMenuEntry);\r
331\r
332 NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;\r
333\r
334 LoadOptionPtr = LoadOption;\r
335 LoadOptionEnd = LoadOption + BootOptionSize;\r
336\r
337 NewMenuEntry->OptionNumber = BootOrderList[Index];\r
4af04335
DB
338 NewLoadContext->Deleted = FALSE;\r
339 NewLoadContext->IsBootNext = BootNextFlag;\r
340\r
341 //\r
342 // Is a Legacy Device?\r
343 //\r
344 Ptr = (UINT8 *) LoadOption;\r
345\r
346 //\r
347 // Attribute = *(UINT32 *)Ptr;\r
348 //\r
349 Ptr += sizeof (UINT32);\r
350\r
351 //\r
352 // FilePathSize = *(UINT16 *)Ptr;\r
353 //\r
354 Ptr += sizeof (UINT16);\r
355\r
356 //\r
357 // Description = (CHAR16 *)Ptr;\r
358 //\r
359 Ptr += StrSize ((CHAR16 *) Ptr);\r
360\r
361 //\r
362 // Now Ptr point to Device Path\r
363 //\r
364 DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) Ptr;\r
365 if ((BBS_DEVICE_PATH == DevicePath->Type) && (BBS_BBS_DP == DevicePath->SubType)) {\r
366 NewLoadContext->IsLegacy = TRUE;\r
367 } else {\r
368 NewLoadContext->IsLegacy = FALSE;\r
369 }\r
370 //\r
371 // LoadOption is a pointer type of UINT8\r
372 // for easy use with following LOAD_OPTION\r
373 // embedded in this struct\r
374 //\r
4af04335
DB
375\r
376 NewLoadContext->Attributes = *(UINT32 *) LoadOptionPtr;\r
4af04335
DB
377\r
378 LoadOptionPtr += sizeof (UINT32);\r
379\r
380 NewLoadContext->FilePathListLength = *(UINT16 *) LoadOptionPtr;\r
381 LoadOptionPtr += sizeof (UINT16);\r
382 \r
383 StringSize = StrSize((UINT16*)LoadOptionPtr);\r
384\r
385 NewLoadContext->Description = AllocateZeroPool (StrSize((UINT16*)LoadOptionPtr));\r
386 ASSERT (NewLoadContext->Description != NULL);\r
387 StrCpyS (NewLoadContext->Description, StrSize((UINT16*)LoadOptionPtr) / sizeof (UINT16), (UINT16*)LoadOptionPtr);\r
388 \r
389 ASSERT (NewLoadContext->Description != NULL);\r
390 NewMenuEntry->DisplayString = NewLoadContext->Description;\r
391 NewMenuEntry->DisplayStringToken = HiiSetString (CallbackData->BmmHiiHandle, 0, NewMenuEntry->DisplayString, NULL);\r
392\r
393 LoadOptionPtr += StringSize;\r
394\r
395 NewLoadContext->FilePathList = AllocateZeroPool (NewLoadContext->FilePathListLength);\r
396 ASSERT (NewLoadContext->FilePathList != NULL);\r
397 CopyMem (\r
398 NewLoadContext->FilePathList,\r
399 (EFI_DEVICE_PATH_PROTOCOL *) LoadOptionPtr,\r
400 NewLoadContext->FilePathListLength\r
401 );\r
402\r
403 NewMenuEntry->HelpString = UiDevicePathToStr (NewLoadContext->FilePathList);\r
404 NewMenuEntry->HelpStringToken = HiiSetString (CallbackData->BmmHiiHandle, 0, NewMenuEntry->HelpString, NULL); \r
405\r
406 LoadOptionPtr += NewLoadContext->FilePathListLength;\r
407\r
408 if (LoadOptionPtr < LoadOptionEnd) {\r
409 OptionalDataSize = BootOptionSize -\r
410 sizeof (UINT32) -\r
411 sizeof (UINT16) -\r
412 StringSize -\r
413 NewLoadContext->FilePathListLength;\r
414\r
415 NewLoadContext->OptionalData = AllocateZeroPool (OptionalDataSize);\r
416 ASSERT (NewLoadContext->OptionalData != NULL);\r
417 CopyMem (\r
418 NewLoadContext->OptionalData,\r
419 LoadOptionPtr,\r
420 OptionalDataSize\r
421 );\r
4af04335
DB
422 }\r
423\r
424 InsertTailList (&BootOptionMenu.Head, &NewMenuEntry->Link);\r
425 MenuCount++;\r
426 }\r
427 EfiBootManagerFreeLoadOptions (BootOption, BootOptionCount);\r
428\r
429 if (BootNext != NULL) {\r
430 FreePool (BootNext);\r
431 }\r
432 if (BootOrderList != NULL) {\r
433 FreePool (BootOrderList);\r
434 }\r
2ba36b2f
DB
435\r
436 FreePool(LoadOption);\r
4af04335
DB
437 BootOptionMenu.MenuNumber = MenuCount;\r
438 return EFI_SUCCESS;\r
439}\r
440\r
441/**\r
442\r
443 Find drivers that will be added as Driver#### variables from handles\r
444 in current system environment\r
445 All valid handles in the system except those consume SimpleFs, LoadFile\r
446 are stored in DriverMenu for future use.\r
447\r
448 @retval EFI_SUCCESS The function complets successfully.\r
449 @return Other value if failed to build the DriverMenu.\r
450\r
451**/\r
452EFI_STATUS\r
453BOpt_FindDrivers (\r
454 VOID\r
455 )\r
456{\r
457 UINTN NoDevicePathHandles;\r
458 EFI_HANDLE *DevicePathHandle;\r
459 UINTN Index;\r
460 EFI_STATUS Status;\r
461 BM_MENU_ENTRY *NewMenuEntry;\r
462 BM_HANDLE_CONTEXT *NewHandleContext;\r
463 EFI_HANDLE CurHandle;\r
464 UINTN OptionNumber;\r
465 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFs;\r
466 EFI_LOAD_FILE_PROTOCOL *LoadFile;\r
467\r
468 SimpleFs = NULL;\r
469 LoadFile = NULL;\r
470\r
471 InitializeListHead (&DriverMenu.Head);\r
472\r
473 //\r
474 // At first, get all handles that support Device Path\r
475 // protocol which is the basic requirement for\r
476 // Driver####\r
477 //\r
478 Status = gBS->LocateHandleBuffer (\r
479 ByProtocol,\r
480 &gEfiDevicePathProtocolGuid,\r
481 NULL,\r
482 &NoDevicePathHandles,\r
483 &DevicePathHandle\r
484 );\r
485 if (EFI_ERROR (Status)) {\r
486 return Status;\r
487 }\r
488\r
489 OptionNumber = 0;\r
490 for (Index = 0; Index < NoDevicePathHandles; Index++) {\r
491 CurHandle = DevicePathHandle[Index];\r
492\r
493 Status = gBS->HandleProtocol (\r
494 CurHandle,\r
495 &gEfiSimpleFileSystemProtocolGuid,\r
496 (VOID **) &SimpleFs\r
497 );\r
498 if (Status == EFI_SUCCESS) {\r
499 continue;\r
500 }\r
501\r
502 Status = gBS->HandleProtocol (\r
503 CurHandle,\r
504 &gEfiLoadFileProtocolGuid,\r
505 (VOID **) &LoadFile\r
506 );\r
507 if (Status == EFI_SUCCESS) {\r
508 continue;\r
509 }\r
510\r
511 NewMenuEntry = BOpt_CreateMenuEntry (BM_HANDLE_CONTEXT_SELECT);\r
512 if (NULL == NewMenuEntry) {\r
513 FreePool (DevicePathHandle);\r
514 return EFI_OUT_OF_RESOURCES;\r
515 }\r
516\r
517 NewHandleContext = (BM_HANDLE_CONTEXT *) NewMenuEntry->VariableContext;\r
518 NewHandleContext->Handle = CurHandle;\r
519 NewHandleContext->DevicePath = DevicePathFromHandle (CurHandle);\r
520 NewMenuEntry->DisplayString = UiDevicePathToStr (NewHandleContext->DevicePath);\r
521 NewMenuEntry->DisplayStringToken = HiiSetString (mBmmCallbackInfo->BmmHiiHandle,0,NewMenuEntry->DisplayString,NULL);\r
522 NewMenuEntry->HelpString = NULL;\r
523 NewMenuEntry->HelpStringToken = NewMenuEntry->DisplayStringToken;\r
524 NewMenuEntry->OptionNumber = OptionNumber;\r
525 OptionNumber++;\r
526 InsertTailList (&DriverMenu.Head, &NewMenuEntry->Link);\r
527\r
528 }\r
529\r
530 if (DevicePathHandle != NULL) {\r
531 FreePool (DevicePathHandle);\r
532 }\r
533\r
534 DriverMenu.MenuNumber = OptionNumber;\r
535 return EFI_SUCCESS;\r
536}\r
537\r
538/**\r
539\r
540 Get the Option Number that has not been allocated for use.\r
541\r
542 @param Type The type of Option.\r
543\r
544 @return The available Option Number.\r
545\r
546**/\r
547UINT16\r
548BOpt_GetOptionNumber (\r
549 CHAR16 *Type\r
550 )\r
551{\r
552 UINT16 *OrderList;\r
553 UINTN OrderListSize;\r
554 UINTN Index;\r
555 CHAR16 StrTemp[20];\r
556 UINT16 *OptionBuffer;\r
557 UINT16 OptionNumber;\r
558 UINTN OptionSize;\r
559\r
560 OrderListSize = 0;\r
561 OrderList = NULL;\r
562 OptionNumber = 0;\r
563 Index = 0;\r
564\r
565 UnicodeSPrint (StrTemp, sizeof (StrTemp), L"%sOrder", Type);\r
566\r
567 GetEfiGlobalVariable2 (StrTemp, (VOID **) &OrderList, &OrderListSize);\r
568 for (OptionNumber = 0; ; OptionNumber++) {\r
569 if (OrderList != NULL) {\r
570 for (Index = 0; Index < OrderListSize / sizeof (UINT16); Index++) {\r
571 if (OptionNumber == OrderList[Index]) {\r
572 break;\r
573 }\r
574 }\r
575 }\r
576\r
577 if (Index < OrderListSize / sizeof (UINT16)) {\r
578 //\r
579 // The OptionNumber occurs in the OrderList, continue to use next one\r
580 //\r
581 continue;\r
582 }\r
583 UnicodeSPrint (StrTemp, sizeof (StrTemp), L"%s%04x", Type, (UINTN) OptionNumber);\r
584 DEBUG((EFI_D_ERROR,"Option = %s\n", StrTemp));\r
585 GetEfiGlobalVariable2 (StrTemp, (VOID **) &OptionBuffer, &OptionSize);\r
586 if (NULL == OptionBuffer) {\r
587 //\r
588 // The Boot[OptionNumber] / Driver[OptionNumber] NOT occurs, we found it\r
589 //\r
590 break;\r
591 }\r
592 }\r
593\r
594 return OptionNumber;\r
595}\r
596\r
597/**\r
598\r
599 Get the Option Number for Boot#### that does not used.\r
600\r
601 @return The available Option Number.\r
602\r
603**/\r
604UINT16\r
605BOpt_GetBootOptionNumber (\r
606 VOID\r
607 )\r
608{\r
609 return BOpt_GetOptionNumber (L"Boot");\r
610}\r
611\r
612/**\r
613\r
614 Get the Option Number for Driver#### that does not used.\r
615\r
616 @return The unused Option Number.\r
617\r
618**/\r
619UINT16\r
620BOpt_GetDriverOptionNumber (\r
621 VOID\r
622 )\r
623{\r
624 return BOpt_GetOptionNumber (L"Driver");\r
625}\r
626\r
627/**\r
628\r
629 Build up all DriverOptionMenu\r
630\r
631 @param CallbackData The BMM context data.\r
632\r
633 @retval EFI_SUCESS The functin completes successfully.\r
634 @retval EFI_OUT_OF_RESOURCES Not enough memory to compete the operation.\r
635 @retval EFI_NOT_FOUND Fail to get "DriverOrder" variable.\r
636\r
637**/\r
638EFI_STATUS\r
639BOpt_GetDriverOptions (\r
640 IN BMM_CALLBACK_DATA *CallbackData\r
641 )\r
642{\r
643 UINTN Index;\r
644 UINT16 DriverString[12];\r
645 UINT8 *LoadOptionFromVar;\r
646 UINT8 *LoadOption;\r
647 UINTN DriverOptionSize;\r
648\r
649 UINT16 *DriverOrderList;\r
650 UINTN DriverOrderListSize;\r
651 BM_MENU_ENTRY *NewMenuEntry;\r
652 BM_LOAD_CONTEXT *NewLoadContext;\r
653 UINT8 *LoadOptionPtr;\r
654 UINTN StringSize;\r
655 UINTN OptionalDataSize;\r
656 UINT8 *LoadOptionEnd;\r
657\r
658 DriverOrderListSize = 0;\r
659 DriverOrderList = NULL;\r
660 DriverOptionSize = 0;\r
661 LoadOptionFromVar = NULL;\r
662 BOpt_FreeMenu (&DriverOptionMenu);\r
663 InitializeListHead (&DriverOptionMenu.Head);\r
664 //\r
665 // Get the DriverOrder from the Var\r
666 //\r
667 GetEfiGlobalVariable2 (L"DriverOrder", (VOID **) &DriverOrderList, &DriverOrderListSize);\r
668 if (DriverOrderList == NULL) {\r
669 return EFI_NOT_FOUND;\r
670 }\r
671 \r
672 for (Index = 0; Index < DriverOrderListSize / sizeof (UINT16); Index++) {\r
673 UnicodeSPrint (\r
674 DriverString,\r
675 sizeof (DriverString),\r
676 L"Driver%04x",\r
677 DriverOrderList[Index]\r
678 );\r
679 //\r
680 // Get all loadoptions from the VAR\r
681 //\r
682 GetEfiGlobalVariable2 (DriverString, (VOID **) &LoadOptionFromVar, &DriverOptionSize);\r
683 if (LoadOptionFromVar == NULL) {\r
684 continue;\r
685 }\r
686\r
687 LoadOption = AllocateZeroPool (DriverOptionSize);\r
688 if (LoadOption == NULL) {\r
689 continue;\r
690 }\r
691\r
692 CopyMem (LoadOption, LoadOptionFromVar, DriverOptionSize);\r
693 FreePool (LoadOptionFromVar);\r
694\r
695 NewMenuEntry = BOpt_CreateMenuEntry (BM_LOAD_CONTEXT_SELECT);\r
696 if (NULL == NewMenuEntry) {\r
697 return EFI_OUT_OF_RESOURCES;\r
698 }\r
699\r
700 NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;\r
701 LoadOptionPtr = LoadOption;\r
702 LoadOptionEnd = LoadOption + DriverOptionSize;\r
703 NewMenuEntry->OptionNumber = DriverOrderList[Index];\r
4af04335
DB
704 NewLoadContext->Deleted = FALSE;\r
705 NewLoadContext->IsLegacy = FALSE;\r
706\r
707 //\r
708 // LoadOption is a pointer type of UINT8\r
709 // for easy use with following LOAD_OPTION\r
710 // embedded in this struct\r
711 //\r
4af04335
DB
712\r
713 NewLoadContext->Attributes = *(UINT32 *) LoadOptionPtr;\r
4af04335
DB
714\r
715 LoadOptionPtr += sizeof (UINT32);\r
716\r
717 NewLoadContext->FilePathListLength = *(UINT16 *) LoadOptionPtr;\r
718 LoadOptionPtr += sizeof (UINT16);\r
719\r
720 StringSize = StrSize ((UINT16 *) LoadOptionPtr);\r
721 NewLoadContext->Description = AllocateZeroPool (StringSize);\r
722 ASSERT (NewLoadContext->Description != NULL);\r
723 CopyMem (\r
724 NewLoadContext->Description,\r
725 (UINT16 *) LoadOptionPtr,\r
726 StringSize\r
727 );\r
728 NewMenuEntry->DisplayString = NewLoadContext->Description;\r
729 NewMenuEntry->DisplayStringToken = HiiSetString (CallbackData->BmmHiiHandle, 0, NewMenuEntry->DisplayString, NULL);\r
730\r
731 LoadOptionPtr += StringSize;\r
732\r
733 NewLoadContext->FilePathList = AllocateZeroPool (NewLoadContext->FilePathListLength);\r
734 ASSERT (NewLoadContext->FilePathList != NULL);\r
735 CopyMem (\r
736 NewLoadContext->FilePathList,\r
737 (EFI_DEVICE_PATH_PROTOCOL *) LoadOptionPtr,\r
738 NewLoadContext->FilePathListLength\r
739 );\r
740\r
741 NewMenuEntry->HelpString = UiDevicePathToStr (NewLoadContext->FilePathList);\r
742 NewMenuEntry->HelpStringToken = HiiSetString (CallbackData->BmmHiiHandle, 0, NewMenuEntry->HelpString, NULL); \r
743\r
744 LoadOptionPtr += NewLoadContext->FilePathListLength;\r
745\r
746 if (LoadOptionPtr < LoadOptionEnd) {\r
747 OptionalDataSize = DriverOptionSize -\r
748 sizeof (UINT32) -\r
749 sizeof (UINT16) -\r
750 StringSize -\r
751 NewLoadContext->FilePathListLength;\r
752\r
753 NewLoadContext->OptionalData = AllocateZeroPool (OptionalDataSize);\r
754 ASSERT (NewLoadContext->OptionalData != NULL);\r
755 CopyMem (\r
756 NewLoadContext->OptionalData,\r
757 LoadOptionPtr,\r
758 OptionalDataSize\r
759 );\r
760\r
4af04335
DB
761 }\r
762\r
763 InsertTailList (&DriverOptionMenu.Head, &NewMenuEntry->Link);\r
764\r
765 }\r
766\r
767 if (DriverOrderList != NULL) {\r
768 FreePool (DriverOrderList);\r
769 }\r
2ba36b2f 770 FreePool(LoadOption);\r
4af04335
DB
771 DriverOptionMenu.MenuNumber = Index;\r
772 return EFI_SUCCESS;\r
773\r
774}\r
775\r
776/**\r
777 Get option number according to Boot#### and BootOrder variable. \r
778 The value is saved as #### + 1.\r
779\r
780 @param CallbackData The BMM context data.\r
781**/\r
782VOID \r
783GetBootOrder (\r
784 IN BMM_CALLBACK_DATA *CallbackData\r
785 )\r
786{\r
787 BMM_FAKE_NV_DATA *BmmConfig;\r
788 UINT16 Index;\r
789 UINT16 OptionOrderIndex; \r
790 UINTN DeviceType;\r
791 BM_MENU_ENTRY *NewMenuEntry;\r
792 BM_LOAD_CONTEXT *NewLoadContext; \r
793\r
794 ASSERT (CallbackData != NULL);\r
795 \r
796 DeviceType = (UINTN) -1; \r
797 BmmConfig = &CallbackData->BmmFakeNvData; \r
798 ZeroMem (BmmConfig->BootOptionOrder, sizeof (BmmConfig->BootOptionOrder));\r
799 \r
800 for (Index = 0, OptionOrderIndex = 0; ((Index < BootOptionMenu.MenuNumber) &&\r
801 (OptionOrderIndex < (sizeof (BmmConfig->BootOptionOrder) / sizeof (BmmConfig->BootOptionOrder[0]))));\r
802 Index++) {\r
803 NewMenuEntry = BOpt_GetMenuEntry (&BootOptionMenu, Index);\r
804 NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;\r
805\r
806 if (NewLoadContext->IsLegacy) {\r
807 if (((BBS_BBS_DEVICE_PATH *) NewLoadContext->FilePathList)->DeviceType != DeviceType) {\r
808 DeviceType = ((BBS_BBS_DEVICE_PATH *) NewLoadContext->FilePathList)->DeviceType;\r
809 } else {\r
810 //\r
811 // Only show one legacy boot option for the same device type\r
812 // assuming the boot options are grouped by the device type\r
813 //\r
814 continue;\r
815 }\r
816 }\r
817 BmmConfig->BootOptionOrder[OptionOrderIndex++] = (UINT32) (NewMenuEntry->OptionNumber + 1);\r
818 } \r
819}\r
820\r
821/**\r
822 Get driver option order from globalc DriverOptionMenu.\r
823\r
824 @param CallbackData The BMM context data.\r
825 \r
826**/\r
827VOID \r
828GetDriverOrder (\r
829 IN BMM_CALLBACK_DATA *CallbackData\r
830 )\r
831{\r
832 BMM_FAKE_NV_DATA *BmmConfig;\r
833 UINT16 Index;\r
834 UINT16 OptionOrderIndex; \r
835 UINTN DeviceType;\r
836 BM_MENU_ENTRY *NewMenuEntry;\r
837 BM_LOAD_CONTEXT *NewLoadContext; \r
838\r
839\r
840 ASSERT (CallbackData != NULL);\r
841 \r
842 DeviceType = (UINTN) -1; \r
843 BmmConfig = &CallbackData->BmmFakeNvData; \r
844 ZeroMem (BmmConfig->DriverOptionOrder, sizeof (BmmConfig->DriverOptionOrder));\r
845 \r
846 for (Index = 0, OptionOrderIndex = 0; ((Index < DriverOptionMenu.MenuNumber) &&\r
847 (OptionOrderIndex < (sizeof (BmmConfig->DriverOptionOrder) / sizeof (BmmConfig->DriverOptionOrder[0]))));\r
848 Index++) {\r
849 NewMenuEntry = BOpt_GetMenuEntry (&DriverOptionMenu, Index);\r
850 NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;\r
851\r
852 if (NewLoadContext->IsLegacy) {\r
853 if (((BBS_BBS_DEVICE_PATH *) NewLoadContext->FilePathList)->DeviceType != DeviceType) {\r
854 DeviceType = ((BBS_BBS_DEVICE_PATH *) NewLoadContext->FilePathList)->DeviceType;\r
855 } else {\r
856 //\r
857 // Only show one legacy boot option for the same device type\r
858 // assuming the boot options are grouped by the device type\r
859 //\r
860 continue;\r
861 }\r
862 }\r
863 BmmConfig->DriverOptionOrder[OptionOrderIndex++] = (UINT32) (NewMenuEntry->OptionNumber + 1);\r
864 } \r
865} \r
866\r
867/**\r
868 Boot the file specified by the input file path info.\r
869\r
870 @param FilePath Point to the file path.\r
871\r
872 @retval TRUE Exit caller function.\r
873 @retval FALSE Not exit caller function.\r
874**/\r
875BOOLEAN \r
876BootFromFile (\r
877 IN EFI_DEVICE_PATH_PROTOCOL *FilePath\r
878 )\r
879{\r
880 EFI_BOOT_MANAGER_LOAD_OPTION BootOption;\r
881 CHAR16 *FileName;\r
882\r
883 FileName = ExtractFileNameFromDevicePath(FilePath);\r
884 EfiBootManagerInitializeLoadOption (\r
885 &BootOption,\r
886 0,\r
887 LoadOptionTypeBoot,\r
888 LOAD_OPTION_ACTIVE,\r
889 FileName,\r
890 FilePath,\r
891 NULL,\r
892 0\r
893 );\r
894 //\r
895 // Since current no boot from removable media directly is allowed */\r
896 //\r
897 gST->ConOut->ClearScreen (gST->ConOut);\r
898\r
899 BmmBdsSetConsoleMode (FALSE);\r
900 EfiBootManagerBoot (&BootOption);\r
901 BmmBdsSetConsoleMode (TRUE);\r
902\r
903 FreePool(FileName);\r
904\r
905 EfiBootManagerFreeLoadOption (&BootOption);\r
906\r
907 return FALSE;\r
908}\r
909\r
910/**\r
911 Display the form base on the selected file.\r
912\r
913 @param FilePath Point to the file path.\r
914 @param FormId The form need to display.\r
915\r
916**/\r
917BOOLEAN\r
918ReSendForm(\r
919 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,\r
920 IN EFI_FORM_ID FormId\r
921 )\r
922{\r
923 gBootMaintenancePrivate.LoadContext->FilePathList = FilePath;\r
924\r
925 UpdateOptionPage(&gBootMaintenancePrivate, FormId, FilePath);\r
926\r
927 gBootMaintenancePrivate.FormBrowser2->SendForm (\r
928 gBootMaintenancePrivate.FormBrowser2,\r
929 &gBootMaintenancePrivate.BmmHiiHandle,\r
930 1,\r
931 &mBootMaintGuid,\r
932 FormId,\r
933 NULL,\r
934 NULL\r
935 );\r
936 return TRUE;\r
937}\r
938\r
939/**\r
940 Create boot option base on the input file path info.\r
941\r
942 @param FilePath Point to the file path.\r
943\r
944 @retval TRUE Exit caller function.\r
945 @retval FALSE Not exit caller function.\r
946**/\r
947BOOLEAN \r
948CreateBootOptionFromFile (\r
949 IN EFI_DEVICE_PATH_PROTOCOL *FilePath\r
950 )\r
951{\r
952 return ReSendForm(FilePath, FORM_BOOT_ADD_ID);\r
953}\r
954\r
955/**\r
956 Create driver option base on the input file path info.\r
957\r
958 @param FilePath Point to the file path.\r
959\r
960 @retval TRUE Exit caller function.\r
961 @retval FALSE Not exit caller function.\r
962\r
963**/\r
964BOOLEAN \r
965CreateDriverOptionFromFile (\r
966 IN EFI_DEVICE_PATH_PROTOCOL *FilePath\r
967 )\r
968{\r
969 return ReSendForm(FilePath, FORM_DRV_ADD_FILE_ID);\r
970}\r
971\r