blob: 58bbcce9db191b26556e83a02a83d3cd2a75453f [file] [log] [blame]
// Copyright 2021 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.
#include <memory>
#include <base/files/file.h>
#include <base/files/file_path.h>
#include <base/memory/ref_counted.h>
#include <base/files/scoped_temp_dir.h>
#include <gtest/gtest.h>
#include "hps/hal/fake_dev.h"
#include "hps/hps.h"
#include "hps/hps_reg.h"
namespace {
class HPSTest : public testing::Test {
protected:
virtual void SetUp() {
fake_ = hps::FakeDev::Create();
hps_ = std::make_unique<hps::HPS>(fake_->CreateDevInterface());
}
void CreateBlob(const base::FilePath& file, int len) {
base::File f(file, base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
ASSERT_TRUE(f.IsValid());
f.SetLength(len);
}
scoped_refptr<hps::FakeDev> fake_;
std::unique_ptr<hps::HPS> hps_;
};
/*
* Check for a magic number.
*/
TEST_F(HPSTest, MagicNumber) {
EXPECT_EQ(hps_->Device()->ReadReg(hps::HpsReg::kMagic), hps::kHpsMagic);
}
/*
* Check that features can be enabled/disabled, and
* results are returned only when allowed.
*/
TEST_F(HPSTest, FeatureControl) {
// No features enabled until module is ready.
EXPECT_FALSE(hps_->Enable(0));
EXPECT_FALSE(hps_->Enable(1));
EXPECT_EQ(hps_->Result(0), -1);
// Set the module to be ready for features.
fake_->SkipBoot();
EXPECT_FALSE(hps_->Enable(hps::kFeatures));
EXPECT_FALSE(hps_->Disable(hps::kFeatures));
EXPECT_EQ(hps_->Result(hps::kFeatures), -1);
ASSERT_TRUE(hps_->Enable(0));
ASSERT_TRUE(hps_->Enable(1));
// Check that enabled features can be disabled.
EXPECT_TRUE(hps_->Disable(0));
EXPECT_TRUE(hps_->Disable(1));
// Check that a result is returned if the feature is enabled.
const int result = 42;
fake_->SetF1Result(result);
EXPECT_EQ(hps_->Result(0), -1);
ASSERT_TRUE(hps_->Enable(0));
EXPECT_EQ(hps_->Result(0), result);
ASSERT_TRUE(hps_->Disable(0));
EXPECT_EQ(hps_->Result(0), -1);
}
/*
* Download testing.
*/
TEST_F(HPSTest, Download) {
base::ScopedTempDir temp_dir;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
auto f = temp_dir.GetPath().Append("blob");
const int len = 1024;
CreateBlob(f, len);
// Download allowed to bank 0 in pre-booted state.
ASSERT_TRUE(hps_->Download(0, f));
// Make sure the right amount was written.
EXPECT_EQ(fake_->GetBankLen(0), len);
// Fail the memory write and confirm that the request fails.
// TODO(amcrae): Refactor to use enum directly.
fake_->Set(hps::FakeDev::Flags::kMemFail);
ASSERT_FALSE(hps_->Download(0, f));
// No change to length.
EXPECT_EQ(fake_->GetBankLen(0), len);
fake_->Clear(hps::FakeDev::Flags::kMemFail);
EXPECT_FALSE(hps_->Download(1, f));
fake_->SkipBoot();
// No downloads allowed when running.
EXPECT_FALSE(hps_->Download(0, f));
}
/*
* Download testing with small block size
*/
TEST_F(HPSTest, DownloadSmallBlocks) {
base::ScopedTempDir temp_dir;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
auto f = temp_dir.GetPath().Append("blob");
const int len = 1024;
CreateBlob(f, len);
fake_->SetBlockSizeBytes(32);
// Download allowed to bank 0 in pre-booted state.
ASSERT_TRUE(hps_->Download(0, f));
// Make sure the right amount was written.
EXPECT_EQ(fake_->GetBankLen(0), len);
}
/*
* Boot testing.
*/
TEST_F(HPSTest, SkipBoot) {
// Make sure features can't be enabled.
ASSERT_FALSE(hps_->Enable(0));
// Put the fake straight into application stage.
fake_->SkipBoot();
// Inform the HPS handler that application stage is ready.
hps_->SkipBoot();
// Ensure that features can be enabled.
EXPECT_TRUE(hps_->Enable(0));
}
/*
* Test normal boot, where the versions match and
* the files are verified, so no flash update should occur.
*/
TEST_F(HPSTest, NormalBoot) {
base::ScopedTempDir temp_dir;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
// Create MCU and SPI flash filenames (but do not
// create the files themselves).
auto mcu = temp_dir.GetPath().Append("mcu");
auto spi = temp_dir.GetPath().Append("spi");
// Set the expected version
const uint16_t version = 1234;
fake_->SetVersion(version);
// Set up the version and files.
hps_->Init(version, mcu, spi);
// Boot the module.
ASSERT_TRUE(hps_->Boot());
// Ensure that features can be enabled.
EXPECT_TRUE(hps_->Enable(0));
EXPECT_EQ(fake_->GetBankLen(0), 0);
EXPECT_EQ(fake_->GetBankLen(1), 0);
}
/*
* Test that the MCU flash is updated when not verified.
*/
TEST_F(HPSTest, McuUpdate) {
base::ScopedTempDir temp_dir;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
// Create MCU and SPI flash filenames (but do not
// create the files themselves).
auto mcu = temp_dir.GetPath().Append("mcu");
auto spi = temp_dir.GetPath().Append("spi");
const int len = 1024;
CreateBlob(mcu, len);
// Set the expected version
const uint16_t version = 1234;
fake_->SetVersion(version);
fake_->Set(hps::FakeDev::Flags::kApplNotVerified);
fake_->Set(hps::FakeDev::Flags::kResetApplVerification);
// Set up the version and files.
hps_->Init(version, mcu, spi);
// Boot the module.
ASSERT_TRUE(hps_->Boot());
// Check that MCU was downloaded.
EXPECT_EQ(fake_->GetBankLen(0), len);
EXPECT_EQ(fake_->GetBankLen(1), 0);
}
/*
* Test that the SPI flash is updated when not verified.
*/
TEST_F(HPSTest, SpiUpdate) {
base::ScopedTempDir temp_dir;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
// Create MCU and SPI flash filenames (but do not
// create the files themselves).
auto mcu = temp_dir.GetPath().Append("mcu");
auto spi = temp_dir.GetPath().Append("spi");
const int len = 1024;
CreateBlob(spi, len);
// Set the expected version
const uint16_t version = 1234;
fake_->SetVersion(version);
fake_->Set(hps::FakeDev::Flags::kSpiNotVerified);
fake_->Set(hps::FakeDev::Flags::kResetSpiVerification);
// Set up the version and files.
hps_->Init(version, mcu, spi);
// Boot the module.
ASSERT_TRUE(hps_->Boot());
// Check that SPI was downloaded.
EXPECT_EQ(fake_->GetBankLen(0), 0);
EXPECT_EQ(fake_->GetBankLen(1), len);
}
/*
* Test that the both SPI and MCU are updated
* when not verified.
*/
TEST_F(HPSTest, BothUpdate) {
base::ScopedTempDir temp_dir;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
// Create MCU and SPI flash filenames (but do not
// create the files themselves).
auto mcu = temp_dir.GetPath().Append("mcu");
auto spi = temp_dir.GetPath().Append("spi");
const int len = 1024;
CreateBlob(spi, len);
CreateBlob(mcu, len);
// Set the expected version
const uint16_t version = 1234;
fake_->SetVersion(version);
fake_->Set(hps::FakeDev::Flags::kApplNotVerified);
fake_->Set(hps::FakeDev::Flags::kResetApplVerification);
fake_->Set(hps::FakeDev::Flags::kSpiNotVerified);
fake_->Set(hps::FakeDev::Flags::kResetSpiVerification);
// Set up the version and files.
hps_->Init(version, mcu, spi);
// Boot the module.
ASSERT_TRUE(hps_->Boot());
// Check that both MCU and SPI blobs were updated.
EXPECT_EQ(fake_->GetBankLen(0), len);
EXPECT_EQ(fake_->GetBankLen(1), len);
}
/*
* Verify that mismatching version will update both MCU and SPI
*/
TEST_F(HPSTest, VersionUpdate) {
base::ScopedTempDir temp_dir;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
// Create MCU and SPI flash filenames (but do not
// create the files themselves).
auto mcu = temp_dir.GetPath().Append("mcu");
auto spi = temp_dir.GetPath().Append("spi");
const int len = 1024;
CreateBlob(spi, len);
CreateBlob(mcu, len);
// Set the current version
const uint16_t version = 1234;
fake_->SetVersion(version);
fake_->Set(hps::FakeDev::Flags::kSpiNotVerified);
fake_->Set(hps::FakeDev::Flags::kResetSpiVerification);
fake_->Set(hps::FakeDev::Flags::kIncrementVersion);
// Set up the version to be the next version.
hps_->Init(version + 1, mcu, spi);
// Boot the module.
ASSERT_TRUE(hps_->Boot());
// Check that both MCU and SPI were downloaded.
EXPECT_EQ(fake_->GetBankLen(0), len);
EXPECT_EQ(fake_->GetBankLen(1), len);
}
} // namespace