blob: 640bcf5d8a9b80597440b3091060bac5d42c2a58 [file] [log] [blame]
// Copyright 2022 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 (
"bytes"
"context"
"strings"
"time"
"github.com/golang/protobuf/ptypes/empty"
common "chromiumos/tast/common/firmware"
"chromiumos/tast/ctxutil"
"chromiumos/tast/remote/firmware"
"chromiumos/tast/remote/firmware/fixture"
pb "chromiumos/tast/services/cros/firmware"
"chromiumos/tast/ssh"
"chromiumos/tast/testing"
"chromiumos/tast/testing/hwdep"
)
func init() {
testing.AddTest(&testing.Test{
Func: SoftwareSync,
Desc: "Servo based EC software sync test",
Contacts: []string{"jbettis@google.com", "chromeos-firmware@google.com"},
Attr: []string{"group:firmware", "firmware_unstable"},
ServiceDeps: []string{"tast.cros.firmware.BiosService"},
HardwareDeps: hwdep.D(hwdep.ChromeEC()),
Params: []testing.Param{
{Name: "normal",
Fixture: fixture.NormalMode,
},
{Name: "dev",
Fixture: fixture.DevModeGBB,
},
},
})
}
const hashCommand = "ectool echash | grep hash: | sed \"s/hash:\\s\\+//\""
func SoftwareSync(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)
}
// TODO(b/194910957): old test disables EC WP here
if err := h.RequireBiosServiceClient(ctx); err != nil {
s.Fatal("Requiring BiosServiceClient: ", err)
}
bs := h.BiosServiceClient
old, err := bs.GetGBBFlags(ctx, &empty.Empty{})
if err != nil {
s.Fatal("initial GetGBBFlags failed: ", err)
}
if common.GBBFlagsContains(old, pb.GBBFlag_DISABLE_EC_SOFTWARE_SYNC) {
s.Log("Clearing GBB flag DISABLE_EC_SOFTWARE_SYNC")
req := pb.GBBFlagsState{Clear: []pb.GBBFlag{pb.GBBFlag_DISABLE_EC_SOFTWARE_SYNC}}
if _, err := bs.ClearAndSetGBBFlags(ctx, &req); err != nil {
s.Fatal("Failed to clear gbb flag: ", err)
}
// TODO(b/194910957): old test does warm reset, seems unneeded
}
backup, err := bs.BackupImageSection(ctx, &pb.FWBackUpSection{Section: pb.ImageSection_ECRWImageSection, Programmer: pb.Programmer_ECProgrammer})
if err != nil {
s.Fatal("Could not backup EC firmware: ", err)
}
cleanupContext := ctx
ctx, cancel := ctxutil.Shorten(ctx, 30*time.Second)
defer cancel()
defer func(ctx context.Context) {
s.Log("Deleting temp file")
if err := h.DUT.Conn().CommandContext(ctx, "rm", "-f", backup.Path).Run(ssh.DumpLogOnError); err != nil {
s.Fatal("Failed to delete firmware backup: ", err)
}
}(cleanupContext)
// TODO(b/194910957): Old test checks that fw-a section does not have preamble flag PREAMBLE_USE_RO_NORMAL. this really needed?
// TODO(b/194910957): Old test unlocks CCD, is this needed?
// Check CR50 boot mode is NORMAL
output, err := h.Servo.RunCR50CommandGetOutput(ctx, "ec_comm", []string{`boot_mode\s*:\s*(\S+)\b`})
if err != nil {
s.Fatal("CR50 cmd failed: ", err)
}
if output[0][1] != "NORMAL" {
s.Fatalf("CR50 boot mode incorrect, got %q want %q", output[0][1], "NORMAL")
}
s.Log("Corrupt EC firmware RW body")
activeCopy, err := h.Servo.GetString(ctx, "ec_active_copy")
if err != nil {
s.Fatal("EC active copy failed: ", err)
}
if !strings.HasPrefix(activeCopy, "RW") {
s.Fatalf("EC active copy incorrect, got %q want RW", activeCopy)
}
ecHashBefore, err := h.DUT.Conn().CommandContext(ctx, "sh", "-c", hashCommand).
Output()
if err != nil {
s.Fatal("Failed to get ec hash: ", err)
}
ecSection := pb.ImageSection_ECRWImageSection
if activeCopy == "RW_B" {
ecSection = pb.ImageSection_ECRWBImageSection
}
s.Log("Corrupt the EC section: ", ecSection)
defer func(ctx context.Context) {
s.Log("Restoring EC firmware backup")
if _, err := bs.RestoreImageSection(ctx, backup); err != nil {
s.Fatal("Failed to restore EC firmware: ", err)
}
}(cleanupContext)
if _, err = bs.CorruptECSection(ctx, &pb.CorruptSection{Section: ecSection}); err != nil {
s.Fatal("Failed to corrupt EC: ", err)
}
s.Log("Reboot AP, check EC hash, and software sync it")
if err := ms.ModeAwareReboot(ctx, firmware.WarmReset); err != nil {
s.Fatal("Failed to reboot: ", err)
}
h.CloseRPCConnection(ctx)
if err := h.RequireBiosServiceClient(ctx); err != nil {
s.Fatal("Requiring BiosServiceClient: ", err)
}
bs = h.BiosServiceClient
s.Log("Expect EC in RW and RW is restored")
ecHashAfter, err := h.DUT.Conn().CommandContext(ctx, "sh", "-c", hashCommand).
Output()
if err != nil {
s.Fatal("Failed to get ec hash: ", err)
}
if !bytes.Equal(ecHashAfter, ecHashBefore) {
s.Fatalf("EC hash wrong, got %s want %s", ecHashAfter, ecHashBefore)
}
activeCopy, err = h.Servo.GetString(ctx, "ec_active_copy")
if err != nil {
s.Fatal("EC active copy failed: ", err)
}
if !strings.HasPrefix(activeCopy, "RW") {
s.Fatalf("EC active copy incorrect, got %q want RW", activeCopy)
}
// TODO(b/194910957): run_test_corrupt_hash_in_cr50 if EC_FEATURE_EFS2
}