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