blob: 8f209ad1ddfa65daac7dd5e3824e71f293fabac4 [file] [log] [blame]
// Copyright 2017 The Fuchsia Authors
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT
#include "object/vcpu_dispatcher.h"
#include <lib/counters.h>
#include <zircon/rights.h>
#include <zircon/types.h>
#include <arch/hypervisor.h>
#include <fbl/alloc_checker.h>
#include <ktl/type_traits.h>
#include <object/guest_dispatcher.h>
#include <vm/vm_object.h>
KCOUNTER(dispatcher_vcpu_create_count, "dispatcher.vcpu.create")
KCOUNTER(dispatcher_vcpu_destroy_count, "dispatcher.vcpu.destroy")
namespace {
zx::result<ktl::unique_ptr<Vcpu>> CreateVcpu(Guest& guest, uint32_t guest_options,
zx_vaddr_t entry) {
switch (guest_options) {
case ZX_GUEST_OPT_NORMAL:
return NormalVcpu::Create(static_cast<NormalGuest&>(guest), entry);
default:
return zx::error(ZX_ERR_INVALID_ARGS);
}
}
} // namespace
zx_status_t VcpuDispatcher::Create(fbl::RefPtr<GuestDispatcher> guest_dispatcher, zx_vaddr_t entry,
KernelHandle<VcpuDispatcher>* handle, zx_rights_t* rights) {
auto vcpu = CreateVcpu(guest_dispatcher->guest(), guest_dispatcher->options(), entry);
if (vcpu.is_error()) {
return vcpu.status_value();
}
fbl::AllocChecker ac;
KernelHandle new_handle(
fbl::AdoptRef(new (&ac) VcpuDispatcher(guest_dispatcher, ktl::move(*vcpu))));
if (!ac.check())
return ZX_ERR_NO_MEMORY;
*rights = default_rights();
*handle = ktl::move(new_handle);
return ZX_OK;
}
VcpuDispatcher::VcpuDispatcher(fbl::RefPtr<GuestDispatcher> guest_dispatcher,
ktl::unique_ptr<Vcpu> vcpu)
: guest_dispatcher_(guest_dispatcher), vcpu_(ktl::move(vcpu)) {
kcounter_add(dispatcher_vcpu_create_count, 1);
}
VcpuDispatcher::~VcpuDispatcher() { kcounter_add(dispatcher_vcpu_destroy_count, 1); }
zx_status_t VcpuDispatcher::Enter(zx_port_packet_t& packet) {
canary_.Assert();
return vcpu_->Enter(packet).status_value();
}
void VcpuDispatcher::Kick() {
canary_.Assert();
vcpu_->Kick();
}
zx_status_t VcpuDispatcher::Interrupt(uint32_t vector) {
canary_.Assert();
if (guest_dispatcher_->options() == ZX_GUEST_OPT_NORMAL) {
static_cast<NormalVcpu*>(vcpu_.get())->Interrupt(vector);
return ZX_OK;
}
return ZX_ERR_NOT_SUPPORTED;
}
zx_status_t VcpuDispatcher::ReadState(zx_vcpu_state_t& vcpu_state) const {
canary_.Assert();
return vcpu_->ReadState(vcpu_state).status_value();
}
zx_status_t VcpuDispatcher::WriteState(const zx_vcpu_state_t& vcpu_state) {
canary_.Assert();
return vcpu_->WriteState(vcpu_state).status_value();
}
zx_status_t VcpuDispatcher::WriteState(const zx_vcpu_io_t& io_state) {
canary_.Assert();
if (guest_dispatcher_->options() == ZX_GUEST_OPT_NORMAL) {
return static_cast<NormalVcpu*>(vcpu_.get())->WriteState(io_state).status_value();
}
return ZX_ERR_INVALID_ARGS;
}
void VcpuDispatcher::GetInfo(zx_info_vcpu_t* info) {
canary_.Assert();
vcpu_->GetInfo(info);
}