0004-Support-auto-boot-timeout-delay-bootflow-menu.patch 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. From d9371422ac74ea73d1620f01300a7136a7649754 Mon Sep 17 00:00:00 2001
  2. From: Leah Rowe <info@minifree.org>
  3. Date: Wed, 4 Dec 2024 06:52:39 +0000
  4. Subject: [PATCH 1/1] Support auto-boot timeout delay bootflow menu
  5. The bootflow menu cannot currently auto-boot a selected entry,
  6. which means that the user must press enter to boot their system.
  7. This can be a problem on headless setups; for example, it is not
  8. currently feasible to set up a headless server with U-Boot, when
  9. using it to boot via UEFI on a coreboot setup.
  10. This patch adds the following build-time configuration option:
  11. CONFIG_CMD_BOOTFLOW_BOOTDELAY
  12. This creates a timeout delay in the given number of seconds.
  13. If an arrow key is press to navigate the menu, the timer is
  14. disabled and the user must then press enter to boot the selected
  15. option. When this happens, the timeout display is replaced by
  16. the old message indicating that the user should press enter.
  17. The default boot delay is 30 seconds, and the timeout is enabled
  18. by default. Setting it to zero will restore the old behaviour,
  19. whereby no timeout is provided and the user must press enter.
  20. If a negative integer is provided, the timer will default to
  21. zero. The timer value is further filtered by modulus of 100,
  22. so that the maximum number of seconds allowed is 99 seconds.
  23. Signed-off-by: Leah Rowe <info@minifree.org>
  24. ---
  25. boot/bootflow_menu.c | 117 +++++++++++++++++++++++++++++++++++--
  26. cmd/Kconfig | 12 ++++
  27. doc/usage/cmd/bootflow.rst | 11 ++++
  28. include/bootflow.h | 10 +++-
  29. 4 files changed, 143 insertions(+), 7 deletions(-)
  30. diff --git a/boot/bootflow_menu.c b/boot/bootflow_menu.c
  31. index 9d0dc352f9..172139b187 100644
  32. --- a/boot/bootflow_menu.c
  33. +++ b/boot/bootflow_menu.c
  34. @@ -30,7 +30,7 @@ struct menu_priv {
  35. int num_bootflows;
  36. };
  37. -int bootflow_menu_new(struct expo **expp)
  38. +int bootflow_menu_new(struct expo **expp, const char *prompt)
  39. {
  40. struct udevice *last_bootdev;
  41. struct scene_obj_menu *menu;
  42. @@ -54,7 +54,7 @@ int bootflow_menu_new(struct expo **expp)
  43. return log_msg_ret("scn", ret);
  44. ret |= scene_txt_str(scn, "prompt", OBJ_PROMPT, STR_PROMPT,
  45. - "UP and DOWN to choose, ENTER to select", NULL);
  46. + prompt, NULL);
  47. ret = scene_menu(scn, "main", OBJ_MENU, &menu);
  48. ret |= scene_obj_set_pos(scn, OBJ_MENU, MARGIN_LEFT, 100);
  49. @@ -138,6 +138,29 @@ int bootflow_menu_new(struct expo **expp)
  50. return 0;
  51. }
  52. +int bootflow_menu_show_countdown(struct expo *exp, char *prompt,
  53. + char bootflow_delay)
  54. +{
  55. + char *i;
  56. +
  57. + if (prompt == NULL)
  58. + return 0;
  59. + if (strlen(prompt) < 2)
  60. + return 0;
  61. +
  62. + i = prompt + strlen(prompt) - 2;
  63. +
  64. + if (bootflow_delay >= 10) {
  65. + *(i) = 48 + (bootflow_delay / 10);
  66. + *(i + 1) = 48 + (bootflow_delay % 10);
  67. + } else {
  68. + *(i) = 48 + bootflow_delay;
  69. + *(i + 1) = ' ';
  70. + }
  71. +
  72. + return expo_render(exp);
  73. +}
  74. +
  75. int bootflow_menu_apply_theme(struct expo *exp, ofnode node)
  76. {
  77. struct menu_priv *priv = exp->priv;
  78. @@ -184,14 +207,62 @@ int bootflow_menu_run(struct bootstd_priv *std, bool text_mode,
  79. struct expo *exp;
  80. uint sel_id;
  81. bool done;
  82. - int ret;
  83. + int i, ret;
  84. +
  85. + /* Auto-boot countdown */
  86. + char bootflow_delay_secs, *prompt;
  87. + int bootflow_time, bootflow_delay;
  88. + bool skip_render_once = false;
  89. + bool bootflow_countdown = false;
  90. +
  91. + /* TODO: perhaps set based on defconfig? */
  92. + /* WARNING: These two strings must be of the same length. */
  93. + char promptChoice[] = "UP and DOWN to choose, ENTER to select";
  94. + char promptTimeout[] = "UP and DOWN to choose. Auto-boot in ";
  95. +/*
  96. + // Uncomment if the strings become configurable (defconfig):
  97. + // (to prevent buffer overflows)
  98. + char promptDefault[] = "UP and DOWN to choose, ENTER to select";
  99. + if (promptTimeout = NULL)
  100. + promptTimeout = promptDefault;
  101. + if (promptChoice = NULL)
  102. + promptChoice = promptDefault;
  103. + if (strlen(promptChoice) < 2)
  104. + promptChoice = promptDefault;
  105. + if (strlen(promptTimeout) < 2)
  106. + promptTimeout = promptDefault;
  107. + if (strlen(promptChoice) != strlen(promptTimeout))
  108. + promptChoice = promptTimeout;
  109. +*/
  110. + prompt = promptChoice;
  111. +
  112. + bootflow_delay_secs = 15; /* TODO: set based on defconfig. */
  113. +
  114. +#if defined(CONFIG_CMD_BOOTFLOW_BOOTDELAY)
  115. + /* If set to zero, the auto-boot timeout is disabled. */
  116. + bootflow_delay_secs = CONFIG_CMD_BOOTFLOW_BOOTDELAY;
  117. +#else
  118. + bootflow_delay_secs = 30;
  119. +#endif
  120. +
  121. + if (bootflow_delay_secs < 0)
  122. + bootflow_delay_secs = 0; /* disable countdown if negative */
  123. + bootflow_delay_secs %= 100; /* No higher than 99 seconds */
  124. +
  125. + if (bootflow_delay_secs > 0) {
  126. + bootflow_countdown = true; /* enable auto-boot countdown */
  127. + prompt = promptTimeout;
  128. + bootflow_time = 0; /* Time elapsed in milliseconds */
  129. + bootflow_delay =
  130. + (int)bootflow_delay_secs * 1000; /* milliseconds */
  131. + }
  132. cli_ch_init(cch);
  133. sel_bflow = NULL;
  134. *bflowp = NULL;
  135. - ret = bootflow_menu_new(&exp);
  136. + ret = bootflow_menu_new(&exp, prompt);
  137. if (ret)
  138. return log_msg_ret("exp", ret);
  139. @@ -216,12 +287,20 @@ int bootflow_menu_run(struct bootstd_priv *std, bool text_mode,
  140. if (text_mode)
  141. expo_set_text_mode(exp, text_mode);
  142. + if (bootflow_countdown) {
  143. + ret = bootflow_menu_show_countdown(exp, prompt,
  144. + bootflow_delay_secs);
  145. + skip_render_once = true; /* Don't print menu twice on start */
  146. + }
  147. done = false;
  148. do {
  149. struct expo_action act;
  150. int ichar, key;
  151. - ret = expo_render(exp);
  152. + if (skip_render_once)
  153. + skip_render_once = false;
  154. + else
  155. + ret = expo_render(exp);
  156. if (ret)
  157. break;
  158. @@ -231,7 +310,23 @@ int bootflow_menu_run(struct bootstd_priv *std, bool text_mode,
  159. schedule();
  160. mdelay(2);
  161. ichar = cli_ch_process(cch, -ETIMEDOUT);
  162. + if (bootflow_countdown) {
  163. + bootflow_delay -= 2;
  164. + bootflow_time += 2;
  165. + if (bootflow_delay <= 0)
  166. + ichar='\n';
  167. + if (bootflow_time < 1000)
  168. + continue;
  169. + bootflow_time = 0;
  170. + --bootflow_delay_secs;
  171. + ret = bootflow_menu_show_countdown(exp,
  172. + prompt, bootflow_delay_secs);
  173. + if (ret)
  174. + break;
  175. + }
  176. }
  177. + if (ret)
  178. + break;
  179. if (!ichar) {
  180. ichar = getchar();
  181. ichar = cli_ch_process(cch, ichar);
  182. @@ -265,6 +360,17 @@ int bootflow_menu_run(struct bootstd_priv *std, bool text_mode,
  183. break;
  184. }
  185. }
  186. + if (bootflow_countdown) {
  187. + /* A key press interrupted the auto-boot timeout */
  188. + bootflow_countdown = false;
  189. + if (strlen(prompt) == strlen(promptChoice)) {
  190. + /* "Auto-boot in" becomes "Press ENTER" */
  191. + (void) memcpy(prompt, promptChoice,
  192. + strlen(promptChoice));
  193. + ret = expo_render(exp);
  194. + skip_render_once = true;
  195. + }
  196. + }
  197. } while (!done);
  198. if (ret)
  199. @@ -272,7 +378,6 @@ int bootflow_menu_run(struct bootstd_priv *std, bool text_mode,
  200. if (sel_id) {
  201. struct bootflow *bflow;
  202. - int i;
  203. for (ret = bootflow_first_glob(&bflow), i = 0; !ret && i < 36;
  204. ret = bootflow_next_glob(&bflow), i++) {
  205. diff --git a/cmd/Kconfig b/cmd/Kconfig
  206. index 978f44eda4..0303869625 100644
  207. --- a/cmd/Kconfig
  208. +++ b/cmd/Kconfig
  209. @@ -288,6 +288,7 @@ config CMD_BOOTDEV
  210. config CMD_BOOTFLOW
  211. bool "bootflow"
  212. depends on BOOTSTD
  213. + select CMD_BOOTFLOW_BOOTDELAY
  214. default y
  215. help
  216. Support scanning for bootflows available with the bootdevs. The
  217. @@ -303,6 +304,17 @@ config CMD_BOOTFLOW_FULL
  218. This command is not necessary for bootstd to work.
  219. +config CMD_BOOTFLOW_BOOTDELAY
  220. + int "bootflow - delay in seconds before booting the first menu option"
  221. + depends on CMD_BOOTFLOW
  222. + default 30
  223. + help
  224. + On the bootflow menu, wait for the defined number of seconds before
  225. + automatically booting. Unless interrupted, this will auto-boot the
  226. + first option in the generated list of boot options.
  227. +
  228. + Set this to zero if you wish to disable the auto-boot timeout.
  229. +
  230. config CMD_BOOTMETH
  231. bool "bootmeth"
  232. depends on BOOTSTD
  233. diff --git a/doc/usage/cmd/bootflow.rst b/doc/usage/cmd/bootflow.rst
  234. index 5d41fe37a7..728f294274 100644
  235. --- a/doc/usage/cmd/bootflow.rst
  236. +++ b/doc/usage/cmd/bootflow.rst
  237. @@ -32,6 +32,17 @@ Note that `CONFIG_BOOTSTD_FULL` (which enables `CONFIG_CMD_BOOTFLOW_FULL) must
  238. be enabled to obtain full functionality with this command. Otherwise, it only
  239. supports `bootflow scan` which scans and boots the first available bootflow.
  240. +The `CONFIG_CMD_BOOTFLOW_BOOTDELAY` option can be set, defining (in seconds) the
  241. +amount of time that U-Boot will wait; after this time passes, it will
  242. +automatically boot the first item when generating a bootflow menu. If the value
  243. +is set to zero, the timeout is disabled and the user must press enter; if it's
  244. +negative, the timeout is disabled, and the maximum number of seconds is 99
  245. +seconds. If a value higher than 100 is provided, the value is changed to a
  246. +modulus of 100 (remainder of the value divided by 100).
  247. +
  248. +If the `CONFIG_BOOTFLOW_BOOTFLOW` option is undefined, the timeout will default
  249. +to 30 seconds.
  250. +
  251. bootflow scan
  252. ~~~~~~~~~~~~~
  253. diff --git a/include/bootflow.h b/include/bootflow.h
  254. index 4d2fc7b69b..9f4245caa7 100644
  255. --- a/include/bootflow.h
  256. +++ b/include/bootflow.h
  257. @@ -452,7 +452,15 @@ int bootflow_iter_check_system(const struct bootflow_iter *iter);
  258. * @expp: Returns the expo created
  259. * Returns 0 on success, -ve on error
  260. */
  261. -int bootflow_menu_new(struct expo **expp);
  262. +int bootflow_menu_new(struct expo **expp, const char *prompt);
  263. +
  264. +/**
  265. + * bootflow_menu_show_countdown() - Show countdown timer for auto-boot
  266. + *
  267. + * Returns the value of expo_render()
  268. + */
  269. +int bootflow_menu_show_countdown(struct expo *exp, char *prompt,
  270. + char bootflow_delay);
  271. /**
  272. * bootflow_menu_apply_theme() - Apply a theme to a bootmenu
  273. --
  274. 2.39.5