blob: 8428eebc87d02eabb777af4b6d806e5d272de6e6 [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.
#ifndef SRC_GRAPHICS_LIB_MAGMA_SRC_LIBMAGMA_LINUX_VIRTMAGMA_UTIL_H_
#define SRC_GRAPHICS_LIB_MAGMA_SRC_LIBMAGMA_LINUX_VIRTMAGMA_UTIL_H_
#include <errno.h>
#include <sys/fcntl.h>
#include <sys/ioctl.h>
#include <sys/unistd.h>
#include <map>
#include "src/graphics/lib/magma/src/magma_util/macros.h"
#include "virtmagma.h"
inline bool virtmagma_handshake(int32_t file_descriptor) {
if (fcntl(file_descriptor, F_GETFD) == -1) {
DMESSAGE("Invalid file descriptor: %d\n", errno);
return false;
}
virtmagma_ioctl_args_handshake handshake{};
handshake.handshake_inout = VIRTMAGMA_HANDSHAKE_SEND;
if (ioctl(file_descriptor, VIRTMAGMA_IOCTL_HANDSHAKE, &handshake)) {
DMESSAGE("ioctl(HANDSHAKE) failed: %d\n", errno);
return false;
}
if (handshake.handshake_inout != VIRTMAGMA_HANDSHAKE_RECV) {
DMESSAGE("Handshake failed: 0x%08X\n", handshake.handshake_inout);
return false;
}
uint32_t version_major = 0;
uint32_t version_minor = 0;
uint32_t version_patch = 0;
VIRTMAGMA_GET_VERSION(handshake.version_out, version_major, version_minor, version_patch);
DMESSAGE("Successfully connected to virtio-magma driver (version %d.%d.%d)\n", version_major,
version_minor, version_patch);
return true;
}
// Wrap the pair of file descriptors necessary to interact with the virtmagma driver. The first is
// for the device itself (i.e. /dev/magma0). The second is acquired via an ioctl and is used solely
// for the mmap syscall as part of handling magma_map. Refer to the implementation of magma_map in
// ./magma.cc for details.
inline std::pair<int32_t, int32_t> virtmagma_fd_pair(int32_t file_descriptor) {
virtmagma_ioctl_args_get_mmfd args{};
if (ioctl(file_descriptor, VIRTMAGMA_IOCTL_GET_MMFD, &args)) {
DMESSAGE("ioctl(GET_MMFD) failed: %d\n", errno);
return std::make_pair(-1, -1);
}
return std::make_pair(file_descriptor, args.fd_out);
}
inline bool virtmagma_send_command(int32_t file_descriptor, void* request, size_t request_size,
void* response, size_t response_size) {
virtmagma_ioctl_args_magma_command command{};
command.request_address = (uint64_t)request;
command.request_size = request_size;
command.response_address = (uint64_t)response;
command.response_size = response_size;
if (ioctl(file_descriptor, VIRTMAGMA_IOCTL_MAGMA_COMMAND, &command)) {
DMESSAGE("ioctl(MAGMA_COMMAND) failed: %d\n", errno);
return false;
}
return true;
}
class OwnedFd {
public:
OwnedFd(int fd) : fd_(fd) {}
~OwnedFd() {
if (fd_ >= 0)
close(fd_);
}
OwnedFd(const OwnedFd&) = delete;
OwnedFd(OwnedFd&& other) {
fd_ = other.fd_;
other.fd_ = -1;
}
int fd() const { return fd_; }
private:
int fd_;
};
template <class T, class U, int magic>
class VirtmagmaObject {
public:
static VirtmagmaObject* Create(T object, U parent) {
return new VirtmagmaObject(object, std::move(parent));
}
static VirtmagmaObject* Get(T object) {
auto p = reinterpret_cast<VirtmagmaObject*>(object);
DASSERT(p->magic_ == magic);
return p;
}
T Wrap() { return reinterpret_cast<T>(this); }
T& Object() { return object_; }
U& Parent() { return parent_; }
void Destroy() { delete this; }
private:
VirtmagmaObject(T object, U parent)
: object_{object}, parent_{std::move(parent)}, magic_{magic} {}
T object_;
U parent_;
int magic_;
};
typedef VirtmagmaObject<magma_connection_t, std::pair<int32_t, int32_t>, 0x1111>
virtmagma_connection_t;
typedef VirtmagmaObject<magma_buffer_t, magma_connection_t, 0x2222> virtmagma_buffer_t;
typedef VirtmagmaObject<magma_semaphore_t, magma_connection_t, 0x3333> virtmagma_semaphore_t;
typedef VirtmagmaObject<magma_handle_t, int32_t, 0x4444> virtmagma_handle_t;
typedef VirtmagmaObject<magma_device_t, OwnedFd, 0x5555> virtmagma_device_t;
// 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();
#endif // SRC_GRAPHICS_LIB_MAGMA_SRC_LIBMAGMA_LINUX_VIRTMAGMA_UTIL_H_