3 # Jailhouse, a Linux-based partitioning hypervisor
5 # Copyright (c) Siemens AG, 2016
8 # Jan Kiszka <jan.kiszka@siemens.com>
10 # This work is licensed under the terms of the GNU GPL, version 2. See
11 # the COPYING file in the top-level directory.
13 from __future__ import print_function
23 def check_feature(msg, ok, optional=False):
24 if not (ok or optional):
27 print('%-32s%s' % (msg, 'ok' if ok else
28 ('missing (optional)' if optional else 'MISSING')))
36 with open('/proc/cpuinfo', 'r') as info:
40 key, value = line.split(':')
41 if key.strip() == 'vendor_id':
43 vendor = value.strip()
44 elif vendor != value.strip():
45 print('ERROR: Inconsistent vendor string on CPU %d' % cpus,
49 if key.strip() == 'flags':
51 features = value.strip().split(' ')
52 elif features != value.strip().split(' '):
53 print('ERROR: Inconsistent feature set on CPU %d' % cpus,
56 return (vendor, features, cpus)
60 IA32_FEATURE_CONTROL = 0x0000003a
61 IA32_VMX_BASIC = 0x00000480
62 IA32_VMX_PINBASED_CTLS = 0x00000481
63 IA32_VMX_PROCBASED_CTLS = 0x00000482
64 IA32_VMX_EXIT_CTLS = 0x00000483
65 IA32_VMX_ENTRY_CTLS = 0x00000484
66 IA32_VMX_MISC = 0x00000485
67 IA32_VMX_PROCBASED_CTLS2 = 0x0000048b
68 IA32_VMX_EPT_VPID_CAP = 0x0000048c
69 IA32_VMX_TRUE_PROCBASED_CTLS = 0x0000048e
71 def __init__(self, num_cpus):
72 self.num_cpus = num_cpus
74 for n in range(self.num_cpus):
75 self.msr.append(open('/dev/cpu/%d/msr' % n, 'rb', 0))
77 def read(self, index):
79 self.msr[0].seek(index)
80 value = struct.unpack('Q', self.msr[0].read(8))[0]
84 for n in range(1, self.num_cpus):
85 self.msr[n].seek(index)
86 if value != struct.unpack('Q', self.msr[n].read(8))[0]:
87 print('ERROR: Inconsistent value of MSR 0x%x on CPU %d' %
88 (index, n), file=sys.stderr)
94 def __init__(self, base, size):
95 f = os.open('/dev/mem', os.O_RDONLY | os.O_SYNC)
96 self.mmap = mmap.mmap(f, size, mmap.MAP_SHARED, mmap.PROT_READ,
99 def read64(self, offset):
100 self.mmap.seek(offset)
101 return struct.unpack('Q', self.mmap.read(8))[0]
108 X86_MMCFGBASE_SIZE = 8
109 X86_MMCFGENDBUS_SIZE = 1
112 X86_MAX_IOMMU_UNITS = 8
115 def __init__(self, path):
116 self.config = open(path, 'rb')
117 if self.config.read(Sysconfig.SIGNATURE_SIZE).decode() != 'JAILSYST':
118 print('Not a system configuration', file=sys.stderr)
121 def parse_iommus(self):
122 self.config.seek(Sysconfig.SIGNATURE_SIZE + Sysconfig.HVMEM_SIZE +
123 Sysconfig.DBGCON_SIZE + Sysconfig.X86_MMCFGBASE_SIZE +
124 Sysconfig.X86_MMCFGENDBUS_SIZE +
125 Sysconfig.X86_PADDING + Sysconfig.X86_PMTMR_SIZE)
127 keys = 'base size amd_bdf amd_base_cap amd_features'
128 IOMMU = collections.namedtuple('IOMMU', keys)
131 for n in range(Sysconfig.X86_MAX_IOMMU_UNITS):
132 data = self.config.read(Sysconfig.X86_IOMMU_SIZE)
133 iommu = IOMMU(*struct.unpack('QIHBxI', data))
138 def usage(exit_code):
139 prog = os.path.basename(sys.argv[0]).replace('-', ' ')
140 print('usage: %s SYSCONFIG' % prog)
144 if len(sys.argv) != 2:
146 if sys.argv[1] in ("--help", "-h"):
149 if os.uname()[4] not in ('x86_64', 'i686'):
150 print('Unsupported architecture', file=sys.stderr)
153 config = Sysconfig(sys.argv[1])
154 iommu = config.parse_iommus()
156 (cpu_vendor, cpu_features, cpu_count) = parse_cpuinfo()
158 if not os.access('/dev/cpu/0/msr', os.R_OK):
159 if os.system('/sbin/modprobe msr'):
164 print('Feature Availability')
165 print('------------------------------ ------------------')
166 check_feature('Number of CPUs > 1', cpu_count > 1)
167 check_feature('Long mode', 'lm' in cpu_features)
169 if cpu_vendor == 'GenuineIntel':
170 check_feature('x2APIC', 'x2apic' in cpu_features, True)
172 check_feature('VT-x (VMX)', 'vmx' in cpu_features)
174 feature = msr.read(MSR.IA32_FEATURE_CONTROL)
175 check_feature(' VMX without TXT',
176 (feature & (1 << 0)) == 0 or feature & (1 << 2))
177 check_feature(' IA32_TRUE_*_CLTS',
178 msr.read(MSR.IA32_VMX_BASIC) & (1 << 55))
180 pinbased = msr.read(MSR.IA32_VMX_PINBASED_CTLS) >> 32
181 check_feature(' NMI exiting', pinbased & (1 << 3))
182 check_feature(' Preemption timer', pinbased & (1 << 6))
184 procbased = msr.read(MSR.IA32_VMX_PROCBASED_CTLS) >> 32
185 check_feature(' I/O bitmap', procbased & (1 << 25))
186 check_feature(' MSR bitmap', procbased & (1 << 28))
187 check_feature(' Secondary controls', procbased & (1 << 31))
188 check_feature(' Optional CR3 interception',
189 (msr.read(MSR.IA32_VMX_TRUE_PROCBASED_CTLS) &
192 procbased2 = msr.read(MSR.IA32_VMX_PROCBASED_CTLS2) >> 32
193 check_feature(' Virtualize APIC access', procbased2 & (1 << 0))
194 check_feature(' RDTSCP', procbased2 & (1 << 3),
195 'rdtscp' not in cpu_features)
196 check_feature(' Unrestricted guest', procbased2 & (1 << 7))
198 check_feature(' EPT', procbased2 & (1 << 1))
199 ept_cap = msr.read(MSR.IA32_VMX_EPT_VPID_CAP)
200 check_feature(' 4-level page walk', ept_cap & (1 << 6))
201 check_feature(' EPTP write-back', ept_cap & (1 << 14))
202 check_feature(' 2M pages', ept_cap & (1 << 16), True)
203 check_feature(' 1G pages', ept_cap & (1 << 17), True)
204 check_feature(' INVEPT', ept_cap & (1 << 20))
205 check_feature(' Single or all-context', ept_cap & (3 << 25))
207 vmexit = msr.read(MSR.IA32_VMX_EXIT_CTLS) >> 32
208 check_feature(' VM-exit save IA32_PAT', vmexit & (1 << 18))
209 check_feature(' VM-exit load IA32_PAT', vmexit & (1 << 19))
210 check_feature(' VM-exit save IA32_EFER', vmexit & (1 << 20))
211 check_feature(' VM-exit load IA32_EFER', vmexit & (1 << 21))
213 vmentry = msr.read(MSR.IA32_VMX_ENTRY_CTLS) >> 32
214 check_feature(' VM-entry load IA32_PAT', vmentry & (1 << 14))
215 check_feature(' VM-entry load IA32_EFER', vmentry & (1 << 15))
216 check_feature(' Activity state HLT',
217 msr.read(MSR.IA32_VMX_MISC) & (1 << 6))
220 if iommu[n].base == 0 and n > 0:
223 check_feature('VT-d (IOMMU #%d)' % n, iommu[n].base)
224 if iommu[n].base == 0:
226 mmio = MMIO(iommu[n].base, iommu[n].size)
227 cap = mmio.read64(0x08)
228 check_feature(' Caching mode = 0', (cap & (1 << 7)) == 0)
229 check_feature(' 39-bit AGAW', cap & (1 << 9), cap & (1 << 10))
230 check_feature(' 48-bit AGAW', cap & (1 << 10), cap & (1 << 9))
231 check_feature(' 2M pages', cap & (1 << 34), True)
232 check_feature(' 1G pages', cap & (1 << 35), True)
233 ecap = mmio.read64(0x10)
234 check_feature(' Queued invalidation', ecap & (1 << 1))
235 check_feature(' Interrupt remapping', ecap & (1 << 3))
236 check_feature(' Extended interrupt mode', ecap & (1 << 4),
237 'x2apic' not in cpu_features)
239 elif cpu_vendor == 'AuthenticAMD':
241 check_feature('AMD-V (SVM)', 'svm' in cpu_features)
242 check_feature(' NPT', 'npt' in cpu_features)
243 check_feature(' Decode assist', 'decodeassists' in cpu_features, True)
244 check_feature(' AVIC', 'avic' in cpu_features, True)
245 check_feature(' Flush by ASID', 'flushbyasid' in cpu_features, True)
248 if iommu[n].base == 0 and n > 0:
251 check_feature('AMD-Vi (IOMMU #%d)' % n, iommu[n].base)
252 if iommu[n].base == 0:
255 bdf = iommu[n].amd_bdf
256 path = '/sys/bus/pci/devices/0000:%02x:%02x.%x/config' % \
257 (bdf >> 8, (bdf >> 3) & 0x1f, bdf & 0x7)
258 with open(path, 'rb') as config:
259 config.seek(iommu[n].amd_base_cap)
260 (caps, base) = struct.unpack('QQ', config.read(16))
262 check_feature(' Extended feature register', caps & (1 << 27))
263 check_feature(' Valid base register',
264 (base & (1 << 0)) == 0 or
265 base == (iommu[n].base | (1 << 0)))
267 mmio = MMIO(iommu[n].base, iommu[n].size)
268 efr = mmio.read64(0x30)
269 if check_feature(' SMI filter', ((efr >> 16) & 0x3) == 1):
271 num_filter_regs = 1 << ((efr >> 18) & 7)
272 for n in range(num_filter_regs):
273 smi_freg = mmio.read64(0x60 + (n << 3))
274 # must not be locked AND set to match against specific device
275 if smi_freg & (1 << 17) and smi_freg & (1 << 16):
276 smi_filter_ok = False
277 check_feature(' Valid filter registers', smi_filter_ok)
279 he_feature = iommu[n].amd_features if iommu[n].amd_features != 0 \
281 check_feature(' Hardware events', he_feature & (1 << 8), True)
284 print('Unsupported CPU', file=sys.stderr)
286 print('\nCheck %s!' % ('passed' if check_passed else 'FAILED'))
287 sys.exit(0 if check_passed else 2)