blob: 51bdcba2a79a3dda21adf1c931c4a15334dd5665 [file] [log] [blame]
// Copyright 2020 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 <lib/dma-buffer/buffer.h>
#include <lib/zx/vmar.h>
#include <fake-dma-buffer/fake-dma-buffer.h>
class ContiguousBufferImpl : public dma_buffer::ContiguousBuffer {
public:
ContiguousBufferImpl(size_t size, zx::vmo vmo, void* virt, zx_paddr_t phys, zx::pmt pmt)
: size_(size), virt_(virt), phys_(phys), vmo_(std::move(vmo)), pmt_(std::move(pmt)) {}
size_t size() const { return size_; }
void* virt() const { return virt_; }
zx_paddr_t phys() const { return phys_; }
~ContiguousBufferImpl() {
if (vmo_.is_valid()) {
delete reinterpret_cast<ddk_fake::FakePage*>(phys_);
}
}
private:
size_t size_;
void* virt_;
zx_paddr_t phys_;
zx::vmo vmo_;
zx::pmt pmt_;
};
class PagedBufferImpl : public dma_buffer::PagedBuffer {
public:
PagedBufferImpl(size_t size, zx::vmo vmo, void* virt, std::vector<zx_paddr_t> phys, zx::pmt pmt)
: size_(size), virt_(virt), phys_(phys), vmo_(std::move(vmo)), pmt_(std::move(pmt)) {}
size_t size() const override { return size_; }
void* virt() const override { return virt_; }
const zx_paddr_t* phys() const override { return phys_.data(); }
~PagedBufferImpl() override {
if (vmo_.is_valid()) {
static_assert(sizeof(phys_[0]) == sizeof(ddk_fake::FakePage*));
for (auto paddr : phys_) {
delete reinterpret_cast<ddk_fake::FakePage*>(paddr);
}
}
}
private:
size_t size_;
void* virt_;
std::vector<zx_paddr_t> phys_;
zx::vmo vmo_;
zx::pmt pmt_;
};
class BufferFactoryImpl : public dma_buffer::BufferFactory {
zx_status_t CreateContiguous(const zx::bti& bti, size_t size, uint32_t alignment_log2,
std::unique_ptr<dma_buffer::ContiguousBuffer>* out) const override {
if (size > ZX_PAGE_SIZE) {
// TODO(fxbug.dev/45011): We don't currently support contiguous buffers > 1 page.
return ZX_ERR_NOT_SUPPORTED;
}
zx::vmo real_vmo;
zx_status_t status = zx::vmo::create(size, 0, &real_vmo);
if (status != ZX_OK) {
return status;
}
void* virt;
status = zx::vmar::root_self()->map(ZX_VM_PERM_READ | ZX_VM_PERM_WRITE, 0, real_vmo, 0, size,
reinterpret_cast<zx_vaddr_t*>(&virt));
if (status != ZX_OK) {
return status;
}
auto fake = new ddk_fake::FakePage();
fake->alignment_log2 = alignment_log2;
fake->enable_cache = true;
fake->size = size;
status = real_vmo.duplicate(ZX_RIGHT_SAME_RIGHTS, &fake->backing_storage);
if (status != ZX_OK) {
return status;
}
fake->virt = virt;
fake->contiguous = true;
fake->bti = bti.get();
auto buffer = std::make_unique<ContiguousBufferImpl>(size, std::move(real_vmo), virt,
reinterpret_cast<zx_paddr_t>(fake),
zx::pmt(ZX_HANDLE_INVALID));
*out = std::move(buffer);
return ZX_OK;
}
zx_status_t CreatePaged(const zx::bti& bti, size_t size, bool enable_cache,
std::unique_ptr<dma_buffer::PagedBuffer>* out) const override {
zx::vmo real_vmo;
zx_status_t status = zx::vmo::create(size, 0, &real_vmo);
if (status != ZX_OK) {
return status;
}
uint8_t* virt;
status = zx::vmar::root_self()->map(ZX_VM_PERM_READ | ZX_VM_PERM_WRITE, 0, real_vmo, 0, size,
reinterpret_cast<zx_vaddr_t*>(&virt));
if (status != ZX_OK) {
return status;
}
size_t pages = fbl::round_up(size, ZX_PAGE_SIZE) / ZX_PAGE_SIZE;
std::vector<zx_paddr_t> physvec;
physvec.resize(pages);
for (size_t i = 0; i < pages; i++) {
auto phys = new ddk_fake::FakePage();
phys->enable_cache = enable_cache;
phys->size = size;
status = real_vmo.duplicate(ZX_RIGHT_SAME_RIGHTS, &phys->backing_storage);
if (status != ZX_OK) {
return status;
}
phys->virt = virt + (ZX_PAGE_SIZE * i);
phys->bti = bti.get();
phys->contiguous = false;
physvec[i] = reinterpret_cast<zx_paddr_t>(phys);
}
auto buffer = std::make_unique<PagedBufferImpl>(size, std::move(real_vmo), virt,
std::move(physvec), zx::pmt(ZX_HANDLE_INVALID));
*out = std::move(buffer);
return ZX_OK;
}
};
namespace ddk_fake {
void* PhysToVirt(zx_paddr_t phys) { return PhysToVirt<void*>(phys); }
const FakePage& GetPage(zx_paddr_t phys) {
size_t start = fbl::round_down(phys, ZX_PAGE_SIZE);
return *reinterpret_cast<FakePage*>(start);
}
std::unique_ptr<dma_buffer::BufferFactory> CreateBufferFactory() {
return std::make_unique<BufferFactoryImpl>();
}
} // namespace ddk_fake