blob: ea91f7421661a529e24763d933db730eff21f6b6 [file] [log] [blame]
// Copyright 2020 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package firmware
import (
"context"
fwCommon "chromiumos/tast/common/firmware"
"chromiumos/tast/remote/firmware"
"chromiumos/tast/remote/firmware/fixture"
"chromiumos/tast/testing"
)
func init() {
testing.AddTest(&testing.Test{
Func: FWTries,
Desc: "Verify that the DUT can be specified to boot from A or B",
Contacts: []string{"cros-fw-engprod@google.com"},
SoftwareDeps: []string{"crossystem", "flashrom"},
ServiceDeps: []string{"tast.cros.firmware.BiosService", "tast.cros.firmware.UtilsService"},
Attr: []string{"group:firmware", "firmware_bios"},
Vars: []string{"servo"},
Params: []testing.Param{
testing.Param{
Name: "normal",
Fixture: fixture.NormalMode,
},
testing.Param{
Name: "dev",
Fixture: fixture.DevModeGBB,
},
},
})
}
func FWTries(ctx context.Context, s *testing.State) {
h := s.FixtValue().(*fixture.Value).Helper
if err := h.RequireServo(ctx); err != nil {
s.Fatal("Failed to init servo: ", err)
}
ms, err := firmware.NewModeSwitcher(ctx, h)
if err != nil {
s.Fatal("Creating mode switcher: ", err)
}
vboot2, err := h.Reporter.Vboot2(ctx)
if err != nil {
s.Fatal("Failed to determine fw_vboot2: ", err)
}
if vboot2 {
s.Log("DUT uses vboot2")
} else {
s.Log("DUT does not use vboot2")
}
currentFW, nextFW, tryCount, err := h.Reporter.FWTries(ctx)
if err != nil {
s.Fatal("Reporting FW Tries at start of test: ", err)
}
s.Logf("At start of test, currentFW/nextFW/tryCount are: %s/%s/%d", currentFW, nextFW, tryCount)
// Set next=B, tries=2.
if err := firmware.SetFWTries(ctx, h.DUT, fwCommon.RWSectionB, 2); err != nil {
s.Fatal("Setting FWTries to B/2: ", err)
}
if err := firmware.CheckFWTries(ctx, h.Reporter, fwCommon.RWSectionUnspecified, fwCommon.RWSectionB, 2); err != nil {
s.Fatal("After setting FWTries to B/2, before rebooting: ", err)
}
s.Log("nextFW/tryCount has been set to B/2")
// Reboot the DUT.
s.Log("Rebooting; expect to boot into B leaving tryCount=1 or 0")
if err := ms.ModeAwareReboot(ctx, firmware.WarmReset); err != nil {
s.Fatal("Error resetting DUT: ", err)
}
// DUT should have rebooted into firmware B, and tryCount should have decremented by 1.
// Occasionally, vboot needs an extra reboot along the way, so the tryCount decrements by 2 instead. This is OK.
currentFW, nextFW, tryCount, err = h.Reporter.FWTries(ctx)
if err != nil {
s.Fatal("Reporting FW tries after first reboot: ", err)
}
if currentFW != fwCommon.RWSectionB {
s.Fatalf("After rebooting from A/B/2: unexpected currentFW: got %s; want B", currentFW)
}
if nextFW == fwCommon.RWSectionB && tryCount == 1 {
s.Log("DUT rebooted once. currentFW/nextFW/tryCount: B/B/1")
s.Log("Rebooting; expect to boot into B leaving tryCount=0")
if err := ms.ModeAwareReboot(ctx, firmware.WarmReset); err != nil {
s.Fatal("Error resetting DUT: ", err)
}
if err := firmware.CheckFWTries(ctx, h.Reporter, fwCommon.RWSectionB, fwCommon.RWSectionUnspecified, 0); err != nil {
s.Fatal("After rebooting from B/B/1: ", err)
}
currentFW, nextFW, tryCount, err = h.Reporter.FWTries(ctx)
s.Logf("DUT rebooted. currentFW/nextFW/tryCount:%s/%s/%d", currentFW, nextFW, tryCount)
} else if tryCount == 0 {
s.Logf("DUT rebooted twice. currentFW/nextFW/tryCount: B/%s/0", nextFW)
} else {
s.Fatalf("After setting FWTries to B/2 then rebooting: unexpected nextFW/tryCount: got %s/%d; want B/1 or {either}/0", nextFW, tryCount)
}
// Next reboot should return to Firmware A.
s.Log("Rebooting; expect to boot into A leaving tryCount=0")
if err := ms.ModeAwareReboot(ctx, firmware.WarmReset); err != nil {
s.Fatal("Error resetting DUT: ", err)
}
if err := firmware.CheckFWTries(ctx, h.Reporter, fwCommon.RWSectionA, fwCommon.RWSectionA, 0); err != nil {
s.Fatal("After rebooting from B/A/0: ", err)
}
}