diff --git a/firmware/include/vboot_struct.h b/firmware/include/vboot_struct.h index 5e637ba09e..923e63cd83 100644 --- a/firmware/include/vboot_struct.h +++ b/firmware/include/vboot_struct.h @@ -263,6 +263,10 @@ typedef struct VbKernelPreambleHeader { #define VBSD_BOOT_REC_SWITCH_VIRTUAL 0x00004000 /* Firmware used vboot2 for firmware selection */ #define VBSD_BOOT_FIRMWARE_VBOOT2 0x00008000 +/* Firmware needs VGA Option ROM to display screens */ +#define VBSD_OPROM_MATTERS 0x00010000 +/* Firmware has loaded the VGA Option ROM */ +#define VBSD_OPROM_LOADED 0x00020000 /* * Supported flags by header version. It's ok to add new flags while keeping diff --git a/firmware/lib/vboot_api_init.c b/firmware/lib/vboot_api_init.c index b83214f2a2..38bc8793e8 100644 --- a/firmware/lib/vboot_api_init.c +++ b/firmware/lib/vboot_api_init.c @@ -82,6 +82,10 @@ VbError_t VbInit(VbCommonParams *cparams, VbInitParams *iparams) shared->flags |= VBSD_EC_SLOW_UPDATE; if (iparams->flags & VB_INIT_FLAG_VIRTUAL_REC_SWITCH) shared->flags |= VBSD_BOOT_REC_SWITCH_VIRTUAL; + if (iparams->flags & VB_INIT_FLAG_OPROM_MATTERS) + shared->flags |= VBSD_OPROM_MATTERS; + if (iparams->flags & VB_INIT_FLAG_OPROM_LOADED) + shared->flags |= VBSD_OPROM_LOADED; is_s3_resume = (iparams->flags & VB_INIT_FLAG_S3_RESUME ? 1 : 0); @@ -327,7 +331,14 @@ VbError_t VbInit(VbCommonParams *cparams, VbInitParams *iparams) if ((iparams->flags & VB_INIT_FLAG_OPROM_MATTERS) && (iparams->flags & VB_INIT_FLAG_OPROM_LOADED)) { VbNvSet(&vnc, VBNV_OPROM_NEEDED, 0); - retval = VBERROR_VGA_OPROM_MISMATCH; + /* + * If this is a system with slow EC update then don't + * reboot immediately in case VGA option ROM is still + * needed to display an update screen. The reboot will + * be requested after EC software sync is complete. + */ + if (!(iparams->flags & VB_INIT_FLAG_EC_SLOW_UPDATE)) + retval = VBERROR_VGA_OPROM_MISMATCH; VBDEBUG(("VbInit() has oprom, doesn't need it\n")); } } diff --git a/firmware/lib/vboot_api_kernel.c b/firmware/lib/vboot_api_kernel.c index 0b2f941e13..0609b55b4f 100644 --- a/firmware/lib/vboot_api_kernel.c +++ b/firmware/lib/vboot_api_kernel.c @@ -801,6 +801,18 @@ VbError_t VbEcSoftwareSync(int devidx, VbCommonParams *cparams) if (in_rw) { if (need_update) { + /* + * Check if BIOS should also load VGA Option ROM when + * rebooting to save another reboot if possible. + */ + if ((shared->flags & VBSD_EC_SLOW_UPDATE) && + (shared->flags & VBSD_OPROM_MATTERS) && + !(shared->flags & VBSD_OPROM_LOADED)) { + VBDEBUG(("VbEcSoftwareSync() - Reboot to " + "load VGA Option ROM\n")); + VbNvSet(&vnc, VBNV_OPROM_NEEDED, 1); + } + /* * EC is running the wrong RW image. Reboot the EC to * RO so we can update it on the next boot. @@ -821,10 +833,16 @@ VbError_t VbEcSoftwareSync(int devidx, VbCommonParams *cparams) if (shared->flags & VBSD_EC_SLOW_UPDATE) { VBDEBUG(("VbEcSoftwareSync() - " "EC is slow. Show WAIT screen.\n")); - /* - * FIXME(crosbug.com/p/12257): Ensure the VGA Option - * ROM is loaded! - */ + + /* Ensure the VGA Option ROM is loaded */ + if ((shared->flags & VBSD_OPROM_MATTERS) && + !(shared->flags & VBSD_OPROM_LOADED)) { + VBDEBUG(("VbEcSoftwareSync() - Reboot to " + "load VGA Option ROM\n")); + VbNvSet(&vnc, VBNV_OPROM_NEEDED, 1); + return VBERROR_VGA_OPROM_MISMATCH; + } + VbDisplayScreen(cparams, VB_SCREEN_WAIT, 0, &vnc); } @@ -890,6 +908,23 @@ VbError_t VbEcSoftwareSync(int devidx, VbCommonParams *cparams) return VBERROR_EC_REBOOT_TO_RO_REQUIRED; } + /* + * Reboot to unload VGA Option ROM if: + * - RW update was done + * - the system is NOT in developer mode + * - the system has slow EC update flag set + * - the VGA Option ROM was needed and loaded + */ + if (need_update && + !(shared->flags & VBSD_BOOT_DEV_SWITCH_ON) && + (shared->flags & VBSD_EC_SLOW_UPDATE) && + (shared->flags & VBSD_OPROM_MATTERS) && + (shared->flags & VBSD_OPROM_LOADED)) { + VBDEBUG(("VbEcSoftwareSync() - Reboot to " + "unload VGA Option ROM\n")); + return VBERROR_VGA_OPROM_MISMATCH; + } + VBDEBUG(("VbEcSoftwareSync() in RW; done\n")); return VBERROR_SUCCESS; } @@ -939,18 +974,31 @@ VbError_t VbSelectAndLoadKernel(VbCommonParams *cparams, /* Do EC software sync if necessary */ if ((shared->flags & VBSD_EC_SOFTWARE_SYNC) && !(cparams->gbb->flags & GBB_FLAG_DISABLE_EC_SOFTWARE_SYNC)) { + int oprom_mismatch = 0; + retval = VbEcSoftwareSync(0, cparams); - if (retval != VBERROR_SUCCESS) + /* Save reboot requested until after possible PD sync */ + if (retval == VBERROR_VGA_OPROM_MISMATCH) + oprom_mismatch = 1; + else if (retval != VBERROR_SUCCESS) goto VbSelectAndLoadKernel_exit; #ifdef PD_SYNC if (!(cparams->gbb->flags & GBB_FLAG_DISABLE_PD_SOFTWARE_SYNC)) { retval = VbEcSoftwareSync(1, cparams); - if (retval != VBERROR_SUCCESS) + if (retval == VBERROR_VGA_OPROM_MISMATCH) + oprom_mismatch = 1; + else if (retval != VBERROR_SUCCESS) goto VbSelectAndLoadKernel_exit; } #endif + + /* Request reboot to unload VGA Option ROM */ + if (oprom_mismatch) { + retval = VBERROR_VGA_OPROM_MISMATCH; + goto VbSelectAndLoadKernel_exit; + } } /* Read kernel version from the TPM. Ignore errors in recovery mode. */