blob: 1b3ed178d2779fc1cacca57c9f5870282282a2eb [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 <zircon/compiler.h>
#define VS_RESUME 0
#define HS_RIP (VS_RESUME + 8)
#define HS_RBX (HS_RIP + 8)
#define HS_RSP (HS_RBX + 8)
#define HS_RBP (HS_RSP + 8)
#define HS_R12 (HS_RBP + 8)
#define HS_R13 (HS_R12 + 8)
#define HS_R14 (HS_R13 + 8)
#define HS_R15 (HS_R14 + 8)
#define HS_RFLAGS (HS_R15 + 8)
#define GS_RAX (HS_RFLAGS + 16)
#define GS_RCX (GS_RAX + 8)
#define GS_RDX (GS_RCX + 8)
#define GS_RBX (GS_RDX + 8)
#define GS_RBP (GS_RBX + 8)
#define GS_RSI (GS_RBP + 8)
#define GS_RDI (GS_RSI + 8)
#define GS_R8 (GS_RDI + 8)
#define GS_R9 (GS_R8 + 8)
#define GS_R10 (GS_R9 + 8)
#define GS_R11 (GS_R10 + 8)
#define GS_R12 (GS_R11 + 8)
#define GS_R13 (GS_R12 + 8)
#define GS_R14 (GS_R13 + 8)
#define GS_R15 (GS_R14 + 8)
#define GS_CR2 (GS_R15 + 8)
#ifndef ASSEMBLY
#include <sys/types.h>
/* Holds the register state used to restore a host. */
struct HostState {
// Return address.
uint64_t rip;
// Callee-save registers.
uint64_t rbx;
uint64_t rsp;
uint64_t rbp;
uint64_t r12;
uint64_t r13;
uint64_t r14;
uint64_t r15;
// Processor flags.
uint64_t rflags;
// Extended control registers.
uint64_t xcr0;
};
struct GuestState {
// RIP, RSP, and RFLAGS are automatically saved by VMX in the VMCS.
uint64_t rax;
uint64_t rcx;
uint64_t rdx;
uint64_t rbx;
uint64_t rbp;
uint64_t rsi;
uint64_t rdi;
uint64_t r8;
uint64_t r9;
uint64_t r10;
uint64_t r11;
uint64_t r12;
uint64_t r13;
uint64_t r14;
uint64_t r15;
// Control registers.
uint64_t cr2;
// Extended control registers.
uint64_t xcr0;
};
struct VmxState {
bool resume;
HostState host_state;
GuestState guest_state;
};
static_assert(__offsetof(VmxState, resume) == VS_RESUME, "");
static_assert(__offsetof(VmxState, host_state.rip) == HS_RIP, "");
static_assert(__offsetof(VmxState, host_state.rsp) == HS_RSP, "");
static_assert(__offsetof(VmxState, host_state.rbp) == HS_RBP, "");
static_assert(__offsetof(VmxState, host_state.rbx) == HS_RBX, "");
static_assert(__offsetof(VmxState, host_state.r12) == HS_R12, "");
static_assert(__offsetof(VmxState, host_state.r13) == HS_R13, "");
static_assert(__offsetof(VmxState, host_state.r14) == HS_R14, "");
static_assert(__offsetof(VmxState, host_state.r15) == HS_R15, "");
static_assert(__offsetof(VmxState, host_state.rflags) == HS_RFLAGS, "");
static_assert(__offsetof(VmxState, guest_state.rax) == GS_RAX, "");
static_assert(__offsetof(VmxState, guest_state.rbx) == GS_RBX, "");
static_assert(__offsetof(VmxState, guest_state.rcx) == GS_RCX, "");
static_assert(__offsetof(VmxState, guest_state.rdx) == GS_RDX, "");
static_assert(__offsetof(VmxState, guest_state.rdi) == GS_RDI, "");
static_assert(__offsetof(VmxState, guest_state.rsi) == GS_RSI, "");
static_assert(__offsetof(VmxState, guest_state.rbp) == GS_RBP, "");
static_assert(__offsetof(VmxState, guest_state.r8) == GS_R8, "");
static_assert(__offsetof(VmxState, guest_state.r9) == GS_R9, "");
static_assert(__offsetof(VmxState, guest_state.r10) == GS_R10, "");
static_assert(__offsetof(VmxState, guest_state.r11) == GS_R11, "");
static_assert(__offsetof(VmxState, guest_state.r12) == GS_R12, "");
static_assert(__offsetof(VmxState, guest_state.r13) == GS_R13, "");
static_assert(__offsetof(VmxState, guest_state.r14) == GS_R14, "");
static_assert(__offsetof(VmxState, guest_state.r15) == GS_R15, "");
static_assert(__offsetof(VmxState, guest_state.cr2) == GS_CR2, "");
__BEGIN_CDECLS
/* Launch the guest and save the host state.
* If we return 0, we have exited from the guest, otherwise we have failed to
* launch the guest.
*/
status_t vmx_enter(VmxState* vmx_state);
/* Exit from the guest, and load the saved host state.
* This function is never called directly, but is executed on exit from a guest.
* It calls vmx_exit before returning through vmx_enter.
*/
void vmx_exit_entry();
void vmx_exit(VmxState* vmx_state);
__END_CDECLS
#endif // ASSEMBLY