blob: 5a0fbf2ef859c14ebc4a91c884ac6db5043640cd [file] [log] [blame]
// Copyright 2017 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 GARNET_LIB_MACHINA_VCPU_H_
#define GARNET_LIB_MACHINA_VCPU_H_
#include <threads.h>
#include <fbl/mutex.h>
#include <fbl/unique_ptr.h>
#include <zircon/compiler.h>
#include <zircon/syscalls/port.h>
#include <zircon/types.h>
typedef struct zx_vcpu_state zx_vcpu_state_t;
namespace machina {
class Guest;
class Vcpu {
public:
Vcpu() { cnd_init(&state_cnd_); }
~Vcpu() { cnd_destroy(&state_cnd_); }
// Create a new VCPU for a given guest.
//
// Upon successful completion the VCPU will be in the state
// |WAITING_TO_START|.
zx_status_t Create(Guest* guest, zx_vaddr_t entry, uint64_t id);
// TODO(alexlegg): Remove this once the above is used in Garnet.
zx_status_t Create(Guest* guest, zx_vaddr_t entry) {
return Create(guest, entry, 0);
}
static Vcpu* GetCurrent();
// Begins VCPU execution.
//
// If |initial_vcpu_state| is non-null the given state will be written to
// the VCPU before execution begins.
zx_status_t Start(zx_vcpu_state_t* initial_vcpu_state);
// Waits for the VCPU to transition to a terminal state.
zx_status_t Join();
// TODO(tjdetwiler): These should be made private as they're not thread-
// safe.
zx_status_t Interrupt(uint32_t vector);
zx_status_t ReadState(uint32_t kind, void* buffer, uint32_t len) const;
zx_status_t WriteState(uint32_t kind, const void* buffer, uint32_t len);
uint64_t id() const { return id_; }
private:
enum class State {
// No kernel objects have been created.
UNINITIALIZED = 0,
// A handle to the VCPU has been obtained but the thread has not yet
// begun execution.
WAITING_TO_START = 1,
// The VCPU is in the process of starting execution.
STARTING = 2,
// The VCPU is running in the guest context. VCPU packets are being
// processed.
STARTED = 3,
// The VCPU has been terminated gracefully.
TERMINATED = 4,
// A failure was encountered while creating the VCPU.
ERROR_FAILED_TO_CREATE = 5,
// A failure was encountered while starting the VCPU.
ERROR_FAILED_TO_START = 6,
// A failure was encountered while resuming the VCPU.
ERROR_FAILED_TO_RESUME = 7,
// A terminal failure was encountered while handling a guest packet.
ERROR_ABORTED = 7,
};
// Entry point for the VCPU on the dedicated VCPU thread. This thread will
// handle taking the VCPU through the entire VCPU life-cycle and handle any
// interaction with the VCPU syscalls.
struct ThreadEntryArgs;
zx_status_t ThreadEntry(const ThreadEntryArgs* args);
// Resume the VCPU and handle packets in a loop.
zx_status_t Loop();
// Sets the VCPU state and notifies any waiters.
void SetState(State new_state);
void SetStateLocked(State new_state) __TA_REQUIRES(mutex_);
// Block until |state_| != |initial_state|.
void WaitForStateChangeLocked(State initial_state) __TA_REQUIRES(mutex_);
// Guest packet handlers
zx_status_t HandlePacket(const zx_port_packet_t& packet);
zx_status_t HandleMem(const zx_packet_guest_mem_t& mem, uint64_t trap_key);
#if __x86_64__
zx_status_t HandleInput(const zx_packet_guest_io_t& io, uint64_t trap_key);
zx_status_t HandleOutput(const zx_packet_guest_io_t& io, uint64_t trap_key);
zx_status_t HandleIo(const zx_packet_guest_io_t& io, uint64_t trap_key);
#endif
zx_status_t HandleVcpu(const zx_packet_guest_vcpu_t& packet,
uint64_t trap_key);
Guest* guest_;
uint64_t id_;
thrd_t thread_;
zx_handle_t vcpu_ = ZX_HANDLE_INVALID;
State state_ __TA_GUARDED(mutex_) = State::UNINITIALIZED;
cnd_t state_cnd_;
fbl::Mutex mutex_;
zx_vcpu_state_t* initial_vcpu_state_ __TA_GUARDED(mutex_);
};
} // namespace machina
#endif // GARNET_LIB_MACHINA_VCPU_H_