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