blob: fcc5567e2b96b8f799eecf86e072368422cfea5f [file] [log] [blame]
// Copyright 2023 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 "src/graphics/display/drivers/virtio-guest/v2/gpu-device.h"
#include <lib/driver/logging/cpp/logger.h>
#include <lib/stdcompat/span.h>
#include <lib/zx/pmt.h>
#include <lib/zx/vmo.h>
#include <zircon/assert.h>
#include <zircon/compiler.h>
#include <zircon/status.h>
#include <zircon/types.h>
#include <memory>
#include <utility>
#include <fbl/alloc_checker.h>
#include <fbl/auto_lock.h>
namespace virtio_display {
GpuDevice::GpuDevice(zx::vmo virtio_queue_buffer_pool_vmo, zx::pmt virtio_queue_buffer_pool_pin,
zx_paddr_t virtio_queue_buffer_pool_physical_address,
cpp20::span<uint8_t> virtio_queue_buffer_pool)
: virtio_queue_buffer_pool_vmo_(std::move(virtio_queue_buffer_pool_vmo)),
virtio_queue_buffer_pool_pin_(std::move(virtio_queue_buffer_pool_pin)),
virtio_queue_buffer_pool_(virtio_queue_buffer_pool) {}
GpuDevice::~GpuDevice() {
if (!virtio_queue_buffer_pool_.empty()) {
zx_vaddr_t virtio_queue_buffer_pool_begin =
reinterpret_cast<zx_vaddr_t>(virtio_queue_buffer_pool_.data());
zx::vmar::root_self()->unmap(virtio_queue_buffer_pool_begin, virtio_queue_buffer_pool_.size());
}
}
// static
zx::result<std::unique_ptr<GpuDevice>> GpuDevice::Create(
fidl::ClientEnd<fuchsia_hardware_pci::Device> client_end) {
zx::vmo virtio_queue_buffer_pool_vmo;
zx_status_t status =
zx::vmo::create(zx_system_get_page_size(), /*options=*/0, &virtio_queue_buffer_pool_vmo);
if (status != ZX_OK) {
FDF_LOG(ERROR, "Failed to allocate virtqueue buffers VMO: %s", zx_status_get_string(status));
return zx::error(status);
}
uint64_t virtio_queue_buffer_pool_size;
status = virtio_queue_buffer_pool_vmo.get_size(&virtio_queue_buffer_pool_size);
if (status != ZX_OK) {
FDF_LOG(ERROR, "Failed to get virtqueue buffers VMO size: %s", zx_status_get_string(status));
return zx::error(status);
}
// Commit backing store and get the physical address.
zx_paddr_t virtio_queue_buffer_pool_physical_address = 0;
zx::pmt virtio_queue_buffer_pool_pin;
zx_vaddr_t virtio_queue_buffer_pool_begin;
status = zx::vmar::root_self()->map(
ZX_VM_PERM_READ | ZX_VM_PERM_WRITE, /*vmar_offset=*/0, virtio_queue_buffer_pool_vmo,
/*vmo_offset=*/0, virtio_queue_buffer_pool_size, &virtio_queue_buffer_pool_begin);
if (status != ZX_OK) {
FDF_LOG(ERROR, "Failed to map virtqueue buffers VMO: %s", zx_status_get_string(status));
return zx::error(status);
}
FDF_LOG(INFO,
"Allocated virtqueue buffers at virtual address 0x%016" PRIx64
", physical address 0x%016" PRIx64,
virtio_queue_buffer_pool_begin, virtio_queue_buffer_pool_physical_address);
// NOLINTBEGIN(performance-no-int-to-ptr): Casting from zx_vaddr_t to a
// pointer is unavoidable due to the zx::vmar::map() API.
cpp20::span<uint8_t> virtio_queue_buffer_pool(
reinterpret_cast<uint8_t*>(virtio_queue_buffer_pool_begin), virtio_queue_buffer_pool_size);
// NOLINTEND(performance-no-int-to-ptr)
fbl::AllocChecker alloc_checker;
auto device = fbl::make_unique_checked<GpuDevice>(
&alloc_checker, std::move(virtio_queue_buffer_pool_vmo),
std::move(virtio_queue_buffer_pool_pin), virtio_queue_buffer_pool_physical_address,
virtio_queue_buffer_pool);
if (!alloc_checker.check()) {
FDF_LOG(ERROR, "Failed to allocate memory for GpuDevice");
return zx::error(ZX_ERR_NO_MEMORY);
}
status = device->Init();
if (status != ZX_OK) {
FDF_LOG(ERROR, "Failed to initialize device");
return zx::error(status);
}
return zx::ok(std::move(device));
}
void GpuDevice::IsAvailable(fdf::Arena& arena, IsAvailableCompleter::Sync& completer) {
completer.buffer(arena).Reply();
}
void GpuDevice::handle_unknown_method(
fidl::UnknownMethodMetadata<fuchsia_hardware_display_engine::Engine> metadata,
fidl::UnknownMethodCompleter::Sync& completer) {
FDF_LOG(WARNING, "Received an unknown method with ordinal %lu", metadata.method_ordinal);
}
zx_status_t GpuDevice::Init() { return ZX_OK; }
} // namespace virtio_display