]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Application/UiApp/BootMaint/BootOption.c
MdeModulePkg:Create Boot Maintenance Manager Library
[mirror_edk2.git] / MdeModulePkg / Application / UiApp / BootMaint / BootOption.c
CommitLineData
143f0b1d
ED
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
afc244a5 8Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR>\r
143f0b1d
ED
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 "BootMaint.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
119 FreePool (LoadContext->LoadOption);\r
120 if (LoadContext->OptionalData != NULL) {\r
121 FreePool (LoadContext->OptionalData);\r
122 }\r
123 FreePool (LoadContext);\r
124 break;\r
125\r
126 case BM_FILE_CONTEXT_SELECT:\r
127 FileContext = (BM_FILE_CONTEXT *) MenuEntry->VariableContext;\r
128\r
129 if (!FileContext->IsRoot) {\r
130 FreePool (FileContext->DevicePath);\r
131 } else {\r
132 if (FileContext->FHandle != NULL) {\r
133 FileContext->FHandle->Close (FileContext->FHandle);\r
134 }\r
135 }\r
136\r
137 if (FileContext->FileName != NULL) {\r
138 FreePool (FileContext->FileName);\r
139 }\r
140 if (FileContext->Info != NULL) {\r
141 FreePool (FileContext->Info);\r
142 }\r
143 FreePool (FileContext);\r
144 break;\r
145\r
146 case BM_CONSOLE_CONTEXT_SELECT:\r
147 ConsoleContext = (BM_CONSOLE_CONTEXT *) MenuEntry->VariableContext;\r
148 FreePool (ConsoleContext->DevicePath);\r
149 FreePool (ConsoleContext);\r
150 break;\r
151\r
152 case BM_TERMINAL_CONTEXT_SELECT:\r
153 TerminalContext = (BM_TERMINAL_CONTEXT *) MenuEntry->VariableContext;\r
154 FreePool (TerminalContext->DevicePath);\r
155 FreePool (TerminalContext);\r
156 break;\r
157\r
158 case BM_HANDLE_CONTEXT_SELECT:\r
159 HandleContext = (BM_HANDLE_CONTEXT *) MenuEntry->VariableContext;\r
160 FreePool (HandleContext);\r
161 break;\r
162\r
163 default:\r
164 break;\r
165 }\r
166\r
167 FreePool (MenuEntry->DisplayString);\r
168 if (MenuEntry->HelpString != NULL) {\r
169 FreePool (MenuEntry->HelpString);\r
170 }\r
171\r
172 FreePool (MenuEntry);\r
173}\r
174\r
175/**\r
176 Get the Menu Entry from the list in Menu Entry List.\r
177\r
178 If MenuNumber is great or equal to the number of Menu\r
179 Entry in the list, then ASSERT.\r
180\r
181 @param MenuOption The Menu Entry List to read the menu entry.\r
182 @param MenuNumber The index of Menu Entry.\r
183\r
184 @return The Menu Entry.\r
185\r
186**/\r
187BM_MENU_ENTRY *\r
188BOpt_GetMenuEntry (\r
189 BM_MENU_OPTION *MenuOption,\r
190 UINTN MenuNumber\r
191 )\r
192{\r
193 BM_MENU_ENTRY *NewMenuEntry;\r
194 UINTN Index;\r
195 LIST_ENTRY *List;\r
196\r
197 ASSERT (MenuNumber < MenuOption->MenuNumber);\r
198\r
199 List = MenuOption->Head.ForwardLink;\r
200 for (Index = 0; Index < MenuNumber; Index++) {\r
201 List = List->ForwardLink;\r
202 }\r
203\r
204 NewMenuEntry = CR (List, BM_MENU_ENTRY, Link, BM_MENU_ENTRY_SIGNATURE);\r
205\r
206 return NewMenuEntry;\r
207}\r
208\r
209/**\r
210 This function build the FsOptionMenu list which records all\r
211 available file system in the system. They includes all instances\r
212 of EFI_SIMPLE_FILE_SYSTEM_PROTOCOL, all instances of EFI_LOAD_FILE_SYSTEM\r
213 and all type of legacy boot device.\r
214\r
215 @param CallbackData BMM context data\r
216\r
217 @retval EFI_SUCCESS Success find the file system\r
218 @retval EFI_OUT_OF_RESOURCES Can not create menu entry\r
219\r
220**/\r
221EFI_STATUS\r
222BOpt_FindFileSystem (\r
223 IN BMM_CALLBACK_DATA *CallbackData\r
224 )\r
225{\r
226 UINTN NoBlkIoHandles;\r
227 UINTN NoSimpleFsHandles;\r
228 UINTN NoLoadFileHandles;\r
229 EFI_HANDLE *BlkIoHandle;\r
230 EFI_HANDLE *SimpleFsHandle;\r
231 EFI_HANDLE *LoadFileHandle;\r
232 UINT16 *VolumeLabel;\r
233 EFI_BLOCK_IO_PROTOCOL *BlkIo;\r
234 UINTN Index;\r
235 EFI_STATUS Status;\r
236 BM_MENU_ENTRY *MenuEntry;\r
237 BM_FILE_CONTEXT *FileContext;\r
238 UINT16 *TempStr;\r
239 UINTN OptionNumber;\r
240 VOID *Buffer;\r
143f0b1d
ED
241 BOOLEAN RemovableMedia;\r
242\r
143f0b1d
ED
243 NoSimpleFsHandles = 0;\r
244 NoLoadFileHandles = 0;\r
245 OptionNumber = 0;\r
246 InitializeListHead (&FsOptionMenu.Head);\r
247\r
248 //\r
249 // Locate Handles that support BlockIo protocol\r
250 //\r
251 Status = gBS->LocateHandleBuffer (\r
252 ByProtocol,\r
253 &gEfiBlockIoProtocolGuid,\r
254 NULL,\r
255 &NoBlkIoHandles,\r
256 &BlkIoHandle\r
257 );\r
258 if (!EFI_ERROR (Status)) {\r
259\r
260 for (Index = 0; Index < NoBlkIoHandles; Index++) {\r
261 Status = gBS->HandleProtocol (\r
262 BlkIoHandle[Index],\r
263 &gEfiBlockIoProtocolGuid,\r
264 (VOID **) &BlkIo\r
265 );\r
266\r
267 if (EFI_ERROR (Status)) {\r
268 continue;\r
269 }\r
270\r
271 //\r
272 // Issue a dummy read to trigger reinstall of BlockIo protocol for removable media\r
273 //\r
274 if (BlkIo->Media->RemovableMedia) {\r
275 Buffer = AllocateZeroPool (BlkIo->Media->BlockSize);\r
276 if (NULL == Buffer) {\r
277 FreePool (BlkIoHandle);\r
278 return EFI_OUT_OF_RESOURCES;\r
279 }\r
280\r
281 BlkIo->ReadBlocks (\r
282 BlkIo,\r
283 BlkIo->Media->MediaId,\r
284 0,\r
285 BlkIo->Media->BlockSize,\r
286 Buffer\r
287 );\r
288 FreePool (Buffer);\r
289 }\r
290 }\r
291 FreePool (BlkIoHandle);\r
292 }\r
293\r
294 //\r
295 // Locate Handles that support Simple File System protocol\r
296 //\r
297 Status = gBS->LocateHandleBuffer (\r
298 ByProtocol,\r
299 &gEfiSimpleFileSystemProtocolGuid,\r
300 NULL,\r
301 &NoSimpleFsHandles,\r
302 &SimpleFsHandle\r
303 );\r
304 if (!EFI_ERROR (Status)) {\r
305 //\r
306 // Find all the instances of the File System prototocol\r
307 //\r
308 for (Index = 0; Index < NoSimpleFsHandles; Index++) {\r
309 Status = gBS->HandleProtocol (\r
310 SimpleFsHandle[Index],\r
311 &gEfiBlockIoProtocolGuid,\r
312 (VOID **) &BlkIo\r
313 );\r
314 if (EFI_ERROR (Status)) {\r
315 //\r
316 // If no block IO exists assume it's NOT a removable media\r
317 //\r
318 RemovableMedia = FALSE;\r
319 } else {\r
320 //\r
321 // If block IO exists check to see if it's remobable media\r
322 //\r
323 RemovableMedia = BlkIo->Media->RemovableMedia;\r
324 }\r
325\r
326 //\r
327 // Allocate pool for this load option\r
328 //\r
329 MenuEntry = BOpt_CreateMenuEntry (BM_FILE_CONTEXT_SELECT);\r
330 if (NULL == MenuEntry) {\r
331 FreePool (SimpleFsHandle);\r
332 return EFI_OUT_OF_RESOURCES;\r
333 }\r
334\r
335 FileContext = (BM_FILE_CONTEXT *) MenuEntry->VariableContext;\r
336\r
337 FileContext->Handle = SimpleFsHandle[Index];\r
338 MenuEntry->OptionNumber = Index;\r
339 FileContext->FHandle = EfiLibOpenRoot (FileContext->Handle);\r
340 if (FileContext->FHandle == NULL) {\r
341 BOpt_DestroyMenuEntry (MenuEntry);\r
342 continue;\r
343 }\r
344\r
345 MenuEntry->HelpString = UiDevicePathToStr (DevicePathFromHandle (FileContext->Handle));\r
346 FileContext->Info = EfiLibFileSystemVolumeLabelInfo (FileContext->FHandle);\r
347 FileContext->FileName = EfiStrDuplicate (L"\\");\r
348 FileContext->DevicePath = FileDevicePath (\r
349 FileContext->Handle,\r
350 FileContext->FileName\r
351 );\r
352 FileContext->IsDir = TRUE;\r
353 FileContext->IsRoot = TRUE;\r
354 FileContext->IsRemovableMedia = RemovableMedia;\r
355 FileContext->IsLoadFile = FALSE;\r
356\r
357 //\r
358 // Get current file system's Volume Label\r
359 //\r
360 if (FileContext->Info == NULL) {\r
361 VolumeLabel = L"NO FILE SYSTEM INFO";\r
362 } else {\r
363 if (FileContext->Info->VolumeLabel == NULL) {\r
364 VolumeLabel = L"NULL VOLUME LABEL";\r
365 } else {\r
366 VolumeLabel = FileContext->Info->VolumeLabel;\r
367 if (*VolumeLabel == 0x0000) {\r
368 VolumeLabel = L"NO VOLUME LABEL";\r
369 }\r
370 }\r
371 }\r
372\r
373 TempStr = MenuEntry->HelpString;\r
374 MenuEntry->DisplayString = AllocateZeroPool (MAX_CHAR);\r
375 ASSERT (MenuEntry->DisplayString != NULL);\r
376 UnicodeSPrint (\r
377 MenuEntry->DisplayString,\r
378 MAX_CHAR,\r
379 L"%s, [%s]",\r
380 VolumeLabel,\r
381 TempStr\r
382 );\r
383 OptionNumber++;\r
384 InsertTailList (&FsOptionMenu.Head, &MenuEntry->Link);\r
385 }\r
386 }\r
387\r
388 if (NoSimpleFsHandles != 0) {\r
389 FreePool (SimpleFsHandle);\r
390 }\r
391 //\r
392 // Searching for handles that support Load File protocol\r
393 //\r
394 Status = gBS->LocateHandleBuffer (\r
395 ByProtocol,\r
396 &gEfiLoadFileProtocolGuid,\r
397 NULL,\r
398 &NoLoadFileHandles,\r
399 &LoadFileHandle\r
400 );\r
401\r
402 if (!EFI_ERROR (Status)) {\r
403 for (Index = 0; Index < NoLoadFileHandles; Index++) {\r
404 MenuEntry = BOpt_CreateMenuEntry (BM_FILE_CONTEXT_SELECT);\r
405 if (NULL == MenuEntry) {\r
406 FreePool (LoadFileHandle);\r
407 return EFI_OUT_OF_RESOURCES;\r
408 }\r
409\r
410 FileContext = (BM_FILE_CONTEXT *) MenuEntry->VariableContext;\r
411 FileContext->IsRemovableMedia = FALSE;\r
412 FileContext->IsLoadFile = TRUE;\r
413 FileContext->Handle = LoadFileHandle[Index];\r
414 FileContext->IsRoot = TRUE;\r
415\r
416 FileContext->DevicePath = DevicePathFromHandle (FileContext->Handle);\r
417 FileContext->FileName = UiDevicePathToStr (FileContext->DevicePath);\r
418\r
419 MenuEntry->HelpString = UiDevicePathToStr (FileContext->DevicePath);\r
420\r
421 TempStr = MenuEntry->HelpString;\r
422 MenuEntry->DisplayString = AllocateZeroPool (MAX_CHAR);\r
423 ASSERT (MenuEntry->DisplayString != NULL);\r
424 UnicodeSPrint (\r
425 MenuEntry->DisplayString,\r
426 MAX_CHAR,\r
427 L"Load File [%s]",\r
428 TempStr\r
429 );\r
430\r
431 MenuEntry->OptionNumber = OptionNumber;\r
432 OptionNumber++;\r
433 InsertTailList (&FsOptionMenu.Head, &MenuEntry->Link);\r
434 }\r
435 }\r
436\r
437 if (NoLoadFileHandles != 0) {\r
438 FreePool (LoadFileHandle);\r
439 }\r
440\r
143f0b1d
ED
441 //\r
442 // Remember how many file system options are here\r
443 //\r
444 FsOptionMenu.MenuNumber = OptionNumber;\r
445 return EFI_SUCCESS;\r
446}\r
447\r
448/**\r
449 Free resources allocated in Allocate Rountine.\r
450\r
451 @param FreeMenu Menu to be freed\r
452**/\r
453VOID\r
454BOpt_FreeMenu (\r
455 BM_MENU_OPTION *FreeMenu\r
456 )\r
457{\r
458 BM_MENU_ENTRY *MenuEntry;\r
459 while (!IsListEmpty (&FreeMenu->Head)) {\r
460 MenuEntry = CR (\r
461 FreeMenu->Head.ForwardLink,\r
462 BM_MENU_ENTRY,\r
463 Link,\r
464 BM_MENU_ENTRY_SIGNATURE\r
465 );\r
466 RemoveEntryList (&MenuEntry->Link);\r
467 BOpt_DestroyMenuEntry (MenuEntry);\r
468 }\r
469 FreeMenu->MenuNumber = 0;\r
470}\r
471\r
472/**\r
473 Find files under current directory\r
474 All files and sub-directories in current directory\r
475 will be stored in DirectoryMenu for future use.\r
476\r
477 @param CallbackData The BMM context data.\r
478 @param MenuEntry The Menu Entry.\r
479\r
480 @retval EFI_SUCCESS Get files from current dir successfully.\r
481 @return Other value if can't get files from current dir.\r
482\r
483**/\r
484EFI_STATUS\r
485BOpt_FindFiles (\r
486 IN BMM_CALLBACK_DATA *CallbackData,\r
487 IN BM_MENU_ENTRY *MenuEntry\r
488 )\r
489{\r
490 EFI_FILE_HANDLE NewDir;\r
491 EFI_FILE_HANDLE Dir;\r
492 EFI_FILE_INFO *DirInfo;\r
493 UINTN BufferSize;\r
494 UINTN DirBufferSize;\r
495 BM_MENU_ENTRY *NewMenuEntry;\r
496 BM_FILE_CONTEXT *FileContext;\r
497 BM_FILE_CONTEXT *NewFileContext;\r
498 UINTN Pass;\r
499 EFI_STATUS Status;\r
500 UINTN OptionNumber;\r
501\r
502 FileContext = (BM_FILE_CONTEXT *) MenuEntry->VariableContext;\r
503 Dir = FileContext->FHandle;\r
504 OptionNumber = 0;\r
505 //\r
506 // Open current directory to get files from it\r
507 //\r
508 Status = Dir->Open (\r
509 Dir,\r
510 &NewDir,\r
511 FileContext->FileName,\r
512 EFI_FILE_READ_ONLY,\r
513 0\r
514 );\r
515 if (!FileContext->IsRoot) {\r
516 Dir->Close (Dir);\r
517 }\r
518\r
519 if (EFI_ERROR (Status)) {\r
520 return Status;\r
521 }\r
522\r
523 DirInfo = EfiLibFileInfo (NewDir);\r
524 if (DirInfo == NULL) {\r
525 return EFI_NOT_FOUND;\r
526 }\r
527\r
528 if ((DirInfo->Attribute & EFI_FILE_DIRECTORY) == 0) {\r
529 return EFI_INVALID_PARAMETER;\r
530 }\r
531\r
532 FileContext->DevicePath = FileDevicePath (\r
533 FileContext->Handle,\r
534 FileContext->FileName\r
535 );\r
536\r
537 DirBufferSize = sizeof (EFI_FILE_INFO) + 1024;\r
538 DirInfo = AllocateZeroPool (DirBufferSize);\r
539 if (DirInfo == NULL) {\r
540 return EFI_OUT_OF_RESOURCES;\r
541 }\r
542 //\r
543 // Get all files in current directory\r
544 // Pass 1 to get Directories\r
545 // Pass 2 to get files that are EFI images\r
546 //\r
547 for (Pass = 1; Pass <= 2; Pass++) {\r
548 NewDir->SetPosition (NewDir, 0);\r
549 for (;;) {\r
550 BufferSize = DirBufferSize;\r
551 Status = NewDir->Read (NewDir, &BufferSize, DirInfo);\r
552 if (EFI_ERROR (Status) || BufferSize == 0) {\r
553 break;\r
554 }\r
555\r
556 if (((DirInfo->Attribute & EFI_FILE_DIRECTORY) != 0 && Pass == 2) ||\r
557 ((DirInfo->Attribute & EFI_FILE_DIRECTORY) == 0 && Pass == 1)\r
558 ) {\r
559 //\r
560 // Pass 1 is for Directories\r
561 // Pass 2 is for file names\r
562 //\r
563 continue;\r
564 }\r
565\r
566 if (!(BOpt_IsEfiImageName (DirInfo->FileName) || (DirInfo->Attribute & EFI_FILE_DIRECTORY) != 0)) {\r
567 //\r
568 // Slip file unless it is a directory entry or a .EFI file\r
569 //\r
570 continue;\r
571 }\r
572\r
573 NewMenuEntry = BOpt_CreateMenuEntry (BM_FILE_CONTEXT_SELECT);\r
574 if (NULL == NewMenuEntry) {\r
575 return EFI_OUT_OF_RESOURCES;\r
576 }\r
577\r
578 NewFileContext = (BM_FILE_CONTEXT *) NewMenuEntry->VariableContext;\r
579 NewFileContext->Handle = FileContext->Handle;\r
580 NewFileContext->FileName = BOpt_AppendFileName (\r
581 FileContext->FileName,\r
582 DirInfo->FileName\r
583 );\r
584 NewFileContext->FHandle = NewDir;\r
585 NewFileContext->DevicePath = FileDevicePath (\r
586 NewFileContext->Handle,\r
587 NewFileContext->FileName\r
588 );\r
589 NewMenuEntry->HelpString = NULL;\r
590\r
591 MenuEntry->DisplayStringToken = GetStringTokenFromDepository (\r
592 CallbackData,\r
593 FileOptionStrDepository\r
594 );\r
595\r
596 NewFileContext->IsDir = (BOOLEAN) ((DirInfo->Attribute & EFI_FILE_DIRECTORY) == EFI_FILE_DIRECTORY);\r
597\r
598 if (NewFileContext->IsDir) {\r
599 BufferSize = StrLen (DirInfo->FileName) * 2 + 6;\r
600 NewMenuEntry->DisplayString = AllocateZeroPool (BufferSize);\r
601\r
602 UnicodeSPrint (\r
603 NewMenuEntry->DisplayString,\r
604 BufferSize,\r
605 L"<%s>",\r
606 DirInfo->FileName\r
607 );\r
608\r
609 } else {\r
610 NewMenuEntry->DisplayString = EfiStrDuplicate (DirInfo->FileName);\r
611 }\r
612\r
613 NewFileContext->IsRoot = FALSE;\r
614 NewFileContext->IsLoadFile = FALSE;\r
615 NewFileContext->IsRemovableMedia = FALSE;\r
616\r
617 NewMenuEntry->OptionNumber = OptionNumber;\r
618 OptionNumber++;\r
619 InsertTailList (&DirectoryMenu.Head, &NewMenuEntry->Link);\r
620 }\r
621 }\r
622\r
623 DirectoryMenu.MenuNumber = OptionNumber;\r
624 FreePool (DirInfo);\r
625 return EFI_SUCCESS;\r
626}\r
627\r
628/**\r
629\r
630 Build the BootOptionMenu according to BootOrder Variable.\r
631 This Routine will access the Boot#### to get EFI_LOAD_OPTION.\r
632\r
633 @param CallbackData The BMM context data.\r
634\r
635 @return EFI_NOT_FOUND Fail to find "BootOrder" variable.\r
636 @return EFI_SUCESS Success build boot option menu.\r
637\r
638**/\r
639EFI_STATUS\r
640BOpt_GetBootOptions (\r
641 IN BMM_CALLBACK_DATA *CallbackData\r
642 )\r
643{\r
644 UINTN Index;\r
645 UINT16 BootString[10];\r
646 UINT8 *LoadOptionFromVar;\r
647 UINT8 *LoadOption;\r
648 UINTN BootOptionSize;\r
649 BOOLEAN BootNextFlag;\r
650 UINT16 *BootOrderList;\r
651 UINTN BootOrderListSize;\r
652 UINT16 *BootNext;\r
653 UINTN BootNextSize;\r
654 BM_MENU_ENTRY *NewMenuEntry;\r
655 BM_LOAD_CONTEXT *NewLoadContext;\r
656 UINT8 *LoadOptionPtr;\r
657 UINTN StringSize;\r
658 UINTN OptionalDataSize;\r
659 UINT8 *LoadOptionEnd;\r
660 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
661 UINTN MenuCount;\r
662 UINT8 *Ptr;\r
663 EFI_BOOT_MANAGER_LOAD_OPTION *BootOption;\r
664 UINTN BootOptionCount; \r
665 \r
666 MenuCount = 0;\r
667 BootOrderListSize = 0;\r
668 BootNextSize = 0;\r
669 BootOrderList = NULL;\r
670 BootNext = NULL;\r
671 LoadOptionFromVar = NULL;\r
672 BOpt_FreeMenu (&BootOptionMenu);\r
673 InitializeListHead (&BootOptionMenu.Head);\r
674\r
675 //\r
676 // Get the BootOrder from the Var\r
677 //\r
678 GetEfiGlobalVariable2 (L"BootOrder", (VOID **) &BootOrderList, &BootOrderListSize);\r
679 if (BootOrderList == NULL) {\r
680 return EFI_NOT_FOUND;\r
681 }\r
682 \r
683 //\r
684 // Get the BootNext from the Var\r
685 //\r
686 GetEfiGlobalVariable2 (L"BootNext", (VOID **) &BootNext, &BootNextSize);\r
687 if (BootNext != NULL) {\r
688 if (BootNextSize != sizeof (UINT16)) {\r
689 FreePool (BootNext);\r
690 BootNext = NULL;\r
691 }\r
692 }\r
693 BootOption = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);\r
694 for (Index = 0; Index < BootOrderListSize / sizeof (UINT16); Index++) {\r
695 //\r
696 // Don't display the hidden/inactive boot option\r
697 //\r
698 if (((BootOption[Index].Attributes & LOAD_OPTION_HIDDEN) != 0) || ((BootOption[Index].Attributes & LOAD_OPTION_ACTIVE) == 0)) {\r
699 continue;\r
700 }\r
701 \r
702 UnicodeSPrint (BootString, sizeof (BootString), L"Boot%04x", BootOrderList[Index]);\r
703 //\r
704 // Get all loadoptions from the VAR\r
705 //\r
706 GetEfiGlobalVariable2 (BootString, (VOID **) &LoadOptionFromVar, &BootOptionSize);\r
707 if (LoadOptionFromVar == NULL) {\r
708 continue;\r
709 }\r
710\r
711 LoadOption = AllocateZeroPool (BootOptionSize);\r
712 if (LoadOption == NULL) {\r
713 continue;\r
714 }\r
715\r
716 CopyMem (LoadOption, LoadOptionFromVar, BootOptionSize);\r
717 FreePool (LoadOptionFromVar);\r
718\r
719 if (BootNext != NULL) {\r
720 BootNextFlag = (BOOLEAN) (*BootNext == BootOrderList[Index]);\r
721 } else {\r
722 BootNextFlag = FALSE;\r
723 }\r
724\r
725 NewMenuEntry = BOpt_CreateMenuEntry (BM_LOAD_CONTEXT_SELECT);\r
726 ASSERT (NULL != NewMenuEntry);\r
727\r
728 NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;\r
729\r
730 LoadOptionPtr = LoadOption;\r
731 LoadOptionEnd = LoadOption + BootOptionSize;\r
732\r
733 NewMenuEntry->OptionNumber = BootOrderList[Index];\r
734 NewLoadContext->LoadOptionModified = FALSE;\r
735 NewLoadContext->Deleted = FALSE;\r
736 NewLoadContext->IsBootNext = BootNextFlag;\r
737\r
738 //\r
739 // Is a Legacy Device?\r
740 //\r
741 Ptr = (UINT8 *) LoadOption;\r
742\r
743 //\r
744 // Attribute = *(UINT32 *)Ptr;\r
745 //\r
746 Ptr += sizeof (UINT32);\r
747\r
748 //\r
749 // FilePathSize = *(UINT16 *)Ptr;\r
750 //\r
751 Ptr += sizeof (UINT16);\r
752\r
753 //\r
754 // Description = (CHAR16 *)Ptr;\r
755 //\r
756 Ptr += StrSize ((CHAR16 *) Ptr);\r
757\r
758 //\r
759 // Now Ptr point to Device Path\r
760 //\r
761 DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) Ptr;\r
762 if ((BBS_DEVICE_PATH == DevicePath->Type) && (BBS_BBS_DP == DevicePath->SubType)) {\r
763 NewLoadContext->IsLegacy = TRUE;\r
764 } else {\r
765 NewLoadContext->IsLegacy = FALSE;\r
766 }\r
767 //\r
768 // LoadOption is a pointer type of UINT8\r
769 // for easy use with following LOAD_OPTION\r
770 // embedded in this struct\r
771 //\r
772 NewLoadContext->LoadOption = LoadOption;\r
773 NewLoadContext->LoadOptionSize = BootOptionSize;\r
774\r
775 NewLoadContext->Attributes = *(UINT32 *) LoadOptionPtr;\r
776 NewLoadContext->IsActive = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_ACTIVE);\r
777\r
778 NewLoadContext->ForceReconnect = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_FORCE_RECONNECT);\r
779\r
780 LoadOptionPtr += sizeof (UINT32);\r
781\r
782 NewLoadContext->FilePathListLength = *(UINT16 *) LoadOptionPtr;\r
783 LoadOptionPtr += sizeof (UINT16);\r
784 \r
785 StringSize = StrSize((UINT16*)LoadOptionPtr);\r
786\r
787 NewLoadContext->Description = AllocateZeroPool (StrSize((UINT16*)LoadOptionPtr));\r
788 ASSERT (NewLoadContext->Description != NULL);\r
d91cb870 789 StrCpyS (NewLoadContext->Description, StrSize((UINT16*)LoadOptionPtr) / sizeof (UINT16), (UINT16*)LoadOptionPtr);\r
143f0b1d
ED
790 \r
791 ASSERT (NewLoadContext->Description != NULL);\r
792 NewMenuEntry->DisplayString = NewLoadContext->Description;\r
793\r
794 LoadOptionPtr += StringSize;\r
795\r
796 NewLoadContext->FilePathList = AllocateZeroPool (NewLoadContext->FilePathListLength);\r
797 ASSERT (NewLoadContext->FilePathList != NULL);\r
798 CopyMem (\r
799 NewLoadContext->FilePathList,\r
800 (EFI_DEVICE_PATH_PROTOCOL *) LoadOptionPtr,\r
801 NewLoadContext->FilePathListLength\r
802 );\r
803\r
804 NewMenuEntry->HelpString = UiDevicePathToStr (NewLoadContext->FilePathList);\r
805 NewMenuEntry->DisplayStringToken = GetStringTokenFromDepository (\r
806 CallbackData,\r
807 BootOptionStrDepository\r
808 );\r
809 NewMenuEntry->HelpStringToken = GetStringTokenFromDepository (\r
810 CallbackData,\r
811 BootOptionHelpStrDepository\r
812 );\r
813 LoadOptionPtr += NewLoadContext->FilePathListLength;\r
814\r
815 if (LoadOptionPtr < LoadOptionEnd) {\r
816 OptionalDataSize = BootOptionSize -\r
817 sizeof (UINT32) -\r
818 sizeof (UINT16) -\r
819 StringSize -\r
820 NewLoadContext->FilePathListLength;\r
821\r
822 NewLoadContext->OptionalData = AllocateZeroPool (OptionalDataSize);\r
823 ASSERT (NewLoadContext->OptionalData != NULL);\r
824 CopyMem (\r
825 NewLoadContext->OptionalData,\r
826 LoadOptionPtr,\r
827 OptionalDataSize\r
828 );\r
829\r
830 NewLoadContext->OptionalDataSize = OptionalDataSize;\r
831 }\r
832\r
833 InsertTailList (&BootOptionMenu.Head, &NewMenuEntry->Link);\r
834 MenuCount++;\r
835 }\r
836 EfiBootManagerFreeLoadOptions (BootOption, BootOptionCount);\r
837\r
838 if (BootNext != NULL) {\r
839 FreePool (BootNext);\r
840 }\r
841 if (BootOrderList != NULL) {\r
842 FreePool (BootOrderList);\r
843 }\r
844 BootOptionMenu.MenuNumber = MenuCount;\r
845 return EFI_SUCCESS;\r
846}\r
847\r
848/**\r
849\r
850 Append file name to existing file name.\r
851\r
852 @param Str1 The existing file name\r
853 @param Str2 The file name to be appended\r
854\r
855 @return Allocate a new string to hold the appended result.\r
856 Caller is responsible to free the returned string.\r
857\r
858**/\r
859CHAR16 *\r
860BOpt_AppendFileName (\r
861 IN CHAR16 *Str1,\r
862 IN CHAR16 *Str2\r
863 )\r
864{\r
d91cb870 865 UINTN DestMax;\r
143f0b1d
ED
866 CHAR16 *Str;\r
867 CHAR16 *TmpStr;\r
868 CHAR16 *Ptr;\r
869 CHAR16 *LastSlash;\r
870\r
d91cb870
DB
871 DestMax = (StrSize (Str1) + StrSize (Str2) + sizeof (CHAR16)) / sizeof (CHAR16);\r
872 Str = AllocateZeroPool (DestMax * sizeof (CHAR16));\r
143f0b1d
ED
873 ASSERT (Str != NULL);\r
874\r
d91cb870 875 TmpStr = AllocateZeroPool (DestMax * sizeof (CHAR16)); \r
143f0b1d
ED
876 ASSERT (TmpStr != NULL);\r
877\r
d91cb870 878 StrCatS (Str, DestMax, Str1);\r
143f0b1d 879 if (!((*Str == '\\') && (*(Str + 1) == 0))) {\r
d91cb870 880 StrCatS (Str, DestMax, L"\\");\r
143f0b1d
ED
881 }\r
882\r
d91cb870 883 StrCatS (Str, DestMax, Str2);\r
143f0b1d
ED
884\r
885 Ptr = Str;\r
886 LastSlash = Str;\r
887 while (*Ptr != 0) {\r
888 if (*Ptr == '\\' && *(Ptr + 1) == '.' && *(Ptr + 2) == '.' && *(Ptr + 3) == L'\\') {\r
889 //\r
890 // Convert "\Name\..\" to "\"\r
891 // DO NOT convert the .. if it is at the end of the string. This will\r
892 // break the .. behavior in changing directories.\r
893 //\r
894\r
895 //\r
d91cb870 896 // Use TmpStr as a backup, as StrCpyS in BaseLib does not handle copy of two strings \r
143f0b1d
ED
897 // that overlap.\r
898 //\r
d91cb870
DB
899 StrCpyS (TmpStr, DestMax, Ptr + 3);\r
900 StrCpyS (LastSlash, DestMax - (UINTN) (LastSlash - Str), TmpStr);\r
143f0b1d
ED
901 Ptr = LastSlash;\r
902 } else if (*Ptr == '\\' && *(Ptr + 1) == '.' && *(Ptr + 2) == '\\') {\r
903 //\r
904 // Convert a "\.\" to a "\"\r
905 //\r
906\r
907 //\r
d91cb870 908 // Use TmpStr as a backup, as StrCpyS in BaseLib does not handle copy of two strings \r
143f0b1d
ED
909 // that overlap.\r
910 //\r
d91cb870
DB
911 StrCpyS (TmpStr, DestMax, Ptr + 2);\r
912 StrCpyS (Ptr, DestMax - (UINTN) (Ptr - Str), TmpStr);\r
143f0b1d
ED
913 Ptr = LastSlash;\r
914 } else if (*Ptr == '\\') {\r
915 LastSlash = Ptr;\r
916 }\r
917\r
918 Ptr++;\r
919 }\r
920\r
921 FreePool (TmpStr);\r
922 \r
923 return Str;\r
924}\r
925\r
926/**\r
927\r
928 Check whether current FileName point to a valid\r
929 Efi Image File.\r
930\r
931 @param FileName File need to be checked.\r
932\r
933 @retval TRUE Is Efi Image\r
934 @retval FALSE Not a valid Efi Image\r
935\r
936**/\r
937BOOLEAN\r
938BOpt_IsEfiImageName (\r
939 IN UINT16 *FileName\r
940 )\r
941{\r
942 //\r
943 // Search for ".efi" extension\r
944 //\r
945 while (*FileName != L'\0') {\r
946 if (FileName[0] == '.') {\r
947 if (FileName[1] == 'e' || FileName[1] == 'E') {\r
948 if (FileName[2] == 'f' || FileName[2] == 'F') {\r
949 if (FileName[3] == 'i' || FileName[3] == 'I') {\r
950 return TRUE;\r
951 } else if (FileName[3] == 0x0000) {\r
952 return FALSE;\r
953 }\r
954 } else if (FileName[2] == 0x0000) {\r
955 return FALSE;\r
956 }\r
957 } else if (FileName[1] == 0x0000) {\r
958 return FALSE;\r
959 }\r
960 }\r
961\r
962 FileName += 1;\r
963 }\r
964\r
965 return FALSE;\r
966}\r
967\r
968/**\r
969\r
970 Check whether current FileName point to a valid Efi Application\r
971\r
972 @param Dir Pointer to current Directory\r
973 @param FileName Pointer to current File name.\r
974\r
975 @retval TRUE Is a valid Efi Application\r
976 @retval FALSE not a valid Efi Application\r
977\r
978**/\r
979BOOLEAN\r
980BOpt_IsEfiApp (\r
981 IN EFI_FILE_HANDLE Dir,\r
982 IN UINT16 *FileName\r
983 )\r
984{\r
985 UINTN BufferSize;\r
986 EFI_IMAGE_DOS_HEADER DosHdr;\r
987 UINT16 Subsystem;\r
988 EFI_FILE_HANDLE File;\r
989 EFI_STATUS Status;\r
990 EFI_IMAGE_OPTIONAL_HEADER_UNION PeHdr;\r
991\r
992 Status = Dir->Open (Dir, &File, FileName, EFI_FILE_MODE_READ, 0);\r
993\r
994 if (EFI_ERROR (Status)) {\r
995 return FALSE;\r
996 }\r
997\r
998 BufferSize = sizeof (EFI_IMAGE_DOS_HEADER);\r
999 File->Read (File, &BufferSize, &DosHdr);\r
1000 if (DosHdr.e_magic != EFI_IMAGE_DOS_SIGNATURE) {\r
1001 File->Close (File);\r
1002 return FALSE;\r
1003 }\r
1004\r
1005 File->SetPosition (File, DosHdr.e_lfanew);\r
1006 BufferSize = sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION);\r
1007 File->Read (File, &BufferSize, &PeHdr);\r
1008 if (PeHdr.Pe32.Signature != EFI_IMAGE_NT_SIGNATURE) {\r
1009 File->Close (File);\r
1010 return FALSE;\r
1011 }\r
1012 //\r
1013 // Determine PE type and read subsytem\r
1014 //\r
1015 if (PeHdr.Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
1016 Subsystem = PeHdr.Pe32.OptionalHeader.Subsystem;\r
1017 } else if (PeHdr.Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {\r
1018 Subsystem = PeHdr.Pe32Plus.OptionalHeader.Subsystem;\r
1019 } else {\r
1020 return FALSE;\r
1021 }\r
1022\r
1023 if (Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) {\r
1024 File->Close (File);\r
1025 return TRUE;\r
1026 } else {\r
1027 File->Close (File);\r
1028 return FALSE;\r
1029 }\r
1030}\r
1031\r
1032/**\r
1033\r
1034 Find drivers that will be added as Driver#### variables from handles\r
1035 in current system environment\r
1036 All valid handles in the system except those consume SimpleFs, LoadFile\r
1037 are stored in DriverMenu for future use.\r
1038\r
1039 @retval EFI_SUCCESS The function complets successfully.\r
1040 @return Other value if failed to build the DriverMenu.\r
1041\r
1042**/\r
1043EFI_STATUS\r
1044BOpt_FindDrivers (\r
1045 VOID\r
1046 )\r
1047{\r
1048 UINTN NoDevicePathHandles;\r
1049 EFI_HANDLE *DevicePathHandle;\r
1050 UINTN Index;\r
1051 EFI_STATUS Status;\r
1052 BM_MENU_ENTRY *NewMenuEntry;\r
1053 BM_HANDLE_CONTEXT *NewHandleContext;\r
1054 EFI_HANDLE CurHandle;\r
1055 UINTN OptionNumber;\r
1056 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFs;\r
1057 EFI_LOAD_FILE_PROTOCOL *LoadFile;\r
1058\r
1059 SimpleFs = NULL;\r
1060 LoadFile = NULL;\r
1061\r
1062 InitializeListHead (&DriverMenu.Head);\r
1063\r
1064 //\r
1065 // At first, get all handles that support Device Path\r
1066 // protocol which is the basic requirement for\r
1067 // Driver####\r
1068 //\r
1069 Status = gBS->LocateHandleBuffer (\r
1070 ByProtocol,\r
1071 &gEfiDevicePathProtocolGuid,\r
1072 NULL,\r
1073 &NoDevicePathHandles,\r
1074 &DevicePathHandle\r
1075 );\r
1076 if (EFI_ERROR (Status)) {\r
1077 return Status;\r
1078 }\r
1079\r
1080 OptionNumber = 0;\r
1081 for (Index = 0; Index < NoDevicePathHandles; Index++) {\r
1082 CurHandle = DevicePathHandle[Index];\r
1083\r
1084 Status = gBS->HandleProtocol (\r
1085 CurHandle,\r
1086 &gEfiSimpleFileSystemProtocolGuid,\r
1087 (VOID **) &SimpleFs\r
1088 );\r
1089 if (Status == EFI_SUCCESS) {\r
1090 continue;\r
1091 }\r
1092\r
1093 Status = gBS->HandleProtocol (\r
1094 CurHandle,\r
1095 &gEfiLoadFileProtocolGuid,\r
1096 (VOID **) &LoadFile\r
1097 );\r
1098 if (Status == EFI_SUCCESS) {\r
1099 continue;\r
1100 }\r
1101\r
1102 NewMenuEntry = BOpt_CreateMenuEntry (BM_HANDLE_CONTEXT_SELECT);\r
1103 if (NULL == NewMenuEntry) {\r
1104 FreePool (DevicePathHandle);\r
1105 return EFI_OUT_OF_RESOURCES;\r
1106 }\r
1107\r
1108 NewHandleContext = (BM_HANDLE_CONTEXT *) NewMenuEntry->VariableContext;\r
1109 NewHandleContext->Handle = CurHandle;\r
1110 NewHandleContext->DevicePath = DevicePathFromHandle (CurHandle);\r
1111 NewMenuEntry->DisplayString = UiDevicePathToStr (NewHandleContext->DevicePath);\r
1112 NewMenuEntry->HelpString = NULL;\r
1113 NewMenuEntry->OptionNumber = OptionNumber;\r
1114 OptionNumber++;\r
1115 InsertTailList (&DriverMenu.Head, &NewMenuEntry->Link);\r
1116\r
1117 }\r
1118\r
1119 if (DevicePathHandle != NULL) {\r
1120 FreePool (DevicePathHandle);\r
1121 }\r
1122\r
1123 DriverMenu.MenuNumber = OptionNumber;\r
1124 return EFI_SUCCESS;\r
1125}\r
1126\r
1127/**\r
1128\r
1129 Get the Option Number that has not been allocated for use.\r
1130\r
1131 @param Type The type of Option.\r
1132\r
1133 @return The available Option Number.\r
1134\r
1135**/\r
1136UINT16\r
1137BOpt_GetOptionNumber (\r
1138 CHAR16 *Type\r
1139 )\r
1140{\r
1141 UINT16 *OrderList;\r
1142 UINTN OrderListSize;\r
1143 UINTN Index;\r
1144 CHAR16 StrTemp[20];\r
1145 UINT16 *OptionBuffer;\r
1146 UINT16 OptionNumber;\r
1147 UINTN OptionSize;\r
1148\r
1149 OrderListSize = 0;\r
1150 OrderList = NULL;\r
1151 OptionNumber = 0;\r
1152 Index = 0;\r
1153\r
1154 UnicodeSPrint (StrTemp, sizeof (StrTemp), L"%sOrder", Type);\r
1155\r
1156 GetEfiGlobalVariable2 (StrTemp, (VOID **) &OrderList, &OrderListSize);\r
1157 for (OptionNumber = 0; ; OptionNumber++) {\r
1158 if (OrderList != NULL) {\r
1159 for (Index = 0; Index < OrderListSize / sizeof (UINT16); Index++) {\r
1160 if (OptionNumber == OrderList[Index]) {\r
1161 break;\r
1162 }\r
1163 }\r
1164 }\r
1165\r
1166 if (Index < OrderListSize / sizeof (UINT16)) {\r
1167 //\r
1168 // The OptionNumber occurs in the OrderList, continue to use next one\r
1169 //\r
1170 continue;\r
1171 }\r
1172 UnicodeSPrint (StrTemp, sizeof (StrTemp), L"%s%04x", Type, (UINTN) OptionNumber);\r
1173 DEBUG((EFI_D_ERROR,"Option = %s\n", StrTemp));\r
1174 GetEfiGlobalVariable2 (StrTemp, (VOID **) &OptionBuffer, &OptionSize);\r
1175 if (NULL == OptionBuffer) {\r
1176 //\r
1177 // The Boot[OptionNumber] / Driver[OptionNumber] NOT occurs, we found it\r
1178 //\r
1179 break;\r
1180 }\r
1181 }\r
1182\r
1183 return OptionNumber;\r
1184}\r
1185\r
1186/**\r
1187\r
1188 Get the Option Number for Boot#### that does not used.\r
1189\r
1190 @return The available Option Number.\r
1191\r
1192**/\r
1193UINT16\r
1194BOpt_GetBootOptionNumber (\r
1195 VOID\r
1196 )\r
1197{\r
1198 return BOpt_GetOptionNumber (L"Boot");\r
1199}\r
1200\r
1201/**\r
1202\r
1203 Get the Option Number for Driver#### that does not used.\r
1204\r
1205 @return The unused Option Number.\r
1206\r
1207**/\r
1208UINT16\r
1209BOpt_GetDriverOptionNumber (\r
1210 VOID\r
1211 )\r
1212{\r
1213 return BOpt_GetOptionNumber (L"Driver");\r
1214}\r
1215\r
1216/**\r
1217\r
1218 Build up all DriverOptionMenu\r
1219\r
1220 @param CallbackData The BMM context data.\r
1221\r
1222 @retval EFI_SUCESS The functin completes successfully.\r
1223 @retval EFI_OUT_OF_RESOURCES Not enough memory to compete the operation.\r
1224 @retval EFI_NOT_FOUND Fail to get "DriverOrder" variable.\r
1225\r
1226**/\r
1227EFI_STATUS\r
1228BOpt_GetDriverOptions (\r
1229 IN BMM_CALLBACK_DATA *CallbackData\r
1230 )\r
1231{\r
1232 UINTN Index;\r
1233 UINT16 DriverString[12];\r
1234 UINT8 *LoadOptionFromVar;\r
1235 UINT8 *LoadOption;\r
1236 UINTN DriverOptionSize;\r
1237\r
1238 UINT16 *DriverOrderList;\r
1239 UINTN DriverOrderListSize;\r
1240 BM_MENU_ENTRY *NewMenuEntry;\r
1241 BM_LOAD_CONTEXT *NewLoadContext;\r
1242 UINT8 *LoadOptionPtr;\r
1243 UINTN StringSize;\r
1244 UINTN OptionalDataSize;\r
1245 UINT8 *LoadOptionEnd;\r
1246\r
1247 DriverOrderListSize = 0;\r
1248 DriverOrderList = NULL;\r
1249 DriverOptionSize = 0;\r
1250 LoadOptionFromVar = NULL;\r
1251 BOpt_FreeMenu (&DriverOptionMenu);\r
1252 InitializeListHead (&DriverOptionMenu.Head);\r
1253 //\r
1254 // Get the DriverOrder from the Var\r
1255 //\r
1256 GetEfiGlobalVariable2 (L"DriverOrder", (VOID **) &DriverOrderList, &DriverOrderListSize);\r
1257 if (DriverOrderList == NULL) {\r
1258 return EFI_NOT_FOUND;\r
1259 }\r
1260 \r
1261 for (Index = 0; Index < DriverOrderListSize / sizeof (UINT16); Index++) {\r
1262 UnicodeSPrint (\r
1263 DriverString,\r
1264 sizeof (DriverString),\r
1265 L"Driver%04x",\r
1266 DriverOrderList[Index]\r
1267 );\r
1268 //\r
1269 // Get all loadoptions from the VAR\r
1270 //\r
1271 GetEfiGlobalVariable2 (DriverString, (VOID **) &LoadOptionFromVar, &DriverOptionSize);\r
1272 if (LoadOptionFromVar == NULL) {\r
1273 continue;\r
1274 }\r
1275\r
1276 LoadOption = AllocateZeroPool (DriverOptionSize);\r
1277 if (LoadOption == NULL) {\r
1278 continue;\r
1279 }\r
1280\r
1281 CopyMem (LoadOption, LoadOptionFromVar, DriverOptionSize);\r
1282 FreePool (LoadOptionFromVar);\r
1283\r
1284 NewMenuEntry = BOpt_CreateMenuEntry (BM_LOAD_CONTEXT_SELECT);\r
1285 if (NULL == NewMenuEntry) {\r
1286 return EFI_OUT_OF_RESOURCES;\r
1287 }\r
1288\r
1289 NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;\r
1290 LoadOptionPtr = LoadOption;\r
1291 LoadOptionEnd = LoadOption + DriverOptionSize;\r
1292 NewMenuEntry->OptionNumber = DriverOrderList[Index];\r
1293 NewLoadContext->LoadOptionModified = FALSE;\r
1294 NewLoadContext->Deleted = FALSE;\r
1295 NewLoadContext->IsLegacy = FALSE;\r
1296\r
1297 //\r
1298 // LoadOption is a pointer type of UINT8\r
1299 // for easy use with following LOAD_OPTION\r
1300 // embedded in this struct\r
1301 //\r
1302 NewLoadContext->LoadOption = LoadOption;\r
1303 NewLoadContext->LoadOptionSize = DriverOptionSize;\r
1304\r
1305 NewLoadContext->Attributes = *(UINT32 *) LoadOptionPtr;\r
1306 NewLoadContext->IsActive = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_ACTIVE);\r
1307\r
1308 NewLoadContext->ForceReconnect = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_FORCE_RECONNECT);\r
1309\r
1310 LoadOptionPtr += sizeof (UINT32);\r
1311\r
1312 NewLoadContext->FilePathListLength = *(UINT16 *) LoadOptionPtr;\r
1313 LoadOptionPtr += sizeof (UINT16);\r
1314\r
1315 StringSize = StrSize ((UINT16 *) LoadOptionPtr);\r
1316 NewLoadContext->Description = AllocateZeroPool (StringSize);\r
1317 ASSERT (NewLoadContext->Description != NULL);\r
1318 CopyMem (\r
1319 NewLoadContext->Description,\r
1320 (UINT16 *) LoadOptionPtr,\r
1321 StringSize\r
1322 );\r
1323 NewMenuEntry->DisplayString = NewLoadContext->Description;\r
1324\r
1325 LoadOptionPtr += StringSize;\r
1326\r
1327 NewLoadContext->FilePathList = AllocateZeroPool (NewLoadContext->FilePathListLength);\r
1328 ASSERT (NewLoadContext->FilePathList != NULL);\r
1329 CopyMem (\r
1330 NewLoadContext->FilePathList,\r
1331 (EFI_DEVICE_PATH_PROTOCOL *) LoadOptionPtr,\r
1332 NewLoadContext->FilePathListLength\r
1333 );\r
1334\r
1335 NewMenuEntry->HelpString = UiDevicePathToStr (NewLoadContext->FilePathList);\r
1336 NewMenuEntry->DisplayStringToken = GetStringTokenFromDepository (\r
1337 CallbackData,\r
1338 DriverOptionStrDepository\r
1339 );\r
1340 NewMenuEntry->HelpStringToken = GetStringTokenFromDepository (\r
1341 CallbackData,\r
1342 DriverOptionHelpStrDepository\r
1343 );\r
1344 LoadOptionPtr += NewLoadContext->FilePathListLength;\r
1345\r
1346 if (LoadOptionPtr < LoadOptionEnd) {\r
1347 OptionalDataSize = DriverOptionSize -\r
1348 sizeof (UINT32) -\r
1349 sizeof (UINT16) -\r
1350 StringSize -\r
1351 NewLoadContext->FilePathListLength;\r
1352\r
1353 NewLoadContext->OptionalData = AllocateZeroPool (OptionalDataSize);\r
1354 ASSERT (NewLoadContext->OptionalData != NULL);\r
1355 CopyMem (\r
1356 NewLoadContext->OptionalData,\r
1357 LoadOptionPtr,\r
1358 OptionalDataSize\r
1359 );\r
1360\r
1361 NewLoadContext->OptionalDataSize = OptionalDataSize;\r
1362 }\r
1363\r
1364 InsertTailList (&DriverOptionMenu.Head, &NewMenuEntry->Link);\r
1365\r
1366 }\r
1367\r
1368 if (DriverOrderList != NULL) {\r
1369 FreePool (DriverOrderList);\r
1370 }\r
1371 DriverOptionMenu.MenuNumber = Index;\r
1372 return EFI_SUCCESS;\r
1373\r
1374}\r
1375\r
1376/**\r
1377 Get option number according to Boot#### and BootOrder variable. \r
1378 The value is saved as #### + 1.\r
1379\r
1380 @param CallbackData The BMM context data.\r
1381**/\r
1382VOID \r
1383GetBootOrder (\r
1384 IN BMM_CALLBACK_DATA *CallbackData\r
1385 )\r
1386{\r
1387 BMM_FAKE_NV_DATA *BmmConfig;\r
1388 UINT16 Index;\r
1389 UINT16 OptionOrderIndex; \r
1390 UINTN DeviceType;\r
1391 BM_MENU_ENTRY *NewMenuEntry;\r
1392 BM_LOAD_CONTEXT *NewLoadContext; \r
1393\r
1394 ASSERT (CallbackData != NULL);\r
1395 \r
1396 DeviceType = (UINTN) -1; \r
1397 BmmConfig = &CallbackData->BmmFakeNvData; \r
1398 ZeroMem (BmmConfig->BootOptionOrder, sizeof (BmmConfig->BootOptionOrder));\r
1399 \r
1400 for (Index = 0, OptionOrderIndex = 0; ((Index < BootOptionMenu.MenuNumber) &&\r
1401 (OptionOrderIndex < (sizeof (BmmConfig->BootOptionOrder) / sizeof (BmmConfig->BootOptionOrder[0]))));\r
1402 Index++) {\r
1403 NewMenuEntry = BOpt_GetMenuEntry (&BootOptionMenu, Index);\r
1404 NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;\r
1405\r
1406 if (NewLoadContext->IsLegacy) {\r
1407 if (((BBS_BBS_DEVICE_PATH *) NewLoadContext->FilePathList)->DeviceType != DeviceType) {\r
1408 DeviceType = ((BBS_BBS_DEVICE_PATH *) NewLoadContext->FilePathList)->DeviceType;\r
1409 } else {\r
1410 //\r
1411 // Only show one legacy boot option for the same device type\r
1412 // assuming the boot options are grouped by the device type\r
1413 //\r
1414 continue;\r
1415 }\r
1416 }\r
1417 BmmConfig->BootOptionOrder[OptionOrderIndex++] = (UINT32) (NewMenuEntry->OptionNumber + 1);\r
1418 } \r
1419}\r
1420\r
1421/**\r
1422 Get driver option order from globalc DriverOptionMenu.\r
1423\r
1424 @param CallbackData The BMM context data.\r
1425 \r
1426**/\r
1427VOID \r
1428GetDriverOrder (\r
1429 IN BMM_CALLBACK_DATA *CallbackData\r
1430 )\r
1431{\r
1432 BMM_FAKE_NV_DATA *BmmConfig;\r
1433 UINT16 Index;\r
1434 UINT16 OptionOrderIndex; \r
1435 UINTN DeviceType;\r
1436 BM_MENU_ENTRY *NewMenuEntry;\r
1437 BM_LOAD_CONTEXT *NewLoadContext; \r
1438\r
1439\r
1440 ASSERT (CallbackData != NULL);\r
1441 \r
1442 DeviceType = (UINTN) -1; \r
1443 BmmConfig = &CallbackData->BmmFakeNvData; \r
1444 ZeroMem (BmmConfig->DriverOptionOrder, sizeof (BmmConfig->DriverOptionOrder));\r
1445 \r
1446 for (Index = 0, OptionOrderIndex = 0; ((Index < DriverOptionMenu.MenuNumber) &&\r
1447 (OptionOrderIndex < (sizeof (BmmConfig->DriverOptionOrder) / sizeof (BmmConfig->DriverOptionOrder[0]))));\r
1448 Index++) {\r
1449 NewMenuEntry = BOpt_GetMenuEntry (&DriverOptionMenu, Index);\r
1450 NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;\r
1451\r
1452 if (NewLoadContext->IsLegacy) {\r
1453 if (((BBS_BBS_DEVICE_PATH *) NewLoadContext->FilePathList)->DeviceType != DeviceType) {\r
1454 DeviceType = ((BBS_BBS_DEVICE_PATH *) NewLoadContext->FilePathList)->DeviceType;\r
1455 } else {\r
1456 //\r
1457 // Only show one legacy boot option for the same device type\r
1458 // assuming the boot options are grouped by the device type\r
1459 //\r
1460 continue;\r
1461 }\r
1462 }\r
1463 BmmConfig->DriverOptionOrder[OptionOrderIndex++] = (UINT32) (NewMenuEntry->OptionNumber + 1);\r
1464 } \r
1465} \r
1466 \r
1467\r