blob: 68663fc6aab372c1b754c136f4ebb7aa8683c500 [file] [log] [blame]
// Copyright 2019 The Fuchsia 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 "ftl_internal.h"
#include <fbl/vector.h>
#include <zxtest/zxtest.h>
namespace internal {
constexpr SpareArea kSimpleOob = {1, {2, 3, 4, 5}, {6, 7, 8, 9}, {10, 11, 12}, 0x5D, {14, 15}, 16};
constexpr SpareArea kEmptyOob = {0xFF,
{0xFF, 0xFF, 0xFF, 0xFF},
{0xFF, 0xFF, 0xFF, 0xFF},
{0xFF, 0xFF, 0xFF},
0xFF,
{0xFF, 0xFF},
0xFF};
TEST(SpareArea, DecodePageNum) {
EXPECT_EQ(0x05040302, DecodePageNum(kSimpleOob));
EXPECT_EQ(-1, DecodePageNum(kEmptyOob));
}
TEST(SpareArea, DecodeBlockCount) {
EXPECT_EQ(0x09080706, DecodeBlockCount(kSimpleOob));
EXPECT_EQ(-1, DecodeBlockCount(kEmptyOob));
}
TEST(SpareArea, DecodeWear) {
EXPECT_EQ(0x050C0B0A, DecodeWear(kSimpleOob));
EXPECT_EQ(-1, DecodeWear(kEmptyOob));
}
TEST(SpareArea, IsNdmBlock) {
SpareArea oob = kSimpleOob;
oob.ndm = 0;
EXPECT_FALSE(IsNdmBlock(oob));
memcpy(oob.page_num, kNdmSignature, sizeof(kNdmSignature) - 1);
EXPECT_TRUE(IsNdmBlock(oob));
}
TEST(SpareArea, IsFtlBlock) {
SpareArea oob = kSimpleOob;
EXPECT_FALSE(IsFtlBlock(oob));
oob.ndm = 0xFF;
EXPECT_TRUE(IsFtlBlock(oob));
}
TEST(SpareArea, IsDataBlock) {
SpareArea oob = kSimpleOob;
EXPECT_FALSE(IsDataBlock(oob));
memset(oob.block_count, 0xFF, 4);
EXPECT_TRUE(IsDataBlock(oob));
}
TEST(SpareArea, IsCopyBlock) {
SpareArea oob = kSimpleOob;
EXPECT_FALSE(IsCopyBlock(oob));
oob.block_count[0] = 0xFE;
memset(oob.block_count + 1, 0xFF, 3);
EXPECT_TRUE(IsCopyBlock(oob));
}
TEST(SpareArea, IsMapBlock) {
SpareArea oob = kSimpleOob;
EXPECT_TRUE(IsMapBlock(oob));
memset(oob.block_count, 0xFF, 4);
EXPECT_FALSE(IsMapBlock(oob));
oob.block_count[0] = 0xFE;
EXPECT_FALSE(IsMapBlock(oob));
oob.block_count[0] = 0xFD;
EXPECT_TRUE(IsMapBlock(oob));
}
constexpr uint32_t kControl1[] = {
0x00010001, 0x00000002, 0x0ba819e4, 0x0000012c, 0x00040000, 0x0000012b, 0x0000012a, 0x0000011c,
0x00000129, 0xffffffff, 0x00000000, 0x0000002a, 0x00000064, 0x0000012c, 0xffffffff, 0xffffffff,
};
TEST(NdmData, BadBlocks) {
NdmData ndm;
fbl::Vector<int32_t> bad_blocks;
fbl::Vector<int32_t> replacements;
ndm.ParseNdmData(kControl1, &bad_blocks, &replacements);
ASSERT_EQ(2, bad_blocks.size());
ASSERT_EQ(0, replacements.size());
EXPECT_EQ(42, bad_blocks[0]);
EXPECT_EQ(100, bad_blocks[1]);
}
constexpr uint32_t kControl2[] = {
0x00010001, 0x00000002, 0x85241afd, 0x0000012c, 0x00040000, 0x0000012b, 0x0000012a, 0x0000011c,
0x00000129, 0xffffffff, 0x00000001, 0x0000012c, 0x00000000, 0x0000011b, 0xffffffff, 0xffffffff,
0x00000000, 0x0000011b, 0x006c7466, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff};
TEST(NdmData, Replacements) {
NdmData ndm;
fbl::Vector<int32_t> bad_blocks;
fbl::Vector<int32_t> replacements;
ndm.ParseNdmData(kControl2, &bad_blocks, &replacements);
ASSERT_EQ(1, bad_blocks.size());
ASSERT_EQ(1, replacements.size());
EXPECT_EQ(0, bad_blocks[0]);
EXPECT_EQ(283, replacements[0]);
}
constexpr uint32_t kControl3[] = {
0x00010001, 0x00000002, 0xb97253b3, 0x0000012c, 0x00040000, 0x0000012b, 0x0000012a, 0x0000011e,
0x00000129, 0xffffffff, 0x00000001, 0x0000002a, 0x00000064, 0x0000012c, 0x00000000, 0x0000011d,
0xffffffff, 0xffffffff, 0x00000000, 0x0000011b, 0x006c7466, 0x00000000, 0x00000000, 0x00000000};
TEST(NdmData, BothBadBlockTypes) {
NdmData ndm;
fbl::Vector<int32_t> bad_blocks;
fbl::Vector<int32_t> replacements;
ndm.ParseNdmData(kControl3, &bad_blocks, &replacements);
ASSERT_EQ(3, bad_blocks.size());
ASSERT_EQ(1, replacements.size());
EXPECT_EQ(42, bad_blocks[0]);
EXPECT_EQ(100, bad_blocks[1]);
EXPECT_EQ(0, bad_blocks[2]);
EXPECT_EQ(285, replacements[0]);
}
constexpr uint32_t kControl4[] = {
0x00010001, 0x00000002, 0x19a0c54b, 0x0000012c, 0x00040000, 0x0000012b, 0x0000012a, 0x0000011c,
0x00000129, 0x0000011c, 0x0000011b, 0x0000002d, 0x00000102, 0x00012c00, 0x00000000, 0x00011b00,
0x00011b00, 0x00011c00, 0xffffff00, 0xffffffff, 0x000000ff, 0x00011b00, 0x6c746600, 0x00000000,
0x00000000, 0x00000000, 0xffffff00, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff};
TEST(NdmData, Transitional) {
NdmData ndm;
fbl::Vector<int32_t> bad_blocks;
fbl::Vector<int32_t> replacements;
ndm.ParseNdmData(kControl4, &bad_blocks, &replacements);
#if defined(__arm__) || defined(__aarch64__)
ASSERT_EQ(0, bad_blocks.size());
ASSERT_EQ(0, replacements.size());
#else
ASSERT_EQ(2, bad_blocks.size());
ASSERT_EQ(2, replacements.size());
EXPECT_EQ(0, bad_blocks[0]);
EXPECT_EQ(283, bad_blocks[1]);
EXPECT_EQ(283, replacements[0]);
EXPECT_EQ(284, replacements[1]);
#endif
}
// Goes over a few members to verify that the proper shift is taking place.
TEST(GetHeader, Version1Basic) {
NdmHeader header = GetNdmHeader(kControl2);
EXPECT_EQ(1, header.major_version);
EXPECT_EQ(1, header.minor_version);
EXPECT_EQ(0x12c, header.num_blocks);
EXPECT_EQ(0x12a, header.control_block1);
}
TEST(GetHeader, Version1Transitional) {
NdmHeader header = GetNdmHeader(kControl4);
EXPECT_EQ(1, header.major_version);
EXPECT_EQ(1, header.minor_version);
EXPECT_EQ(0x12c, header.num_blocks);
EXPECT_EQ(0x12a, header.control_block1);
EXPECT_EQ(0x11c, header.transfer_to_block);
EXPECT_EQ(0x11b, header.transfer_bad_block);
EXPECT_EQ(0x2d, header.transfer_bad_page);
}
constexpr uint32_t kControlBlockBadBlocksV2[] = {
0x00000002, 0x00010001, 0x00000002, 0x01148752, 0x0000001e, 0x00010000, 0x0000001d, 0x0000001c,
0xffffffff, 0xffffffff, 0xffffffff, 0x00000003, 0x0000000d, 0x00000001, 0x00000000, 0x0000001e,
0x00000003, 0x0000001b, 0xffffffff, 0xffffffff, 0x00000000, 0x0000001a, 0x006c7466, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff};
TEST(GetHeader, Version2Basic) {
NdmHeader header = GetNdmHeader(kControlBlockBadBlocksV2);
EXPECT_EQ(2, header.major_version);
EXPECT_EQ(0, header.minor_version);
EXPECT_EQ(0x1e, header.num_blocks);
EXPECT_EQ(0x1c, header.control_block1);
}
constexpr uint32_t kControlBlockTransferV2[] = {
0x00000002, 0x00010001, 0x00000001, 0xdc1fd63c, 0x0000001e, 0x00010000, 0x0000001d, 0x0000001c,
0xffffffff, 0xffffffff, 0x0000001b, 0x00000003, 0x0000000d, 0x00000001, 0x00000000, 0x0000001e,
0x00000003, 0x0000001b, 0xffffffff, 0xffffffff, 0x00000000, 0x0000001a, 0x006c7466, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff};
TEST(GetHeader, Version2Transitional) {
NdmHeader header = GetNdmHeader(kControlBlockTransferV2);
EXPECT_EQ(2, header.major_version);
EXPECT_EQ(0, header.minor_version);
EXPECT_EQ(0x1e, header.num_blocks);
EXPECT_EQ(0x1c, header.control_block1);
EXPECT_EQ(0x1b, header.transfer_to_block);
EXPECT_EQ(0x3, header.transfer_bad_block);
EXPECT_EQ(0xd, header.transfer_bad_page);
}
TEST(NdmData, BothBadBlockTypesVersion2) {
NdmData ndm;
fbl::Vector<int32_t> bad_blocks;
fbl::Vector<int32_t> replacements;
ndm.ParseNdmData(kControlBlockBadBlocksV2, &bad_blocks, &replacements);
ASSERT_EQ(2, bad_blocks.size());
ASSERT_EQ(1, replacements.size());
EXPECT_EQ(0, bad_blocks[0]);
EXPECT_EQ(3, bad_blocks[1]);
EXPECT_EQ(27, replacements[0]);
}
TEST(NdmData, TransitionalVersion2) {
NdmData ndm;
fbl::Vector<int32_t> bad_blocks;
fbl::Vector<int32_t> replacements;
ndm.ParseNdmData(kControlBlockTransferV2, &bad_blocks, &replacements);
ASSERT_EQ(2, bad_blocks.size());
ASSERT_EQ(1, replacements.size());
EXPECT_EQ(0, bad_blocks[0]);
EXPECT_EQ(3, bad_blocks[1]);
EXPECT_EQ(27, replacements[0]);
}
} // namespace internal