blob: aa7894776485b2abb65ebcd4b75ad6e9ae384b97 [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT
#include <lib/arch/testing/x86/fake-msr.h>
#include <optional>
#include <gtest/gtest.h>
namespace {
TEST(FakeMsrIoTests, PopulateAndPeek) {
arch::testing::FakeMsrIo io;
io.Populate(arch::X86Msr::IA32_FS_BASE, 0xaaaa'bbbb'cccc'dddd);
EXPECT_EQ(0xaaaa'bbbb'cccc'ddddu, io.Peek(arch::X86Msr::IA32_FS_BASE));
EXPECT_EQ(0xaaaa'bbbb'cccc'ddddu, io.Peek(arch::X86Msr::IA32_FS_BASE));
}
TEST(FakeMsrIoTests, Read) {
const uint32_t fs_base = static_cast<uint32_t>(arch::X86Msr::IA32_FS_BASE);
arch::testing::FakeMsrIo io;
io.Populate(arch::X86Msr::IA32_FS_BASE, 0xaaaa'bbbb'cccc'dddd);
EXPECT_EQ(0xaaaa'bbbb'cccc'ddddu, io.Read<uint64_t>(fs_base));
EXPECT_EQ(0xaaaa'bbbb'cccc'ddddu, io.Read<uint64_t>(fs_base));
EXPECT_EQ(0xaaaa'bbbb'cccc'ddddu, io.Peek(arch::X86Msr::IA32_FS_BASE));
}
TEST(FakeMsrIoTests, PopulateOverwrites) {
arch::testing::FakeMsrIo io;
io.Populate(arch::X86Msr::IA32_FS_BASE, 0xaaaa'bbbb'cccc'dddd);
EXPECT_EQ(0xaaaa'bbbb'cccc'ddddu, io.Peek(arch::X86Msr::IA32_FS_BASE));
io.Populate(arch::X86Msr::IA32_FS_BASE, 0xdddd'cccc'bbbb'aaaa);
EXPECT_EQ(0xdddd'cccc'bbbb'aaaau, io.Peek(arch::X86Msr::IA32_FS_BASE));
}
TEST(FakeMsrIoTests, Write) {
const uint32_t fs_base = static_cast<uint32_t>(arch::X86Msr::IA32_FS_BASE);
arch::testing::FakeMsrIo io;
io.Populate(arch::X86Msr::IA32_FS_BASE, 0xaaaa'bbbb'cccc'dddd);
io.Write(uint64_t{0xdddd'cccc'bbbb'aaaa}, fs_base);
EXPECT_EQ(0xdddd'cccc'bbbb'aaaau, io.Peek(arch::X86Msr::IA32_FS_BASE));
EXPECT_EQ(0xdddd'cccc'bbbb'aaaau, io.Read<uint64_t>(fs_base));
io.Write(uint64_t{0xaaaa'bbbb'cccc'dddd}, fs_base);
EXPECT_EQ(0xaaaa'bbbb'cccc'ddddu, io.Peek(arch::X86Msr::IA32_FS_BASE));
EXPECT_EQ(0xaaaa'bbbb'cccc'ddddu, io.Read<uint64_t>(fs_base));
}
TEST(FakeMsrIoTests, IoWithSideEffects) {
const uint32_t fs_base = static_cast<uint32_t>(arch::X86Msr::IA32_FS_BASE);
const uint32_t gs_base = static_cast<uint32_t>(arch::X86Msr::IA32_GS_BASE);
std::optional<arch::X86Msr> last_written_msr, last_read_msr;
std::optional<uint64_t> last_written_value, last_read_value;
// These are of course nonsense side-effects.
auto on_write = [&last_written_msr, &last_written_value](arch::X86Msr msr, uint64_t& value) {
last_written_msr = msr;
last_written_value = value;
value = 0x1234'1234'1234'1234; // Reset to a strange, specific value.
};
auto on_read = [&last_read_msr, &last_read_value](arch::X86Msr msr, uint64_t& value) {
last_read_msr = msr;
last_read_value = value;
};
arch::testing::FakeMsrIo io(std::move(on_write), std::move(on_read));
// Populate should have no side-effects - and can be chained.
io.Populate(arch::X86Msr::IA32_FS_BASE, 0xaaaa'bbbb'cccc'dddd)
.Populate(arch::X86Msr::IA32_GS_BASE, 0xabcd'abcd'abcd'abcd);
EXPECT_FALSE(last_read_msr.has_value());
EXPECT_FALSE(last_read_value.has_value());
EXPECT_FALSE(last_written_msr.has_value());
EXPECT_FALSE(last_written_value.has_value());
// Peek should have no side-effects.
static_cast<void>(io.Peek(arch::X86Msr::IA32_FS_BASE));
static_cast<void>(io.Peek(arch::X86Msr::IA32_GS_BASE));
EXPECT_FALSE(last_read_msr.has_value());
EXPECT_FALSE(last_read_value.has_value());
EXPECT_FALSE(last_written_msr.has_value());
EXPECT_FALSE(last_written_value.has_value());
// Read should only update the last_read_* variables to not alter the stored
// register value.
EXPECT_EQ(0xaaaa'bbbb'cccc'ddddu, io.Read<uint64_t>(fs_base));
EXPECT_EQ(0xaaaa'bbbb'cccc'ddddu, io.Read<uint64_t>(fs_base));
EXPECT_EQ(arch::X86Msr::IA32_FS_BASE, *last_read_msr);
EXPECT_EQ(0xaaaa'bbbb'cccc'ddddu, *last_read_value);
EXPECT_FALSE(last_written_msr.has_value());
EXPECT_FALSE(last_written_value.has_value());
EXPECT_EQ(0xabcd'abcd'abcd'abcdu, io.Read<uint64_t>(gs_base));
EXPECT_EQ(0xabcd'abcd'abcd'abcdu, io.Read<uint64_t>(gs_base));
EXPECT_EQ(arch::X86Msr::IA32_GS_BASE, *last_read_msr);
EXPECT_EQ(0xabcd'abcd'abcd'abcdu, *last_read_value);
EXPECT_FALSE(last_written_msr.has_value());
EXPECT_FALSE(last_written_value.has_value());
// Write should only update the last_written_* variables and reset the stored
// register value to 0x1234'1234'1234'1234.
last_read_msr = std::nullopt;
last_read_value = std::nullopt;
io.Write(uint64_t{0xdddd'cccc'bbbb'aaaa}, fs_base);
EXPECT_FALSE(last_read_msr.has_value());
EXPECT_FALSE(last_read_value.has_value());
EXPECT_EQ(arch::X86Msr::IA32_FS_BASE, *last_written_msr);
EXPECT_EQ(0xdddd'cccc'bbbb'aaaau, *last_written_value);
EXPECT_EQ(0x1234'1234'1234'1234u, io.Peek(arch::X86Msr::IA32_FS_BASE));
last_read_msr = std::nullopt;
last_read_value = std::nullopt;
io.Write(uint64_t{0xdcba'dcba'dcba'dcba}, gs_base);
EXPECT_FALSE(last_read_msr.has_value());
EXPECT_FALSE(last_read_value.has_value());
EXPECT_EQ(arch::X86Msr::IA32_GS_BASE, *last_written_msr);
EXPECT_EQ(0xdcba'dcba'dcba'dcbau, *last_written_value);
EXPECT_EQ(0x1234'1234'1234'1234u, io.Peek(arch::X86Msr::IA32_GS_BASE));
}
} // namespace