From b093de999a3c0bca2341dc742aa37b13adbba28a Mon Sep 17 00:00:00 2001 From: Benson Leung Date: Wed, 7 Oct 2020 21:07:58 -0700 Subject: [PATCH] cros-ec: Fix reboot to RO sequence Previously, we sent a 'stay-in-ro' subcommand when we are in fu_cros_ec_usb_device_reset_to_ro, which is called from the detach phase, in other words, we are currently sitting in RW. This is incorrect, since stay-in-ro only interrupts an RO's rw_sig process if it is in progress. Instead, 'stay-in-ro' must be issued when the device reenumerates in RO, immediately before the writing sequence starts. On devices that implement rw_sig, they will briefly enumerate as RO before self-issuing a jump to RW on the signature check being valid. In order to stay in RO to perform a RW partition update, we must interrupt it as soon as we see the RO version enumerate. --- plugins/cros-ec/fu-cros-ec-usb-device.c | 50 +++++++++++++++++-------- 1 file changed, 34 insertions(+), 16 deletions(-) diff --git a/plugins/cros-ec/fu-cros-ec-usb-device.c b/plugins/cros-ec/fu-cros-ec-usb-device.c index 24864aa39..5bb55a8d8 100644 --- a/plugins/cros-ec/fu-cros-ec-usb-device.c +++ b/plugins/cros-ec/fu-cros-ec-usb-device.c @@ -641,19 +641,12 @@ static gboolean fu_cros_ec_usb_device_reset_to_ro (FuDevice *device, GError **error) { guint8 response; - guint16 subcommand = UPDATE_EXTRA_CMD_STAY_IN_RO; + guint16 subcommand = UPDATE_EXTRA_CMD_IMMEDIATE_RESET; guint8 command_body[2]; /* Max command body size. */ gsize command_body_size = 0; gsize response_size = 1; - /* send subcommand to remain in RO */ - if (!fu_cros_ec_usb_device_send_subcommand (device, subcommand, command_body, - command_body_size, &response, - &response_size, FALSE, error)) - return FALSE; - - response_size = 1; - subcommand = UPDATE_EXTRA_CMD_IMMEDIATE_RESET; + fu_device_set_custom_flags (device, "rebooting-to-ro"); if (!fu_cros_ec_usb_device_send_subcommand (device, subcommand, command_body, command_body_size, &response, &response_size, FALSE, error)) { @@ -694,6 +687,23 @@ fu_cros_ec_usb_device_write_firmware (FuDevice *device, FuCrosEcFirmware *cros_ec_firmware = FU_CROS_EC_FIRMWARE (firmware); gint num_txed_sections = 0; + if (fu_device_has_custom_flag (device, "rebooting-to-ro")) { + gsize response_size = 1; + guint8 response; + guint16 subcommand = UPDATE_EXTRA_CMD_STAY_IN_RO; + guint8 command_body[2]; /* Max command body size. */ + gsize command_body_size = 0; + + if (!fu_cros_ec_usb_device_send_subcommand (device, subcommand, command_body, + command_body_size, &response, + &response_size, FALSE, error)) { + /* failure here is ok */ + g_clear_error (error); + } + /* clear custom flags */ + fu_device_set_custom_flags (device, ""); + } + sections = fu_cros_ec_firmware_get_sections (cros_ec_firmware); if (sections == NULL) { g_set_error_literal (error, @@ -812,18 +822,26 @@ fu_cros_ec_usb_device_attach (FuDevice *device, GError **error) } static gboolean -fu_cros_ec_usb_device_detach (FuDevice *self, GError **error) +fu_cros_ec_usb_device_detach (FuDevice *device, GError **error) { - if (fu_device_has_custom_flag (self, "rw-written") && - !fu_device_has_custom_flag (self, "ro-written")) + FuCrosEcUsbDevice *self = FU_CROS_EC_USB_DEVICE (device); + + if (fu_device_has_custom_flag (device, "rw-written") && + !fu_device_has_custom_flag (device, "ro-written")) return TRUE; - fu_device_set_remove_delay (self, FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE); - if (!fu_cros_ec_usb_device_reset_to_ro (self, error)) + if (self->in_bootloader) { + g_debug ("skipping immediate reboot in case of already in bootloader"); + /* already in ro so skip reboot */ + return TRUE; + } + + fu_device_set_remove_delay (device, FU_DEVICE_REMOVE_DELAY_RE_ENUMERATE); + if (!fu_cros_ec_usb_device_reset_to_ro (device, error)) return FALSE; - fu_device_set_status (self, FWUPD_STATUS_DEVICE_RESTART); - fu_device_add_flag (self, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); + fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); + fu_device_add_flag (device, FWUPD_DEVICE_FLAG_WAIT_FOR_REPLUG); /* success */ return TRUE;