FreeBSD/sys/amd64/vmm/amd/svm.c
/*
 * Start vcpu with specified RIP.
 */
Start vcpu with specified RIP.
Start vcpu with specified RIP .
static int
svm_vmrun(void *arg, int vcpu, register_t rip, pmap_t pmap, 
	struct vm_eventinfo *evinfo)
{
	struct svm_regctx *gctx;
	struct svm_softc *svm_sc;
	struct svm_vcpu *vcpustate;
	struct vmcb_state *state;
	struct vmcb_ctrl *ctrl;
	struct vm_exit *vmexit;
	struct vlapic *vlapic;
	struct vm *vm;
	uint64_t vmcb_pa;
	int handled;
	svm_sc = arg;
	vm = svm_sc->vm;
	vcpustate = svm_get_vcpu(svm_sc, vcpu);
	state = svm_get_vmcb_state(svm_sc, vcpu);
	ctrl = svm_get_vmcb_ctrl(svm_sc, vcpu);
	vmexit = vm_exitinfo(vm, vcpu);
	vlapic = vm_lapic(vm, vcpu);
	gctx = svm_get_guest_regctx(svm_sc, vcpu);
	vmcb_pa = svm_sc->vcpu[vcpu].vmcb_pa;
	if (vcpustate->lastcpu != curcpu) {
		vcpustate->asid.gen = 0;
		svm_set_dirty(svm_sc, vcpu, 0xffffffff);
		vcpustate->lastcpu = curcpu;
		vmm_stat_incr(vm, vcpu, VCPU_MIGRATIONS, 1);
	}
	svm_msr_guest_enter(svm_sc, vcpu);
	state->rip = rip;
	do {
		disable_gintr();
		if (vcpu_suspended(evinfo)) {
			enable_gintr();
			vm_exit_suspended(vm, vcpu, state->rip);
			break;
		}
		if (vcpu_rendezvous_pending(evinfo)) {
			enable_gintr();
			vm_exit_rendezvous(vm, vcpu, state->rip);
			break;
		}
		if (vcpu_reqidle(evinfo)) {
			enable_gintr();
			vm_exit_reqidle(vm, vcpu, state->rip);
			break;
		}
		if (vcpu_should_yield(vm, vcpu)) {
			enable_gintr();
			vm_exit_astpending(vm, vcpu, state->rip);
			break;
		}
		svm_inj_interrupts(svm_sc, vcpu, vlapic);
		CPU_SET_ATOMIC_ACQ(curcpu, &pmap->pm_active);
		check_asid(svm_sc, vcpu, pmap, curcpu);
		ctrl->vmcb_clean = vmcb_clean & ~vcpustate->dirty;
		vcpustate->dirty = 0;
		VCPU_CTR1(vm, vcpu, "vmcb clean %#x", ctrl->vmcb_clean);
		VCPU_CTR1(vm, vcpu, "Resume execution at %#lx", state->rip);
		svm_launch(vmcb_pa, gctx, &__pcpu[curcpu]);
		CPU_CLR_ATOMIC(curcpu, &pmap->pm_active);
		restore_host_tss();
		enable_gintr();
		vcpustate->nextrip = state->rip;
		handled = svm_vmexit(svm_sc, vcpu, vmexit);
	} while (handled);
	svm_msr_guest_exit(svm_sc, vcpu);
	return (0);
}
static int svm_vmrun ( void * arg , int vcpu , register_t rip , pmap_t pmap , struct vm_eventinfo * evinfo ) { struct svm_regctx * gctx ; struct svm_softc * svm_sc ; struct svm_vcpu * vcpustate ; struct vmcb_state * state ; struct vmcb_ctrl * ctrl ; struct vm_exit * vmexit ; struct vlapic * vlapic ; struct vm * vm ; uint64_t vmcb_pa ; int handled ; svm_sc = arg ; vm = svm_sc -> vm ; vcpustate = svm_get_vcpu ( svm_sc , vcpu ) ; state = svm_get_vmcb_state ( svm_sc , vcpu ) ; ctrl = svm_get_vmcb_ctrl ( svm_sc , vcpu ) ; vmexit = vm_exitinfo ( vm , vcpu ) ; vlapic = vm_lapic ( vm , vcpu ) ; gctx = svm_get_guest_regctx ( svm_sc , vcpu ) ; vmcb_pa = svm_sc -> vcpu [ vcpu ] . vmcb_pa ; if ( vcpustate -> lastcpu != curcpu ) { vcpustate -> asid . gen = 0 ; svm_set_dirty ( svm_sc , vcpu , 0xffffffff ) ; vcpustate -> lastcpu = curcpu ; vmm_stat_incr ( vm , vcpu , VCPU_MIGRATIONS , 1 ) ; } svm_msr_guest_enter ( svm_sc , vcpu ) ; state -> rip = rip ; do { disable_gintr ( ) ; if ( vcpu_suspended ( evinfo ) ) { enable_gintr ( ) ; vm_exit_suspended ( vm , vcpu , state -> rip ) ; break ; } if ( vcpu_rendezvous_pending ( evinfo ) ) { enable_gintr ( ) ; vm_exit_rendezvous ( vm , vcpu , state -> rip ) ; break ; } if ( vcpu_reqidle ( evinfo ) ) { enable_gintr ( ) ; vm_exit_reqidle ( vm , vcpu , state -> rip ) ; break ; } if ( vcpu_should_yield ( vm , vcpu ) ) { enable_gintr ( ) ; vm_exit_astpending ( vm , vcpu , state -> rip ) ; break ; } svm_inj_interrupts ( svm_sc , vcpu , vlapic ) ; CPU_SET_ATOMIC_ACQ ( curcpu , & pmap -> pm_active ) ; check_asid ( svm_sc , vcpu , pmap , curcpu ) ; ctrl -> vmcb_clean = vmcb_clean & ~ vcpustate -> dirty ; vcpustate -> dirty = 0 ; VCPU_CTR1 ( vm , vcpu , " " , ctrl -> vmcb_clean ) ; VCPU_CTR1 ( vm , vcpu , " " , state -> rip ) ; svm_launch ( vmcb_pa , gctx , & __pcpu [ curcpu ] ) ; CPU_CLR_ATOMIC ( curcpu , & pmap -> pm_active ) ; restore_host_tss ( ) ; enable_gintr ( ) ; vcpustate -> nextrip = state -> rip ; handled = svm_vmexit ( svm_sc , vcpu , vmexit ) ; } while ( handled ) ; svm_msr_guest_exit ( svm_sc , vcpu ) ; return ( 0 ) ; }
Start vcpu with specified RIP.
Start vcpu with specified RIP .
/*
		 * Force new ASID allocation by invalidating the generation.
		 */ /*
		 * Invalidate the VMCB state cache by marking all fields dirty.
		 */ /*
		 * XXX
		 * Setting 'vcpustate->lastcpu' here is bit premature because
		 * we may return from this function without actually executing
		 * the VMRUN  instruction. This could happen if a rendezvous
		 * or an AST is pending on the first time through the loop.
		 *
		 * This works for now but any new side-effects of vcpu
		 * migration should take this case into account.
		 */ /* Update Guest RIP */ /*
		 * Disable global interrupts to guarantee atomicity during
		 * loading of guest state. This includes not only the state
		 * loaded by the "vmrun" instruction but also software state
		 * maintained by the hypervisor: suspended and rendezvous
		 * state, NPT generation number, vlapic interrupts etc.
		 */ /* We are asked to give the cpu by scheduler. */ /* Activate the nested pmap on 'curcpu' */ /*
		 * Check the pmap generation and the ASID generation to
		 * ensure that the vcpu does not use stale TLB mappings.
		 */ /* Launch Virtual Machine. */ /*
		 * The host GDTR and IDTR is saved by VMRUN and restored
		 * automatically on #VMEXIT. However, the host TSS needs
		 * to be restored explicitly.
		 */ /* #VMEXIT disables interrupts so re-enable them here. */ /* Update 'nextrip' */ /* Handle #VMEXIT and if required return to user space. */