]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Application/UiApp/BootMaint/BootOption.c
UiApp: Update copyright info, cover old code existed in old BdsDxe driver.
[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
789 StrCpy (NewLoadContext->Description, (UINT16*)LoadOptionPtr);\r
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
865 UINTN Size1;\r
866 UINTN Size2;\r
867 CHAR16 *Str;\r
868 CHAR16 *TmpStr;\r
869 CHAR16 *Ptr;\r
870 CHAR16 *LastSlash;\r
871\r
872 Size1 = StrSize (Str1);\r
873 Size2 = StrSize (Str2);\r
874 Str = AllocateZeroPool (Size1 + Size2 + sizeof (CHAR16));\r
875 ASSERT (Str != NULL);\r
876\r
877 TmpStr = AllocateZeroPool (Size1 + Size2 + sizeof (CHAR16)); \r
878 ASSERT (TmpStr != NULL);\r
879\r
880 StrCat (Str, Str1);\r
881 if (!((*Str == '\\') && (*(Str + 1) == 0))) {\r
882 StrCat (Str, L"\\");\r
883 }\r
884\r
885 StrCat (Str, Str2);\r
886\r
887 Ptr = Str;\r
888 LastSlash = Str;\r
889 while (*Ptr != 0) {\r
890 if (*Ptr == '\\' && *(Ptr + 1) == '.' && *(Ptr + 2) == '.' && *(Ptr + 3) == L'\\') {\r
891 //\r
892 // Convert "\Name\..\" to "\"\r
893 // DO NOT convert the .. if it is at the end of the string. This will\r
894 // break the .. behavior in changing directories.\r
895 //\r
896\r
897 //\r
898 // Use TmpStr as a backup, as StrCpy in BaseLib does not handle copy of two strings \r
899 // that overlap.\r
900 //\r
901 StrCpy (TmpStr, Ptr + 3);\r
902 StrCpy (LastSlash, TmpStr);\r
903 Ptr = LastSlash;\r
904 } else if (*Ptr == '\\' && *(Ptr + 1) == '.' && *(Ptr + 2) == '\\') {\r
905 //\r
906 // Convert a "\.\" to a "\"\r
907 //\r
908\r
909 //\r
910 // Use TmpStr as a backup, as StrCpy in BaseLib does not handle copy of two strings \r
911 // that overlap.\r
912 //\r
913 StrCpy (TmpStr, Ptr + 2);\r
914 StrCpy (Ptr, TmpStr);\r
915 Ptr = LastSlash;\r
916 } else if (*Ptr == '\\') {\r
917 LastSlash = Ptr;\r
918 }\r
919\r
920 Ptr++;\r
921 }\r
922\r
923 FreePool (TmpStr);\r
924 \r
925 return Str;\r
926}\r
927\r
928/**\r
929\r
930 Check whether current FileName point to a valid\r
931 Efi Image File.\r
932\r
933 @param FileName File need to be checked.\r
934\r
935 @retval TRUE Is Efi Image\r
936 @retval FALSE Not a valid Efi Image\r
937\r
938**/\r
939BOOLEAN\r
940BOpt_IsEfiImageName (\r
941 IN UINT16 *FileName\r
942 )\r
943{\r
944 //\r
945 // Search for ".efi" extension\r
946 //\r
947 while (*FileName != L'\0') {\r
948 if (FileName[0] == '.') {\r
949 if (FileName[1] == 'e' || FileName[1] == 'E') {\r
950 if (FileName[2] == 'f' || FileName[2] == 'F') {\r
951 if (FileName[3] == 'i' || FileName[3] == 'I') {\r
952 return TRUE;\r
953 } else if (FileName[3] == 0x0000) {\r
954 return FALSE;\r
955 }\r
956 } else if (FileName[2] == 0x0000) {\r
957 return FALSE;\r
958 }\r
959 } else if (FileName[1] == 0x0000) {\r
960 return FALSE;\r
961 }\r
962 }\r
963\r
964 FileName += 1;\r
965 }\r
966\r
967 return FALSE;\r
968}\r
969\r
970/**\r
971\r
972 Check whether current FileName point to a valid Efi Application\r
973\r
974 @param Dir Pointer to current Directory\r
975 @param FileName Pointer to current File name.\r
976\r
977 @retval TRUE Is a valid Efi Application\r
978 @retval FALSE not a valid Efi Application\r
979\r
980**/\r
981BOOLEAN\r
982BOpt_IsEfiApp (\r
983 IN EFI_FILE_HANDLE Dir,\r
984 IN UINT16 *FileName\r
985 )\r
986{\r
987 UINTN BufferSize;\r
988 EFI_IMAGE_DOS_HEADER DosHdr;\r
989 UINT16 Subsystem;\r
990 EFI_FILE_HANDLE File;\r
991 EFI_STATUS Status;\r
992 EFI_IMAGE_OPTIONAL_HEADER_UNION PeHdr;\r
993\r
994 Status = Dir->Open (Dir, &File, FileName, EFI_FILE_MODE_READ, 0);\r
995\r
996 if (EFI_ERROR (Status)) {\r
997 return FALSE;\r
998 }\r
999\r
1000 BufferSize = sizeof (EFI_IMAGE_DOS_HEADER);\r
1001 File->Read (File, &BufferSize, &DosHdr);\r
1002 if (DosHdr.e_magic != EFI_IMAGE_DOS_SIGNATURE) {\r
1003 File->Close (File);\r
1004 return FALSE;\r
1005 }\r
1006\r
1007 File->SetPosition (File, DosHdr.e_lfanew);\r
1008 BufferSize = sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION);\r
1009 File->Read (File, &BufferSize, &PeHdr);\r
1010 if (PeHdr.Pe32.Signature != EFI_IMAGE_NT_SIGNATURE) {\r
1011 File->Close (File);\r
1012 return FALSE;\r
1013 }\r
1014 //\r
1015 // Determine PE type and read subsytem\r
1016 //\r
1017 if (PeHdr.Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
1018 Subsystem = PeHdr.Pe32.OptionalHeader.Subsystem;\r
1019 } else if (PeHdr.Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {\r
1020 Subsystem = PeHdr.Pe32Plus.OptionalHeader.Subsystem;\r
1021 } else {\r
1022 return FALSE;\r
1023 }\r
1024\r
1025 if (Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) {\r
1026 File->Close (File);\r
1027 return TRUE;\r
1028 } else {\r
1029 File->Close (File);\r
1030 return FALSE;\r
1031 }\r
1032}\r
1033\r
1034/**\r
1035\r
1036 Find drivers that will be added as Driver#### variables from handles\r
1037 in current system environment\r
1038 All valid handles in the system except those consume SimpleFs, LoadFile\r
1039 are stored in DriverMenu for future use.\r
1040\r
1041 @retval EFI_SUCCESS The function complets successfully.\r
1042 @return Other value if failed to build the DriverMenu.\r
1043\r
1044**/\r
1045EFI_STATUS\r
1046BOpt_FindDrivers (\r
1047 VOID\r
1048 )\r
1049{\r
1050 UINTN NoDevicePathHandles;\r
1051 EFI_HANDLE *DevicePathHandle;\r
1052 UINTN Index;\r
1053 EFI_STATUS Status;\r
1054 BM_MENU_ENTRY *NewMenuEntry;\r
1055 BM_HANDLE_CONTEXT *NewHandleContext;\r
1056 EFI_HANDLE CurHandle;\r
1057 UINTN OptionNumber;\r
1058 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFs;\r
1059 EFI_LOAD_FILE_PROTOCOL *LoadFile;\r
1060\r
1061 SimpleFs = NULL;\r
1062 LoadFile = NULL;\r
1063\r
1064 InitializeListHead (&DriverMenu.Head);\r
1065\r
1066 //\r
1067 // At first, get all handles that support Device Path\r
1068 // protocol which is the basic requirement for\r
1069 // Driver####\r
1070 //\r
1071 Status = gBS->LocateHandleBuffer (\r
1072 ByProtocol,\r
1073 &gEfiDevicePathProtocolGuid,\r
1074 NULL,\r
1075 &NoDevicePathHandles,\r
1076 &DevicePathHandle\r
1077 );\r
1078 if (EFI_ERROR (Status)) {\r
1079 return Status;\r
1080 }\r
1081\r
1082 OptionNumber = 0;\r
1083 for (Index = 0; Index < NoDevicePathHandles; Index++) {\r
1084 CurHandle = DevicePathHandle[Index];\r
1085\r
1086 Status = gBS->HandleProtocol (\r
1087 CurHandle,\r
1088 &gEfiSimpleFileSystemProtocolGuid,\r
1089 (VOID **) &SimpleFs\r
1090 );\r
1091 if (Status == EFI_SUCCESS) {\r
1092 continue;\r
1093 }\r
1094\r
1095 Status = gBS->HandleProtocol (\r
1096 CurHandle,\r
1097 &gEfiLoadFileProtocolGuid,\r
1098 (VOID **) &LoadFile\r
1099 );\r
1100 if (Status == EFI_SUCCESS) {\r
1101 continue;\r
1102 }\r
1103\r
1104 NewMenuEntry = BOpt_CreateMenuEntry (BM_HANDLE_CONTEXT_SELECT);\r
1105 if (NULL == NewMenuEntry) {\r
1106 FreePool (DevicePathHandle);\r
1107 return EFI_OUT_OF_RESOURCES;\r
1108 }\r
1109\r
1110 NewHandleContext = (BM_HANDLE_CONTEXT *) NewMenuEntry->VariableContext;\r
1111 NewHandleContext->Handle = CurHandle;\r
1112 NewHandleContext->DevicePath = DevicePathFromHandle (CurHandle);\r
1113 NewMenuEntry->DisplayString = UiDevicePathToStr (NewHandleContext->DevicePath);\r
1114 NewMenuEntry->HelpString = NULL;\r
1115 NewMenuEntry->OptionNumber = OptionNumber;\r
1116 OptionNumber++;\r
1117 InsertTailList (&DriverMenu.Head, &NewMenuEntry->Link);\r
1118\r
1119 }\r
1120\r
1121 if (DevicePathHandle != NULL) {\r
1122 FreePool (DevicePathHandle);\r
1123 }\r
1124\r
1125 DriverMenu.MenuNumber = OptionNumber;\r
1126 return EFI_SUCCESS;\r
1127}\r
1128\r
1129/**\r
1130\r
1131 Get the Option Number that has not been allocated for use.\r
1132\r
1133 @param Type The type of Option.\r
1134\r
1135 @return The available Option Number.\r
1136\r
1137**/\r
1138UINT16\r
1139BOpt_GetOptionNumber (\r
1140 CHAR16 *Type\r
1141 )\r
1142{\r
1143 UINT16 *OrderList;\r
1144 UINTN OrderListSize;\r
1145 UINTN Index;\r
1146 CHAR16 StrTemp[20];\r
1147 UINT16 *OptionBuffer;\r
1148 UINT16 OptionNumber;\r
1149 UINTN OptionSize;\r
1150\r
1151 OrderListSize = 0;\r
1152 OrderList = NULL;\r
1153 OptionNumber = 0;\r
1154 Index = 0;\r
1155\r
1156 UnicodeSPrint (StrTemp, sizeof (StrTemp), L"%sOrder", Type);\r
1157\r
1158 GetEfiGlobalVariable2 (StrTemp, (VOID **) &OrderList, &OrderListSize);\r
1159 for (OptionNumber = 0; ; OptionNumber++) {\r
1160 if (OrderList != NULL) {\r
1161 for (Index = 0; Index < OrderListSize / sizeof (UINT16); Index++) {\r
1162 if (OptionNumber == OrderList[Index]) {\r
1163 break;\r
1164 }\r
1165 }\r
1166 }\r
1167\r
1168 if (Index < OrderListSize / sizeof (UINT16)) {\r
1169 //\r
1170 // The OptionNumber occurs in the OrderList, continue to use next one\r
1171 //\r
1172 continue;\r
1173 }\r
1174 UnicodeSPrint (StrTemp, sizeof (StrTemp), L"%s%04x", Type, (UINTN) OptionNumber);\r
1175 DEBUG((EFI_D_ERROR,"Option = %s\n", StrTemp));\r
1176 GetEfiGlobalVariable2 (StrTemp, (VOID **) &OptionBuffer, &OptionSize);\r
1177 if (NULL == OptionBuffer) {\r
1178 //\r
1179 // The Boot[OptionNumber] / Driver[OptionNumber] NOT occurs, we found it\r
1180 //\r
1181 break;\r
1182 }\r
1183 }\r
1184\r
1185 return OptionNumber;\r
1186}\r
1187\r
1188/**\r
1189\r
1190 Get the Option Number for Boot#### that does not used.\r
1191\r
1192 @return The available Option Number.\r
1193\r
1194**/\r
1195UINT16\r
1196BOpt_GetBootOptionNumber (\r
1197 VOID\r
1198 )\r
1199{\r
1200 return BOpt_GetOptionNumber (L"Boot");\r
1201}\r
1202\r
1203/**\r
1204\r
1205 Get the Option Number for Driver#### that does not used.\r
1206\r
1207 @return The unused Option Number.\r
1208\r
1209**/\r
1210UINT16\r
1211BOpt_GetDriverOptionNumber (\r
1212 VOID\r
1213 )\r
1214{\r
1215 return BOpt_GetOptionNumber (L"Driver");\r
1216}\r
1217\r
1218/**\r
1219\r
1220 Build up all DriverOptionMenu\r
1221\r
1222 @param CallbackData The BMM context data.\r
1223\r
1224 @retval EFI_SUCESS The functin completes successfully.\r
1225 @retval EFI_OUT_OF_RESOURCES Not enough memory to compete the operation.\r
1226 @retval EFI_NOT_FOUND Fail to get "DriverOrder" variable.\r
1227\r
1228**/\r
1229EFI_STATUS\r
1230BOpt_GetDriverOptions (\r
1231 IN BMM_CALLBACK_DATA *CallbackData\r
1232 )\r
1233{\r
1234 UINTN Index;\r
1235 UINT16 DriverString[12];\r
1236 UINT8 *LoadOptionFromVar;\r
1237 UINT8 *LoadOption;\r
1238 UINTN DriverOptionSize;\r
1239\r
1240 UINT16 *DriverOrderList;\r
1241 UINTN DriverOrderListSize;\r
1242 BM_MENU_ENTRY *NewMenuEntry;\r
1243 BM_LOAD_CONTEXT *NewLoadContext;\r
1244 UINT8 *LoadOptionPtr;\r
1245 UINTN StringSize;\r
1246 UINTN OptionalDataSize;\r
1247 UINT8 *LoadOptionEnd;\r
1248\r
1249 DriverOrderListSize = 0;\r
1250 DriverOrderList = NULL;\r
1251 DriverOptionSize = 0;\r
1252 LoadOptionFromVar = NULL;\r
1253 BOpt_FreeMenu (&DriverOptionMenu);\r
1254 InitializeListHead (&DriverOptionMenu.Head);\r
1255 //\r
1256 // Get the DriverOrder from the Var\r
1257 //\r
1258 GetEfiGlobalVariable2 (L"DriverOrder", (VOID **) &DriverOrderList, &DriverOrderListSize);\r
1259 if (DriverOrderList == NULL) {\r
1260 return EFI_NOT_FOUND;\r
1261 }\r
1262 \r
1263 for (Index = 0; Index < DriverOrderListSize / sizeof (UINT16); Index++) {\r
1264 UnicodeSPrint (\r
1265 DriverString,\r
1266 sizeof (DriverString),\r
1267 L"Driver%04x",\r
1268 DriverOrderList[Index]\r
1269 );\r
1270 //\r
1271 // Get all loadoptions from the VAR\r
1272 //\r
1273 GetEfiGlobalVariable2 (DriverString, (VOID **) &LoadOptionFromVar, &DriverOptionSize);\r
1274 if (LoadOptionFromVar == NULL) {\r
1275 continue;\r
1276 }\r
1277\r
1278 LoadOption = AllocateZeroPool (DriverOptionSize);\r
1279 if (LoadOption == NULL) {\r
1280 continue;\r
1281 }\r
1282\r
1283 CopyMem (LoadOption, LoadOptionFromVar, DriverOptionSize);\r
1284 FreePool (LoadOptionFromVar);\r
1285\r
1286 NewMenuEntry = BOpt_CreateMenuEntry (BM_LOAD_CONTEXT_SELECT);\r
1287 if (NULL == NewMenuEntry) {\r
1288 return EFI_OUT_OF_RESOURCES;\r
1289 }\r
1290\r
1291 NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;\r
1292 LoadOptionPtr = LoadOption;\r
1293 LoadOptionEnd = LoadOption + DriverOptionSize;\r
1294 NewMenuEntry->OptionNumber = DriverOrderList[Index];\r
1295 NewLoadContext->LoadOptionModified = FALSE;\r
1296 NewLoadContext->Deleted = FALSE;\r
1297 NewLoadContext->IsLegacy = FALSE;\r
1298\r
1299 //\r
1300 // LoadOption is a pointer type of UINT8\r
1301 // for easy use with following LOAD_OPTION\r
1302 // embedded in this struct\r
1303 //\r
1304 NewLoadContext->LoadOption = LoadOption;\r
1305 NewLoadContext->LoadOptionSize = DriverOptionSize;\r
1306\r
1307 NewLoadContext->Attributes = *(UINT32 *) LoadOptionPtr;\r
1308 NewLoadContext->IsActive = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_ACTIVE);\r
1309\r
1310 NewLoadContext->ForceReconnect = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_FORCE_RECONNECT);\r
1311\r
1312 LoadOptionPtr += sizeof (UINT32);\r
1313\r
1314 NewLoadContext->FilePathListLength = *(UINT16 *) LoadOptionPtr;\r
1315 LoadOptionPtr += sizeof (UINT16);\r
1316\r
1317 StringSize = StrSize ((UINT16 *) LoadOptionPtr);\r
1318 NewLoadContext->Description = AllocateZeroPool (StringSize);\r
1319 ASSERT (NewLoadContext->Description != NULL);\r
1320 CopyMem (\r
1321 NewLoadContext->Description,\r
1322 (UINT16 *) LoadOptionPtr,\r
1323 StringSize\r
1324 );\r
1325 NewMenuEntry->DisplayString = NewLoadContext->Description;\r
1326\r
1327 LoadOptionPtr += StringSize;\r
1328\r
1329 NewLoadContext->FilePathList = AllocateZeroPool (NewLoadContext->FilePathListLength);\r
1330 ASSERT (NewLoadContext->FilePathList != NULL);\r
1331 CopyMem (\r
1332 NewLoadContext->FilePathList,\r
1333 (EFI_DEVICE_PATH_PROTOCOL *) LoadOptionPtr,\r
1334 NewLoadContext->FilePathListLength\r
1335 );\r
1336\r
1337 NewMenuEntry->HelpString = UiDevicePathToStr (NewLoadContext->FilePathList);\r
1338 NewMenuEntry->DisplayStringToken = GetStringTokenFromDepository (\r
1339 CallbackData,\r
1340 DriverOptionStrDepository\r
1341 );\r
1342 NewMenuEntry->HelpStringToken = GetStringTokenFromDepository (\r
1343 CallbackData,\r
1344 DriverOptionHelpStrDepository\r
1345 );\r
1346 LoadOptionPtr += NewLoadContext->FilePathListLength;\r
1347\r
1348 if (LoadOptionPtr < LoadOptionEnd) {\r
1349 OptionalDataSize = DriverOptionSize -\r
1350 sizeof (UINT32) -\r
1351 sizeof (UINT16) -\r
1352 StringSize -\r
1353 NewLoadContext->FilePathListLength;\r
1354\r
1355 NewLoadContext->OptionalData = AllocateZeroPool (OptionalDataSize);\r
1356 ASSERT (NewLoadContext->OptionalData != NULL);\r
1357 CopyMem (\r
1358 NewLoadContext->OptionalData,\r
1359 LoadOptionPtr,\r
1360 OptionalDataSize\r
1361 );\r
1362\r
1363 NewLoadContext->OptionalDataSize = OptionalDataSize;\r
1364 }\r
1365\r
1366 InsertTailList (&DriverOptionMenu.Head, &NewMenuEntry->Link);\r
1367\r
1368 }\r
1369\r
1370 if (DriverOrderList != NULL) {\r
1371 FreePool (DriverOrderList);\r
1372 }\r
1373 DriverOptionMenu.MenuNumber = Index;\r
1374 return EFI_SUCCESS;\r
1375\r
1376}\r
1377\r
1378/**\r
1379 Get option number according to Boot#### and BootOrder variable. \r
1380 The value is saved as #### + 1.\r
1381\r
1382 @param CallbackData The BMM context data.\r
1383**/\r
1384VOID \r
1385GetBootOrder (\r
1386 IN BMM_CALLBACK_DATA *CallbackData\r
1387 )\r
1388{\r
1389 BMM_FAKE_NV_DATA *BmmConfig;\r
1390 UINT16 Index;\r
1391 UINT16 OptionOrderIndex; \r
1392 UINTN DeviceType;\r
1393 BM_MENU_ENTRY *NewMenuEntry;\r
1394 BM_LOAD_CONTEXT *NewLoadContext; \r
1395\r
1396 ASSERT (CallbackData != NULL);\r
1397 \r
1398 DeviceType = (UINTN) -1; \r
1399 BmmConfig = &CallbackData->BmmFakeNvData; \r
1400 ZeroMem (BmmConfig->BootOptionOrder, sizeof (BmmConfig->BootOptionOrder));\r
1401 \r
1402 for (Index = 0, OptionOrderIndex = 0; ((Index < BootOptionMenu.MenuNumber) &&\r
1403 (OptionOrderIndex < (sizeof (BmmConfig->BootOptionOrder) / sizeof (BmmConfig->BootOptionOrder[0]))));\r
1404 Index++) {\r
1405 NewMenuEntry = BOpt_GetMenuEntry (&BootOptionMenu, Index);\r
1406 NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;\r
1407\r
1408 if (NewLoadContext->IsLegacy) {\r
1409 if (((BBS_BBS_DEVICE_PATH *) NewLoadContext->FilePathList)->DeviceType != DeviceType) {\r
1410 DeviceType = ((BBS_BBS_DEVICE_PATH *) NewLoadContext->FilePathList)->DeviceType;\r
1411 } else {\r
1412 //\r
1413 // Only show one legacy boot option for the same device type\r
1414 // assuming the boot options are grouped by the device type\r
1415 //\r
1416 continue;\r
1417 }\r
1418 }\r
1419 BmmConfig->BootOptionOrder[OptionOrderIndex++] = (UINT32) (NewMenuEntry->OptionNumber + 1);\r
1420 } \r
1421}\r
1422\r
1423/**\r
1424 Get driver option order from globalc DriverOptionMenu.\r
1425\r
1426 @param CallbackData The BMM context data.\r
1427 \r
1428**/\r
1429VOID \r
1430GetDriverOrder (\r
1431 IN BMM_CALLBACK_DATA *CallbackData\r
1432 )\r
1433{\r
1434 BMM_FAKE_NV_DATA *BmmConfig;\r
1435 UINT16 Index;\r
1436 UINT16 OptionOrderIndex; \r
1437 UINTN DeviceType;\r
1438 BM_MENU_ENTRY *NewMenuEntry;\r
1439 BM_LOAD_CONTEXT *NewLoadContext; \r
1440\r
1441\r
1442 ASSERT (CallbackData != NULL);\r
1443 \r
1444 DeviceType = (UINTN) -1; \r
1445 BmmConfig = &CallbackData->BmmFakeNvData; \r
1446 ZeroMem (BmmConfig->DriverOptionOrder, sizeof (BmmConfig->DriverOptionOrder));\r
1447 \r
1448 for (Index = 0, OptionOrderIndex = 0; ((Index < DriverOptionMenu.MenuNumber) &&\r
1449 (OptionOrderIndex < (sizeof (BmmConfig->DriverOptionOrder) / sizeof (BmmConfig->DriverOptionOrder[0]))));\r
1450 Index++) {\r
1451 NewMenuEntry = BOpt_GetMenuEntry (&DriverOptionMenu, Index);\r
1452 NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;\r
1453\r
1454 if (NewLoadContext->IsLegacy) {\r
1455 if (((BBS_BBS_DEVICE_PATH *) NewLoadContext->FilePathList)->DeviceType != DeviceType) {\r
1456 DeviceType = ((BBS_BBS_DEVICE_PATH *) NewLoadContext->FilePathList)->DeviceType;\r
1457 } else {\r
1458 //\r
1459 // Only show one legacy boot option for the same device type\r
1460 // assuming the boot options are grouped by the device type\r
1461 //\r
1462 continue;\r
1463 }\r
1464 }\r
1465 BmmConfig->DriverOptionOrder[OptionOrderIndex++] = (UINT32) (NewMenuEntry->OptionNumber + 1);\r
1466 } \r
1467} \r
1468 \r
1469\r