]> git.proxmox.com Git - mirror_edk2.git/blob - IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/BootOption.c
1519315d40007403bb9ea9bf2f06f2781d4b773c
[mirror_edk2.git] / IntelFrameworkModulePkg / Universal / BdsDxe / BootMaint / BootOption.c
1 /** @file
2 Provide boot option support for Application "BootMaint"
3
4 Include file system navigation, system handle selection
5
6 Boot option manipulation
7
8 Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR>
9 This program and the accompanying materials
10 are licensed and made available under the terms and conditions of the BSD License
11 which accompanies this distribution. The full text of the license may be found at
12 http://opensource.org/licenses/bsd-license.php
13
14 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
15 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16
17 **/
18
19 #include "BootMaint.h"
20 #include "BBSsupport.h"
21
22 /**
23 Create a menu entry by given menu type.
24
25 @param MenuType The Menu type to be created.
26
27 @retval NULL If failed to create the menu.
28 @return the new menu entry.
29
30 **/
31 BM_MENU_ENTRY *
32 BOpt_CreateMenuEntry (
33 UINTN MenuType
34 )
35 {
36 BM_MENU_ENTRY *MenuEntry;
37 UINTN ContextSize;
38
39 //
40 // Get context size according to menu type
41 //
42 switch (MenuType) {
43 case BM_LOAD_CONTEXT_SELECT:
44 ContextSize = sizeof (BM_LOAD_CONTEXT);
45 break;
46
47 case BM_FILE_CONTEXT_SELECT:
48 ContextSize = sizeof (BM_FILE_CONTEXT);
49 break;
50
51 case BM_CONSOLE_CONTEXT_SELECT:
52 ContextSize = sizeof (BM_CONSOLE_CONTEXT);
53 break;
54
55 case BM_TERMINAL_CONTEXT_SELECT:
56 ContextSize = sizeof (BM_TERMINAL_CONTEXT);
57 break;
58
59 case BM_HANDLE_CONTEXT_SELECT:
60 ContextSize = sizeof (BM_HANDLE_CONTEXT);
61 break;
62
63 case BM_LEGACY_DEV_CONTEXT_SELECT:
64 ContextSize = sizeof (BM_LEGACY_DEVICE_CONTEXT);
65 break;
66
67 default:
68 ContextSize = 0;
69 break;
70 }
71
72 if (ContextSize == 0) {
73 return NULL;
74 }
75
76 //
77 // Create new menu entry
78 //
79 MenuEntry = AllocateZeroPool (sizeof (BM_MENU_ENTRY));
80 if (MenuEntry == NULL) {
81 return NULL;
82 }
83
84 MenuEntry->VariableContext = AllocateZeroPool (ContextSize);
85 if (MenuEntry->VariableContext == NULL) {
86 FreePool (MenuEntry);
87 return NULL;
88 }
89
90 MenuEntry->Signature = BM_MENU_ENTRY_SIGNATURE;
91 MenuEntry->ContextSelection = MenuType;
92 return MenuEntry;
93 }
94
95 /**
96 Free up all resource allocated for a BM_MENU_ENTRY.
97
98 @param MenuEntry A pointer to BM_MENU_ENTRY.
99
100 **/
101 VOID
102 BOpt_DestroyMenuEntry (
103 BM_MENU_ENTRY *MenuEntry
104 )
105 {
106 BM_LOAD_CONTEXT *LoadContext;
107 BM_FILE_CONTEXT *FileContext;
108 BM_CONSOLE_CONTEXT *ConsoleContext;
109 BM_TERMINAL_CONTEXT *TerminalContext;
110 BM_HANDLE_CONTEXT *HandleContext;
111 BM_LEGACY_DEVICE_CONTEXT *LegacyDevContext;
112
113 //
114 // Select by the type in Menu entry for current context type
115 //
116 switch (MenuEntry->ContextSelection) {
117 case BM_LOAD_CONTEXT_SELECT:
118 LoadContext = (BM_LOAD_CONTEXT *) MenuEntry->VariableContext;
119 FreePool (LoadContext->FilePathList);
120 FreePool (LoadContext->LoadOption);
121 if (LoadContext->OptionalData != NULL) {
122 FreePool (LoadContext->OptionalData);
123 }
124 FreePool (LoadContext);
125 break;
126
127 case BM_FILE_CONTEXT_SELECT:
128 FileContext = (BM_FILE_CONTEXT *) MenuEntry->VariableContext;
129
130 if (!FileContext->IsRoot) {
131 FreePool (FileContext->DevicePath);
132 } else {
133 if (FileContext->FHandle != NULL) {
134 FileContext->FHandle->Close (FileContext->FHandle);
135 }
136 }
137
138 if (FileContext->FileName != NULL) {
139 FreePool (FileContext->FileName);
140 }
141 if (FileContext->Info != NULL) {
142 FreePool (FileContext->Info);
143 }
144 FreePool (FileContext);
145 break;
146
147 case BM_CONSOLE_CONTEXT_SELECT:
148 ConsoleContext = (BM_CONSOLE_CONTEXT *) MenuEntry->VariableContext;
149 FreePool (ConsoleContext->DevicePath);
150 FreePool (ConsoleContext);
151 break;
152
153 case BM_TERMINAL_CONTEXT_SELECT:
154 TerminalContext = (BM_TERMINAL_CONTEXT *) MenuEntry->VariableContext;
155 FreePool (TerminalContext->DevicePath);
156 FreePool (TerminalContext);
157 break;
158
159 case BM_HANDLE_CONTEXT_SELECT:
160 HandleContext = (BM_HANDLE_CONTEXT *) MenuEntry->VariableContext;
161 FreePool (HandleContext);
162 break;
163
164 case BM_LEGACY_DEV_CONTEXT_SELECT:
165 LegacyDevContext = (BM_LEGACY_DEVICE_CONTEXT *) MenuEntry->VariableContext;
166 FreePool (LegacyDevContext);
167
168 default:
169 break;
170 }
171
172 FreePool (MenuEntry->DisplayString);
173 if (MenuEntry->HelpString != NULL) {
174 FreePool (MenuEntry->HelpString);
175 }
176
177 FreePool (MenuEntry);
178 }
179
180 /**
181 Get the Menu Entry from the list in Menu Entry List.
182
183 If MenuNumber is great or equal to the number of Menu
184 Entry in the list, then ASSERT.
185
186 @param MenuOption The Menu Entry List to read the menu entry.
187 @param MenuNumber The index of Menu Entry.
188
189 @return The Menu Entry.
190
191 **/
192 BM_MENU_ENTRY *
193 BOpt_GetMenuEntry (
194 BM_MENU_OPTION *MenuOption,
195 UINTN MenuNumber
196 )
197 {
198 BM_MENU_ENTRY *NewMenuEntry;
199 UINTN Index;
200 LIST_ENTRY *List;
201
202 ASSERT (MenuNumber < MenuOption->MenuNumber);
203
204 List = MenuOption->Head.ForwardLink;
205 for (Index = 0; Index < MenuNumber; Index++) {
206 List = List->ForwardLink;
207 }
208
209 NewMenuEntry = CR (List, BM_MENU_ENTRY, Link, BM_MENU_ENTRY_SIGNATURE);
210
211 return NewMenuEntry;
212 }
213
214 /**
215 This function build the FsOptionMenu list which records all
216 available file system in the system. They includes all instances
217 of EFI_SIMPLE_FILE_SYSTEM_PROTOCOL, all instances of EFI_LOAD_FILE_SYSTEM
218 and all type of legacy boot device.
219
220 @param CallbackData BMM context data
221
222 @retval EFI_SUCCESS Success find the file system
223 @retval EFI_OUT_OF_RESOURCES Can not create menu entry
224
225 **/
226 EFI_STATUS
227 BOpt_FindFileSystem (
228 IN BMM_CALLBACK_DATA *CallbackData
229 )
230 {
231 UINTN NoBlkIoHandles;
232 UINTN NoSimpleFsHandles;
233 UINTN NoLoadFileHandles;
234 EFI_HANDLE *BlkIoHandle;
235 EFI_HANDLE *SimpleFsHandle;
236 EFI_HANDLE *LoadFileHandle;
237 UINT16 *VolumeLabel;
238 EFI_BLOCK_IO_PROTOCOL *BlkIo;
239 UINTN Index;
240 EFI_STATUS Status;
241 BM_MENU_ENTRY *MenuEntry;
242 BM_FILE_CONTEXT *FileContext;
243 UINT16 *TempStr;
244 UINTN OptionNumber;
245 VOID *Buffer;
246 EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
247 UINT16 DeviceType;
248 BBS_BBS_DEVICE_PATH BbsDevicePathNode;
249 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
250 BOOLEAN RemovableMedia;
251
252
253 NoSimpleFsHandles = 0;
254 NoLoadFileHandles = 0;
255 OptionNumber = 0;
256 InitializeListHead (&FsOptionMenu.Head);
257
258 //
259 // Locate Handles that support BlockIo protocol
260 //
261 Status = gBS->LocateHandleBuffer (
262 ByProtocol,
263 &gEfiBlockIoProtocolGuid,
264 NULL,
265 &NoBlkIoHandles,
266 &BlkIoHandle
267 );
268 if (!EFI_ERROR (Status)) {
269
270 for (Index = 0; Index < NoBlkIoHandles; Index++) {
271 Status = gBS->HandleProtocol (
272 BlkIoHandle[Index],
273 &gEfiBlockIoProtocolGuid,
274 (VOID **) &BlkIo
275 );
276
277 if (EFI_ERROR (Status)) {
278 continue;
279 }
280
281 //
282 // Issue a dummy read to trigger reinstall of BlockIo protocol for removable media
283 //
284 if (BlkIo->Media->RemovableMedia) {
285 Buffer = AllocateZeroPool (BlkIo->Media->BlockSize);
286 if (NULL == Buffer) {
287 FreePool (BlkIoHandle);
288 return EFI_OUT_OF_RESOURCES;
289 }
290
291 BlkIo->ReadBlocks (
292 BlkIo,
293 BlkIo->Media->MediaId,
294 0,
295 BlkIo->Media->BlockSize,
296 Buffer
297 );
298 FreePool (Buffer);
299 }
300 }
301 FreePool (BlkIoHandle);
302 }
303
304 //
305 // Locate Handles that support Simple File System protocol
306 //
307 Status = gBS->LocateHandleBuffer (
308 ByProtocol,
309 &gEfiSimpleFileSystemProtocolGuid,
310 NULL,
311 &NoSimpleFsHandles,
312 &SimpleFsHandle
313 );
314 if (!EFI_ERROR (Status)) {
315 //
316 // Find all the instances of the File System prototocol
317 //
318 for (Index = 0; Index < NoSimpleFsHandles; Index++) {
319 Status = gBS->HandleProtocol (
320 SimpleFsHandle[Index],
321 &gEfiBlockIoProtocolGuid,
322 (VOID **) &BlkIo
323 );
324 if (EFI_ERROR (Status)) {
325 //
326 // If no block IO exists assume it's NOT a removable media
327 //
328 RemovableMedia = FALSE;
329 } else {
330 //
331 // If block IO exists check to see if it's remobable media
332 //
333 RemovableMedia = BlkIo->Media->RemovableMedia;
334 }
335
336 //
337 // Allocate pool for this load option
338 //
339 MenuEntry = BOpt_CreateMenuEntry (BM_FILE_CONTEXT_SELECT);
340 if (NULL == MenuEntry) {
341 FreePool (SimpleFsHandle);
342 return EFI_OUT_OF_RESOURCES;
343 }
344
345 FileContext = (BM_FILE_CONTEXT *) MenuEntry->VariableContext;
346
347 FileContext->Handle = SimpleFsHandle[Index];
348 MenuEntry->OptionNumber = Index;
349 FileContext->FHandle = EfiLibOpenRoot (FileContext->Handle);
350 if (FileContext->FHandle == NULL) {
351 BOpt_DestroyMenuEntry (MenuEntry);
352 continue;
353 }
354
355 MenuEntry->HelpString = DevicePathToStr (DevicePathFromHandle (FileContext->Handle));
356 FileContext->Info = EfiLibFileSystemVolumeLabelInfo (FileContext->FHandle);
357 FileContext->FileName = EfiStrDuplicate (L"\\");
358 FileContext->DevicePath = FileDevicePath (
359 FileContext->Handle,
360 FileContext->FileName
361 );
362 FileContext->IsDir = TRUE;
363 FileContext->IsRoot = TRUE;
364 FileContext->IsRemovableMedia = RemovableMedia;
365 FileContext->IsLoadFile = FALSE;
366
367 //
368 // Get current file system's Volume Label
369 //
370 if (FileContext->Info == NULL) {
371 VolumeLabel = L"NO FILE SYSTEM INFO";
372 } else {
373 VolumeLabel = FileContext->Info->VolumeLabel;
374 if (*VolumeLabel == 0x0000) {
375 VolumeLabel = L"NO VOLUME LABEL";
376 }
377 }
378
379 TempStr = MenuEntry->HelpString;
380 MenuEntry->DisplayString = AllocateZeroPool (MAX_CHAR);
381 ASSERT (MenuEntry->DisplayString != NULL);
382 UnicodeSPrint (
383 MenuEntry->DisplayString,
384 MAX_CHAR,
385 L"%s, [%s]",
386 VolumeLabel,
387 TempStr
388 );
389 OptionNumber++;
390 InsertTailList (&FsOptionMenu.Head, &MenuEntry->Link);
391 }
392 }
393
394 if (NoSimpleFsHandles != 0) {
395 FreePool (SimpleFsHandle);
396 }
397 //
398 // Searching for handles that support Load File protocol
399 //
400 Status = gBS->LocateHandleBuffer (
401 ByProtocol,
402 &gEfiLoadFileProtocolGuid,
403 NULL,
404 &NoLoadFileHandles,
405 &LoadFileHandle
406 );
407
408 if (!EFI_ERROR (Status)) {
409 for (Index = 0; Index < NoLoadFileHandles; Index++) {
410 MenuEntry = BOpt_CreateMenuEntry (BM_FILE_CONTEXT_SELECT);
411 if (NULL == MenuEntry) {
412 FreePool (LoadFileHandle);
413 return EFI_OUT_OF_RESOURCES;
414 }
415
416 FileContext = (BM_FILE_CONTEXT *) MenuEntry->VariableContext;
417 FileContext->IsRemovableMedia = FALSE;
418 FileContext->IsLoadFile = TRUE;
419 FileContext->Handle = LoadFileHandle[Index];
420 FileContext->IsRoot = TRUE;
421
422 FileContext->DevicePath = DevicePathFromHandle (FileContext->Handle);
423 FileContext->FileName = DevicePathToStr (FileContext->DevicePath);
424
425 MenuEntry->HelpString = DevicePathToStr (FileContext->DevicePath);
426
427 TempStr = MenuEntry->HelpString;
428 MenuEntry->DisplayString = AllocateZeroPool (MAX_CHAR);
429 ASSERT (MenuEntry->DisplayString != NULL);
430 UnicodeSPrint (
431 MenuEntry->DisplayString,
432 MAX_CHAR,
433 L"Load File [%s]",
434 TempStr
435 );
436
437 MenuEntry->OptionNumber = OptionNumber;
438 OptionNumber++;
439 InsertTailList (&FsOptionMenu.Head, &MenuEntry->Link);
440 }
441 }
442
443 if (NoLoadFileHandles != 0) {
444 FreePool (LoadFileHandle);
445 }
446
447 //
448 // Add Legacy Boot Option Support Here
449 //
450 Status = gBS->LocateProtocol (
451 &gEfiLegacyBiosProtocolGuid,
452 NULL,
453 (VOID **) &LegacyBios
454 );
455 if (!EFI_ERROR (Status)) {
456
457 for (Index = BBS_TYPE_FLOPPY; Index <= BBS_TYPE_EMBEDDED_NETWORK; Index++) {
458 MenuEntry = BOpt_CreateMenuEntry (BM_FILE_CONTEXT_SELECT);
459 if (NULL == MenuEntry) {
460 return EFI_OUT_OF_RESOURCES;
461 }
462
463 FileContext = (BM_FILE_CONTEXT *) MenuEntry->VariableContext;
464
465 FileContext->IsRemovableMedia = FALSE;
466 FileContext->IsLoadFile = TRUE;
467 FileContext->IsBootLegacy = TRUE;
468 DeviceType = (UINT16) Index;
469 BbsDevicePathNode.Header.Type = BBS_DEVICE_PATH;
470 BbsDevicePathNode.Header.SubType = BBS_BBS_DP;
471 SetDevicePathNodeLength (
472 &BbsDevicePathNode.Header,
473 sizeof (BBS_BBS_DEVICE_PATH)
474 );
475 BbsDevicePathNode.DeviceType = DeviceType;
476 BbsDevicePathNode.StatusFlag = 0;
477 BbsDevicePathNode.String[0] = 0;
478 DevicePath = AppendDevicePathNode (
479 EndDevicePath,
480 (EFI_DEVICE_PATH_PROTOCOL *) &BbsDevicePathNode
481 );
482
483 FileContext->DevicePath = DevicePath;
484 MenuEntry->HelpString = DevicePathToStr (FileContext->DevicePath);
485
486 TempStr = MenuEntry->HelpString;
487 MenuEntry->DisplayString = AllocateZeroPool (MAX_CHAR);
488 ASSERT (MenuEntry->DisplayString != NULL);
489 UnicodeSPrint (
490 MenuEntry->DisplayString,
491 MAX_CHAR,
492 L"Boot Legacy [%s]",
493 TempStr
494 );
495 MenuEntry->OptionNumber = OptionNumber;
496 OptionNumber++;
497 InsertTailList (&FsOptionMenu.Head, &MenuEntry->Link);
498 }
499 }
500 //
501 // Remember how many file system options are here
502 //
503 FsOptionMenu.MenuNumber = OptionNumber;
504 return EFI_SUCCESS;
505 }
506
507 /**
508 Free resources allocated in Allocate Rountine.
509
510 @param FreeMenu Menu to be freed
511 **/
512 VOID
513 BOpt_FreeMenu (
514 BM_MENU_OPTION *FreeMenu
515 )
516 {
517 BM_MENU_ENTRY *MenuEntry;
518 while (!IsListEmpty (&FreeMenu->Head)) {
519 MenuEntry = CR (
520 FreeMenu->Head.ForwardLink,
521 BM_MENU_ENTRY,
522 Link,
523 BM_MENU_ENTRY_SIGNATURE
524 );
525 RemoveEntryList (&MenuEntry->Link);
526 BOpt_DestroyMenuEntry (MenuEntry);
527 }
528 FreeMenu->MenuNumber = 0;
529 }
530
531 /**
532 Find files under current directory
533 All files and sub-directories in current directory
534 will be stored in DirectoryMenu for future use.
535
536 @param CallbackData The BMM context data.
537 @param MenuEntry The Menu Entry.
538
539 @retval EFI_SUCCESS Get files from current dir successfully.
540 @return Other value if can't get files from current dir.
541
542 **/
543 EFI_STATUS
544 BOpt_FindFiles (
545 IN BMM_CALLBACK_DATA *CallbackData,
546 IN BM_MENU_ENTRY *MenuEntry
547 )
548 {
549 EFI_FILE_HANDLE NewDir;
550 EFI_FILE_HANDLE Dir;
551 EFI_FILE_INFO *DirInfo;
552 UINTN BufferSize;
553 UINTN DirBufferSize;
554 BM_MENU_ENTRY *NewMenuEntry;
555 BM_FILE_CONTEXT *FileContext;
556 BM_FILE_CONTEXT *NewFileContext;
557 UINTN Pass;
558 EFI_STATUS Status;
559 UINTN OptionNumber;
560
561 FileContext = (BM_FILE_CONTEXT *) MenuEntry->VariableContext;
562 Dir = FileContext->FHandle;
563 OptionNumber = 0;
564 //
565 // Open current directory to get files from it
566 //
567 Status = Dir->Open (
568 Dir,
569 &NewDir,
570 FileContext->FileName,
571 EFI_FILE_READ_ONLY,
572 0
573 );
574 if (!FileContext->IsRoot) {
575 Dir->Close (Dir);
576 }
577
578 if (EFI_ERROR (Status)) {
579 return Status;
580 }
581
582 DirInfo = EfiLibFileInfo (NewDir);
583 if (DirInfo == NULL) {
584 return EFI_NOT_FOUND;
585 }
586
587 if ((DirInfo->Attribute & EFI_FILE_DIRECTORY) == 0) {
588 return EFI_INVALID_PARAMETER;
589 }
590
591 FileContext->DevicePath = FileDevicePath (
592 FileContext->Handle,
593 FileContext->FileName
594 );
595
596 DirBufferSize = sizeof (EFI_FILE_INFO) + 1024;
597 DirInfo = AllocateZeroPool (DirBufferSize);
598 if (DirInfo == NULL) {
599 return EFI_OUT_OF_RESOURCES;
600 }
601 //
602 // Get all files in current directory
603 // Pass 1 to get Directories
604 // Pass 2 to get files that are EFI images
605 //
606 for (Pass = 1; Pass <= 2; Pass++) {
607 NewDir->SetPosition (NewDir, 0);
608 for (;;) {
609 BufferSize = DirBufferSize;
610 Status = NewDir->Read (NewDir, &BufferSize, DirInfo);
611 if (EFI_ERROR (Status) || BufferSize == 0) {
612 break;
613 }
614
615 if (((DirInfo->Attribute & EFI_FILE_DIRECTORY) != 0 && Pass == 2) ||
616 ((DirInfo->Attribute & EFI_FILE_DIRECTORY) == 0 && Pass == 1)
617 ) {
618 //
619 // Pass 1 is for Directories
620 // Pass 2 is for file names
621 //
622 continue;
623 }
624
625 if (!(BOpt_IsEfiImageName (DirInfo->FileName) || (DirInfo->Attribute & EFI_FILE_DIRECTORY) != 0)) {
626 //
627 // Slip file unless it is a directory entry or a .EFI file
628 //
629 continue;
630 }
631
632 NewMenuEntry = BOpt_CreateMenuEntry (BM_FILE_CONTEXT_SELECT);
633 if (NULL == NewMenuEntry) {
634 return EFI_OUT_OF_RESOURCES;
635 }
636
637 NewFileContext = (BM_FILE_CONTEXT *) NewMenuEntry->VariableContext;
638 NewFileContext->Handle = FileContext->Handle;
639 NewFileContext->FileName = BOpt_AppendFileName (
640 FileContext->FileName,
641 DirInfo->FileName
642 );
643 NewFileContext->FHandle = NewDir;
644 NewFileContext->DevicePath = FileDevicePath (
645 NewFileContext->Handle,
646 NewFileContext->FileName
647 );
648 NewMenuEntry->HelpString = NULL;
649
650 MenuEntry->DisplayStringToken = GetStringTokenFromDepository (
651 CallbackData,
652 FileOptionStrDepository
653 );
654
655 NewFileContext->IsDir = (BOOLEAN) ((DirInfo->Attribute & EFI_FILE_DIRECTORY) == EFI_FILE_DIRECTORY);
656
657 if (NewFileContext->IsDir) {
658 BufferSize = StrLen (DirInfo->FileName) * 2 + 6;
659 NewMenuEntry->DisplayString = AllocateZeroPool (BufferSize);
660
661 UnicodeSPrint (
662 NewMenuEntry->DisplayString,
663 BufferSize,
664 L"<%s>",
665 DirInfo->FileName
666 );
667
668 } else {
669 NewMenuEntry->DisplayString = EfiStrDuplicate (DirInfo->FileName);
670 }
671
672 NewFileContext->IsRoot = FALSE;
673 NewFileContext->IsLoadFile = FALSE;
674 NewFileContext->IsRemovableMedia = FALSE;
675
676 NewMenuEntry->OptionNumber = OptionNumber;
677 OptionNumber++;
678 InsertTailList (&DirectoryMenu.Head, &NewMenuEntry->Link);
679 }
680 }
681
682 DirectoryMenu.MenuNumber = OptionNumber;
683 FreePool (DirInfo);
684 return EFI_SUCCESS;
685 }
686
687 /**
688 Build the LegacyFDMenu LegacyHDMenu LegacyCDMenu according to LegacyBios.GetBbsInfo().
689
690 @retval EFI_SUCCESS The function complete successfully.
691 @retval EFI_OUT_OF_RESOURCES No enough memory to complete this function.
692
693 **/
694 EFI_STATUS
695 BOpt_GetLegacyOptions (
696 VOID
697 )
698 {
699 BM_MENU_ENTRY *NewMenuEntry;
700 BM_LEGACY_DEVICE_CONTEXT *NewLegacyDevContext;
701 EFI_STATUS Status;
702 EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
703 UINT16 HddCount;
704 HDD_INFO *HddInfo;
705 UINT16 BbsCount;
706 BBS_TABLE *BbsTable;
707 UINT16 Index;
708 CHAR16 DescString[100];
709 UINTN FDNum;
710 UINTN HDNum;
711 UINTN CDNum;
712 UINTN NETNum;
713 UINTN BEVNum;
714
715 NewMenuEntry = NULL;
716 HddInfo = NULL;
717 BbsTable = NULL;
718 BbsCount = 0;
719
720 //
721 // Initialize Bbs Table Context from BBS info data
722 //
723 InitializeListHead (&LegacyFDMenu.Head);
724 InitializeListHead (&LegacyHDMenu.Head);
725 InitializeListHead (&LegacyCDMenu.Head);
726 InitializeListHead (&LegacyNETMenu.Head);
727 InitializeListHead (&LegacyBEVMenu.Head);
728
729 Status = gBS->LocateProtocol (
730 &gEfiLegacyBiosProtocolGuid,
731 NULL,
732 (VOID **) &LegacyBios
733 );
734 if (!EFI_ERROR (Status)) {
735 Status = LegacyBios->GetBbsInfo (
736 LegacyBios,
737 &HddCount,
738 &HddInfo,
739 &BbsCount,
740 &BbsTable
741 );
742 if (EFI_ERROR (Status)) {
743 return Status;
744 }
745 }
746
747 FDNum = 0;
748 HDNum = 0;
749 CDNum = 0;
750 NETNum = 0;
751 BEVNum = 0;
752
753 for (Index = 0; Index < BbsCount; Index++) {
754 if ((BBS_IGNORE_ENTRY == BbsTable[Index].BootPriority) ||
755 (BBS_DO_NOT_BOOT_FROM == BbsTable[Index].BootPriority)
756 ) {
757 continue;
758 }
759
760 NewMenuEntry = BOpt_CreateMenuEntry (BM_LEGACY_DEV_CONTEXT_SELECT);
761 if (NULL == NewMenuEntry) {
762 break;
763 }
764
765 NewLegacyDevContext = (BM_LEGACY_DEVICE_CONTEXT *) NewMenuEntry->VariableContext;
766 NewLegacyDevContext->BbsEntry = &BbsTable[Index];
767 NewLegacyDevContext->BbsIndex = Index;
768 NewLegacyDevContext->BbsCount = BbsCount;
769 BdsBuildLegacyDevNameString (
770 &BbsTable[Index],
771 Index,
772 sizeof (DescString),
773 DescString
774 );
775 NewLegacyDevContext->Description = AllocateCopyPool (StrSize (DescString), DescString);
776 if (NULL == NewLegacyDevContext->Description) {
777 break;
778 }
779
780 NewMenuEntry->DisplayString = NewLegacyDevContext->Description;
781 NewMenuEntry->HelpString = NULL;
782
783 switch (BbsTable[Index].DeviceType) {
784 case BBS_FLOPPY:
785 InsertTailList (&LegacyFDMenu.Head, &NewMenuEntry->Link);
786 FDNum++;
787 break;
788
789 case BBS_HARDDISK:
790 InsertTailList (&LegacyHDMenu.Head, &NewMenuEntry->Link);
791 HDNum++;
792 break;
793
794 case BBS_CDROM:
795 InsertTailList (&LegacyCDMenu.Head, &NewMenuEntry->Link);
796 CDNum++;
797 break;
798
799 case BBS_EMBED_NETWORK:
800 InsertTailList (&LegacyNETMenu.Head, &NewMenuEntry->Link);
801 NETNum++;
802 break;
803
804 case BBS_BEV_DEVICE:
805 InsertTailList (&LegacyBEVMenu.Head, &NewMenuEntry->Link);
806 BEVNum++;
807 break;
808 }
809 }
810
811 if (Index != BbsCount) {
812 BOpt_FreeLegacyOptions ();
813 return EFI_OUT_OF_RESOURCES;
814 }
815
816 LegacyFDMenu.MenuNumber = FDNum;
817 LegacyHDMenu.MenuNumber = HDNum;
818 LegacyCDMenu.MenuNumber = CDNum;
819 LegacyNETMenu.MenuNumber = NETNum;
820 LegacyBEVMenu.MenuNumber = BEVNum;
821 return EFI_SUCCESS;
822 }
823
824 /**
825 Free out resouce allocated from Legacy Boot Options.
826
827 **/
828 VOID
829 BOpt_FreeLegacyOptions (
830 VOID
831 )
832 {
833 BOpt_FreeMenu (&LegacyFDMenu);
834 BOpt_FreeMenu (&LegacyHDMenu);
835 BOpt_FreeMenu (&LegacyCDMenu);
836 BOpt_FreeMenu (&LegacyNETMenu);
837 BOpt_FreeMenu (&LegacyBEVMenu);
838 }
839
840 /**
841
842 Build the BootOptionMenu according to BootOrder Variable.
843 This Routine will access the Boot#### to get EFI_LOAD_OPTION.
844
845 @param CallbackData The BMM context data.
846
847 @return EFI_NOT_FOUND Fail to find "BootOrder" variable.
848 @return EFI_SUCESS Success build boot option menu.
849
850 **/
851 EFI_STATUS
852 BOpt_GetBootOptions (
853 IN BMM_CALLBACK_DATA *CallbackData
854 )
855 {
856 UINTN Index;
857 UINT16 BootString[10];
858 UINT8 *LoadOptionFromVar;
859 UINT8 *LoadOption;
860 UINTN BootOptionSize;
861 BOOLEAN BootNextFlag;
862 UINT16 *BootOrderList;
863 UINTN BootOrderListSize;
864 UINT16 *BootNext;
865 UINTN BootNextSize;
866 BM_MENU_ENTRY *NewMenuEntry;
867 BM_LOAD_CONTEXT *NewLoadContext;
868 UINT8 *LoadOptionPtr;
869 UINTN StringSize;
870 UINTN OptionalDataSize;
871 UINT8 *LoadOptionEnd;
872 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
873 UINTN MenuCount;
874 UINT8 *Ptr;
875
876 MenuCount = 0;
877 BootOrderListSize = 0;
878 BootNextSize = 0;
879 BootOrderList = NULL;
880 BootNext = NULL;
881 LoadOptionFromVar = NULL;
882 BOpt_FreeMenu (&BootOptionMenu);
883 InitializeListHead (&BootOptionMenu.Head);
884
885 //
886 // Get the BootOrder from the Var
887 //
888 BootOrderList = BdsLibGetVariableAndSize (
889 L"BootOrder",
890 &gEfiGlobalVariableGuid,
891 &BootOrderListSize
892 );
893 if (BootOrderList == NULL) {
894 return EFI_NOT_FOUND;
895 }
896
897 //
898 // Get the BootNext from the Var
899 //
900 BootNext = BdsLibGetVariableAndSize (
901 L"BootNext",
902 &gEfiGlobalVariableGuid,
903 &BootNextSize
904 );
905
906 if (BootNext != NULL) {
907 if (BootNextSize != sizeof (UINT16)) {
908 FreePool (BootNext);
909 BootNext = NULL;
910 }
911 }
912
913 for (Index = 0; Index < BootOrderListSize / sizeof (UINT16); Index++) {
914 UnicodeSPrint (BootString, sizeof (BootString), L"Boot%04x", BootOrderList[Index]);
915 //
916 // Get all loadoptions from the VAR
917 //
918 LoadOptionFromVar = BdsLibGetVariableAndSize (
919 BootString,
920 &gEfiGlobalVariableGuid,
921 &BootOptionSize
922 );
923 if (LoadOptionFromVar == NULL) {
924 continue;
925 }
926
927 LoadOption = AllocateZeroPool (BootOptionSize);
928 if (LoadOption == NULL) {
929 continue;
930 }
931
932 CopyMem (LoadOption, LoadOptionFromVar, BootOptionSize);
933 FreePool (LoadOptionFromVar);
934
935 if (BootNext != NULL) {
936 BootNextFlag = (BOOLEAN) (*BootNext == BootOrderList[Index]);
937 } else {
938 BootNextFlag = FALSE;
939 }
940
941 if (0 == (*((UINT32 *) LoadOption) & LOAD_OPTION_ACTIVE)) {
942 FreePool (LoadOption);
943 continue;
944 }
945 //
946 // BUGBUG: could not return EFI_OUT_OF_RESOURCES here directly.
947 // the buffer allocated already should be freed before returning.
948 //
949 NewMenuEntry = BOpt_CreateMenuEntry (BM_LOAD_CONTEXT_SELECT);
950 if (NULL == NewMenuEntry) {
951 return EFI_OUT_OF_RESOURCES;
952 }
953
954 NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
955
956 LoadOptionPtr = LoadOption;
957 LoadOptionEnd = LoadOption + BootOptionSize;
958
959 NewMenuEntry->OptionNumber = BootOrderList[Index];
960 NewLoadContext->LoadOptionModified = FALSE;
961 NewLoadContext->Deleted = FALSE;
962 NewLoadContext->IsBootNext = BootNextFlag;
963
964 //
965 // Is a Legacy Device?
966 //
967 Ptr = (UINT8 *) LoadOption;
968
969 //
970 // Attribute = *(UINT32 *)Ptr;
971 //
972 Ptr += sizeof (UINT32);
973
974 //
975 // FilePathSize = *(UINT16 *)Ptr;
976 //
977 Ptr += sizeof (UINT16);
978
979 //
980 // Description = (CHAR16 *)Ptr;
981 //
982 Ptr += StrSize ((CHAR16 *) Ptr);
983
984 //
985 // Now Ptr point to Device Path
986 //
987 DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) Ptr;
988 if ((BBS_DEVICE_PATH == DevicePath->Type) && (BBS_BBS_DP == DevicePath->SubType)) {
989 NewLoadContext->IsLegacy = TRUE;
990 } else {
991 NewLoadContext->IsLegacy = FALSE;
992 }
993 //
994 // LoadOption is a pointer type of UINT8
995 // for easy use with following LOAD_OPTION
996 // embedded in this struct
997 //
998 NewLoadContext->LoadOption = LoadOption;
999 NewLoadContext->LoadOptionSize = BootOptionSize;
1000
1001 NewLoadContext->Attributes = *(UINT32 *) LoadOptionPtr;
1002 NewLoadContext->IsActive = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_ACTIVE);
1003
1004 NewLoadContext->ForceReconnect = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_FORCE_RECONNECT);
1005
1006 LoadOptionPtr += sizeof (UINT32);
1007
1008 NewLoadContext->FilePathListLength = *(UINT16 *) LoadOptionPtr;
1009 LoadOptionPtr += sizeof (UINT16);
1010
1011 StringSize = StrSize((UINT16*)LoadOptionPtr);
1012
1013 NewLoadContext->Description = AllocateCopyPool (StrSize((UINT16*)LoadOptionPtr), LoadOptionPtr);
1014 ASSERT (NewLoadContext->Description != NULL);
1015
1016 NewMenuEntry->DisplayString = NewLoadContext->Description;
1017
1018 LoadOptionPtr += StringSize;
1019
1020 NewLoadContext->FilePathList = AllocateZeroPool (NewLoadContext->FilePathListLength);
1021 ASSERT (NewLoadContext->FilePathList != NULL);
1022 CopyMem (
1023 NewLoadContext->FilePathList,
1024 (EFI_DEVICE_PATH_PROTOCOL *) LoadOptionPtr,
1025 NewLoadContext->FilePathListLength
1026 );
1027
1028 NewMenuEntry->HelpString = DevicePathToStr (NewLoadContext->FilePathList);
1029 NewMenuEntry->DisplayStringToken = GetStringTokenFromDepository (
1030 CallbackData,
1031 BootOptionStrDepository
1032 );
1033 NewMenuEntry->HelpStringToken = GetStringTokenFromDepository (
1034 CallbackData,
1035 BootOptionHelpStrDepository
1036 );
1037 LoadOptionPtr += NewLoadContext->FilePathListLength;
1038
1039 if (LoadOptionPtr < LoadOptionEnd) {
1040 OptionalDataSize = BootOptionSize -
1041 sizeof (UINT32) -
1042 sizeof (UINT16) -
1043 StringSize -
1044 NewLoadContext->FilePathListLength;
1045
1046 NewLoadContext->OptionalData = AllocateZeroPool (OptionalDataSize);
1047 ASSERT (NewLoadContext->OptionalData != NULL);
1048 CopyMem (
1049 NewLoadContext->OptionalData,
1050 LoadOptionPtr,
1051 OptionalDataSize
1052 );
1053
1054 NewLoadContext->OptionalDataSize = OptionalDataSize;
1055 }
1056
1057 InsertTailList (&BootOptionMenu.Head, &NewMenuEntry->Link);
1058 MenuCount++;
1059 }
1060
1061 if (BootNext != NULL) {
1062 FreePool (BootNext);
1063 }
1064 if (BootOrderList != NULL) {
1065 FreePool (BootOrderList);
1066 }
1067 BootOptionMenu.MenuNumber = MenuCount;
1068 return EFI_SUCCESS;
1069 }
1070
1071 /**
1072
1073 Append file name to existing file name.
1074
1075 @param Str1 The existing file name
1076 @param Str2 The file name to be appended
1077
1078 @return Allocate a new string to hold the appended result.
1079 Caller is responsible to free the returned string.
1080
1081 **/
1082 CHAR16 *
1083 BOpt_AppendFileName (
1084 IN CHAR16 *Str1,
1085 IN CHAR16 *Str2
1086 )
1087 {
1088 UINTN Size1;
1089 UINTN Size2;
1090 UINTN MaxLen;
1091 CHAR16 *Str;
1092 CHAR16 *TmpStr;
1093 CHAR16 *Ptr;
1094 CHAR16 *LastSlash;
1095
1096 Size1 = StrSize (Str1);
1097 Size2 = StrSize (Str2);
1098 MaxLen = (Size1 + Size2 + sizeof (CHAR16)) / sizeof (CHAR16);
1099 Str = AllocateCopyPool (MaxLen * sizeof (CHAR16), Str1);
1100 ASSERT (Str != NULL);
1101
1102 TmpStr = AllocateZeroPool (MaxLen * sizeof (CHAR16));
1103 ASSERT (TmpStr != NULL);
1104
1105 if (!((*Str == '\\') && (*(Str + 1) == 0))) {
1106 StrCatS (Str, MaxLen, L"\\");
1107 }
1108
1109 StrCatS (Str, MaxLen, Str2);
1110
1111 Ptr = Str;
1112 LastSlash = Str;
1113 while (*Ptr != 0) {
1114 if (*Ptr == '\\' && *(Ptr + 1) == '.' && *(Ptr + 2) == '.' && *(Ptr + 3) == L'\\') {
1115 //
1116 // Convert "\Name\..\" to "\"
1117 // DO NOT convert the .. if it is at the end of the string. This will
1118 // break the .. behavior in changing directories.
1119 //
1120
1121 //
1122 // Use TmpStr as a backup, as StrCpyS in BaseLib does not handle copy of two strings
1123 // that overlap.
1124 //
1125 StrCpyS (TmpStr, MaxLen, Ptr + 3);
1126 StrCpyS (LastSlash, MaxLen - (UINTN) (LastSlash - Str), TmpStr);
1127 Ptr = LastSlash;
1128 } else if (*Ptr == '\\' && *(Ptr + 1) == '.' && *(Ptr + 2) == '\\') {
1129 //
1130 // Convert a "\.\" to a "\"
1131 //
1132
1133 //
1134 // Use TmpStr as a backup, as StrCpyS in BaseLib does not handle copy of two strings
1135 // that overlap.
1136 //
1137 StrCpyS (TmpStr, MaxLen, Ptr + 2);
1138 StrCpyS (Ptr, MaxLen - (UINTN) (Ptr - Str), TmpStr);
1139 Ptr = LastSlash;
1140 } else if (*Ptr == '\\') {
1141 LastSlash = Ptr;
1142 }
1143
1144 Ptr++;
1145 }
1146
1147 FreePool (TmpStr);
1148
1149 return Str;
1150 }
1151
1152 /**
1153
1154 Check whether current FileName point to a valid
1155 Efi Image File.
1156
1157 @param FileName File need to be checked.
1158
1159 @retval TRUE Is Efi Image
1160 @retval FALSE Not a valid Efi Image
1161
1162 **/
1163 BOOLEAN
1164 BOpt_IsEfiImageName (
1165 IN UINT16 *FileName
1166 )
1167 {
1168 //
1169 // Search for ".efi" extension
1170 //
1171 while (*FileName != L'\0') {
1172 if (FileName[0] == '.') {
1173 if (FileName[1] == 'e' || FileName[1] == 'E') {
1174 if (FileName[2] == 'f' || FileName[2] == 'F') {
1175 if (FileName[3] == 'i' || FileName[3] == 'I') {
1176 return TRUE;
1177 } else if (FileName[3] == 0x0000) {
1178 return FALSE;
1179 }
1180 } else if (FileName[2] == 0x0000) {
1181 return FALSE;
1182 }
1183 } else if (FileName[1] == 0x0000) {
1184 return FALSE;
1185 }
1186 }
1187
1188 FileName += 1;
1189 }
1190
1191 return FALSE;
1192 }
1193
1194 /**
1195
1196 Check whether current FileName point to a valid Efi Application
1197
1198 @param Dir Pointer to current Directory
1199 @param FileName Pointer to current File name.
1200
1201 @retval TRUE Is a valid Efi Application
1202 @retval FALSE not a valid Efi Application
1203
1204 **/
1205 BOOLEAN
1206 BOpt_IsEfiApp (
1207 IN EFI_FILE_HANDLE Dir,
1208 IN UINT16 *FileName
1209 )
1210 {
1211 UINTN BufferSize;
1212 EFI_IMAGE_DOS_HEADER DosHdr;
1213 UINT16 Subsystem;
1214 EFI_FILE_HANDLE File;
1215 EFI_STATUS Status;
1216 EFI_IMAGE_OPTIONAL_HEADER_UNION PeHdr;
1217
1218 Status = Dir->Open (Dir, &File, FileName, EFI_FILE_MODE_READ, 0);
1219
1220 if (EFI_ERROR (Status)) {
1221 return FALSE;
1222 }
1223
1224 BufferSize = sizeof (EFI_IMAGE_DOS_HEADER);
1225 File->Read (File, &BufferSize, &DosHdr);
1226 if (DosHdr.e_magic != EFI_IMAGE_DOS_SIGNATURE) {
1227 File->Close (File);
1228 return FALSE;
1229 }
1230
1231 File->SetPosition (File, DosHdr.e_lfanew);
1232 BufferSize = sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION);
1233 File->Read (File, &BufferSize, &PeHdr);
1234 if (PeHdr.Pe32.Signature != EFI_IMAGE_NT_SIGNATURE) {
1235 File->Close (File);
1236 return FALSE;
1237 }
1238 //
1239 // Determine PE type and read subsytem
1240 //
1241 if (PeHdr.Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
1242 Subsystem = PeHdr.Pe32.OptionalHeader.Subsystem;
1243 } else if (PeHdr.Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
1244 Subsystem = PeHdr.Pe32Plus.OptionalHeader.Subsystem;
1245 } else {
1246 return FALSE;
1247 }
1248
1249 if (Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) {
1250 File->Close (File);
1251 return TRUE;
1252 } else {
1253 File->Close (File);
1254 return FALSE;
1255 }
1256 }
1257
1258 /**
1259
1260 Find drivers that will be added as Driver#### variables from handles
1261 in current system environment
1262 All valid handles in the system except those consume SimpleFs, LoadFile
1263 are stored in DriverMenu for future use.
1264
1265 @retval EFI_SUCCESS The function complets successfully.
1266 @return Other value if failed to build the DriverMenu.
1267
1268 **/
1269 EFI_STATUS
1270 BOpt_FindDrivers (
1271 VOID
1272 )
1273 {
1274 UINTN NoDevicePathHandles;
1275 EFI_HANDLE *DevicePathHandle;
1276 UINTN Index;
1277 EFI_STATUS Status;
1278 BM_MENU_ENTRY *NewMenuEntry;
1279 BM_HANDLE_CONTEXT *NewHandleContext;
1280 EFI_HANDLE CurHandle;
1281 UINTN OptionNumber;
1282 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFs;
1283 EFI_LOAD_FILE_PROTOCOL *LoadFile;
1284
1285 SimpleFs = NULL;
1286 LoadFile = NULL;
1287
1288 InitializeListHead (&DriverMenu.Head);
1289
1290 //
1291 // At first, get all handles that support Device Path
1292 // protocol which is the basic requirement for
1293 // Driver####
1294 //
1295 Status = gBS->LocateHandleBuffer (
1296 ByProtocol,
1297 &gEfiDevicePathProtocolGuid,
1298 NULL,
1299 &NoDevicePathHandles,
1300 &DevicePathHandle
1301 );
1302 if (EFI_ERROR (Status)) {
1303 return Status;
1304 }
1305
1306 OptionNumber = 0;
1307 for (Index = 0; Index < NoDevicePathHandles; Index++) {
1308 CurHandle = DevicePathHandle[Index];
1309
1310 Status = gBS->HandleProtocol (
1311 CurHandle,
1312 &gEfiSimpleFileSystemProtocolGuid,
1313 (VOID **) &SimpleFs
1314 );
1315 if (Status == EFI_SUCCESS) {
1316 continue;
1317 }
1318
1319 Status = gBS->HandleProtocol (
1320 CurHandle,
1321 &gEfiLoadFileProtocolGuid,
1322 (VOID **) &LoadFile
1323 );
1324 if (Status == EFI_SUCCESS) {
1325 continue;
1326 }
1327
1328 NewMenuEntry = BOpt_CreateMenuEntry (BM_HANDLE_CONTEXT_SELECT);
1329 if (NULL == NewMenuEntry) {
1330 FreePool (DevicePathHandle);
1331 return EFI_OUT_OF_RESOURCES;
1332 }
1333
1334 NewHandleContext = (BM_HANDLE_CONTEXT *) NewMenuEntry->VariableContext;
1335 NewHandleContext->Handle = CurHandle;
1336 NewHandleContext->DevicePath = DevicePathFromHandle (CurHandle);
1337 NewMenuEntry->DisplayString = DevicePathToStr (NewHandleContext->DevicePath);
1338 NewMenuEntry->HelpString = NULL;
1339 NewMenuEntry->OptionNumber = OptionNumber;
1340 OptionNumber++;
1341 InsertTailList (&DriverMenu.Head, &NewMenuEntry->Link);
1342
1343 }
1344
1345 if (DevicePathHandle != NULL) {
1346 FreePool (DevicePathHandle);
1347 }
1348
1349 DriverMenu.MenuNumber = OptionNumber;
1350 return EFI_SUCCESS;
1351 }
1352
1353 /**
1354
1355 Get the Option Number that has not been allocated for use.
1356
1357 @param Type The type of Option.
1358
1359 @return The available Option Number.
1360
1361 **/
1362 UINT16
1363 BOpt_GetOptionNumber (
1364 CHAR16 *Type
1365 )
1366 {
1367 UINT16 *OrderList;
1368 UINTN OrderListSize;
1369 UINTN Index;
1370 CHAR16 StrTemp[20];
1371 UINT16 *OptionBuffer;
1372 UINT16 OptionNumber;
1373 UINTN OptionSize;
1374
1375 OrderListSize = 0;
1376 OrderList = NULL;
1377 OptionNumber = 0;
1378 Index = 0;
1379
1380 UnicodeSPrint (StrTemp, sizeof (StrTemp), L"%sOrder", Type);
1381
1382 OrderList = BdsLibGetVariableAndSize (
1383 StrTemp,
1384 &gEfiGlobalVariableGuid,
1385 &OrderListSize
1386 );
1387
1388 for (OptionNumber = 0; ; OptionNumber++) {
1389 if (OrderList != NULL) {
1390 for (Index = 0; Index < OrderListSize / sizeof (UINT16); Index++) {
1391 if (OptionNumber == OrderList[Index]) {
1392 break;
1393 }
1394 }
1395 }
1396
1397 if (Index < OrderListSize / sizeof (UINT16)) {
1398 //
1399 // The OptionNumber occurs in the OrderList, continue to use next one
1400 //
1401 continue;
1402 }
1403 UnicodeSPrint (StrTemp, sizeof (StrTemp), L"%s%04x", Type, (UINTN) OptionNumber);
1404 DEBUG((EFI_D_ERROR,"Option = %s\n", StrTemp));
1405 OptionBuffer = BdsLibGetVariableAndSize (
1406 StrTemp,
1407 &gEfiGlobalVariableGuid,
1408 &OptionSize
1409 );
1410 if (NULL == OptionBuffer) {
1411 //
1412 // The Boot[OptionNumber] / Driver[OptionNumber] NOT occurs, we found it
1413 //
1414 break;
1415 }
1416 }
1417
1418 return OptionNumber;
1419 }
1420
1421 /**
1422
1423 Get the Option Number for Boot#### that does not used.
1424
1425 @return The available Option Number.
1426
1427 **/
1428 UINT16
1429 BOpt_GetBootOptionNumber (
1430 VOID
1431 )
1432 {
1433 return BOpt_GetOptionNumber (L"Boot");
1434 }
1435
1436 /**
1437
1438 Get the Option Number for Driver#### that does not used.
1439
1440 @return The unused Option Number.
1441
1442 **/
1443 UINT16
1444 BOpt_GetDriverOptionNumber (
1445 VOID
1446 )
1447 {
1448 return BOpt_GetOptionNumber (L"Driver");
1449 }
1450
1451 /**
1452
1453 Build up all DriverOptionMenu
1454
1455 @param CallbackData The BMM context data.
1456
1457 @retval EFI_SUCESS The functin completes successfully.
1458 @retval EFI_OUT_OF_RESOURCES Not enough memory to compete the operation.
1459 @retval EFI_NOT_FOUND Fail to get "DriverOrder" variable.
1460
1461 **/
1462 EFI_STATUS
1463 BOpt_GetDriverOptions (
1464 IN BMM_CALLBACK_DATA *CallbackData
1465 )
1466 {
1467 UINTN Index;
1468 UINT16 DriverString[12];
1469 UINT8 *LoadOptionFromVar;
1470 UINT8 *LoadOption;
1471 UINTN DriverOptionSize;
1472
1473 UINT16 *DriverOrderList;
1474 UINTN DriverOrderListSize;
1475 BM_MENU_ENTRY *NewMenuEntry;
1476 BM_LOAD_CONTEXT *NewLoadContext;
1477 UINT8 *LoadOptionPtr;
1478 UINTN StringSize;
1479 UINTN OptionalDataSize;
1480 UINT8 *LoadOptionEnd;
1481
1482 DriverOrderListSize = 0;
1483 DriverOrderList = NULL;
1484 DriverOptionSize = 0;
1485 LoadOptionFromVar = NULL;
1486 BOpt_FreeMenu (&DriverOptionMenu);
1487 InitializeListHead (&DriverOptionMenu.Head);
1488 //
1489 // Get the DriverOrder from the Var
1490 //
1491 DriverOrderList = BdsLibGetVariableAndSize (
1492 L"DriverOrder",
1493 &gEfiGlobalVariableGuid,
1494 &DriverOrderListSize
1495 );
1496 if (DriverOrderList == NULL) {
1497 return EFI_NOT_FOUND;
1498 }
1499
1500 for (Index = 0; Index < DriverOrderListSize / sizeof (UINT16); Index++) {
1501 UnicodeSPrint (
1502 DriverString,
1503 sizeof (DriverString),
1504 L"Driver%04x",
1505 DriverOrderList[Index]
1506 );
1507 //
1508 // Get all loadoptions from the VAR
1509 //
1510 LoadOptionFromVar = BdsLibGetVariableAndSize (
1511 DriverString,
1512 &gEfiGlobalVariableGuid,
1513 &DriverOptionSize
1514 );
1515 if (LoadOptionFromVar == NULL) {
1516 continue;
1517 }
1518
1519 LoadOption = AllocateZeroPool (DriverOptionSize);
1520 if (LoadOption == NULL) {
1521 continue;
1522 }
1523
1524 CopyMem (LoadOption, LoadOptionFromVar, DriverOptionSize);
1525 FreePool (LoadOptionFromVar);
1526
1527 NewMenuEntry = BOpt_CreateMenuEntry (BM_LOAD_CONTEXT_SELECT);
1528 if (NULL == NewMenuEntry) {
1529 return EFI_OUT_OF_RESOURCES;
1530 }
1531
1532 NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
1533 LoadOptionPtr = LoadOption;
1534 LoadOptionEnd = LoadOption + DriverOptionSize;
1535 NewMenuEntry->OptionNumber = DriverOrderList[Index];
1536 NewLoadContext->LoadOptionModified = FALSE;
1537 NewLoadContext->Deleted = FALSE;
1538 NewLoadContext->IsLegacy = FALSE;
1539
1540 //
1541 // LoadOption is a pointer type of UINT8
1542 // for easy use with following LOAD_OPTION
1543 // embedded in this struct
1544 //
1545 NewLoadContext->LoadOption = LoadOption;
1546 NewLoadContext->LoadOptionSize = DriverOptionSize;
1547
1548 NewLoadContext->Attributes = *(UINT32 *) LoadOptionPtr;
1549 NewLoadContext->IsActive = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_ACTIVE);
1550
1551 NewLoadContext->ForceReconnect = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_FORCE_RECONNECT);
1552
1553 LoadOptionPtr += sizeof (UINT32);
1554
1555 NewLoadContext->FilePathListLength = *(UINT16 *) LoadOptionPtr;
1556 LoadOptionPtr += sizeof (UINT16);
1557
1558 StringSize = StrSize ((UINT16 *) LoadOptionPtr);
1559 NewLoadContext->Description = AllocateZeroPool (StringSize);
1560 ASSERT (NewLoadContext->Description != NULL);
1561 CopyMem (
1562 NewLoadContext->Description,
1563 (UINT16 *) LoadOptionPtr,
1564 StringSize
1565 );
1566 NewMenuEntry->DisplayString = NewLoadContext->Description;
1567
1568 LoadOptionPtr += StringSize;
1569
1570 NewLoadContext->FilePathList = AllocateZeroPool (NewLoadContext->FilePathListLength);
1571 ASSERT (NewLoadContext->FilePathList != NULL);
1572 CopyMem (
1573 NewLoadContext->FilePathList,
1574 (EFI_DEVICE_PATH_PROTOCOL *) LoadOptionPtr,
1575 NewLoadContext->FilePathListLength
1576 );
1577
1578 NewMenuEntry->HelpString = DevicePathToStr (NewLoadContext->FilePathList);
1579 NewMenuEntry->DisplayStringToken = GetStringTokenFromDepository (
1580 CallbackData,
1581 DriverOptionStrDepository
1582 );
1583 NewMenuEntry->HelpStringToken = GetStringTokenFromDepository (
1584 CallbackData,
1585 DriverOptionHelpStrDepository
1586 );
1587 LoadOptionPtr += NewLoadContext->FilePathListLength;
1588
1589 if (LoadOptionPtr < LoadOptionEnd) {
1590 OptionalDataSize = DriverOptionSize -
1591 sizeof (UINT32) -
1592 sizeof (UINT16) -
1593 StringSize -
1594 NewLoadContext->FilePathListLength;
1595
1596 NewLoadContext->OptionalData = AllocateZeroPool (OptionalDataSize);
1597 ASSERT (NewLoadContext->OptionalData != NULL);
1598 CopyMem (
1599 NewLoadContext->OptionalData,
1600 LoadOptionPtr,
1601 OptionalDataSize
1602 );
1603
1604 NewLoadContext->OptionalDataSize = OptionalDataSize;
1605 }
1606
1607 InsertTailList (&DriverOptionMenu.Head, &NewMenuEntry->Link);
1608
1609 }
1610
1611 if (DriverOrderList != NULL) {
1612 FreePool (DriverOrderList);
1613 }
1614 DriverOptionMenu.MenuNumber = Index;
1615 return EFI_SUCCESS;
1616
1617 }
1618
1619 /**
1620 Get option number according to Boot#### and BootOrder variable.
1621 The value is saved as #### + 1.
1622
1623 @param CallbackData The BMM context data.
1624 **/
1625 VOID
1626 GetBootOrder (
1627 IN BMM_CALLBACK_DATA *CallbackData
1628 )
1629 {
1630 BMM_FAKE_NV_DATA *BmmConfig;
1631 UINT16 Index;
1632 UINT16 OptionOrderIndex;
1633 UINTN DeviceType;
1634 BM_MENU_ENTRY *NewMenuEntry;
1635 BM_LOAD_CONTEXT *NewLoadContext;
1636
1637 ASSERT (CallbackData != NULL);
1638
1639 DeviceType = (UINTN) -1;
1640 BmmConfig = &CallbackData->BmmFakeNvData;
1641 ZeroMem (BmmConfig->BootOptionOrder, sizeof (BmmConfig->BootOptionOrder));
1642
1643 for (Index = 0, OptionOrderIndex = 0; ((Index < BootOptionMenu.MenuNumber) &&
1644 (OptionOrderIndex < (sizeof (BmmConfig->BootOptionOrder) / sizeof (BmmConfig->BootOptionOrder[0]))));
1645 Index++) {
1646 NewMenuEntry = BOpt_GetMenuEntry (&BootOptionMenu, Index);
1647 NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
1648
1649 if (NewLoadContext->IsLegacy) {
1650 if (((BBS_BBS_DEVICE_PATH *) NewLoadContext->FilePathList)->DeviceType != DeviceType) {
1651 DeviceType = ((BBS_BBS_DEVICE_PATH *) NewLoadContext->FilePathList)->DeviceType;
1652 } else {
1653 //
1654 // Only show one legacy boot option for the same device type
1655 // assuming the boot options are grouped by the device type
1656 //
1657 continue;
1658 }
1659 }
1660 BmmConfig->BootOptionOrder[OptionOrderIndex++] = (UINT32) (NewMenuEntry->OptionNumber + 1);
1661 }
1662 }
1663
1664 /**
1665 According to LegacyDevOrder variable to get legacy FD\HD\CD\NET\BEV
1666 devices list .
1667
1668 @param CallbackData The BMM context data.
1669 **/
1670 VOID
1671 GetLegacyDeviceOrder (
1672 IN BMM_CALLBACK_DATA *CallbackData
1673 )
1674 {
1675 UINTN Index;
1676 UINTN OptionIndex;
1677 UINT16 PageIdList[5];
1678 UINTN PageNum;
1679 UINTN VarSize;
1680 UINT8 *VarData;
1681 UINT8 *WorkingVarData;
1682 LEGACY_DEV_ORDER_ENTRY *DevOrder;
1683 UINT16 VarDevOrder;
1684 UINT8 *DisMap;
1685 BM_MENU_OPTION *OptionMenu;
1686 BBS_TYPE BbsType;
1687 UINT8 *LegacyOrder;
1688 UINT8 *OldData;
1689 UINTN Pos;
1690 UINTN Bit;
1691
1692 ASSERT (CallbackData != NULL);
1693
1694 PageIdList[0] = FORM_SET_FD_ORDER_ID;
1695 PageIdList[1] = FORM_SET_HD_ORDER_ID;
1696 PageIdList[2] = FORM_SET_CD_ORDER_ID;
1697 PageIdList[3] = FORM_SET_NET_ORDER_ID;
1698 PageIdList[4] = FORM_SET_BEV_ORDER_ID;
1699 OptionMenu = NULL;
1700 BbsType = 0;
1701 LegacyOrder = NULL;
1702 OldData = NULL;
1703 DisMap = ZeroMem (CallbackData->BmmFakeNvData.DisableMap, sizeof (CallbackData->BmmFakeNvData.DisableMap));
1704 PageNum = sizeof (PageIdList) / sizeof (PageIdList[0]);
1705 VarData = BdsLibGetVariableAndSize (
1706 VAR_LEGACY_DEV_ORDER,
1707 &gEfiLegacyDevOrderVariableGuid,
1708 &VarSize
1709 );
1710
1711 for (Index = 0; Index < PageNum; Index++) {
1712 switch (PageIdList[Index]) {
1713
1714 case FORM_SET_FD_ORDER_ID:
1715 OptionMenu = (BM_MENU_OPTION *) &LegacyFDMenu;
1716 BbsType = BBS_FLOPPY;
1717 LegacyOrder = CallbackData->BmmFakeNvData.LegacyFD;
1718 OldData = CallbackData->BmmOldFakeNVData.LegacyFD;
1719 break;
1720
1721 case FORM_SET_HD_ORDER_ID:
1722 OptionMenu = (BM_MENU_OPTION *) &LegacyHDMenu;
1723 BbsType = BBS_HARDDISK;
1724 LegacyOrder = CallbackData->BmmFakeNvData.LegacyHD;
1725 OldData = CallbackData->BmmOldFakeNVData.LegacyHD;
1726 break;
1727
1728 case FORM_SET_CD_ORDER_ID:
1729 OptionMenu = (BM_MENU_OPTION *) &LegacyCDMenu;
1730 BbsType = BBS_CDROM;
1731 LegacyOrder = CallbackData->BmmFakeNvData.LegacyCD;
1732 OldData = CallbackData->BmmOldFakeNVData.LegacyCD;
1733 break;
1734
1735 case FORM_SET_NET_ORDER_ID:
1736 OptionMenu = (BM_MENU_OPTION *) &LegacyNETMenu;
1737 BbsType = BBS_EMBED_NETWORK;
1738 LegacyOrder = CallbackData->BmmFakeNvData.LegacyNET;
1739 OldData = CallbackData->BmmOldFakeNVData.LegacyNET;
1740 break;
1741
1742 default:
1743 ASSERT (PageIdList[Index] == FORM_SET_BEV_ORDER_ID);
1744 OptionMenu = (BM_MENU_OPTION *) &LegacyBEVMenu;
1745 BbsType = BBS_BEV_DEVICE;
1746 LegacyOrder = CallbackData->BmmFakeNvData.LegacyBEV;
1747 OldData = CallbackData->BmmOldFakeNVData.LegacyBEV;
1748 break;
1749 }
1750
1751 if (NULL != VarData) {
1752 WorkingVarData = VarData;
1753 DevOrder = (LEGACY_DEV_ORDER_ENTRY *) WorkingVarData;
1754 while (WorkingVarData < VarData + VarSize) {
1755 if (DevOrder->BbsType == BbsType) {
1756 break;
1757 }
1758
1759 WorkingVarData = (UINT8 *)((UINTN)WorkingVarData + sizeof (BBS_TYPE));
1760 WorkingVarData += *(UINT16 *) WorkingVarData;
1761 DevOrder = (LEGACY_DEV_ORDER_ENTRY *) WorkingVarData;
1762 }
1763 for (OptionIndex = 0; OptionIndex < OptionMenu->MenuNumber; OptionIndex++) {
1764 VarDevOrder = *(UINT16 *) ((UINTN) DevOrder + sizeof (BBS_TYPE) + sizeof (UINT16) + OptionIndex * sizeof (UINT16));
1765 if (0xFF00 == (VarDevOrder & 0xFF00)) {
1766 LegacyOrder[OptionIndex] = 0xFF;
1767 Pos = (VarDevOrder & 0xFF) / 8;
1768 Bit = 7 - ((VarDevOrder & 0xFF) % 8);
1769 DisMap[Pos] = (UINT8) (DisMap[Pos] | (UINT8) (1 << Bit));
1770 } else {
1771 LegacyOrder[OptionIndex] = (UINT8) (VarDevOrder & 0xFF);
1772 }
1773 }
1774 CopyMem (OldData, LegacyOrder, 100);
1775 }
1776 }
1777 }
1778
1779 /**
1780 Get driver option order from globalc DriverOptionMenu.
1781
1782 @param CallbackData The BMM context data.
1783
1784 **/
1785 VOID
1786 GetDriverOrder (
1787 IN BMM_CALLBACK_DATA *CallbackData
1788 )
1789 {
1790 BMM_FAKE_NV_DATA *BmmConfig;
1791 UINT16 Index;
1792 UINT16 OptionOrderIndex;
1793 UINTN DeviceType;
1794 BM_MENU_ENTRY *NewMenuEntry;
1795 BM_LOAD_CONTEXT *NewLoadContext;
1796
1797 ASSERT (CallbackData != NULL);
1798
1799 DeviceType = (UINTN) -1;
1800 BmmConfig = &CallbackData->BmmFakeNvData;
1801 ZeroMem (BmmConfig->DriverOptionOrder, sizeof (BmmConfig->DriverOptionOrder));
1802
1803 for (Index = 0, OptionOrderIndex = 0; ((Index < DriverOptionMenu.MenuNumber) &&
1804 (OptionOrderIndex < (sizeof (BmmConfig->DriverOptionOrder) / sizeof (BmmConfig->DriverOptionOrder[0]))));
1805 Index++) {
1806 NewMenuEntry = BOpt_GetMenuEntry (&DriverOptionMenu, Index);
1807 NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
1808
1809 if (NewLoadContext->IsLegacy) {
1810 if (((BBS_BBS_DEVICE_PATH *) NewLoadContext->FilePathList)->DeviceType != DeviceType) {
1811 DeviceType = ((BBS_BBS_DEVICE_PATH *) NewLoadContext->FilePathList)->DeviceType;
1812 } else {
1813 //
1814 // Only show one legacy boot option for the same device type
1815 // assuming the boot options are grouped by the device type
1816 //
1817 continue;
1818 }
1819 }
1820 BmmConfig->DriverOptionOrder[OptionOrderIndex++] = (UINT32) (NewMenuEntry->OptionNumber + 1);
1821 }
1822 }