blob: a51652e6de5a88fd921b09e5212f35009db0b57e [file] [log] [blame]
// Copyright 2018 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.
#ifndef SRC_VIRTUALIZATION_BIN_VMM_DEVICE_DEVICE_BASE_H_
#define SRC_VIRTUALIZATION_BIN_VMM_DEVICE_DEVICE_BASE_H_
#include <fuchsia/virtualization/hardware/cpp/fidl.h>
#include <lib/async/cpp/trap.h>
#include <lib/async/default.h>
#include <lib/fidl/cpp/binding_set.h>
#include <lib/fsl/handles/object_info.h>
#include <lib/sys/cpp/component_context.h>
#include <lib/trace/event.h>
#include <lib/zx/event.h>
#include "src/virtualization/bin/vmm/device/config.h"
#include "src/virtualization/bin/vmm/device/phys_mem.h"
// DeviceBase exposes a single fidl interface for a given device. For cases where the device only
// implements a single interface, the fidl interface can be derived from the class declaration
// itself. In cases where the class implements multiple interfaces, the desired interface must be
// explicitly specified.
template <typename DeviceClass, typename Interface = DeviceClass>
class DeviceBase {
private:
// Converts a device trap into queue notifications.
void OnQueueNotify(async_dispatcher_t* dispatcher, async::GuestBellTrapBase* trap,
zx_status_t status, const zx_packet_guest_bell_t* bell) {
FXL_CHECK(status == ZX_OK) << "Device trap failed " << status;
uint16_t queue = queue_from(trap_addr_, bell->addr);
static_cast<DeviceClass*>(this)->NotifyQueue(queue);
}
protected:
fidl::BindingSet<Interface> bindings_;
zx_gpaddr_t trap_addr_;
zx::event event_;
zx_koid_t event_koid_;
PhysMem phys_mem_;
async::GuestBellTrapMethod<DeviceBase, &DeviceBase::OnQueueNotify> trap_{this};
explicit DeviceBase(sys::ComponentContext* context) {
context->outgoing()->AddPublicService(bindings_.GetHandler(static_cast<DeviceClass*>(this)));
}
// Prepares a device to start.
void PrepStart(fuchsia::virtualization::hardware::StartInfo start_info) {
FXL_CHECK(!event_) << "Device has already been started";
event_ = std::move(start_info.event);
event_koid_ = fsl::GetKoid(event_.get());
zx_status_t status = phys_mem_.Init(std::move(start_info.vmo));
FXL_CHECK(status == ZX_OK) << "Failed to init guest physical memory " << status;
if (start_info.guest) {
trap_addr_ = start_info.trap.addr;
status = trap_.SetTrap(async_get_default_dispatcher(), start_info.guest, start_info.trap.addr,
start_info.trap.size);
FXL_CHECK(status == ZX_OK) << "Failed to set trap " << status;
}
}
// Signals an interrupt for the device.
zx_status_t Interrupt(uint8_t actions) {
TRACE_FLOW_BEGIN("machina", "device:interrupt", event_koid_);
return event_.signal(0, static_cast<zx_signals_t>(actions) << kDeviceInterruptShift);
}
};
#endif // SRC_VIRTUALIZATION_BIN_VMM_DEVICE_DEVICE_BASE_H_