BootOption.c 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017
  1. /** @file
  2. Provide boot option support for Application "BootMaint"
  3. Include file system navigation, system handle selection
  4. Boot option manipulation
  5. Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
  6. SPDX-License-Identifier: BSD-2-Clause-Patent
  7. **/
  8. #include "BootMaintenanceManager.h"
  9. ///
  10. /// Define the maximum characters that will be accepted.
  11. ///
  12. #define MAX_CHAR 480
  13. /**
  14. Check whether a reset is needed, if reset is needed, Popup a menu to notice user.
  15. **/
  16. VOID
  17. BmmSetupResetReminder (
  18. VOID
  19. )
  20. {
  21. EFI_INPUT_KEY Key;
  22. CHAR16 *StringBuffer1;
  23. CHAR16 *StringBuffer2;
  24. EFI_STATUS Status;
  25. EDKII_FORM_BROWSER_EXTENSION2_PROTOCOL *FormBrowserEx2;
  26. //
  27. // Use BrowserEx2 protocol to check whether reset is required.
  28. //
  29. Status = gBS->LocateProtocol (&gEdkiiFormBrowserEx2ProtocolGuid, NULL, (VOID **)&FormBrowserEx2);
  30. //
  31. // check any reset required change is applied? if yes, reset system
  32. //
  33. if (!EFI_ERROR (Status) && FormBrowserEx2->IsResetRequired ()) {
  34. StringBuffer1 = AllocateZeroPool (MAX_CHAR * sizeof (CHAR16));
  35. ASSERT (StringBuffer1 != NULL);
  36. StringBuffer2 = AllocateZeroPool (MAX_CHAR * sizeof (CHAR16));
  37. ASSERT (StringBuffer2 != NULL);
  38. StrCpyS (StringBuffer1, MAX_CHAR, L"Configuration changed. Reset to apply it Now.");
  39. StrCpyS (StringBuffer2, MAX_CHAR, L"Press ENTER to reset");
  40. //
  41. // Popup a menu to notice user
  42. //
  43. do {
  44. CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, StringBuffer1, StringBuffer2, NULL);
  45. } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
  46. FreePool (StringBuffer1);
  47. FreePool (StringBuffer2);
  48. gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL);
  49. }
  50. }
  51. /**
  52. Create a menu entry by given menu type.
  53. @param MenuType The Menu type to be created.
  54. @retval NULL If failed to create the menu.
  55. @return the new menu entry.
  56. **/
  57. BM_MENU_ENTRY *
  58. BOpt_CreateMenuEntry (
  59. UINTN MenuType
  60. )
  61. {
  62. BM_MENU_ENTRY *MenuEntry;
  63. UINTN ContextSize;
  64. //
  65. // Get context size according to menu type
  66. //
  67. switch (MenuType) {
  68. case BM_LOAD_CONTEXT_SELECT:
  69. ContextSize = sizeof (BM_LOAD_CONTEXT);
  70. break;
  71. case BM_FILE_CONTEXT_SELECT:
  72. ContextSize = sizeof (BM_FILE_CONTEXT);
  73. break;
  74. case BM_CONSOLE_CONTEXT_SELECT:
  75. ContextSize = sizeof (BM_CONSOLE_CONTEXT);
  76. break;
  77. case BM_TERMINAL_CONTEXT_SELECT:
  78. ContextSize = sizeof (BM_TERMINAL_CONTEXT);
  79. break;
  80. case BM_HANDLE_CONTEXT_SELECT:
  81. ContextSize = sizeof (BM_HANDLE_CONTEXT);
  82. break;
  83. default:
  84. ContextSize = 0;
  85. break;
  86. }
  87. if (ContextSize == 0) {
  88. return NULL;
  89. }
  90. //
  91. // Create new menu entry
  92. //
  93. MenuEntry = AllocateZeroPool (sizeof (BM_MENU_ENTRY));
  94. if (MenuEntry == NULL) {
  95. return NULL;
  96. }
  97. MenuEntry->VariableContext = AllocateZeroPool (ContextSize);
  98. if (MenuEntry->VariableContext == NULL) {
  99. FreePool (MenuEntry);
  100. return NULL;
  101. }
  102. MenuEntry->Signature = BM_MENU_ENTRY_SIGNATURE;
  103. MenuEntry->ContextSelection = MenuType;
  104. return MenuEntry;
  105. }
  106. /**
  107. Free up all resource allocated for a BM_MENU_ENTRY.
  108. @param MenuEntry A pointer to BM_MENU_ENTRY.
  109. **/
  110. VOID
  111. BOpt_DestroyMenuEntry (
  112. BM_MENU_ENTRY *MenuEntry
  113. )
  114. {
  115. BM_LOAD_CONTEXT *LoadContext;
  116. BM_FILE_CONTEXT *FileContext;
  117. BM_CONSOLE_CONTEXT *ConsoleContext;
  118. BM_TERMINAL_CONTEXT *TerminalContext;
  119. BM_HANDLE_CONTEXT *HandleContext;
  120. //
  121. // Select by the type in Menu entry for current context type
  122. //
  123. switch (MenuEntry->ContextSelection) {
  124. case BM_LOAD_CONTEXT_SELECT:
  125. LoadContext = (BM_LOAD_CONTEXT *)MenuEntry->VariableContext;
  126. FreePool (LoadContext->FilePathList);
  127. if (LoadContext->OptionalData != NULL) {
  128. FreePool (LoadContext->OptionalData);
  129. }
  130. FreePool (LoadContext);
  131. break;
  132. case BM_FILE_CONTEXT_SELECT:
  133. FileContext = (BM_FILE_CONTEXT *)MenuEntry->VariableContext;
  134. if (!FileContext->IsRoot) {
  135. FreePool (FileContext->DevicePath);
  136. } else {
  137. if (FileContext->FHandle != NULL) {
  138. FileContext->FHandle->Close (FileContext->FHandle);
  139. }
  140. }
  141. if (FileContext->FileName != NULL) {
  142. FreePool (FileContext->FileName);
  143. }
  144. if (FileContext->Info != NULL) {
  145. FreePool (FileContext->Info);
  146. }
  147. FreePool (FileContext);
  148. break;
  149. case BM_CONSOLE_CONTEXT_SELECT:
  150. ConsoleContext = (BM_CONSOLE_CONTEXT *)MenuEntry->VariableContext;
  151. FreePool (ConsoleContext->DevicePath);
  152. FreePool (ConsoleContext);
  153. break;
  154. case BM_TERMINAL_CONTEXT_SELECT:
  155. TerminalContext = (BM_TERMINAL_CONTEXT *)MenuEntry->VariableContext;
  156. FreePool (TerminalContext->DevicePath);
  157. FreePool (TerminalContext);
  158. break;
  159. case BM_HANDLE_CONTEXT_SELECT:
  160. HandleContext = (BM_HANDLE_CONTEXT *)MenuEntry->VariableContext;
  161. FreePool (HandleContext);
  162. break;
  163. default:
  164. break;
  165. }
  166. FreePool (MenuEntry->DisplayString);
  167. if (MenuEntry->HelpString != NULL) {
  168. FreePool (MenuEntry->HelpString);
  169. }
  170. FreePool (MenuEntry);
  171. }
  172. /**
  173. Get the Menu Entry from the list in Menu Entry List.
  174. If MenuNumber is great or equal to the number of Menu
  175. Entry in the list, then ASSERT.
  176. @param MenuOption The Menu Entry List to read the menu entry.
  177. @param MenuNumber The index of Menu Entry.
  178. @return The Menu Entry.
  179. **/
  180. BM_MENU_ENTRY *
  181. BOpt_GetMenuEntry (
  182. BM_MENU_OPTION *MenuOption,
  183. UINTN MenuNumber
  184. )
  185. {
  186. BM_MENU_ENTRY *NewMenuEntry;
  187. UINTN Index;
  188. LIST_ENTRY *List;
  189. ASSERT (MenuNumber < MenuOption->MenuNumber);
  190. List = MenuOption->Head.ForwardLink;
  191. for (Index = 0; Index < MenuNumber; Index++) {
  192. List = List->ForwardLink;
  193. }
  194. NewMenuEntry = CR (List, BM_MENU_ENTRY, Link, BM_MENU_ENTRY_SIGNATURE);
  195. return NewMenuEntry;
  196. }
  197. /**
  198. Free resources allocated in Allocate Rountine.
  199. @param FreeMenu Menu to be freed
  200. **/
  201. VOID
  202. BOpt_FreeMenu (
  203. BM_MENU_OPTION *FreeMenu
  204. )
  205. {
  206. BM_MENU_ENTRY *MenuEntry;
  207. while (!IsListEmpty (&FreeMenu->Head)) {
  208. MenuEntry = CR (
  209. FreeMenu->Head.ForwardLink,
  210. BM_MENU_ENTRY,
  211. Link,
  212. BM_MENU_ENTRY_SIGNATURE
  213. );
  214. RemoveEntryList (&MenuEntry->Link);
  215. BOpt_DestroyMenuEntry (MenuEntry);
  216. }
  217. FreeMenu->MenuNumber = 0;
  218. }
  219. /**
  220. Build the BootOptionMenu according to BootOrder Variable.
  221. This Routine will access the Boot#### to get EFI_LOAD_OPTION.
  222. @param CallbackData The BMM context data.
  223. @return EFI_NOT_FOUND Fail to find "BootOrder" variable.
  224. @return EFI_SUCESS Success build boot option menu.
  225. **/
  226. EFI_STATUS
  227. BOpt_GetBootOptions (
  228. IN BMM_CALLBACK_DATA *CallbackData
  229. )
  230. {
  231. UINTN Index;
  232. UINT16 BootString[10];
  233. UINT8 *LoadOptionFromVar;
  234. UINTN BootOptionSize;
  235. BOOLEAN BootNextFlag;
  236. UINT16 *BootOrderList;
  237. UINTN BootOrderListSize;
  238. UINT16 *BootNext;
  239. UINTN BootNextSize;
  240. BM_MENU_ENTRY *NewMenuEntry;
  241. BM_LOAD_CONTEXT *NewLoadContext;
  242. UINT8 *LoadOptionPtr;
  243. UINTN StringSize;
  244. UINTN OptionalDataSize;
  245. UINT8 *LoadOptionEnd;
  246. EFI_DEVICE_PATH_PROTOCOL *DevicePath;
  247. UINTN MenuCount;
  248. UINT8 *Ptr;
  249. EFI_BOOT_MANAGER_LOAD_OPTION *BootOption;
  250. UINTN BootOptionCount;
  251. MenuCount = 0;
  252. BootOrderListSize = 0;
  253. BootNextSize = 0;
  254. BootOrderList = NULL;
  255. BootNext = NULL;
  256. LoadOptionFromVar = NULL;
  257. BOpt_FreeMenu (&BootOptionMenu);
  258. InitializeListHead (&BootOptionMenu.Head);
  259. //
  260. // Get the BootOrder from the Var
  261. //
  262. GetEfiGlobalVariable2 (L"BootOrder", (VOID **)&BootOrderList, &BootOrderListSize);
  263. if (BootOrderList == NULL) {
  264. return EFI_NOT_FOUND;
  265. }
  266. //
  267. // Get the BootNext from the Var
  268. //
  269. GetEfiGlobalVariable2 (L"BootNext", (VOID **)&BootNext, &BootNextSize);
  270. if (BootNext != NULL) {
  271. if (BootNextSize != sizeof (UINT16)) {
  272. FreePool (BootNext);
  273. BootNext = NULL;
  274. }
  275. }
  276. BootOption = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
  277. for (Index = 0; Index < BootOrderListSize / sizeof (UINT16); Index++) {
  278. //
  279. // Don't display the hidden/inactive boot option
  280. //
  281. if (((BootOption[Index].Attributes & LOAD_OPTION_HIDDEN) != 0) || ((BootOption[Index].Attributes & LOAD_OPTION_ACTIVE) == 0)) {
  282. continue;
  283. }
  284. UnicodeSPrint (BootString, sizeof (BootString), L"Boot%04x", BootOrderList[Index]);
  285. //
  286. // Get all loadoptions from the VAR
  287. //
  288. GetEfiGlobalVariable2 (BootString, (VOID **)&LoadOptionFromVar, &BootOptionSize);
  289. if (LoadOptionFromVar == NULL) {
  290. continue;
  291. }
  292. if (BootNext != NULL) {
  293. BootNextFlag = (BOOLEAN)(*BootNext == BootOrderList[Index]);
  294. } else {
  295. BootNextFlag = FALSE;
  296. }
  297. NewMenuEntry = BOpt_CreateMenuEntry (BM_LOAD_CONTEXT_SELECT);
  298. ASSERT (NULL != NewMenuEntry);
  299. NewLoadContext = (BM_LOAD_CONTEXT *)NewMenuEntry->VariableContext;
  300. LoadOptionPtr = LoadOptionFromVar;
  301. LoadOptionEnd = LoadOptionFromVar + BootOptionSize;
  302. NewMenuEntry->OptionNumber = BootOrderList[Index];
  303. NewLoadContext->Deleted = FALSE;
  304. NewLoadContext->IsBootNext = BootNextFlag;
  305. //
  306. // Is a Legacy Device?
  307. //
  308. Ptr = (UINT8 *)LoadOptionFromVar;
  309. //
  310. // Attribute = *(UINT32 *)Ptr;
  311. //
  312. Ptr += sizeof (UINT32);
  313. //
  314. // FilePathSize = *(UINT16 *)Ptr;
  315. //
  316. Ptr += sizeof (UINT16);
  317. //
  318. // Description = (CHAR16 *)Ptr;
  319. //
  320. Ptr += StrSize ((CHAR16 *)Ptr);
  321. //
  322. // Now Ptr point to Device Path
  323. //
  324. DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)Ptr;
  325. if ((BBS_DEVICE_PATH == DevicePath->Type) && (BBS_BBS_DP == DevicePath->SubType)) {
  326. NewLoadContext->IsLegacy = TRUE;
  327. } else {
  328. NewLoadContext->IsLegacy = FALSE;
  329. }
  330. //
  331. // LoadOption is a pointer type of UINT8
  332. // for easy use with following LOAD_OPTION
  333. // embedded in this struct
  334. //
  335. NewLoadContext->Attributes = *(UINT32 *)LoadOptionPtr;
  336. LoadOptionPtr += sizeof (UINT32);
  337. NewLoadContext->FilePathListLength = *(UINT16 *)LoadOptionPtr;
  338. LoadOptionPtr += sizeof (UINT16);
  339. StringSize = StrSize ((UINT16 *)LoadOptionPtr);
  340. NewLoadContext->Description = AllocateZeroPool (StrSize ((UINT16 *)LoadOptionPtr));
  341. ASSERT (NewLoadContext->Description != NULL);
  342. StrCpyS (NewLoadContext->Description, StrSize ((UINT16 *)LoadOptionPtr) / sizeof (UINT16), (UINT16 *)LoadOptionPtr);
  343. ASSERT (NewLoadContext->Description != NULL);
  344. NewMenuEntry->DisplayString = NewLoadContext->Description;
  345. NewMenuEntry->DisplayStringToken = HiiSetString (CallbackData->BmmHiiHandle, 0, NewMenuEntry->DisplayString, NULL);
  346. LoadOptionPtr += StringSize;
  347. NewLoadContext->FilePathList = AllocateZeroPool (NewLoadContext->FilePathListLength);
  348. ASSERT (NewLoadContext->FilePathList != NULL);
  349. CopyMem (
  350. NewLoadContext->FilePathList,
  351. (EFI_DEVICE_PATH_PROTOCOL *)LoadOptionPtr,
  352. NewLoadContext->FilePathListLength
  353. );
  354. NewMenuEntry->HelpString = UiDevicePathToStr (NewLoadContext->FilePathList);
  355. NewMenuEntry->HelpStringToken = HiiSetString (CallbackData->BmmHiiHandle, 0, NewMenuEntry->HelpString, NULL);
  356. LoadOptionPtr += NewLoadContext->FilePathListLength;
  357. if (LoadOptionPtr < LoadOptionEnd) {
  358. OptionalDataSize = BootOptionSize -
  359. sizeof (UINT32) -
  360. sizeof (UINT16) -
  361. StringSize -
  362. NewLoadContext->FilePathListLength;
  363. NewLoadContext->OptionalData = AllocateZeroPool (OptionalDataSize);
  364. ASSERT (NewLoadContext->OptionalData != NULL);
  365. CopyMem (
  366. NewLoadContext->OptionalData,
  367. LoadOptionPtr,
  368. OptionalDataSize
  369. );
  370. }
  371. InsertTailList (&BootOptionMenu.Head, &NewMenuEntry->Link);
  372. MenuCount++;
  373. FreePool (LoadOptionFromVar);
  374. }
  375. EfiBootManagerFreeLoadOptions (BootOption, BootOptionCount);
  376. if (BootNext != NULL) {
  377. FreePool (BootNext);
  378. }
  379. if (BootOrderList != NULL) {
  380. FreePool (BootOrderList);
  381. }
  382. BootOptionMenu.MenuNumber = MenuCount;
  383. return EFI_SUCCESS;
  384. }
  385. /**
  386. Find drivers that will be added as Driver#### variables from handles
  387. in current system environment
  388. All valid handles in the system except those consume SimpleFs, LoadFile
  389. are stored in DriverMenu for future use.
  390. @retval EFI_SUCCESS The function complets successfully.
  391. @return Other value if failed to build the DriverMenu.
  392. **/
  393. EFI_STATUS
  394. BOpt_FindDrivers (
  395. VOID
  396. )
  397. {
  398. UINTN NoDevicePathHandles;
  399. EFI_HANDLE *DevicePathHandle;
  400. UINTN Index;
  401. EFI_STATUS Status;
  402. BM_MENU_ENTRY *NewMenuEntry;
  403. BM_HANDLE_CONTEXT *NewHandleContext;
  404. EFI_HANDLE CurHandle;
  405. UINTN OptionNumber;
  406. EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFs;
  407. EFI_LOAD_FILE_PROTOCOL *LoadFile;
  408. SimpleFs = NULL;
  409. LoadFile = NULL;
  410. InitializeListHead (&DriverMenu.Head);
  411. //
  412. // At first, get all handles that support Device Path
  413. // protocol which is the basic requirement for
  414. // Driver####
  415. //
  416. Status = gBS->LocateHandleBuffer (
  417. ByProtocol,
  418. &gEfiDevicePathProtocolGuid,
  419. NULL,
  420. &NoDevicePathHandles,
  421. &DevicePathHandle
  422. );
  423. if (EFI_ERROR (Status)) {
  424. return Status;
  425. }
  426. OptionNumber = 0;
  427. for (Index = 0; Index < NoDevicePathHandles; Index++) {
  428. CurHandle = DevicePathHandle[Index];
  429. Status = gBS->HandleProtocol (
  430. CurHandle,
  431. &gEfiSimpleFileSystemProtocolGuid,
  432. (VOID **)&SimpleFs
  433. );
  434. if (Status == EFI_SUCCESS) {
  435. continue;
  436. }
  437. Status = gBS->HandleProtocol (
  438. CurHandle,
  439. &gEfiLoadFileProtocolGuid,
  440. (VOID **)&LoadFile
  441. );
  442. if (Status == EFI_SUCCESS) {
  443. continue;
  444. }
  445. NewMenuEntry = BOpt_CreateMenuEntry (BM_HANDLE_CONTEXT_SELECT);
  446. if (NULL == NewMenuEntry) {
  447. FreePool (DevicePathHandle);
  448. return EFI_OUT_OF_RESOURCES;
  449. }
  450. NewHandleContext = (BM_HANDLE_CONTEXT *)NewMenuEntry->VariableContext;
  451. NewHandleContext->Handle = CurHandle;
  452. NewHandleContext->DevicePath = DevicePathFromHandle (CurHandle);
  453. NewMenuEntry->DisplayString = UiDevicePathToStr (NewHandleContext->DevicePath);
  454. NewMenuEntry->DisplayStringToken = HiiSetString (mBmmCallbackInfo->BmmHiiHandle, 0, NewMenuEntry->DisplayString, NULL);
  455. NewMenuEntry->HelpString = NULL;
  456. NewMenuEntry->HelpStringToken = NewMenuEntry->DisplayStringToken;
  457. NewMenuEntry->OptionNumber = OptionNumber;
  458. OptionNumber++;
  459. InsertTailList (&DriverMenu.Head, &NewMenuEntry->Link);
  460. }
  461. if (DevicePathHandle != NULL) {
  462. FreePool (DevicePathHandle);
  463. }
  464. DriverMenu.MenuNumber = OptionNumber;
  465. return EFI_SUCCESS;
  466. }
  467. /**
  468. Get the Option Number that has not been allocated for use.
  469. @param Type The type of Option.
  470. @return The available Option Number.
  471. **/
  472. UINT16
  473. BOpt_GetOptionNumber (
  474. CHAR16 *Type
  475. )
  476. {
  477. UINT16 *OrderList;
  478. UINTN OrderListSize;
  479. UINTN Index;
  480. CHAR16 StrTemp[20];
  481. UINT16 *OptionBuffer;
  482. UINT16 OptionNumber;
  483. UINTN OptionSize;
  484. OrderListSize = 0;
  485. OrderList = NULL;
  486. OptionNumber = 0;
  487. Index = 0;
  488. UnicodeSPrint (StrTemp, sizeof (StrTemp), L"%sOrder", Type);
  489. GetEfiGlobalVariable2 (StrTemp, (VOID **)&OrderList, &OrderListSize);
  490. for (OptionNumber = 0; ; OptionNumber++) {
  491. if (OrderList != NULL) {
  492. for (Index = 0; Index < OrderListSize / sizeof (UINT16); Index++) {
  493. if (OptionNumber == OrderList[Index]) {
  494. break;
  495. }
  496. }
  497. }
  498. if (Index < OrderListSize / sizeof (UINT16)) {
  499. //
  500. // The OptionNumber occurs in the OrderList, continue to use next one
  501. //
  502. continue;
  503. }
  504. UnicodeSPrint (StrTemp, sizeof (StrTemp), L"%s%04x", Type, (UINTN)OptionNumber);
  505. DEBUG ((DEBUG_ERROR, "Option = %s\n", StrTemp));
  506. GetEfiGlobalVariable2 (StrTemp, (VOID **)&OptionBuffer, &OptionSize);
  507. if (NULL == OptionBuffer) {
  508. //
  509. // The Boot[OptionNumber] / Driver[OptionNumber] NOT occurs, we found it
  510. //
  511. break;
  512. }
  513. }
  514. return OptionNumber;
  515. }
  516. /**
  517. Get the Option Number for Boot#### that does not used.
  518. @return The available Option Number.
  519. **/
  520. UINT16
  521. BOpt_GetBootOptionNumber (
  522. VOID
  523. )
  524. {
  525. return BOpt_GetOptionNumber (L"Boot");
  526. }
  527. /**
  528. Get the Option Number for Driver#### that does not used.
  529. @return The unused Option Number.
  530. **/
  531. UINT16
  532. BOpt_GetDriverOptionNumber (
  533. VOID
  534. )
  535. {
  536. return BOpt_GetOptionNumber (L"Driver");
  537. }
  538. /**
  539. Build up all DriverOptionMenu
  540. @param CallbackData The BMM context data.
  541. @retval EFI_SUCESS The functin completes successfully.
  542. @retval EFI_OUT_OF_RESOURCES Not enough memory to compete the operation.
  543. @retval EFI_NOT_FOUND Fail to get "DriverOrder" variable.
  544. **/
  545. EFI_STATUS
  546. BOpt_GetDriverOptions (
  547. IN BMM_CALLBACK_DATA *CallbackData
  548. )
  549. {
  550. UINTN Index;
  551. UINT16 DriverString[12];
  552. UINT8 *LoadOptionFromVar;
  553. UINTN DriverOptionSize;
  554. UINT16 *DriverOrderList;
  555. UINTN DriverOrderListSize;
  556. BM_MENU_ENTRY *NewMenuEntry;
  557. BM_LOAD_CONTEXT *NewLoadContext;
  558. UINT8 *LoadOptionPtr;
  559. UINTN StringSize;
  560. UINTN OptionalDataSize;
  561. UINT8 *LoadOptionEnd;
  562. DriverOrderListSize = 0;
  563. DriverOrderList = NULL;
  564. DriverOptionSize = 0;
  565. LoadOptionFromVar = NULL;
  566. BOpt_FreeMenu (&DriverOptionMenu);
  567. InitializeListHead (&DriverOptionMenu.Head);
  568. //
  569. // Get the DriverOrder from the Var
  570. //
  571. GetEfiGlobalVariable2 (L"DriverOrder", (VOID **)&DriverOrderList, &DriverOrderListSize);
  572. if (DriverOrderList == NULL) {
  573. return EFI_NOT_FOUND;
  574. }
  575. for (Index = 0; Index < DriverOrderListSize / sizeof (UINT16); Index++) {
  576. UnicodeSPrint (
  577. DriverString,
  578. sizeof (DriverString),
  579. L"Driver%04x",
  580. DriverOrderList[Index]
  581. );
  582. //
  583. // Get all loadoptions from the VAR
  584. //
  585. GetEfiGlobalVariable2 (DriverString, (VOID **)&LoadOptionFromVar, &DriverOptionSize);
  586. if (LoadOptionFromVar == NULL) {
  587. continue;
  588. }
  589. NewMenuEntry = BOpt_CreateMenuEntry (BM_LOAD_CONTEXT_SELECT);
  590. if (NULL == NewMenuEntry) {
  591. return EFI_OUT_OF_RESOURCES;
  592. }
  593. NewLoadContext = (BM_LOAD_CONTEXT *)NewMenuEntry->VariableContext;
  594. LoadOptionPtr = LoadOptionFromVar;
  595. LoadOptionEnd = LoadOptionFromVar + DriverOptionSize;
  596. NewMenuEntry->OptionNumber = DriverOrderList[Index];
  597. NewLoadContext->Deleted = FALSE;
  598. NewLoadContext->IsLegacy = FALSE;
  599. //
  600. // LoadOption is a pointer type of UINT8
  601. // for easy use with following LOAD_OPTION
  602. // embedded in this struct
  603. //
  604. NewLoadContext->Attributes = *(UINT32 *)LoadOptionPtr;
  605. LoadOptionPtr += sizeof (UINT32);
  606. NewLoadContext->FilePathListLength = *(UINT16 *)LoadOptionPtr;
  607. LoadOptionPtr += sizeof (UINT16);
  608. StringSize = StrSize ((UINT16 *)LoadOptionPtr);
  609. NewLoadContext->Description = AllocateZeroPool (StringSize);
  610. ASSERT (NewLoadContext->Description != NULL);
  611. CopyMem (
  612. NewLoadContext->Description,
  613. (UINT16 *)LoadOptionPtr,
  614. StringSize
  615. );
  616. NewMenuEntry->DisplayString = NewLoadContext->Description;
  617. NewMenuEntry->DisplayStringToken = HiiSetString (CallbackData->BmmHiiHandle, 0, NewMenuEntry->DisplayString, NULL);
  618. LoadOptionPtr += StringSize;
  619. NewLoadContext->FilePathList = AllocateZeroPool (NewLoadContext->FilePathListLength);
  620. ASSERT (NewLoadContext->FilePathList != NULL);
  621. CopyMem (
  622. NewLoadContext->FilePathList,
  623. (EFI_DEVICE_PATH_PROTOCOL *)LoadOptionPtr,
  624. NewLoadContext->FilePathListLength
  625. );
  626. NewMenuEntry->HelpString = UiDevicePathToStr (NewLoadContext->FilePathList);
  627. NewMenuEntry->HelpStringToken = HiiSetString (CallbackData->BmmHiiHandle, 0, NewMenuEntry->HelpString, NULL);
  628. LoadOptionPtr += NewLoadContext->FilePathListLength;
  629. if (LoadOptionPtr < LoadOptionEnd) {
  630. OptionalDataSize = DriverOptionSize -
  631. sizeof (UINT32) -
  632. sizeof (UINT16) -
  633. StringSize -
  634. NewLoadContext->FilePathListLength;
  635. NewLoadContext->OptionalData = AllocateZeroPool (OptionalDataSize);
  636. ASSERT (NewLoadContext->OptionalData != NULL);
  637. CopyMem (
  638. NewLoadContext->OptionalData,
  639. LoadOptionPtr,
  640. OptionalDataSize
  641. );
  642. }
  643. InsertTailList (&DriverOptionMenu.Head, &NewMenuEntry->Link);
  644. FreePool (LoadOptionFromVar);
  645. }
  646. if (DriverOrderList != NULL) {
  647. FreePool (DriverOrderList);
  648. }
  649. DriverOptionMenu.MenuNumber = Index;
  650. return EFI_SUCCESS;
  651. }
  652. /**
  653. Get option number according to Boot#### and BootOrder variable.
  654. The value is saved as #### + 1.
  655. @param CallbackData The BMM context data.
  656. **/
  657. VOID
  658. GetBootOrder (
  659. IN BMM_CALLBACK_DATA *CallbackData
  660. )
  661. {
  662. BMM_FAKE_NV_DATA *BmmConfig;
  663. UINT16 Index;
  664. UINT16 OptionOrderIndex;
  665. UINTN DeviceType;
  666. BM_MENU_ENTRY *NewMenuEntry;
  667. BM_LOAD_CONTEXT *NewLoadContext;
  668. ASSERT (CallbackData != NULL);
  669. DeviceType = (UINTN)-1;
  670. BmmConfig = &CallbackData->BmmFakeNvData;
  671. ZeroMem (BmmConfig->BootOptionOrder, sizeof (BmmConfig->BootOptionOrder));
  672. for (Index = 0, OptionOrderIndex = 0; ((Index < BootOptionMenu.MenuNumber) &&
  673. (OptionOrderIndex < (sizeof (BmmConfig->BootOptionOrder) / sizeof (BmmConfig->BootOptionOrder[0]))));
  674. Index++)
  675. {
  676. NewMenuEntry = BOpt_GetMenuEntry (&BootOptionMenu, Index);
  677. NewLoadContext = (BM_LOAD_CONTEXT *)NewMenuEntry->VariableContext;
  678. if (NewLoadContext->IsLegacy) {
  679. if (((BBS_BBS_DEVICE_PATH *)NewLoadContext->FilePathList)->DeviceType != DeviceType) {
  680. DeviceType = ((BBS_BBS_DEVICE_PATH *)NewLoadContext->FilePathList)->DeviceType;
  681. } else {
  682. //
  683. // Only show one legacy boot option for the same device type
  684. // assuming the boot options are grouped by the device type
  685. //
  686. continue;
  687. }
  688. }
  689. BmmConfig->BootOptionOrder[OptionOrderIndex++] = (UINT32)(NewMenuEntry->OptionNumber + 1);
  690. }
  691. }
  692. /**
  693. Get driver option order from globalc DriverOptionMenu.
  694. @param CallbackData The BMM context data.
  695. **/
  696. VOID
  697. GetDriverOrder (
  698. IN BMM_CALLBACK_DATA *CallbackData
  699. )
  700. {
  701. BMM_FAKE_NV_DATA *BmmConfig;
  702. UINT16 Index;
  703. UINT16 OptionOrderIndex;
  704. UINTN DeviceType;
  705. BM_MENU_ENTRY *NewMenuEntry;
  706. BM_LOAD_CONTEXT *NewLoadContext;
  707. ASSERT (CallbackData != NULL);
  708. DeviceType = (UINTN)-1;
  709. BmmConfig = &CallbackData->BmmFakeNvData;
  710. ZeroMem (BmmConfig->DriverOptionOrder, sizeof (BmmConfig->DriverOptionOrder));
  711. for (Index = 0, OptionOrderIndex = 0; ((Index < DriverOptionMenu.MenuNumber) &&
  712. (OptionOrderIndex < (sizeof (BmmConfig->DriverOptionOrder) / sizeof (BmmConfig->DriverOptionOrder[0]))));
  713. Index++)
  714. {
  715. NewMenuEntry = BOpt_GetMenuEntry (&DriverOptionMenu, Index);
  716. NewLoadContext = (BM_LOAD_CONTEXT *)NewMenuEntry->VariableContext;
  717. if (NewLoadContext->IsLegacy) {
  718. if (((BBS_BBS_DEVICE_PATH *)NewLoadContext->FilePathList)->DeviceType != DeviceType) {
  719. DeviceType = ((BBS_BBS_DEVICE_PATH *)NewLoadContext->FilePathList)->DeviceType;
  720. } else {
  721. //
  722. // Only show one legacy boot option for the same device type
  723. // assuming the boot options are grouped by the device type
  724. //
  725. continue;
  726. }
  727. }
  728. BmmConfig->DriverOptionOrder[OptionOrderIndex++] = (UINT32)(NewMenuEntry->OptionNumber + 1);
  729. }
  730. }
  731. /**
  732. Boot the file specified by the input file path info.
  733. @param FilePath Point to the file path.
  734. @retval TRUE Exit caller function.
  735. @retval FALSE Not exit caller function.
  736. **/
  737. BOOLEAN
  738. EFIAPI
  739. BootFromFile (
  740. IN EFI_DEVICE_PATH_PROTOCOL *FilePath
  741. )
  742. {
  743. EFI_STATUS Status;
  744. EFI_BOOT_MANAGER_LOAD_OPTION BootOption;
  745. CHAR16 *FileName;
  746. Status = EFI_NOT_STARTED;
  747. FileName = NULL;
  748. FileName = ExtractFileNameFromDevicePath (FilePath);
  749. if (FileName != NULL) {
  750. Status = EfiBootManagerInitializeLoadOption (
  751. &BootOption,
  752. 0,
  753. LoadOptionTypeBoot,
  754. LOAD_OPTION_ACTIVE,
  755. FileName,
  756. FilePath,
  757. NULL,
  758. 0
  759. );
  760. }
  761. if (!EFI_ERROR (Status)) {
  762. //
  763. // Since current no boot from removable media directly is allowed */
  764. //
  765. gST->ConOut->ClearScreen (gST->ConOut);
  766. //
  767. // Check whether need to reset system.
  768. //
  769. BmmSetupResetReminder ();
  770. BmmSetConsoleMode (FALSE);
  771. EfiBootManagerBoot (&BootOption);
  772. BmmSetConsoleMode (TRUE);
  773. FreePool (FileName);
  774. EfiBootManagerFreeLoadOption (&BootOption);
  775. }
  776. return FALSE;
  777. }
  778. /**
  779. Display the form base on the selected file.
  780. @param FilePath Point to the file path.
  781. @param FormId The form need to display.
  782. **/
  783. BOOLEAN
  784. ReSendForm (
  785. IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
  786. IN EFI_FORM_ID FormId
  787. )
  788. {
  789. gBootMaintenancePrivate.LoadContext->FilePathList = FilePath;
  790. UpdateOptionPage (&gBootMaintenancePrivate, FormId, FilePath);
  791. gBootMaintenancePrivate.FormBrowser2->SendForm (
  792. gBootMaintenancePrivate.FormBrowser2,
  793. &gBootMaintenancePrivate.BmmHiiHandle,
  794. 1,
  795. &mBootMaintGuid,
  796. FormId,
  797. NULL,
  798. NULL
  799. );
  800. return TRUE;
  801. }
  802. /**
  803. Create boot option base on the input file path info.
  804. @param FilePath Point to the file path.
  805. @retval TRUE Exit caller function.
  806. @retval FALSE Not exit caller function.
  807. **/
  808. BOOLEAN
  809. EFIAPI
  810. CreateBootOptionFromFile (
  811. IN EFI_DEVICE_PATH_PROTOCOL *FilePath
  812. )
  813. {
  814. return ReSendForm (FilePath, FORM_BOOT_ADD_ID);
  815. }
  816. /**
  817. Create driver option base on the input file path info.
  818. @param FilePath Point to the file path.
  819. @retval TRUE Exit caller function.
  820. @retval FALSE Not exit caller function.
  821. **/
  822. BOOLEAN
  823. EFIAPI
  824. CreateDriverOptionFromFile (
  825. IN EFI_DEVICE_PATH_PROTOCOL *FilePath
  826. )
  827. {
  828. return ReSendForm (FilePath, FORM_DRV_ADD_FILE_ID);
  829. }