blob: d202fb5d60dee6f630c1d71092f74baf8424b9d4 [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
#pragma once
#include <arch/x86/interrupts.h>
#include <arch/x86/vmx_state.h>
#include <bitmap/raw-bitmap.h>
#include <bitmap/storage.h>
#include <hypervisor/packet_mux.h>
#include <kernel/event.h>
#include <kernel/spinlock.h>
#include <kernel/timer.h>
#include <zircon/types.h>
#include <fbl/array.h>
#include <fbl/ref_ptr.h>
#include <fbl/unique_ptr.h>
static const uint16_t kNumInterrupts = X86_MAX_INT + 1;
typedef struct vm_page vm_page_t;
class GuestPhysicalAddressSpace;
class VmObject;
struct VmxInfo;
class VmxPage {
public:
VmxPage() = default;
~VmxPage();
DISALLOW_COPY_ASSIGN_AND_MOVE(VmxPage);
status_t Alloc(const VmxInfo& info, uint8_t fill);
paddr_t PhysicalAddress() const;
void* VirtualAddress() const;
template<typename T>
T* VirtualAddress() const {
return static_cast<T*>(VirtualAddress());
}
bool IsAllocated() const { return pa_ != 0; }
private:
paddr_t pa_ = 0;
};
/* Represents a guest within the hypervisor. */
class Guest {
public:
static status_t Create(fbl::RefPtr<VmObject> physmem, fbl::unique_ptr<Guest>* out);
~Guest();
DISALLOW_COPY_ASSIGN_AND_MOVE(Guest);
status_t SetTrap(uint32_t kind, zx_vaddr_t addr, size_t len,
fbl::RefPtr<PortDispatcher> port, uint64_t key);
GuestPhysicalAddressSpace* AddressSpace() const { return gpas_.get(); }
PacketMux& Mux() { return mux_; }
paddr_t ApicAccessAddress() const { return apic_access_page_.PhysicalAddress(); }
paddr_t MsrBitmapsAddress() const { return msr_bitmaps_page_.PhysicalAddress(); }
private:
fbl::unique_ptr<GuestPhysicalAddressSpace> gpas_;
PacketMux mux_;
VmxPage apic_access_page_;
VmxPage msr_bitmaps_page_;
Guest() = default;
};
/* Stores the local APIC state across VM exits. */
struct LocalApicState {
// Timer for APIC timer.
timer_t timer;
// Event for handling block on HLT.
event_t event;
// Lock for the interrupt bitmap.
SpinLock interrupt_lock;
// Bitmap of active interrupts.
bitmap::RawBitmapGeneric<bitmap::FixedStorage<kNumInterrupts>> interrupt_bitmap;
// Virtual local APIC address.
void* apic_addr = nullptr;
};
/* Represents a virtual CPU within a guest. */
class Vcpu {
public:
static status_t Create(zx_vaddr_t ip, zx_vaddr_t cr3, fbl::RefPtr<VmObject> apic_vmo,
paddr_t apic_access_address, paddr_t msr_bitmaps_address,
GuestPhysicalAddressSpace* gpas, PacketMux& mux,
fbl::unique_ptr<Vcpu>* out);
~Vcpu();
DISALLOW_COPY_ASSIGN_AND_MOVE(Vcpu);
status_t Resume(zx_port_packet_t* packet);
status_t Interrupt(uint32_t interrupt);
status_t ReadState(uint32_t kind, void* buffer, uint32_t len) const;
status_t WriteState(uint32_t kind, const void* buffer, uint32_t len);
uint16_t vpid() const { return vpid_; }
private:
const thread_t* thread_;
const uint16_t vpid_;
fbl::RefPtr<VmObject> apic_vmo_;
LocalApicState local_apic_state_;
GuestPhysicalAddressSpace* gpas_;
PacketMux& mux_;
VmxState vmx_state_;
VmxPage host_msr_page_;
VmxPage guest_msr_page_;
VmxPage vmcs_page_;
Vcpu(const thread_t* thread, uint16_t vpid, fbl::RefPtr<VmObject> apic_vmo,
GuestPhysicalAddressSpace* gpas, PacketMux& mux);
};
/* Create a guest. */
status_t arch_guest_create(fbl::RefPtr<VmObject> physmem, fbl::unique_ptr<Guest>* guest);
/* Set a trap within a guest. */
status_t arch_guest_set_trap(Guest* guest, uint32_t kind, zx_vaddr_t addr, size_t len,
fbl::RefPtr<PortDispatcher> port, uint64_t key);
/* Create a VCPU. */
status_t x86_vcpu_create(zx_vaddr_t ip, zx_vaddr_t cr3, fbl::RefPtr<VmObject> apic_vmo,
paddr_t apic_access_address, paddr_t msr_bitmaps_address,
GuestPhysicalAddressSpace* gpas, PacketMux& mux,
fbl::unique_ptr<Vcpu>* out);
/* Resume execution of a VCPU. */
status_t arch_vcpu_resume(Vcpu* vcpu, zx_port_packet_t* packet);
/* Issue an interrupt on a VCPU. */
status_t arch_vcpu_interrupt(Vcpu* vcpu, uint32_t interrupt);
/* Read the register state of a VCPU. */
status_t arch_vcpu_read_state(const Vcpu* vcpu, uint32_t kind, void* buffer, uint32_t len);
/* Write the register state of a VCPU. */
status_t arch_vcpu_write_state(Vcpu* vcpu, uint32_t kind, const void* buffer, uint32_t len);