eficonfig.c 58 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Menu-driven UEFI Variable maintenance
  4. *
  5. * Copyright (c) 2022 Masahisa Kojima, Linaro Limited
  6. */
  7. #include <ansi.h>
  8. #include <cli.h>
  9. #include <common.h>
  10. #include <charset.h>
  11. #include <efi_loader.h>
  12. #include <efi_load_initrd.h>
  13. #include <efi_config.h>
  14. #include <efi_variable.h>
  15. #include <log.h>
  16. #include <malloc.h>
  17. #include <menu.h>
  18. #include <sort.h>
  19. #include <watchdog.h>
  20. #include <asm/unaligned.h>
  21. #include <linux/delay.h>
  22. static struct efi_simple_text_input_protocol *cin;
  23. const char *eficonfig_menu_desc =
  24. " Press UP/DOWN to move, ENTER to select, ESC to quit";
  25. static const char *eficonfig_change_boot_order_desc =
  26. " Press UP/DOWN to move, +/- to change orde\n"
  27. " Press SPACE to activate or deactivate the entry\n"
  28. " CTRL+S to save, ESC to quit";
  29. static struct efi_simple_text_output_protocol *cout;
  30. static int avail_row;
  31. #define EFICONFIG_DESCRIPTION_MAX 32
  32. #define EFICONFIG_OPTIONAL_DATA_MAX 64
  33. #define EFICONFIG_MENU_HEADER_ROW_NUM 3
  34. #define EFICONFIG_MENU_DESC_ROW_NUM 5
  35. /**
  36. * struct eficonfig_filepath_info - structure to be used to store file path
  37. *
  38. * @name: file or directory name
  39. * @list: list structure
  40. */
  41. struct eficonfig_filepath_info {
  42. char *name;
  43. struct list_head list;
  44. };
  45. /**
  46. * struct eficonfig_boot_option - structure to be used for updating UEFI boot option
  47. *
  48. * @file_info: user selected file info
  49. * @initrd_info: user selected initrd file info
  50. * @boot_index: index of the boot option
  51. * @description: pointer to the description string
  52. * @optional_data: pointer to the optional_data
  53. * @edit_completed: flag indicates edit complete
  54. */
  55. struct eficonfig_boot_option {
  56. struct eficonfig_select_file_info file_info;
  57. struct eficonfig_select_file_info initrd_info;
  58. unsigned int boot_index;
  59. u16 *description;
  60. u16 *optional_data;
  61. bool edit_completed;
  62. };
  63. /**
  64. * struct eficonfig_volume_entry_data - structure to be used to store volume info
  65. *
  66. * @file_info: pointer to file info structure
  67. * @v: pointer to the protocol interface
  68. * @dp: pointer to the device path
  69. */
  70. struct eficonfig_volume_entry_data {
  71. struct eficonfig_select_file_info *file_info;
  72. struct efi_simple_file_system_protocol *v;
  73. struct efi_device_path *dp;
  74. };
  75. /**
  76. * struct eficonfig_file_entry_data - structure to be used to store file info
  77. *
  78. * @file_info: pointer to file info structure
  79. * @is_directory: flag to identify the directory or file
  80. * @file_name: name of directory or file
  81. */
  82. struct eficonfig_file_entry_data {
  83. struct eficonfig_select_file_info *file_info;
  84. bool is_directory;
  85. char *file_name;
  86. };
  87. /**
  88. * struct eficonfig_boot_selection_data - structure to be used to select the boot option entry
  89. *
  90. * @boot_index: index of the boot option
  91. * @selected: pointer to store the selected index in the BootOrder variable
  92. */
  93. struct eficonfig_boot_selection_data {
  94. u16 boot_index;
  95. int *selected;
  96. };
  97. /**
  98. * struct eficonfig_boot_order_data - structure to be used to update BootOrder variable
  99. *
  100. * @boot_index: boot option index
  101. * @active: flag to include the boot option into BootOrder variable
  102. */
  103. struct eficonfig_boot_order_data {
  104. u32 boot_index;
  105. bool active;
  106. };
  107. /**
  108. * struct eficonfig_save_boot_order_data - structure to be used to change boot order
  109. *
  110. * @efi_menu: pointer to efimenu structure
  111. * @selected: flag to indicate user selects "Save" entry
  112. */
  113. struct eficonfig_save_boot_order_data {
  114. struct efimenu *efi_menu;
  115. bool selected;
  116. };
  117. /**
  118. * struct eficonfig_menu_adjust - update start and end entry index
  119. *
  120. * @efi_menu: pointer to efimenu structure
  121. * @add: flag to add or substract the index
  122. */
  123. static void eficonfig_menu_adjust(struct efimenu *efi_menu, bool add)
  124. {
  125. if (add)
  126. ++efi_menu->active;
  127. else
  128. --efi_menu->active;
  129. if (add && efi_menu->end < efi_menu->active) {
  130. efi_menu->start++;
  131. efi_menu->end++;
  132. } else if (!add && efi_menu->start > efi_menu->active) {
  133. efi_menu->start--;
  134. efi_menu->end--;
  135. }
  136. }
  137. #define eficonfig_menu_up(_a) eficonfig_menu_adjust(_a, false)
  138. #define eficonfig_menu_down(_a) eficonfig_menu_adjust(_a, true)
  139. /**
  140. * eficonfig_print_msg() - print message
  141. *
  142. * display the message to the user, user proceeds the screen
  143. * with any key press.
  144. *
  145. * @items: pointer to the structure of each menu entry
  146. * @count: the number of menu entry
  147. * @menu_header: pointer to the menu header string
  148. * Return: status code
  149. */
  150. void eficonfig_print_msg(char *msg)
  151. {
  152. /* Flush input */
  153. while (tstc())
  154. getchar();
  155. printf(ANSI_CURSOR_HIDE
  156. ANSI_CLEAR_CONSOLE
  157. ANSI_CURSOR_POSITION
  158. "%s\n\n Press any key to continue", 3, 4, msg);
  159. getchar();
  160. }
  161. /**
  162. * eficonfig_print_entry() - print each menu entry
  163. *
  164. * @data: pointer to the data associated with each menu entry
  165. */
  166. void eficonfig_print_entry(void *data)
  167. {
  168. struct eficonfig_entry *entry = data;
  169. bool reverse = (entry->efi_menu->active == entry->num);
  170. if (entry->efi_menu->start > entry->num || entry->efi_menu->end < entry->num)
  171. return;
  172. printf(ANSI_CURSOR_POSITION, (entry->num - entry->efi_menu->start) +
  173. EFICONFIG_MENU_HEADER_ROW_NUM + 1, 7);
  174. if (reverse)
  175. puts(ANSI_COLOR_REVERSE);
  176. printf(ANSI_CLEAR_LINE "%s", entry->title);
  177. if (reverse)
  178. puts(ANSI_COLOR_RESET);
  179. }
  180. /**
  181. * eficonfig_display_statusline() - print status line
  182. *
  183. * @m: pointer to the menu structure
  184. */
  185. void eficonfig_display_statusline(struct menu *m)
  186. {
  187. struct eficonfig_entry *entry;
  188. if (menu_default_choice(m, (void *)&entry) < 0)
  189. return;
  190. printf(ANSI_CURSOR_POSITION
  191. "\n%s\n"
  192. ANSI_CURSOR_POSITION ANSI_CLEAR_LINE ANSI_CURSOR_POSITION
  193. "%s"
  194. ANSI_CLEAR_LINE_TO_END,
  195. 1, 1, entry->efi_menu->menu_header, avail_row + 4, 1,
  196. avail_row + 5, 1, entry->efi_menu->menu_desc);
  197. }
  198. /**
  199. * eficonfig_choice_entry() - user key input handler
  200. *
  201. * @data: pointer to the efimenu structure
  202. * Return: key string to identify the selected entry
  203. */
  204. char *eficonfig_choice_entry(void *data)
  205. {
  206. struct cli_ch_state s_cch, *cch = &s_cch;
  207. struct list_head *pos, *n;
  208. struct eficonfig_entry *entry;
  209. enum bootmenu_key key = BKEY_NONE;
  210. struct efimenu *efi_menu = data;
  211. cli_ch_init(cch);
  212. while (1) {
  213. key = bootmenu_loop((struct bootmenu_data *)efi_menu, cch);
  214. switch (key) {
  215. case BKEY_UP:
  216. if (efi_menu->active > 0)
  217. eficonfig_menu_up(efi_menu);
  218. /* no menu key selected, regenerate menu */
  219. return NULL;
  220. case BKEY_DOWN:
  221. if (efi_menu->active < efi_menu->count - 1)
  222. eficonfig_menu_down(efi_menu);
  223. /* no menu key selected, regenerate menu */
  224. return NULL;
  225. case BKEY_SELECT:
  226. list_for_each_safe(pos, n, &efi_menu->list) {
  227. entry = list_entry(pos, struct eficonfig_entry, list);
  228. if (entry->num == efi_menu->active)
  229. return entry->key;
  230. }
  231. break;
  232. case BKEY_QUIT:
  233. /* Quit by choosing the last entry */
  234. entry = list_last_entry(&efi_menu->list, struct eficonfig_entry, list);
  235. return entry->key;
  236. default:
  237. /* Pressed key is not valid, no need to regenerate the menu */
  238. break;
  239. }
  240. }
  241. }
  242. /**
  243. * eficonfig_destroy() - destroy efimenu
  244. *
  245. * @efi_menu: pointer to the efimenu structure
  246. */
  247. void eficonfig_destroy(struct efimenu *efi_menu)
  248. {
  249. struct list_head *pos, *n;
  250. struct eficonfig_entry *entry;
  251. if (!efi_menu)
  252. return;
  253. list_for_each_safe(pos, n, &efi_menu->list) {
  254. entry = list_entry(pos, struct eficonfig_entry, list);
  255. free(entry->title);
  256. list_del(&entry->list);
  257. free(entry);
  258. }
  259. free(efi_menu->menu_header);
  260. free(efi_menu);
  261. }
  262. /**
  263. * eficonfig_process_quit() - callback function for "Quit" entry
  264. *
  265. * @data: pointer to the data
  266. * Return: status code
  267. */
  268. efi_status_t eficonfig_process_quit(void *data)
  269. {
  270. return EFI_ABORTED;
  271. }
  272. /**
  273. * eficonfig_append_menu_entry() - append menu item
  274. *
  275. * @efi_menu: pointer to the efimenu structure
  276. * @title: pointer to the entry title
  277. * @func: callback of each entry
  278. * @data: pointer to the data to be passed to each entry callback
  279. * Return: status code
  280. */
  281. efi_status_t eficonfig_append_menu_entry(struct efimenu *efi_menu,
  282. char *title, eficonfig_entry_func func,
  283. void *data)
  284. {
  285. struct eficonfig_entry *entry;
  286. if (efi_menu->count >= EFICONFIG_ENTRY_NUM_MAX)
  287. return EFI_OUT_OF_RESOURCES;
  288. entry = calloc(1, sizeof(struct eficonfig_entry));
  289. if (!entry)
  290. return EFI_OUT_OF_RESOURCES;
  291. entry->title = title;
  292. sprintf(entry->key, "%d", efi_menu->count);
  293. entry->efi_menu = efi_menu;
  294. entry->func = func;
  295. entry->data = data;
  296. entry->num = efi_menu->count++;
  297. list_add_tail(&entry->list, &efi_menu->list);
  298. return EFI_SUCCESS;
  299. }
  300. /**
  301. * eficonfig_append_quit_entry() - append quit entry
  302. *
  303. * @efi_menu: pointer to the efimenu structure
  304. * Return: status code
  305. */
  306. efi_status_t eficonfig_append_quit_entry(struct efimenu *efi_menu)
  307. {
  308. char *title;
  309. efi_status_t ret;
  310. title = strdup("Quit");
  311. if (!title)
  312. return EFI_OUT_OF_RESOURCES;
  313. ret = eficonfig_append_menu_entry(efi_menu, title, eficonfig_process_quit, NULL);
  314. if (ret != EFI_SUCCESS)
  315. free(title);
  316. return ret;
  317. }
  318. /**
  319. * eficonfig_create_fixed_menu() - create fixed entry menu structure
  320. *
  321. * @items: pointer to the menu entry item
  322. * @count: the number of menu entry
  323. * Return: pointer to the efimenu structure
  324. */
  325. void *eficonfig_create_fixed_menu(const struct eficonfig_item *items, int count)
  326. {
  327. u32 i;
  328. char *title;
  329. efi_status_t ret;
  330. struct efimenu *efi_menu;
  331. const struct eficonfig_item *iter = items;
  332. efi_menu = calloc(1, sizeof(struct efimenu));
  333. if (!efi_menu)
  334. return NULL;
  335. INIT_LIST_HEAD(&efi_menu->list);
  336. for (i = 0; i < count; i++, iter++) {
  337. title = strdup(iter->title);
  338. if (!title)
  339. goto out;
  340. ret = eficonfig_append_menu_entry(efi_menu, title, iter->func, iter->data);
  341. if (ret != EFI_SUCCESS) {
  342. free(title);
  343. goto out;
  344. }
  345. }
  346. return efi_menu;
  347. out:
  348. eficonfig_destroy(efi_menu);
  349. return NULL;
  350. }
  351. /**
  352. * eficonfig_process_common() - main handler for UEFI menu
  353. *
  354. * Construct the structures required to show the menu, then handle
  355. * the user input interacting with u-boot menu functions.
  356. *
  357. * @efi_menu: pointer to the efimenu structure
  358. * @menu_header: pointer to the menu header string
  359. * @menu_desc: pointer to the menu description
  360. * @display_statusline: function pointer to draw statusline
  361. * @item_data_print: function pointer to draw the menu item
  362. * @item_choice: function pointer to handle the key press
  363. * Return: status code
  364. */
  365. efi_status_t eficonfig_process_common(struct efimenu *efi_menu,
  366. char *menu_header, const char *menu_desc,
  367. void (*display_statusline)(struct menu *),
  368. void (*item_data_print)(void *),
  369. char *(*item_choice)(void *))
  370. {
  371. struct menu *menu;
  372. void *choice = NULL;
  373. struct list_head *pos, *n;
  374. struct eficonfig_entry *entry;
  375. efi_status_t ret = EFI_SUCCESS;
  376. if (efi_menu->count > EFICONFIG_ENTRY_NUM_MAX)
  377. return EFI_OUT_OF_RESOURCES;
  378. efi_menu->delay = -1;
  379. efi_menu->active = 0;
  380. efi_menu->start = 0;
  381. efi_menu->end = avail_row - 1;
  382. if (menu_header) {
  383. efi_menu->menu_header = strdup(menu_header);
  384. if (!efi_menu->menu_header)
  385. return EFI_OUT_OF_RESOURCES;
  386. }
  387. if (menu_desc)
  388. efi_menu->menu_desc = menu_desc;
  389. menu = menu_create(NULL, 0, 1, display_statusline, item_data_print,
  390. item_choice, efi_menu);
  391. if (!menu)
  392. return EFI_INVALID_PARAMETER;
  393. list_for_each_safe(pos, n, &efi_menu->list) {
  394. entry = list_entry(pos, struct eficonfig_entry, list);
  395. if (!menu_item_add(menu, entry->key, entry)) {
  396. ret = EFI_INVALID_PARAMETER;
  397. goto out;
  398. }
  399. }
  400. entry = list_first_entry_or_null(&efi_menu->list, struct eficonfig_entry, list);
  401. if (entry)
  402. menu_default_set(menu, entry->key);
  403. printf(ANSI_CURSOR_HIDE
  404. ANSI_CLEAR_CONSOLE
  405. ANSI_CURSOR_POSITION, 1, 1);
  406. if (menu_get_choice(menu, &choice)) {
  407. entry = choice;
  408. if (entry->func)
  409. ret = entry->func(entry->data);
  410. }
  411. out:
  412. menu_destroy(menu);
  413. printf(ANSI_CLEAR_CONSOLE
  414. ANSI_CURSOR_POSITION
  415. ANSI_CURSOR_SHOW, 1, 1);
  416. return ret;
  417. }
  418. /**
  419. * eficonfig_volume_selected() - handler of volume selection
  420. *
  421. * @data: pointer to the data of selected entry
  422. * Return: status code
  423. */
  424. static efi_status_t eficonfig_volume_selected(void *data)
  425. {
  426. struct eficonfig_volume_entry_data *info = data;
  427. if (info) {
  428. info->file_info->current_volume = info->v;
  429. info->file_info->dp_volume = info->dp;
  430. }
  431. return EFI_SUCCESS;
  432. }
  433. /**
  434. * eficonfig_create_device_path() - create device path
  435. *
  436. * @dp_volume: pointer to the volume
  437. * @current_path: pointer to the file path u16 string
  438. * Return:
  439. * device path or NULL. Caller must free the returned value
  440. */
  441. struct efi_device_path *eficonfig_create_device_path(struct efi_device_path *dp_volume,
  442. u16 *current_path)
  443. {
  444. char *p;
  445. void *buf;
  446. efi_uintn_t fp_size;
  447. struct efi_device_path *dp;
  448. struct efi_device_path_file_path *fp;
  449. fp_size = sizeof(struct efi_device_path) + u16_strsize(current_path);
  450. buf = calloc(1, fp_size + sizeof(END));
  451. if (!buf)
  452. return NULL;
  453. fp = buf;
  454. fp->dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE,
  455. fp->dp.sub_type = DEVICE_PATH_SUB_TYPE_FILE_PATH,
  456. fp->dp.length = (u16)fp_size;
  457. u16_strcpy(fp->str, current_path);
  458. p = buf;
  459. p += fp_size;
  460. *((struct efi_device_path *)p) = END;
  461. dp = efi_dp_append(dp_volume, (struct efi_device_path *)buf);
  462. free(buf);
  463. return dp;
  464. }
  465. /**
  466. * eficonfig_file_selected() - handler of file selection
  467. *
  468. * @data: pointer to the data of selected entry
  469. * Return: status code
  470. */
  471. static efi_status_t eficonfig_file_selected(void *data)
  472. {
  473. u16 *tmp;
  474. struct eficonfig_file_entry_data *info = data;
  475. if (!info)
  476. return EFI_INVALID_PARAMETER;
  477. if (!strcmp(info->file_name, "..\\")) {
  478. struct eficonfig_filepath_info *iter;
  479. struct list_head *pos, *n;
  480. int is_last;
  481. char *filepath;
  482. tmp = info->file_info->current_path;
  483. memset(info->file_info->current_path, 0, EFICONFIG_FILE_PATH_BUF_SIZE);
  484. filepath = calloc(1, EFICONFIG_FILE_PATH_MAX);
  485. if (!filepath)
  486. return EFI_OUT_OF_RESOURCES;
  487. list_for_each_safe(pos, n, &info->file_info->filepath_list) {
  488. iter = list_entry(pos, struct eficonfig_filepath_info, list);
  489. is_last = list_is_last(&iter->list, &info->file_info->filepath_list);
  490. if (is_last) {
  491. list_del(&iter->list);
  492. free(iter->name);
  493. free(iter);
  494. break;
  495. }
  496. strlcat(filepath, iter->name, EFICONFIG_FILE_PATH_MAX);
  497. }
  498. utf8_utf16_strcpy(&tmp, filepath);
  499. } else {
  500. size_t new_len;
  501. struct eficonfig_filepath_info *filepath_info;
  502. new_len = u16_strlen(info->file_info->current_path) +
  503. strlen(info->file_name);
  504. if (new_len >= EFICONFIG_FILE_PATH_MAX) {
  505. eficonfig_print_msg("File path is too long!");
  506. return EFI_INVALID_PARAMETER;
  507. }
  508. tmp = &info->file_info->current_path[u16_strlen(info->file_info->current_path)];
  509. utf8_utf16_strcpy(&tmp, info->file_name);
  510. filepath_info = calloc(1, sizeof(struct eficonfig_filepath_info));
  511. if (!filepath_info)
  512. return EFI_OUT_OF_RESOURCES;
  513. filepath_info->name = strdup(info->file_name);
  514. if (!filepath_info->name) {
  515. free(filepath_info);
  516. return EFI_OUT_OF_RESOURCES;
  517. }
  518. list_add_tail(&filepath_info->list, &info->file_info->filepath_list);
  519. if (!info->is_directory)
  520. info->file_info->file_selected = true;
  521. }
  522. return EFI_SUCCESS;
  523. }
  524. /**
  525. * eficonfig_select_volume() - construct the volume selection menu
  526. *
  527. * @file_info: pointer to the file selection structure
  528. * Return: status code
  529. */
  530. static efi_status_t eficonfig_select_volume(struct eficonfig_select_file_info *file_info)
  531. {
  532. u32 i;
  533. efi_status_t ret;
  534. efi_uintn_t count;
  535. struct efimenu *efi_menu;
  536. struct list_head *pos, *n;
  537. struct efi_handler *handler;
  538. struct eficonfig_entry *entry;
  539. struct efi_device_path *device_path;
  540. efi_handle_t *volume_handles = NULL;
  541. struct efi_simple_file_system_protocol *v;
  542. ret = efi_locate_handle_buffer_int(BY_PROTOCOL, &efi_simple_file_system_protocol_guid,
  543. NULL, &count, (efi_handle_t **)&volume_handles);
  544. if (ret != EFI_SUCCESS) {
  545. eficonfig_print_msg("No block device found!");
  546. return ret;
  547. }
  548. efi_menu = calloc(1, sizeof(struct efimenu));
  549. if (!efi_menu)
  550. return EFI_OUT_OF_RESOURCES;
  551. INIT_LIST_HEAD(&efi_menu->list);
  552. for (i = 0; i < count; i++) {
  553. char *devname;
  554. struct efi_block_io *block_io;
  555. struct eficonfig_volume_entry_data *info;
  556. if (efi_menu->count >= EFICONFIG_ENTRY_NUM_MAX - 1)
  557. break;
  558. ret = efi_search_protocol(volume_handles[i],
  559. &efi_simple_file_system_protocol_guid, &handler);
  560. if (ret != EFI_SUCCESS)
  561. continue;
  562. ret = efi_protocol_open(handler, (void **)&v, efi_root, NULL,
  563. EFI_OPEN_PROTOCOL_GET_PROTOCOL);
  564. if (ret != EFI_SUCCESS)
  565. continue;
  566. ret = efi_search_protocol(volume_handles[i], &efi_guid_device_path, &handler);
  567. if (ret != EFI_SUCCESS)
  568. continue;
  569. ret = efi_protocol_open(handler, (void **)&device_path,
  570. efi_root, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
  571. if (ret != EFI_SUCCESS)
  572. continue;
  573. ret = efi_search_protocol(volume_handles[i], &efi_block_io_guid, &handler);
  574. if (ret != EFI_SUCCESS)
  575. continue;
  576. ret = efi_protocol_open(handler, (void **)&block_io,
  577. efi_root, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
  578. if (ret != EFI_SUCCESS)
  579. continue;
  580. info = calloc(1, sizeof(struct eficonfig_volume_entry_data));
  581. if (!info) {
  582. ret = EFI_OUT_OF_RESOURCES;
  583. goto out;
  584. }
  585. devname = calloc(1, BOOTMENU_DEVICE_NAME_MAX);
  586. if (!devname) {
  587. free(info);
  588. ret = EFI_OUT_OF_RESOURCES;
  589. goto out;
  590. }
  591. ret = efi_disk_get_device_name(volume_handles[i], devname,
  592. BOOTMENU_DEVICE_NAME_MAX);
  593. if (ret != EFI_SUCCESS) {
  594. free(info);
  595. goto out;
  596. }
  597. info->v = v;
  598. info->dp = device_path;
  599. info->file_info = file_info;
  600. ret = eficonfig_append_menu_entry(efi_menu, devname, eficonfig_volume_selected,
  601. info);
  602. if (ret != EFI_SUCCESS) {
  603. free(info);
  604. goto out;
  605. }
  606. }
  607. ret = eficonfig_append_quit_entry(efi_menu);
  608. if (ret != EFI_SUCCESS)
  609. goto out;
  610. ret = eficonfig_process_common(efi_menu, " ** Select Volume **",
  611. eficonfig_menu_desc,
  612. eficonfig_display_statusline,
  613. eficonfig_print_entry,
  614. eficonfig_choice_entry);
  615. out:
  616. efi_free_pool(volume_handles);
  617. list_for_each_safe(pos, n, &efi_menu->list) {
  618. entry = list_entry(pos, struct eficonfig_entry, list);
  619. free(entry->data);
  620. }
  621. eficonfig_destroy(efi_menu);
  622. return ret;
  623. }
  624. /**
  625. * sort_file() - sort the file name in ascii order
  626. *
  627. * @data1: pointer to the file entry data
  628. * @data2: pointer to the file entry data
  629. * Return: -1 if the data1 file name is less than data2 file name,
  630. * 0 if both file name match,
  631. * 1 if the data1 file name is greater thant data2 file name.
  632. */
  633. static int sort_file(const void *arg1, const void *arg2)
  634. {
  635. const struct eficonfig_file_entry_data *data1, *data2;
  636. data1 = *((const struct eficonfig_file_entry_data **)arg1);
  637. data2 = *((const struct eficonfig_file_entry_data **)arg2);
  638. return strcasecmp(data1->file_name, data2->file_name);
  639. }
  640. /**
  641. * eficonfig_create_file_entry() - construct the file menu entry
  642. *
  643. * @efi_menu: pointer to the efimenu structure
  644. * @count: number of the directory and file
  645. * @tmp_infos: pointer to the entry data array
  646. * @f: pointer to the file handle
  647. * @buf: pointer to the buffer to store the directory information
  648. * @file_info: pointer to the file selection structure
  649. * Return: status code
  650. */
  651. static efi_status_t
  652. eficonfig_create_file_entry(struct efimenu *efi_menu, u32 count,
  653. struct eficonfig_file_entry_data **tmp_infos,
  654. struct efi_file_handle *f, struct efi_file_info *buf,
  655. struct eficonfig_select_file_info *file_info)
  656. {
  657. char *name, *p;
  658. efi_uintn_t len;
  659. efi_status_t ret;
  660. u32 i, entry_num = 0;
  661. struct eficonfig_file_entry_data *info;
  662. EFI_CALL(f->setpos(f, 0));
  663. /* Read directory and construct menu structure */
  664. for (i = 0; i < count; i++) {
  665. if (entry_num >= EFICONFIG_ENTRY_NUM_MAX - 1)
  666. break;
  667. len = sizeof(struct efi_file_info) + EFICONFIG_FILE_PATH_BUF_SIZE;
  668. ret = EFI_CALL(f->read(f, &len, buf));
  669. if (ret != EFI_SUCCESS || len == 0)
  670. break;
  671. info = calloc(1, sizeof(struct eficonfig_file_entry_data));
  672. if (!info) {
  673. ret = EFI_OUT_OF_RESOURCES;
  674. goto out;
  675. }
  676. /* append '\\' at the end of directory name */
  677. name = calloc(1, utf16_utf8_strlen(buf->file_name) + 2);
  678. if (!name) {
  679. ret = EFI_OUT_OF_RESOURCES;
  680. free(info);
  681. goto out;
  682. }
  683. p = name;
  684. utf16_utf8_strcpy(&p, buf->file_name);
  685. if (buf->attribute & EFI_FILE_DIRECTORY) {
  686. /* filter out u'.' */
  687. if (!u16_strcmp(buf->file_name, u".")) {
  688. free(info);
  689. free(name);
  690. continue;
  691. }
  692. name[u16_strlen(buf->file_name)] = '\\';
  693. info->is_directory = true;
  694. }
  695. info->file_name = name;
  696. info->file_info = file_info;
  697. tmp_infos[entry_num++] = info;
  698. }
  699. qsort(tmp_infos, entry_num, sizeof(*tmp_infos),
  700. (int (*)(const void *, const void *))sort_file);
  701. for (i = 0; i < entry_num; i++) {
  702. ret = eficonfig_append_menu_entry(efi_menu, tmp_infos[i]->file_name,
  703. eficonfig_file_selected, tmp_infos[i]);
  704. if (ret != EFI_SUCCESS)
  705. goto out;
  706. }
  707. out:
  708. return ret;
  709. }
  710. /**
  711. * eficonfig_show_file_selection() - construct the file selection menu
  712. *
  713. * @file_info: pointer to the file selection structure
  714. * @root: pointer to the file handle
  715. * Return: status code
  716. */
  717. static efi_status_t eficonfig_show_file_selection(struct eficonfig_select_file_info *file_info,
  718. struct efi_file_handle *root)
  719. {
  720. u32 count = 0, i;
  721. efi_uintn_t len;
  722. efi_status_t ret;
  723. struct efimenu *efi_menu;
  724. struct efi_file_handle *f;
  725. struct efi_file_info *buf;
  726. struct eficonfig_file_entry_data **tmp_infos;
  727. buf = calloc(1, sizeof(struct efi_file_info) + EFICONFIG_FILE_PATH_BUF_SIZE);
  728. if (!buf)
  729. return EFI_OUT_OF_RESOURCES;
  730. while (!file_info->file_selected) {
  731. efi_menu = calloc(1, sizeof(struct efimenu));
  732. if (!efi_menu) {
  733. ret = EFI_OUT_OF_RESOURCES;
  734. goto out;
  735. }
  736. INIT_LIST_HEAD(&efi_menu->list);
  737. ret = EFI_CALL(root->open(root, &f, file_info->current_path,
  738. EFI_FILE_MODE_READ, 0));
  739. if (ret != EFI_SUCCESS) {
  740. eficonfig_print_msg("Reading volume failed!");
  741. free(efi_menu);
  742. ret = EFI_ABORTED;
  743. goto out;
  744. }
  745. /* Count the number of directory entries */
  746. for (;;) {
  747. len = sizeof(struct efi_file_info) + EFICONFIG_FILE_PATH_BUF_SIZE;
  748. ret = EFI_CALL(f->read(f, &len, buf));
  749. if (ret != EFI_SUCCESS || len == 0)
  750. break;
  751. count++;
  752. }
  753. /* allocate array to sort the entry */
  754. tmp_infos = calloc(count, sizeof(*tmp_infos));
  755. if (!tmp_infos) {
  756. ret = EFI_OUT_OF_RESOURCES;
  757. goto err;
  758. }
  759. ret = eficonfig_create_file_entry(efi_menu, count, tmp_infos,
  760. f, buf, file_info);
  761. if (ret != EFI_SUCCESS)
  762. goto err;
  763. ret = eficonfig_append_quit_entry(efi_menu);
  764. if (ret != EFI_SUCCESS)
  765. goto err;
  766. ret = eficonfig_process_common(efi_menu, " ** Select File **",
  767. eficonfig_menu_desc,
  768. eficonfig_display_statusline,
  769. eficonfig_print_entry,
  770. eficonfig_choice_entry);
  771. err:
  772. EFI_CALL(f->close(f));
  773. eficonfig_destroy(efi_menu);
  774. if (tmp_infos) {
  775. for (i = 0; i < count; i++)
  776. free(tmp_infos[i]);
  777. }
  778. free(tmp_infos);
  779. if (ret != EFI_SUCCESS)
  780. break;
  781. }
  782. out:
  783. free(buf);
  784. return ret;
  785. }
  786. /**
  787. * handle_user_input() - handle user input
  788. *
  789. * @buf: pointer to the buffer
  790. * @buf_size: size of the buffer
  791. * @cursor_col: cursor column for user input
  792. * @msg: pointer to the string to display
  793. * Return: status code
  794. */
  795. static efi_status_t handle_user_input(u16 *buf, int buf_size,
  796. int cursor_col, char *msg)
  797. {
  798. u16 *tmp;
  799. efi_status_t ret;
  800. printf(ANSI_CLEAR_CONSOLE
  801. ANSI_CURSOR_POSITION
  802. "%s"
  803. ANSI_CURSOR_POSITION
  804. " Press ENTER to complete, ESC to quit",
  805. 0, 1, msg, 8, 1);
  806. /* tmp is used to accept user cancel */
  807. tmp = calloc(1, buf_size * sizeof(u16));
  808. if (!tmp)
  809. return EFI_OUT_OF_RESOURCES;
  810. ret = efi_console_get_u16_string(cin, tmp, buf_size, NULL, 4, cursor_col);
  811. if (ret == EFI_SUCCESS)
  812. u16_strcpy(buf, tmp);
  813. free(tmp);
  814. /* to stay the parent menu */
  815. ret = (ret == EFI_ABORTED) ? EFI_NOT_READY : ret;
  816. return ret;
  817. }
  818. /**
  819. * eficonfig_boot_add_enter_description() - handle user input for description
  820. *
  821. * @data: pointer to the internal boot option structure
  822. * Return: status code
  823. */
  824. static efi_status_t eficonfig_boot_add_enter_description(void *data)
  825. {
  826. struct eficonfig_boot_option *bo = data;
  827. return handle_user_input(bo->description, EFICONFIG_DESCRIPTION_MAX, 22,
  828. "\n ** Edit Description **\n"
  829. "\n"
  830. " enter description: ");
  831. }
  832. /**
  833. * eficonfig_boot_add_optional_data() - handle user input for optional data
  834. *
  835. * @data: pointer to the internal boot option structure
  836. * Return: status code
  837. */
  838. static efi_status_t eficonfig_boot_add_optional_data(void *data)
  839. {
  840. struct eficonfig_boot_option *bo = data;
  841. return handle_user_input(bo->optional_data, EFICONFIG_OPTIONAL_DATA_MAX, 24,
  842. "\n ** Edit Optional Data **\n"
  843. "\n"
  844. " enter optional data:");
  845. }
  846. /**
  847. * eficonfig_boot_edit_save() - handler to save the boot option
  848. *
  849. * @data: pointer to the internal boot option structure
  850. * Return: status code
  851. */
  852. static efi_status_t eficonfig_boot_edit_save(void *data)
  853. {
  854. struct eficonfig_boot_option *bo = data;
  855. if (u16_strlen(bo->description) == 0) {
  856. eficonfig_print_msg("Boot Description is empty!");
  857. bo->edit_completed = false;
  858. return EFI_NOT_READY;
  859. }
  860. if (u16_strlen(bo->file_info.current_path) == 0) {
  861. eficonfig_print_msg("File is not selected!");
  862. bo->edit_completed = false;
  863. return EFI_NOT_READY;
  864. }
  865. bo->edit_completed = true;
  866. return EFI_SUCCESS;
  867. }
  868. /**
  869. * eficonfig_process_clear_file_selection() - callback function for "Clear" entry
  870. *
  871. * @data: pointer to the data
  872. * Return: status code
  873. */
  874. efi_status_t eficonfig_process_clear_file_selection(void *data)
  875. {
  876. struct eficonfig_select_file_info *file_info = data;
  877. /* clear the existing file information */
  878. file_info->current_volume = NULL;
  879. file_info->current_path[0] = u'\0';
  880. file_info->dp_volume = NULL;
  881. return EFI_ABORTED;
  882. }
  883. static struct eficonfig_item select_file_menu_items[] = {
  884. {"Select File", eficonfig_process_select_file},
  885. {"Clear", eficonfig_process_clear_file_selection},
  886. {"Quit", eficonfig_process_quit},
  887. };
  888. /**
  889. * eficonfig_process_show_file_option() - display select file option
  890. *
  891. * @file_info: pointer to the file information structure
  892. * Return: status code
  893. */
  894. efi_status_t eficonfig_process_show_file_option(void *data)
  895. {
  896. efi_status_t ret;
  897. struct efimenu *efi_menu;
  898. select_file_menu_items[0].data = data;
  899. select_file_menu_items[1].data = data;
  900. efi_menu = eficonfig_create_fixed_menu(select_file_menu_items,
  901. ARRAY_SIZE(select_file_menu_items));
  902. if (!efi_menu)
  903. return EFI_OUT_OF_RESOURCES;
  904. ret = eficonfig_process_common(efi_menu, " ** Update File **",
  905. eficonfig_menu_desc,
  906. eficonfig_display_statusline,
  907. eficonfig_print_entry,
  908. eficonfig_choice_entry);
  909. if (ret != EFI_SUCCESS) /* User selects "Clear" or "Quit" */
  910. ret = EFI_NOT_READY;
  911. eficonfig_destroy(efi_menu);
  912. return ret;
  913. }
  914. /**
  915. * eficonfig_process_select_file() - handle user file selection
  916. *
  917. * @data: pointer to the data
  918. * Return: status code
  919. */
  920. efi_status_t eficonfig_process_select_file(void *data)
  921. {
  922. size_t len;
  923. efi_status_t ret;
  924. struct list_head *pos, *n;
  925. struct efi_file_handle *root;
  926. struct eficonfig_filepath_info *item;
  927. struct eficonfig_select_file_info *tmp = NULL;
  928. struct eficonfig_select_file_info *file_info = data;
  929. tmp = calloc(1, sizeof(struct eficonfig_select_file_info));
  930. if (!tmp)
  931. return EFI_OUT_OF_RESOURCES;
  932. tmp->current_path = calloc(1, EFICONFIG_FILE_PATH_BUF_SIZE);
  933. if (!tmp->current_path) {
  934. free(tmp);
  935. return EFI_OUT_OF_RESOURCES;
  936. }
  937. INIT_LIST_HEAD(&tmp->filepath_list);
  938. while (!tmp->file_selected) {
  939. tmp->current_volume = NULL;
  940. memset(tmp->current_path, 0, EFICONFIG_FILE_PATH_BUF_SIZE);
  941. ret = eficonfig_select_volume(tmp);
  942. if (ret != EFI_SUCCESS)
  943. goto out;
  944. if (!tmp->current_volume)
  945. return EFI_INVALID_PARAMETER;
  946. ret = EFI_CALL(tmp->current_volume->open_volume(tmp->current_volume, &root));
  947. if (ret != EFI_SUCCESS)
  948. goto out;
  949. ret = eficonfig_show_file_selection(tmp, root);
  950. if (ret == EFI_ABORTED)
  951. continue;
  952. if (ret != EFI_SUCCESS)
  953. goto out;
  954. }
  955. out:
  956. if (ret == EFI_SUCCESS) {
  957. len = u16_strlen(tmp->current_path);
  958. len = (len >= EFICONFIG_FILE_PATH_MAX) ? (EFICONFIG_FILE_PATH_MAX - 1) : len;
  959. memcpy(file_info->current_path, tmp->current_path, len * sizeof(u16));
  960. file_info->current_path[len] = u'\0';
  961. file_info->current_volume = tmp->current_volume;
  962. file_info->dp_volume = tmp->dp_volume;
  963. }
  964. list_for_each_safe(pos, n, &tmp->filepath_list) {
  965. item = list_entry(pos, struct eficonfig_filepath_info, list);
  966. list_del(&item->list);
  967. free(item->name);
  968. free(item);
  969. }
  970. free(tmp->current_path);
  971. free(tmp);
  972. /* to stay the parent menu */
  973. ret = (ret == EFI_ABORTED) ? EFI_NOT_READY : ret;
  974. return ret;
  975. }
  976. /**
  977. * eficonfig_set_boot_option() - set boot option
  978. *
  979. * @varname: pointer to variable name
  980. * @dp: pointer to device path
  981. * @label: pointer to label string
  982. * @optional_data: pointer to optional data
  983. * Return: status code
  984. */
  985. static efi_status_t eficonfig_set_boot_option(u16 *varname, struct efi_device_path *dp,
  986. efi_uintn_t dp_size, u16 *label, char *optional_data)
  987. {
  988. void *p = NULL;
  989. efi_status_t ret;
  990. efi_uintn_t size;
  991. struct efi_load_option lo;
  992. lo.file_path = dp;
  993. lo.file_path_length = dp_size;
  994. lo.attributes = LOAD_OPTION_ACTIVE;
  995. lo.optional_data = optional_data;
  996. lo.label = label;
  997. size = efi_serialize_load_option(&lo, (u8 **)&p);
  998. if (!size)
  999. return EFI_INVALID_PARAMETER;
  1000. ret = efi_set_variable_int(varname, &efi_global_variable_guid,
  1001. EFI_VARIABLE_NON_VOLATILE |
  1002. EFI_VARIABLE_BOOTSERVICE_ACCESS |
  1003. EFI_VARIABLE_RUNTIME_ACCESS,
  1004. size, p, false);
  1005. free(p);
  1006. return ret;
  1007. }
  1008. /**
  1009. * create_boot_option_entry() - create boot option entry
  1010. *
  1011. * @efi_menu: pointer to the efimenu structure
  1012. * @title: pointer to the entry title
  1013. * @val: pointer to boot option label
  1014. * @func: callback of each entry
  1015. * @data: pointer to the data to be passed to each entry callback
  1016. * Return: status code
  1017. */
  1018. static efi_status_t create_boot_option_entry(struct efimenu *efi_menu, char *title, u16 *val,
  1019. eficonfig_entry_func func, void *data)
  1020. {
  1021. u32 len;
  1022. char *p, *buf;
  1023. len = strlen(title) + 1;
  1024. if (val)
  1025. len += utf16_utf8_strlen(val);
  1026. buf = calloc(1, len);
  1027. if (!buf)
  1028. return EFI_OUT_OF_RESOURCES;
  1029. strcpy(buf, title);
  1030. if (val) {
  1031. p = buf + strlen(title);
  1032. utf16_utf8_strcpy(&p, val);
  1033. }
  1034. return eficonfig_append_menu_entry(efi_menu, buf, func, data);
  1035. }
  1036. /**
  1037. * prepare_file_selection_entry() - prepare file selection entry
  1038. *
  1039. * @efi_menu: pointer to the efimenu structure
  1040. * @title: pointer to the title string
  1041. * @file_info: pointer to the file info
  1042. * Return: status code
  1043. */
  1044. static efi_status_t prepare_file_selection_entry(struct efimenu *efi_menu, char *title,
  1045. struct eficonfig_select_file_info *file_info)
  1046. {
  1047. u32 len;
  1048. efi_status_t ret;
  1049. u16 *file_name = NULL, *p;
  1050. efi_handle_t handle;
  1051. char *devname;
  1052. devname = calloc(1, EFICONFIG_VOLUME_PATH_MAX + 1);
  1053. if (!devname)
  1054. return EFI_OUT_OF_RESOURCES;
  1055. /* get the device name only when the user already selected the file path */
  1056. handle = efi_dp_find_obj(file_info->dp_volume, NULL, NULL);
  1057. if (handle) {
  1058. ret = efi_disk_get_device_name(handle, devname, EFICONFIG_VOLUME_PATH_MAX);
  1059. if (ret != EFI_SUCCESS)
  1060. goto out;
  1061. }
  1062. /*
  1063. * If the preconfigured volume does not exist in the system, display the text
  1064. * converted volume device path instead of U-Boot friendly name(e.g. "usb 0:1").
  1065. */
  1066. if (!handle && file_info->dp_volume) {
  1067. u16 *dp_str;
  1068. char *q = devname;
  1069. dp_str = efi_dp_str(file_info->dp_volume);
  1070. if (dp_str)
  1071. utf16_utf8_strncpy(&q, dp_str, EFICONFIG_VOLUME_PATH_MAX);
  1072. efi_free_pool(dp_str);
  1073. }
  1074. /* append u'/' to devname, it is just for display purpose. */
  1075. if (file_info->current_path[0] != u'\0' && file_info->current_path[0] != u'/')
  1076. strlcat(devname, "/", EFICONFIG_VOLUME_PATH_MAX + 1);
  1077. len = strlen(devname);
  1078. len += utf16_utf8_strlen(file_info->current_path) + 1;
  1079. file_name = calloc(1, len * sizeof(u16));
  1080. if (!file_name) {
  1081. ret = EFI_OUT_OF_RESOURCES;
  1082. goto out;
  1083. }
  1084. p = file_name;
  1085. utf8_utf16_strcpy(&p, devname);
  1086. u16_strlcat(file_name, file_info->current_path, len);
  1087. ret = create_boot_option_entry(efi_menu, title, file_name,
  1088. eficonfig_process_show_file_option, file_info);
  1089. out:
  1090. free(devname);
  1091. free(file_name);
  1092. return ret;
  1093. }
  1094. /**
  1095. * eficonfig_show_boot_option() - prepare menu entry for editing boot option
  1096. *
  1097. * Construct the structures to create edit boot option menu
  1098. *
  1099. * @bo: pointer to the boot option
  1100. * @header_str: pointer to the header string
  1101. * Return: status code
  1102. */
  1103. static efi_status_t eficonfig_show_boot_option(struct eficonfig_boot_option *bo,
  1104. char *header_str)
  1105. {
  1106. efi_status_t ret;
  1107. struct efimenu *efi_menu;
  1108. efi_menu = calloc(1, sizeof(struct efimenu));
  1109. if (!efi_menu)
  1110. return EFI_OUT_OF_RESOURCES;
  1111. INIT_LIST_HEAD(&efi_menu->list);
  1112. ret = create_boot_option_entry(efi_menu, "Description: ", bo->description,
  1113. eficonfig_boot_add_enter_description, bo);
  1114. if (ret != EFI_SUCCESS)
  1115. goto out;
  1116. ret = prepare_file_selection_entry(efi_menu, "File: ", &bo->file_info);
  1117. if (ret != EFI_SUCCESS)
  1118. goto out;
  1119. ret = prepare_file_selection_entry(efi_menu, "Initrd File: ", &bo->initrd_info);
  1120. if (ret != EFI_SUCCESS)
  1121. goto out;
  1122. ret = create_boot_option_entry(efi_menu, "Optional Data: ", bo->optional_data,
  1123. eficonfig_boot_add_optional_data, bo);
  1124. if (ret != EFI_SUCCESS)
  1125. goto out;
  1126. ret = create_boot_option_entry(efi_menu, "Save", NULL,
  1127. eficonfig_boot_edit_save, bo);
  1128. if (ret != EFI_SUCCESS)
  1129. goto out;
  1130. ret = create_boot_option_entry(efi_menu, "Quit", NULL,
  1131. eficonfig_process_quit, NULL);
  1132. if (ret != EFI_SUCCESS)
  1133. goto out;
  1134. ret = eficonfig_process_common(efi_menu, header_str,
  1135. eficonfig_menu_desc,
  1136. eficonfig_display_statusline,
  1137. eficonfig_print_entry,
  1138. eficonfig_choice_entry);
  1139. out:
  1140. eficonfig_destroy(efi_menu);
  1141. return ret;
  1142. }
  1143. /**
  1144. * fill_file_info() - fill the file info from efi_device_path structure
  1145. *
  1146. * @dp: pointer to the device path
  1147. * @file_info: pointer to the file info structure
  1148. * @device_dp: pointer to the volume device path
  1149. */
  1150. static void fill_file_info(struct efi_device_path *dp,
  1151. struct eficonfig_select_file_info *file_info,
  1152. struct efi_device_path *device_dp)
  1153. {
  1154. u16 *file_str, *p;
  1155. struct efi_device_path *file_dp = NULL;
  1156. efi_dp_split_file_path(dp, &device_dp, &file_dp);
  1157. file_info->dp_volume = device_dp;
  1158. if (file_dp) {
  1159. file_str = efi_dp_str(file_dp);
  1160. /*
  1161. * efi_convert_device_path_to_text() automatically adds u'/' at the
  1162. * beginning of file name, remove u'/' before copying to current_path
  1163. */
  1164. p = file_str;
  1165. if (p[0] == u'/')
  1166. p++;
  1167. u16_strcpy(file_info->current_path, p);
  1168. efi_free_pool(file_dp);
  1169. efi_free_pool(file_str);
  1170. }
  1171. }
  1172. /**
  1173. * eficonfig_edit_boot_option() - prepare boot option structure for editing
  1174. *
  1175. * Construct the boot option structure and copy the existing value
  1176. *
  1177. * @varname: pointer to the UEFI variable name
  1178. * @bo: pointer to the boot option
  1179. * @load_option: pointer to the load option
  1180. * @load_option_size: size of the load option
  1181. * @header_str: pointer to the header string
  1182. * Return : status code
  1183. */
  1184. static efi_status_t eficonfig_edit_boot_option(u16 *varname, struct eficonfig_boot_option *bo,
  1185. void *load_option, efi_uintn_t load_option_size,
  1186. char *header_str)
  1187. {
  1188. size_t len;
  1189. efi_status_t ret;
  1190. char *tmp = NULL, *p;
  1191. struct efi_load_option lo = {0};
  1192. efi_uintn_t final_dp_size;
  1193. struct efi_device_path *dp = NULL;
  1194. efi_uintn_t size = load_option_size;
  1195. struct efi_device_path *final_dp = NULL;
  1196. struct efi_device_path *device_dp = NULL;
  1197. struct efi_device_path *initrd_dp = NULL;
  1198. struct efi_device_path *initrd_device_dp = NULL;
  1199. const struct efi_initrd_dp id_dp = {
  1200. .vendor = {
  1201. {
  1202. DEVICE_PATH_TYPE_MEDIA_DEVICE,
  1203. DEVICE_PATH_SUB_TYPE_VENDOR_PATH,
  1204. sizeof(id_dp.vendor),
  1205. },
  1206. EFI_INITRD_MEDIA_GUID,
  1207. },
  1208. .end = {
  1209. DEVICE_PATH_TYPE_END,
  1210. DEVICE_PATH_SUB_TYPE_END,
  1211. sizeof(id_dp.end),
  1212. }
  1213. };
  1214. bo->file_info.current_path = calloc(1, EFICONFIG_FILE_PATH_BUF_SIZE);
  1215. if (!bo->file_info.current_path) {
  1216. ret = EFI_OUT_OF_RESOURCES;
  1217. goto out;
  1218. }
  1219. bo->initrd_info.current_path = calloc(1, EFICONFIG_FILE_PATH_BUF_SIZE);
  1220. if (!bo->file_info.current_path) {
  1221. ret = EFI_OUT_OF_RESOURCES;
  1222. goto out;
  1223. }
  1224. bo->description = calloc(1, EFICONFIG_DESCRIPTION_MAX * sizeof(u16));
  1225. if (!bo->description) {
  1226. ret = EFI_OUT_OF_RESOURCES;
  1227. goto out;
  1228. }
  1229. bo->optional_data = calloc(1, EFICONFIG_OPTIONAL_DATA_MAX * sizeof(u16));
  1230. if (!bo->optional_data) {
  1231. ret = EFI_OUT_OF_RESOURCES;
  1232. goto out;
  1233. }
  1234. /* copy the preset value */
  1235. if (load_option) {
  1236. ret = efi_deserialize_load_option(&lo, load_option, &size);
  1237. if (ret != EFI_SUCCESS)
  1238. goto out;
  1239. if (!lo.label) {
  1240. ret = EFI_INVALID_PARAMETER;
  1241. goto out;
  1242. }
  1243. /* truncate the long label string */
  1244. if (u16_strlen(lo.label) >= EFICONFIG_DESCRIPTION_MAX)
  1245. lo.label[EFICONFIG_DESCRIPTION_MAX - 1] = u'\0';
  1246. u16_strcpy(bo->description, lo.label);
  1247. /* EFI image file path is a first instance */
  1248. if (lo.file_path)
  1249. fill_file_info(lo.file_path, &bo->file_info, device_dp);
  1250. /* Initrd file path(optional) is placed at second instance. */
  1251. initrd_dp = efi_dp_from_lo(&lo, &efi_lf2_initrd_guid);
  1252. if (initrd_dp) {
  1253. fill_file_info(initrd_dp, &bo->initrd_info, initrd_device_dp);
  1254. efi_free_pool(initrd_dp);
  1255. }
  1256. if (size > 0)
  1257. memcpy(bo->optional_data, lo.optional_data, size);
  1258. }
  1259. while (1) {
  1260. ret = eficonfig_show_boot_option(bo, header_str);
  1261. if (ret == EFI_SUCCESS && bo->edit_completed)
  1262. break;
  1263. if (ret == EFI_NOT_READY)
  1264. continue;
  1265. if (ret != EFI_SUCCESS)
  1266. goto out;
  1267. }
  1268. if (bo->initrd_info.dp_volume) {
  1269. dp = eficonfig_create_device_path(bo->initrd_info.dp_volume,
  1270. bo->initrd_info.current_path);
  1271. if (!dp) {
  1272. ret = EFI_OUT_OF_RESOURCES;
  1273. goto out;
  1274. }
  1275. initrd_dp = efi_dp_append((const struct efi_device_path *)&id_dp, dp);
  1276. efi_free_pool(dp);
  1277. }
  1278. dp = eficonfig_create_device_path(bo->file_info.dp_volume, bo->file_info.current_path);
  1279. if (!dp) {
  1280. ret = EFI_OUT_OF_RESOURCES;
  1281. goto out;
  1282. }
  1283. final_dp_size = efi_dp_size(dp) + sizeof(END);
  1284. if (initrd_dp) {
  1285. final_dp = efi_dp_concat(dp, initrd_dp);
  1286. final_dp_size += efi_dp_size(initrd_dp) + sizeof(END);
  1287. } else {
  1288. final_dp = efi_dp_dup(dp);
  1289. }
  1290. efi_free_pool(dp);
  1291. if (!final_dp)
  1292. goto out;
  1293. if (utf16_utf8_strlen(bo->optional_data)) {
  1294. len = utf16_utf8_strlen(bo->optional_data) + 1;
  1295. tmp = calloc(1, len);
  1296. if (!tmp)
  1297. goto out;
  1298. p = tmp;
  1299. utf16_utf8_strncpy(&p, bo->optional_data, u16_strlen(bo->optional_data));
  1300. }
  1301. ret = eficonfig_set_boot_option(varname, final_dp, final_dp_size, bo->description, tmp);
  1302. out:
  1303. free(tmp);
  1304. free(bo->optional_data);
  1305. free(bo->description);
  1306. free(bo->file_info.current_path);
  1307. free(bo->initrd_info.current_path);
  1308. efi_free_pool(device_dp);
  1309. efi_free_pool(initrd_device_dp);
  1310. efi_free_pool(initrd_dp);
  1311. efi_free_pool(final_dp);
  1312. return ret;
  1313. }
  1314. /**
  1315. * eficonfig_process_add_boot_option() - handler to add boot option
  1316. *
  1317. * @data: pointer to the data for each entry
  1318. * Return: status code
  1319. */
  1320. static efi_status_t eficonfig_process_add_boot_option(void *data)
  1321. {
  1322. u16 varname[9];
  1323. efi_status_t ret;
  1324. struct eficonfig_boot_option *bo = NULL;
  1325. bo = calloc(1, sizeof(struct eficonfig_boot_option));
  1326. if (!bo)
  1327. return EFI_OUT_OF_RESOURCES;
  1328. ret = efi_bootmgr_get_unused_bootoption(varname, sizeof(varname), &bo->boot_index);
  1329. if (ret != EFI_SUCCESS)
  1330. return ret;
  1331. ret = eficonfig_edit_boot_option(varname, bo, NULL, 0, " ** Add Boot Option ** ");
  1332. if (ret != EFI_SUCCESS)
  1333. goto out;
  1334. ret = efi_bootmgr_append_bootorder((u16)bo->boot_index);
  1335. if (ret != EFI_SUCCESS)
  1336. goto out;
  1337. out:
  1338. free(bo);
  1339. /* to stay the parent menu */
  1340. ret = (ret == EFI_ABORTED) ? EFI_SUCCESS : ret;
  1341. return ret;
  1342. }
  1343. /**
  1344. * eficonfig_process_boot_selected() - handler to select boot option entry
  1345. *
  1346. * @data: pointer to the data for each entry
  1347. * Return: status code
  1348. */
  1349. static efi_status_t eficonfig_process_boot_selected(void *data)
  1350. {
  1351. struct eficonfig_boot_selection_data *info = data;
  1352. if (info)
  1353. *info->selected = info->boot_index;
  1354. return EFI_SUCCESS;
  1355. }
  1356. /**
  1357. * eficonfig_add_boot_selection_entry() - add boot option menu entry
  1358. *
  1359. * @efi_menu: pointer to store the efimenu structure
  1360. * @boot_index: boot option index to be added
  1361. * @selected: pointer to store the selected boot option index
  1362. * Return: status code
  1363. */
  1364. static efi_status_t eficonfig_add_boot_selection_entry(struct efimenu *efi_menu,
  1365. unsigned int boot_index,
  1366. unsigned int *selected)
  1367. {
  1368. char *buf, *p;
  1369. efi_status_t ret;
  1370. efi_uintn_t size;
  1371. void *load_option;
  1372. struct efi_load_option lo;
  1373. u16 varname[] = u"Boot####";
  1374. struct eficonfig_boot_selection_data *info;
  1375. efi_create_indexed_name(varname, sizeof(varname), "Boot", boot_index);
  1376. load_option = efi_get_var(varname, &efi_global_variable_guid, &size);
  1377. if (!load_option)
  1378. return EFI_SUCCESS;
  1379. ret = efi_deserialize_load_option(&lo, load_option, &size);
  1380. if (ret != EFI_SUCCESS) {
  1381. log_warning("Invalid load option for %ls\n", varname);
  1382. free(load_option);
  1383. return ret;
  1384. }
  1385. if (size >= sizeof(efi_guid_t) &&
  1386. !guidcmp(lo.optional_data, &efi_guid_bootmenu_auto_generated)) {
  1387. /*
  1388. * auto generated entry has GUID in optional_data,
  1389. * skip auto generated entry because it will be generated
  1390. * again even if it is edited or deleted.
  1391. */
  1392. free(load_option);
  1393. return EFI_SUCCESS;
  1394. }
  1395. info = calloc(1, sizeof(struct eficonfig_boot_selection_data));
  1396. if (!info) {
  1397. free(load_option);
  1398. return EFI_OUT_OF_RESOURCES;
  1399. }
  1400. buf = calloc(1, utf16_utf8_strlen(lo.label) + 1);
  1401. if (!buf) {
  1402. free(load_option);
  1403. free(info);
  1404. return EFI_OUT_OF_RESOURCES;
  1405. }
  1406. p = buf;
  1407. utf16_utf8_strcpy(&p, lo.label);
  1408. info->boot_index = boot_index;
  1409. info->selected = selected;
  1410. ret = eficonfig_append_menu_entry(efi_menu, buf, eficonfig_process_boot_selected, info);
  1411. if (ret != EFI_SUCCESS) {
  1412. free(load_option);
  1413. free(info);
  1414. return ret;
  1415. }
  1416. free(load_option);
  1417. return EFI_SUCCESS;
  1418. }
  1419. /**
  1420. * eficonfig_show_boot_selection() - construct boot option menu entry
  1421. *
  1422. * @selected: pointer to store the selected boot option index
  1423. * Return: status code
  1424. */
  1425. static efi_status_t eficonfig_show_boot_selection(unsigned int *selected)
  1426. {
  1427. u32 i;
  1428. u16 *bootorder;
  1429. efi_status_t ret;
  1430. u16 *var_name16 = NULL;
  1431. efi_uintn_t num, size, buf_size;
  1432. struct efimenu *efi_menu;
  1433. struct list_head *pos, *n;
  1434. struct eficonfig_entry *entry;
  1435. efi_menu = calloc(1, sizeof(struct efimenu));
  1436. if (!efi_menu)
  1437. return EFI_OUT_OF_RESOURCES;
  1438. bootorder = efi_get_var(u"BootOrder", &efi_global_variable_guid, &size);
  1439. INIT_LIST_HEAD(&efi_menu->list);
  1440. num = size / sizeof(u16);
  1441. /* list the load option in the order of BootOrder variable */
  1442. for (i = 0; i < num; i++) {
  1443. ret = eficonfig_add_boot_selection_entry(efi_menu, bootorder[i], selected);
  1444. if (ret != EFI_SUCCESS)
  1445. goto out;
  1446. if (efi_menu->count >= EFICONFIG_ENTRY_NUM_MAX - 1)
  1447. break;
  1448. }
  1449. /* list the remaining load option not included in the BootOrder */
  1450. buf_size = 128;
  1451. var_name16 = malloc(buf_size);
  1452. if (!var_name16)
  1453. return EFI_OUT_OF_RESOURCES;
  1454. var_name16[0] = 0;
  1455. for (;;) {
  1456. int index;
  1457. efi_guid_t guid;
  1458. ret = efi_next_variable_name(&buf_size, &var_name16, &guid);
  1459. if (ret == EFI_NOT_FOUND)
  1460. break;
  1461. if (ret != EFI_SUCCESS)
  1462. goto out;
  1463. if (efi_varname_is_load_option(var_name16, &index)) {
  1464. /* If the index is included in the BootOrder, skip it */
  1465. if (efi_search_bootorder(bootorder, num, index, NULL))
  1466. continue;
  1467. ret = eficonfig_add_boot_selection_entry(efi_menu, index, selected);
  1468. if (ret != EFI_SUCCESS)
  1469. goto out;
  1470. }
  1471. if (efi_menu->count >= EFICONFIG_ENTRY_NUM_MAX - 1)
  1472. break;
  1473. }
  1474. ret = eficonfig_append_quit_entry(efi_menu);
  1475. if (ret != EFI_SUCCESS)
  1476. goto out;
  1477. ret = eficonfig_process_common(efi_menu, " ** Select Boot Option **",
  1478. eficonfig_menu_desc,
  1479. eficonfig_display_statusline,
  1480. eficonfig_print_entry,
  1481. eficonfig_choice_entry);
  1482. out:
  1483. list_for_each_safe(pos, n, &efi_menu->list) {
  1484. entry = list_entry(pos, struct eficonfig_entry, list);
  1485. free(entry->data);
  1486. }
  1487. eficonfig_destroy(efi_menu);
  1488. free(var_name16);
  1489. return ret;
  1490. }
  1491. /**
  1492. * eficonfig_process_edit_boot_option() - handler to edit boot option
  1493. *
  1494. * @data: pointer to the data for each entry
  1495. * Return: status code
  1496. */
  1497. static efi_status_t eficonfig_process_edit_boot_option(void *data)
  1498. {
  1499. efi_status_t ret;
  1500. efi_uintn_t size;
  1501. struct eficonfig_boot_option *bo = NULL;
  1502. while (1) {
  1503. unsigned int selected;
  1504. void *load_option;
  1505. u16 varname[] = u"Boot####";
  1506. ret = eficonfig_show_boot_selection(&selected);
  1507. if (ret != EFI_SUCCESS)
  1508. break;
  1509. bo = calloc(1, sizeof(struct eficonfig_boot_option));
  1510. if (!bo) {
  1511. ret = EFI_OUT_OF_RESOURCES;
  1512. goto out;
  1513. }
  1514. bo->boot_index = selected;
  1515. efi_create_indexed_name(varname, sizeof(varname), "Boot", selected);
  1516. load_option = efi_get_var(varname, &efi_global_variable_guid, &size);
  1517. if (!load_option) {
  1518. free(bo);
  1519. ret = EFI_NOT_FOUND;
  1520. goto out;
  1521. }
  1522. ret = eficonfig_edit_boot_option(varname, bo, load_option, size,
  1523. " ** Edit Boot Option ** ");
  1524. free(load_option);
  1525. free(bo);
  1526. if (ret != EFI_SUCCESS && ret != EFI_ABORTED)
  1527. break;
  1528. }
  1529. out:
  1530. /* to stay the parent menu */
  1531. ret = (ret == EFI_ABORTED) ? EFI_NOT_READY : ret;
  1532. return ret;
  1533. }
  1534. /**
  1535. * eficonfig_print_change_boot_order_entry() - print the boot option entry
  1536. *
  1537. * @data: pointer to the data associated with each menu entry
  1538. */
  1539. static void eficonfig_print_change_boot_order_entry(void *data)
  1540. {
  1541. struct eficonfig_entry *entry = data;
  1542. bool reverse = (entry->efi_menu->active == entry->num);
  1543. if (entry->efi_menu->start > entry->num || entry->efi_menu->end < entry->num)
  1544. return;
  1545. printf(ANSI_CURSOR_POSITION ANSI_CLEAR_LINE,
  1546. (entry->num - entry->efi_menu->start) + EFICONFIG_MENU_HEADER_ROW_NUM + 1, 7);
  1547. if (reverse)
  1548. puts(ANSI_COLOR_REVERSE);
  1549. if (entry->num < entry->efi_menu->count - 2) {
  1550. if (((struct eficonfig_boot_order_data *)entry->data)->active)
  1551. printf("[*] ");
  1552. else
  1553. printf("[ ] ");
  1554. }
  1555. printf("%s", entry->title);
  1556. if (reverse)
  1557. puts(ANSI_COLOR_RESET);
  1558. }
  1559. /**
  1560. * eficonfig_choice_change_boot_order() - user key input handler
  1561. *
  1562. * @data: pointer to the menu entry
  1563. * Return: key string to identify the selected entry
  1564. */
  1565. char *eficonfig_choice_change_boot_order(void *data)
  1566. {
  1567. struct cli_ch_state s_cch, *cch = &s_cch;
  1568. struct list_head *pos, *n;
  1569. struct efimenu *efi_menu = data;
  1570. enum bootmenu_key key = BKEY_NONE;
  1571. struct eficonfig_entry *entry, *tmp;
  1572. cli_ch_init(cch);
  1573. while (1) {
  1574. key = bootmenu_loop(NULL, cch);
  1575. switch (key) {
  1576. case BKEY_PLUS:
  1577. if (efi_menu->active > 0 &&
  1578. efi_menu->active < efi_menu->count - 2) {
  1579. list_for_each_safe(pos, n, &efi_menu->list) {
  1580. entry = list_entry(pos, struct eficonfig_entry, list);
  1581. if (entry->num == efi_menu->active)
  1582. break;
  1583. }
  1584. tmp = list_entry(pos->prev, struct eficonfig_entry, list);
  1585. entry->num--;
  1586. tmp->num++;
  1587. list_del(&tmp->list);
  1588. list_add(&tmp->list, &entry->list);
  1589. eficonfig_menu_up(efi_menu);
  1590. }
  1591. return NULL;
  1592. case BKEY_UP:
  1593. if (efi_menu->active > 0)
  1594. eficonfig_menu_up(efi_menu);
  1595. return NULL;
  1596. case BKEY_MINUS:
  1597. if (efi_menu->active < efi_menu->count - 3) {
  1598. list_for_each_safe(pos, n, &efi_menu->list) {
  1599. entry = list_entry(pos, struct eficonfig_entry, list);
  1600. if (entry->num == efi_menu->active)
  1601. break;
  1602. }
  1603. tmp = list_entry(pos->next, struct eficonfig_entry, list);
  1604. entry->num++;
  1605. tmp->num--;
  1606. list_del(&entry->list);
  1607. list_add(&entry->list, &tmp->list);
  1608. eficonfig_menu_down(efi_menu);
  1609. }
  1610. return NULL;
  1611. case BKEY_DOWN:
  1612. if (efi_menu->active < efi_menu->count - 1)
  1613. eficonfig_menu_down(efi_menu);
  1614. return NULL;
  1615. case BKEY_SAVE:
  1616. /* force to select "Save" entry */
  1617. efi_menu->active = efi_menu->count - 2;
  1618. fallthrough;
  1619. case BKEY_SELECT:
  1620. /* "Save" */
  1621. if (efi_menu->active == efi_menu->count - 2) {
  1622. list_for_each_prev_safe(pos, n, &efi_menu->list) {
  1623. entry = list_entry(pos, struct eficonfig_entry, list);
  1624. if (entry->num == efi_menu->active)
  1625. break;
  1626. }
  1627. return entry->key;
  1628. }
  1629. /* "Quit" */
  1630. if (efi_menu->active == efi_menu->count - 1) {
  1631. entry = list_last_entry(&efi_menu->list,
  1632. struct eficonfig_entry,
  1633. list);
  1634. return entry->key;
  1635. }
  1636. /* Pressed key is not valid, wait next key press */
  1637. break;
  1638. case BKEY_SPACE:
  1639. if (efi_menu->active < efi_menu->count - 2) {
  1640. list_for_each_safe(pos, n, &efi_menu->list) {
  1641. entry = list_entry(pos, struct eficonfig_entry, list);
  1642. if (entry->num == efi_menu->active) {
  1643. struct eficonfig_boot_order_data *data = entry->data;
  1644. data->active = !data->active;
  1645. return NULL;
  1646. }
  1647. }
  1648. }
  1649. /* Pressed key is not valid, wait next key press */
  1650. break;
  1651. case BKEY_QUIT:
  1652. entry = list_last_entry(&efi_menu->list,
  1653. struct eficonfig_entry, list);
  1654. return entry->key;
  1655. default:
  1656. /* Pressed key is not valid, wait next key press */
  1657. break;
  1658. }
  1659. }
  1660. }
  1661. /**
  1662. * eficonfig_process_save_boot_order() - callback function for "Save" entry
  1663. *
  1664. * @data: pointer to the data
  1665. * Return: status code
  1666. */
  1667. static efi_status_t eficonfig_process_save_boot_order(void *data)
  1668. {
  1669. u32 count = 0;
  1670. efi_status_t ret;
  1671. efi_uintn_t size;
  1672. struct list_head *pos, *n;
  1673. u16 *new_bootorder;
  1674. struct efimenu *efi_menu;
  1675. struct eficonfig_entry *entry;
  1676. struct eficonfig_save_boot_order_data *save_data = data;
  1677. efi_menu = save_data->efi_menu;
  1678. /*
  1679. * The change boot order menu always has "Save" and "Quit" entries.
  1680. * !(efi_menu->count - 2) means there is no user defined boot option.
  1681. */
  1682. if (!(efi_menu->count - 2))
  1683. return EFI_SUCCESS;
  1684. new_bootorder = calloc(1, (efi_menu->count - 2) * sizeof(u16));
  1685. if (!new_bootorder) {
  1686. ret = EFI_OUT_OF_RESOURCES;
  1687. goto out;
  1688. }
  1689. /* create new BootOrder */
  1690. count = 0;
  1691. list_for_each_safe(pos, n, &efi_menu->list) {
  1692. struct eficonfig_boot_order_data *data;
  1693. entry = list_entry(pos, struct eficonfig_entry, list);
  1694. /* exit the loop when iteration reaches "Save" */
  1695. if (!strncmp(entry->title, "Save", strlen("Save")))
  1696. break;
  1697. data = entry->data;
  1698. if (data->active)
  1699. new_bootorder[count++] = data->boot_index;
  1700. }
  1701. size = count * sizeof(u16);
  1702. ret = efi_set_variable_int(u"BootOrder", &efi_global_variable_guid,
  1703. EFI_VARIABLE_NON_VOLATILE |
  1704. EFI_VARIABLE_BOOTSERVICE_ACCESS |
  1705. EFI_VARIABLE_RUNTIME_ACCESS,
  1706. size, new_bootorder, false);
  1707. save_data->selected = true;
  1708. out:
  1709. free(new_bootorder);
  1710. return ret;
  1711. }
  1712. /**
  1713. * eficonfig_add_change_boot_order_entry() - add boot order entry
  1714. *
  1715. * @efi_menu: pointer to the efimenu structure
  1716. * @boot_index: boot option index to be added
  1717. * @active: flag to include the boot option into BootOrder
  1718. * Return: status code
  1719. */
  1720. static efi_status_t eficonfig_add_change_boot_order_entry(struct efimenu *efi_menu,
  1721. u32 boot_index, bool active)
  1722. {
  1723. char *title, *p;
  1724. efi_status_t ret;
  1725. efi_uintn_t size;
  1726. void *load_option;
  1727. struct efi_load_option lo;
  1728. u16 varname[] = u"Boot####";
  1729. struct eficonfig_boot_order_data *data;
  1730. efi_create_indexed_name(varname, sizeof(varname), "Boot", boot_index);
  1731. load_option = efi_get_var(varname, &efi_global_variable_guid, &size);
  1732. if (!load_option)
  1733. return EFI_SUCCESS;
  1734. ret = efi_deserialize_load_option(&lo, load_option, &size);
  1735. if (ret != EFI_SUCCESS)
  1736. goto out;
  1737. data = calloc(1, sizeof(*data));
  1738. if (!data) {
  1739. ret = EFI_OUT_OF_RESOURCES;
  1740. goto out;
  1741. }
  1742. title = calloc(1, utf16_utf8_strlen(lo.label) + 1);
  1743. if (!title) {
  1744. free(data);
  1745. ret = EFI_OUT_OF_RESOURCES;
  1746. goto out;
  1747. }
  1748. p = title;
  1749. utf16_utf8_strcpy(&p, lo.label);
  1750. data->boot_index = boot_index;
  1751. data->active = active;
  1752. ret = eficonfig_append_menu_entry(efi_menu, title, NULL, data);
  1753. if (ret != EFI_SUCCESS) {
  1754. free(data);
  1755. free(title);
  1756. goto out;
  1757. }
  1758. out:
  1759. free(load_option);
  1760. return ret;
  1761. }
  1762. /**
  1763. * eficonfig_create_change_boot_order_entry() - create boot order entry
  1764. *
  1765. * @efi_menu: pointer to the efimenu structure
  1766. * @bootorder: pointer to the BootOrder variable
  1767. * @num: number of BootOrder entry
  1768. * Return: status code
  1769. */
  1770. static efi_status_t eficonfig_create_change_boot_order_entry(struct efimenu *efi_menu,
  1771. u16 *bootorder, efi_uintn_t num)
  1772. {
  1773. u32 i;
  1774. char *title;
  1775. efi_status_t ret;
  1776. u16 *var_name16 = NULL;
  1777. efi_uintn_t size, buf_size;
  1778. struct eficonfig_save_boot_order_data *save_data;
  1779. /* list the load option in the order of BootOrder variable */
  1780. for (i = 0; i < num; i++) {
  1781. if (efi_menu->count >= EFICONFIG_ENTRY_NUM_MAX - 2)
  1782. break;
  1783. ret = eficonfig_add_change_boot_order_entry(efi_menu, bootorder[i], true);
  1784. if (ret != EFI_SUCCESS)
  1785. goto out;
  1786. }
  1787. /* list the remaining load option not included in the BootOrder */
  1788. buf_size = 128;
  1789. var_name16 = malloc(buf_size);
  1790. if (!var_name16)
  1791. return EFI_OUT_OF_RESOURCES;
  1792. var_name16[0] = 0;
  1793. for (;;) {
  1794. int index;
  1795. efi_guid_t guid;
  1796. if (efi_menu->count >= EFICONFIG_ENTRY_NUM_MAX - 2)
  1797. break;
  1798. size = buf_size;
  1799. ret = efi_next_variable_name(&buf_size, &var_name16, &guid);
  1800. if (ret == EFI_NOT_FOUND)
  1801. break;
  1802. if (ret != EFI_SUCCESS)
  1803. goto out;
  1804. if (efi_varname_is_load_option(var_name16, &index)) {
  1805. /* If the index is included in the BootOrder, skip it */
  1806. if (efi_search_bootorder(bootorder, num, index, NULL))
  1807. continue;
  1808. ret = eficonfig_add_change_boot_order_entry(efi_menu, index, false);
  1809. if (ret != EFI_SUCCESS)
  1810. goto out;
  1811. }
  1812. }
  1813. /* add "Save" and "Quit" entries */
  1814. title = strdup("Save");
  1815. if (!title) {
  1816. ret = EFI_OUT_OF_RESOURCES;
  1817. goto out;
  1818. }
  1819. save_data = malloc(sizeof(struct eficonfig_save_boot_order_data));
  1820. if (!save_data) {
  1821. ret = EFI_OUT_OF_RESOURCES;
  1822. goto out;
  1823. }
  1824. save_data->efi_menu = efi_menu;
  1825. save_data->selected = false;
  1826. ret = eficonfig_append_menu_entry(efi_menu, title,
  1827. eficonfig_process_save_boot_order,
  1828. save_data);
  1829. if (ret != EFI_SUCCESS)
  1830. goto out;
  1831. ret = eficonfig_append_quit_entry(efi_menu);
  1832. if (ret != EFI_SUCCESS)
  1833. goto out;
  1834. efi_menu->active = 0;
  1835. out:
  1836. free(var_name16);
  1837. return ret;
  1838. }
  1839. /**
  1840. * eficonfig_process_change_boot_order() - handler to change boot order
  1841. *
  1842. * @data: pointer to the data for each entry
  1843. * Return: status code
  1844. */
  1845. static efi_status_t eficonfig_process_change_boot_order(void *data)
  1846. {
  1847. u16 *bootorder;
  1848. efi_status_t ret;
  1849. efi_uintn_t num, size;
  1850. struct list_head *pos, *n;
  1851. struct eficonfig_entry *entry;
  1852. struct efimenu *efi_menu;
  1853. efi_menu = calloc(1, sizeof(struct efimenu));
  1854. if (!efi_menu)
  1855. return EFI_OUT_OF_RESOURCES;
  1856. bootorder = efi_get_var(u"BootOrder", &efi_global_variable_guid, &size);
  1857. INIT_LIST_HEAD(&efi_menu->list);
  1858. num = size / sizeof(u16);
  1859. ret = eficonfig_create_change_boot_order_entry(efi_menu, bootorder, num);
  1860. if (ret != EFI_SUCCESS)
  1861. goto out;
  1862. while (1) {
  1863. ret = eficonfig_process_common(efi_menu,
  1864. " ** Change Boot Order **",
  1865. eficonfig_change_boot_order_desc,
  1866. eficonfig_display_statusline,
  1867. eficonfig_print_change_boot_order_entry,
  1868. eficonfig_choice_change_boot_order);
  1869. /* exit from the menu if user selects the "Save" entry. */
  1870. if (ret == EFI_SUCCESS && efi_menu->active == (efi_menu->count - 2)) {
  1871. list_for_each_prev_safe(pos, n, &efi_menu->list) {
  1872. entry = list_entry(pos, struct eficonfig_entry, list);
  1873. if (entry->num == efi_menu->active)
  1874. break;
  1875. }
  1876. if (((struct eficonfig_save_boot_order_data *)entry->data)->selected)
  1877. break;
  1878. }
  1879. if (ret != EFI_SUCCESS)
  1880. break;
  1881. }
  1882. out:
  1883. free(bootorder);
  1884. list_for_each_safe(pos, n, &efi_menu->list) {
  1885. entry = list_entry(pos, struct eficonfig_entry, list);
  1886. free(entry->data);
  1887. }
  1888. eficonfig_destroy(efi_menu);
  1889. /* to stay the parent menu */
  1890. ret = (ret == EFI_ABORTED) ? EFI_NOT_READY : ret;
  1891. return ret;
  1892. }
  1893. /**
  1894. * eficonfig_process_delete_boot_option() - handler to delete boot option
  1895. *
  1896. * @data: pointer to the data for each entry
  1897. * Return: status code
  1898. */
  1899. static efi_status_t eficonfig_process_delete_boot_option(void *data)
  1900. {
  1901. efi_status_t ret;
  1902. unsigned int selected;
  1903. while (1) {
  1904. ret = eficonfig_show_boot_selection(&selected);
  1905. if (ret == EFI_SUCCESS)
  1906. ret = efi_bootmgr_delete_boot_option(selected);
  1907. if (ret != EFI_SUCCESS)
  1908. break;
  1909. }
  1910. /* to stay the parent menu */
  1911. ret = (ret == EFI_ABORTED) ? EFI_NOT_READY : ret;
  1912. return ret;
  1913. }
  1914. /**
  1915. * eficonfig_init() - do required initialization for eficonfig command
  1916. *
  1917. * Return: status code
  1918. */
  1919. static efi_status_t eficonfig_init(void)
  1920. {
  1921. efi_status_t ret = EFI_SUCCESS;
  1922. static bool init;
  1923. struct efi_handler *handler;
  1924. unsigned long columns, rows;
  1925. if (!init) {
  1926. ret = efi_search_protocol(efi_root, &efi_guid_text_input_protocol, &handler);
  1927. if (ret != EFI_SUCCESS)
  1928. return ret;
  1929. ret = efi_protocol_open(handler, (void **)&cin, efi_root, NULL,
  1930. EFI_OPEN_PROTOCOL_GET_PROTOCOL);
  1931. if (ret != EFI_SUCCESS)
  1932. return ret;
  1933. ret = efi_search_protocol(efi_root, &efi_guid_text_output_protocol, &handler);
  1934. if (ret != EFI_SUCCESS)
  1935. return ret;
  1936. ret = efi_protocol_open(handler, (void **)&cout, efi_root, NULL,
  1937. EFI_OPEN_PROTOCOL_GET_PROTOCOL);
  1938. if (ret != EFI_SUCCESS)
  1939. return ret;
  1940. cout->query_mode(cout, cout->mode->mode, &columns, &rows);
  1941. avail_row = rows - (EFICONFIG_MENU_HEADER_ROW_NUM +
  1942. EFICONFIG_MENU_DESC_ROW_NUM);
  1943. if (avail_row <= 0) {
  1944. eficonfig_print_msg("Console size is too small!");
  1945. return EFI_INVALID_PARAMETER;
  1946. }
  1947. /* TODO: Should we check the minimum column size? */
  1948. }
  1949. init = true;
  1950. return ret;
  1951. }
  1952. static const struct eficonfig_item maintenance_menu_items[] = {
  1953. {"Add Boot Option", eficonfig_process_add_boot_option},
  1954. {"Edit Boot Option", eficonfig_process_edit_boot_option},
  1955. {"Change Boot Order", eficonfig_process_change_boot_order},
  1956. {"Delete Boot Option", eficonfig_process_delete_boot_option},
  1957. #if (IS_ENABLED(CONFIG_EFI_SECURE_BOOT) && IS_ENABLED(CONFIG_EFI_MM_COMM_TEE))
  1958. {"Secure Boot Configuration", eficonfig_process_secure_boot_config},
  1959. #endif
  1960. {"Quit", eficonfig_process_quit},
  1961. };
  1962. /**
  1963. * do_eficonfig() - execute `eficonfig` command
  1964. *
  1965. * @cmdtp: table entry describing command
  1966. * @flag: bitmap indicating how the command was invoked
  1967. * @argc: number of arguments
  1968. * @argv: command line arguments
  1969. * Return: status code
  1970. */
  1971. static int do_eficonfig(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
  1972. {
  1973. efi_status_t ret;
  1974. struct efimenu *efi_menu;
  1975. if (argc > 1)
  1976. return CMD_RET_USAGE;
  1977. ret = efi_init_obj_list();
  1978. if (ret != EFI_SUCCESS) {
  1979. log_err("Error: Cannot initialize UEFI sub-system, r = %lu\n",
  1980. ret & ~EFI_ERROR_MASK);
  1981. return CMD_RET_FAILURE;
  1982. }
  1983. ret = eficonfig_init();
  1984. if (ret != EFI_SUCCESS)
  1985. return CMD_RET_FAILURE;
  1986. ret = efi_bootmgr_update_media_device_boot_option();
  1987. if (ret != EFI_SUCCESS)
  1988. return ret;
  1989. while (1) {
  1990. efi_menu = eficonfig_create_fixed_menu(maintenance_menu_items,
  1991. ARRAY_SIZE(maintenance_menu_items));
  1992. if (!efi_menu)
  1993. return CMD_RET_FAILURE;
  1994. ret = eficonfig_process_common(efi_menu,
  1995. " ** UEFI Maintenance Menu **",
  1996. eficonfig_menu_desc,
  1997. eficonfig_display_statusline,
  1998. eficonfig_print_entry,
  1999. eficonfig_choice_entry);
  2000. eficonfig_destroy(efi_menu);
  2001. if (ret == EFI_ABORTED)
  2002. break;
  2003. }
  2004. return CMD_RET_SUCCESS;
  2005. }
  2006. U_BOOT_CMD(
  2007. eficonfig, 1, 0, do_eficonfig,
  2008. "provide menu-driven UEFI variable maintenance interface",
  2009. ""
  2010. );