]> git.proxmox.com Git - mirror_edk2.git/blame - IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/BootOption.c
1. Correct Col * Row string
[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
8Copyright (c) 2004 - 2008, Intel Corporation. <BR>\r
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
426 FileContext->DevicePath = DevicePathFromHandle (FileContext->Handle);\r
427\r
428 MenuEntry->HelpString = DevicePathToStr (FileContext->DevicePath);\r
429\r
430 TempStr = MenuEntry->HelpString;\r
431 MenuEntry->DisplayString = AllocateZeroPool (MAX_CHAR);\r
432 ASSERT (MenuEntry->DisplayString != NULL);\r
433 UnicodeSPrint (\r
434 MenuEntry->DisplayString,\r
435 MAX_CHAR,\r
436 L"Load File [%s]",\r
437 TempStr\r
438 );\r
439\r
440 MenuEntry->OptionNumber = OptionNumber;\r
441 OptionNumber++;\r
442 InsertTailList (&FsOptionMenu.Head, &MenuEntry->Link);\r
443 }\r
444 }\r
445\r
446 if (NoLoadFileHandles != 0) {\r
447 FreePool (LoadFileHandle);\r
448 }\r
449\r
450 //\r
451 // Add Legacy Boot Option Support Here\r
452 //\r
453 Status = gBS->LocateProtocol (\r
454 &gEfiLegacyBiosProtocolGuid,\r
455 NULL,\r
456 (VOID **) &LegacyBios\r
457 );\r
458 if (!EFI_ERROR (Status)) {\r
459\r
460 for (Index = BBS_TYPE_FLOPPY; Index <= BBS_TYPE_EMBEDDED_NETWORK; Index++) {\r
461 MenuEntry = BOpt_CreateMenuEntry (BM_FILE_CONTEXT_SELECT);\r
462 if (NULL == MenuEntry) {\r
463 return EFI_OUT_OF_RESOURCES;\r
464 }\r
465\r
466 FileContext = (BM_FILE_CONTEXT *) MenuEntry->VariableContext;\r
467\r
468 FileContext->IsRemovableMedia = FALSE;\r
469 FileContext->IsLoadFile = TRUE;\r
470 FileContext->IsBootLegacy = TRUE;\r
471 DeviceType = (UINT16) Index;\r
472 BbsDevicePathNode.Header.Type = BBS_DEVICE_PATH;\r
473 BbsDevicePathNode.Header.SubType = BBS_BBS_DP;\r
474 SetDevicePathNodeLength (\r
475 &BbsDevicePathNode.Header,\r
476 sizeof (BBS_BBS_DEVICE_PATH)\r
477 );\r
478 BbsDevicePathNode.DeviceType = DeviceType;\r
479 BbsDevicePathNode.StatusFlag = 0;\r
480 BbsDevicePathNode.String[0] = 0;\r
481 DevicePath = AppendDevicePathNode (\r
482 EndDevicePath,\r
483 (EFI_DEVICE_PATH_PROTOCOL *) &BbsDevicePathNode\r
484 );\r
485\r
486 FileContext->DevicePath = DevicePath;\r
487 MenuEntry->HelpString = DevicePathToStr (FileContext->DevicePath);\r
488\r
489 TempStr = MenuEntry->HelpString;\r
490 MenuEntry->DisplayString = AllocateZeroPool (MAX_CHAR);\r
491 ASSERT (MenuEntry->DisplayString != NULL);\r
492 UnicodeSPrint (\r
493 MenuEntry->DisplayString,\r
494 MAX_CHAR,\r
495 L"Boot Legacy [%s]",\r
496 TempStr\r
497 );\r
498 MenuEntry->OptionNumber = OptionNumber;\r
499 OptionNumber++;\r
500 InsertTailList (&FsOptionMenu.Head, &MenuEntry->Link);\r
501 }\r
502 }\r
503 //\r
504 // Remember how many file system options are here\r
505 //\r
506 FsOptionMenu.MenuNumber = OptionNumber;\r
507 return EFI_SUCCESS;\r
508}\r
509\r
510/**\r
511 Free resources allocated in Allocate Rountine.\r
512\r
513 @param FreeMenu Menu to be freed\r
514**/\r
515VOID\r
516BOpt_FreeMenu (\r
517 BM_MENU_OPTION *FreeMenu\r
518 )\r
519{\r
520 BM_MENU_ENTRY *MenuEntry;\r
521 while (!IsListEmpty (&FreeMenu->Head)) {\r
522 MenuEntry = CR (\r
523 FreeMenu->Head.ForwardLink,\r
524 BM_MENU_ENTRY,\r
525 Link,\r
526 BM_MENU_ENTRY_SIGNATURE\r
527 );\r
528 RemoveEntryList (&MenuEntry->Link);\r
529 BOpt_DestroyMenuEntry (MenuEntry);\r
530 }\r
531}\r
532\r
533/**\r
534 Find files under current directory\r
535 All files and sub-directories in current directory\r
536 will be stored in DirectoryMenu for future use.\r
537\r
538 @param CallbackData The BMM context data.\r
539 @param MenuEntry The Menu Entry.\r
540\r
541 @retval EFI_SUCCESS Get files from current dir successfully.\r
542 @return Other value if can't get files from current dir.\r
543\r
544**/\r
545EFI_STATUS\r
546BOpt_FindFiles (\r
547 IN BMM_CALLBACK_DATA *CallbackData,\r
548 IN BM_MENU_ENTRY *MenuEntry\r
549 )\r
550{\r
551 EFI_FILE_HANDLE NewDir;\r
552 EFI_FILE_HANDLE Dir;\r
553 EFI_FILE_INFO *DirInfo;\r
554 UINTN BufferSize;\r
555 UINTN DirBufferSize;\r
556 BM_MENU_ENTRY *NewMenuEntry;\r
557 BM_FILE_CONTEXT *FileContext;\r
558 BM_FILE_CONTEXT *NewFileContext;\r
559 UINTN Pass;\r
560 EFI_STATUS Status;\r
561 UINTN OptionNumber;\r
562\r
563 FileContext = (BM_FILE_CONTEXT *) MenuEntry->VariableContext;\r
564 Dir = FileContext->FHandle;\r
565 OptionNumber = 0;\r
566 //\r
567 // Open current directory to get files from it\r
568 //\r
569 Status = Dir->Open (\r
570 Dir,\r
571 &NewDir,\r
572 FileContext->FileName,\r
573 EFI_FILE_READ_ONLY,\r
574 0\r
575 );\r
576 if (!FileContext->IsRoot) {\r
577 Dir->Close (Dir);\r
578 }\r
579\r
580 if (EFI_ERROR (Status)) {\r
581 return Status;\r
582 }\r
583\r
584 DirInfo = EfiLibFileInfo (NewDir);\r
585 if (DirInfo == NULL) {\r
586 return EFI_NOT_FOUND;\r
587 }\r
588\r
7ec9caab 589 if ((DirInfo->Attribute & EFI_FILE_DIRECTORY) == 0) {\r
5c08e117 590 return EFI_INVALID_PARAMETER;\r
591 }\r
592\r
593 FileContext->DevicePath = FileDevicePath (\r
594 FileContext->Handle,\r
595 FileContext->FileName\r
596 );\r
597\r
598 DirBufferSize = sizeof (EFI_FILE_INFO) + 1024;\r
599 DirInfo = AllocateZeroPool (DirBufferSize);\r
600 if (DirInfo == NULL) {\r
601 return EFI_OUT_OF_RESOURCES;\r
602 }\r
603 //\r
604 // Get all files in current directory\r
605 // Pass 1 to get Directories\r
606 // Pass 2 to get files that are EFI images\r
607 //\r
608 for (Pass = 1; Pass <= 2; Pass++) {\r
609 NewDir->SetPosition (NewDir, 0);\r
610 for (;;) {\r
611 BufferSize = DirBufferSize;\r
612 Status = NewDir->Read (NewDir, &BufferSize, DirInfo);\r
613 if (EFI_ERROR (Status) || BufferSize == 0) {\r
614 break;\r
615 }\r
616\r
7ec9caab 617 if (((DirInfo->Attribute & EFI_FILE_DIRECTORY) != 0 && Pass == 2) ||\r
618 ((DirInfo->Attribute & EFI_FILE_DIRECTORY) == 0 && Pass == 1)\r
5c08e117 619 ) {\r
620 //\r
621 // Pass 1 is for Directories\r
622 // Pass 2 is for file names\r
623 //\r
624 continue;\r
625 }\r
626\r
7ec9caab 627 if (!(BOpt_IsEfiImageName (DirInfo->FileName) || (DirInfo->Attribute & EFI_FILE_DIRECTORY) != 0)) {\r
5c08e117 628 //\r
629 // Slip file unless it is a directory entry or a .EFI file\r
630 //\r
631 continue;\r
632 }\r
633\r
634 NewMenuEntry = BOpt_CreateMenuEntry (BM_FILE_CONTEXT_SELECT);\r
635 if (NULL == NewMenuEntry) {\r
636 return EFI_OUT_OF_RESOURCES;\r
637 }\r
638\r
639 NewFileContext = (BM_FILE_CONTEXT *) NewMenuEntry->VariableContext;\r
640 NewFileContext->Handle = FileContext->Handle;\r
641 NewFileContext->FileName = BOpt_AppendFileName (\r
642 FileContext->FileName,\r
643 DirInfo->FileName\r
644 );\r
645 NewFileContext->FHandle = NewDir;\r
646 NewFileContext->DevicePath = FileDevicePath (\r
647 NewFileContext->Handle,\r
648 NewFileContext->FileName\r
649 );\r
650 NewMenuEntry->HelpString = NULL;\r
651\r
652 MenuEntry->DisplayStringToken = GetStringTokenFromDepository (\r
653 CallbackData,\r
654 FileOptionStrDepository\r
655 );\r
656\r
657 NewFileContext->IsDir = (BOOLEAN) ((DirInfo->Attribute & EFI_FILE_DIRECTORY) == EFI_FILE_DIRECTORY);\r
658\r
659 if (NewFileContext->IsDir) {\r
660 BufferSize = StrLen (DirInfo->FileName) * 2 + 6;\r
661 NewMenuEntry->DisplayString = AllocateZeroPool (BufferSize);\r
662\r
663 UnicodeSPrint (\r
664 NewMenuEntry->DisplayString,\r
665 BufferSize,\r
666 L"<%s>",\r
667 DirInfo->FileName\r
668 );\r
669\r
670 } else {\r
671 NewMenuEntry->DisplayString = EfiStrDuplicate (DirInfo->FileName);\r
672 }\r
673\r
674 NewFileContext->IsRoot = FALSE;\r
675 NewFileContext->IsLoadFile = FALSE;\r
676 NewFileContext->IsRemovableMedia = FALSE;\r
677\r
678 NewMenuEntry->OptionNumber = OptionNumber;\r
679 OptionNumber++;\r
680 InsertTailList (&DirectoryMenu.Head, &NewMenuEntry->Link);\r
681 }\r
682 }\r
683\r
684 DirectoryMenu.MenuNumber = OptionNumber;\r
685 FreePool (DirInfo);\r
686 return EFI_SUCCESS;\r
687}\r
688\r
689/**\r
690 Build the LegacyFDMenu LegacyHDMenu LegacyCDMenu according to LegacyBios.GetBbsInfo().\r
691\r
692 @retval EFI_SUCCESS The function complete successfully.\r
693 @retval EFI_OUT_OF_RESOURCES No enough memory to complete this function.\r
694\r
695**/\r
696EFI_STATUS\r
697BOpt_GetLegacyOptions (\r
698 VOID\r
699 )\r
700{\r
701 BM_MENU_ENTRY *NewMenuEntry;\r
702 BM_LEGACY_DEVICE_CONTEXT *NewLegacyDevContext;\r
703 EFI_STATUS Status;\r
704 EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;\r
705 UINT16 HddCount;\r
706 HDD_INFO *HddInfo;\r
707 UINT16 BbsCount;\r
708 BBS_TABLE *BbsTable;\r
709 UINTN Index;\r
710 CHAR16 DescString[100];\r
711 UINTN FDNum;\r
712 UINTN HDNum;\r
713 UINTN CDNum;\r
714 UINTN NETNum;\r
715 UINTN BEVNum;\r
716\r
717 NewMenuEntry = NULL;\r
718 HddInfo = NULL;\r
719 BbsTable = NULL;\r
720 BbsCount = 0;\r
721\r
722 //\r
723 // Initialize Bbs Table Context from BBS info data\r
724 //\r
725 InitializeListHead (&LegacyFDMenu.Head);\r
726 InitializeListHead (&LegacyHDMenu.Head);\r
727 InitializeListHead (&LegacyCDMenu.Head);\r
728 InitializeListHead (&LegacyNETMenu.Head);\r
729 InitializeListHead (&LegacyBEVMenu.Head);\r
730\r
731 Status = gBS->LocateProtocol (\r
732 &gEfiLegacyBiosProtocolGuid,\r
733 NULL,\r
734 (VOID **) &LegacyBios\r
735 );\r
736 if (!EFI_ERROR (Status)) {\r
737 Status = LegacyBios->GetBbsInfo (\r
738 LegacyBios,\r
739 &HddCount,\r
740 &HddInfo,\r
741 &BbsCount,\r
742 &BbsTable\r
743 );\r
744 if (EFI_ERROR (Status)) {\r
745 return Status;\r
746 }\r
747 }\r
748\r
749 FDNum = 0;\r
750 HDNum = 0;\r
751 CDNum = 0;\r
752 NETNum = 0;\r
753 BEVNum = 0;\r
754\r
755 for (Index = 0; Index < BbsCount; Index++) {\r
756 if ((BBS_IGNORE_ENTRY == BbsTable[Index].BootPriority) ||\r
757 (BBS_DO_NOT_BOOT_FROM == BbsTable[Index].BootPriority)\r
758 ) {\r
759 continue;\r
760 }\r
761\r
762 NewMenuEntry = BOpt_CreateMenuEntry (BM_LEGACY_DEV_CONTEXT_SELECT);\r
763 if (NULL == NewMenuEntry) {\r
764 break;\r
765 }\r
766\r
767 NewLegacyDevContext = (BM_LEGACY_DEVICE_CONTEXT *) NewMenuEntry->VariableContext;\r
768 NewLegacyDevContext->BbsTable = &BbsTable[Index];\r
769 NewLegacyDevContext->Index = Index;\r
770 NewLegacyDevContext->BbsCount = BbsCount;\r
771 BdsBuildLegacyDevNameString (\r
772 &BbsTable[Index],\r
773 Index,\r
774 sizeof (DescString),\r
775 DescString\r
776 );\r
777 NewLegacyDevContext->Description = AllocateZeroPool (StrSize (DescString));\r
778 if (NULL == NewLegacyDevContext->Description) {\r
779 break;\r
780 }\r
781\r
782 CopyMem (NewLegacyDevContext->Description, DescString, StrSize (DescString));\r
783 NewMenuEntry->DisplayString = NewLegacyDevContext->Description;\r
784 NewMenuEntry->HelpString = NULL;\r
785\r
786 switch (BbsTable[Index].DeviceType) {\r
787 case BBS_FLOPPY:\r
788 InsertTailList (&LegacyFDMenu.Head, &NewMenuEntry->Link);\r
789 FDNum++;\r
790 break;\r
791\r
792 case BBS_HARDDISK:\r
793 InsertTailList (&LegacyHDMenu.Head, &NewMenuEntry->Link);\r
794 HDNum++;\r
795 break;\r
796\r
797 case BBS_CDROM:\r
798 InsertTailList (&LegacyCDMenu.Head, &NewMenuEntry->Link);\r
799 CDNum++;\r
800 break;\r
801\r
802 case BBS_EMBED_NETWORK:\r
803 InsertTailList (&LegacyNETMenu.Head, &NewMenuEntry->Link);\r
804 NETNum++;\r
805 break;\r
806\r
807 case BBS_BEV_DEVICE:\r
808 InsertTailList (&LegacyBEVMenu.Head, &NewMenuEntry->Link);\r
809 BEVNum++;\r
810 break;\r
811 }\r
812 }\r
813\r
814 if (Index != BbsCount) {\r
815 BOpt_FreeLegacyOptions ();\r
816 return EFI_OUT_OF_RESOURCES;\r
817 }\r
818\r
819 LegacyFDMenu.MenuNumber = FDNum;\r
820 LegacyHDMenu.MenuNumber = HDNum;\r
821 LegacyCDMenu.MenuNumber = CDNum;\r
822 LegacyNETMenu.MenuNumber = NETNum;\r
823 LegacyBEVMenu.MenuNumber = BEVNum;\r
824 return EFI_SUCCESS;\r
825}\r
826\r
827/**\r
828 Free out resouce allocated from Legacy Boot Options.\r
829\r
830**/\r
831VOID\r
832BOpt_FreeLegacyOptions (\r
833 VOID\r
834 )\r
835{\r
836 BOpt_FreeMenu (&LegacyFDMenu);\r
837 BOpt_FreeMenu (&LegacyHDMenu);\r
838 BOpt_FreeMenu (&LegacyCDMenu);\r
839 BOpt_FreeMenu (&LegacyNETMenu);\r
840 BOpt_FreeMenu (&LegacyBEVMenu);\r
841}\r
842\r
843/**\r
844\r
845 Build the BootOptionMenu according to BootOrder Variable.\r
846 This Routine will access the Boot#### to get EFI_LOAD_OPTION.\r
847\r
848 @param CallbackData The BMM context data.\r
849\r
850 @return EFI_NOT_FOUND Fail to find "BootOrder" variable.\r
851 @return EFI_SUCESS Success build boot option menu.\r
852\r
853**/\r
854EFI_STATUS\r
855BOpt_GetBootOptions (\r
856 IN BMM_CALLBACK_DATA *CallbackData\r
857 )\r
858{\r
859 UINTN Index;\r
860 UINT16 BootString[10];\r
861 UINT8 *LoadOptionFromVar;\r
862 UINT8 *LoadOption;\r
863 UINTN BootOptionSize;\r
864 BOOLEAN BootNextFlag;\r
865 UINT16 *BootOrderList;\r
866 UINTN BootOrderListSize;\r
867 UINT16 *BootNext;\r
868 UINTN BootNextSize;\r
869 BM_MENU_ENTRY *NewMenuEntry;\r
870 BM_LOAD_CONTEXT *NewLoadContext;\r
871 UINT8 *LoadOptionPtr;\r
872 UINTN StringSize;\r
873 UINTN OptionalDataSize;\r
874 UINT8 *LoadOptionEnd;\r
875 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
876 UINTN MenuCount;\r
877 UINT8 *Ptr;\r
5caec787 878 UINTN DevicePathType;\r
879 CHAR16 *HiiString;\r
880 \r
5c08e117 881 MenuCount = 0;\r
882 BootOrderListSize = 0;\r
883 BootNextSize = 0;\r
884 BootOrderList = NULL;\r
885 BootNext = NULL;\r
886 LoadOptionFromVar = NULL;\r
887 BOpt_FreeMenu (&BootOptionMenu);\r
888 InitializeListHead (&BootOptionMenu.Head);\r
889\r
890 //\r
891 // Get the BootOrder from the Var\r
892 //\r
893 BootOrderList = BdsLibGetVariableAndSize (\r
894 L"BootOrder",\r
895 &gEfiGlobalVariableGuid,\r
896 &BootOrderListSize\r
897 );\r
898 if (BootOrderList == NULL) {\r
899 return EFI_NOT_FOUND;\r
900 }\r
901 \r
902 //\r
903 // Get the BootNext from the Var\r
904 //\r
905 BootNext = BdsLibGetVariableAndSize (\r
906 L"BootNext",\r
907 &gEfiGlobalVariableGuid,\r
908 &BootNextSize\r
909 );\r
910\r
911 if (BootNext != NULL) {\r
912 if (BootNextSize != sizeof (UINT16)) {\r
913 FreePool (BootNext);\r
914 BootNext = NULL;\r
915 }\r
916 }\r
917\r
918 for (Index = 0; Index < BootOrderListSize / sizeof (UINT16); Index++) {\r
919 UnicodeSPrint (BootString, sizeof (BootString), L"Boot%04x", BootOrderList[Index]);\r
920 //\r
921 // Get all loadoptions from the VAR\r
922 //\r
923 LoadOptionFromVar = BdsLibGetVariableAndSize (\r
924 BootString,\r
925 &gEfiGlobalVariableGuid,\r
926 &BootOptionSize\r
927 );\r
928 if (LoadOptionFromVar == NULL) {\r
929 continue;\r
930 }\r
931\r
932 LoadOption = AllocateZeroPool (BootOptionSize);\r
933 if (LoadOption == NULL) {\r
934 continue;\r
935 }\r
936\r
937 CopyMem (LoadOption, LoadOptionFromVar, BootOptionSize);\r
938 FreePool (LoadOptionFromVar);\r
939\r
940 if (BootNext != NULL) {\r
941 BootNextFlag = (BOOLEAN) (*BootNext == BootOrderList[Index]);\r
942 } else {\r
943 BootNextFlag = FALSE;\r
944 }\r
945\r
946 if (0 == (*((UINT32 *) LoadOption) & LOAD_OPTION_ACTIVE)) {\r
947 FreePool (LoadOption);\r
948 continue;\r
949 }\r
950 //\r
951 // BUGBUG: could not return EFI_OUT_OF_RESOURCES here directly.\r
952 // the buffer allocated already should be freed before returning.\r
953 //\r
954 NewMenuEntry = BOpt_CreateMenuEntry (BM_LOAD_CONTEXT_SELECT);\r
955 if (NULL == NewMenuEntry) {\r
956 return EFI_OUT_OF_RESOURCES;\r
957 }\r
958\r
959 NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;\r
960\r
961 LoadOptionPtr = LoadOption;\r
962 LoadOptionEnd = LoadOption + BootOptionSize;\r
963\r
964 NewMenuEntry->OptionNumber = BootOrderList[Index];\r
965 NewLoadContext->LoadOptionModified = FALSE;\r
966 NewLoadContext->Deleted = FALSE;\r
967 NewLoadContext->IsBootNext = BootNextFlag;\r
968\r
969 //\r
970 // Is a Legacy Device?\r
971 //\r
972 Ptr = (UINT8 *) LoadOption;\r
973\r
974 //\r
975 // Attribute = *(UINT32 *)Ptr;\r
976 //\r
977 Ptr += sizeof (UINT32);\r
978\r
979 //\r
980 // FilePathSize = *(UINT16 *)Ptr;\r
981 //\r
982 Ptr += sizeof (UINT16);\r
983\r
984 //\r
985 // Description = (CHAR16 *)Ptr;\r
986 //\r
987 Ptr += StrSize ((CHAR16 *) Ptr);\r
988\r
989 //\r
990 // Now Ptr point to Device Path\r
991 //\r
992 DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) Ptr;\r
993 if ((BBS_DEVICE_PATH == DevicePath->Type) && (BBS_BBS_DP == DevicePath->SubType)) {\r
994 NewLoadContext->IsLegacy = TRUE;\r
995 } else {\r
996 NewLoadContext->IsLegacy = FALSE;\r
997 }\r
998 //\r
999 // LoadOption is a pointer type of UINT8\r
1000 // for easy use with following LOAD_OPTION\r
1001 // embedded in this struct\r
1002 //\r
1003 NewLoadContext->LoadOption = LoadOption;\r
1004 NewLoadContext->LoadOptionSize = BootOptionSize;\r
1005\r
1006 NewLoadContext->Attributes = *(UINT32 *) LoadOptionPtr;\r
1007 NewLoadContext->IsActive = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_ACTIVE);\r
1008\r
1009 NewLoadContext->ForceReconnect = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_FORCE_RECONNECT);\r
1010\r
1011 LoadOptionPtr += sizeof (UINT32);\r
1012\r
1013 NewLoadContext->FilePathListLength = *(UINT16 *) LoadOptionPtr;\r
1014 LoadOptionPtr += sizeof (UINT16);\r
5caec787 1015 \r
1016 StringSize = StrSize((UINT16*)LoadOptionPtr);\r
1017 //\r
1018 // Get Hii description string according to device path type\r
1019 //\r
1020 HiiString = NULL;\r
1021 DevicePathType = BdsGetBootTypeFromDevicePath (DevicePath);\r
1022 switch (DevicePathType) {\r
1023 case BDS_EFI_ACPI_FLOPPY_BOOT:\r
1024 HiiString = GetStringById (STRING_TOKEN (STR_DESCRIPTION_FLOPPY));\r
1025 break;\r
1026 case BDS_EFI_MESSAGE_SATA_BOOT:\r
1027 case BDS_EFI_MESSAGE_ATAPI_BOOT:\r
1028 case BDS_EFI_MEDIA_CDROM_BOOT:\r
1029 HiiString = GetStringById (STRING_TOKEN (STR_DESCRIPTION_DVD));\r
1030 break;\r
1031 case BDS_EFI_MESSAGE_USB_DEVICE_BOOT:\r
1032 HiiString = GetStringById (STRING_TOKEN (STR_DESCRIPTION_USB));\r
1033 break;\r
1034 case BDS_EFI_MESSAGE_SCSI_BOOT:\r
1035 HiiString = GetStringById (STRING_TOKEN (STR_DESCRIPTION_SCSI));\r
1036 break;\r
1037 case BDS_EFI_MESSAGE_MISC_BOOT:\r
1038 HiiString = GetStringById (STRING_TOKEN (STR_DESCRIPTION_MISC));\r
1039 break;\r
1040 case BDS_EFI_MESSAGE_MAC_BOOT:\r
1041 HiiString = GetStringById (STRING_TOKEN (STR_DESCRIPTION_NETWORK));\r
1042 break;\r
1043 case BBS_DEVICE_PATH:\r
1044 //\r
1045 // Do nothing for legacy boot option.\r
1046 //\r
1047 break; \r
1048 default:\r
1049 DEBUG((EFI_D_INFO, "Can not find HiiString for given device path type 0x%x\n", DevicePathType));\r
1050 }\r
1051 \r
1052 if (HiiString != NULL) {\r
7edfacbf 1053 NewLoadContext->Description = AllocateZeroPool(StringSize + StrSize(HiiString));\r
5caec787 1054 StrCpy (NewLoadContext->Description, HiiString);\r
1055 if (StrnCmp ((UINT16*)LoadOptionPtr, L"0", 1) != 0) {\r
1056 StrCat (NewLoadContext->Description, L" ");\r
1057 StrCat (NewLoadContext->Description, (UINT16*)LoadOptionPtr);\r
1058 } \r
1059 \r
1060 FreePool (HiiString);\r
1061 } else {\r
1062 NewLoadContext->Description = AllocateZeroPool (StrSize((UINT16*)LoadOptionPtr));\r
1063 StrCpy(NewLoadContext->Description, (UINT16*)LoadOptionPtr);\r
1064 }\r
1065 \r
5c08e117 1066 ASSERT (NewLoadContext->Description != NULL);\r
5c08e117 1067 NewMenuEntry->DisplayString = NewLoadContext->Description;\r
1068\r
1069 LoadOptionPtr += StringSize;\r
1070\r
1071 NewLoadContext->FilePathList = AllocateZeroPool (NewLoadContext->FilePathListLength);\r
1072 ASSERT (NewLoadContext->FilePathList != NULL);\r
1073 CopyMem (\r
1074 NewLoadContext->FilePathList,\r
1075 (EFI_DEVICE_PATH_PROTOCOL *) LoadOptionPtr,\r
1076 NewLoadContext->FilePathListLength\r
1077 );\r
1078\r
1079 NewMenuEntry->HelpString = DevicePathToStr (NewLoadContext->FilePathList);\r
1080 NewMenuEntry->DisplayStringToken = GetStringTokenFromDepository (\r
1081 CallbackData,\r
1082 BootOptionStrDepository\r
1083 );\r
1084 NewMenuEntry->HelpStringToken = GetStringTokenFromDepository (\r
1085 CallbackData,\r
1086 BootOptionHelpStrDepository\r
1087 );\r
1088 LoadOptionPtr += NewLoadContext->FilePathListLength;\r
1089\r
1090 if (LoadOptionPtr < LoadOptionEnd) {\r
1091 OptionalDataSize = BootOptionSize -\r
1092 sizeof (UINT32) -\r
1093 sizeof (UINT16) -\r
1094 StringSize -\r
1095 NewLoadContext->FilePathListLength;\r
1096\r
1097 NewLoadContext->OptionalData = AllocateZeroPool (OptionalDataSize);\r
1098 ASSERT (NewLoadContext->OptionalData != NULL);\r
1099 CopyMem (\r
1100 NewLoadContext->OptionalData,\r
1101 LoadOptionPtr,\r
1102 OptionalDataSize\r
1103 );\r
1104\r
1105 NewLoadContext->OptionalDataSize = OptionalDataSize;\r
1106 }\r
1107\r
1108 InsertTailList (&BootOptionMenu.Head, &NewMenuEntry->Link);\r
1109 MenuCount++;\r
1110 }\r
1111\r
1112 if (BootNext != NULL) {\r
1113 FreePool (BootNext);\r
1114 }\r
1115 if (BootOrderList != NULL) {\r
1116 FreePool (BootOrderList);\r
1117 }\r
1118 BootOptionMenu.MenuNumber = MenuCount;\r
1119 return EFI_SUCCESS;\r
1120}\r
1121\r
1122/**\r
1123\r
1124 Append file name to existing file name.\r
1125\r
1126 @param Str1 The existing file name\r
1127 @param Str2 The file name to be appended\r
1128\r
1129 @return Allocate a new string to hold the appended result.\r
1130 Caller is responsible to free the returned string.\r
1131\r
1132**/\r
1133CHAR16 *\r
1134BOpt_AppendFileName (\r
1135 IN CHAR16 *Str1,\r
1136 IN CHAR16 *Str2\r
1137 )\r
1138{\r
1139 UINTN Size1;\r
1140 UINTN Size2;\r
1141 CHAR16 *Str;\r
1142 CHAR16 *TmpStr;\r
1143 CHAR16 *Ptr;\r
1144 CHAR16 *LastSlash;\r
1145\r
1146 Size1 = StrSize (Str1);\r
1147 Size2 = StrSize (Str2);\r
1148 Str = AllocateZeroPool (Size1 + Size2 + sizeof (CHAR16));\r
1149 ASSERT (Str != NULL);\r
1150\r
1151 TmpStr = AllocateZeroPool (Size1 + Size2 + sizeof (CHAR16)); \r
1152 ASSERT (TmpStr != NULL);\r
1153\r
1154 StrCat (Str, Str1);\r
1155 if (!((*Str == '\\') && (*(Str + 1) == 0))) {\r
1156 StrCat (Str, L"\\");\r
1157 }\r
1158\r
1159 StrCat (Str, Str2);\r
1160\r
1161 Ptr = Str;\r
1162 LastSlash = Str;\r
1163 while (*Ptr != 0) {\r
1164 if (*Ptr == '\\' && *(Ptr + 1) == '.' && *(Ptr + 2) == '.' && *(Ptr + 3) == L'\\') {\r
1165 //\r
1166 // Convert "\Name\..\" to "\"\r
1167 // DO NOT convert the .. if it is at the end of the string. This will\r
1168 // break the .. behavior in changing directories.\r
1169 //\r
1170\r
1171 //\r
1172 // Use TmpStr as a backup, as StrCpy in BaseLib does not handle copy of two strings \r
1173 // that overlap.\r
1174 //\r
1175 StrCpy (TmpStr, Ptr + 3);\r
1176 StrCpy (LastSlash, TmpStr);\r
1177 Ptr = LastSlash;\r
1178 } else if (*Ptr == '\\' && *(Ptr + 1) == '.' && *(Ptr + 2) == '\\') {\r
1179 //\r
1180 // Convert a "\.\" to a "\"\r
1181 //\r
1182\r
1183 //\r
1184 // Use TmpStr as a backup, as StrCpy in BaseLib does not handle copy of two strings \r
1185 // that overlap.\r
1186 //\r
1187 StrCpy (TmpStr, Ptr + 2);\r
1188 StrCpy (Ptr, TmpStr);\r
1189 Ptr = LastSlash;\r
1190 } else if (*Ptr == '\\') {\r
1191 LastSlash = Ptr;\r
1192 }\r
1193\r
1194 Ptr++;\r
1195 }\r
1196\r
1197 FreePool (TmpStr);\r
1198 \r
1199 return Str;\r
1200}\r
1201\r
1202/**\r
1203\r
1204 Check whether current FileName point to a valid\r
1205 Efi Image File.\r
1206\r
1207 @param FileName File need to be checked.\r
1208\r
1209 @retval TRUE Is Efi Image\r
1210 @retval FALSE Not a valid Efi Image\r
1211\r
1212**/\r
1213BOOLEAN\r
1214BOpt_IsEfiImageName (\r
1215 IN UINT16 *FileName\r
1216 )\r
1217{\r
1218 //\r
1219 // Search for ".efi" extension\r
1220 //\r
1221 while (*FileName != L'\0') {\r
1222 if (FileName[0] == '.') {\r
1223 if (FileName[1] == 'e' || FileName[1] == 'E') {\r
1224 if (FileName[2] == 'f' || FileName[2] == 'F') {\r
1225 if (FileName[3] == 'i' || FileName[3] == 'I') {\r
1226 return TRUE;\r
1227 } else if (FileName[3] == 0x0000) {\r
1228 return FALSE;\r
1229 }\r
1230 } else if (FileName[2] == 0x0000) {\r
1231 return FALSE;\r
1232 }\r
1233 } else if (FileName[1] == 0x0000) {\r
1234 return FALSE;\r
1235 }\r
1236 }\r
1237\r
1238 FileName += 1;\r
1239 }\r
1240\r
1241 return FALSE;\r
1242}\r
1243\r
1244/**\r
1245\r
1246 Check whether current FileName point to a valid Efi Application\r
1247\r
1248 @param Dir Pointer to current Directory\r
1249 @param FileName Pointer to current File name.\r
1250\r
1251 @retval TRUE Is a valid Efi Application\r
1252 @retval FALSE not a valid Efi Application\r
1253\r
1254**/\r
1255BOOLEAN\r
1256BOpt_IsEfiApp (\r
1257 IN EFI_FILE_HANDLE Dir,\r
1258 IN UINT16 *FileName\r
1259 )\r
1260{\r
1261 UINTN BufferSize;\r
1262 EFI_IMAGE_DOS_HEADER DosHdr;\r
1263 UINT16 Subsystem;\r
1264 EFI_FILE_HANDLE File;\r
1265 EFI_STATUS Status;\r
1266 EFI_IMAGE_OPTIONAL_HEADER_UNION PeHdr;\r
1267\r
1268 Status = Dir->Open (Dir, &File, FileName, EFI_FILE_MODE_READ, 0);\r
1269\r
1270 if (EFI_ERROR (Status)) {\r
1271 return FALSE;\r
1272 }\r
1273\r
1274 BufferSize = sizeof (EFI_IMAGE_DOS_HEADER);\r
1275 File->Read (File, &BufferSize, &DosHdr);\r
1276 if (DosHdr.e_magic != EFI_IMAGE_DOS_SIGNATURE) {\r
1277 File->Close (File);\r
1278 return FALSE;\r
1279 }\r
1280\r
1281 File->SetPosition (File, DosHdr.e_lfanew);\r
1282 BufferSize = sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION);\r
1283 File->Read (File, &BufferSize, &PeHdr);\r
1284 if (PeHdr.Pe32.Signature != EFI_IMAGE_NT_SIGNATURE) {\r
1285 File->Close (File);\r
1286 return FALSE;\r
1287 }\r
1288 //\r
1289 // Determine PE type and read subsytem\r
1290 //\r
1291 if (PeHdr.Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
1292 Subsystem = PeHdr.Pe32.OptionalHeader.Subsystem;\r
1293 } else if (PeHdr.Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {\r
1294 Subsystem = PeHdr.Pe32Plus.OptionalHeader.Subsystem;\r
1295 } else {\r
1296 return FALSE;\r
1297 }\r
1298\r
1299 if (Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) {\r
1300 File->Close (File);\r
1301 return TRUE;\r
1302 } else {\r
1303 File->Close (File);\r
1304 return FALSE;\r
1305 }\r
1306}\r
1307\r
1308/**\r
1309\r
1310 Find drivers that will be added as Driver#### variables from handles\r
1311 in current system environment\r
1312 All valid handles in the system except those consume SimpleFs, LoadFile\r
1313 are stored in DriverMenu for future use.\r
1314\r
1315 @retval EFI_SUCCESS The function complets successfully.\r
1316 @return Other value if failed to build the DriverMenu.\r
1317\r
1318**/\r
1319EFI_STATUS\r
1320BOpt_FindDrivers (\r
1321 VOID\r
1322 )\r
1323{\r
1324 UINTN NoDevicePathHandles;\r
1325 EFI_HANDLE *DevicePathHandle;\r
1326 UINTN Index;\r
1327 EFI_STATUS Status;\r
1328 BM_MENU_ENTRY *NewMenuEntry;\r
1329 BM_HANDLE_CONTEXT *NewHandleContext;\r
1330 EFI_HANDLE CurHandle;\r
1331 UINTN OptionNumber;\r
1332 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFs;\r
1333 EFI_LOAD_FILE_PROTOCOL *LoadFile;\r
1334\r
1335 SimpleFs = NULL;\r
1336 LoadFile = NULL;\r
1337\r
1338 InitializeListHead (&DriverMenu.Head);\r
1339\r
1340 //\r
1341 // At first, get all handles that support Device Path\r
1342 // protocol which is the basic requirement for\r
1343 // Driver####\r
1344 //\r
1345 Status = gBS->LocateHandleBuffer (\r
1346 ByProtocol,\r
1347 &gEfiDevicePathProtocolGuid,\r
1348 NULL,\r
1349 &NoDevicePathHandles,\r
1350 &DevicePathHandle\r
1351 );\r
1352 if (EFI_ERROR (Status)) {\r
1353 return Status;\r
1354 }\r
1355\r
1356 OptionNumber = 0;\r
1357 for (Index = 0; Index < NoDevicePathHandles; Index++) {\r
1358 CurHandle = DevicePathHandle[Index];\r
1359\r
1360 Status = gBS->HandleProtocol (\r
1361 CurHandle,\r
1362 &gEfiSimpleFileSystemProtocolGuid,\r
1363 (VOID **) &SimpleFs\r
1364 );\r
1365 if (Status == EFI_SUCCESS) {\r
1366 continue;\r
1367 }\r
1368\r
1369 Status = gBS->HandleProtocol (\r
1370 CurHandle,\r
1371 &gEfiLoadFileProtocolGuid,\r
1372 (VOID **) &LoadFile\r
1373 );\r
1374 if (Status == EFI_SUCCESS) {\r
1375 continue;\r
1376 }\r
1377\r
1378 NewMenuEntry = BOpt_CreateMenuEntry (BM_HANDLE_CONTEXT_SELECT);\r
1379 if (NULL == NewMenuEntry) {\r
1380 FreePool (DevicePathHandle);\r
1381 return EFI_OUT_OF_RESOURCES;\r
1382 }\r
1383\r
1384 NewHandleContext = (BM_HANDLE_CONTEXT *) NewMenuEntry->VariableContext;\r
1385 NewHandleContext->Handle = CurHandle;\r
1386 NewHandleContext->DevicePath = DevicePathFromHandle (CurHandle);\r
1387 NewMenuEntry->DisplayString = DevicePathToStr (NewHandleContext->DevicePath);\r
1388 NewMenuEntry->HelpString = NULL;\r
1389 NewMenuEntry->OptionNumber = OptionNumber;\r
1390 OptionNumber++;\r
1391 InsertTailList (&DriverMenu.Head, &NewMenuEntry->Link);\r
1392\r
1393 }\r
1394\r
1395 if (DevicePathHandle != NULL) {\r
1396 FreePool (DevicePathHandle);\r
1397 }\r
1398\r
1399 DriverMenu.MenuNumber = OptionNumber;\r
1400 return EFI_SUCCESS;\r
1401}\r
1402\r
1403/**\r
1404\r
1405 Get the Option Number that has not been allocated for use.\r
1406\r
1407 @return The available Option Number.\r
1408\r
1409**/\r
1410UINT16\r
1411BOpt_GetBootOptionNumber (\r
1412 VOID\r
1413 )\r
1414{\r
1415 BM_MENU_ENTRY *NewMenuEntry;\r
1416 UINT16 *BootOrderList;\r
1417 UINTN BootOrderListSize;\r
1418 UINT16 Number;\r
1419 UINTN Index;\r
1420 UINTN Index2;\r
1421 BOOLEAN Found;\r
1422 CHAR16 StrTemp[100];\r
1423 UINT16 *OptionBuffer;\r
1424 UINTN OptionSize;\r
1425\r
1426 BootOrderListSize = 0;\r
1427 BootOrderList = NULL;\r
1428\r
1429 BootOrderList = BdsLibGetVariableAndSize (\r
1430 L"BootOrder",\r
1431 &gEfiGlobalVariableGuid,\r
1432 &BootOrderListSize\r
1433 );\r
1434 if (BootOrderList != NULL) {\r
1435 //\r
1436 // already have Boot####\r
1437 //\r
1438 // AlreadyBootNumbers = BootOrderListSize / sizeof(UINT16);\r
1439 //\r
1440 for (Index = 0; Index < BootOrderListSize / sizeof (UINT16); Index++) {\r
1441 Found = TRUE;\r
1442 for (Index2 = 0; Index2 < BootOptionMenu.MenuNumber; Index2++) {\r
1443 NewMenuEntry = BOpt_GetMenuEntry (&BootOptionMenu, Index2);\r
1444 if (Index == NewMenuEntry->OptionNumber) {\r
1445 Found = FALSE;\r
1446 break;\r
1447 }\r
1448 }\r
1449\r
1450 if (Found) {\r
1451 UnicodeSPrint (StrTemp, 100, L"Boot%04x", Index);\r
1452 DEBUG((DEBUG_ERROR,"INdex= %s\n", StrTemp));\r
1453 OptionBuffer = BdsLibGetVariableAndSize (\r
1454 StrTemp,\r
1455 &gEfiGlobalVariableGuid,\r
1456 &OptionSize\r
1457 );\r
1458 if (NULL == OptionBuffer) {\r
1459 break;\r
1460 }\r
1461 }\r
1462 }\r
1463 //\r
1464 // end for Index\r
1465 //\r
1466 Number = (UINT16) Index;\r
1467 } else {\r
1468 //\r
1469 // No Boot####\r
1470 //\r
1471 Number = 0;\r
1472 }\r
1473\r
1474 return Number;\r
1475}\r
1476\r
1477/**\r
1478\r
1479 Get the Option Number that is not in use.\r
1480\r
1481 @return The unused Option Number.\r
1482\r
1483**/\r
1484UINT16\r
1485BOpt_GetDriverOptionNumber (\r
1486 VOID\r
1487 )\r
1488{\r
1489 BM_MENU_ENTRY *NewMenuEntry;\r
1490 UINT16 *DriverOrderList;\r
1491 UINTN DriverOrderListSize;\r
1492 UINT16 Number;\r
1493 UINTN Index;\r
1494 UINTN Index2;\r
1495 BOOLEAN Found;\r
1496\r
1497 DriverOrderListSize = 0;\r
1498 DriverOrderList = NULL;\r
1499\r
1500 DriverOrderList = BdsLibGetVariableAndSize (\r
1501 L"DriverOrder",\r
1502 &gEfiGlobalVariableGuid,\r
1503 &DriverOrderListSize\r
1504 );\r
1505 if (DriverOrderList != NULL) {\r
1506 //\r
1507 // already have Driver####\r
1508 //\r
1509 // AlreadyDriverNumbers = DriverOrderListSize / sizeof(UINT16);\r
1510 //\r
1511 for (Index = 0; Index < DriverOrderListSize / sizeof (UINT16); Index++) {\r
1512 Found = TRUE;\r
1513 for (Index2 = 0; Index2 < DriverOptionMenu.MenuNumber; Index2++) {\r
1514 NewMenuEntry = BOpt_GetMenuEntry (&DriverOptionMenu, Index2);\r
1515 if (Index == NewMenuEntry->OptionNumber) {\r
1516 Found = FALSE;\r
1517 break;\r
1518 }\r
1519 }\r
1520\r
1521 if (Found) {\r
1522 break;\r
1523 }\r
1524 }\r
1525 //\r
1526 // end for Index\r
1527 //\r
1528 Number = (UINT16) Index;\r
1529 } else {\r
1530 //\r
1531 // No Driver####\r
1532 //\r
1533 Number = 0;\r
1534 }\r
1535\r
1536 return Number;\r
1537}\r
1538\r
1539/**\r
1540\r
1541 Build up all DriverOptionMenu\r
1542\r
1543 @param CallbackData The BMM context data.\r
1544\r
1545 @retval EFI_SUCESS The functin completes successfully.\r
1546 @retval EFI_OUT_OF_RESOURCES Not enough memory to compete the operation.\r
1547 @retval EFI_NOT_FOUND Fail to get "DriverOrder" variable.\r
1548\r
1549**/\r
1550EFI_STATUS\r
1551BOpt_GetDriverOptions (\r
1552 IN BMM_CALLBACK_DATA *CallbackData\r
1553 )\r
1554{\r
1555 UINTN Index;\r
1556 UINT16 DriverString[12];\r
1557 UINT8 *LoadOptionFromVar;\r
1558 UINT8 *LoadOption;\r
1559 UINTN DriverOptionSize;\r
1560\r
1561 UINT16 *DriverOrderList;\r
1562 UINTN DriverOrderListSize;\r
1563 BM_MENU_ENTRY *NewMenuEntry;\r
1564 BM_LOAD_CONTEXT *NewLoadContext;\r
1565 UINT8 *LoadOptionPtr;\r
1566 UINTN StringSize;\r
1567 UINTN OptionalDataSize;\r
1568 UINT8 *LoadOptionEnd;\r
1569\r
1570 DriverOrderListSize = 0;\r
1571 DriverOrderList = NULL;\r
1572 DriverOptionSize = 0;\r
1573 LoadOptionFromVar = NULL;\r
1574 BOpt_FreeMenu (&DriverOptionMenu);\r
1575 InitializeListHead (&DriverOptionMenu.Head);\r
1576 //\r
1577 // Get the DriverOrder from the Var\r
1578 //\r
1579 DriverOrderList = BdsLibGetVariableAndSize (\r
1580 L"DriverOrder",\r
1581 &gEfiGlobalVariableGuid,\r
1582 &DriverOrderListSize\r
1583 );\r
1584 if (DriverOrderList == NULL) {\r
1585 return EFI_NOT_FOUND;\r
1586 }\r
1587 \r
1588 for (Index = 0; Index < DriverOrderListSize / sizeof (UINT16); Index++) {\r
1589 UnicodeSPrint (\r
1590 DriverString,\r
1591 sizeof (DriverString),\r
1592 L"Driver%04x",\r
1593 DriverOrderList[Index]\r
1594 );\r
1595 //\r
1596 // Get all loadoptions from the VAR\r
1597 //\r
1598 LoadOptionFromVar = BdsLibGetVariableAndSize (\r
1599 DriverString,\r
1600 &gEfiGlobalVariableGuid,\r
1601 &DriverOptionSize\r
1602 );\r
1603 if (LoadOptionFromVar == NULL) {\r
1604 continue;\r
1605 }\r
1606\r
1607 LoadOption = AllocateZeroPool (DriverOptionSize);\r
1608 if (LoadOption == NULL) {\r
1609 continue;\r
1610 }\r
1611\r
1612 CopyMem (LoadOption, LoadOptionFromVar, DriverOptionSize);\r
1613 FreePool (LoadOptionFromVar);\r
1614\r
1615 NewMenuEntry = BOpt_CreateMenuEntry (BM_LOAD_CONTEXT_SELECT);\r
1616 if (NULL == NewMenuEntry) {\r
1617 return EFI_OUT_OF_RESOURCES;\r
1618 }\r
1619\r
1620 NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;\r
1621 LoadOptionPtr = LoadOption;\r
1622 LoadOptionEnd = LoadOption + DriverOptionSize;\r
1623 NewMenuEntry->OptionNumber = DriverOrderList[Index];\r
1624 NewLoadContext->LoadOptionModified = FALSE;\r
1625 NewLoadContext->Deleted = FALSE;\r
1626 NewLoadContext->IsLegacy = FALSE;\r
1627\r
1628 //\r
1629 // LoadOption is a pointer type of UINT8\r
1630 // for easy use with following LOAD_OPTION\r
1631 // embedded in this struct\r
1632 //\r
1633 NewLoadContext->LoadOption = LoadOption;\r
1634 NewLoadContext->LoadOptionSize = DriverOptionSize;\r
1635\r
1636 NewLoadContext->Attributes = *(UINT32 *) LoadOptionPtr;\r
1637 NewLoadContext->IsActive = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_ACTIVE);\r
1638\r
1639 NewLoadContext->ForceReconnect = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_FORCE_RECONNECT);\r
1640\r
1641 LoadOptionPtr += sizeof (UINT32);\r
1642\r
1643 NewLoadContext->FilePathListLength = *(UINT16 *) LoadOptionPtr;\r
1644 LoadOptionPtr += sizeof (UINT16);\r
1645\r
1646 StringSize = StrSize ((UINT16 *) LoadOptionPtr);\r
1647 NewLoadContext->Description = AllocateZeroPool (StringSize);\r
1648 ASSERT (NewLoadContext->Description != NULL);\r
1649 CopyMem (\r
1650 NewLoadContext->Description,\r
1651 (UINT16 *) LoadOptionPtr,\r
1652 StringSize\r
1653 );\r
1654 NewMenuEntry->DisplayString = NewLoadContext->Description;\r
1655\r
1656 LoadOptionPtr += StringSize;\r
1657\r
1658 NewLoadContext->FilePathList = AllocateZeroPool (NewLoadContext->FilePathListLength);\r
1659 ASSERT (NewLoadContext->FilePathList != NULL);\r
1660 CopyMem (\r
1661 NewLoadContext->FilePathList,\r
1662 (EFI_DEVICE_PATH_PROTOCOL *) LoadOptionPtr,\r
1663 NewLoadContext->FilePathListLength\r
1664 );\r
1665\r
1666 NewMenuEntry->HelpString = DevicePathToStr (NewLoadContext->FilePathList);\r
1667 NewMenuEntry->DisplayStringToken = GetStringTokenFromDepository (\r
1668 CallbackData,\r
1669 DriverOptionStrDepository\r
1670 );\r
1671 NewMenuEntry->HelpStringToken = GetStringTokenFromDepository (\r
1672 CallbackData,\r
1673 DriverOptionHelpStrDepository\r
1674 );\r
1675 LoadOptionPtr += NewLoadContext->FilePathListLength;\r
1676\r
1677 if (LoadOptionPtr < LoadOptionEnd) {\r
1678 OptionalDataSize = DriverOptionSize -\r
1679 sizeof (UINT32) -\r
1680 sizeof (UINT16) -\r
1681 StringSize -\r
1682 NewLoadContext->FilePathListLength;\r
1683\r
1684 NewLoadContext->OptionalData = AllocateZeroPool (OptionalDataSize);\r
1685 ASSERT (NewLoadContext->OptionalData != NULL);\r
1686 CopyMem (\r
1687 NewLoadContext->OptionalData,\r
1688 LoadOptionPtr,\r
1689 OptionalDataSize\r
1690 );\r
1691\r
1692 NewLoadContext->OptionalDataSize = OptionalDataSize;\r
1693 }\r
1694\r
1695 InsertTailList (&DriverOptionMenu.Head, &NewMenuEntry->Link);\r
1696\r
1697 }\r
1698\r
1699 if (DriverOrderList != NULL) {\r
1700 FreePool (DriverOrderList);\r
1701 }\r
1702 DriverOptionMenu.MenuNumber = Index;\r
1703 return EFI_SUCCESS;\r
1704\r
1705}\r
1706\r