svm.c revision 267144
11590Srgrimes/*-
21590Srgrimes * Copyright (c) 2013, Anish Gupta (akgupt3@gmail.com)
31590Srgrimes * All rights reserved.
41590Srgrimes *
51590Srgrimes * Redistribution and use in source and binary forms, with or without
61590Srgrimes * modification, are permitted provided that the following conditions
71590Srgrimes * are met:
81590Srgrimes * 1. Redistributions of source code must retain the above copyright
91590Srgrimes *    notice unmodified, this list of conditions, and the following
101590Srgrimes *    disclaimer.
111590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
121590Srgrimes *    notice, this list of conditions and the following disclaimer in the
131590Srgrimes *    documentation and/or other materials provided with the distribution.
141590Srgrimes *
151590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
161590Srgrimes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
171590Srgrimes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
181590Srgrimes * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
191590Srgrimes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
201590Srgrimes * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
211590Srgrimes * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
221590Srgrimes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
231590Srgrimes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
241590Srgrimes * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
251590Srgrimes */
261590Srgrimes
271590Srgrimes#include <sys/cdefs.h>
281590Srgrimes__FBSDID("$FreeBSD: projects/bhyve_svm/sys/amd64/vmm/amd/svm.c 267144 2014-06-06 02:55:18Z grehan $");
291590Srgrimes
301590Srgrimes#include <sys/param.h>
311590Srgrimes#include <sys/systm.h>
321590Srgrimes#include <sys/smp.h>
331590Srgrimes#include <sys/kernel.h>
341590Srgrimes#include <sys/malloc.h>
351590Srgrimes#include <sys/pcpu.h>
361590Srgrimes#include <sys/proc.h>
371590Srgrimes
381590Srgrimes#include <vm/vm.h>
391590Srgrimes#include <vm/pmap.h>
401590Srgrimes
411590Srgrimes#include <machine/cpufunc.h>
421590Srgrimes#include <machine/psl.h>
431590Srgrimes#include <machine/pmap.h>
441590Srgrimes#include <machine/md_var.h>
451590Srgrimes#include <machine/vmparam.h>
461590Srgrimes#include <machine/specialreg.h>
471590Srgrimes#include <machine/segments.h>
481590Srgrimes#include <machine/vmm.h>
491590Srgrimes#include <machine/vmm_dev.h>
501590Srgrimes#include <machine/vmm_instruction_emul.h>
511590Srgrimes
521590Srgrimes#include <x86/apicreg.h>
531590Srgrimes
541590Srgrimes#include "vmm_lapic.h"
551590Srgrimes#include "vmm_msr.h"
561590Srgrimes#include "vmm_stat.h"
571590Srgrimes#include "vmm_ktr.h"
581590Srgrimes#include "vmm_ioport.h"
591590Srgrimes#include "vlapic.h"
601590Srgrimes#include "vlapic_priv.h"
611590Srgrimes
621590Srgrimes#include "x86.h"
631590Srgrimes#include "vmcb.h"
641590Srgrimes#include "svm.h"
651590Srgrimes#include "svm_softc.h"
661590Srgrimes#include "npt.h"
671590Srgrimes
681590Srgrimes/*
691590Srgrimes * SVM CPUID function 0x8000_000A, edx bit decoding.
701590Srgrimes */
711590Srgrimes#define AMD_CPUID_SVM_NP		BIT(0)  /* Nested paging or RVI */
721590Srgrimes#define AMD_CPUID_SVM_LBR		BIT(1)  /* Last branch virtualization */
731590Srgrimes#define AMD_CPUID_SVM_SVML		BIT(2)  /* SVM lock */
741590Srgrimes#define AMD_CPUID_SVM_NRIP_SAVE		BIT(3)  /* Next RIP is saved */
751590Srgrimes#define AMD_CPUID_SVM_TSC_RATE		BIT(4)  /* TSC rate control. */
761590Srgrimes#define AMD_CPUID_SVM_VMCB_CLEAN	BIT(5)  /* VMCB state caching */
771590Srgrimes#define AMD_CPUID_SVM_ASID_FLUSH	BIT(6)  /* Flush by ASID */
781590Srgrimes#define AMD_CPUID_SVM_DECODE_ASSIST	BIT(7)  /* Decode assist */
791590Srgrimes#define AMD_CPUID_SVM_PAUSE_INC		BIT(10) /* Pause intercept filter. */
801590Srgrimes#define AMD_CPUID_SVM_PAUSE_FTH		BIT(12) /* Pause filter threshold */
811590Srgrimes
821590SrgrimesMALLOC_DEFINE(M_SVM, "svm", "svm");
831590SrgrimesMALLOC_DEFINE(M_SVM_VLAPIC, "svm-vlapic", "svm-vlapic");
841590Srgrimes
851590Srgrimes/* Per-CPU context area. */
861590Srgrimesextern struct pcpu __pcpu[];
871590Srgrimes
881590Srgrimesstatic bool svm_vmexit(struct svm_softc *svm_sc, int vcpu,
891590Srgrimes			struct vm_exit *vmexit);
901590Srgrimesstatic int svm_msr_rw_ok(uint8_t *btmap, uint64_t msr);
911590Srgrimesstatic int svm_msr_rd_ok(uint8_t *btmap, uint64_t msr);
921590Srgrimesstatic int svm_msr_index(uint64_t msr, int *index, int *bit);
931590Srgrimesstatic int svm_getdesc(void *arg, int vcpu, int type, struct seg_desc *desc);
941590Srgrimes
951590Srgrimesstatic uint32_t svm_feature; /* AMD SVM features. */
961590Srgrimes
971590Srgrimes/*
981590Srgrimes * Starting guest ASID, 0 is reserved for host.
991590Srgrimes * Each guest will have its own unique ASID.
1001590Srgrimes */
1011590Srgrimesstatic uint32_t guest_asid = 1;
1021590Srgrimes
1031590Srgrimes/*
1041590Srgrimes * Max ASID processor can support.
1051590Srgrimes * This limit the maximum number of virtual machines that can be created.
1061590Srgrimes */
1071590Srgrimesstatic int max_asid;
1081590Srgrimes
1091590Srgrimes/*
1101590Srgrimes * SVM host state saved area of size 4KB for each core.
1111590Srgrimes */
1121590Srgrimesstatic uint8_t hsave[MAXCPU][PAGE_SIZE] __aligned(PAGE_SIZE);
1131590Srgrimes
1141590Srgrimes/*
1151590Srgrimes * S/w saved host context.
1161590Srgrimes */
1171590Srgrimesstatic struct svm_regctx host_ctx[MAXCPU];
1181590Srgrimes
1191590Srgrimesstatic VMM_STAT_AMD(VCPU_EXITINTINFO, "Valid EXITINTINFO");
1201590Srgrimes
1211590Srgrimes/*
1221590Srgrimes * Common function to enable or disabled SVM for a CPU.
1231590Srgrimes */
1241590Srgrimesstatic int
1251590Srgrimescpu_svm_enable_disable(boolean_t enable)
1261590Srgrimes{
1271590Srgrimes	uint64_t efer_msr;
1281590Srgrimes
1291590Srgrimes	efer_msr = rdmsr(MSR_EFER);
1301590Srgrimes
1311590Srgrimes	if (enable)
1321590Srgrimes		efer_msr |= EFER_SVM;
1331590Srgrimes	else
1341590Srgrimes		efer_msr &= ~EFER_SVM;
1351590Srgrimes
1361590Srgrimes	wrmsr(MSR_EFER, efer_msr);
1371590Srgrimes
1381590Srgrimes	return(0);
1391590Srgrimes}
1401590Srgrimes
1411590Srgrimes/*
1421590Srgrimes * Disable SVM on a CPU.
1431590Srgrimes */
1441590Srgrimesstatic void
1451590Srgrimessvm_disable(void *arg __unused)
1461590Srgrimes{
1471590Srgrimes
1481590Srgrimes	(void)cpu_svm_enable_disable(FALSE);
1491590Srgrimes}
1501590Srgrimes
1511590Srgrimes/*
1521590Srgrimes * Disable SVM for all CPUs.
1531590Srgrimes */
1541590Srgrimesstatic int
1551590Srgrimessvm_cleanup(void)
1561590Srgrimes{
1571590Srgrimes
1581590Srgrimes	smp_rendezvous(NULL, svm_disable, NULL, NULL);
1591590Srgrimes	return (0);
1601590Srgrimes}
1611590Srgrimes
1621590Srgrimes/*
1631590Srgrimes * Check for required BHyVe SVM features in a CPU.
1641590Srgrimes */
1651590Srgrimesstatic int
1661590Srgrimessvm_cpuid_features(void)
1671590Srgrimes{
1681590Srgrimes	u_int regs[4];
1691590Srgrimes
1701590Srgrimes	/* CPUID Fn8000_000A is for SVM */
1711590Srgrimes	do_cpuid(0x8000000A, regs);
1721590Srgrimes	svm_feature = regs[3];
1731590Srgrimes
1741590Srgrimes	printf("SVM rev: 0x%x NASID:0x%x\n", regs[0] & 0xFF, regs[1]);
1751590Srgrimes	max_asid = regs[1];
1761590Srgrimes
1771590Srgrimes	printf("SVM Features:0x%b\n", svm_feature,
1781590Srgrimes		"\020"
1791590Srgrimes		"\001NP"		/* Nested paging */
1801590Srgrimes		"\002LbrVirt"		/* LBR virtualization */
1811590Srgrimes		"\003SVML"		/* SVM lock */
1821590Srgrimes		"\004NRIPS"		/* NRIP save */
1831590Srgrimes		"\005TscRateMsr"	/* MSR based TSC rate control */
1841590Srgrimes		"\006VmcbClean"		/* VMCB clean bits */
1851590Srgrimes		"\007FlushByAsid"	/* Flush by ASID */
1861590Srgrimes		"\010DecodeAssist"	/* Decode assist */
1871590Srgrimes		"\011<b20>"
1881590Srgrimes		"\012<b20>"
1891590Srgrimes		"\013PauseFilter"
1901590Srgrimes		"\014<b20>"
1911590Srgrimes		"\015PauseFilterThreshold"
1921590Srgrimes		"\016AVIC"
1931590Srgrimes		);
1941590Srgrimes
1951590Srgrimes	/* SVM Lock */
1961590Srgrimes	if (!(svm_feature & AMD_CPUID_SVM_SVML)) {
1971590Srgrimes		printf("SVM is disabled by BIOS, please enable in BIOS.\n");
1981590Srgrimes		return (ENXIO);
1991590Srgrimes	}
2001590Srgrimes
2011590Srgrimes	/*
2021590Srgrimes	 * bhyve need RVI to work.
2031590Srgrimes	 */
2041590Srgrimes	if (!(svm_feature & AMD_CPUID_SVM_NP)) {
2051590Srgrimes		printf("Missing Nested paging or RVI SVM support in processor.\n");
2061590Srgrimes		return (EIO);
2071590Srgrimes	}
2081590Srgrimes
2091590Srgrimes	if (svm_feature & AMD_CPUID_SVM_NRIP_SAVE)
2101590Srgrimes		return (0);
2111590Srgrimes
2121590Srgrimes	return (EIO);
2131590Srgrimes}
2141590Srgrimes
2151590Srgrimes/*
2161590Srgrimes * Enable SVM for a CPU.
2171590Srgrimes */
2181590Srgrimesstatic void
2191590Srgrimessvm_enable(void *arg __unused)
2201590Srgrimes{
2211590Srgrimes	uint64_t hsave_pa;
2221590Srgrimes
2231590Srgrimes	(void)cpu_svm_enable_disable(TRUE);
2241590Srgrimes
2251590Srgrimes	hsave_pa = vtophys(hsave[curcpu]);
2261590Srgrimes	wrmsr(MSR_VM_HSAVE_PA, hsave_pa);
2271590Srgrimes
2281590Srgrimes	if (rdmsr(MSR_VM_HSAVE_PA) != hsave_pa) {
2291590Srgrimes		panic("VM_HSAVE_PA is wrong on CPU%d\n", curcpu);
2301590Srgrimes	}
2311590Srgrimes}
2321590Srgrimes
2331590Srgrimes/*
2341590Srgrimes * Check if a processor support SVM.
2351590Srgrimes */
2361590Srgrimesstatic int
2371590Srgrimesis_svm_enabled(void)
2381590Srgrimes{
2391590Srgrimes	uint64_t msr;
2401590Srgrimes
2411590Srgrimes	 /* Section 15.4 Enabling SVM from APM2. */
2421590Srgrimes	if ((amd_feature2 & AMDID2_SVM) == 0) {
2431590Srgrimes		printf("SVM is not supported on this processor.\n");
2441590Srgrimes		return (ENXIO);
2451590Srgrimes	}
2461590Srgrimes
2471590Srgrimes	msr = rdmsr(MSR_VM_CR);
2481590Srgrimes	/* Make sure SVM is not disabled by BIOS. */
2491590Srgrimes	if ((msr & VM_CR_SVMDIS) == 0) {
2501590Srgrimes		return svm_cpuid_features();
2511590Srgrimes	}
2521590Srgrimes
2531590Srgrimes	printf("SVM disabled by Key, consult TPM/BIOS manual.\n");
2541590Srgrimes	return (ENXIO);
2551590Srgrimes}
2561590Srgrimes
2571590Srgrimes/*
2581590Srgrimes * Enable SVM on CPU and initialize nested page table h/w.
2591590Srgrimes */
2601590Srgrimesstatic int
2611590Srgrimessvm_init(int ipinum)
2621590Srgrimes{
2631590Srgrimes	int err;
2641590Srgrimes
2651590Srgrimes	err = is_svm_enabled();
2661590Srgrimes	if (err)
2671590Srgrimes		return (err);
2681590Srgrimes
2691590Srgrimes
2701590Srgrimes	svm_npt_init(ipinum);
2711590Srgrimes
2721590Srgrimes	/* Start SVM on all CPUs */
2731590Srgrimes	smp_rendezvous(NULL, svm_enable, NULL, NULL);
2741590Srgrimes
2751590Srgrimes	return (0);
2761590Srgrimes}
2771590Srgrimes
2781590Srgrimesstatic void
2791590Srgrimessvm_restore(void)
2801590Srgrimes{
2811590Srgrimes	svm_enable(NULL);
2821590Srgrimes}
2831590Srgrimes/*
2841590Srgrimes * Get index and bit position for a MSR in MSR permission
2851590Srgrimes * bitmap. Two bits are used for each MSR, lower bit is
2861590Srgrimes * for read and higher bit is for write.
2871590Srgrimes */
2881590Srgrimesstatic int
2891590Srgrimessvm_msr_index(uint64_t msr, int *index, int *bit)
2901590Srgrimes{
2911590Srgrimes	uint32_t base, off;
2921590Srgrimes
2931590Srgrimes/* Pentium compatible MSRs */
2941590Srgrimes#define MSR_PENTIUM_START 	0
2951590Srgrimes#define MSR_PENTIUM_END 	0x1FFF
2961590Srgrimes/* AMD 6th generation and Intel compatible MSRs */
2971590Srgrimes#define MSR_AMD6TH_START 	0xC0000000UL
2981590Srgrimes#define MSR_AMD6TH_END 		0xC0001FFFUL
2991590Srgrimes/* AMD 7th and 8th generation compatible MSRs */
3001590Srgrimes#define MSR_AMD7TH_START 	0xC0010000UL
3011590Srgrimes#define MSR_AMD7TH_END 		0xC0011FFFUL
3021590Srgrimes
3031590Srgrimes	*index = -1;
3041590Srgrimes	*bit = (msr % 4) * 2;
3051590Srgrimes	base = 0;
3061590Srgrimes
3071590Srgrimes	if (msr >= MSR_PENTIUM_START && msr <= MSR_PENTIUM_END) {
3081590Srgrimes		*index = msr / 4;
3091590Srgrimes		return (0);
3101590Srgrimes	}
3111590Srgrimes
3121590Srgrimes	base += (MSR_PENTIUM_END - MSR_PENTIUM_START + 1);
3131590Srgrimes	if (msr >= MSR_AMD6TH_START && msr <= MSR_AMD6TH_END) {
3141590Srgrimes		off = (msr - MSR_AMD6TH_START);
3151590Srgrimes		*index = (off + base) / 4;
3161590Srgrimes		return (0);
3171590Srgrimes	}
3181590Srgrimes
3191590Srgrimes	base += (MSR_AMD6TH_END - MSR_AMD6TH_START + 1);
3201590Srgrimes	if (msr >= MSR_AMD7TH_START && msr <= MSR_AMD7TH_END) {
3211590Srgrimes		off = (msr - MSR_AMD7TH_START);
3221590Srgrimes		*index = (off + base) / 4;
3231590Srgrimes		return (0);
3241590Srgrimes	}
3251590Srgrimes
3261590Srgrimes	return (EIO);
3271590Srgrimes}
3281590Srgrimes
3291590Srgrimes/*
3301590Srgrimes * Give virtual cpu the complete access to MSR(read & write).
3311590Srgrimes */
3321590Srgrimesstatic int
3331590Srgrimessvm_msr_perm(uint8_t *perm_bitmap, uint64_t msr, bool read, bool write)
3341590Srgrimes{
3351590Srgrimes	int index, bit, err;
3361590Srgrimes
3371590Srgrimes	err = svm_msr_index(msr, &index, &bit);
3381590Srgrimes	if (err) {
3391590Srgrimes		ERR("MSR 0x%lx is not writeable by guest.\n", msr);
3401590Srgrimes		return (err);
3411590Srgrimes	}
3421590Srgrimes
3431590Srgrimes	if (index < 0 || index > (SVM_MSR_BITMAP_SIZE)) {
3441590Srgrimes		ERR("MSR 0x%lx index out of range(%d).\n", msr, index);
3451590Srgrimes		return (EINVAL);
3461590Srgrimes	}
3471590Srgrimes	if (bit < 0 || bit > 8) {
3481590Srgrimes		ERR("MSR 0x%lx bit out of range(%d).\n", msr, bit);
3491590Srgrimes		return (EINVAL);
3501590Srgrimes	}
3511590Srgrimes
3521590Srgrimes	/* Disable intercept for read and write. */
3531590Srgrimes	if (read)
3541590Srgrimes		perm_bitmap[index] &= ~(1UL << bit);
3551590Srgrimes	if (write)
3561590Srgrimes		perm_bitmap[index] &= ~(2UL << bit);
3571590Srgrimes	CTR2(KTR_VMM, "Guest has control:0x%x on SVM:MSR(0x%lx).\n",
3581590Srgrimes		(perm_bitmap[index] >> bit) & 0x3, msr);
3591590Srgrimes
3601590Srgrimes	return (0);
3611590Srgrimes}
3621590Srgrimes
3631590Srgrimesstatic int
3641590Srgrimessvm_msr_rw_ok(uint8_t *perm_bitmap, uint64_t msr)
3651590Srgrimes{
3661590Srgrimes	return svm_msr_perm(perm_bitmap, msr, true, true);
3671590Srgrimes}
3681590Srgrimes
3691590Srgrimesstatic int
3701590Srgrimessvm_msr_rd_ok(uint8_t *perm_bitmap, uint64_t msr)
3711590Srgrimes{
3721590Srgrimes	return svm_msr_perm(perm_bitmap, msr, true, false);
3731590Srgrimes}
3741590Srgrimes/*
3751590Srgrimes * Initialise VCPU.
3761590Srgrimes */
3771590Srgrimesstatic int
3781590Srgrimessvm_init_vcpu(struct svm_vcpu *vcpu, vm_paddr_t iopm_pa, vm_paddr_t msrpm_pa,
3791590Srgrimes		vm_paddr_t pml4_pa, uint8_t asid)
3801590Srgrimes{
3811590Srgrimes
3821590Srgrimes	vcpu->lastcpu = NOCPU;
3831590Srgrimes	vcpu->vmcb_pa = vtophys(&vcpu->vmcb);
3841590Srgrimes
3851590Srgrimes	/*
3861590Srgrimes	 * Initiaise VMCB persistent area of vcpu.
3871590Srgrimes	 * 1. Permission bitmap for MSR and IO space.
3881590Srgrimes	 * 2. Nested paging.
3891590Srgrimes	 * 3. ASID of virtual machine.
3901590Srgrimes	 */
3911590Srgrimes	if (svm_init_vmcb(&vcpu->vmcb, iopm_pa, msrpm_pa, pml4_pa)) {
3921590Srgrimes			return (EIO);
3931590Srgrimes	}
3941590Srgrimes
3951590Srgrimes	return (0);
3961590Srgrimes}
3971590Srgrimes/*
3981590Srgrimes * Initialise a virtual machine.
3991590Srgrimes */
4001590Srgrimesstatic void *
4011590Srgrimessvm_vminit(struct vm *vm, pmap_t pmap)
4021590Srgrimes{
4031590Srgrimes	struct svm_softc *svm_sc;
4041590Srgrimes	vm_paddr_t msrpm_pa, iopm_pa, pml4_pa;
4051590Srgrimes	int i;
4061590Srgrimes
4071590Srgrimes	if (guest_asid >= max_asid) {
4081590Srgrimes		ERR("Host support max ASID:%d, can't create more guests.\n",
4091590Srgrimes			max_asid);
4101590Srgrimes		return (NULL);
4111590Srgrimes	}
4121590Srgrimes
4131590Srgrimes	svm_sc = (struct svm_softc *)malloc(sizeof (struct svm_softc),
4141590Srgrimes			M_SVM, M_WAITOK | M_ZERO);
4151590Srgrimes
4161590Srgrimes	svm_sc->vm = vm;
4171590Srgrimes	svm_sc->svm_feature = svm_feature;
4181590Srgrimes	svm_sc->vcpu_cnt = VM_MAXCPU;
4191590Srgrimes	svm_sc->nptp = (vm_offset_t)vtophys(pmap->pm_pml4);
4201590Srgrimes	/*
4211590Srgrimes	 * Each guest has its own unique ASID.
4221590Srgrimes	 * ASID(Address Space Identifier) is used by TLB entry.
4231590Srgrimes	 */
4241590Srgrimes	svm_sc->asid = guest_asid++;
4251590Srgrimes
4261590Srgrimes	/*
4271590Srgrimes	 * Intercept MSR access to all MSRs except GSBASE, FSBASE,... etc.
4281590Srgrimes	 */
4291590Srgrimes	 memset(svm_sc->msr_bitmap, 0xFF, sizeof(svm_sc->msr_bitmap));
4301590Srgrimes
4311590Srgrimes	/*
4321590Srgrimes	 * Following MSR can be completely controlled by virtual machines
4331590Srgrimes	 * since access to following are translated to access to VMCB.
4341590Srgrimes	 */
4351590Srgrimes	svm_msr_rw_ok(svm_sc->msr_bitmap, MSR_GSBASE);
4361590Srgrimes	svm_msr_rw_ok(svm_sc->msr_bitmap, MSR_FSBASE);
4371590Srgrimes	svm_msr_rw_ok(svm_sc->msr_bitmap, MSR_KGSBASE);
4381590Srgrimes
4391590Srgrimes	svm_msr_rw_ok(svm_sc->msr_bitmap, MSR_STAR);
4401590Srgrimes	svm_msr_rw_ok(svm_sc->msr_bitmap, MSR_LSTAR);
4411590Srgrimes	svm_msr_rw_ok(svm_sc->msr_bitmap, MSR_CSTAR);
4421590Srgrimes	svm_msr_rw_ok(svm_sc->msr_bitmap, MSR_SF_MASK);
4431590Srgrimes	svm_msr_rw_ok(svm_sc->msr_bitmap, MSR_SYSENTER_CS_MSR);
4441590Srgrimes	svm_msr_rw_ok(svm_sc->msr_bitmap, MSR_SYSENTER_ESP_MSR);
4451590Srgrimes	svm_msr_rw_ok(svm_sc->msr_bitmap, MSR_SYSENTER_EIP_MSR);
4461590Srgrimes
4471590Srgrimes	/* For Nested Paging/RVI only. */
4481590Srgrimes	svm_msr_rw_ok(svm_sc->msr_bitmap, MSR_PAT);
4491590Srgrimes
4501590Srgrimes	 /* Intercept access to all I/O ports. */
4511590Srgrimes	memset(svm_sc->iopm_bitmap, 0xFF, sizeof(svm_sc->iopm_bitmap));
4521590Srgrimes
4531590Srgrimes	/* Cache physical address for multiple vcpus. */
4541590Srgrimes	iopm_pa = vtophys(svm_sc->iopm_bitmap);
4551590Srgrimes	msrpm_pa = vtophys(svm_sc->msr_bitmap);
4561590Srgrimes	pml4_pa = svm_sc->nptp;
4571590Srgrimes
4581590Srgrimes	for (i = 0; i < svm_sc->vcpu_cnt; i++) {
4591590Srgrimes		if (svm_init_vcpu(svm_get_vcpu(svm_sc, i), iopm_pa, msrpm_pa,
4601590Srgrimes				pml4_pa, svm_sc->asid)) {
4611590Srgrimes			ERR("SVM couldn't initialise VCPU%d\n", i);
4621590Srgrimes			goto cleanup;
4631590Srgrimes		}
4641590Srgrimes	}
4651590Srgrimes
4661590Srgrimes	return (svm_sc);
4671590Srgrimes
4681590Srgrimescleanup:
4691590Srgrimes	free(svm_sc, M_SVM);
4701590Srgrimes	return (NULL);
4711590Srgrimes}
4721590Srgrimes
4731590Srgrimesstatic int
4741590Srgrimessvm_cpl(struct vmcb_state *state)
4751590Srgrimes{
4761590Srgrimes
4771590Srgrimes	/*
4781590Srgrimes	 * From APMv2:
4791590Srgrimes	 *   "Retrieve the CPL from the CPL field in the VMCB, not
4801590Srgrimes	 *    from any segment DPL"
4811590Srgrimes	 */
4821590Srgrimes	return (state->cpl);
4831590Srgrimes}
4841590Srgrimes
4851590Srgrimesstatic enum vm_cpu_mode
4861590Srgrimessvm_vcpu_mode(uint64_t efer)
4871590Srgrimes{
4881590Srgrimes
4891590Srgrimes	if (efer & EFER_LMA)
4901590Srgrimes		return (CPU_MODE_64BIT);
4911590Srgrimes	else
4921590Srgrimes		return (CPU_MODE_COMPATIBILITY);
4931590Srgrimes}
4941590Srgrimes
4951590Srgrimesstatic enum vm_paging_mode
4961590Srgrimessvm_paging_mode(uint64_t cr0, uint64_t cr4, uint64_t efer)
4971590Srgrimes{
4981590Srgrimes
4991590Srgrimes	if ((cr0 & CR0_PG) == 0)
5001590Srgrimes		return (PAGING_MODE_FLAT);
5011590Srgrimes	if ((cr4 & CR4_PAE) == 0)
5021590Srgrimes		return (PAGING_MODE_32);
5031590Srgrimes	if (efer & EFER_LME)
5041590Srgrimes		return (PAGING_MODE_64);
5051590Srgrimes	else
5061590Srgrimes		return (PAGING_MODE_PAE);
5071590Srgrimes}
5081590Srgrimes
5091590Srgrimes/*
5101590Srgrimes * ins/outs utility routines
5111590Srgrimes */
5121590Srgrimesstatic uint64_t
5131590Srgrimessvm_inout_str_index(struct svm_regctx *regs, int in)
5141590Srgrimes{
5151590Srgrimes	uint64_t val;
5161590Srgrimes
5171590Srgrimes	val = in ? regs->e.g.sctx_rdi : regs->e.g.sctx_rsi;
5181590Srgrimes
5191590Srgrimes	return (val);
5201590Srgrimes}
5211590Srgrimes
5221590Srgrimesstatic uint64_t
5231590Srgrimessvm_inout_str_count(struct svm_regctx *regs, int rep)
5241590Srgrimes{
5251590Srgrimes	uint64_t val;
5261590Srgrimes
5271590Srgrimes	val = rep ? regs->sctx_rcx : 1;
5281590Srgrimes
5291590Srgrimes	return (val);
5301590Srgrimes}
5311590Srgrimes
5321590Srgrimesstatic void
5331590Srgrimessvm_inout_str_seginfo(struct svm_softc *svm_sc, int vcpu, int64_t info1,
5341590Srgrimes    int in, struct vm_inout_str *vis)
5351590Srgrimes{
5361590Srgrimes	int error, s;
5371590Srgrimes
5381590Srgrimes	if (in) {
5391590Srgrimes		vis->seg_name = VM_REG_GUEST_ES;
5401590Srgrimes	} else {
5411590Srgrimes		/* The segment field has standard encoding */
5421590Srgrimes		s = (info1 >> 10) & 0x7;
5431590Srgrimes		vis->seg_name = vm_segment_name(s);
5441590Srgrimes	}
5451590Srgrimes
5461590Srgrimes	error = svm_getdesc(svm_sc, vcpu, vis->seg_name, &vis->seg_desc);
5471590Srgrimes	KASSERT(error == 0, ("%s: svm_getdesc error %d", __func__, error));
5481590Srgrimes}
5491590Srgrimes
5501590Srgrimesstatic int
5511590Srgrimessvm_inout_str_addrsize(uint64_t info1)
5521590Srgrimes{
5531590Srgrimes        uint32_t size;
5541590Srgrimes
5551590Srgrimes        size = (info1 >> 7) & 0x7;
5561590Srgrimes        switch (size) {
5571590Srgrimes        case 1:
5581590Srgrimes                return (2);     /* 16 bit */
5591590Srgrimes        case 2:
5601590Srgrimes                return (4);     /* 32 bit */
5611590Srgrimes        case 4:
5621590Srgrimes                return (8);     /* 64 bit */
5631590Srgrimes        default:
5641590Srgrimes                panic("%s: invalid size encoding %d", __func__, size);
5651590Srgrimes        }
5661590Srgrimes}
5671590Srgrimes
5681590Srgrimesstatic void
5691590Srgrimessvm_paging_info(struct vmcb_state *state, struct vm_guest_paging *paging)
5701590Srgrimes{
5711590Srgrimes
5721590Srgrimes	paging->cr3 = state->cr3;
5731590Srgrimes	paging->cpl = svm_cpl(state);
5741590Srgrimes	paging->cpu_mode = svm_vcpu_mode(state->efer);
5751590Srgrimes	paging->paging_mode = svm_paging_mode(state->cr0, state->cr4,
5761590Srgrimes		   	          state->efer);
5771590Srgrimes}
5781590Srgrimes
5791590Srgrimes/*
5801590Srgrimes * Handle guest I/O intercept.
5811590Srgrimes */
5821590Srgrimesstatic bool
5831590Srgrimessvm_handle_io(struct svm_softc *svm_sc, int vcpu, struct vm_exit *vmexit)
5841590Srgrimes{
5851590Srgrimes	struct vmcb_ctrl *ctrl;
5861590Srgrimes	struct vmcb_state *state;
5871590Srgrimes	struct svm_regctx *regs;
5881590Srgrimes	struct vm_inout_str *vis;
5891590Srgrimes	uint64_t info1;
5901590Srgrimes
5911590Srgrimes	state = svm_get_vmcb_state(svm_sc, vcpu);
5921590Srgrimes	ctrl  = svm_get_vmcb_ctrl(svm_sc, vcpu);
5931590Srgrimes	regs  = svm_get_guest_regctx(svm_sc, vcpu);
5941590Srgrimes	info1 = ctrl->exitinfo1;
5951590Srgrimes
5961590Srgrimes	vmexit->exitcode 	= VM_EXITCODE_INOUT;
5971590Srgrimes	vmexit->u.inout.in 	= (info1 & BIT(0)) ? 1 : 0;
5981590Srgrimes	vmexit->u.inout.string 	= (info1 & BIT(2)) ? 1 : 0;
5991590Srgrimes	vmexit->u.inout.rep 	= (info1 & BIT(3)) ? 1 : 0;
6001590Srgrimes	vmexit->u.inout.bytes 	= (info1 >> 4) & 0x7;
6011590Srgrimes	vmexit->u.inout.port 	= (uint16_t)(info1 >> 16);
6021590Srgrimes	vmexit->u.inout.eax 	= (uint32_t)(state->rax);
6031590Srgrimes
6041590Srgrimes	if (vmexit->u.inout.string) {
6051590Srgrimes		vmexit->exitcode = VM_EXITCODE_INOUT_STR;
6061590Srgrimes		vis = &vmexit->u.inout_str;
6071590Srgrimes		svm_paging_info(state, &vis->paging);
6081590Srgrimes		vis->rflags = state->rflags;
6091590Srgrimes		vis->cr0 = state->cr0;
6101590Srgrimes		vis->index = svm_inout_str_index(regs, vmexit->u.inout.in);
6111590Srgrimes		vis->count = svm_inout_str_count(regs, vmexit->u.inout.rep);
6121590Srgrimes		vis->addrsize = svm_inout_str_addrsize(info1);
6131590Srgrimes		svm_inout_str_seginfo(svm_sc, vcpu, info1,
6141590Srgrimes		    vmexit->u.inout.in, vis);
6151590Srgrimes	}
6161590Srgrimes
6171590Srgrimes	return (false);
6181590Srgrimes}
6191590Srgrimes
6201590Srgrimesstatic int
6211590Srgrimessvm_npf_paging(uint64_t exitinfo1)
6221590Srgrimes{
6231590Srgrimes
6241590Srgrimes	if (exitinfo1 & VMCB_NPF_INFO1_W)
6251590Srgrimes		return (VM_PROT_WRITE);
6261590Srgrimes
6271590Srgrimes	return (VM_PROT_READ);
6281590Srgrimes}
6291590Srgrimes
6301590Srgrimesstatic bool
6311590Srgrimessvm_npf_emul_fault(uint64_t exitinfo1)
6321590Srgrimes{
6331590Srgrimes
6341590Srgrimes	if (exitinfo1 & VMCB_NPF_INFO1_ID) {
6351590Srgrimes		return (false);
6361590Srgrimes	}
6371590Srgrimes
6381590Srgrimes	if (exitinfo1 & VMCB_NPF_INFO1_GPT) {
6391590Srgrimes		return (false);
6401590Srgrimes	}
6411590Srgrimes
6421590Srgrimes	if ((exitinfo1 & VMCB_NPF_INFO1_GPA) == 0) {
6431590Srgrimes		return (false);
6441590Srgrimes	}
6451590Srgrimes
6461590Srgrimes	return (true);
6471590Srgrimes}
6481590Srgrimes
6491590Srgrimes/*
6501590Srgrimes * Special handling of EFER MSR.
6511590Srgrimes * SVM guest must have SVM EFER bit set, prohibit guest from cleareing SVM
6521590Srgrimes * enable bit in EFER.
6531590Srgrimes */
6541590Srgrimesstatic void
6551590Srgrimessvm_efer(struct svm_softc *svm_sc, int vcpu, boolean_t write)
6561590Srgrimes{
6571590Srgrimes	struct svm_regctx *swctx;
6581590Srgrimes	struct vmcb_state *state;
6591590Srgrimes
6601590Srgrimes	state = svm_get_vmcb_state(svm_sc, vcpu);
6611590Srgrimes	swctx = svm_get_guest_regctx(svm_sc, vcpu);
6621590Srgrimes
6631590Srgrimes	if (write) {
6641590Srgrimes		state->efer = ((swctx->e.g.sctx_rdx & (uint32_t)~0) << 32) |
6651590Srgrimes				((uint32_t)state->rax) | EFER_SVM;
6661590Srgrimes	} else {
6671590Srgrimes		state->rax = (uint32_t)state->efer;
6681590Srgrimes		swctx->e.g.sctx_rdx = (uint32_t)(state->efer >> 32);
6691590Srgrimes	}
6701590Srgrimes}
6711590Srgrimes
6721590Srgrimes/*
6731590Srgrimes * Determine the cause of virtual cpu exit and handle VMEXIT.
6741590Srgrimes * Return: false - Break vcpu execution loop and handle vmexit
6751590Srgrimes *		   in kernel or user space.
6761590Srgrimes *	   true  - Continue vcpu run.
6771590Srgrimes */
6781590Srgrimesstatic bool
6791590Srgrimessvm_vmexit(struct svm_softc *svm_sc, int vcpu, struct vm_exit *vmexit)
6801590Srgrimes{
6811590Srgrimes	struct vmcb_state *state;
6821590Srgrimes	struct vmcb_ctrl *ctrl;
6831590Srgrimes	struct svm_regctx *ctx;
6841590Srgrimes	uint64_t code, info1, info2, val;
6851590Srgrimes	uint32_t eax, ecx, edx;
6861590Srgrimes	bool update_rip, loop, retu;
6871590Srgrimes
6881590Srgrimes	KASSERT(vcpu < svm_sc->vcpu_cnt, ("Guest doesn't have VCPU%d", vcpu));
6891590Srgrimes
6901590Srgrimes	state = svm_get_vmcb_state(svm_sc, vcpu);
6911590Srgrimes	ctrl  = svm_get_vmcb_ctrl(svm_sc, vcpu);
6921590Srgrimes	ctx   = svm_get_guest_regctx(svm_sc, vcpu);
6931590Srgrimes	code  = ctrl->exitcode;
6941590Srgrimes	info1 = ctrl->exitinfo1;
6951590Srgrimes	info2 = ctrl->exitinfo2;
6961590Srgrimes
6971590Srgrimes	update_rip = true;
6981590Srgrimes	loop = true;
6991590Srgrimes	vmexit->exitcode = VM_EXITCODE_VMX;
7001590Srgrimes	vmexit->u.vmx.status = 0;
7011590Srgrimes
7021590Srgrimes	switch (code) {
7031590Srgrimes		case	VMCB_EXIT_MC: /* Machine Check. */
7041590Srgrimes			vmm_stat_incr(svm_sc->vm, vcpu, VMEXIT_MTRAP, 1);
7051590Srgrimes			vmexit->exitcode = VM_EXITCODE_MTRAP;
7061590Srgrimes			loop = false;
7071590Srgrimes			break;
7081590Srgrimes
7091590Srgrimes		case	VMCB_EXIT_MSR:	/* MSR access. */
7101590Srgrimes			eax = state->rax;
7111590Srgrimes			ecx = ctx->sctx_rcx;
7121590Srgrimes			edx = ctx->e.g.sctx_rdx;
7131590Srgrimes
7141590Srgrimes			if (ecx == MSR_EFER) {
7151590Srgrimes				VCPU_CTR0(svm_sc->vm, vcpu,"VMEXIT EFER\n");
7161590Srgrimes				svm_efer(svm_sc, vcpu, info1);
7171590Srgrimes				break;
7181590Srgrimes			}
7191590Srgrimes
7201590Srgrimes			retu = false;
7211590Srgrimes			if (info1) {
7221590Srgrimes				/* VM exited because of write MSR */
7231590Srgrimes				vmm_stat_incr(svm_sc->vm, vcpu,
7241590Srgrimes					VMEXIT_WRMSR, 1);
7251590Srgrimes				vmexit->exitcode = VM_EXITCODE_WRMSR;
7261590Srgrimes				vmexit->u.msr.code = ecx;
7271590Srgrimes				val = (uint64_t)edx << 32 | eax;
7281590Srgrimes				if (emulate_wrmsr(svm_sc->vm, vcpu, ecx, val,
7291590Srgrimes					&retu)) {
7301590Srgrimes					vmexit->u.msr.wval = val;
7311590Srgrimes					loop = false;
7321590Srgrimes				} else
7331590Srgrimes					loop = retu ? false : true;
7341590Srgrimes
7351590Srgrimes				VCPU_CTR3(svm_sc->vm, vcpu,
7361590Srgrimes					"VMEXIT WRMSR(%s handling) 0x%lx @0x%x",
7371590Srgrimes					loop ? "kernel" : "user", val, ecx);
7381590Srgrimes			} else {
7391590Srgrimes				vmm_stat_incr(svm_sc->vm, vcpu,
7401590Srgrimes					VMEXIT_RDMSR, 1);
7411590Srgrimes				vmexit->exitcode = VM_EXITCODE_RDMSR;
7421590Srgrimes				vmexit->u.msr.code = ecx;
7431590Srgrimes				if (emulate_rdmsr(svm_sc->vm, vcpu, ecx,
7441590Srgrimes					&retu)) {
7451590Srgrimes					loop = false;
7461590Srgrimes				} else
7471590Srgrimes					loop = retu ? false : true;
7481590Srgrimes				VCPU_CTR3(svm_sc->vm, vcpu, "SVM:VMEXIT RDMSR"
7491590Srgrimes					" MSB=0x%08x, LSB=%08x @0x%x",
7501590Srgrimes					ctx->e.g.sctx_rdx, state->rax, ecx);
7511590Srgrimes			}
7521590Srgrimes
7531590Srgrimes#define MSR_AMDK8_IPM           0xc0010055
7541590Srgrimes			/*
7551590Srgrimes			 * We can't hide AMD C1E idle capability since its
7561590Srgrimes			 * based on CPU generation, for now ignore access to
7571590Srgrimes			 * this MSR by vcpus
7581590Srgrimes			 * XXX: special handling of AMD C1E - Ignore.
7591590Srgrimes			 */
7601590Srgrimes			 if (ecx == MSR_AMDK8_IPM)
7611590Srgrimes				loop = true;
7621590Srgrimes			break;
7631590Srgrimes
7641590Srgrimes		case VMCB_EXIT_INTR:
7651590Srgrimes			/*
7661590Srgrimes			 * Exit on External Interrupt.
7671590Srgrimes			 * Give host interrupt handler to run and if its guest
7681590Srgrimes			 * interrupt, local APIC will inject event in guest.
7691590Srgrimes			 */
7701590Srgrimes			update_rip = false;
7711590Srgrimes			VCPU_CTR1(svm_sc->vm, vcpu, "SVM:VMEXIT ExtInt"
7721590Srgrimes				" RIP:0x%lx.\n", state->rip);
7731590Srgrimes			vmm_stat_incr(svm_sc->vm, vcpu, VMEXIT_EXTINT, 1);
7741590Srgrimes			break;
7751590Srgrimes
7761590Srgrimes		case VMCB_EXIT_IO:
7771590Srgrimes			loop = svm_handle_io(svm_sc, vcpu, vmexit);
7781590Srgrimes			vmm_stat_incr(svm_sc->vm, vcpu, VMEXIT_INOUT, 1);
7791590Srgrimes			update_rip = true;
7801590Srgrimes			break;
7811590Srgrimes
7821590Srgrimes		case VMCB_EXIT_CPUID:
7831590Srgrimes			vmm_stat_incr(svm_sc->vm, vcpu, VMEXIT_CPUID, 1);
7841590Srgrimes			(void)x86_emulate_cpuid(svm_sc->vm, vcpu,
7851590Srgrimes					(uint32_t *)&state->rax,
7861590Srgrimes					(uint32_t *)&ctx->sctx_rbx,
7871590Srgrimes					(uint32_t *)&ctx->sctx_rcx,
7881590Srgrimes					(uint32_t *)&ctx->e.g.sctx_rdx);
7891590Srgrimes			VCPU_CTR0(svm_sc->vm, vcpu, "SVM:VMEXIT CPUID\n");
790			break;
791
792		case VMCB_EXIT_HLT:
793			vmm_stat_incr(svm_sc->vm, vcpu, VMEXIT_HLT, 1);
794 			if (ctrl->v_irq) {
795				 /* Interrupt is pending, can't halt guest. */
796				vmm_stat_incr(svm_sc->vm, vcpu,
797					VMEXIT_HLT_IGNORED, 1);
798				VCPU_CTR0(svm_sc->vm, vcpu,
799					"VMEXIT halt ignored.");
800			} else {
801				VCPU_CTR0(svm_sc->vm, vcpu,
802					"VMEXIT halted CPU.");
803				vmexit->exitcode = VM_EXITCODE_HLT;
804				vmexit->u.hlt.rflags = state->rflags;
805				loop = false;
806
807			}
808			break;
809
810		case VMCB_EXIT_PAUSE:
811			VCPU_CTR0(svm_sc->vm, vcpu, "SVM:VMEXIT pause");
812			vmexit->exitcode = VM_EXITCODE_PAUSE;
813			vmm_stat_incr(svm_sc->vm, vcpu, VMEXIT_PAUSE, 1);
814
815			break;
816
817		case VMCB_EXIT_NPF:
818			loop = false;
819			update_rip = false;
820
821        		if (info1 & VMCB_NPF_INFO1_RSV) {
822 				VCPU_CTR2(svm_sc->vm, vcpu, "SVM_ERR:NPT"
823					" reserved bit is set,"
824					"INFO1:0x%lx INFO2:0x%lx .\n",
825					info1, info2);
826        			break;
827			}
828
829			 /* EXITINFO2 has the physical fault address (GPA). */
830			if(vm_mem_allocated(svm_sc->vm, info2)) {
831 				VCPU_CTR3(svm_sc->vm, vcpu, "SVM:NPF-paging,"
832					"RIP:0x%lx INFO1:0x%lx INFO2:0x%lx .\n",
833				 	state->rip, info1, info2);
834				vmexit->exitcode = VM_EXITCODE_PAGING;
835				vmexit->u.paging.gpa = info2;
836				vmexit->u.paging.fault_type =
837					svm_npf_paging(info1);
838				vmm_stat_incr(svm_sc->vm, vcpu,
839					VMEXIT_NESTED_FAULT, 1);
840			} else if (svm_npf_emul_fault(info1)) {
841 				VCPU_CTR3(svm_sc->vm, vcpu, "SVM:NPF inst_emul,"
842					"RIP:0x%lx INFO1:0x%lx INFO2:0x%lx .\n",
843					state->rip, info1, info2);
844				vmexit->exitcode = VM_EXITCODE_INST_EMUL;
845				vmexit->u.inst_emul.gpa = info2;
846				vmexit->u.inst_emul.gla = VIE_INVALID_GLA;
847				vmexit->u.inst_emul.paging.cr3 = state->cr3;
848				vmexit->u.inst_emul.paging.cpu_mode =
849					svm_vcpu_mode(state->efer);
850				vmexit->u.inst_emul.paging.paging_mode =
851					svm_paging_mode(state->cr0, state->cr4,
852                                                 state->efer);
853				/* XXX: get CPL from SS */
854				vmexit->u.inst_emul.paging.cpl = 0;
855				/*
856				 * If DecodeAssist SVM feature doesn't exist,
857				 * we don't have faulty instuction length. New
858				 * RIP will be calculated based on software
859				 * instruction emulation.
860				 */
861				vmexit->inst_length = VIE_INST_SIZE;
862				vmm_stat_incr(svm_sc->vm, vcpu,
863					VMEXIT_INST_EMUL, 1);
864			}
865
866			break;
867
868		case VMCB_EXIT_SHUTDOWN:
869			VCPU_CTR0(svm_sc->vm, vcpu, "SVM:VMEXIT shutdown.");
870			loop = false;
871			break;
872
873		case VMCB_EXIT_INVALID:
874			VCPU_CTR0(svm_sc->vm, vcpu, "SVM:VMEXIT INVALID.");
875			loop = false;
876			break;
877
878		default:
879			 /* Return to user space. */
880			loop = false;
881			update_rip = false;
882			VCPU_CTR3(svm_sc->vm, vcpu, "VMEXIT=0x%lx"
883				" EXITINFO1: 0x%lx EXITINFO2:0x%lx\n",
884		 		ctrl->exitcode, info1, info2);
885			VCPU_CTR3(svm_sc->vm, vcpu, "SVM:RIP: 0x%lx nRIP:0x%lx"
886				" Inst decoder len:%d\n", state->rip,
887				ctrl->nrip, ctrl->inst_decode_size);
888			vmm_stat_incr(svm_sc->vm, vcpu, VMEXIT_UNKNOWN, 1);
889			break;
890	}
891
892	vmexit->rip = state->rip;
893	if (update_rip) {
894		if (ctrl->nrip == 0) {
895 			VCPU_CTR1(svm_sc->vm, vcpu, "SVM_ERR:nRIP is not set "
896				 "for RIP0x%lx.\n", state->rip);
897			vmexit->exitcode = VM_EXITCODE_VMX;
898		} else
899			vmexit->rip = ctrl->nrip;
900	}
901
902	/* If vcpu execution is continued, update RIP. */
903	if (loop) {
904		state->rip = vmexit->rip;
905	}
906
907	if (state->rip == 0) {
908		VCPU_CTR0(svm_sc->vm, vcpu, "SVM_ERR:RIP is NULL\n");
909		vmexit->exitcode = VM_EXITCODE_VMX;
910	}
911
912	return (loop);
913}
914
915/*
916 * Inject NMI to virtual cpu.
917 */
918static int
919svm_inject_nmi(struct svm_softc *svm_sc, int vcpu)
920{
921	struct vmcb_ctrl *ctrl;
922
923	KASSERT(vcpu < svm_sc->vcpu_cnt, ("Guest doesn't have VCPU%d", vcpu));
924
925	ctrl  = svm_get_vmcb_ctrl(svm_sc, vcpu);
926	 /* Can't inject another NMI if last one is pending.*/
927	if (!vm_nmi_pending(svm_sc->vm, vcpu))
928		return (0);
929
930	 /* Inject NMI, vector number is not used.*/
931	if (vmcb_eventinject(ctrl, VMCB_EVENTINJ_TYPE_NMI, IDT_NMI, 0, false)) {
932		VCPU_CTR0(svm_sc->vm, vcpu, "SVM:NMI injection failed.\n");
933		return (EIO);
934	}
935
936	/* Acknowledge the request is accepted.*/
937	vm_nmi_clear(svm_sc->vm, vcpu);
938
939	VCPU_CTR0(svm_sc->vm, vcpu, "SVM:Injected NMI.\n");
940
941	return (1);
942}
943
944/*
945 * Inject event to virtual cpu.
946 */
947static void
948svm_inj_interrupts(struct svm_softc *svm_sc, int vcpu, struct vlapic *vlapic)
949{
950	struct vmcb_ctrl *ctrl;
951	struct vmcb_state *state;
952	struct vm_exception exc;
953	int vector;
954
955	KASSERT(vcpu < svm_sc->vcpu_cnt, ("Guest doesn't have VCPU%d", vcpu));
956
957	state = svm_get_vmcb_state(svm_sc, vcpu);
958	ctrl  = svm_get_vmcb_ctrl(svm_sc, vcpu);
959
960	/* Can't inject multiple events at once. */
961	if (ctrl->eventinj & VMCB_EVENTINJ_VALID) {
962		VCPU_CTR1(svm_sc->vm, vcpu,
963			"SVM:Last event(0x%lx) is pending.\n", ctrl->eventinj);
964		return ;
965	}
966
967	/* Wait for guest to come out of interrupt shadow. */
968	if (ctrl->intr_shadow) {
969		VCPU_CTR0(svm_sc->vm, vcpu, "SVM:Guest in interrupt shadow.\n");
970		return;
971	}
972
973	if (vm_exception_pending(svm_sc->vm, vcpu, &exc)) {
974		KASSERT(exc.vector >= 0 && exc.vector < 32,
975			("Exception vector% invalid", exc.vector));
976		if (vmcb_eventinject(ctrl, VMCB_EVENTINJ_TYPE_EXCEPTION,
977			exc.vector, exc.error_code,
978			exc.error_code_valid)) {
979			VCPU_CTR1(svm_sc->vm, vcpu, "SVM:Exception%d injection"
980				" failed.\n", exc.vector);
981			return;
982		}
983	}
984	/* NMI event has priority over interrupts.*/
985	if (svm_inject_nmi(svm_sc, vcpu)) {
986		return;
987	}
988
989        /* Ask the local apic for a vector to inject */
990        if (!vlapic_pending_intr(vlapic, &vector))
991                return;
992
993	if (vector < 32 || vector > 255) {
994		VCPU_CTR1(svm_sc->vm, vcpu, "SVM_ERR:Event injection"
995			"invalid vector=%d.\n", vector);
996		ERR("SVM_ERR:Event injection invalid vector=%d.\n", vector);
997		return;
998	}
999
1000	if ((state->rflags & PSL_I) == 0) {
1001		VCPU_CTR0(svm_sc->vm, vcpu, "SVM:Interrupt is disabled\n");
1002		return;
1003	}
1004
1005	if (vmcb_eventinject(ctrl, VMCB_EVENTINJ_TYPE_INTR, vector, 0, false)) {
1006		VCPU_CTR1(svm_sc->vm, vcpu, "SVM:Event injection failed to"
1007			" vector=%d.\n", vector);
1008		return;
1009	}
1010
1011	/* Acknowledge that event is accepted.*/
1012	vlapic_intr_accepted(vlapic, vector);
1013	VCPU_CTR1(svm_sc->vm, vcpu, "SVM:event injected,vector=%d.\n", vector);
1014}
1015
1016/*
1017 * Restore host Task Register selector type after every vcpu exit.
1018 */
1019static void
1020setup_tss_type(void)
1021{
1022	struct system_segment_descriptor *desc;
1023
1024	desc = (struct system_segment_descriptor *)&gdt[curcpu * NGDT +
1025		GPROC0_SEL];
1026	/*
1027	 * Task selector that should be restored in host is
1028	 * 64-bit available(9), not what is read(0xb), see
1029	 * APMvol2 Rev3.21 4.8.3 System Descriptors table.
1030	 */
1031	desc->sd_type = 9;
1032}
1033
1034static void
1035svm_handle_exitintinfo(struct svm_softc *svm_sc, int vcpu)
1036{
1037	struct vmcb_ctrl *ctrl;
1038	uint64_t intinfo;
1039
1040	ctrl  	= svm_get_vmcb_ctrl(svm_sc, vcpu);
1041
1042	/*
1043	 * VMEXIT while delivering an exception or interrupt.
1044	 * Inject it as virtual interrupt.
1045	 * Section 15.7.2 Intercepts during IDT interrupt delivery.
1046	 */
1047	intinfo = ctrl->exitintinfo;
1048
1049	if (intinfo & VMCB_EXITINTINFO_VALID) {
1050		vmm_stat_incr(svm_sc->vm, vcpu, VCPU_EXITINTINFO, 1);
1051		VCPU_CTR1(svm_sc->vm, vcpu, "SVM:EXITINTINFO:0x%lx is valid\n",
1052			intinfo);
1053		if (vmcb_eventinject(ctrl, VMCB_EXITINTINFO_TYPE(intinfo),
1054			VMCB_EXITINTINFO_VECTOR(intinfo),
1055			VMCB_EXITINTINFO_EC(intinfo),
1056			VMCB_EXITINTINFO_EC_VALID & intinfo)) {
1057			VCPU_CTR1(svm_sc->vm, vcpu, "SVM:couldn't inject pending"
1058				" interrupt, exitintinfo:0x%lx\n", intinfo);
1059		}
1060	}
1061}
1062/*
1063 * Start vcpu with specified RIP.
1064 */
1065static int
1066svm_vmrun(void *arg, int vcpu, register_t rip, pmap_t pmap,
1067	void *rend_cookie, void *suspended_cookie)
1068{
1069	struct svm_regctx *hctx, *gctx;
1070	struct svm_softc *svm_sc;
1071	struct svm_vcpu *vcpustate;
1072	struct vmcb_state *state;
1073	struct vmcb_ctrl *ctrl;
1074	struct vm_exit *vmexit;
1075	struct vlapic *vlapic;
1076	struct vm *vm;
1077	uint64_t vmcb_pa;
1078	bool loop;	/* Continue vcpu execution loop. */
1079
1080	loop = true;
1081	svm_sc = arg;
1082	vm = svm_sc->vm;
1083
1084	vcpustate = svm_get_vcpu(svm_sc, vcpu);
1085	state = svm_get_vmcb_state(svm_sc, vcpu);
1086	ctrl = svm_get_vmcb_ctrl(svm_sc, vcpu);
1087	vmexit = vm_exitinfo(vm, vcpu);
1088	vlapic = vm_lapic(vm, vcpu);
1089
1090	gctx = svm_get_guest_regctx(svm_sc, vcpu);
1091	hctx = &host_ctx[curcpu];
1092	vmcb_pa = svm_sc->vcpu[vcpu].vmcb_pa;
1093
1094	if (vcpustate->lastcpu != curcpu) {
1095		/* Virtual CPU is running on a diiferent CPU now.*/
1096		vmm_stat_incr(vm, vcpu, VCPU_MIGRATIONS, 1);
1097
1098		/*
1099		 * Flush all TLB mapping for this guest on this CPU,
1100		 * it might have stale entries.
1101		 */
1102		ctrl->tlb_ctrl = VMCB_TLB_FLUSH_GUEST;
1103
1104		/* Can't use any cached VMCB state by cpu.*/
1105		ctrl->vmcb_clean = VMCB_CACHE_NONE;
1106	} else {
1107		/*
1108		 * XXX: Using same ASID for all vcpus of a VM will cause TLB
1109		 * corruption. This can easily be produced by muxing two vcpus
1110		 * on same core.
1111		 * For now, flush guest TLB for every vmrun.
1112		 */
1113		ctrl->tlb_ctrl = VMCB_TLB_FLUSH_GUEST;
1114
1115		/*
1116		 * This is the same cpu on which vcpu last ran so don't
1117		 * need to reload all VMCB state.
1118		 * ASID is unique for a guest.
1119		 * IOPM is unchanged.
1120		 * RVI/EPT is unchanged.
1121		 *
1122		 */
1123		ctrl->vmcb_clean = VMCB_CACHE_ASID |
1124				VMCB_CACHE_IOPM |
1125				VMCB_CACHE_NP;
1126	}
1127
1128	vcpustate->lastcpu = curcpu;
1129	VCPU_CTR3(vm, vcpu, "SVM:Enter vmrun RIP:0x%lx"
1130		" inst len=%d/%d\n",
1131		rip, vmexit->inst_length,
1132		vmexit->u.inst_emul.vie.num_valid);
1133	/* Update Guest RIP */
1134	state->rip = rip;
1135
1136	do {
1137		vmexit->inst_length = 0;
1138		 /* We are asked to give the cpu by scheduler. */
1139		if (curthread->td_flags & (TDF_ASTPENDING | TDF_NEEDRESCHED)) {
1140			vmexit->exitcode = VM_EXITCODE_BOGUS;
1141			vmm_stat_incr(vm, vcpu, VMEXIT_ASTPENDING, 1);
1142			VCPU_CTR1(vm, vcpu,
1143				"SVM: ASTPENDING, RIP:0x%lx\n", state->rip);
1144			vmexit->rip = state->rip;
1145			break;
1146		}
1147
1148		if (vcpu_suspended(suspended_cookie)) {
1149			vm_exit_suspended(vm, vcpu, state->rip);
1150			break;
1151		}
1152
1153		if (vcpu_rendezvous_pending(rend_cookie)) {
1154			vmexit->exitcode = VM_EXITCODE_RENDEZVOUS;
1155			vmm_stat_incr(vm, vcpu, VMEXIT_RENDEZVOUS, 1);
1156			VCPU_CTR1(vm, vcpu,
1157				"SVM: VCPU rendezvous, RIP:0x%lx\n",
1158				state->rip);
1159			vmexit->rip = state->rip;
1160			break;
1161		}
1162
1163		(void)svm_set_vmcb(svm_get_vmcb(svm_sc, vcpu), svm_sc->asid);
1164
1165		svm_handle_exitintinfo(svm_sc, vcpu);
1166
1167		(void)svm_inj_interrupts(svm_sc, vcpu, vlapic);
1168
1169		/* Change TSS type to available.*/
1170		setup_tss_type();
1171
1172		/*
1173		 * Disable global interrupt to guarantee atomicity
1174		 * during loading of guest state.
1175		 * See 15.5.1 "Loading guest state" APM2.
1176		 */
1177		disable_gintr();
1178
1179		/* Launch Virtual Machine. */
1180		svm_launch(vmcb_pa, gctx, hctx);
1181
1182		/*
1183		 * Only GDTR and IDTR of host is saved and restore by SVM,
1184		 * LDTR and TR need to be restored by VMM.
1185		 * XXX: kernel doesn't use LDT, only user space.
1186		 */
1187		ltr(GSEL(GPROC0_SEL, SEL_KPL));
1188
1189		/*
1190		 * Guest FS and GS selector are stashed by vmload and vmsave.
1191		 * Host FS and GS selector are stashed by svm_launch().
1192		 * Host GS base that holds per-cpu need to be restored before
1193		 * enabling global interrupt.
1194		 * FS is not used by FreeBSD kernel and kernel does restore
1195		 * back FS selector and base of user before returning to
1196		 * userland.
1197		 *
1198		 * Note: You can't use 'curcpu' which uses pcpu.
1199		 */
1200		wrmsr(MSR_GSBASE, (uint64_t)&__pcpu[vcpustate->lastcpu]);
1201		wrmsr(MSR_KGSBASE, (uint64_t)&__pcpu[vcpustate->lastcpu]);
1202
1203		/* vcpu exit with glbal interrupt disabled. */
1204		enable_gintr();
1205
1206		/* Handle #VMEXIT and if required return to user space. */
1207		loop = svm_vmexit(svm_sc, vcpu, vmexit);
1208		vcpustate->loop++;
1209		vmm_stat_incr(vm, vcpu, VMEXIT_COUNT, 1);
1210
1211	} while (loop);
1212
1213	return (0);
1214}
1215
1216/*
1217 * Cleanup for virtual machine.
1218 */
1219static void
1220svm_vmcleanup(void *arg)
1221{
1222	struct svm_softc *svm_sc;
1223
1224	svm_sc = arg;
1225
1226	VCPU_CTR0(svm_sc->vm, 0, "SVM:cleanup\n");
1227
1228	free(svm_sc, M_SVM);
1229}
1230
1231/*
1232 * Return pointer to hypervisor saved register state.
1233 */
1234static register_t *
1235swctx_regptr(struct svm_regctx *regctx, int reg)
1236{
1237
1238	switch (reg) {
1239		case VM_REG_GUEST_RBX:
1240			return (&regctx->sctx_rbx);
1241		case VM_REG_GUEST_RCX:
1242			return (&regctx->sctx_rcx);
1243		case VM_REG_GUEST_RDX:
1244			return (&regctx->e.g.sctx_rdx);
1245		case VM_REG_GUEST_RDI:
1246			return (&regctx->e.g.sctx_rdi);
1247		case VM_REG_GUEST_RSI:
1248			return (&regctx->e.g.sctx_rsi);
1249		case VM_REG_GUEST_RBP:
1250			return (&regctx->sctx_rbp);
1251		case VM_REG_GUEST_R8:
1252			return (&regctx->sctx_r8);
1253		case VM_REG_GUEST_R9:
1254			return (&regctx->sctx_r9);
1255		case VM_REG_GUEST_R10:
1256			return (&regctx->sctx_r10);
1257		case VM_REG_GUEST_R11:
1258			return (&regctx->sctx_r11);
1259		case VM_REG_GUEST_R12:
1260			return (&regctx->sctx_r12);
1261		case VM_REG_GUEST_R13:
1262			return (&regctx->sctx_r13);
1263		case VM_REG_GUEST_R14:
1264			return (&regctx->sctx_r14);
1265		case VM_REG_GUEST_R15:
1266			return (&regctx->sctx_r15);
1267		default:
1268			ERR("Unknown register requested, reg=%d.\n", reg);
1269			break;
1270	}
1271
1272	return (NULL);
1273}
1274
1275/*
1276 * Interface to read guest registers.
1277 * This can be SVM h/w saved or hypervisor saved register.
1278 */
1279static int
1280svm_getreg(void *arg, int vcpu, int ident, uint64_t *val)
1281{
1282	struct svm_softc *svm_sc;
1283	struct vmcb *vmcb;
1284	register_t *reg;
1285
1286	svm_sc = arg;
1287	KASSERT(vcpu < svm_sc->vcpu_cnt, ("Guest doesn't have VCPU%d", vcpu));
1288
1289	vmcb = svm_get_vmcb(svm_sc, vcpu);
1290
1291	if (vmcb_read(vmcb, ident, val) == 0) {
1292		return (0);
1293	}
1294
1295	reg = swctx_regptr(svm_get_guest_regctx(svm_sc, vcpu), ident);
1296
1297	if (reg != NULL) {
1298		*val = *reg;
1299		return (0);
1300	}
1301
1302 	ERR("SVM_ERR:reg type %x is not saved in VMCB.\n", ident);
1303	return (EINVAL);
1304}
1305
1306/*
1307 * Interface to write to guest registers.
1308 * This can be SVM h/w saved or hypervisor saved register.
1309 */
1310static int
1311svm_setreg(void *arg, int vcpu, int ident, uint64_t val)
1312{
1313	struct svm_softc *svm_sc;
1314	struct vmcb *vmcb;
1315	register_t *reg;
1316
1317	svm_sc = arg;
1318	KASSERT(vcpu < svm_sc->vcpu_cnt, ("Guest doesn't have VCPU%d", vcpu));
1319
1320	vmcb = svm_get_vmcb(svm_sc, vcpu);
1321	if (vmcb_write(vmcb, ident, val) == 0) {
1322		return (0);
1323	}
1324
1325	reg = swctx_regptr(svm_get_guest_regctx(svm_sc, vcpu), ident);
1326
1327	if (reg != NULL) {
1328		*reg = val;
1329		return (0);
1330	}
1331
1332 	ERR("SVM_ERR:reg type %x is not saved in VMCB.\n", ident);
1333	return (EINVAL);
1334}
1335
1336
1337/*
1338 * Inteface to set various descriptors.
1339 */
1340static int
1341svm_setdesc(void *arg, int vcpu, int type, struct seg_desc *desc)
1342{
1343	struct svm_softc *svm_sc;
1344	struct vmcb *vmcb;
1345	struct vmcb_segment *seg;
1346	uint16_t attrib;
1347
1348	svm_sc = arg;
1349	KASSERT(vcpu < svm_sc->vcpu_cnt, ("Guest doesn't have VCPU%d", vcpu));
1350
1351	vmcb = svm_get_vmcb(svm_sc, vcpu);
1352
1353	VCPU_CTR1(svm_sc->vm, vcpu, "SVM:set_desc: Type%d\n", type);
1354
1355	seg = vmcb_seg(vmcb, type);
1356	if (seg == NULL) {
1357		ERR("SVM_ERR:Unsupported segment type%d\n", type);
1358		return (EINVAL);
1359	}
1360
1361	/* Map seg_desc access to VMCB attribute format.*/
1362	attrib = ((desc->access & 0xF000) >> 4) | (desc->access & 0xFF);
1363	VCPU_CTR3(svm_sc->vm, vcpu, "SVM:[sel %d attribute 0x%x limit:0x%x]\n",
1364		type, desc->access, desc->limit);
1365	seg->attrib = attrib;
1366	seg->base = desc->base;
1367	seg->limit = desc->limit;
1368
1369	return (0);
1370}
1371
1372/*
1373 * Interface to get guest descriptor.
1374 */
1375static int
1376svm_getdesc(void *arg, int vcpu, int type, struct seg_desc *desc)
1377{
1378	struct svm_softc *svm_sc;
1379	struct vmcb_segment	*seg;
1380
1381	svm_sc = arg;
1382	KASSERT(vcpu < svm_sc->vcpu_cnt, ("Guest doesn't have VCPU%d", vcpu));
1383
1384	VCPU_CTR1(svm_sc->vm, vcpu, "SVM:get_desc: Type%d\n", type);
1385
1386	seg = vmcb_seg(svm_get_vmcb(svm_sc, vcpu), type);
1387	if (!seg) {
1388		ERR("SVM_ERR:Unsupported segment type%d\n", type);
1389		return (EINVAL);
1390	}
1391
1392	/* Map seg_desc access to VMCB attribute format.*/
1393	desc->access = ((seg->attrib & 0xF00) << 4) | (seg->attrib & 0xFF);
1394	desc->base = seg->base;
1395	desc->limit = seg->limit;
1396
1397	/*
1398	 * VT-x uses bit 16 (Unusable) to indicate a segment that has been
1399	 * loaded with a NULL segment selector. The 'desc->access' field is
1400	 * interpreted in the VT-x format by the processor-independent code.
1401	 *
1402	 * SVM uses the 'P' bit to convey the same information so convert it
1403	 * into the VT-x format. For more details refer to section
1404	 * "Segment State in the VMCB" in APMv2.
1405	 */
1406	if (type == VM_REG_GUEST_CS && type == VM_REG_GUEST_TR)
1407		desc->access |= 0x80;		/* CS and TS always present */
1408
1409	if (!(desc->access & 0x80))
1410		desc->access |= 0x10000;	/* Unusable segment */
1411
1412	return (0);
1413}
1414
1415static int
1416svm_setcap(void *arg, int vcpu, int type, int val)
1417{
1418	struct svm_softc *svm_sc;
1419	struct vmcb_ctrl *ctrl;
1420	int ret = ENOENT;
1421
1422	svm_sc = arg;
1423	KASSERT(vcpu < svm_sc->vcpu_cnt, ("Guest doesn't have VCPU%d", vcpu));
1424
1425	ctrl = svm_get_vmcb_ctrl(svm_sc, vcpu);
1426
1427	switch (type) {
1428		case VM_CAP_HALT_EXIT:
1429			if (val)
1430				ctrl->ctrl1 |= VMCB_INTCPT_HLT;
1431			else
1432				ctrl->ctrl1 &= ~VMCB_INTCPT_HLT;
1433			ret = 0;
1434			VCPU_CTR1(svm_sc->vm, vcpu, "SVM:Set_gap:Halt exit %s.\n",
1435				val ? "enabled": "disabled");
1436			break;
1437
1438		case VM_CAP_PAUSE_EXIT:
1439			if (val)
1440				ctrl->ctrl1 |= VMCB_INTCPT_PAUSE;
1441			else
1442				ctrl->ctrl1 &= ~VMCB_INTCPT_PAUSE;
1443			ret = 0;
1444			VCPU_CTR1(svm_sc->vm, vcpu, "SVM:Set_gap:Pause exit %s.\n",
1445				val ? "enabled": "disabled");
1446			break;
1447
1448		case VM_CAP_MTRAP_EXIT:
1449			if (val)
1450				ctrl->exception |= BIT(IDT_MC);
1451			else
1452				ctrl->exception &= ~BIT(IDT_MC);
1453			ret = 0;
1454			VCPU_CTR1(svm_sc->vm, vcpu, "SVM:Set_gap:MC exit %s.\n",
1455				val ? "enabled": "disabled");
1456			break;
1457
1458		case VM_CAP_UNRESTRICTED_GUEST:
1459			/* SVM doesn't need special capability for SMP.*/
1460			VCPU_CTR0(svm_sc->vm, vcpu, "SVM:Set_gap:Unrestricted "
1461			"always enabled.\n");
1462			ret = 0;
1463			break;
1464
1465		default:
1466			break;
1467		}
1468
1469	return (ret);
1470}
1471
1472static int
1473svm_getcap(void *arg, int vcpu, int type, int *retval)
1474{
1475	struct svm_softc *svm_sc;
1476	struct vmcb_ctrl *ctrl;
1477
1478	svm_sc = arg;
1479	KASSERT(vcpu < svm_sc->vcpu_cnt, ("Guest doesn't have VCPU%d", vcpu));
1480
1481	ctrl = svm_get_vmcb_ctrl(svm_sc, vcpu);
1482
1483	switch (type) {
1484		case VM_CAP_HALT_EXIT:
1485		*retval = (ctrl->ctrl1 & VMCB_INTCPT_HLT) ? 1 : 0;
1486		VCPU_CTR1(svm_sc->vm, vcpu, "SVM:get_cap:Halt exit %s.\n",
1487			*retval ? "enabled": "disabled");
1488		break;
1489
1490		case VM_CAP_PAUSE_EXIT:
1491		*retval = (ctrl->ctrl1 & VMCB_INTCPT_PAUSE) ? 1 : 0;
1492		VCPU_CTR1(svm_sc->vm, vcpu, "SVM:get_cap:Pause exit %s.\n",
1493			*retval ? "enabled": "disabled");
1494		break;
1495
1496		case VM_CAP_MTRAP_EXIT:
1497		*retval = (ctrl->exception & BIT(IDT_MC)) ? 1 : 0;
1498		VCPU_CTR1(svm_sc->vm, vcpu, "SVM:get_cap:MC exit %s.\n",
1499			*retval ? "enabled": "disabled");
1500		break;
1501
1502	case VM_CAP_UNRESTRICTED_GUEST:
1503		VCPU_CTR0(svm_sc->vm, vcpu, "SVM:get_cap:Unrestricted.\n");
1504		*retval = 1;
1505		break;
1506		default:
1507		break;
1508	}
1509
1510	return (0);
1511}
1512
1513static struct vlapic *
1514svm_vlapic_init(void *arg, int vcpuid)
1515{
1516	struct svm_softc *svm_sc;
1517	struct vlapic *vlapic;
1518
1519	svm_sc = arg;
1520	vlapic = malloc(sizeof(struct vlapic), M_SVM_VLAPIC, M_WAITOK | M_ZERO);
1521	vlapic->vm = svm_sc->vm;
1522	vlapic->vcpuid = vcpuid;
1523	vlapic->apic_page = (struct LAPIC *)&svm_sc->apic_page[vcpuid];
1524
1525	vlapic_init(vlapic);
1526
1527	return (vlapic);
1528}
1529
1530static void
1531svm_vlapic_cleanup(void *arg, struct vlapic *vlapic)
1532{
1533
1534        vlapic_cleanup(vlapic);
1535        free(vlapic, M_SVM_VLAPIC);
1536}
1537
1538struct vmm_ops vmm_ops_amd = {
1539	svm_init,
1540	svm_cleanup,
1541	svm_restore,
1542	svm_vminit,
1543	svm_vmrun,
1544	svm_vmcleanup,
1545	svm_getreg,
1546	svm_setreg,
1547	svm_getdesc,
1548	svm_setdesc,
1549	svm_getcap,
1550	svm_setcap,
1551	svm_npt_alloc,
1552	svm_npt_free,
1553	svm_vlapic_init,
1554	svm_vlapic_cleanup
1555};
1556