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