| // 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 <fuchsia/hardware/block/c/banjo.h> |
| #include <string.h> |
| #include <unistd.h> |
| |
| #include <zxtest/zxtest.h> |
| |
| #include "manager.h" |
| #include "test/stub-block-device.h" |
| |
| namespace { |
| |
| TEST(ManagerTest, StartServer) { |
| StubBlockDevice blkdev; |
| ddk::BlockProtocolClient client(blkdev.proto()); |
| Manager manager; |
| zx::fifo fifo; |
| ASSERT_OK(manager.StartServer(&client, &fifo)); |
| ASSERT_OK(manager.CloseFifoServer()); |
| } |
| |
| TEST(ManagerTest, AttachVmo) { |
| StubBlockDevice blkdev; |
| ddk::BlockProtocolClient client(blkdev.proto()); |
| Manager manager; |
| zx::fifo fifo; |
| ASSERT_OK(manager.StartServer(&client, &fifo)); |
| |
| zx::vmo vmo; |
| ASSERT_OK(zx::vmo::create(8192, 0, &vmo)); |
| |
| vmoid_t vmoid; |
| ASSERT_OK(manager.AttachVmo(std::move(vmo), &vmoid)); |
| |
| ASSERT_OK(manager.CloseFifoServer()); |
| } |
| |
| TEST(ManagerTest, CloseVMO) { |
| StubBlockDevice blkdev; |
| ddk::BlockProtocolClient client(blkdev.proto()); |
| Manager manager; |
| zx::fifo fifo; |
| ASSERT_OK(manager.StartServer(&client, &fifo)); |
| zx::vmo vmo; |
| ASSERT_OK(zx::vmo::create(8192, 0, &vmo)); |
| vmoid_t vmoid; |
| ASSERT_OK(manager.AttachVmo(std::move(vmo), &vmoid)); |
| |
| // Request close VMO. |
| block_fifo_request_t req = { |
| .opcode = BLOCK_OP_CLOSE_VMO, |
| .reqid = 0x100, |
| .group = 0, |
| .vmoid = vmoid, |
| .length = 0, |
| .vmo_offset = 0, |
| .dev_offset = 0, |
| }; |
| |
| // Write request. |
| size_t actual_count = 0; |
| ASSERT_OK(fifo.write(sizeof(req), &req, 1, &actual_count)); |
| ASSERT_EQ(actual_count, 1); |
| |
| // Wait for response. |
| zx_signals_t observed; |
| ASSERT_OK(fifo.wait_one(ZX_FIFO_READABLE, zx::time::infinite(), &observed)); |
| |
| block_fifo_response_t res; |
| ASSERT_OK(fifo.read(sizeof(res), &res, 1, &actual_count)); |
| ASSERT_EQ(actual_count, 1); |
| ASSERT_OK(res.status); |
| ASSERT_EQ(req.reqid, res.reqid); |
| ASSERT_EQ(res.count, 1); |
| |
| ASSERT_OK(manager.CloseFifoServer()); |
| } |
| |
| zx_status_t FillVMO(zx::unowned_vmo vmo, size_t size) { |
| uint8_t buf[PAGE_SIZE]; |
| memset(buf, 0x44, PAGE_SIZE); |
| zx_status_t status; |
| for (size_t i = 0; i < size; i += PAGE_SIZE) { |
| size_t remain = size - i; |
| if (remain > PAGE_SIZE) { |
| remain = PAGE_SIZE; |
| } |
| if ((status = vmo->write(buf, i, remain)) != ZX_OK) { |
| return status; |
| } |
| } |
| return ZX_OK; |
| } |
| |
| TEST(ManagerTest, ReadSingleTest) { |
| StubBlockDevice blkdev; |
| ddk::BlockProtocolClient client(blkdev.proto()); |
| Manager manager; |
| zx::fifo fifo; |
| ASSERT_OK(manager.StartServer(&client, &fifo)); |
| |
| const size_t vmo_size = 8192; |
| zx::vmo vmo; |
| ASSERT_OK(zx::vmo::create(vmo_size, 0, &vmo)); |
| ASSERT_OK(FillVMO(zx::unowned_vmo(vmo), vmo_size)); |
| |
| vmoid_t vmoid; |
| ASSERT_OK(manager.AttachVmo(std::move(vmo), &vmoid)); |
| |
| // Request close VMO. |
| block_fifo_request_t req = { |
| .opcode = BLOCK_OP_READ, |
| .reqid = 0x100, |
| .group = 0, |
| .vmoid = vmoid, |
| .length = 1, |
| .vmo_offset = 0, |
| .dev_offset = 0, |
| }; |
| |
| // Write request. |
| size_t actual_count = 0; |
| ASSERT_OK(fifo.write(sizeof(req), &req, 1, &actual_count)); |
| ASSERT_EQ(actual_count, 1); |
| |
| // Wait for response. |
| zx_signals_t observed; |
| ASSERT_OK(zx_object_wait_one(fifo.get(), ZX_FIFO_READABLE, ZX_TIME_INFINITE, &observed)); |
| |
| block_fifo_response_t res; |
| ASSERT_OK(fifo.read(sizeof(res), &res, 1, &actual_count)); |
| ASSERT_EQ(actual_count, 1); |
| ASSERT_OK(res.status); |
| ASSERT_EQ(req.reqid, res.reqid); |
| ASSERT_EQ(res.count, 1); |
| |
| ASSERT_OK(manager.CloseFifoServer()); |
| } |
| |
| TEST(ManagerTest, ReadManyBlocksHasOneResponse) { |
| StubBlockDevice blkdev; |
| // Restrict max_transfer_size so that the server has to split up our request. |
| block_info_t block_info = { |
| .block_count = kBlockCount, .block_size = kBlockSize, .max_transfer_size = kBlockSize}; |
| blkdev.SetInfo(&block_info); |
| ddk::BlockProtocolClient client(blkdev.proto()); |
| Manager manager; |
| zx::fifo fifo; |
| ASSERT_OK(manager.StartServer(&client, &fifo)); |
| |
| const size_t vmo_size = 8192; |
| zx::vmo vmo; |
| ASSERT_OK(zx::vmo::create(vmo_size, 0, &vmo)); |
| ASSERT_OK(FillVMO(zx::unowned_vmo(vmo), vmo_size)); |
| |
| vmoid_t vmoid; |
| ASSERT_OK(manager.AttachVmo(std::move(vmo), &vmoid)); |
| |
| block_fifo_request_t reqs[2] = { |
| { |
| .opcode = BLOCK_OP_READ, |
| .reqid = 0x100, |
| .group = 0, |
| .vmoid = vmoid, |
| .length = 4, |
| .vmo_offset = 0, |
| .dev_offset = 0, |
| }, |
| { |
| .opcode = BLOCK_OP_READ, |
| .reqid = 0x101, |
| .group = 0, |
| .vmoid = vmoid, |
| .length = 1, |
| .vmo_offset = 0, |
| .dev_offset = 0, |
| }, |
| }; |
| |
| // Write requests. |
| size_t actual_count = 0; |
| ASSERT_OK(fifo.write(sizeof(reqs[0]), reqs, 2, &actual_count)); |
| ASSERT_EQ(actual_count, 2); |
| |
| // Wait for first response. |
| zx_signals_t observed; |
| ASSERT_OK(zx_object_wait_one(fifo.get(), ZX_FIFO_READABLE, ZX_TIME_INFINITE, &observed)); |
| |
| block_fifo_response_t res; |
| ASSERT_OK(fifo.read(sizeof(res), &res, 1, &actual_count)); |
| ASSERT_EQ(actual_count, 1); |
| ASSERT_OK(res.status); |
| ASSERT_EQ(reqs[0].reqid, res.reqid); |
| ASSERT_EQ(res.count, 1); |
| |
| // Wait for second response. |
| ASSERT_OK(zx_object_wait_one(fifo.get(), ZX_FIFO_READABLE, ZX_TIME_INFINITE, &observed)); |
| |
| ASSERT_OK(fifo.read(sizeof(res), &res, 1, &actual_count)); |
| ASSERT_EQ(actual_count, 1); |
| ASSERT_OK(res.status); |
| ASSERT_EQ(reqs[1].reqid, res.reqid); |
| ASSERT_EQ(res.count, 1); |
| |
| ASSERT_OK(manager.CloseFifoServer()); |
| } |
| |
| TEST(ManagerTest, TestLargeGroupedTransaction) { |
| StubBlockDevice blkdev; |
| // Restrict max_transfer_size so that the server has to split up our request. |
| block_info_t block_info = { |
| .block_count = kBlockCount, .block_size = kBlockSize, .max_transfer_size = kBlockSize}; |
| blkdev.SetInfo(&block_info); |
| ddk::BlockProtocolClient client(blkdev.proto()); |
| Manager manager; |
| zx::fifo fifo; |
| ASSERT_OK(manager.StartServer(&client, &fifo)); |
| |
| const size_t vmo_size = 8192; |
| zx::vmo vmo; |
| ASSERT_OK(zx::vmo::create(vmo_size, 0, &vmo)); |
| ASSERT_OK(FillVMO(zx::unowned_vmo(vmo), vmo_size)); |
| |
| vmoid_t vmoid; |
| ASSERT_OK(manager.AttachVmo(std::move(vmo), &vmoid)); |
| |
| block_fifo_request_t reqs[2] = { |
| { |
| .opcode = BLOCK_OP_READ | BLOCK_GROUP_ITEM, |
| .reqid = 0x101, |
| .group = 0, |
| .vmoid = vmoid, |
| .length = 4, |
| .vmo_offset = 0, |
| .dev_offset = 0, |
| }, |
| { |
| .opcode = BLOCK_OP_READ | BLOCK_GROUP_ITEM | BLOCK_GROUP_LAST, |
| .reqid = 0x101, |
| .group = 0, |
| .vmoid = vmoid, |
| .length = 1, |
| .vmo_offset = 0, |
| .dev_offset = 0, |
| }, |
| }; |
| |
| // Write requests. |
| size_t actual_count = 0; |
| ASSERT_OK(fifo.write(sizeof(reqs[0]), reqs, 2, &actual_count)); |
| ASSERT_EQ(actual_count, 2); |
| |
| // Wait for first response. |
| zx_signals_t observed; |
| ASSERT_OK(zx_object_wait_one(fifo.get(), ZX_FIFO_READABLE, ZX_TIME_INFINITE, &observed)); |
| |
| block_fifo_response_t res; |
| ASSERT_OK(fifo.read(sizeof(res), &res, 1, &actual_count)); |
| ASSERT_EQ(actual_count, 1); |
| ASSERT_OK(res.status); |
| ASSERT_EQ(reqs[0].reqid, res.reqid); |
| ASSERT_EQ(res.count, 2); |
| ASSERT_EQ(res.group, 0); |
| } |
| |
| } // namespace |