blob: fc5d53b311a7072d15a9314bceb6e0973fa4e862 [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 <lib/driver/fake-bti/cpp/fake-bti.h>
#include <lib/driver/fake-platform-device/cpp/fake-pdev.h>
#include <lib/driver/fake-resource/cpp/fake-resource.h>
#include <lib/driver/platform-device/cpp/pdev.h>
#if FUCHSIA_API_LEVEL_AT_LEAST(HEAD)
namespace fdf_fake {
zx::result<fuchsia_hardware_platform_device::wire::Mmio> FakePDev::GetMmioById(
uint32_t index, fidl::AnyArena& arena) {
auto mmio = config_.mmios.find(index);
if (mmio == config_.mmios.end()) {
return zx::error(ZX_ERR_NOT_FOUND);
}
auto builder = fuchsia_hardware_platform_device::wire::Mmio::Builder(arena);
if (auto* mmio_info = std::get_if<fdf::PDev::MmioInfo>(&mmio->second); mmio_info) {
builder.offset(mmio_info->offset).size(mmio_info->size);
zx::vmo dup;
mmio_info->vmo.duplicate(ZX_RIGHT_SAME_RIGHTS, &dup);
builder.vmo(std::move(dup));
} else {
auto& mmio_buffer = std::get<fdf::MmioBuffer>(mmio->second);
builder.offset(reinterpret_cast<size_t>(&mmio_buffer));
}
return zx::ok(builder.Build());
}
void FakePDev::GetMmioById(GetMmioByIdRequestView request, GetMmioByIdCompleter::Sync& completer) {
fidl::Arena arena;
zx::result mmio = GetMmioById(request->index, arena);
if (mmio.is_error()) {
completer.ReplyError(mmio.status_value());
return;
}
completer.ReplySuccess(std::move(mmio.value()));
}
void FakePDev::GetMmioByName(GetMmioByNameRequestView request,
GetMmioByNameCompleter::Sync& completer) {
auto index = config_.mmio_names.find(request->name.get());
if (index == config_.mmio_names.end()) {
completer.ReplyError(ZX_ERR_NOT_FOUND);
return;
}
fidl::Arena arena;
zx::result mmio = GetMmioById(index->second, arena);
if (mmio.is_error()) {
completer.ReplyError(mmio.status_value());
return;
}
completer.ReplySuccess(std::move(mmio.value()));
}
zx::result<zx::interrupt> FakePDev::GetInterruptById(uint32_t index) {
auto itr = config_.irqs.find(index);
if (itr == config_.irqs.end()) {
if (!config_.use_fake_irq) {
return zx::error(ZX_ERR_NOT_FOUND);
}
zx::interrupt irq;
if (zx_status_t status = zx::interrupt::create(zx::resource(), 0, ZX_INTERRUPT_VIRTUAL, &irq);
status != ZX_OK) {
return zx::error(status);
}
return zx::ok(std::move(irq));
}
zx::interrupt irq;
itr->second.duplicate(ZX_RIGHT_SAME_RIGHTS, &irq);
return zx::ok(std::move(irq));
}
zx::result<zx::bti> FakePDev::GetBtiById(uint32_t index) {
auto itr = config_.btis.find(index);
if (itr == config_.btis.end()) {
if (!config_.use_fake_bti) {
return zx::error(ZX_ERR_NOT_FOUND);
}
return fake_bti::CreateFakeBti();
}
zx::bti bti;
itr->second.duplicate(ZX_RIGHT_SAME_RIGHTS, &bti);
return zx::ok(std::move(bti));
}
void FakePDev::GetInterruptById(GetInterruptByIdRequestView request,
GetInterruptByIdCompleter::Sync& completer) {
zx::result irq = GetInterruptById(request->index);
if (irq.is_error()) {
completer.ReplyError(irq.status_value());
return;
}
completer.ReplySuccess(std::move(irq.value()));
}
void FakePDev::GetInterruptByName(GetInterruptByNameRequestView request,
GetInterruptByNameCompleter::Sync& completer) {
auto index = config_.irq_names.find(request->name.get());
if (index == config_.irq_names.end()) {
completer.ReplyError(ZX_ERR_NOT_FOUND);
return;
}
zx::result irq = GetInterruptById(index->second);
if (irq.is_error()) {
completer.ReplyError(irq.status_value());
return;
}
completer.ReplySuccess(std::move(irq.value()));
}
void FakePDev::GetBtiById(GetBtiByIdRequestView request, GetBtiByIdCompleter::Sync& completer) {
zx::result bti = GetBtiById(request->index);
if (bti.is_error()) {
completer.ReplyError(bti.status_value());
return;
}
completer.ReplySuccess(std::move(bti.value()));
}
void FakePDev::GetBtiByName(GetBtiByNameRequestView request,
GetBtiByNameCompleter::Sync& completer) {
auto index = config_.bti_names.find(request->name.get());
if (index == config_.bti_names.end()) {
completer.ReplyError(ZX_ERR_NOT_FOUND);
return;
}
zx::result bti = GetBtiById(index->second);
if (bti.is_error()) {
completer.ReplyError(bti.status_value());
return;
}
completer.ReplySuccess(std::move(bti.value()));
}
void FakePDev::GetSmcById(GetSmcByIdRequestView request, GetSmcByIdCompleter::Sync& completer) {
zx::resource smc;
auto itr = config_.smcs.find(request->index);
if (itr == config_.smcs.end()) {
if (!config_.use_fake_smc) {
completer.ReplyError(ZX_ERR_NOT_FOUND);
return;
}
zx_status_t status = fake_root_resource_create(smc.reset_and_get_address());
if (status != ZX_OK) {
completer.ReplyError(status);
return;
}
} else {
itr->second.duplicate(ZX_RIGHT_SAME_RIGHTS, &smc);
}
completer.ReplySuccess(std::move(smc));
}
void FakePDev::GetSmcByName(GetSmcByNameRequestView request,
GetSmcByNameCompleter::Sync& completer) {
completer.ReplyError(ZX_ERR_NOT_SUPPORTED);
}
void FakePDev::GetNodeDeviceInfo(GetNodeDeviceInfoCompleter::Sync& completer) {
if (!config_.device_info.has_value()) {
completer.ReplyError(ZX_ERR_NOT_SUPPORTED);
return;
}
fdf::PDev::DeviceInfo& info = config_.device_info.value();
fidl::Arena arena;
completer.ReplySuccess(fuchsia_hardware_platform_device::wire::NodeDeviceInfo::Builder(arena)
.vid(info.vid)
.pid(info.pid)
.did(info.did)
.mmio_count(info.mmio_count)
.irq_count(info.irq_count)
.bti_count(info.bti_count)
.smc_count(info.smc_count)
.metadata_count(info.metadata_count)
.name(info.name)
.Build());
}
void FakePDev::GetBoardInfo(GetBoardInfoCompleter::Sync& completer) {
if (!config_.board_info.has_value()) {
completer.ReplyError(ZX_ERR_NOT_SUPPORTED);
return;
}
fdf::PDev::BoardInfo& info = config_.board_info.value();
fidl::Arena arena;
completer.ReplySuccess(fuchsia_hardware_platform_device::wire::BoardInfo::Builder(arena)
.vid(info.vid)
.pid(info.pid)
.board_name(info.board_name)
.board_revision(info.board_revision)
.Build());
}
void FakePDev::GetPowerConfiguration(GetPowerConfigurationCompleter::Sync& completer) {
static fidl::Arena arena;
fidl::VectorView<fuchsia_hardware_power::wire::PowerElementConfiguration> value;
value.Allocate(arena, config_.power_elements.size());
for (size_t i = 0; i < config_.power_elements.size(); i++) {
value[i] = fidl::ToWire(arena, config_.power_elements[i]);
}
completer.ReplySuccess(value);
}
void FakePDev::GetMetadata(GetMetadataRequestView request, GetMetadataCompleter::Sync& completer) {
if (auto metadata = metadata_.find(request->id.get()); metadata != metadata_.end()) {
completer.ReplySuccess(fidl::VectorView<uint8_t>::FromExternal(metadata->second));
return;
}
completer.ReplyError(ZX_ERR_NOT_FOUND);
}
void FakePDev::handle_unknown_method(
fidl::UnknownMethodMetadata<fuchsia_hardware_platform_device::Device> metadata,
fidl::UnknownMethodCompleter::Sync& completer) {}
} // namespace fdf_fake
zx::result<fdf::MmioBuffer> fdf::internal::PDevMakeMmioBufferWeak(fdf::PDev::MmioInfo& pdev_mmio,
uint32_t cache_policy) {
if (pdev_mmio.vmo.is_valid()) {
return MmioBuffer::Create(pdev_mmio.offset, pdev_mmio.size, std::move(pdev_mmio.vmo),
cache_policy);
}
auto* mmio_buffer = reinterpret_cast<MmioBuffer*>(pdev_mmio.offset);
return zx::ok(std::move(*mmio_buffer));
}
#endif // FUCHSIA_API_LEVEL_AT_LEAST(HEAD)