blob: 69e8dd128123c1e4b9d5c2eea0ab8e9dbd0d164a [file] [log] [blame]
// Copyright 2024 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-gpu-display/imported-image.h"
#include <lib/driver/logging/cpp/logger.h>
#include <lib/zx/bti.h>
#include <lib/zx/pmt.h>
#include <lib/zx/result.h>
#include <lib/zx/vmo.h>
#include <zircon/assert.h>
#include <zircon/errors.h>
#include <zircon/syscalls.h>
#include <zircon/types.h>
#include <cstddef>
#include <cstdint>
#include <limits>
#include <utility>
#include "src/graphics/lib/virtio/virtio-abi.h"
namespace virtio_display {
// static
zx::result<ImportedImage> ImportedImage::Create(const zx::bti& bti, zx::vmo& image_vmo,
uint64_t image_vmo_offset, size_t image_size,
virtio_abi::ResourceFormat resource_format,
uint32_t stride) {
ZX_DEBUG_ASSERT(bti.is_valid());
ZX_DEBUG_ASSERT(image_vmo.is_valid());
ZX_DEBUG_ASSERT(image_vmo_offset % zx_system_get_page_size() == 0);
ZX_DEBUG_ASSERT(image_size > 0);
// zx_bti_pin() requires an integer number of pages.
const size_t pinned_memory_size = ImportedImage::RoundedUpImageSize(image_size);
zx::pmt pinned_memory_token;
zx_paddr_t image_physical_address;
zx_status_t pin_status = bti.pin(ZX_BTI_PERM_READ | ZX_BTI_CONTIGUOUS, image_vmo,
image_vmo_offset, pinned_memory_size, &image_physical_address,
/*addrs_count=*/1, &pinned_memory_token);
if (pin_status != ZX_OK) {
fdf::error("Failed to pin image VMO: {}", zx::make_result(pin_status));
return zx::error(pin_status);
}
return zx::ok(ImportedImage(image_physical_address, std::move(pinned_memory_token),
virtio_abi::kInvalidResourceId, resource_format, stride));
}
// static
ImportedImage ImportedImage::CreateEmpty() { return ImportedImage(); }
ImportedImage::ImportedImage() = default;
ImportedImage::ImportedImage(zx_paddr_t physical_address, zx::pmt pinned_memory_token,
uint32_t virtio_resource_id,
virtio_abi::ResourceFormat resource_format, uint32_t stride)
: physical_address_(physical_address),
pinned_memory_token_(std::move(pinned_memory_token)),
virtio_resource_id_(virtio_resource_id),
resource_format_(resource_format),
stride_(stride) {
ZX_DEBUG_ASSERT(pinned_memory_token_.is_valid());
}
ImportedImage::~ImportedImage() {
if (!pinned_memory_token_.is_valid()) {
return;
}
zx_status_t unpin_status = pinned_memory_token_.unpin();
if (unpin_status != ZX_OK) {
fdf::warn("Failed to unpin image memory: {}", zx::make_result(unpin_status));
}
}
// static
size_t ImportedImage::RoundedUpImageSize(size_t original_image_size) {
const uint32_t page_size = zx_system_get_page_size();
ZX_DEBUG_ASSERT(page_size > 0);
ZX_DEBUG_ASSERT_MSG((page_size & (page_size - 1)) == 0, "Page size must be a power of two");
ZX_DEBUG_ASSERT_MSG(size_t{page_size} <= std::numeric_limits<size_t>::max(),
"size_t can't hold a single page");
ZX_DEBUG_ASSERT_MSG(original_image_size <= std::numeric_limits<size_t>::max() - (page_size - 1),
"Rounding up the image size would overflow size_t");
const size_t page_size_mask = size_t{page_size - 1};
ZX_DEBUG_ASSERT((original_image_size & page_size_mask) == (original_image_size % page_size));
ZX_DEBUG_ASSERT(((original_image_size + page_size_mask) & ~page_size_mask) ==
((original_image_size + page_size - 1) / page_size) * page_size);
return (original_image_size + page_size_mask) & (~page_size_mask);
}
} // namespace virtio_display