| // 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 "magma.h" |
| |
| #include <sys/mman.h> |
| |
| #include <vector> |
| |
| #include "src/graphics/lib/magma/include/virtio/virtio_magma.h" |
| #include "src/graphics/lib/magma/src/libmagma_linux/virtmagma_util.h" |
| |
| // TODO(MA-623): support an object that is a parent of magma_connection_t |
| // This class is a temporary workaround to support magma APIs that do not |
| // pass in generic objects capable of holding file descriptors, e.g. |
| // magma_duplicate_handle. |
| std::map<uint32_t, virtmagma_handle_t*>& GlobalHandleTable() { |
| static std::map<uint32_t, virtmagma_handle_t*> ht; |
| return ht; |
| } |
| |
| magma_status_t magma_map(magma_connection_t connection, magma_buffer_t buffer, void** addr_out) { |
| *addr_out = nullptr; |
| |
| auto connection_wrapped = virtmagma_connection_t::Get(connection); |
| connection = connection_wrapped->Object(); |
| int32_t file_descriptor = connection_wrapped->Parent().first; |
| int32_t file_descriptor_mmap = connection_wrapped->Parent().second; |
| auto buffer_wrapped = virtmagma_buffer_t::Get(buffer); |
| buffer = buffer_wrapped->Object(); |
| |
| virtio_magma_map_ctrl_t request{}; |
| struct { |
| virtio_magma_map_resp_t virtio_response; |
| size_t size_to_mmap_out; |
| } response{}; |
| request.hdr.type = VIRTIO_MAGMA_CMD_MAP; |
| request.connection = reinterpret_cast<decltype(request.connection)>(connection); |
| request.buffer = reinterpret_cast<decltype(request.buffer)>(buffer); |
| |
| if (!virtmagma_send_command(file_descriptor, &request, sizeof(request), &response, |
| sizeof(response))) { |
| return MAGMA_STATUS_INTERNAL_ERROR; |
| } |
| if (response.virtio_response.hdr.type != VIRTIO_MAGMA_RESP_MAP) { |
| return MAGMA_STATUS_INTERNAL_ERROR; |
| } |
| |
| // The only simple way to construct a new vm_area_struct in the kernel is to reuse |
| // the mmap call path. |
| void* mapped_addr = mmap(nullptr, response.size_to_mmap_out, PROT_READ | PROT_WRITE, MAP_SHARED, |
| file_descriptor_mmap, 0); |
| if (mapped_addr == MAP_FAILED) { |
| return MAGMA_STATUS_INTERNAL_ERROR; |
| } |
| *addr_out = mapped_addr; |
| |
| magma_status_t result_return = |
| static_cast<decltype(result_return)>(response.virtio_response.result_return); |
| return result_return; |
| } |
| |
| magma_status_t magma_map_aligned(magma_connection_t connection, magma_buffer_t buffer, |
| uint64_t alignment, void** addr_out) { |
| *addr_out = nullptr; |
| return MAGMA_STATUS_UNIMPLEMENTED; |
| } |
| |
| magma_status_t magma_map_specific(magma_connection_t connection, magma_buffer_t buffer, |
| uint64_t addr, uint64_t offset, uint64_t length) { |
| return MAGMA_STATUS_UNIMPLEMENTED; |
| } |
| |
| magma_status_t magma_wait_semaphores(const magma_semaphore_t* semaphores, uint32_t count, |
| uint64_t timeout_ms, magma_bool_t wait_all) { |
| if (count == 0) |
| return MAGMA_STATUS_OK; |
| |
| auto semaphore0_wrapped = virtmagma_semaphore_t::Get(semaphores[0]); |
| auto semaphore0_parent_wrapped = virtmagma_connection_t::Get(semaphore0_wrapped->Parent()); |
| int32_t file_descriptor = semaphore0_parent_wrapped->Parent().first; |
| |
| virtio_magma_wait_semaphores_ctrl_t request{}; |
| virtio_magma_wait_semaphores_resp_t response{}; |
| request.hdr.type = VIRTIO_MAGMA_CMD_WAIT_SEMAPHORES; |
| std::vector<magma_semaphore_t> unwrapped_semaphores(count); |
| for (uint32_t i = 0; i < count; ++i) { |
| unwrapped_semaphores[i] = virtmagma_semaphore_t::Get(semaphores[i])->Object(); |
| } |
| request.semaphores = reinterpret_cast<decltype(request.semaphores)>(unwrapped_semaphores.data()); |
| request.count = count; |
| request.timeout_ms = timeout_ms; |
| request.wait_all = wait_all; |
| |
| if (!virtmagma_send_command(file_descriptor, &request, sizeof(request), &response, |
| sizeof(response))) |
| return MAGMA_STATUS_INTERNAL_ERROR; |
| if (response.hdr.type != VIRTIO_MAGMA_RESP_WAIT_SEMAPHORES) |
| return MAGMA_STATUS_INTERNAL_ERROR; |
| |
| magma_status_t result_return = static_cast<decltype(result_return)>(response.result_return); |
| return result_return; |
| } |
| |
| magma_status_t magma_poll(magma_poll_item_t* items, uint32_t count, uint64_t timeout_ns) { |
| return MAGMA_STATUS_UNIMPLEMENTED; |
| } |
| |
| void magma_execute_command_buffer_with_resources(magma_connection_t connection, uint32_t context_id, |
| struct magma_system_command_buffer* command_buffer, |
| struct magma_system_exec_resource* resources, |
| uint64_t* semaphore_ids) { |
| virtmagma_command_buffer virt_command_buffer; |
| virt_command_buffer.command_buffer_size = sizeof(magma_system_command_buffer); |
| virt_command_buffer.command_buffer = |
| reinterpret_cast<decltype(virt_command_buffer.command_buffer)>(command_buffer); |
| virt_command_buffer.resource_size = |
| sizeof(magma_system_exec_resource) * command_buffer->num_resources; |
| virt_command_buffer.resources = |
| reinterpret_cast<decltype(virt_command_buffer.resources)>(resources); |
| virt_command_buffer.semaphore_size = sizeof(uint64_t) * (command_buffer->wait_semaphore_count + |
| command_buffer->signal_semaphore_count); |
| virt_command_buffer.semaphores = |
| reinterpret_cast<decltype(virt_command_buffer.resources)>(semaphore_ids); |
| |
| virtio_magma_execute_command_buffer_with_resources_ctrl request{}; |
| virtio_magma_execute_command_buffer_with_resources_resp response{}; |
| request.hdr.type = VIRTIO_MAGMA_CMD_EXECUTE_COMMAND_BUFFER_WITH_RESOURCES; |
| |
| auto connection_wrapped = virtmagma_connection_t::Get(connection); |
| request.connection = reinterpret_cast<decltype(request.connection)>(connection_wrapped->Object()); |
| |
| request.context_id = context_id; |
| request.command_buffer = reinterpret_cast<decltype(request.command_buffer)>(&virt_command_buffer); |
| |
| int32_t file_descriptor = connection_wrapped->Parent().first; |
| |
| if (!virtmagma_send_command(file_descriptor, &request, sizeof(request), &response, |
| sizeof(response))) { |
| assert(false); |
| } |
| } |
| |
| magma_status_t magma_initialize_tracing(magma_handle_t channel) { |
| return MAGMA_STATUS_UNIMPLEMENTED; |
| } |