- Output a summary of optional VT-x features in dmesg similar to CPU

features.  If bootverbose is enabled, a detailed list is provided;
  otherwise, a single-line summary is displayed.
- Add read-only sysctls for optional VT-x capabilities used by bhyve
  under a new hw.vmm.vmx.cap node. Move a few exiting sysctls that
  indicate the presence of optional capabilities under this node.

CR:		https://phabric.freebsd.org/D498
Reviewed by:	grehan, neel
MFC after:	1 week
This commit is contained in:
John Baldwin 2014-07-30 00:00:12 +00:00
parent 39c8c62ec4
commit 06fc6db948
5 changed files with 245 additions and 30 deletions

View File

@ -61,6 +61,7 @@ __FBSDID("$FreeBSD$");
#include <machine/specialreg.h>
#include <machine/md_var.h>
#include <amd64/vmm/intel/vmx_controls.h>
#include <x86/isa/icu.h>
/* XXX - should be in header file: */
@ -73,6 +74,7 @@ static u_int find_cpu_vendor_id(void);
static void print_AMD_info(void);
static void print_AMD_assoc(int i);
static void print_via_padlock_info(void);
static void print_vmx_info(void);
int cpu_class;
char machine[] = "amd64";
@ -428,6 +430,9 @@ printcpuinfo(void)
if (via_feature_rng != 0 || via_feature_xcrypt != 0)
print_via_padlock_info();
if (cpu_feature2 & CPUID2_VMX)
print_vmx_info();
if ((cpu_feature & CPUID_HTT) &&
cpu_vendor_id == CPU_VENDOR_AMD)
cpu_feature &= ~CPUID_HTT;
@ -722,3 +727,197 @@ print_via_padlock_info(void)
"\015RSA" /* PMM */
);
}
static uint32_t
vmx_settable(uint64_t basic, int msr, int true_msr)
{
uint64_t val;
if (basic & (1UL << 55))
val = rdmsr(true_msr);
else
val = rdmsr(msr);
/* Just report the controls that can be set to 1. */
return (val >> 32);
}
static void
print_vmx_info(void)
{
uint64_t basic, msr;
uint32_t entry, exit, mask, pin, proc, proc2;
int comma;
printf("\n VT-x: ");
msr = rdmsr(MSR_IA32_FEATURE_CONTROL);
if (!(msr & IA32_FEATURE_CONTROL_VMX_EN))
printf("(disabled in BIOS) ");
basic = rdmsr(MSR_VMX_BASIC);
pin = vmx_settable(basic, MSR_VMX_PINBASED_CTLS,
MSR_VMX_TRUE_PINBASED_CTLS);
proc = vmx_settable(basic, MSR_VMX_PROCBASED_CTLS,
MSR_VMX_TRUE_PROCBASED_CTLS);
if (proc & PROCBASED_SECONDARY_CONTROLS)
proc2 = vmx_settable(basic, MSR_VMX_PROCBASED_CTLS2,
MSR_VMX_PROCBASED_CTLS2);
else
proc2 = 0;
exit = vmx_settable(basic, MSR_VMX_EXIT_CTLS, MSR_VMX_TRUE_EXIT_CTLS);
entry = vmx_settable(basic, MSR_VMX_ENTRY_CTLS, MSR_VMX_TRUE_ENTRY_CTLS);
if (!bootverbose) {
comma = 0;
if (exit & VM_EXIT_SAVE_PAT && exit & VM_EXIT_LOAD_PAT &&
entry & VM_ENTRY_LOAD_PAT) {
printf("%sPAT", comma ? "," : "");
comma = 1;
}
if (proc & PROCBASED_HLT_EXITING) {
printf("%sHLT", comma ? "," : "");
comma = 1;
}
if (proc & PROCBASED_MTF) {
printf("%sMTF", comma ? "," : "");
comma = 1;
}
if (proc & PROCBASED_PAUSE_EXITING) {
printf("%sPAUSE", comma ? "," : "");
comma = 1;
}
if (proc2 & PROCBASED2_ENABLE_EPT) {
printf("%sEPT", comma ? "," : "");
comma = 1;
}
if (proc2 & PROCBASED2_UNRESTRICTED_GUEST) {
printf("%sUG", comma ? "," : "");
comma = 1;
}
if (proc2 & PROCBASED2_ENABLE_VPID) {
printf("%sVPID", comma ? "," : "");
comma = 1;
}
if (proc & PROCBASED_USE_TPR_SHADOW &&
proc2 & PROCBASED2_VIRTUALIZE_APIC_ACCESSES &&
proc2 & PROCBASED2_VIRTUALIZE_X2APIC_MODE &&
proc2 & PROCBASED2_APIC_REGISTER_VIRTUALIZATION &&
proc2 & PROCBASED2_VIRTUAL_INTERRUPT_DELIVERY) {
printf("%sVID", comma ? "," : "");
comma = 1;
if (pin & PINBASED_POSTED_INTERRUPT)
printf(",PostIntr");
}
return;
}
mask = basic >> 32;
printf("Basic Features=0x%b", mask,
"\020"
"\02132PA" /* 32-bit physical addresses */
"\022SMM" /* SMM dual-monitor */
"\027INS/OUTS" /* VM-exit info for INS and OUTS */
"\030TRUE" /* TRUE_CTLS MSRs */
);
printf("\n Pin-Based Controls=0x%b", pin,
"\020"
"\001ExtINT" /* External-interrupt exiting */
"\004NMI" /* NMI exiting */
"\006VNMI" /* Virtual NMIs */
"\007PreTmr" /* Activate VMX-preemption timer */
"\010PostIntr" /* Process posted interrupts */
);
printf("\n Primary Processor Controls=0x%b", proc,
"\020"
"\003INTWIN" /* Interrupt-window exiting */
"\004TSCOff" /* Use TSC offsetting */
"\010HLT" /* HLT exiting */
"\012INVLPG" /* INVLPG exiting */
"\013MWAIT" /* MWAIT exiting */
"\014RDPMC" /* RDPMC exiting */
"\015RDTSC" /* RDTSC exiting */
"\020CR3-LD" /* CR3-load exiting */
"\021CR3-ST" /* CR3-store exiting */
"\024CR8-LD" /* CR8-load exiting */
"\025CR8-ST" /* CR8-store exiting */
"\026TPR" /* Use TPR shadow */
"\027NMIWIN" /* NMI-window exiting */
"\030MOV-DR" /* MOV-DR exiting */
"\031IO" /* Unconditional I/O exiting */
"\032IOmap" /* Use I/O bitmaps */
"\034MTF" /* Monitor trap flag */
"\035MSRmap" /* Use MSR bitmaps */
"\036MONITOR" /* MONITOR exiting */
"\037PAUSE" /* PAUSE exiting */
);
if (proc & PROCBASED_SECONDARY_CONTROLS)
printf("\n Secondary Processor Controls=0x%b", proc2,
"\020"
"\001APIC" /* Virtualize APIC accesses */
"\002EPT" /* Enable EPT */
"\003DT" /* Descriptor-table exiting */
"\004RDTSCP" /* Enable RDTSCP */
"\005x2APIC" /* Virtualize x2APIC mode */
"\006VPID" /* Enable VPID */
"\007WBINVD" /* WBINVD exiting */
"\010UG" /* Unrestricted guest */
"\011APIC-reg" /* APIC-register virtualization */
"\012VID" /* Virtual-interrupt delivery */
"\013PAUSE-loop" /* PAUSE-loop exiting */
"\014RDRAND" /* RDRAND exiting */
"\015INVPCID" /* Enable INVPCID */
"\016VMFUNC" /* Enable VM functions */
"\017VMCS" /* VMCS shadowing */
"\020EPT#VE" /* EPT-violation #VE */
"\021XSAVES" /* Enable XSAVES/XRSTORS */
);
printf("\n Exit Controls=0x%b", mask,
"\020"
"\003DR" /* Save debug controls */
/* Ignore Host address-space size */
"\015PERF" /* Load MSR_PERF_GLOBAL_CTRL */
"\020AckInt" /* Acknowledge interrupt on exit */
"\023PAT-SV" /* Save MSR_PAT */
"\024PAT-LD" /* Load MSR_PAT */
"\025EFER-SV" /* Save MSR_EFER */
"\026EFER-LD" /* Load MSR_EFER */
"\027PTMR-SV" /* Save VMX-preemption timer value */
);
printf("\n Entry Controls=0x%b", mask,
"\020"
"\003DR" /* Save debug controls */
/* Ignore IA-32e mode guest */
/* Ignore Entry to SMM */
/* Ignore Deactivate dual-monitor treatment */
"\016PERF" /* Load MSR_PERF_GLOBAL_CTRL */
"\017PAT" /* Load MSR_PAT */
"\020EFER" /* Load MSR_EFER */
);
if (proc & PROCBASED_SECONDARY_CONTROLS &&
(proc2 & (PROCBASED2_ENABLE_EPT | PROCBASED2_ENABLE_VPID)) != 0) {
msr = rdmsr(MSR_VMX_EPT_VPID_CAP);
mask = msr;
printf("\n EPT Features=0x%b", mask,
"\020"
"\001XO" /* Execute-only translations */
"\007PW4" /* Page-walk length of 4 */
"\011UC" /* EPT paging-structure mem can be UC */
"\017WB" /* EPT paging-structure mem can be WB */
"\0212M" /* EPT PDE can map a 2-Mbyte page */
"\0221G" /* EPT PDPTE can map a 1-Gbyte page */
"\025INVEPT" /* INVEPT is supported */
"\026AD" /* Accessed and dirty flags for EPT */
"\032single" /* INVEPT single-context type */
"\033all" /* INVEPT all-context type */
);
mask = msr >> 32;
printf("\n VPID Features=0x%b", mask,
"\020"
"\001INVVPID" /* INVVPID is supported */
"\011individual" /* INVVPID individual-address type */
"\012single" /* INVVPID single-context type */
"\013all" /* INVVPID all-context type */
/* INVVPID single-context-retaining-globals type */
"\014single-globals"
);
}
}

View File

@ -149,8 +149,6 @@ SYSCTL_ULONG(_hw_vmm_vmx, OID_AUTO, cr4_ones_mask, CTLFLAG_RD,
SYSCTL_ULONG(_hw_vmm_vmx, OID_AUTO, cr4_zeros_mask, CTLFLAG_RD,
&cr4_zeros_mask, 0, NULL);
static int vmx_no_patmsr;
static int vmx_initialized;
SYSCTL_INT(_hw_vmm_vmx, OID_AUTO, initialized, CTLFLAG_RD,
&vmx_initialized, 0, "Intel VMX initialized");
@ -158,18 +156,38 @@ SYSCTL_INT(_hw_vmm_vmx, OID_AUTO, initialized, CTLFLAG_RD,
/*
* Optional capabilities
*/
static SYSCTL_NODE(_hw_vmm_vmx, OID_AUTO, cap, CTLFLAG_RW, NULL, NULL);
static int vmx_patmsr;
SYSCTL_INT(_hw_vmm_vmx_cap, OID_AUTO, patmsr, CTLFLAG_RD, &vmx_patmsr, 0,
"PAT MSR saved and restored in VCMS");
static int cap_halt_exit;
SYSCTL_INT(_hw_vmm_vmx_cap, OID_AUTO, halt_exit, CTLFLAG_RD, &cap_halt_exit, 0,
"HLT triggers a VM-exit");
static int cap_pause_exit;
SYSCTL_INT(_hw_vmm_vmx_cap, OID_AUTO, pause_exit, CTLFLAG_RD, &cap_pause_exit,
0, "PAUSE triggers a VM-exit");
static int cap_unrestricted_guest;
SYSCTL_INT(_hw_vmm_vmx_cap, OID_AUTO, unrestricted_guest, CTLFLAG_RD,
&cap_unrestricted_guest, 0, "Unrestricted guests");
static int cap_monitor_trap;
SYSCTL_INT(_hw_vmm_vmx_cap, OID_AUTO, monitor_trap, CTLFLAG_RD,
&cap_monitor_trap, 0, "Monitor trap flag");
static int cap_invpcid;
SYSCTL_INT(_hw_vmm_vmx_cap, OID_AUTO, invpcid, CTLFLAG_RD, &cap_invpcid,
0, "Guests are allowed to use INVPCID");
static int virtual_interrupt_delivery;
SYSCTL_INT(_hw_vmm_vmx, OID_AUTO, virtual_interrupt_delivery, CTLFLAG_RD,
SYSCTL_INT(_hw_vmm_vmx_cap, OID_AUTO, virtual_interrupt_delivery, CTLFLAG_RD,
&virtual_interrupt_delivery, 0, "APICv virtual interrupt delivery support");
static int posted_interrupts;
SYSCTL_INT(_hw_vmm_vmx, OID_AUTO, posted_interrupts, CTLFLAG_RD,
SYSCTL_INT(_hw_vmm_vmx_cap, OID_AUTO, posted_interrupts, CTLFLAG_RD,
&posted_interrupts, 0, "APICv posted interrupt support");
static int pirvec;
@ -618,6 +636,7 @@ vmx_init(int ipinum)
}
/* Check support for VM-exit controls */
vmx_patmsr = 1;
error = vmx_set_ctlreg(MSR_VMX_EXIT_CTLS, MSR_VMX_TRUE_EXIT_CTLS,
VM_EXIT_CTLS_ONE_SETTING,
VM_EXIT_CTLS_ZERO_SETTING,
@ -637,12 +656,12 @@ vmx_init(int ipinum)
if (bootverbose)
printf("vmm: PAT MSR access not supported\n");
guest_msr_valid(MSR_PAT);
vmx_no_patmsr = 1;
vmx_patmsr = 0;
}
}
/* Check support for VM-entry controls */
if (!vmx_no_patmsr) {
if (vmx_patmsr) {
error = vmx_set_ctlreg(MSR_VMX_ENTRY_CTLS,
MSR_VMX_TRUE_ENTRY_CTLS,
VM_ENTRY_CTLS_ONE_SETTING,
@ -918,7 +937,7 @@ vmx_vminit(struct vm *vm, pmap_t pmap)
* MSR_PAT save/restore support, leave access disabled so accesses
* will be trapped.
*/
if (!vmx_no_patmsr && guest_msr_rw(vmx, MSR_PAT))
if (vmx_patmsr && guest_msr_rw(vmx, MSR_PAT))
panic("vmx_vminit: error setting guest pat msr access");
vpid_alloc(vpid, VM_MAXCPU);

View File

@ -33,6 +33,7 @@ __FBSDID("$FreeBSD$");
#include <sys/systm.h>
#include <machine/cpufunc.h>
#include <machine/specialreg.h>
#include "vmx_msr.h"

View File

@ -29,29 +29,6 @@
#ifndef _VMX_MSR_H_
#define _VMX_MSR_H_
#define MSR_VMX_BASIC 0x480
#define MSR_VMX_EPT_VPID_CAP 0x48C
#define MSR_VMX_PROCBASED_CTLS 0x482
#define MSR_VMX_TRUE_PROCBASED_CTLS 0x48E
#define MSR_VMX_PINBASED_CTLS 0x481
#define MSR_VMX_TRUE_PINBASED_CTLS 0x48D
#define MSR_VMX_PROCBASED_CTLS2 0x48B
#define MSR_VMX_EXIT_CTLS 0x483
#define MSR_VMX_TRUE_EXIT_CTLS 0x48f
#define MSR_VMX_ENTRY_CTLS 0x484
#define MSR_VMX_TRUE_ENTRY_CTLS 0x490
#define MSR_VMX_CR0_FIXED0 0x486
#define MSR_VMX_CR0_FIXED1 0x487
#define MSR_VMX_CR4_FIXED0 0x488
#define MSR_VMX_CR4_FIXED1 0x489
uint32_t vmx_revision(void);
int vmx_set_ctlreg(int ctl_reg, int true_ctl_reg, uint32_t ones_mask,

View File

@ -435,6 +435,25 @@
#define MSR_MC4_ADDR 0x412
#define MSR_MC4_MISC 0x413
/*
* VMX MSRs
*/
#define MSR_VMX_BASIC 0x480
#define MSR_VMX_PINBASED_CTLS 0x481
#define MSR_VMX_PROCBASED_CTLS 0x482
#define MSR_VMX_EXIT_CTLS 0x483
#define MSR_VMX_ENTRY_CTLS 0x484
#define MSR_VMX_CR0_FIXED0 0x486
#define MSR_VMX_CR0_FIXED1 0x487
#define MSR_VMX_CR4_FIXED0 0x488
#define MSR_VMX_CR4_FIXED1 0x489
#define MSR_VMX_PROCBASED_CTLS2 0x48b
#define MSR_VMX_EPT_VPID_CAP 0x48c
#define MSR_VMX_TRUE_PINBASED_CTLS 0x48d
#define MSR_VMX_TRUE_PROCBASED_CTLS 0x48e
#define MSR_VMX_TRUE_EXIT_CTLS 0x48f
#define MSR_VMX_TRUE_ENTRY_CTLS 0x490
/*
* X2APIC MSRs
*/