On Thu, May 04, 2017 at 11:17:12PM -0700, Mike Larkin wrote:
> This diff limits the ASID/VPID value to 0xFFF (4095), or in the case of SVN,
> the max ASID capability of the CPU. I use a bitmap to record the VPIDs/ASIDs
> in use, and allocate the next one available when needed. Although VMX can
> support 65535 VPIDs, 4095 seems like a reasonable value for the number of
> "VCPUs currently in use" for a given machine. The bitmap is easily extended
> if needed.
>
> Tested with VM startup, teardown, watching the VPID recycling when VMM_DEBUG
> is enabled.
>
> ok?
>
> -ml
Just noticed identcpu.c got omitted from the previous diff.
-ml
Index: arch/amd64/amd64/identcpu.c
===
RCS file: /cvs/src/sys/arch/amd64/amd64/identcpu.c,v
retrieving revision 1.83
diff -u -p -a -u -r1.83 identcpu.c
--- arch/amd64/amd64/identcpu.c 14 Apr 2017 01:02:28 - 1.83
+++ arch/amd64/amd64/identcpu.c 5 May 2017 06:25:57 -
@@ -949,8 +949,8 @@ cpu_check_vmm_cap(struct cpu_info *ci)
CPUID(0x800A, dummy, ci->ci_vmm_cap.vcc_svm.svm_max_asid,
dummy, dummy);
- if (ci->ci_vmm_cap.vcc_svm.svm_max_asid > 0x)
- ci->ci_vmm_cap.vcc_svm.svm_max_asid = 0x;
+ if (ci->ci_vmm_cap.vcc_svm.svm_max_asid > 0xFFF)
+ ci->ci_vmm_cap.vcc_svm.svm_max_asid = 0xFFF;
}
/*
Index: arch/amd64/amd64/vmm.c
===
RCS file: /cvs/src/sys/arch/amd64/amd64/vmm.c,v
retrieving revision 1.138
diff -u -p -a -u -r1.138 vmm.c
--- arch/amd64/amd64/vmm.c 2 May 2017 02:57:46 - 1.138
+++ arch/amd64/amd64/vmm.c 5 May 2017 06:12:38 -
@@ -100,6 +100,10 @@ struct vmm_softc {
struct rwlock vm_lock;
size_t vm_ct; /* number of in-memory VMs */
size_t vm_idx; /* next unique VM index */
+
+ struct rwlock vpid_lock;
+ uint16_tmax_vpid;
+ uint8_t vpids[512]; /* bitmap of used VPID/ASIDs */
};
int vmm_enabled(void);
@@ -165,6 +169,8 @@ int svm_get_guest_faulttype(void);
int vmx_get_exit_qualification(uint64_t *);
int vmx_fault_page(struct vcpu *, paddr_t);
int vmx_handle_np_fault(struct vcpu *);
+int vmm_alloc_vpid(uint16_t *);
+void vmm_free_vpid(uint16_t);
const char *vcpu_state_decode(u_int);
const char *vmx_exit_reason_decode(uint32_t);
const char *vmx_instruction_error_decode(uint32_t);
@@ -361,6 +367,15 @@ vmm_attach(struct device *parent, struct
sc->mode = VMM_MODE_UNKNOWN;
}
+ if (sc->mode == VMM_MODE_SVM || sc->mode == VMM_MODE_RVI) {
+ sc->max_vpid = ci->ci_vmm_cap.vcc_svm.svm_max_asid;
+ } else {
+ sc->max_vpid = 0xFFF;
+ }
+
+ bzero(>vpids, sizeof(sc->vpids));
+ rw_init(>vpid_lock, "vpidlock");
+
pool_init(_pool, sizeof(struct vm), 0, IPL_NONE, PR_WAITOK,
"vmpool", NULL);
pool_init(_pool, sizeof(struct vcpu), 64, IPL_NONE, PR_WAITOK,
@@ -1033,10 +1048,6 @@ vm_create(struct vm_create_params *vcp,
vmm_softc->vm_ct++;
vmm_softc->vm_idx++;
- /*
-* XXX we use the vm_id for the VPID/ASID, so we need to prevent
-* wrapping around 65536/4096 entries here
-*/
vm->vm_id = vmm_softc->vm_idx;
vm->vm_vcpu_ct = 0;
vm->vm_vcpus_running = 0;
@@ -1671,6 +1682,7 @@ vcpu_reset_regs_svm(struct vcpu *vcpu, s
{
struct vmcb *vmcb;
int ret;
+ uint16_t asid;
vmcb = (struct vmcb *)vcpu->vc_control_va;
@@ -1726,7 +1738,14 @@ vcpu_reset_regs_svm(struct vcpu *vcpu, s
svm_setmsrbr(vcpu, MSR_EFER);
/* Guest VCPU ASID */
- vmcb->v_asid = vcpu->vc_parent->vm_id;
+ if (vmm_alloc_vpid()) {
+ DPRINTF("%s: could not allocate asid\n", __func__);
+ ret = EINVAL;
+ goto exit;
+ }
+
+ vmcb->v_asid = asid;
+ vcpu->vc_vpid = asid;
/* TLB Control */
vmcb->v_tlb_control = 2;/* Flush this guest's TLB entries */
@@ -1745,6 +1764,7 @@ vcpu_reset_regs_svm(struct vcpu *vcpu, s
vmcb->v_efer |= (EFER_LME | EFER_LMA);
vmcb->v_cr4 |= CR4_PAE;
+exit:
return ret;
}
@@ -1947,7 +1967,7 @@ vcpu_reset_regs_vmx(struct vcpu *vcpu, s
uint32_t pinbased, procbased, procbased2, exit, entry;
uint32_t want1, want0;
uint64_t msr, ctrlval, eptp, cr3;
- uint16_t ctrl;
+ uint16_t ctrl, vpid;
struct vmx_msr_store *msr_store;
ret = 0;
@@ -2203,12 +2223,20 @@ vcpu_reset_regs_vmx(struct vcpu *vcpu, s
if (vcpu_vmx_check_cap(vcpu, IA32_VMX_PROCBASED_CTLS,
IA32_VMX_ACTIVATE_SECONDARY_CONTROLS, 1)) {
if (vcpu_vmx_check_cap(vcpu, IA32_VMX_PROCBASED2_CTLS,
-