blob: 3d7496d9ba2eb7b6387d254e02273c17bc835c87 [file] [log] [blame]
// Copyright 2018 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 <lib/paver/device-partitioner.h>
#include <dirent.h>
#include <fcntl.h>
#include <fbl/auto_call.h>
#include <fbl/unique_ptr.h>
#include <fuchsia/hardware/nand/c/fidl.h>
#include <lib/async-loop/cpp/loop.h>
#include <zircon/boot/image.h>
#include <zircon/hw/gpt.h>
#include <zircon/syscalls.h>
#include <zircon/types.h>
#include <zxtest/zxtest.h>
#include <utility>
#include "test/test-utils.h"
namespace {
constexpr uint8_t kZirconAType[GPT_GUID_LEN] = GUID_ZIRCON_A_VALUE;
constexpr uint8_t kZirconBType[GPT_GUID_LEN] = GUID_ZIRCON_B_VALUE;
constexpr uint8_t kZirconRType[GPT_GUID_LEN] = GUID_ZIRCON_R_VALUE;
constexpr uint8_t kVbMetaAType[GPT_GUID_LEN] = GUID_VBMETA_A_VALUE;
constexpr uint8_t kVbMetaBType[GPT_GUID_LEN] = GUID_VBMETA_B_VALUE;
constexpr uint8_t kFvmType[GPT_GUID_LEN] = GUID_FVM_VALUE;
constexpr fuchsia_hardware_nand_RamNandInfo
kNandInfo =
{
.vmo = ZX_HANDLE_INVALID,
.nand_info =
{
.page_size = kPageSize,
.pages_per_block = kPagesPerBlock,
.num_blocks = kNumBlocks,
.ecc_bits = 8,
.oob_size = kOobSize,
.nand_class = fuchsia_hardware_nand_Class_PARTMAP,
.partition_guid = {},
},
.partition_map =
{
.device_guid = {},
.partition_count = 7,
.partitions =
{
{
.type_guid = {},
.unique_guid = {},
.first_block = 0,
.last_block = 3,
.copy_count = 0,
.copy_byte_offset = 0,
.name = {},
.hidden = true,
.bbt = true,
},
{
.type_guid = GUID_BOOTLOADER_VALUE,
.unique_guid = {},
.first_block = 4,
.last_block = 7,
.copy_count = 0,
.copy_byte_offset = 0,
.name = {'b', 'o', 'o', 't', 'l', 'o', 'a', 'd', 'e', 'r'},
.hidden = false,
.bbt = false,
},
{
.type_guid = GUID_ZIRCON_A_VALUE,
.unique_guid = {},
.first_block = 8,
.last_block = 9,
.copy_count = 0,
.copy_byte_offset = 0,
.name = {'z', 'i', 'r', 'c', 'o', 'n', '-', 'a'},
.hidden = false,
.bbt = false,
},
{
.type_guid = GUID_ZIRCON_B_VALUE,
.unique_guid = {},
.first_block = 10,
.last_block = 11,
.copy_count = 0,
.copy_byte_offset = 0,
.name = {'z', 'i', 'r', 'c', 'o', 'n', '-', 'b'},
.hidden = false,
.bbt = false,
},
{
.type_guid = GUID_ZIRCON_R_VALUE,
.unique_guid = {},
.first_block = 12,
.last_block = 13,
.copy_count = 0,
.copy_byte_offset = 0,
.name = {'z', 'i', 'r', 'c', 'o', 'n', '-', 'r'},
.hidden = false,
.bbt = false,
},
{
.type_guid = GUID_VBMETA_A_VALUE,
.unique_guid = {},
.first_block = 14,
.last_block = 15,
.copy_count = 0,
.copy_byte_offset = 0,
.name = {'v', 'b', 'm', 'e', 't', 'a', '-', 'a'},
.hidden = false,
.bbt = false,
},
{
.type_guid = GUID_VBMETA_B_VALUE,
.unique_guid = {},
.first_block = 16,
.last_block = 17,
.copy_count = 0,
.copy_byte_offset = 0,
.name = {'v', 'b', 'm', 'e', 't', 'a', '-', 'b'},
.hidden = false,
.bbt = false,
},
},
},
.export_nand_config = true,
.export_partition_map = true,
};
bool Initialize() {
test_block_devices.reset();
paver::TestBlockFilter = FilterRealBlockDevices;
return true;
}
} // namespace
TEST(EfiDevicePartitionerTests, UseBlockInterfaceTest) {
ASSERT_TRUE(Initialize());
fbl::unique_ptr<BlockDevice> device;
BlockDevice::Create(kZirconAType, &device);
}
TEST(CrosDevicePartitionerTests, UseBlockInterfaceTest) {
ASSERT_TRUE(Initialize());
fbl::unique_ptr<BlockDevice> device;
BlockDevice::Create(kZirconAType, &device);
}
TEST(FixedDevicePartitionerTests, UseBlockInterfaceTest) {
fbl::unique_fd devfs(open("/dev", O_RDWR));
fbl::unique_ptr<paver::DevicePartitioner> partitioner;
ASSERT_EQ(paver::FixedDevicePartitioner::Initialize(std::move(devfs), &partitioner), ZX_OK);
ASSERT_FALSE(partitioner->UseSkipBlockInterface());
}
TEST(FixedDevicePartitionerTests, AddPartitionTest) {
fbl::unique_fd devfs(open("/dev", O_RDWR));
fbl::unique_ptr<paver::DevicePartitioner> partitioner;
ASSERT_EQ(paver::FixedDevicePartitioner::Initialize(std::move(devfs), &partitioner), ZX_OK);
ASSERT_EQ(partitioner->AddPartition(paver::Partition::kZirconB, nullptr), ZX_ERR_NOT_SUPPORTED);
}
TEST(FixedDevicePartitionerTests, WipeFvmTest) {
fbl::unique_fd devfs(open("/dev", O_RDWR));
fbl::unique_ptr<paver::DevicePartitioner> partitioner;
ASSERT_EQ(paver::FixedDevicePartitioner::Initialize(std::move(devfs), &partitioner), ZX_OK);
ASSERT_EQ(partitioner->WipeFvm(), ZX_OK);
}
TEST(FixedDevicePartitionerTests, FinalizePartitionTest) {
fbl::unique_fd devfs(open("/dev", O_RDWR));
fbl::unique_ptr<paver::DevicePartitioner> partitioner;
ASSERT_EQ(paver::FixedDevicePartitioner::Initialize(std::move(devfs), &partitioner), ZX_OK);
ASSERT_EQ(partitioner->FinalizePartition(paver::Partition::kZirconA), ZX_OK);
ASSERT_EQ(partitioner->FinalizePartition(paver::Partition::kZirconB), ZX_OK);
ASSERT_EQ(partitioner->FinalizePartition(paver::Partition::kZirconR), ZX_OK);
ASSERT_EQ(partitioner->FinalizePartition(paver::Partition::kVbMetaA), ZX_OK);
ASSERT_EQ(partitioner->FinalizePartition(paver::Partition::kVbMetaB), ZX_OK);
ASSERT_EQ(partitioner->FinalizePartition(paver::Partition::kFuchsiaVolumeManager), ZX_OK);
}
class AsyncLoop {
public:
explicit AsyncLoop()
: loop_(&kAsyncLoopConfigNoAttachToThread), dispatcher_(loop_.dispatcher()),
fake_sysinfo_(dispatcher_) {
loop_.StartThread("device-partitioner-test-loop");
}
FakeSysinfo& fake_sysinfo() { return fake_sysinfo_; }
private:
async::Loop loop_;
async_dispatcher_t* dispatcher_;
FakeSysinfo fake_sysinfo_;
};
TEST(FixedDevicePartitionerTests, FindPartitionTest) {
ASSERT_TRUE(Initialize());
fbl::unique_ptr<BlockDevice> fvm, zircon_a, zircon_b, zircon_r, vbmeta_a, vbmeta_b;
BlockDevice::Create(kZirconAType, &zircon_a);
BlockDevice::Create(kZirconBType, &zircon_b);
BlockDevice::Create(kZirconRType, &zircon_r);
BlockDevice::Create(kVbMetaAType, &vbmeta_a);
BlockDevice::Create(kVbMetaBType, &vbmeta_b);
BlockDevice::Create(kFvmType, &fvm);
AsyncLoop loop;
fbl::unique_fd devfs(open("/dev", O_RDWR));
auto partitioner = paver::DevicePartitioner::Create(std::move(devfs),
std::move(loop.fake_sysinfo().svc_chan()),
paver::Arch::kArm64);
ASSERT_NE(partitioner.get(), nullptr);
fbl::unique_fd fd;
ASSERT_EQ(partitioner->FindPartition(paver::Partition::kZirconA, &fd), ZX_OK);
ASSERT_EQ(partitioner->FindPartition(paver::Partition::kZirconB, &fd), ZX_OK);
ASSERT_EQ(partitioner->FindPartition(paver::Partition::kZirconR, &fd), ZX_OK);
ASSERT_EQ(partitioner->FindPartition(paver::Partition::kVbMetaA, &fd), ZX_OK);
ASSERT_EQ(partitioner->FindPartition(paver::Partition::kVbMetaB, &fd), ZX_OK);
ASSERT_EQ(partitioner->FindPartition(paver::Partition::kFuchsiaVolumeManager, &fd), ZX_OK);
}
TEST(FixedDevicePartitionerTests, GetBlockSizeTest) {
ASSERT_TRUE(Initialize());
fbl::unique_ptr<BlockDevice> fvm, zircon_a, zircon_b, zircon_r, vbmeta_a, vbmeta_b;
BlockDevice::Create(kZirconAType, &zircon_a);
BlockDevice::Create(kZirconBType, &zircon_b);
BlockDevice::Create(kZirconRType, &zircon_r);
BlockDevice::Create(kVbMetaAType, &vbmeta_a);
BlockDevice::Create(kVbMetaBType, &vbmeta_b);
BlockDevice::Create(kFvmType, &fvm);
AsyncLoop loop;
fbl::unique_fd devfs(open("/dev", O_RDWR));
auto partitioner = paver::DevicePartitioner::Create(std::move(devfs),
std::move(loop.fake_sysinfo().svc_chan()),
paver::Arch::kArm64);
ASSERT_NE(partitioner.get(), nullptr);
fbl::unique_fd fd;
uint32_t block_size;
ASSERT_EQ(partitioner->FindPartition(paver::Partition::kZirconA, &fd), ZX_OK);
ASSERT_EQ(partitioner->GetBlockSize(fd, &block_size), ZX_OK);
ASSERT_EQ(block_size, kBlockSize);
ASSERT_EQ(partitioner->FindPartition(paver::Partition::kZirconB, &fd), ZX_OK);
ASSERT_EQ(partitioner->GetBlockSize(fd, &block_size), ZX_OK);
ASSERT_EQ(block_size, kBlockSize);
ASSERT_EQ(partitioner->FindPartition(paver::Partition::kZirconR, &fd), ZX_OK);
ASSERT_EQ(partitioner->GetBlockSize(fd, &block_size), ZX_OK);
ASSERT_EQ(block_size, kBlockSize);
ASSERT_EQ(partitioner->FindPartition(paver::Partition::kVbMetaA, &fd), ZX_OK);
ASSERT_EQ(partitioner->GetBlockSize(fd, &block_size), ZX_OK);
ASSERT_EQ(block_size, kBlockSize);
ASSERT_EQ(partitioner->FindPartition(paver::Partition::kVbMetaB, &fd), ZX_OK);
ASSERT_EQ(partitioner->GetBlockSize(fd, &block_size), ZX_OK);
ASSERT_EQ(block_size, kBlockSize);
ASSERT_EQ(partitioner->FindPartition(paver::Partition::kFuchsiaVolumeManager, &fd), ZX_OK);
ASSERT_EQ(partitioner->GetBlockSize(fd, &block_size), ZX_OK);
ASSERT_EQ(block_size, kBlockSize);
}
TEST(SkipBlockDevicePartitionerTests, UseSkipBlockInterfaceTest) {
ASSERT_TRUE(Initialize());
fbl::unique_ptr<SkipBlockDevice> device;
SkipBlockDevice::Create(kNandInfo, &device);
fbl::unique_ptr<paver::DevicePartitioner> partitioner;
ASSERT_EQ(paver::SkipBlockDevicePartitioner::Initialize(device->devfs_root(), &partitioner),
ZX_OK);
ASSERT_TRUE(partitioner->UseSkipBlockInterface());
}
TEST(SkipBlockDevicePartitionerTests, ChooseSkipBlockPartitioner) {
ASSERT_TRUE(Initialize());
fbl::unique_ptr<SkipBlockDevice> device;
SkipBlockDevice::Create(kNandInfo, &device);
fbl::unique_ptr<BlockDevice> zircon_a;
BlockDevice::Create(kZirconAType, &zircon_a);
AsyncLoop loop;
auto partitioner = paver::DevicePartitioner::Create(device->devfs_root(),
std::move(loop.fake_sysinfo().svc_chan()),
paver::Arch::kArm64);
ASSERT_NE(partitioner.get(), nullptr);
ASSERT_TRUE(partitioner->UseSkipBlockInterface());
}
TEST(SkipBlockDevicePartitionerTests, AddPartitionTest) {
ASSERT_TRUE(Initialize());
fbl::unique_ptr<SkipBlockDevice> device;
SkipBlockDevice::Create(kNandInfo, &device);
fbl::unique_ptr<paver::DevicePartitioner> partitioner;
ASSERT_EQ(paver::SkipBlockDevicePartitioner::Initialize(device->devfs_root(), &partitioner),
ZX_OK);
ASSERT_EQ(partitioner->AddPartition(paver::Partition::kZirconB, nullptr), ZX_ERR_NOT_SUPPORTED);
}
TEST(SkipBlockDevicePartitionerTests, WipeFvmTest) {
ASSERT_TRUE(Initialize());
fbl::unique_ptr<SkipBlockDevice> device;
SkipBlockDevice::Create(kNandInfo, &device);
fbl::unique_ptr<paver::DevicePartitioner> partitioner;
ASSERT_EQ(paver::SkipBlockDevicePartitioner::Initialize(device->devfs_root(), &partitioner),
ZX_OK);
ASSERT_EQ(partitioner->WipeFvm(), ZX_OK);
}
TEST(SkipBlockDevicePartitionerTests, FinalizePartitionTest) {
ASSERT_TRUE(Initialize());
fbl::unique_ptr<SkipBlockDevice> device;
SkipBlockDevice::Create(kNandInfo, &device);
fbl::unique_ptr<paver::DevicePartitioner> partitioner;
ASSERT_EQ(paver::SkipBlockDevicePartitioner::Initialize(device->devfs_root(), &partitioner),
ZX_OK);
ASSERT_EQ(partitioner->FinalizePartition(paver::Partition::kBootloader), ZX_OK);
ASSERT_EQ(partitioner->FinalizePartition(paver::Partition::kZirconA), ZX_OK);
ASSERT_EQ(partitioner->FinalizePartition(paver::Partition::kZirconB), ZX_OK);
ASSERT_EQ(partitioner->FinalizePartition(paver::Partition::kZirconR), ZX_OK);
ASSERT_EQ(partitioner->FinalizePartition(paver::Partition::kVbMetaA), ZX_OK);
ASSERT_EQ(partitioner->FinalizePartition(paver::Partition::kVbMetaB), ZX_OK);
}
TEST(SkipBlockDevicePartitionerTests, FindPartitionTest) {
ASSERT_TRUE(Initialize());
fbl::unique_ptr<SkipBlockDevice> device;
SkipBlockDevice::Create(kNandInfo, &device);
fbl::unique_ptr<BlockDevice> fvm;
BlockDevice::Create(kFvmType, &fvm);
fbl::unique_ptr<paver::DevicePartitioner> partitioner;
ASSERT_EQ(paver::SkipBlockDevicePartitioner::Initialize(device->devfs_root(), &partitioner),
ZX_OK);
fbl::unique_fd fd;
ASSERT_EQ(partitioner->FindPartition(paver::Partition::kBootloader, &fd), ZX_OK);
ASSERT_EQ(partitioner->FindPartition(paver::Partition::kZirconA, &fd), ZX_OK);
ASSERT_EQ(partitioner->FindPartition(paver::Partition::kZirconB, &fd), ZX_OK);
ASSERT_EQ(partitioner->FindPartition(paver::Partition::kZirconR, &fd), ZX_OK);
ASSERT_EQ(partitioner->FindPartition(paver::Partition::kVbMetaA, &fd), ZX_OK);
ASSERT_EQ(partitioner->FindPartition(paver::Partition::kVbMetaB, &fd), ZX_OK);
ASSERT_EQ(partitioner->FindPartition(paver::Partition::kFuchsiaVolumeManager, &fd), ZX_OK);
}
TEST(SkipBlockDevicePartitionerTests, GetBlockSizeTest) {
ASSERT_TRUE(Initialize());
fbl::unique_ptr<SkipBlockDevice> device;
SkipBlockDevice::Create(kNandInfo, &device);
fbl::unique_ptr<BlockDevice> fvm;
BlockDevice::Create(kFvmType, &fvm);
fbl::unique_ptr<paver::DevicePartitioner> partitioner;
ASSERT_EQ(paver::SkipBlockDevicePartitioner::Initialize(device->devfs_root(), &partitioner),
ZX_OK);
fbl::unique_fd fd;
uint32_t block_size;
ASSERT_EQ(partitioner->FindPartition(paver::Partition::kBootloader, &fd), ZX_OK);
ASSERT_EQ(partitioner->GetBlockSize(fd, &block_size), ZX_OK);
ASSERT_EQ(block_size, kPageSize * kPagesPerBlock);
ASSERT_EQ(partitioner->FindPartition(paver::Partition::kZirconA, &fd), ZX_OK);
ASSERT_EQ(partitioner->GetBlockSize(fd, &block_size), ZX_OK);
ASSERT_EQ(block_size, kPageSize * kPagesPerBlock);
ASSERT_EQ(partitioner->FindPartition(paver::Partition::kZirconB, &fd), ZX_OK);
ASSERT_EQ(partitioner->GetBlockSize(fd, &block_size), ZX_OK);
ASSERT_EQ(block_size, kPageSize * kPagesPerBlock);
ASSERT_EQ(partitioner->FindPartition(paver::Partition::kZirconR, &fd), ZX_OK);
ASSERT_EQ(partitioner->GetBlockSize(fd, &block_size), ZX_OK);
ASSERT_EQ(block_size, kPageSize * kPagesPerBlock);
ASSERT_EQ(partitioner->FindPartition(paver::Partition::kVbMetaA, &fd), ZX_OK);
ASSERT_EQ(partitioner->GetBlockSize(fd, &block_size), ZX_OK);
ASSERT_EQ(block_size, kPageSize * kPagesPerBlock);
ASSERT_EQ(partitioner->FindPartition(paver::Partition::kVbMetaB, &fd), ZX_OK);
ASSERT_EQ(partitioner->GetBlockSize(fd, &block_size), ZX_OK);
ASSERT_EQ(block_size, kPageSize * kPagesPerBlock);
ASSERT_EQ(partitioner->FindPartition(paver::Partition::kFuchsiaVolumeManager, &fd), ZX_OK);
ASSERT_EQ(partitioner->GetBlockSize(fd, &block_size), ZX_OK);
ASSERT_EQ(block_size, kBlockSize);
}