blob: 6157fcd6d305e0c3d8a6fd71566dbc826a8026e7 [file] [log] [blame]
// Copyright 2022 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 "sdmmc-rpmb-device.h"
#include <lib/fidl-async/cpp/bind.h>
#include "sdmmc-block-device.h"
#include "sdmmc-types.h"
namespace sdmmc {
zx_status_t RpmbDevice::Create(zx_device_t* parent, SdmmcBlockDevice* sdmmc,
const std::array<uint8_t, SDMMC_CID_SIZE>& cid,
const std::array<uint8_t, MMC_EXT_CSD_SIZE>& ext_csd) {
auto device = std::make_unique<RpmbDevice>(parent, sdmmc, cid, ext_csd);
if (auto status = device->loop_.StartThread("sdmmc-rpmb-thread"); status != ZX_OK) {
zxlogf(ERROR, "failed to start RPMB thread: %d", status);
return status;
}
device->outgoing_.emplace(device->loop_.dispatcher());
device->outgoing_->svc_dir()->AddEntry(
fidl::DiscoverableProtocolName<fuchsia_hardware_rpmb::Rpmb>,
fbl::MakeRefCounted<fs::Service>(
[device = device.get()](fidl::ServerEnd<fuchsia_hardware_rpmb::Rpmb> request) mutable {
auto status = fidl::BindSingleInFlightOnly(device->loop_.dispatcher(),
std::move(request), device);
if (status != ZX_OK) {
zxlogf(ERROR, "failed to bind channel: %d", status);
}
return status;
}));
auto endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
if (endpoints.is_error()) {
return endpoints.status_value();
}
auto status = device->outgoing_->Serve(std::move(endpoints->server));
if (status != ZX_OK) {
zxlogf(ERROR, "Failed to service the outoing directory");
return status;
}
std::array offers = {
fidl::DiscoverableProtocolName<fuchsia_hardware_rpmb::Rpmb>,
};
status = device->DdkAdd(ddk::DeviceAddArgs("rpmb")
.set_flags(DEVICE_ADD_MUST_ISOLATE)
.set_fidl_protocol_offers(offers)
.set_outgoing_dir(endpoints->client.TakeChannel()));
if (status != ZX_OK) {
zxlogf(ERROR, "failed to add RPMB partition device: %d", status);
return status;
}
__UNUSED auto* dummy1 = device.release();
return ZX_OK;
}
void RpmbDevice::GetDeviceInfo(GetDeviceInfoRequestView request,
GetDeviceInfoCompleter::Sync& completer) {
using DeviceInfo = fuchsia_hardware_rpmb::wire::DeviceInfo;
using EmmcDeviceInfo = fuchsia_hardware_rpmb::wire::EmmcDeviceInfo;
EmmcDeviceInfo emmc_info = {};
memcpy(emmc_info.cid.data(), cid_.data(), cid_.size() * sizeof(cid_[0]));
emmc_info.rpmb_size = rpmb_size_;
emmc_info.reliable_write_sector_count = reliable_write_sector_count_;
auto emmc_info_ptr = fidl::ObjectView<EmmcDeviceInfo>::FromExternal(&emmc_info);
completer.ToAsync().Reply(DeviceInfo::WithEmmcInfo(emmc_info_ptr));
}
void RpmbDevice::Request(RequestRequestView request, RequestCompleter::Sync& completer) {
RpmbRequestInfo info = {
.tx_frames = std::move(request->request.tx_frames),
.completer = completer.ToAsync(),
};
if (request->request.rx_frames) {
info.rx_frames = {
.vmo = std::move(request->request.rx_frames->vmo),
.offset = request->request.rx_frames->offset,
.size = request->request.rx_frames->size,
};
}
sdmmc_parent_->RpmbQueue(std::move(info));
}
} // namespace sdmmc