blob: d9c676bd1459f30e904cc089f2e9f1e03d35c672 [file] [log] [blame]
// 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.
package firmware
import (
"context"
"strconv"
"time"
"github.com/golang/protobuf/ptypes/empty"
"go.chromium.org/tast-tests/cros/remote/firmware"
"go.chromium.org/tast-tests/cros/remote/firmware/fixture"
pb "go.chromium.org/tast-tests/cros/services/cros/firmware"
"go.chromium.org/tast/core/ctxutil"
"go.chromium.org/tast/core/ssh"
"go.chromium.org/tast/core/testing"
)
func init() {
testing.AddTest(&testing.Test{
Func: UpdateKernelVersion,
Desc: "Update kernel version bits in CGPT and verify its consistency",
Contacts: []string{
"chromeos-faft@google.com",
"tij@google.com",
},
BugComponent: "b:792402", // ChromeOS > Platform > Enablement > Firmware > FAFT
Attr: []string{"group:firmware", "firmware_bios", "firmware_level5"},
ServiceDeps: []string{"tast.cros.firmware.KernelService"},
Fixture: fixture.DevModeGBB,
Timeout: 15 * time.Minute,
LacrosStatus: testing.LacrosVariantUnneeded,
})
}
// UpdateKernelVersion reads CGPT headers of kernel partition and
// then modifies the version bits to mimic kernel update and checks
// if it persist after reboot
func UpdateKernelVersion(ctx context.Context, s *testing.State) {
h := s.FixtValue().(*fixture.Value).Helper
if err := h.RequireKernelServiceClient(ctx); err != nil {
s.Fatal("Requiring KernelServiceClient: ", err)
}
ms, err := firmware.NewModeSwitcher(ctx, h)
if err != nil {
s.Fatal("Creating mode switcher: ", err)
}
s.Log("Backing up current Kernel")
kernelBackup, err := h.KernelServiceClient.BackupKernel(ctx, &pb.KernelBackup{})
if err != nil {
s.Fatal("Failed to back up KERN-A and KERN-B: ", err)
}
cleanupContext := ctx
ctx, cancel := ctxutil.Shorten(ctx, 5*time.Minute)
defer cancel()
defer func(ctx context.Context) {
if err := h.RequireKernelServiceClient(ctx); err != nil {
s.Fatal("Failed to connect to kernel service: ", err)
}
s.Log("Restoring kernel from backup")
if _, err := h.KernelServiceClient.RestoreKernel(ctx, kernelBackup); err != nil {
s.Fatal("Failed to restore kernel from backup: ", err)
}
s.Log("Delete backup files from DUT")
rmargs := []string{
kernelBackup.KernA.BackupPath,
kernelBackup.KernB.BackupPath,
}
if _, err := h.DUT.Conn().CommandContext(ctx, "rm", rmargs...).Output(ssh.DumpLogOnError); err != nil {
s.Fatal("Failed to delete backup files: ", err)
}
s.Log("Performing mode aware reboot to ensure restored kernel takes effect")
if err := ms.ModeAwareReboot(ctx, firmware.ColdReset); err != nil {
s.Fatal("Failed to reboot: ", err)
}
}(cleanupContext)
// Make sure we start with a deterministic state so we don't have a
// situation where for example KERN-B is many version ahead of KERN-A.
if _, err := h.KernelServiceClient.EnsureBothKernelCopiesBootable(ctx, &empty.Empty{}); err != nil {
s.Fatal("Failed to ensure both kernel copies are bootable: ", err)
}
if _, err := h.KernelServiceClient.PrioritizeKernelCopy(ctx, &pb.Partition{
Copy: pb.PartitionCopy_A,
}); err != nil {
s.Fatal("Failed to prioritize KERN-A: ", err)
}
s.Log("Performing mode aware reboot to ensure boot to copy A")
if err := ms.ModeAwareReboot(ctx, firmware.ColdReset); err != nil {
s.Fatal("Failed to reboot: ", err)
}
if err := h.RequireKernelServiceClient(ctx); err != nil {
s.Fatal("Failed to connect to kernel service: ", err)
}
s.Log("Get initial kernel version for KERN-A")
initVersion, err := h.KernelServiceClient.GetKernelVersion(ctx, &pb.Partition{
Copy: pb.PartitionCopy_A,
})
if err != nil {
s.Fatal("Failed to get kernel version: ", err)
}
s.Log("Initial kernel version is: ", initVersion.Version)
versionInt, err := strconv.Atoi(initVersion.Version)
if err != nil {
s.Fatal("Failed to parse kernel version as int")
}
newVersion := pb.KernelVersion{
Version: strconv.Itoa(versionInt + 1),
Copy: pb.PartitionCopy_A,
}
s.Log("Setting KERN-A version to ", newVersion.Version)
if _, err := h.KernelServiceClient.SetKernelVersion(ctx, &newVersion); err != nil {
s.Fatal("Failed to set kernel version: ", err)
}
s.Log("Performing mode aware reboot")
if err := ms.ModeAwareReboot(ctx, firmware.ColdReset); err != nil {
s.Fatal("Failed to reboot: ", err)
}
if err := h.RequireKernelServiceClient(ctx); err != nil {
s.Fatal("Failed to connect to kernel service: ", err)
}
s.Log("Get current kernel version for KERN-A")
currVersion, err := h.KernelServiceClient.GetKernelVersion(ctx, &pb.Partition{
Copy: pb.PartitionCopy_A,
})
if err != nil {
s.Fatal("Failed to get kernel version: ", err)
}
s.Log("Current kernel version is: ", currVersion.Version)
if currVersion.Version != newVersion.Version {
s.Fatalf("Expected kernel version to be %s but was %s", newVersion.Version, currVersion.Version)
}
s.Log("Verify DUT in KERN-A or ROOT-A")
if _, err := h.KernelServiceClient.VerifyKernelCopy(ctx, &pb.Partition{
Copy: pb.PartitionCopy_A,
}); err != nil {
s.Fatal("Failed to verify DUT currently is in copy A: ", err)
}
}