blob: 16b33ae5dd6706851476d23da4d91db6364cf12e [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 "mbr-device.h"
#include <fuchsia/hardware/block/c/banjo.h>
#include <inttypes.h>
#include <lib/ddk/debug.h>
#include <lib/ddk/device.h>
#include <lib/ddk/driver.h>
#include <lib/fake_ddk/fake_ddk.h>
#include <lib/zircon-internal/thread_annotations.h>
#include <zircon/errors.h>
#include <zircon/hw/gpt.h>
#include <fbl/alloc_checker.h>
#include <fbl/string.h>
#include <fbl/vector.h>
#include <gpt/c/gpt.h>
#include <zxtest/zxtest.h>
#include "mbr-test-data.h"
#include "mbr.h"
namespace {
constexpr uint32_t kBlockSz = 512;
constexpr uint32_t kBlockCnt = 20;
const block_info_t kInfo = {kBlockCnt, kBlockSz, BLOCK_MAX_TRANSFER_UNBOUNDED, 0, 0};
class FakeBlockDevice : public ddk::BlockProtocol<FakeBlockDevice> {
public:
FakeBlockDevice() : proto_({&block_protocol_ops_, this}), mbr_{kFuchsiaMbr} {}
block_protocol_t* proto() { return &proto_; }
void BlockQuery(block_info_t* info_out, size_t* block_op_size_out) {
*info_out = kInfo;
*block_op_size_out = sizeof(block_op_t);
}
void BlockQueue(block_op_t* operation, block_queue_callback completion_cb, void* cookie) {
if (operation->rw.command == BLOCK_OP_READ) {
if ((operation->rw.offset_dev + operation->rw.length) * kBlockSz <= mbr::kMbrSize) {
// Reading from header
uint64_t vmo_addr = operation->rw.offset_vmo * kBlockSz;
off_t off = operation->rw.offset_dev * kBlockSz;
zx_vmo_write(operation->rw.vmo, mbr_ + off, vmo_addr, operation->rw.length * kBlockSz);
} else {
}
} else if (operation->rw.command == BLOCK_OP_WRITE) {
// Ensure the header is never written into.
ASSERT_GT((operation->rw.offset_dev + operation->rw.length) * kBlockSz, mbr::kMbrSize);
}
completion_cb(cookie, ZX_OK, operation);
}
void SetMbr(const uint8_t* new_mbr) { mbr_ = new_mbr; }
private:
block_protocol_t proto_;
const uint8_t* mbr_;
};
} // namespace
namespace mbr {
class MbrDeviceTest : public zxtest::Test {
public:
MbrDeviceTest() {}
void Init() { ddk_.SetProtocol(ZX_PROTOCOL_BLOCK, fake_block_device_.proto()); }
DISALLOW_COPY_ASSIGN_AND_MOVE(MbrDeviceTest);
fake_ddk::Bind ddk_;
protected:
FakeBlockDevice fake_block_device_;
};
TEST_F(MbrDeviceTest, DeviceCreation) {
Init();
fbl::Vector<std::unique_ptr<MbrDevice>> devices;
ASSERT_OK(MbrDevice::Create(fake_ddk::kFakeParent, &devices));
ASSERT_EQ(devices.size(), 2);
ASSERT_NOT_NULL(devices[0].get());
EXPECT_STR_EQ(devices[0]->Name().c_str(), "part-000");
guid_t guid;
EXPECT_OK(devices[0]->BlockPartitionGetGuid(GUIDTYPE_TYPE, &guid));
{
uint8_t expected_guid[GPT_GUID_LEN] = GUID_SYSTEM_VALUE;
EXPECT_BYTES_EQ(reinterpret_cast<uint8_t*>(&guid), expected_guid, GPT_GUID_LEN);
}
ASSERT_NOT_NULL(devices[1].get());
EXPECT_STR_EQ(devices[1]->Name().c_str(), "part-001");
EXPECT_OK(devices[1]->BlockPartitionGetGuid(GUIDTYPE_TYPE, &guid));
{
uint8_t expected_guid[GPT_GUID_LEN] = GUID_DATA_VALUE;
EXPECT_BYTES_EQ(reinterpret_cast<uint8_t*>(&guid), expected_guid, GPT_GUID_LEN);
}
}
TEST_F(MbrDeviceTest, DeviceCreationProtectiveMbr) {
fake_block_device_.SetMbr(kProtectiveMbr);
Init();
fbl::Vector<std::unique_ptr<MbrDevice>> devices;
ASSERT_EQ(MbrDevice::Create(fake_ddk::kFakeParent, &devices), ZX_ERR_NOT_SUPPORTED);
}
TEST_F(MbrDeviceTest, DdkLifecycle) {
Init();
fbl::Vector<std::unique_ptr<MbrDevice>> devices;
ASSERT_OK(MbrDevice::Create(fake_ddk::kFakeParent, &devices));
ASSERT_EQ(devices.size(), 2);
auto* device0 = devices[0].get();
ASSERT_NOT_NULL(device0);
EXPECT_OK(MbrDevice::Bind(std::move(devices[0])));
auto* device1 = devices[1].get();
ASSERT_NOT_NULL(device1);
EXPECT_OK(MbrDevice::Bind(std::move(devices[1])));
device0->DdkAsyncRemove();
device1->DdkAsyncRemove();
EXPECT_TRUE(ddk_.Ok());
// Delete the object, which means this test should not leak.
device0->DdkRelease();
device1->DdkRelease();
}
TEST(Bind, UnsupportedProtocol) {
fake_ddk::Bind ddk;
auto bind_result = MbrDriverOps.bind(nullptr, fake_ddk::kFakeParent);
ASSERT_EQ(bind_result, ZX_ERR_NOT_SUPPORTED);
}
} // namespace mbr