vboot_ui.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570
  1. /* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
  2. * Use of this source code is governed by a BSD-style license that can be
  3. * found in the LICENSE file.
  4. *
  5. * High-level firmware wrapper API - user interface for RW firmware
  6. */
  7. #include "sysincludes.h"
  8. #include "2sysincludes.h"
  9. #include "2common.h"
  10. #include "2misc.h"
  11. #include "2nvstorage.h"
  12. #include "2rsa.h"
  13. #include "ec_sync.h"
  14. #include "gbb_access.h"
  15. #include "gbb_header.h"
  16. #include "load_kernel_fw.h"
  17. #include "region.h"
  18. #include "rollback_index.h"
  19. #include "utility.h"
  20. #include "vb2_common.h"
  21. #include "vboot_api.h"
  22. #include "vboot_audio.h"
  23. #include "vboot_common.h"
  24. #include "vboot_display.h"
  25. #include "vboot_kernel.h"
  26. #include "vboot_nvstorage.h"
  27. static void VbAllowUsbBoot(struct vb2_context *ctx)
  28. {
  29. VB2_DEBUG(".");
  30. vb2_nv_set(ctx, VB2_NV_DEV_BOOT_USB, 1);
  31. }
  32. /**
  33. * Checks GBB flags against VbExIsShutdownRequested() shutdown request to
  34. * determine if a shutdown is required.
  35. *
  36. * Returns true if a shutdown is required and false if no shutdown is required.
  37. */
  38. static int VbWantShutdown(uint32_t gbb_flags)
  39. {
  40. uint32_t shutdown_request = VbExIsShutdownRequested();
  41. /* If desired, ignore shutdown request due to lid closure. */
  42. if (gbb_flags & GBB_FLAG_DISABLE_LID_SHUTDOWN)
  43. shutdown_request &= ~VB_SHUTDOWN_REQUEST_LID_CLOSED;
  44. return !!shutdown_request;
  45. }
  46. static void VbTryLegacy(int allowed)
  47. {
  48. if (!allowed)
  49. VB2_DEBUG("VbBootDeveloper() - Legacy boot is disabled\n");
  50. else if (0 != RollbackKernelLock(0))
  51. VB2_DEBUG("Error locking kernel versions on legacy boot.\n");
  52. else
  53. VbExLegacy(); /* will not return if successful */
  54. /* If legacy boot fails, beep and return to calling UI loop. */
  55. VbExBeep(120, 400);
  56. VbExSleepMs(120);
  57. VbExBeep(120, 400);
  58. }
  59. uint32_t VbTryUsb(struct vb2_context *ctx, VbCommonParams *cparams)
  60. {
  61. uint32_t retval = VbTryLoadKernel(ctx, cparams, VB_DISK_FLAG_REMOVABLE);
  62. if (VBERROR_SUCCESS == retval) {
  63. VB2_DEBUG("VbBootDeveloper() - booting USB\n");
  64. } else {
  65. VB2_DEBUG("VbBootDeveloper() - no kernel found on USB\n");
  66. VbExBeep(250, 200);
  67. VbExSleepMs(120);
  68. /*
  69. * Clear recovery requests from failed
  70. * kernel loading, so that powering off
  71. * at this point doesn't put us into
  72. * recovery mode.
  73. */
  74. vb2_nv_set(ctx, VB2_NV_RECOVERY_REQUEST,
  75. VBNV_RECOVERY_NOT_REQUESTED);
  76. }
  77. return retval;
  78. }
  79. #define CONFIRM_KEY_DELAY 20 /* Check confirm screen keys every 20ms */
  80. int VbUserConfirms(struct vb2_context *ctx, VbCommonParams *cparams,
  81. uint32_t confirm_flags)
  82. {
  83. VbSharedDataHeader *shared =
  84. (VbSharedDataHeader *)cparams->shared_data_blob;
  85. uint32_t key;
  86. uint32_t key_flags;
  87. uint32_t button;
  88. int rec_button_was_pressed = 0;
  89. VB2_DEBUG("Entering(%x)\n", confirm_flags);
  90. /* Await further instructions */
  91. while (1) {
  92. if (VbWantShutdown(cparams->gbb->flags))
  93. return -1;
  94. key = VbExKeyboardReadWithFlags(&key_flags);
  95. button = VbExGetSwitches(VB_INIT_FLAG_REC_BUTTON_PRESSED);
  96. switch (key) {
  97. case '\r':
  98. /* If we require a trusted keyboard for confirmation,
  99. * but the keyboard may be faked (for instance, a USB
  100. * device), beep and keep waiting.
  101. */
  102. if (confirm_flags & VB_CONFIRM_MUST_TRUST_KEYBOARD &&
  103. !(key_flags & VB_KEY_FLAG_TRUSTED_KEYBOARD)) {
  104. VbExBeep(120, 400);
  105. break;
  106. }
  107. VB2_DEBUG("Yes (1)\n");
  108. return 1;
  109. break;
  110. case ' ':
  111. VB2_DEBUG("Space (%d)\n",
  112. confirm_flags & VB_CONFIRM_SPACE_MEANS_NO);
  113. if (confirm_flags & VB_CONFIRM_SPACE_MEANS_NO)
  114. return 0;
  115. break;
  116. case 0x1b:
  117. VB2_DEBUG("No (0)\n");
  118. return 0;
  119. break;
  120. default:
  121. /* If the recovery button is physical, and is pressed,
  122. * this is also a YES, but must wait for release.
  123. */
  124. if (!(shared->flags & VBSD_BOOT_REC_SWITCH_VIRTUAL)) {
  125. if (button) {
  126. VB2_DEBUG("Rec button pressed\n");
  127. rec_button_was_pressed = 1;
  128. } else if (rec_button_was_pressed) {
  129. VB2_DEBUG("Rec button (1)\n");
  130. return 1;
  131. }
  132. }
  133. VbCheckDisplayKey(ctx, cparams, key);
  134. }
  135. VbExSleepMs(CONFIRM_KEY_DELAY);
  136. }
  137. /* Not reached, but compiler will complain without it */
  138. return -1;
  139. }
  140. static const char dev_disable_msg[] =
  141. "Developer mode is disabled on this device by system policy.\n"
  142. "For more information, see http://dev.chromium.org/chromium-os/fwmp\n"
  143. "\n";
  144. VbError_t vb2_developer_ui(struct vb2_context *ctx, VbCommonParams *cparams)
  145. {
  146. GoogleBinaryBlockHeader *gbb = cparams->gbb;
  147. VbSharedDataHeader *shared =
  148. (VbSharedDataHeader *)cparams->shared_data_blob;
  149. uint32_t disable_dev_boot = 0;
  150. uint32_t use_usb = 0;
  151. uint32_t use_legacy = 0;
  152. uint32_t ctrl_d_pressed = 0;
  153. VbAudioContext *audio = 0;
  154. VB2_DEBUG("Entering\n");
  155. /* Check if USB booting is allowed */
  156. uint32_t allow_usb = vb2_nv_get(ctx, VB2_NV_DEV_BOOT_USB);
  157. uint32_t allow_legacy = vb2_nv_get(ctx, VB2_NV_DEV_BOOT_LEGACY);
  158. /* Check if the default is to boot using disk, usb, or legacy */
  159. uint32_t default_boot = vb2_nv_get(ctx, VB2_NV_DEV_DEFAULT_BOOT);
  160. if(default_boot == VBNV_DEV_DEFAULT_BOOT_USB)
  161. use_usb = 1;
  162. if(default_boot == VBNV_DEV_DEFAULT_BOOT_LEGACY)
  163. use_legacy = 1;
  164. /* Handle GBB flag override */
  165. if (gbb->flags & GBB_FLAG_FORCE_DEV_BOOT_USB)
  166. allow_usb = 1;
  167. if (gbb->flags & GBB_FLAG_FORCE_DEV_BOOT_LEGACY)
  168. allow_legacy = 1;
  169. if (gbb->flags & GBB_FLAG_DEFAULT_DEV_BOOT_LEGACY) {
  170. use_legacy = 1;
  171. use_usb = 0;
  172. }
  173. /* Handle FWMP override */
  174. uint32_t fwmp_flags = vb2_get_fwmp_flags();
  175. if (fwmp_flags & FWMP_DEV_ENABLE_USB)
  176. allow_usb = 1;
  177. if (fwmp_flags & FWMP_DEV_ENABLE_LEGACY)
  178. allow_legacy = 1;
  179. if (fwmp_flags & FWMP_DEV_DISABLE_BOOT) {
  180. if (gbb->flags & GBB_FLAG_FORCE_DEV_SWITCH_ON) {
  181. VB2_DEBUG("FWMP_DEV_DISABLE_BOOT rejected by "
  182. "FORCE_DEV_SWITCH_ON\n");
  183. } else {
  184. disable_dev_boot = 1;
  185. }
  186. }
  187. /* If dev mode is disabled, only allow TONORM */
  188. while (disable_dev_boot) {
  189. VB2_DEBUG("dev_disable_boot is set\n");
  190. VbDisplayScreen(ctx, cparams, VB_SCREEN_DEVELOPER_TO_NORM, 0);
  191. VbExDisplayDebugInfo(dev_disable_msg);
  192. /* Ignore space in VbUserConfirms()... */
  193. switch (VbUserConfirms(ctx, cparams, 0)) {
  194. case 1:
  195. VB2_DEBUG("leaving dev-mode\n");
  196. vb2_nv_set(ctx, VB2_NV_DISABLE_DEV_REQUEST, 1);
  197. VbDisplayScreen(ctx, cparams,
  198. VB_SCREEN_TO_NORM_CONFIRMED,
  199. 0);
  200. VbExSleepMs(5000);
  201. return VBERROR_REBOOT_REQUIRED;
  202. case -1:
  203. VB2_DEBUG("shutdown requested\n");
  204. return VBERROR_SHUTDOWN_REQUESTED;
  205. default:
  206. /* Ignore user attempt to cancel */
  207. VB2_DEBUG("ignore cancel TONORM\n");
  208. }
  209. }
  210. /* Show the dev mode warning screen */
  211. VbDisplayScreen(ctx, cparams, VB_SCREEN_DEVELOPER_WARNING, 0);
  212. /* Get audio/delay context */
  213. audio = VbAudioOpen(cparams);
  214. /* We'll loop until we finish the delay or are interrupted */
  215. do {
  216. uint32_t key;
  217. if (VbWantShutdown(gbb->flags)) {
  218. VB2_DEBUG("VbBootDeveloper() - shutdown requested!\n");
  219. VbAudioClose(audio);
  220. return VBERROR_SHUTDOWN_REQUESTED;
  221. }
  222. key = VbExKeyboardRead();
  223. switch (key) {
  224. case 0:
  225. /* nothing pressed */
  226. break;
  227. case '\r':
  228. /* Only disable virtual dev switch if allowed by GBB */
  229. if (!(gbb->flags & GBB_FLAG_ENTER_TRIGGERS_TONORM))
  230. break;
  231. case ' ':
  232. /* See if we should disable virtual dev-mode switch. */
  233. VB2_DEBUG("shared->flags=0x%x\n", shared->flags);
  234. if (shared->flags & VBSD_HONOR_VIRT_DEV_SWITCH &&
  235. shared->flags & VBSD_BOOT_DEV_SWITCH_ON) {
  236. /* Stop the countdown while we go ask... */
  237. VbAudioClose(audio);
  238. if (gbb->flags & GBB_FLAG_FORCE_DEV_SWITCH_ON) {
  239. /*
  240. * TONORM won't work (only for
  241. * non-shipping devices).
  242. */
  243. VB2_DEBUG("TONORM rejected by "
  244. "FORCE_DEV_SWITCH_ON\n");
  245. VbExDisplayDebugInfo(
  246. "WARNING: TONORM prohibited by "
  247. "GBB FORCE_DEV_SWITCH_ON.\n\n");
  248. VbExBeep(120, 400);
  249. break;
  250. }
  251. VbDisplayScreen(ctx, cparams,
  252. VB_SCREEN_DEVELOPER_TO_NORM,
  253. 0);
  254. /* Ignore space in VbUserConfirms()... */
  255. switch (VbUserConfirms(ctx, cparams, 0)) {
  256. case 1:
  257. VB2_DEBUG("leaving dev-mode\n");
  258. vb2_nv_set(ctx, VB2_NV_DISABLE_DEV_REQUEST,
  259. 1);
  260. VbDisplayScreen(ctx,
  261. cparams,
  262. VB_SCREEN_TO_NORM_CONFIRMED,
  263. 0);
  264. VbExSleepMs(5000);
  265. return VBERROR_REBOOT_REQUIRED;
  266. case -1:
  267. VB2_DEBUG("shutdown requested\n");
  268. return VBERROR_SHUTDOWN_REQUESTED;
  269. default:
  270. /* Stay in dev-mode */
  271. VB2_DEBUG("stay in dev-mode\n");
  272. VbDisplayScreen(ctx,
  273. cparams,
  274. VB_SCREEN_DEVELOPER_WARNING,
  275. 0);
  276. /* Start new countdown */
  277. audio = VbAudioOpen(cparams);
  278. }
  279. } else {
  280. /*
  281. * No virtual dev-mode switch, so go directly
  282. * to recovery mode.
  283. */
  284. VB2_DEBUG("going to recovery\n");
  285. vb2_nv_set(ctx, VB2_NV_RECOVERY_REQUEST,
  286. VBNV_RECOVERY_RW_DEV_SCREEN);
  287. VbAudioClose(audio);
  288. return VBERROR_LOAD_KERNEL_RECOVERY;
  289. }
  290. break;
  291. case 0x04:
  292. /* Ctrl+D = dismiss warning; advance to timeout */
  293. VB2_DEBUG("VbBootDeveloper() - "
  294. "user pressed Ctrl+D; skip delay\n");
  295. ctrl_d_pressed = 1;
  296. goto fallout;
  297. break;
  298. case 0x0c:
  299. VB2_DEBUG("VbBootDeveloper() - "
  300. "user pressed Ctrl+L; Try legacy boot\n");
  301. VbTryLegacy(allow_legacy);
  302. break;
  303. case VB_KEY_CTRL_ENTER:
  304. /*
  305. * The Ctrl-Enter is special for Lumpy test purpose;
  306. * fall through to Ctrl+U handler.
  307. */
  308. case 0x15:
  309. /* Ctrl+U = try USB boot, or beep if failure */
  310. VB2_DEBUG("VbBootDeveloper() - "
  311. "user pressed Ctrl+U; try USB\n");
  312. if (!allow_usb) {
  313. VB2_DEBUG("VbBootDeveloper() - "
  314. "USB booting is disabled\n");
  315. VbExDisplayDebugInfo(
  316. "WARNING: Booting from external media "
  317. "(USB/SD) has not been enabled. Refer "
  318. "to the developer-mode documentation "
  319. "for details.\n");
  320. VbExBeep(120, 400);
  321. VbExSleepMs(120);
  322. VbExBeep(120, 400);
  323. } else {
  324. /*
  325. * Clear the screen to show we get the Ctrl+U
  326. * key press.
  327. */
  328. VbDisplayScreen(ctx, cparams, VB_SCREEN_BLANK,
  329. 0);
  330. if (VBERROR_SUCCESS ==
  331. VbTryUsb(ctx, cparams)) {
  332. VbAudioClose(audio);
  333. return VBERROR_SUCCESS;
  334. } else {
  335. /* Show dev mode warning screen again */
  336. VbDisplayScreen(ctx,
  337. cparams,
  338. VB_SCREEN_DEVELOPER_WARNING,
  339. 0);
  340. }
  341. }
  342. break;
  343. default:
  344. VB2_DEBUG("VbBootDeveloper() - pressed key %d\n", key);
  345. VbCheckDisplayKey(ctx, cparams, key);
  346. break;
  347. }
  348. } while(VbAudioLooping(audio));
  349. fallout:
  350. /* If defaulting to legacy boot, try that unless Ctrl+D was pressed */
  351. if (use_legacy && !ctrl_d_pressed) {
  352. VB2_DEBUG("VbBootDeveloper() - defaulting to legacy\n");
  353. VbTryLegacy(allow_legacy);
  354. }
  355. if ((use_usb && !ctrl_d_pressed) && allow_usb) {
  356. if (VBERROR_SUCCESS == VbTryUsb(ctx, cparams)) {
  357. VbAudioClose(audio);
  358. return VBERROR_SUCCESS;
  359. }
  360. }
  361. /* Timeout or Ctrl+D; attempt loading from fixed disk */
  362. VB2_DEBUG("VbBootDeveloper() - trying fixed disk\n");
  363. VbAudioClose(audio);
  364. return VbTryLoadKernel(ctx, cparams, VB_DISK_FLAG_FIXED);
  365. }
  366. VbError_t VbBootDeveloper(struct vb2_context *ctx, VbCommonParams *cparams)
  367. {
  368. VbError_t retval = vb2_developer_ui(ctx, cparams);
  369. VbDisplayScreen(ctx, cparams, VB_SCREEN_BLANK, 0);
  370. return retval;
  371. }
  372. /* Delay in recovery mode */
  373. #define REC_DISK_DELAY 1000 /* Check disks every 1s */
  374. #define REC_KEY_DELAY 20 /* Check keys every 20ms */
  375. #define REC_MEDIA_INIT_DELAY 500 /* Check removable media every 500ms */
  376. VbError_t vb2_recovery_ui(struct vb2_context *ctx, VbCommonParams *cparams)
  377. {
  378. VbSharedDataHeader *shared =
  379. (VbSharedDataHeader *)cparams->shared_data_blob;
  380. uint32_t retval;
  381. uint32_t key;
  382. int i;
  383. VB2_DEBUG("VbBootRecovery() start\n");
  384. /*
  385. * If the dev-mode switch is off and the user didn't press the recovery
  386. * button (recovery was triggerred automatically), show 'broken' screen.
  387. * The user can either only shutdown to abort or hit esc+refresh+power
  388. * to initiate recovery as instructed on the screen.
  389. */
  390. if (!(shared->flags & VBSD_BOOT_DEV_SWITCH_ON) &&
  391. !(shared->flags & VBSD_BOOT_REC_SWITCH_ON)) {
  392. /*
  393. * We have to save the reason here so that it will survive
  394. * coming up three-finger-salute. We're saving it in
  395. * VBNV_RECOVERY_SUBCODE to avoid a recovery loop.
  396. * If we save the reason in VBNV_RECOVERY_REQUEST, we will come
  397. * back here, thus, we won't be able to give a user a chance to
  398. * reboot to workaround boot hicups.
  399. */
  400. VB2_DEBUG("VbBootRecovery() saving recovery reason (%#x)\n",
  401. shared->recovery_reason);
  402. vb2_nv_set(ctx, VB2_NV_RECOVERY_SUBCODE,
  403. shared->recovery_reason);
  404. /*
  405. * Commit NV now, because it won't get saved if the user forces
  406. * manual recovery via the three-finger salute.
  407. */
  408. vb2_nv_commit(ctx);
  409. VbDisplayScreen(ctx, cparams, VB_SCREEN_OS_BROKEN, 0);
  410. VB2_DEBUG("VbBootRecovery() waiting for manual recovery\n");
  411. while (1) {
  412. VbCheckDisplayKey(ctx, cparams, VbExKeyboardRead());
  413. if (VbWantShutdown(cparams->gbb->flags))
  414. return VBERROR_SHUTDOWN_REQUESTED;
  415. VbExSleepMs(REC_KEY_DELAY);
  416. }
  417. }
  418. /* Loop and wait for a recovery image */
  419. VB2_DEBUG("VbBootRecovery() waiting for a recovery image\n");
  420. while (1) {
  421. VB2_DEBUG("VbBootRecovery() attempting to load kernel2\n");
  422. retval = VbTryLoadKernel(ctx, cparams, VB_DISK_FLAG_REMOVABLE);
  423. /*
  424. * Clear recovery requests from failed kernel loading, since
  425. * we're already in recovery mode. Do this now, so that
  426. * powering off after inserting an invalid disk doesn't leave
  427. * us stuck in recovery mode.
  428. */
  429. vb2_nv_set(ctx, VB2_NV_RECOVERY_REQUEST,
  430. VBNV_RECOVERY_NOT_REQUESTED);
  431. if (VBERROR_SUCCESS == retval)
  432. break; /* Found a recovery kernel */
  433. VbDisplayScreen(ctx, cparams, VBERROR_NO_DISK_FOUND == retval ?
  434. VB_SCREEN_RECOVERY_INSERT :
  435. VB_SCREEN_RECOVERY_NO_GOOD,
  436. 0);
  437. /*
  438. * Scan keyboard more frequently than media, since x86
  439. * platforms don't like to scan USB too rapidly.
  440. */
  441. for (i = 0; i < REC_DISK_DELAY; i += REC_KEY_DELAY) {
  442. key = VbExKeyboardRead();
  443. /*
  444. * We might want to enter dev-mode from the Insert
  445. * screen if all of the following are true:
  446. * - user pressed Ctrl-D
  447. * - we can honor the virtual dev switch
  448. * - not already in dev mode
  449. * - user forced recovery mode
  450. * - EC isn't pwned
  451. */
  452. if (key == 0x04 &&
  453. shared->flags & VBSD_HONOR_VIRT_DEV_SWITCH &&
  454. !(shared->flags & VBSD_BOOT_DEV_SWITCH_ON) &&
  455. (shared->flags & VBSD_BOOT_REC_SWITCH_ON) &&
  456. VbExTrustEC(0)) {
  457. if (!(shared->flags &
  458. VBSD_BOOT_REC_SWITCH_VIRTUAL) &&
  459. VbExGetSwitches(
  460. VB_INIT_FLAG_REC_BUTTON_PRESSED)) {
  461. /*
  462. * Is the recovery button stuck? In
  463. * any case we don't like this. Beep
  464. * and ignore.
  465. */
  466. VB2_DEBUG("^D but rec switch "
  467. "is pressed\n");
  468. VbExBeep(120, 400);
  469. continue;
  470. }
  471. /* Ask the user to confirm entering dev-mode */
  472. VbDisplayScreen(ctx, cparams,
  473. VB_SCREEN_RECOVERY_TO_DEV,
  474. 0);
  475. /* SPACE means no... */
  476. uint32_t vbc_flags =
  477. VB_CONFIRM_SPACE_MEANS_NO |
  478. VB_CONFIRM_MUST_TRUST_KEYBOARD;
  479. switch (VbUserConfirms(ctx, cparams,
  480. vbc_flags)) {
  481. case 1:
  482. VB2_DEBUG("Enabling dev-mode...\n");
  483. if (TPM_SUCCESS != SetVirtualDevMode(1))
  484. return VBERROR_TPM_SET_BOOT_MODE_STATE;
  485. VB2_DEBUG("Reboot so it will take "
  486. "effect\n");
  487. if (VbExGetSwitches
  488. (VB_INIT_FLAG_ALLOW_USB_BOOT))
  489. VbAllowUsbBoot(ctx);
  490. return VBERROR_REBOOT_REQUIRED;
  491. case -1:
  492. VB2_DEBUG("Shutdown requested\n");
  493. return VBERROR_SHUTDOWN_REQUESTED;
  494. default: /* zero, actually */
  495. VB2_DEBUG("Not enabling dev-mode\n");
  496. /*
  497. * Jump out of the outer loop to
  498. * refresh the display quickly.
  499. */
  500. i = 4;
  501. break;
  502. }
  503. } else {
  504. VbCheckDisplayKey(ctx, cparams, key);
  505. }
  506. if (VbWantShutdown(cparams->gbb->flags))
  507. return VBERROR_SHUTDOWN_REQUESTED;
  508. VbExSleepMs(REC_KEY_DELAY);
  509. }
  510. }
  511. return VBERROR_SUCCESS;
  512. }
  513. VbError_t VbBootRecovery(struct vb2_context *ctx, VbCommonParams *cparams)
  514. {
  515. VbError_t retval = vb2_recovery_ui(ctx, cparams);
  516. VbDisplayScreen(ctx, cparams, VB_SCREEN_BLANK, 0);
  517. return retval;
  518. }