| // 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 "msd_img_connection.h" |
| |
| #include "gtest/gtest.h" |
| #include "include/fuchsia_communication.h" |
| #include "msd_img_buffer.h" |
| #include "msd_img_semaphore.h" |
| #include "pvr_bridge.h" |
| |
| namespace |
| { |
| class FakeOwner : public MsdImgConnection::Owner |
| { |
| PVRSRV_DEVICE_NODE* device_node() override { return nullptr; } |
| }; |
| } // namespace |
| |
| |
| class TestMsdImgConnection |
| { |
| public: |
| static void ProcessBuffer() |
| { |
| FakeOwner owner; |
| MsdImgConnection connection(&owner, 1); |
| constexpr uint32_t kBufferSize = 4096; |
| auto payload_buf = MsdImgAbiBuffer(MsdImgBuffer::Create(kBufferSize, "payload")); |
| auto additional_buf = MsdImgAbiBuffer(MsdImgBuffer::Create(kBufferSize, "array")); |
| |
| auto normal_semaphore = MsdImgAbiSemaphore(MsdImgSemaphore::Create()); |
| auto additional_semaphore = MsdImgAbiSemaphore(MsdImgSemaphore::Create()); |
| |
| magma_system_command_buffer command_buffer; |
| |
| msd_buffer_t* buffers[3] = { &payload_buf, &additional_buf }; |
| msd_semaphore_t* semaphore_resources[2] = { &normal_semaphore, &additional_semaphore }; |
| // Exec resource doesn't really matter. |
| magma_system_exec_resource exec_resource[1] = {}; |
| |
| PVRSRV_BRIDGE_PACKAGE package; |
| volatile FuchsiaImgCommandPayload* payload; |
| std::vector<std::shared_ptr<MsdImgSemaphore>> semaphores; |
| |
| // Need at least 1 resource |
| command_buffer.num_resources = 0; |
| EXPECT_EQ(MAGMA_STATUS_INVALID_ARGS, |
| connection.ProcessCommandBuffer(&command_buffer, exec_resource, buffers, semaphore_resources, |
| &package, &payload, &semaphores)); |
| EXPECT_FALSE(connection.payload_buffer_); |
| |
| command_buffer.num_resources = 1; |
| command_buffer.signal_semaphore_count = 1; |
| |
| void* mapped_cpu_addr; |
| ASSERT_TRUE(payload_buf.base_ptr()->platform_buffer()->MapCpu(&mapped_cpu_addr)); |
| |
| auto payload_buf_data = reinterpret_cast<FuchsiaImgCommandPayload*>(mapped_cpu_addr); |
| constexpr uint32_t kValidDataSize = kBufferSize - sizeof(*payload_buf_data); |
| |
| // in_data_size is larger than payload, &semaphores buffer. |
| payload_buf_data->in_data_size = kValidDataSize + 1; |
| EXPECT_EQ(MAGMA_STATUS_INVALID_ARGS, |
| connection.ProcessCommandBuffer(&command_buffer, exec_resource, buffers, semaphore_resources, |
| &package, &payload, &semaphores)); |
| EXPECT_FALSE(connection.payload_buffer_); |
| |
| // in_data_size is way larger than payload, &semaphores buffer and could cause overflow. |
| payload_buf_data->in_data_size = 0xffffffff; |
| EXPECT_EQ(MAGMA_STATUS_INVALID_ARGS, |
| connection.ProcessCommandBuffer(&command_buffer, exec_resource, buffers, semaphore_resources, |
| &package, &payload, &semaphores)); |
| EXPECT_FALSE(connection.payload_buffer_); |
| |
| constexpr uint64_t kThreadId = 0x8765432187654321ul; |
| payload_buf_data->thread_id = kThreadId; |
| payload_buf_data->bridge_group = 1; |
| payload_buf_data->function_id = 2; |
| payload_buf_data->in_data_size = kValidDataSize; |
| payload_buf_data->out_data_size = kValidDataSize; |
| |
| command_buffer.signal_semaphore_count = 0; |
| |
| // Not enough signal semaphores |
| EXPECT_EQ(MAGMA_STATUS_INVALID_ARGS, |
| connection.ProcessCommandBuffer(&command_buffer, exec_resource, buffers, semaphore_resources, |
| &package, &payload, &semaphores)); |
| |
| command_buffer.signal_semaphore_count = 1; |
| EXPECT_EQ(MAGMA_STATUS_OK, |
| connection.ProcessCommandBuffer(&command_buffer, exec_resource, buffers, semaphore_resources, |
| &package, &payload, &semaphores)); |
| |
| EXPECT_EQ(kThreadId, connection.current_client_thread_id_); |
| EXPECT_EQ(1u, package.ui32BridgeID); |
| EXPECT_EQ(2u, package.ui32FunctionID); |
| EXPECT_EQ(sizeof(package), package.ui32Size); |
| EXPECT_EQ(kValidDataSize, package.ui32InBufferSize); |
| EXPECT_EQ(kValidDataSize, package.ui32OutBufferSize); |
| EXPECT_EQ(payload_buf_data + 1, package.pvParamIn); |
| EXPECT_EQ(payload_buf_data + 1, package.pvParamOut); |
| EXPECT_EQ(payload_buf_data, payload); |
| |
| EXPECT_EQ(payload_buf.base_ptr(), connection.payload_buffer_); |
| EXPECT_EQ(nullptr, connection.TakeAdditionalBuffer()); |
| EXPECT_EQ(nullptr, connection.TakeAdditionalSemaphore()); |
| EXPECT_EQ(1u, semaphores.size()); |
| |
| // Unmap to test whether the buffer was mapped persistently. |
| ASSERT_TRUE(payload_buf.base_ptr()->platform_buffer()->UnmapCpu()); |
| connection.payload_buffer_ = nullptr; |
| |
| // 2 resources are given, so the last should be used as the |
| // additional buffer. |
| command_buffer.num_resources = 2; |
| semaphores.resize(0); |
| // Last semaphore should be used as an additional semaphore |
| command_buffer.signal_semaphore_count = 2; |
| EXPECT_EQ(MAGMA_STATUS_OK, |
| connection.ProcessCommandBuffer(&command_buffer, exec_resource, buffers, semaphore_resources, |
| &package, &payload, &semaphores)); |
| EXPECT_EQ(1u, semaphores.size()); |
| EXPECT_EQ(additional_buf.base_ptr(), connection.TakeAdditionalBuffer()); |
| EXPECT_EQ(nullptr, connection.TakeAdditionalBuffer()); |
| EXPECT_EQ(additional_semaphore.base_ptr(), connection.TakeAdditionalSemaphore()); |
| EXPECT_EQ(nullptr, connection.TakeAdditionalSemaphore()); |
| |
| // The parameters should be at the same address because the |
| // buffer has a persistent mapping. |
| EXPECT_EQ(payload_buf_data + 1, package.pvParamIn); |
| |
| connection.CleanupAfterCommand(payload, semaphores, true); |
| EXPECT_EQ(1u, payload->finished_command); |
| EXPECT_FALSE(connection.payload_buffer_); |
| EXPECT_FALSE(connection.additional_buffer_); |
| EXPECT_FALSE(connection.additional_semaphore_); |
| EXPECT_EQ(1u, payload->success); |
| EXPECT_EQ(MAGMA_STATUS_OK, normal_semaphore.base_ptr()->platform_semaphore()->Wait(0u).get()); |
| |
| connection.CleanupAfterCommand(payload, semaphores, false); |
| EXPECT_EQ(0u, payload->success); |
| EXPECT_EQ(MAGMA_STATUS_OK, normal_semaphore.base_ptr()->platform_semaphore()->Wait(0u).get()); |
| } |
| }; |
| |
| TEST(Connection, ProcessBuffer) { TestMsdImgConnection::ProcessBuffer(); } |