]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/BdsDxe/BootMaint/BootOption.c
Remove SafeFreePool from MemoryAllocationLib as this API's name is misleading. Its...
[mirror_edk2.git] / MdeModulePkg / Universal / BdsDxe / BootMaint / BootOption.c
CommitLineData
fd6a62f3 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
93e3992d 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
fd6a62f3 17**/\r
93e3992d 18\r
19#include "BootMaint.h"\r
20#include "BBSsupport.h"\r
21\r
b30312ba 22/**\r
dce655e8 23 Create a menu entry give a Menu type.\r
b30312ba 24\r
dce655e8 25 @param MenuType The Menu type to be created.\r
b30312ba 26\r
dce655e8 27 @retval NULL If failed to create the menu.\r
28 @return The menu.\r
b30312ba 29\r
30**/\r
93e3992d 31BM_MENU_ENTRY *\r
32BOpt_CreateMenuEntry (\r
33 UINTN MenuType\r
34 )\r
93e3992d 35{\r
36 BM_MENU_ENTRY *MenuEntry;\r
37 UINTN ContextSize;\r
38\r
30394aa1 39 //\r
40 // Get context size according to menu type\r
41 //\r
93e3992d 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
93e3992d 70 }\r
71\r
30394aa1 72 if (ContextSize == 0) {\r
93e3992d 73 return NULL;\r
74 }\r
75\r
30394aa1 76 //\r
77 // Create new menu entry\r
78 //\r
dce655e8 79 MenuEntry = AllocateZeroPool (sizeof (BM_MENU_ENTRY));\r
93e3992d 80 if (NULL == MenuEntry) {\r
81 return MenuEntry;\r
82 }\r
83\r
dce655e8 84 MenuEntry->VariableContext = AllocateZeroPool (ContextSize);\r
93e3992d 85 if (NULL == MenuEntry->VariableContext) {\r
676df92c 86 FreePool (MenuEntry);\r
30394aa1 87 return NULL;\r
93e3992d 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
b30312ba 95/**\r
dce655e8 96 Free up all resource allocated for a BM_MENU_ENTRY.\r
b30312ba 97\r
dce655e8 98 @param MenuEntry A pointer to BM_MENU_ENTRY.\r
b30312ba 99\r
b30312ba 100**/\r
93e3992d 101VOID\r
102BOpt_DestroyMenuEntry (\r
103 BM_MENU_ENTRY *MenuEntry\r
104 )\r
93e3992d 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
676df92c 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
93e3992d 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
676df92c 131 FreePool (FileContext->DevicePath);\r
93e3992d 132 } else {\r
133 if (FileContext->FHandle != NULL) {\r
134 FileContext->FHandle->Close (FileContext->FHandle);\r
135 }\r
136 }\r
137\r
676df92c 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
93e3992d 145 break;\r
146\r
147 case BM_CONSOLE_CONTEXT_SELECT:\r
148 ConsoleContext = (BM_CONSOLE_CONTEXT *) MenuEntry->VariableContext;\r
676df92c 149 FreePool (ConsoleContext->DevicePath);\r
150 FreePool (ConsoleContext);\r
93e3992d 151 break;\r
152\r
153 case BM_TERMINAL_CONTEXT_SELECT:\r
154 TerminalContext = (BM_TERMINAL_CONTEXT *) MenuEntry->VariableContext;\r
676df92c 155 FreePool (TerminalContext->DevicePath);\r
156 FreePool (TerminalContext);\r
93e3992d 157 break;\r
158\r
159 case BM_HANDLE_CONTEXT_SELECT:\r
160 HandleContext = (BM_HANDLE_CONTEXT *) MenuEntry->VariableContext;\r
676df92c 161 FreePool (HandleContext);\r
93e3992d 162 break;\r
163\r
164 case BM_LEGACY_DEV_CONTEXT_SELECT:\r
165 LegacyDevContext = (BM_LEGACY_DEVICE_CONTEXT *) MenuEntry->VariableContext;\r
676df92c 166 FreePool (LegacyDevContext);\r
93e3992d 167\r
168 default:\r
169 break;\r
170 }\r
171\r
676df92c 172 FreePool (MenuEntry->DisplayString);\r
93e3992d 173 if (NULL != MenuEntry->HelpString) {\r
676df92c 174 FreePool (MenuEntry->HelpString);\r
93e3992d 175 }\r
176\r
676df92c 177 FreePool (MenuEntry);\r
93e3992d 178}\r
179\r
b30312ba 180/**\r
dce655e8 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
b30312ba 185\r
dce655e8 186 @param MenuOption The Menu Entry List to read the menu entry.\r
187 @param MenuNumber The index of Menu Entry.\r
b30312ba 188\r
dce655e8 189 @return The Menu Entry.\r
b30312ba 190\r
191**/\r
93e3992d 192BM_MENU_ENTRY *\r
193BOpt_GetMenuEntry (\r
194 BM_MENU_OPTION *MenuOption,\r
195 UINTN MenuNumber\r
196 )\r
93e3992d 197{\r
198 BM_MENU_ENTRY *NewMenuEntry;\r
199 UINTN Index;\r
200 LIST_ENTRY *List;\r
201\r
dce655e8 202 ASSERT (MenuNumber < MenuOption->MenuNumber);\r
93e3992d 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
b30312ba 214/**\r
dce655e8 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
b30312ba 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
93e3992d 226EFI_STATUS\r
227BOpt_FindFileSystem (\r
228 IN BMM_CALLBACK_DATA *CallbackData\r
229 )\r
93e3992d 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
dce655e8 285 Buffer = AllocateZeroPool (BlkIo->Media->BlockSize);\r
93e3992d 286 if (NULL == Buffer) {\r
676df92c 287 FreePool (BlkIoHandle);\r
93e3992d 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
676df92c 298 FreePool (Buffer);\r
93e3992d 299 }\r
300 }\r
676df92c 301 FreePool (BlkIoHandle);\r
93e3992d 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
676df92c 341 FreePool (SimpleFsHandle);\r
93e3992d 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
a78b08d1 350 if (FileContext->FHandle == NULL) {\r
93e3992d 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
dce655e8 384 MenuEntry->DisplayString = AllocateZeroPool (MAX_CHAR);\r
93e3992d 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
676df92c 399 FreePool (SimpleFsHandle);\r
93e3992d 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
676df92c 416 FreePool (LoadFileHandle);\r
93e3992d 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
dce655e8 431 MenuEntry->DisplayString = AllocateZeroPool (MAX_CHAR);\r
93e3992d 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
676df92c 447 FreePool (LoadFileHandle);\r
93e3992d 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
dce655e8 490 MenuEntry->DisplayString = AllocateZeroPool (MAX_CHAR);\r
93e3992d 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
dce655e8 510/**\r
744fc758 511 Free resources allocated in Allocate Rountine.\r
93e3992d 512\r
dce655e8 513 @param FreeMenu Menu to be freed\r
dce655e8 514**/\r
515VOID\r
516BOpt_FreeMenu (\r
517 BM_MENU_OPTION *FreeMenu\r
518 )\r
93e3992d 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
dce655e8 533/**\r
93e3992d 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
744fc758 538 @param CallbackData The BMM context data.\r
539 @param MenuEntry The Menu Entry.\r
93e3992d 540\r
744fc758 541 @retval EFI_SUCCESS Get files from current dir successfully.\r
542 @return Other value if can't get files from current dir.\r
93e3992d 543\r
dce655e8 544**/\r
545EFI_STATUS\r
546BOpt_FindFiles (\r
547 IN BMM_CALLBACK_DATA *CallbackData,\r
548 IN BM_MENU_ENTRY *MenuEntry\r
549 )\r
93e3992d 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
a78b08d1 585 if (DirInfo == NULL) {\r
93e3992d 586 return EFI_NOT_FOUND;\r
587 }\r
588\r
589 if (!(DirInfo->Attribute & EFI_FILE_DIRECTORY)) {\r
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
dce655e8 599 DirInfo = AllocateZeroPool (DirBufferSize);\r
a78b08d1 600 if (DirInfo == NULL) {\r
93e3992d 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
617 if ((DirInfo->Attribute & EFI_FILE_DIRECTORY && Pass == 2) ||\r
618 (!(DirInfo->Attribute & EFI_FILE_DIRECTORY) && Pass == 1)\r
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
627 if (!(BOpt_IsEfiImageName (DirInfo->FileName) || DirInfo->Attribute & EFI_FILE_DIRECTORY)) {\r
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
dce655e8 661 NewMenuEntry->DisplayString = AllocateZeroPool (BufferSize);\r
93e3992d 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
676df92c 685 FreePool (DirInfo);\r
93e3992d 686 return EFI_SUCCESS;\r
687}\r
688\r
dce655e8 689/**\r
93e3992d 690 Build the LegacyFDMenu LegacyHDMenu LegacyCDMenu according to LegacyBios.GetBbsInfo().\r
691\r
dce655e8 692 @retval EFI_SUCCESS The function complete successfully.\r
693 @retval EFI_OUT_OF_RESOURCES No enough memory to complete this function.\r
93e3992d 694\r
dce655e8 695**/\r
696EFI_STATUS\r
697BOpt_GetLegacyOptions (\r
698 VOID\r
699 )\r
93e3992d 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
dce655e8 777 NewLegacyDevContext->Description = AllocateZeroPool (StrSize (DescString));\r
93e3992d 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
dce655e8 827/**\r
828 Free out resouce allocated from Legacy Boot Options.\r
829\r
dce655e8 830**/\r
93e3992d 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
dce655e8 843/**\r
93e3992d 844\r
845 Build the BootOptionMenu according to BootOrder Variable.\r
dce655e8 846 This Routine will access the Boot#### to get EFI_LOAD_OPTION.\r
93e3992d 847\r
744fc758 848 @param CallbackData The BMM context data.\r
93e3992d 849\r
dce655e8 850 @return The number of the Var Boot####.\r
93e3992d 851\r
dce655e8 852**/\r
853EFI_STATUS\r
854BOpt_GetBootOptions (\r
855 IN BMM_CALLBACK_DATA *CallbackData\r
856 )\r
93e3992d 857{\r
858 UINTN Index;\r
859 UINT16 BootString[10];\r
860 UINT8 *LoadOptionFromVar;\r
861 UINT8 *LoadOption;\r
862 UINTN BootOptionSize;\r
863 BOOLEAN BootNextFlag;\r
864 UINT16 *BootOrderList;\r
865 UINTN BootOrderListSize;\r
866 UINT16 *BootNext;\r
867 UINTN BootNextSize;\r
868 BM_MENU_ENTRY *NewMenuEntry;\r
869 BM_LOAD_CONTEXT *NewLoadContext;\r
870 UINT8 *LoadOptionPtr;\r
871 UINTN StringSize;\r
872 UINTN OptionalDataSize;\r
873 UINT8 *LoadOptionEnd;\r
874 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
875 UINTN MenuCount;\r
876 UINT8 *Ptr;\r
877\r
878 MenuCount = 0;\r
879 BootOrderListSize = 0;\r
880 BootNextSize = 0;\r
881 BootOrderList = NULL;\r
882 BootNext = NULL;\r
883 LoadOptionFromVar = NULL;\r
884 BOpt_FreeMenu (&BootOptionMenu);\r
885 InitializeListHead (&BootOptionMenu.Head);\r
886\r
887 //\r
888 // Get the BootOrder from the Var\r
889 //\r
890 BootOrderList = BdsLibGetVariableAndSize (\r
891 L"BootOrder",\r
892 &gEfiGlobalVariableGuid,\r
893 &BootOrderListSize\r
894 );\r
895\r
896 //\r
897 // Get the BootNext from the Var\r
898 //\r
899 BootNext = BdsLibGetVariableAndSize (\r
900 L"BootNext",\r
901 &gEfiGlobalVariableGuid,\r
902 &BootNextSize\r
903 );\r
904\r
a78b08d1 905 if (BootNext != NULL) {\r
93e3992d 906 if (BootNextSize != sizeof (UINT16)) {\r
676df92c 907 FreePool (BootNext);\r
93e3992d 908 BootNext = NULL;\r
909 }\r
910 }\r
911\r
912 for (Index = 0; Index < BootOrderListSize / sizeof (UINT16); Index++) {\r
913 UnicodeSPrint (BootString, sizeof (BootString), L"Boot%04x", BootOrderList[Index]);\r
914 //\r
915 // Get all loadoptions from the VAR\r
916 //\r
917 LoadOptionFromVar = BdsLibGetVariableAndSize (\r
918 BootString,\r
919 &gEfiGlobalVariableGuid,\r
920 &BootOptionSize\r
921 );\r
a78b08d1 922 if (LoadOptionFromVar == NULL) {\r
93e3992d 923 continue;\r
924 }\r
925\r
dce655e8 926 LoadOption = AllocateZeroPool (BootOptionSize);\r
a78b08d1 927 if (LoadOption == NULL) {\r
93e3992d 928 continue;\r
929 }\r
930\r
931 CopyMem (LoadOption, LoadOptionFromVar, BootOptionSize);\r
676df92c 932 FreePool (LoadOptionFromVar);\r
93e3992d 933\r
a78b08d1 934 if (BootNext != NULL) {\r
93e3992d 935 BootNextFlag = (BOOLEAN) (*BootNext == BootOrderList[Index]);\r
936 } else {\r
937 BootNextFlag = FALSE;\r
938 }\r
939\r
940 if (0 == (*((UINT32 *) LoadOption) & LOAD_OPTION_ACTIVE)) {\r
676df92c 941 FreePool (LoadOption);\r
93e3992d 942 continue;\r
943 }\r
944 //\r
945 // BUGBUG: could not return EFI_OUT_OF_RESOURCES here directly.\r
946 // the buffer allocated already should be freed before returning.\r
947 //\r
948 NewMenuEntry = BOpt_CreateMenuEntry (BM_LOAD_CONTEXT_SELECT);\r
949 if (NULL == NewMenuEntry) {\r
950 return EFI_OUT_OF_RESOURCES;\r
951 }\r
952\r
953 NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;\r
954\r
955 LoadOptionPtr = LoadOption;\r
956 LoadOptionEnd = LoadOption + BootOptionSize;\r
957\r
958 NewMenuEntry->OptionNumber = BootOrderList[Index];\r
959 NewLoadContext->LoadOptionModified = FALSE;\r
960 NewLoadContext->Deleted = FALSE;\r
961 NewLoadContext->IsBootNext = BootNextFlag;\r
962\r
963 //\r
964 // Is a Legacy Device?\r
965 //\r
966 Ptr = (UINT8 *) LoadOption;\r
967\r
968 //\r
969 // Attribute = *(UINT32 *)Ptr;\r
970 //\r
971 Ptr += sizeof (UINT32);\r
972\r
973 //\r
974 // FilePathSize = *(UINT16 *)Ptr;\r
975 //\r
976 Ptr += sizeof (UINT16);\r
977\r
978 //\r
979 // Description = (CHAR16 *)Ptr;\r
980 //\r
981 Ptr += StrSize ((CHAR16 *) Ptr);\r
982\r
983 //\r
984 // Now Ptr point to Device Path\r
985 //\r
986 DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) Ptr;\r
987 if ((BBS_DEVICE_PATH == DevicePath->Type) && (BBS_BBS_DP == DevicePath->SubType)) {\r
988 NewLoadContext->IsLegacy = TRUE;\r
989 } else {\r
990 NewLoadContext->IsLegacy = FALSE;\r
991 }\r
992 //\r
993 // LoadOption is a pointer type of UINT8\r
994 // for easy use with following LOAD_OPTION\r
995 // embedded in this struct\r
996 //\r
997 NewLoadContext->LoadOption = LoadOption;\r
998 NewLoadContext->LoadOptionSize = BootOptionSize;\r
999\r
1000 NewLoadContext->Attributes = *(UINT32 *) LoadOptionPtr;\r
1001 NewLoadContext->IsActive = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_ACTIVE);\r
1002\r
1003 NewLoadContext->ForceReconnect = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_FORCE_RECONNECT);\r
1004\r
1005 LoadOptionPtr += sizeof (UINT32);\r
1006\r
1007 NewLoadContext->FilePathListLength = *(UINT16 *) LoadOptionPtr;\r
1008 LoadOptionPtr += sizeof (UINT16);\r
1009\r
1010 StringSize = StrSize ((UINT16 *) LoadOptionPtr);\r
dce655e8 1011 NewLoadContext->Description = AllocateZeroPool (StringSize);\r
93e3992d 1012 ASSERT (NewLoadContext->Description != NULL);\r
1013 CopyMem (\r
1014 NewLoadContext->Description,\r
1015 (UINT16 *) LoadOptionPtr,\r
1016 StringSize\r
1017 );\r
1018 NewMenuEntry->DisplayString = NewLoadContext->Description;\r
1019\r
1020 LoadOptionPtr += StringSize;\r
1021\r
dce655e8 1022 NewLoadContext->FilePathList = AllocateZeroPool (NewLoadContext->FilePathListLength);\r
93e3992d 1023 ASSERT (NewLoadContext->FilePathList != NULL);\r
1024 CopyMem (\r
1025 NewLoadContext->FilePathList,\r
1026 (EFI_DEVICE_PATH_PROTOCOL *) LoadOptionPtr,\r
1027 NewLoadContext->FilePathListLength\r
1028 );\r
1029\r
1030 NewMenuEntry->HelpString = DevicePathToStr (NewLoadContext->FilePathList);\r
1031 NewMenuEntry->DisplayStringToken = GetStringTokenFromDepository (\r
1032 CallbackData,\r
1033 BootOptionStrDepository\r
1034 );\r
1035 NewMenuEntry->HelpStringToken = GetStringTokenFromDepository (\r
1036 CallbackData,\r
1037 BootOptionHelpStrDepository\r
1038 );\r
1039 LoadOptionPtr += NewLoadContext->FilePathListLength;\r
1040\r
1041 if (LoadOptionPtr < LoadOptionEnd) {\r
1042 OptionalDataSize = BootOptionSize -\r
1043 sizeof (UINT32) -\r
1044 sizeof (UINT16) -\r
1045 StringSize -\r
1046 NewLoadContext->FilePathListLength;\r
1047\r
dce655e8 1048 NewLoadContext->OptionalData = AllocateZeroPool (OptionalDataSize);\r
93e3992d 1049 ASSERT (NewLoadContext->OptionalData != NULL);\r
1050 CopyMem (\r
1051 NewLoadContext->OptionalData,\r
1052 LoadOptionPtr,\r
1053 OptionalDataSize\r
1054 );\r
1055\r
1056 NewLoadContext->OptionalDataSize = OptionalDataSize;\r
1057 }\r
1058\r
1059 InsertTailList (&BootOptionMenu.Head, &NewMenuEntry->Link);\r
1060 MenuCount++;\r
1061 }\r
1062\r
676df92c 1063 if (BootNext != NULL) {\r
1064 FreePool (BootNext);\r
1065 }\r
1066 if (BootOrderList != NULL) {\r
1067 FreePool (BootOrderList);\r
1068 }\r
93e3992d 1069 BootOptionMenu.MenuNumber = MenuCount;\r
1070 return MenuCount;\r
1071}\r
1072\r
dce655e8 1073/**\r
cd4c1ac3 1074\r
dce655e8 1075 Append file name to existing file name.\r
cd4c1ac3 1076\r
dce655e8 1077 @param Str1 The existing file name\r
1078 @param Str2 The file name to be appended\r
cd4c1ac3 1079\r
dce655e8 1080 @return Allocate a new string to hold the appended result.\r
1081 Caller is responsible to free the returned string.\r
1082\r
1083**/\r
93e3992d 1084CHAR16 *\r
1085BOpt_AppendFileName (\r
1086 IN CHAR16 *Str1,\r
1087 IN CHAR16 *Str2\r
1088 )\r
93e3992d 1089{\r
1090 UINTN Size1;\r
1091 UINTN Size2;\r
1092 CHAR16 *Str;\r
11c11e4e 1093 CHAR16 *TmpStr;\r
93e3992d 1094 CHAR16 *Ptr;\r
1095 CHAR16 *LastSlash;\r
1096\r
1097 Size1 = StrSize (Str1);\r
1098 Size2 = StrSize (Str2);\r
dce655e8 1099 Str = AllocateZeroPool (Size1 + Size2 + sizeof (CHAR16));\r
93e3992d 1100 ASSERT (Str != NULL);\r
1101\r
11c11e4e 1102 TmpStr = AllocateZeroPool (Size1 + Size2 + sizeof (CHAR16)); \r
1103 ASSERT (TmpStr != NULL);\r
1104\r
93e3992d 1105 StrCat (Str, Str1);\r
1106 if (!((*Str == '\\') && (*(Str + 1) == 0))) {\r
1107 StrCat (Str, L"\\");\r
1108 }\r
1109\r
1110 StrCat (Str, Str2);\r
1111\r
1112 Ptr = Str;\r
1113 LastSlash = Str;\r
1114 while (*Ptr != 0) {\r
243324fc 1115 if (*Ptr == '\\' && *(Ptr + 1) == '.' && *(Ptr + 2) == '.' && *(Ptr + 3) == L'\\') {\r
93e3992d 1116 //\r
e02b6b95 1117 // Convert "\Name\..\" to "\"\r
93e3992d 1118 // DO NOT convert the .. if it is at the end of the string. This will\r
1119 // break the .. behavior in changing directories.\r
1120 //\r
11c11e4e 1121\r
1122 //\r
1123 // Use TmpStr as a backup, as StrCpy in BaseLib does not handle copy of two strings \r
1124 // that overlap.\r
1125 //\r
1126 StrCpy (TmpStr, Ptr + 3);\r
1127 StrCpy (LastSlash, TmpStr);\r
93e3992d 1128 Ptr = LastSlash;\r
1129 } else if (*Ptr == '\\' && *(Ptr + 1) == '.' && *(Ptr + 2) == '\\') {\r
1130 //\r
e02b6b95 1131 // Convert a "\.\" to a "\"\r
93e3992d 1132 //\r
11c11e4e 1133\r
1134 //\r
1135 // Use TmpStr as a backup, as StrCpy in BaseLib does not handle copy of two strings \r
1136 // that overlap.\r
1137 //\r
1138 StrCpy (TmpStr, Ptr + 2);\r
1139 StrCpy (Ptr, TmpStr);\r
93e3992d 1140 Ptr = LastSlash;\r
1141 } else if (*Ptr == '\\') {\r
1142 LastSlash = Ptr;\r
1143 }\r
1144\r
1145 Ptr++;\r
1146 }\r
1147\r
11c11e4e 1148 FreePool (TmpStr);\r
1149 \r
93e3992d 1150 return Str;\r
1151}\r
1152\r
dce655e8 1153/**\r
93e3992d 1154\r
93e3992d 1155 Check whether current FileName point to a valid\r
1156 Efi Image File.\r
1157\r
dce655e8 1158 @param FileName File need to be checked.\r
93e3992d 1159\r
dce655e8 1160 @retval TRUE Is Efi Image\r
1161 @retval FALSE Not a valid Efi Image\r
93e3992d 1162\r
dce655e8 1163**/\r
1164BOOLEAN\r
1165BOpt_IsEfiImageName (\r
1166 IN UINT16 *FileName\r
1167 )\r
93e3992d 1168{\r
1169 //\r
1170 // Search for ".efi" extension\r
1171 //\r
a78b08d1 1172 while (*FileName != L'\0') {\r
93e3992d 1173 if (FileName[0] == '.') {\r
1174 if (FileName[1] == 'e' || FileName[1] == 'E') {\r
1175 if (FileName[2] == 'f' || FileName[2] == 'F') {\r
1176 if (FileName[3] == 'i' || FileName[3] == 'I') {\r
1177 return TRUE;\r
1178 } else if (FileName[3] == 0x0000) {\r
1179 return FALSE;\r
1180 }\r
1181 } else if (FileName[2] == 0x0000) {\r
1182 return FALSE;\r
1183 }\r
1184 } else if (FileName[1] == 0x0000) {\r
1185 return FALSE;\r
1186 }\r
1187 }\r
1188\r
1189 FileName += 1;\r
1190 }\r
1191\r
1192 return FALSE;\r
1193}\r
1194\r
dce655e8 1195/**\r
93e3992d 1196\r
93e3992d 1197 Check whether current FileName point to a valid Efi Application\r
1198\r
dce655e8 1199 @param Dir Pointer to current Directory\r
1200 @param FileName Pointer to current File name.\r
93e3992d 1201\r
dce655e8 1202 @retval TRUE Is a valid Efi Application\r
1203 @retval FALSE not a valid Efi Application\r
93e3992d 1204\r
dce655e8 1205**/\r
1206BOOLEAN\r
1207BOpt_IsEfiApp (\r
1208 IN EFI_FILE_HANDLE Dir,\r
1209 IN UINT16 *FileName\r
1210 )\r
93e3992d 1211{\r
1212 UINTN BufferSize;\r
1213 EFI_IMAGE_DOS_HEADER DosHdr;\r
93e3992d 1214 UINT16 Subsystem;\r
1215 EFI_FILE_HANDLE File;\r
1216 EFI_STATUS Status;\r
1fbc8fcb 1217 EFI_IMAGE_OPTIONAL_HEADER_UNION PeHdr;\r
93e3992d 1218\r
1219 Status = Dir->Open (Dir, &File, FileName, EFI_FILE_MODE_READ, 0);\r
1220\r
1221 if (EFI_ERROR (Status)) {\r
1222 return FALSE;\r
1223 }\r
1224\r
1225 BufferSize = sizeof (EFI_IMAGE_DOS_HEADER);\r
1226 File->Read (File, &BufferSize, &DosHdr);\r
1227 if (DosHdr.e_magic != EFI_IMAGE_DOS_SIGNATURE) {\r
1228 File->Close (File);\r
1229 return FALSE;\r
1230 }\r
1231\r
1232 File->SetPosition (File, DosHdr.e_lfanew);\r
1fbc8fcb 1233 BufferSize = sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION);\r
93e3992d 1234 File->Read (File, &BufferSize, &PeHdr);\r
1fbc8fcb 1235 if (PeHdr.Pe32.Signature != EFI_IMAGE_NT_SIGNATURE) {\r
93e3992d 1236 File->Close (File);\r
1237 return FALSE;\r
1238 }\r
1239 //\r
1240 // Determine PE type and read subsytem\r
93e3992d 1241 //\r
1fbc8fcb
LG
1242 if (PeHdr.Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
1243 Subsystem = PeHdr.Pe32.OptionalHeader.Subsystem;\r
1244 } else if (PeHdr.Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {\r
1245 Subsystem = PeHdr.Pe32Plus.OptionalHeader.Subsystem;\r
93e3992d 1246 } else {\r
1247 return FALSE;\r
1248 }\r
1249\r
1250 if (Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) {\r
1251 File->Close (File);\r
1252 return TRUE;\r
1253 } else {\r
1254 File->Close (File);\r
1255 return FALSE;\r
1256 }\r
1257}\r
1258\r
dce655e8 1259/**\r
93e3992d 1260\r
93e3992d 1261 Find drivers that will be added as Driver#### variables from handles\r
1262 in current system environment\r
1263 All valid handles in the system except those consume SimpleFs, LoadFile\r
1264 are stored in DriverMenu for future use.\r
1265\r
dce655e8 1266 @retval EFI_SUCCESS The function complets successfully.\r
1267 @return Other value if failed to build the DriverMenu.\r
93e3992d 1268\r
dce655e8 1269**/\r
1270EFI_STATUS\r
1271BOpt_FindDrivers (\r
1272 VOID\r
1273 )\r
93e3992d 1274{\r
1275 UINTN NoDevicePathHandles;\r
1276 EFI_HANDLE *DevicePathHandle;\r
1277 UINTN Index;\r
1278 EFI_STATUS Status;\r
1279 BM_MENU_ENTRY *NewMenuEntry;\r
1280 BM_HANDLE_CONTEXT *NewHandleContext;\r
1281 EFI_HANDLE CurHandle;\r
1282 UINTN OptionNumber;\r
1283 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFs;\r
1284 EFI_LOAD_FILE_PROTOCOL *LoadFile;\r
1285\r
1286 SimpleFs = NULL;\r
1287 LoadFile = NULL;\r
1288\r
1289 InitializeListHead (&DriverMenu.Head);\r
1290\r
1291 //\r
1292 // At first, get all handles that support Device Path\r
1293 // protocol which is the basic requirement for\r
1294 // Driver####\r
1295 //\r
1296 Status = gBS->LocateHandleBuffer (\r
1297 ByProtocol,\r
1298 &gEfiDevicePathProtocolGuid,\r
1299 NULL,\r
1300 &NoDevicePathHandles,\r
1301 &DevicePathHandle\r
1302 );\r
1303 if (EFI_ERROR (Status)) {\r
1304 return Status;\r
1305 }\r
1306\r
1307 OptionNumber = 0;\r
1308 for (Index = 0; Index < NoDevicePathHandles; Index++) {\r
1309 CurHandle = DevicePathHandle[Index];\r
1310\r
93e3992d 1311 Status = gBS->HandleProtocol (\r
1312 CurHandle,\r
1313 &gEfiSimpleFileSystemProtocolGuid,\r
1314 (VOID **) &SimpleFs\r
1315 );\r
1316 if (Status == EFI_SUCCESS) {\r
1317 continue;\r
1318 }\r
1319\r
1320 Status = gBS->HandleProtocol (\r
1321 CurHandle,\r
1322 &gEfiLoadFileProtocolGuid,\r
1323 (VOID **) &LoadFile\r
1324 );\r
1325 if (Status == EFI_SUCCESS) {\r
1326 continue;\r
1327 }\r
1328\r
1329 NewMenuEntry = BOpt_CreateMenuEntry (BM_HANDLE_CONTEXT_SELECT);\r
1330 if (NULL == NewMenuEntry) {\r
676df92c 1331 FreePool (DevicePathHandle);\r
93e3992d 1332 return EFI_OUT_OF_RESOURCES;\r
1333 }\r
1334\r
1335 NewHandleContext = (BM_HANDLE_CONTEXT *) NewMenuEntry->VariableContext;\r
1336 NewHandleContext->Handle = CurHandle;\r
1337 NewHandleContext->DevicePath = DevicePathFromHandle (CurHandle);\r
1338 NewMenuEntry->DisplayString = DevicePathToStr (NewHandleContext->DevicePath);\r
1339 NewMenuEntry->HelpString = NULL;\r
1340 NewMenuEntry->OptionNumber = OptionNumber;\r
1341 OptionNumber++;\r
1342 InsertTailList (&DriverMenu.Head, &NewMenuEntry->Link);\r
1343\r
1344 }\r
676df92c 1345\r
1346 if (DevicePathHandle != NULL) {\r
1347 FreePool (DevicePathHandle);\r
1348 }\r
93e3992d 1349\r
1350 DriverMenu.MenuNumber = OptionNumber;\r
1351 return EFI_SUCCESS;\r
1352}\r
1353\r
dce655e8 1354/**\r
93e3992d 1355\r
dce655e8 1356 Get the Option Number that has not been allocated for use.\r
93e3992d 1357\r
dce655e8 1358 @return The available Option Number.\r
93e3992d 1359\r
dce655e8 1360**/\r
1361UINT16\r
1362BOpt_GetBootOptionNumber (\r
1363 VOID\r
1364 )\r
93e3992d 1365{\r
1366 BM_MENU_ENTRY *NewMenuEntry;\r
1367 UINT16 *BootOrderList;\r
1368 UINTN BootOrderListSize;\r
1369 UINT16 Number;\r
1370 UINTN Index;\r
1371 UINTN Index2;\r
1372 BOOLEAN Found;\r
1373 CHAR16 StrTemp[100];\r
1374 UINT16 *OptionBuffer;\r
1375 UINTN OptionSize;\r
1376\r
1377 BootOrderListSize = 0;\r
1378 BootOrderList = NULL;\r
1379\r
1380 BootOrderList = BdsLibGetVariableAndSize (\r
1381 L"BootOrder",\r
1382 &gEfiGlobalVariableGuid,\r
1383 &BootOrderListSize\r
1384 );\r
a78b08d1 1385 if (BootOrderList != NULL) {\r
93e3992d 1386 //\r
1387 // already have Boot####\r
1388 //\r
1389 // AlreadyBootNumbers = BootOrderListSize / sizeof(UINT16);\r
1390 //\r
1391 for (Index = 0; Index < BootOrderListSize / sizeof (UINT16); Index++) {\r
1392 Found = TRUE;\r
1393 for (Index2 = 0; Index2 < BootOptionMenu.MenuNumber; Index2++) {\r
1394 NewMenuEntry = BOpt_GetMenuEntry (&BootOptionMenu, Index2);\r
1395 if (Index == NewMenuEntry->OptionNumber) {\r
1396 Found = FALSE;\r
1397 break;\r
1398 }\r
1399 }\r
1400\r
1401 if (Found) {\r
dce655e8 1402 UnicodeSPrint (StrTemp, 100, L"Boot%04x", Index);\r
1403 DEBUG((DEBUG_ERROR,"INdex= %s\n", StrTemp));\r
1404 OptionBuffer = BdsLibGetVariableAndSize (\r
1405 StrTemp,\r
1406 &gEfiGlobalVariableGuid,\r
1407 &OptionSize\r
1408 );\r
1409 if (NULL == OptionBuffer) {\r
1410 break;\r
1411 }\r
93e3992d 1412 }\r
1413 }\r
1414 //\r
1415 // end for Index\r
1416 //\r
1417 Number = (UINT16) Index;\r
1418 } else {\r
1419 //\r
1420 // No Boot####\r
1421 //\r
1422 Number = 0;\r
1423 }\r
1424\r
1425 return Number;\r
1426}\r
1427\r
dce655e8 1428/**\r
93e3992d 1429\r
dce655e8 1430 Get the Option Number that is not in use.\r
93e3992d 1431\r
dce655e8 1432 @return The unused Option Number.\r
93e3992d 1433\r
dce655e8 1434**/\r
1435UINT16\r
1436BOpt_GetDriverOptionNumber (\r
1437 VOID\r
1438 )\r
93e3992d 1439{\r
1440 BM_MENU_ENTRY *NewMenuEntry;\r
1441 UINT16 *DriverOrderList;\r
1442 UINTN DriverOrderListSize;\r
1443 UINT16 Number;\r
1444 UINTN Index;\r
1445 UINTN Index2;\r
1446 BOOLEAN Found;\r
1447\r
1448 DriverOrderListSize = 0;\r
1449 DriverOrderList = NULL;\r
1450\r
1451 DriverOrderList = BdsLibGetVariableAndSize (\r
1452 L"DriverOrder",\r
1453 &gEfiGlobalVariableGuid,\r
1454 &DriverOrderListSize\r
1455 );\r
a78b08d1 1456 if (DriverOrderList != NULL) {\r
93e3992d 1457 //\r
1458 // already have Driver####\r
1459 //\r
1460 // AlreadyDriverNumbers = DriverOrderListSize / sizeof(UINT16);\r
1461 //\r
1462 for (Index = 0; Index < DriverOrderListSize / sizeof (UINT16); Index++) {\r
1463 Found = TRUE;\r
1464 for (Index2 = 0; Index2 < DriverOptionMenu.MenuNumber; Index2++) {\r
1465 NewMenuEntry = BOpt_GetMenuEntry (&DriverOptionMenu, Index2);\r
1466 if (Index == NewMenuEntry->OptionNumber) {\r
1467 Found = FALSE;\r
1468 break;\r
1469 }\r
1470 }\r
1471\r
1472 if (Found) {\r
1473 break;\r
1474 }\r
1475 }\r
1476 //\r
1477 // end for Index\r
1478 //\r
1479 Number = (UINT16) Index;\r
1480 } else {\r
1481 //\r
1482 // No Driver####\r
1483 //\r
1484 Number = 0;\r
1485 }\r
1486\r
1487 return Number;\r
1488}\r
1489\r
dce655e8 1490/**\r
93e3992d 1491\r
93e3992d 1492 Build up all DriverOptionMenu\r
1493\r
dce655e8 1494 @param CallbackData The BMM context data.\r
93e3992d 1495\r
dce655e8 1496 @return EFI_SUCESS The functin completes successfully.\r
1497 @retval EFI_OUT_OF_RESOURCES Not enough memory to compete the operation.\r
1498 \r
93e3992d 1499\r
dce655e8 1500**/\r
1501EFI_STATUS\r
1502BOpt_GetDriverOptions (\r
1503 IN BMM_CALLBACK_DATA *CallbackData\r
1504 )\r
93e3992d 1505{\r
1506 UINTN Index;\r
1507 UINT16 DriverString[12];\r
1508 UINT8 *LoadOptionFromVar;\r
1509 UINT8 *LoadOption;\r
1510 UINTN DriverOptionSize;\r
1511\r
1512 UINT16 *DriverOrderList;\r
1513 UINTN DriverOrderListSize;\r
1514 BM_MENU_ENTRY *NewMenuEntry;\r
1515 BM_LOAD_CONTEXT *NewLoadContext;\r
1516 UINT8 *LoadOptionPtr;\r
1517 UINTN StringSize;\r
1518 UINTN OptionalDataSize;\r
1519 UINT8 *LoadOptionEnd;\r
1520\r
1521 DriverOrderListSize = 0;\r
1522 DriverOrderList = NULL;\r
1523 DriverOptionSize = 0;\r
1524 LoadOptionFromVar = NULL;\r
1525 BOpt_FreeMenu (&DriverOptionMenu);\r
1526 InitializeListHead (&DriverOptionMenu.Head);\r
1527 //\r
1528 // Get the DriverOrder from the Var\r
1529 //\r
1530 DriverOrderList = BdsLibGetVariableAndSize (\r
1531 L"DriverOrder",\r
1532 &gEfiGlobalVariableGuid,\r
1533 &DriverOrderListSize\r
1534 );\r
1535\r
1536 for (Index = 0; Index < DriverOrderListSize / sizeof (UINT16); Index++) {\r
1537 UnicodeSPrint (\r
1538 DriverString,\r
1539 sizeof (DriverString),\r
1540 L"Driver%04x",\r
1541 DriverOrderList[Index]\r
1542 );\r
1543 //\r
1544 // Get all loadoptions from the VAR\r
1545 //\r
1546 LoadOptionFromVar = BdsLibGetVariableAndSize (\r
1547 DriverString,\r
1548 &gEfiGlobalVariableGuid,\r
1549 &DriverOptionSize\r
1550 );\r
a78b08d1 1551 if (LoadOptionFromVar == NULL) {\r
93e3992d 1552 continue;\r
1553 }\r
1554\r
dce655e8 1555 LoadOption = AllocateZeroPool (DriverOptionSize);\r
a78b08d1 1556 if (LoadOption == NULL) {\r
93e3992d 1557 continue;\r
1558 }\r
1559\r
1560 CopyMem (LoadOption, LoadOptionFromVar, DriverOptionSize);\r
676df92c 1561 FreePool (LoadOptionFromVar);\r
93e3992d 1562\r
1563 NewMenuEntry = BOpt_CreateMenuEntry (BM_LOAD_CONTEXT_SELECT);\r
1564 if (NULL == NewMenuEntry) {\r
1565 return EFI_OUT_OF_RESOURCES;\r
1566 }\r
1567\r
1568 NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;\r
1569 LoadOptionPtr = LoadOption;\r
1570 LoadOptionEnd = LoadOption + DriverOptionSize;\r
1571 NewMenuEntry->OptionNumber = DriverOrderList[Index];\r
1572 NewLoadContext->LoadOptionModified = FALSE;\r
1573 NewLoadContext->Deleted = FALSE;\r
1574 NewLoadContext->IsLegacy = FALSE;\r
1575\r
1576 //\r
1577 // LoadOption is a pointer type of UINT8\r
1578 // for easy use with following LOAD_OPTION\r
1579 // embedded in this struct\r
1580 //\r
1581 NewLoadContext->LoadOption = LoadOption;\r
1582 NewLoadContext->LoadOptionSize = DriverOptionSize;\r
1583\r
1584 NewLoadContext->Attributes = *(UINT32 *) LoadOptionPtr;\r
1585 NewLoadContext->IsActive = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_ACTIVE);\r
1586\r
1587 NewLoadContext->ForceReconnect = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_FORCE_RECONNECT);\r
1588\r
1589 LoadOptionPtr += sizeof (UINT32);\r
1590\r
1591 NewLoadContext->FilePathListLength = *(UINT16 *) LoadOptionPtr;\r
1592 LoadOptionPtr += sizeof (UINT16);\r
1593\r
1594 StringSize = StrSize ((UINT16 *) LoadOptionPtr);\r
dce655e8 1595 NewLoadContext->Description = AllocateZeroPool (StringSize);\r
93e3992d 1596 ASSERT (NewLoadContext->Description != NULL);\r
1597 CopyMem (\r
1598 NewLoadContext->Description,\r
1599 (UINT16 *) LoadOptionPtr,\r
1600 StringSize\r
1601 );\r
1602 NewMenuEntry->DisplayString = NewLoadContext->Description;\r
1603\r
1604 LoadOptionPtr += StringSize;\r
1605\r
dce655e8 1606 NewLoadContext->FilePathList = AllocateZeroPool (NewLoadContext->FilePathListLength);\r
93e3992d 1607 ASSERT (NewLoadContext->FilePathList != NULL);\r
1608 CopyMem (\r
1609 NewLoadContext->FilePathList,\r
1610 (EFI_DEVICE_PATH_PROTOCOL *) LoadOptionPtr,\r
1611 NewLoadContext->FilePathListLength\r
1612 );\r
1613\r
1614 NewMenuEntry->HelpString = DevicePathToStr (NewLoadContext->FilePathList);\r
1615 NewMenuEntry->DisplayStringToken = GetStringTokenFromDepository (\r
1616 CallbackData,\r
1617 DriverOptionStrDepository\r
1618 );\r
1619 NewMenuEntry->HelpStringToken = GetStringTokenFromDepository (\r
1620 CallbackData,\r
1621 DriverOptionHelpStrDepository\r
1622 );\r
1623 LoadOptionPtr += NewLoadContext->FilePathListLength;\r
1624\r
1625 if (LoadOptionPtr < LoadOptionEnd) {\r
1626 OptionalDataSize = DriverOptionSize -\r
1627 sizeof (UINT32) -\r
1628 sizeof (UINT16) -\r
1629 StringSize -\r
1630 NewLoadContext->FilePathListLength;\r
1631\r
dce655e8 1632 NewLoadContext->OptionalData = AllocateZeroPool (OptionalDataSize);\r
93e3992d 1633 ASSERT (NewLoadContext->OptionalData != NULL);\r
1634 CopyMem (\r
1635 NewLoadContext->OptionalData,\r
1636 LoadOptionPtr,\r
1637 OptionalDataSize\r
1638 );\r
1639\r
1640 NewLoadContext->OptionalDataSize = OptionalDataSize;\r
1641 }\r
1642\r
1643 InsertTailList (&DriverOptionMenu.Head, &NewMenuEntry->Link);\r
1644\r
1645 }\r
1646\r
676df92c 1647 if (DriverOrderList != NULL) {\r
1648 FreePool (DriverOrderList);\r
1649 }\r
93e3992d 1650 DriverOptionMenu.MenuNumber = Index;\r
1651 return EFI_SUCCESS;\r
1652\r
1653}\r
1654\r