| #!/usr/bin/python |
| # |
| # 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 |
| |
| class msr(object): |
| def __init__(self): |
| try: |
| self.f = open('/dev/cpu/0/msr', 'r', 0) |
| except: |
| self.f = open('/dev/msr0', 'r', 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 |
| mbz, mb1 = self.read2(self.cap_msr) |
| tmbz, tmb1 = 0, 0 |
| if self.true_cap_msr: |
| tmbz, tmb1 = self.read2(self.true_cap_msr) |
| for bit in sorted(self.bits.keys()): |
| zero = not (mbz & (1 << bit)) |
| one = mb1 & (1 << bit) |
| true_zero = not (tmbz & (1 << bit)) |
| true_one = tmb1 & (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) |
| |
| 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) |
| 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, 31): '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', |
| }, |
| 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', |
| 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', |
| 18: 'EPT-violation #VE' |
| }, |
| cap_msr = MSR_IA32_VMX_PROCBASED_CTLS2, |
| ), |
| |
| 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', |
| }, |
| 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-64 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', |
| }, |
| 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', |
| 15: 'IA32_SMBASE support', |
| (16,24): 'Number of CR3-target values', |
| (25,27): 'MSR-load/store count recommenation', |
| 28: 'IA32_SMM_MONITOR_CTL[2] can be set to 1', |
| 29: 'VMWRITE to VM-exit information fields', |
| (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', |
| 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', |
| 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, |
| ), |
| ] |
| |
| for c in controls: |
| c.show() |