| // Copyright 2022 The ChromiumOS Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| // First step of FirmwareService State Machine. Installs RW firmware. |
| package state_machine |
| |
| import ( |
| firmwareservice "go.chromium.org/chromiumos/test/provision/v2/cros-fw-provision/service" |
| "context" |
| "fmt" |
| "log" |
| |
| "go.chromium.org/chromiumos/config/go/test/api" |
| ) |
| |
| // FirmwareUpdateRoState updates firmware with write protection disabled. |
| type FirmwareUpdateRoState struct { |
| service *firmwareservice.FirmwareService |
| } |
| |
| // Execute flashes firmware with write-protection disabled using futility. |
| func (s FirmwareUpdateRoState) Execute(ctx context.Context, log *log.Logger) (*api.FirmwareProvisionResponse, api.InstallResponse_Status, error) { |
| connection := s.service.GetConnectionToFlashingDevice() |
| |
| // form futility command args based on the request |
| var futilityImageArgs []string |
| // Detailed Request |
| var mainRoPath string |
| var err error |
| mainRoMetadata, ok := s.service.GetImageMetadata(s.service.GetMainRoPath()) |
| if ok { |
| log.Printf("[FW Provisioning: Update RO] extracting AP image to flash\n") |
| mainRoPath, err = firmwareservice.PickAndExtractMainImage(ctx, connection, mainRoMetadata, s.service.GetMainRoPath(), s.service) |
| if err != nil { |
| return nil, api.InstallResponse_STATUS_UPDATE_FIRMWARE_FAILED, firmwareservice.UpdateFirmwareFailedErr(err) |
| } |
| futilityImageArgs = append(futilityImageArgs, []string{fmt.Sprint("--image=", mainRoPath)}...) |
| } |
| |
| ecRoMetadata, ok := s.service.GetImageMetadata(s.service.GetEcRoPath()) |
| if ok { |
| log.Printf("[FW Provisioning: Update RO] extracting EC image to flash\n") |
| ecRoPath, err := firmwareservice.PickAndExtractECImage(ctx, connection, ecRoMetadata, s.service.GetEcRoPath(), s.service) |
| if err != nil { |
| return nil, api.InstallResponse_STATUS_UPDATE_FIRMWARE_FAILED, firmwareservice.UpdateFirmwareFailedErr(err) |
| } |
| if s.service.IsServoUsed() { |
| log.Printf("[FW Provisioning: Update RO] separately flashing EC over Servo with flash_ec\n") |
| // futility refuses to flash EC over servod as a separate image and only |
| // accepts single image: http://shortn/_dtaO92HvqW. So, for servod, we |
| // use flash_ec script that to flash the EC separately. |
| flashECScript, err := firmwareservice.GetFlashECScript(ctx, connection, ecRoMetadata.ArchiveDir) |
| if err != nil { |
| return nil, api.InstallResponse_STATUS_UPDATE_FIRMWARE_FAILED, firmwareservice.UpdateFirmwareFailedErr(err) |
| } |
| err = s.service.ProvisionWithFlashEC(ctx, ecRoPath, flashECScript) |
| if err != nil { |
| return nil, api.InstallResponse_STATUS_UPDATE_FIRMWARE_FAILED, firmwareservice.UpdateFirmwareFailedErr(err) |
| } |
| } else { |
| // For SSH, we can simply run `futility ... --ec-image=$EC_IMAGE ...` |
| futilityImageArgs = append(futilityImageArgs, []string{fmt.Sprint("--ec_image=", ecRoPath)}...) |
| } |
| } |
| |
| log.Printf("[FW Provisioning: Update RO] flashing RO firmware with futility\n") |
| err = s.service.FlashWithFutility(ctx, false /* WP */, futilityImageArgs, mainRoPath) |
| if err != nil { |
| return nil, api.InstallResponse_STATUS_UPDATE_FIRMWARE_FAILED, firmwareservice.UpdateFirmwareFailedErr(err) |
| } |
| |
| return nil, api.InstallResponse_STATUS_SUCCESS, nil |
| } |
| |
| func (s FirmwareUpdateRoState) Next() ServiceState { |
| if s.service.UpdateRw() { |
| return FirmwareUpdateRwState(s) |
| } else { |
| return FirmwarePostInstallState(s) |
| } |
| } |
| |
| const UpdateRoStateName = "Firmware Update RO" |
| |
| func (s FirmwareUpdateRoState) Name() string { |
| return UpdateRoStateName |
| } |