#!/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', 'rb', 0)
except:
self.f = open('/dev/msr0', 'rb', 0)
def read(self, index, default = None):
import struct
# file.seek(offset): 能将文件的初始指针指向文件中offset的位置.
self.f.seek(index) # 实际调用时,将msr文件的指针指向对应msr处,如MSR_IA32_VMX_EPT_VPID_CAP处
try:
return struct.unpack('Q', self.f.read(8))[0] # 从指定msr中读取8字节数据(64bit).之所以要置0,是因为.unpack返回的是元组.
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):
# mb means low 32bits. cb means high 32bits.
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()): # sorted(list/tuple):将list/tuple中的数据从小到大排列,返回一个list/tuple
zero = not (mb1 & (1 << bit)) # zero=1 means this control bit can be 0, zero=0 means this control bit cannot be 0
one = cb1 & (1 << bit) # one=1 means this control bit can be 1, one=0 means this control bit cannot be 1
true_zero = not (tmb1 & (1 << bit)) # function means same as zero
true_one = tcb1 & (1 << bit) # function means same as one
s= '?'
if (self.true_cap_msr and true_zero and true_one
and one and not zero): # 如果***TRUE*** MSR存在,从该MSR获得的信息是可置0可置1,从无TRUE MSR获得的信息是可置1不可置0.那么该
# contrl是一个default1 class,并且可置0可置1.
s = 'default'
elif zero and not one: # 如果从无TRUE MSR获得的信息是可置0不可置1,那么该control是一个当前CPU不支持的control.
s = 'no'
elif one and not zero: # 如果从无TRUE MSR中获得的信息是可置1不可置0,那么该control是一个强制置1control.
s = 'forced'
elif one and zero: # 如果从无TRUE MSR中获得的信息是可置1可置0,那么该control是一个当前CPU支持的control.
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)
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',
},
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',
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,
),
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',
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,
),
]
for c in controls:
c.show()