MFC r256645. Add a new capability, VM_CAP_ENABLE_INVPCID, that can be enabled to expose 'invpcid' instruction to the guest. Currently bhyve will try to enable this capability unconditionally if it is available. Consolidate code in bhyve to set the capabilities so it is no longer duplicated in BSP and AP bringup. Add a sysctl 'vm.pmap.invpcid_works' to display whether the 'invpcid' instruction is available. Index: lib/libvmmapi/vmmapi.c =================================================================== --- lib/libvmmapi/vmmapi.c (revision 256860) +++ lib/libvmmapi/vmmapi.c (working copy) @@ -415,6 +415,7 @@ { "mtrap_exit", VM_CAP_MTRAP_EXIT }, { "pause_exit", VM_CAP_PAUSE_EXIT }, { "unrestricted_guest", VM_CAP_UNRESTRICTED_GUEST }, + { "enable_invpcid", VM_CAP_ENABLE_INVPCID }, { 0 } }; Index: lib/libvmmapi =================================================================== --- lib/libvmmapi (revision 256860) +++ lib/libvmmapi (working copy) Property changes on: lib/libvmmapi ___________________________________________________________________ Modified: svn:mergeinfo Merged /head/lib/libvmmapi:r256645 Index: sys/amd64/amd64/pmap.c =================================================================== --- sys/amd64/amd64/pmap.c (revision 256860) +++ sys/amd64/amd64/pmap.c (working copy) @@ -371,6 +371,8 @@ SYSCTL_INT(_vm_pmap, OID_AUTO, pcid_enabled, CTLFLAG_RDTUN, &pmap_pcid_enabled, 0, "Is TLB Context ID enabled ?"); int invpcid_works = 0; +SYSCTL_INT(_vm_pmap, OID_AUTO, invpcid_works, CTLFLAG_RD, &invpcid_works, 0, + "Is the invpcid instruction available ?"); static int pmap_pcid_save_cnt_proc(SYSCTL_HANDLER_ARGS) Index: sys/amd64/include/vmm.h =================================================================== --- sys/amd64/include/vmm.h (revision 256860) +++ sys/amd64/include/vmm.h (working copy) @@ -223,6 +223,7 @@ VM_CAP_MTRAP_EXIT, VM_CAP_PAUSE_EXIT, VM_CAP_UNRESTRICTED_GUEST, + VM_CAP_ENABLE_INVPCID, VM_CAP_MAX }; Property changes on: sys/amd64/include/vmm.h ___________________________________________________________________ Modified: svn:mergeinfo Merged /head/sys/amd64/include/vmm.h:r256645 Index: sys/amd64/vmm/intel/vmx.c =================================================================== --- sys/amd64/vmm/intel/vmx.c (revision 256860) +++ sys/amd64/vmm/intel/vmx.c (working copy) @@ -164,6 +164,7 @@ static int cap_pause_exit; static int cap_unrestricted_guest; static int cap_monitor_trap; +static int cap_invpcid; static struct unrhdr *vpid_unr; static u_int vpid_alloc_failed; @@ -660,6 +661,11 @@ PROCBASED2_UNRESTRICTED_GUEST, 0, &tmp) == 0); + cap_invpcid = (vmx_set_ctlreg(MSR_VMX_PROCBASED_CTLS2, + MSR_VMX_PROCBASED_CTLS2, PROCBASED2_ENABLE_INVPCID, 0, + &tmp) == 0); + + /* Initialize EPT */ error = ept_init(); if (error) { @@ -828,6 +834,7 @@ vmx->cap[i].set = 0; vmx->cap[i].proc_ctls = procbased_ctls; + vmx->cap[i].proc_ctls2 = procbased_ctls2; vmx->state[i].lastcpu = -1; vmx->state[i].vpid = vpid[i]; @@ -1932,6 +1939,10 @@ if (cap_unrestricted_guest) ret = 0; break; + case VM_CAP_ENABLE_INVPCID: + if (cap_invpcid) + ret = 0; + break; default: break; } @@ -1988,11 +1999,21 @@ case VM_CAP_UNRESTRICTED_GUEST: if (cap_unrestricted_guest) { retval = 0; - baseval = procbased_ctls2; + pptr = &vmx->cap[vcpu].proc_ctls2; + baseval = *pptr; flag = PROCBASED2_UNRESTRICTED_GUEST; reg = VMCS_SEC_PROC_BASED_CTLS; } break; + case VM_CAP_ENABLE_INVPCID: + if (cap_invpcid) { + retval = 0; + pptr = &vmx->cap[vcpu].proc_ctls2; + baseval = *pptr; + flag = PROCBASED2_ENABLE_INVPCID; + reg = VMCS_SEC_PROC_BASED_CTLS; + } + break; default: break; } Index: sys/amd64/vmm/intel/vmx.h =================================================================== --- sys/amd64/vmm/intel/vmx.h (revision 256860) +++ sys/amd64/vmm/intel/vmx.h (working copy) @@ -84,6 +84,7 @@ struct vmxcap { int set; uint32_t proc_ctls; + uint32_t proc_ctls2; }; struct vmxstate { Index: sys/amd64/vmm/intel/vmx_controls.h =================================================================== --- sys/amd64/vmm/intel/vmx_controls.h (revision 256860) +++ sys/amd64/vmm/intel/vmx_controls.h (working copy) @@ -68,6 +68,7 @@ #define PROCBASED2_WBINVD_EXITING (1 << 6) #define PROCBASED2_UNRESTRICTED_GUEST (1 << 7) #define PROCBASED2_PAUSE_LOOP_EXITING (1 << 10) +#define PROCBASED2_ENABLE_INVPCID (1 << 12) /* VM Exit Controls */ #define VM_EXIT_SAVE_DEBUG_CONTROLS (1 << 2) Index: sys/amd64/vmm/x86.c =================================================================== --- sys/amd64/vmm/x86.c (revision 256860) +++ sys/amd64/vmm/x86.c (working copy) @@ -53,7 +53,7 @@ x86_emulate_cpuid(struct vm *vm, int vcpu_id, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx) { - int error; + int error, enable_invpcid; unsigned int func, regs[4]; enum x2apic_state x2apic_state; @@ -202,8 +202,22 @@ regs[0] |= 0x04008000; break; + case CPUID_0000_0007: + regs[0] = 0; + regs[1] = 0; + regs[2] = 0; + regs[3] = 0; + + /* leaf 0 */ + if (*ecx == 0) { + error = vm_get_capability(vm, vcpu_id, + VM_CAP_ENABLE_INVPCID, &enable_invpcid); + if (error == 0 && enable_invpcid) + regs[1] |= CPUID_STDEXT_INVPCID; + } + break; + case CPUID_0000_0006: - case CPUID_0000_0007: case CPUID_0000_000A: case CPUID_0000_000D: /* Index: sys/amd64/vmm =================================================================== --- sys/amd64/vmm (revision 256860) +++ sys/amd64/vmm (working copy) Property changes on: sys/amd64/vmm ___________________________________________________________________ Modified: svn:mergeinfo Merged /head/sys/amd64/vmm:r256645 Index: sys =================================================================== --- sys (revision 256860) +++ sys (working copy) Property changes on: sys ___________________________________________________________________ Modified: svn:mergeinfo Merged /head/sys:r256645 Index: usr.sbin/bhyve/bhyverun.c =================================================================== --- usr.sbin/bhyve/bhyverun.c (revision 256860) +++ usr.sbin/bhyve/bhyverun.c (working copy) @@ -493,10 +493,54 @@ return (1); } +void +fbsdrun_set_capabilities(struct vmctx *ctx, int cpu) +{ + int err, tmp; + + if (fbsdrun_vmexit_on_hlt()) { + err = vm_get_capability(ctx, cpu, VM_CAP_HALT_EXIT, &tmp); + if (err < 0) { + fprintf(stderr, "VM exit on HLT not supported\n"); + exit(1); + } + vm_set_capability(ctx, cpu, VM_CAP_HALT_EXIT, 1); + if (cpu == BSP) + handler[VM_EXITCODE_HLT] = vmexit_hlt; + } + + if (fbsdrun_vmexit_on_pause()) { + /* + * pause exit support required for this mode + */ + err = vm_get_capability(ctx, cpu, VM_CAP_PAUSE_EXIT, &tmp); + if (err < 0) { + fprintf(stderr, + "SMP mux requested, no pause support\n"); + exit(1); + } + vm_set_capability(ctx, cpu, VM_CAP_PAUSE_EXIT, 1); + if (cpu == BSP) + handler[VM_EXITCODE_PAUSE] = vmexit_pause; + } + + if (fbsdrun_disable_x2apic()) + err = vm_set_x2apic_state(ctx, cpu, X2APIC_DISABLED); + else + err = vm_set_x2apic_state(ctx, cpu, X2APIC_ENABLED); + + if (err) { + fprintf(stderr, "Unable to set x2apic state (%d)\n", err); + exit(1); + } + + vm_set_capability(ctx, cpu, VM_CAP_ENABLE_INVPCID, 1); +} + int main(int argc, char *argv[]) { - int c, error, gdb_port, tmp, err, ioapic, bvmcons; + int c, error, gdb_port, err, ioapic, bvmcons; int max_vcpus; struct vmctx *ctx; uint64_t rip; @@ -586,40 +630,8 @@ exit(1); } - if (fbsdrun_vmexit_on_hlt()) { - err = vm_get_capability(ctx, BSP, VM_CAP_HALT_EXIT, &tmp); - if (err < 0) { - fprintf(stderr, "VM exit on HLT not supported\n"); - exit(1); - } - vm_set_capability(ctx, BSP, VM_CAP_HALT_EXIT, 1); - handler[VM_EXITCODE_HLT] = vmexit_hlt; - } + fbsdrun_set_capabilities(ctx, BSP); - if (fbsdrun_vmexit_on_pause()) { - /* - * pause exit support required for this mode - */ - err = vm_get_capability(ctx, BSP, VM_CAP_PAUSE_EXIT, &tmp); - if (err < 0) { - fprintf(stderr, - "SMP mux requested, no pause support\n"); - exit(1); - } - vm_set_capability(ctx, BSP, VM_CAP_PAUSE_EXIT, 1); - handler[VM_EXITCODE_PAUSE] = vmexit_pause; - } - - if (fbsdrun_disable_x2apic()) - err = vm_set_x2apic_state(ctx, BSP, X2APIC_DISABLED); - else - err = vm_set_x2apic_state(ctx, BSP, X2APIC_ENABLED); - - if (err) { - fprintf(stderr, "Unable to set x2apic state (%d)\n", err); - exit(1); - } - err = vm_setup_memory(ctx, memsize, VM_MMAP_ALL); if (err) { fprintf(stderr, "Unable to setup memory (%d)\n", err); Index: usr.sbin/bhyve/bhyverun.h =================================================================== --- usr.sbin/bhyve/bhyverun.h (revision 256860) +++ usr.sbin/bhyve/bhyverun.h (working copy) @@ -41,6 +41,7 @@ void *paddr_guest2host(struct vmctx *ctx, uintptr_t addr, size_t len); +void fbsdrun_set_capabilities(struct vmctx *ctx, int cpu); void fbsdrun_addcpu(struct vmctx *ctx, int cpu, uint64_t rip); int fbsdrun_muxed(void); int fbsdrun_vmexit_on_hlt(void); Index: usr.sbin/bhyve/spinup_ap.c =================================================================== --- usr.sbin/bhyve/spinup_ap.c (revision 256860) +++ usr.sbin/bhyve/spinup_ap.c (working copy) @@ -85,23 +85,8 @@ error = vcpu_reset(ctx, newcpu); assert(error == 0); - /* Set up capabilities */ - if (fbsdrun_vmexit_on_hlt()) { - error = vm_set_capability(ctx, newcpu, VM_CAP_HALT_EXIT, 1); - assert(error == 0); - } + fbsdrun_set_capabilities(ctx, newcpu); - if (fbsdrun_vmexit_on_pause()) { - error = vm_set_capability(ctx, newcpu, VM_CAP_PAUSE_EXIT, 1); - assert(error == 0); - } - - if (fbsdrun_disable_x2apic()) - error = vm_set_x2apic_state(ctx, newcpu, X2APIC_DISABLED); - else - error = vm_set_x2apic_state(ctx, newcpu, X2APIC_ENABLED); - assert(error == 0); - /* * Enable the 'unrestricted guest' mode for 'newcpu'. * Index: usr.sbin/bhyve =================================================================== --- usr.sbin/bhyve (revision 256860) +++ usr.sbin/bhyve (working copy) Property changes on: usr.sbin/bhyve ___________________________________________________________________ Modified: svn:mergeinfo Merged /head/usr.sbin/bhyve:r256645 Index: usr.sbin/bhyvectl/bhyvectl.c =================================================================== --- usr.sbin/bhyvectl/bhyvectl.c (revision 256860) +++ usr.sbin/bhyvectl/bhyvectl.c (working copy) @@ -1495,6 +1495,7 @@ vm_capability_type2name(captype), val ? "set" : "not set", vcpu); } else if (errno == ENOENT) { + error = 0; printf("Capability \"%s\" is not available\n", vm_capability_type2name(captype)); } else { Index: usr.sbin/bhyvectl =================================================================== --- usr.sbin/bhyvectl (revision 256860) +++ usr.sbin/bhyvectl (working copy) Property changes on: usr.sbin/bhyvectl ___________________________________________________________________ Modified: svn:mergeinfo Merged /head/usr.sbin/bhyvectl:r256645