|  | #!/usr/bin/env python3 | 
|  | # | 
|  | # tool for querying VMX capabilities | 
|  | # | 
|  | # Copyright 2009-2010 Red Hat, Inc. | 
|  | # | 
|  | # Authors: | 
|  | #  Avi Kivity <avi@redhat.com> | 
|  | # | 
|  | # This work is licensed under the terms of the GNU GPL, version 2.  See | 
|  | # the COPYING file in the top-level directory. | 
|  |  | 
|  | MSR_IA32_VMX_BASIC = 0x480 | 
|  | MSR_IA32_VMX_PINBASED_CTLS = 0x481 | 
|  | MSR_IA32_VMX_PROCBASED_CTLS = 0x482 | 
|  | MSR_IA32_VMX_EXIT_CTLS = 0x483 | 
|  | MSR_IA32_VMX_ENTRY_CTLS = 0x484 | 
|  | MSR_IA32_VMX_MISC_CTLS = 0x485 | 
|  | MSR_IA32_VMX_PROCBASED_CTLS2 = 0x48B | 
|  | MSR_IA32_VMX_EPT_VPID_CAP = 0x48C | 
|  | MSR_IA32_VMX_TRUE_PINBASED_CTLS = 0x48D | 
|  | MSR_IA32_VMX_TRUE_PROCBASED_CTLS = 0x48E | 
|  | MSR_IA32_VMX_TRUE_EXIT_CTLS = 0x48F | 
|  | MSR_IA32_VMX_TRUE_ENTRY_CTLS = 0x490 | 
|  | MSR_IA32_VMX_VMFUNC = 0x491 | 
|  | MSR_IA32_VMX_PROCBASED_CTLS3 = 0x492 | 
|  |  | 
|  | class msr(object): | 
|  | def __init__(self): | 
|  | try: | 
|  | self.f = open('/dev/cpu/0/msr', 'rb', 0) | 
|  | except: | 
|  | self.f = open('/dev/msr0', 'rb', 0) | 
|  | def read(self, index, default = None): | 
|  | import struct | 
|  | self.f.seek(index) | 
|  | try: | 
|  | return struct.unpack('Q', self.f.read(8))[0] | 
|  | except: | 
|  | return default | 
|  |  | 
|  | class Control(object): | 
|  | def __init__(self, name, bits, cap_msr, true_cap_msr = None): | 
|  | self.name = name | 
|  | self.bits = bits | 
|  | self.cap_msr = cap_msr | 
|  | self.true_cap_msr = true_cap_msr | 
|  | def read2(self, nr): | 
|  | m = msr() | 
|  | val = m.read(nr, 0) | 
|  | return (val & 0xffffffff, val >> 32) | 
|  | def show(self): | 
|  | print(self.name) | 
|  | mb1, cb1 = self.read2(self.cap_msr) | 
|  | tmb1, tcb1 = 0, 0 | 
|  | if self.true_cap_msr: | 
|  | tmb1, tcb1 = self.read2(self.true_cap_msr) | 
|  | for bit in sorted(self.bits.keys()): | 
|  | zero = not (mb1 & (1 << bit)) | 
|  | one = cb1 & (1 << bit) | 
|  | true_zero = not (tmb1 & (1 << bit)) | 
|  | true_one = tcb1 & (1 << bit) | 
|  | s= '?' | 
|  | if (self.true_cap_msr and true_zero and true_one | 
|  | and one and not zero): | 
|  | s = 'default' | 
|  | elif zero and not one: | 
|  | s = 'no' | 
|  | elif one and not zero: | 
|  | s = 'forced' | 
|  | elif one and zero: | 
|  | s = 'yes' | 
|  | print('  %-40s %s' % (self.bits[bit], s)) | 
|  |  | 
|  | # All 64 bits in the tertiary controls MSR are allowed-1 | 
|  | class Allowed1Control(Control): | 
|  | def read2(self, nr): | 
|  | m = msr() | 
|  | val = m.read(nr, 0) | 
|  | return (0, val) | 
|  |  | 
|  | class Misc(object): | 
|  | def __init__(self, name, bits, msr): | 
|  | self.name = name | 
|  | self.bits = bits | 
|  | self.msr = msr | 
|  | def show(self): | 
|  | print(self.name) | 
|  | value = msr().read(self.msr, 0) | 
|  | print('  Hex: 0x%x' % (value)) | 
|  | def first_bit(key): | 
|  | if type(key) is tuple: | 
|  | return key[0] | 
|  | else: | 
|  | return key | 
|  | for bits in sorted(self.bits.keys(), key = first_bit): | 
|  | if type(bits) is tuple: | 
|  | lo, hi = bits | 
|  | fmt = int | 
|  | else: | 
|  | lo = hi = bits | 
|  | def fmt(x): | 
|  | return { True: 'yes', False: 'no' }[x] | 
|  | v = (value >> lo) & ((1 << (hi - lo + 1)) - 1) | 
|  | print('  %-40s %s' % (self.bits[bits], fmt(v))) | 
|  |  | 
|  | controls = [ | 
|  | Misc( | 
|  | name = 'Basic VMX Information', | 
|  | bits = { | 
|  | (0, 30): 'Revision', | 
|  | (32,44): 'VMCS size', | 
|  | 48: 'VMCS restricted to 32 bit addresses', | 
|  | 49: 'Dual-monitor support', | 
|  | (50, 53): 'VMCS memory type', | 
|  | 54: 'INS/OUTS instruction information', | 
|  | 55: 'IA32_VMX_TRUE_*_CTLS support', | 
|  | 56: 'Skip checks on event error code', | 
|  | }, | 
|  | msr = MSR_IA32_VMX_BASIC, | 
|  | ), | 
|  | Control( | 
|  | name = 'pin-based controls', | 
|  | bits = { | 
|  | 0: 'External interrupt exiting', | 
|  | 3: 'NMI exiting', | 
|  | 5: 'Virtual NMIs', | 
|  | 6: 'Activate VMX-preemption timer', | 
|  | 7: 'Process posted interrupts', | 
|  | }, | 
|  | cap_msr = MSR_IA32_VMX_PINBASED_CTLS, | 
|  | true_cap_msr = MSR_IA32_VMX_TRUE_PINBASED_CTLS, | 
|  | ), | 
|  |  | 
|  | Control( | 
|  | name = 'primary processor-based controls', | 
|  | bits = { | 
|  | 2: 'Interrupt window exiting', | 
|  | 3: 'Use TSC offsetting', | 
|  | 7: 'HLT exiting', | 
|  | 9: 'INVLPG exiting', | 
|  | 10: 'MWAIT exiting', | 
|  | 11: 'RDPMC exiting', | 
|  | 12: 'RDTSC exiting', | 
|  | 15: 'CR3-load exiting', | 
|  | 16: 'CR3-store exiting', | 
|  | 17: 'Activate tertiary controls', | 
|  | 19: 'CR8-load exiting', | 
|  | 20: 'CR8-store exiting', | 
|  | 21: 'Use TPR shadow', | 
|  | 22: 'NMI-window exiting', | 
|  | 23: 'MOV-DR exiting', | 
|  | 24: 'Unconditional I/O exiting', | 
|  | 25: 'Use I/O bitmaps', | 
|  | 27: 'Monitor trap flag', | 
|  | 28: 'Use MSR bitmaps', | 
|  | 29: 'MONITOR exiting', | 
|  | 30: 'PAUSE exiting', | 
|  | 31: 'Activate secondary control', | 
|  | }, | 
|  | cap_msr = MSR_IA32_VMX_PROCBASED_CTLS, | 
|  | true_cap_msr = MSR_IA32_VMX_TRUE_PROCBASED_CTLS, | 
|  | ), | 
|  |  | 
|  | Control( | 
|  | name = 'secondary processor-based controls', | 
|  | bits = { | 
|  | 0: 'Virtualize APIC accesses', | 
|  | 1: 'Enable EPT', | 
|  | 2: 'Descriptor-table exiting', | 
|  | 3: 'Enable RDTSCP', | 
|  | 4: 'Virtualize x2APIC mode', | 
|  | 5: 'Enable VPID', | 
|  | 6: 'WBINVD exiting', | 
|  | 7: 'Unrestricted guest', | 
|  | 8: 'APIC register emulation', | 
|  | 9: 'Virtual interrupt delivery', | 
|  | 10: 'PAUSE-loop exiting', | 
|  | 11: 'RDRAND exiting', | 
|  | 12: 'Enable INVPCID', | 
|  | 13: 'Enable VM functions', | 
|  | 14: 'VMCS shadowing', | 
|  | 15: 'Enable ENCLS exiting', | 
|  | 16: 'RDSEED exiting', | 
|  | 17: 'Enable PML', | 
|  | 18: 'EPT-violation #VE', | 
|  | 19: 'Conceal non-root operation from PT', | 
|  | 20: 'Enable XSAVES/XRSTORS', | 
|  | 22: 'Mode-based execute control (XS/XU)', | 
|  | 23: 'Sub-page write permissions', | 
|  | 24: 'GPA translation for PT', | 
|  | 25: 'TSC scaling', | 
|  | 26: 'User wait and pause', | 
|  | 28: 'ENCLV exiting', | 
|  | }, | 
|  | cap_msr = MSR_IA32_VMX_PROCBASED_CTLS2, | 
|  | ), | 
|  |  | 
|  | Allowed1Control( | 
|  | name = 'tertiary processor-based controls', | 
|  | bits = { | 
|  | 4: 'Enable IPI virtualization' | 
|  | }, | 
|  | cap_msr = MSR_IA32_VMX_PROCBASED_CTLS3, | 
|  | ), | 
|  |  | 
|  | Control( | 
|  | name = 'VM-Exit controls', | 
|  | bits = { | 
|  | 2: 'Save debug controls', | 
|  | 9: 'Host address-space size', | 
|  | 12: 'Load IA32_PERF_GLOBAL_CTRL', | 
|  | 15: 'Acknowledge interrupt on exit', | 
|  | 18: 'Save IA32_PAT', | 
|  | 19: 'Load IA32_PAT', | 
|  | 20: 'Save IA32_EFER', | 
|  | 21: 'Load IA32_EFER', | 
|  | 22: 'Save VMX-preemption timer value', | 
|  | 23: 'Clear IA32_BNDCFGS', | 
|  | 24: 'Conceal VM exits from PT', | 
|  | 25: 'Clear IA32_RTIT_CTL', | 
|  | }, | 
|  | cap_msr = MSR_IA32_VMX_EXIT_CTLS, | 
|  | true_cap_msr = MSR_IA32_VMX_TRUE_EXIT_CTLS, | 
|  | ), | 
|  |  | 
|  | Control( | 
|  | name = 'VM-Entry controls', | 
|  | bits = { | 
|  | 2: 'Load debug controls', | 
|  | 9: 'IA-32e mode guest', | 
|  | 10: 'Entry to SMM', | 
|  | 11: 'Deactivate dual-monitor treatment', | 
|  | 13: 'Load IA32_PERF_GLOBAL_CTRL', | 
|  | 14: 'Load IA32_PAT', | 
|  | 15: 'Load IA32_EFER', | 
|  | 16: 'Load IA32_BNDCFGS', | 
|  | 17: 'Conceal VM entries from PT', | 
|  | 18: 'Load IA32_RTIT_CTL', | 
|  | }, | 
|  | cap_msr = MSR_IA32_VMX_ENTRY_CTLS, | 
|  | true_cap_msr = MSR_IA32_VMX_TRUE_ENTRY_CTLS, | 
|  | ), | 
|  |  | 
|  | Misc( | 
|  | name = 'Miscellaneous data', | 
|  | bits = { | 
|  | (0,4): 'VMX-preemption timer scale (log2)', | 
|  | 5: 'Store EFER.LMA into IA-32e mode guest control', | 
|  | 6: 'HLT activity state', | 
|  | 7: 'Shutdown activity state', | 
|  | 8: 'Wait-for-SIPI activity state', | 
|  | 14: 'PT in VMX operation', | 
|  | 15: 'IA32_SMBASE support', | 
|  | (16,24): 'Number of CR3-target values', | 
|  | (25,27): 'MSR-load/store count recommendation', | 
|  | 28: 'IA32_SMM_MONITOR_CTL[2] can be set to 1', | 
|  | 29: 'VMWRITE to VM-exit information fields', | 
|  | 30: 'Inject event with insn length=0', | 
|  | (32,63): 'MSEG revision identifier', | 
|  | }, | 
|  | msr = MSR_IA32_VMX_MISC_CTLS, | 
|  | ), | 
|  |  | 
|  | Misc( | 
|  | name = 'VPID and EPT capabilities', | 
|  | bits = { | 
|  | 0: 'Execute-only EPT translations', | 
|  | 6: 'Page-walk length 4', | 
|  | 7: 'Page-walk length 5', | 
|  | 8: 'Paging-structure memory type UC', | 
|  | 14: 'Paging-structure memory type WB', | 
|  | 16: '2MB EPT pages', | 
|  | 17: '1GB EPT pages', | 
|  | 20: 'INVEPT supported', | 
|  | 21: 'EPT accessed and dirty flags', | 
|  | 22: 'Advanced VM-exit information for EPT violations', | 
|  | 25: 'Single-context INVEPT', | 
|  | 26: 'All-context INVEPT', | 
|  | 32: 'INVVPID supported', | 
|  | 40: 'Individual-address INVVPID', | 
|  | 41: 'Single-context INVVPID', | 
|  | 42: 'All-context INVVPID', | 
|  | 43: 'Single-context-retaining-globals INVVPID', | 
|  | }, | 
|  | msr = MSR_IA32_VMX_EPT_VPID_CAP, | 
|  | ), | 
|  | Misc( | 
|  | name = 'VM Functions', | 
|  | bits = { | 
|  | 0: 'EPTP Switching', | 
|  | }, | 
|  | msr = MSR_IA32_VMX_VMFUNC, | 
|  | ), | 
|  | ] | 
|  |  | 
|  | if __name__ == '__main__': | 
|  | for c in controls: | 
|  | c.show() |