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