Philippe Mathieu-Daudé | e57a707 | 2020-05-12 12:32:36 +0200 | [diff] [blame] | 1 | #!/usr/bin/env python3 |
Jan Kiszka | 5f6caa4 | 2011-10-07 09:37:57 +0200 | [diff] [blame] | 2 | # |
| 3 | # tool for querying VMX capabilities |
| 4 | # |
| 5 | # Copyright 2009-2010 Red Hat, Inc. |
| 6 | # |
| 7 | # Authors: |
| 8 | # Avi Kivity <avi@redhat.com> |
| 9 | # |
| 10 | # This work is licensed under the terms of the GNU GPL, version 2. See |
| 11 | # the COPYING file in the top-level directory. |
| 12 | |
| 13 | MSR_IA32_VMX_BASIC = 0x480 |
| 14 | MSR_IA32_VMX_PINBASED_CTLS = 0x481 |
| 15 | MSR_IA32_VMX_PROCBASED_CTLS = 0x482 |
| 16 | MSR_IA32_VMX_EXIT_CTLS = 0x483 |
| 17 | MSR_IA32_VMX_ENTRY_CTLS = 0x484 |
| 18 | MSR_IA32_VMX_MISC_CTLS = 0x485 |
| 19 | MSR_IA32_VMX_PROCBASED_CTLS2 = 0x48B |
| 20 | MSR_IA32_VMX_EPT_VPID_CAP = 0x48C |
| 21 | MSR_IA32_VMX_TRUE_PINBASED_CTLS = 0x48D |
| 22 | MSR_IA32_VMX_TRUE_PROCBASED_CTLS = 0x48E |
| 23 | MSR_IA32_VMX_TRUE_EXIT_CTLS = 0x48F |
| 24 | MSR_IA32_VMX_TRUE_ENTRY_CTLS = 0x490 |
Avi Kivity | 287d55c | 2012-05-16 14:31:37 +0300 | [diff] [blame] | 25 | MSR_IA32_VMX_VMFUNC = 0x491 |
Paolo Bonzini | 333dbac | 2022-05-11 18:39:12 +0200 | [diff] [blame] | 26 | MSR_IA32_VMX_PROCBASED_CTLS3 = 0x492 |
Xin Li | 2e64187 | 2023-11-08 23:20:10 -0800 | [diff] [blame] | 27 | MSR_IA32_VMX_EXIT_CTLS2 = 0x493 |
Jan Kiszka | 5f6caa4 | 2011-10-07 09:37:57 +0200 | [diff] [blame] | 28 | |
| 29 | class msr(object): |
| 30 | def __init__(self): |
| 31 | try: |
Paolo Bonzini | c3e31ea | 2017-02-21 09:29:34 +0100 | [diff] [blame] | 32 | self.f = open('/dev/cpu/0/msr', 'rb', 0) |
Jan Kiszka | 5f6caa4 | 2011-10-07 09:37:57 +0200 | [diff] [blame] | 33 | except: |
Paolo Bonzini | c3e31ea | 2017-02-21 09:29:34 +0100 | [diff] [blame] | 34 | self.f = open('/dev/msr0', 'rb', 0) |
Jan Kiszka | 5f6caa4 | 2011-10-07 09:37:57 +0200 | [diff] [blame] | 35 | def read(self, index, default = None): |
| 36 | import struct |
| 37 | self.f.seek(index) |
| 38 | try: |
| 39 | return struct.unpack('Q', self.f.read(8))[0] |
| 40 | except: |
| 41 | return default |
| 42 | |
| 43 | class Control(object): |
| 44 | def __init__(self, name, bits, cap_msr, true_cap_msr = None): |
| 45 | self.name = name |
| 46 | self.bits = bits |
| 47 | self.cap_msr = cap_msr |
| 48 | self.true_cap_msr = true_cap_msr |
| 49 | def read2(self, nr): |
| 50 | m = msr() |
| 51 | val = m.read(nr, 0) |
| 52 | return (val & 0xffffffff, val >> 32) |
| 53 | def show(self): |
Paolo Bonzini | c3e31ea | 2017-02-21 09:29:34 +0100 | [diff] [blame] | 54 | print(self.name) |
Paolo Bonzini | 49d51b8 | 2019-07-01 16:51:24 +0200 | [diff] [blame] | 55 | mb1, cb1 = self.read2(self.cap_msr) |
| 56 | tmb1, tcb1 = 0, 0 |
Jan Kiszka | 5f6caa4 | 2011-10-07 09:37:57 +0200 | [diff] [blame] | 57 | if self.true_cap_msr: |
Paolo Bonzini | 49d51b8 | 2019-07-01 16:51:24 +0200 | [diff] [blame] | 58 | tmb1, tcb1 = self.read2(self.true_cap_msr) |
Jan Kiszka | 5f6caa4 | 2011-10-07 09:37:57 +0200 | [diff] [blame] | 59 | for bit in sorted(self.bits.keys()): |
Paolo Bonzini | 49d51b8 | 2019-07-01 16:51:24 +0200 | [diff] [blame] | 60 | zero = not (mb1 & (1 << bit)) |
| 61 | one = cb1 & (1 << bit) |
| 62 | true_zero = not (tmb1 & (1 << bit)) |
| 63 | true_one = tcb1 & (1 << bit) |
Jan Kiszka | 5f6caa4 | 2011-10-07 09:37:57 +0200 | [diff] [blame] | 64 | s= '?' |
| 65 | if (self.true_cap_msr and true_zero and true_one |
| 66 | and one and not zero): |
| 67 | s = 'default' |
| 68 | elif zero and not one: |
| 69 | s = 'no' |
| 70 | elif one and not zero: |
| 71 | s = 'forced' |
| 72 | elif one and zero: |
| 73 | s = 'yes' |
Paolo Bonzini | c3e31ea | 2017-02-21 09:29:34 +0100 | [diff] [blame] | 74 | print(' %-40s %s' % (self.bits[bit], s)) |
Jan Kiszka | 5f6caa4 | 2011-10-07 09:37:57 +0200 | [diff] [blame] | 75 | |
Paolo Bonzini | 333dbac | 2022-05-11 18:39:12 +0200 | [diff] [blame] | 76 | # All 64 bits in the tertiary controls MSR are allowed-1 |
| 77 | class Allowed1Control(Control): |
| 78 | def read2(self, nr): |
| 79 | m = msr() |
| 80 | val = m.read(nr, 0) |
| 81 | return (0, val) |
| 82 | |
Jan Kiszka | 5f6caa4 | 2011-10-07 09:37:57 +0200 | [diff] [blame] | 83 | class Misc(object): |
| 84 | def __init__(self, name, bits, msr): |
| 85 | self.name = name |
| 86 | self.bits = bits |
| 87 | self.msr = msr |
| 88 | def show(self): |
Paolo Bonzini | c3e31ea | 2017-02-21 09:29:34 +0100 | [diff] [blame] | 89 | print(self.name) |
Jan Kiszka | 5f6caa4 | 2011-10-07 09:37:57 +0200 | [diff] [blame] | 90 | value = msr().read(self.msr, 0) |
Paolo Bonzini | c3e31ea | 2017-02-21 09:29:34 +0100 | [diff] [blame] | 91 | print(' Hex: 0x%x' % (value)) |
Jan Kiszka | 5f6caa4 | 2011-10-07 09:37:57 +0200 | [diff] [blame] | 92 | def first_bit(key): |
| 93 | if type(key) is tuple: |
| 94 | return key[0] |
| 95 | else: |
| 96 | return key |
| 97 | for bits in sorted(self.bits.keys(), key = first_bit): |
| 98 | if type(bits) is tuple: |
| 99 | lo, hi = bits |
| 100 | fmt = int |
| 101 | else: |
| 102 | lo = hi = bits |
| 103 | def fmt(x): |
| 104 | return { True: 'yes', False: 'no' }[x] |
| 105 | v = (value >> lo) & ((1 << (hi - lo + 1)) - 1) |
Paolo Bonzini | c3e31ea | 2017-02-21 09:29:34 +0100 | [diff] [blame] | 106 | print(' %-40s %s' % (self.bits[bits], fmt(v))) |
Jan Kiszka | 5f6caa4 | 2011-10-07 09:37:57 +0200 | [diff] [blame] | 107 | |
| 108 | controls = [ |
Jan Kiszka | ea4ee28 | 2013-02-13 12:44:06 +0100 | [diff] [blame] | 109 | Misc( |
| 110 | name = 'Basic VMX Information', |
| 111 | bits = { |
Adrian-Ken Rueegsegger | c5d1e2c | 2014-09-17 20:54:11 +0200 | [diff] [blame] | 112 | (0, 30): 'Revision', |
Jan Kiszka | ea4ee28 | 2013-02-13 12:44:06 +0100 | [diff] [blame] | 113 | (32,44): 'VMCS size', |
| 114 | 48: 'VMCS restricted to 32 bit addresses', |
| 115 | 49: 'Dual-monitor support', |
| 116 | (50, 53): 'VMCS memory type', |
| 117 | 54: 'INS/OUTS instruction information', |
| 118 | 55: 'IA32_VMX_TRUE_*_CTLS support', |
Paolo Bonzini | 0c49c91 | 2023-09-20 17:41:17 +0200 | [diff] [blame] | 119 | 56: 'Skip checks on event error code', |
Xin Li | ef202d6 | 2023-11-08 23:20:11 -0800 | [diff] [blame] | 120 | 58: 'VMX nested exception support', |
Jan Kiszka | ea4ee28 | 2013-02-13 12:44:06 +0100 | [diff] [blame] | 121 | }, |
| 122 | msr = MSR_IA32_VMX_BASIC, |
| 123 | ), |
Jan Kiszka | 5f6caa4 | 2011-10-07 09:37:57 +0200 | [diff] [blame] | 124 | Control( |
| 125 | name = 'pin-based controls', |
| 126 | bits = { |
| 127 | 0: 'External interrupt exiting', |
| 128 | 3: 'NMI exiting', |
| 129 | 5: 'Virtual NMIs', |
| 130 | 6: 'Activate VMX-preemption timer', |
Jan Kiszka | ea4ee28 | 2013-02-13 12:44:06 +0100 | [diff] [blame] | 131 | 7: 'Process posted interrupts', |
Jan Kiszka | 5f6caa4 | 2011-10-07 09:37:57 +0200 | [diff] [blame] | 132 | }, |
| 133 | cap_msr = MSR_IA32_VMX_PINBASED_CTLS, |
| 134 | true_cap_msr = MSR_IA32_VMX_TRUE_PINBASED_CTLS, |
| 135 | ), |
| 136 | |
| 137 | Control( |
| 138 | name = 'primary processor-based controls', |
| 139 | bits = { |
| 140 | 2: 'Interrupt window exiting', |
| 141 | 3: 'Use TSC offsetting', |
| 142 | 7: 'HLT exiting', |
| 143 | 9: 'INVLPG exiting', |
| 144 | 10: 'MWAIT exiting', |
| 145 | 11: 'RDPMC exiting', |
| 146 | 12: 'RDTSC exiting', |
| 147 | 15: 'CR3-load exiting', |
| 148 | 16: 'CR3-store exiting', |
Paolo Bonzini | 333dbac | 2022-05-11 18:39:12 +0200 | [diff] [blame] | 149 | 17: 'Activate tertiary controls', |
Jan Kiszka | 5f6caa4 | 2011-10-07 09:37:57 +0200 | [diff] [blame] | 150 | 19: 'CR8-load exiting', |
| 151 | 20: 'CR8-store exiting', |
| 152 | 21: 'Use TPR shadow', |
| 153 | 22: 'NMI-window exiting', |
| 154 | 23: 'MOV-DR exiting', |
| 155 | 24: 'Unconditional I/O exiting', |
| 156 | 25: 'Use I/O bitmaps', |
| 157 | 27: 'Monitor trap flag', |
| 158 | 28: 'Use MSR bitmaps', |
| 159 | 29: 'MONITOR exiting', |
| 160 | 30: 'PAUSE exiting', |
| 161 | 31: 'Activate secondary control', |
| 162 | }, |
| 163 | cap_msr = MSR_IA32_VMX_PROCBASED_CTLS, |
| 164 | true_cap_msr = MSR_IA32_VMX_TRUE_PROCBASED_CTLS, |
| 165 | ), |
| 166 | |
| 167 | Control( |
| 168 | name = 'secondary processor-based controls', |
| 169 | bits = { |
| 170 | 0: 'Virtualize APIC accesses', |
| 171 | 1: 'Enable EPT', |
| 172 | 2: 'Descriptor-table exiting', |
Jan Kiszka | 614413f | 2013-02-18 07:56:54 +0100 | [diff] [blame] | 173 | 3: 'Enable RDTSCP', |
Jan Kiszka | 5f6caa4 | 2011-10-07 09:37:57 +0200 | [diff] [blame] | 174 | 4: 'Virtualize x2APIC mode', |
| 175 | 5: 'Enable VPID', |
| 176 | 6: 'WBINVD exiting', |
| 177 | 7: 'Unrestricted guest', |
Jan Kiszka | 614413f | 2013-02-18 07:56:54 +0100 | [diff] [blame] | 178 | 8: 'APIC register emulation', |
Marcelo Tosatti | f9e90c7 | 2013-01-10 23:02:48 -0200 | [diff] [blame] | 179 | 9: 'Virtual interrupt delivery', |
Jan Kiszka | 5f6caa4 | 2011-10-07 09:37:57 +0200 | [diff] [blame] | 180 | 10: 'PAUSE-loop exiting', |
Avi Kivity | 287d55c | 2012-05-16 14:31:37 +0300 | [diff] [blame] | 181 | 11: 'RDRAND exiting', |
| 182 | 12: 'Enable INVPCID', |
| 183 | 13: 'Enable VM functions', |
Jan Kiszka | 007e986 | 2013-03-17 11:45:50 +0100 | [diff] [blame] | 184 | 14: 'VMCS shadowing', |
Paolo Bonzini | 025533f | 2017-02-21 09:35:45 +0100 | [diff] [blame] | 185 | 15: 'Enable ENCLS exiting', |
Adrian-Ken Rueegsegger | c5d1e2c | 2014-09-17 20:54:11 +0200 | [diff] [blame] | 186 | 16: 'RDSEED exiting', |
Paolo Bonzini | 025533f | 2017-02-21 09:35:45 +0100 | [diff] [blame] | 187 | 17: 'Enable PML', |
Adrian-Ken Rueegsegger | c5d1e2c | 2014-09-17 20:54:11 +0200 | [diff] [blame] | 188 | 18: 'EPT-violation #VE', |
Paolo Bonzini | 025533f | 2017-02-21 09:35:45 +0100 | [diff] [blame] | 189 | 19: 'Conceal non-root operation from PT', |
Adrian-Ken Rueegsegger | c5d1e2c | 2014-09-17 20:54:11 +0200 | [diff] [blame] | 190 | 20: 'Enable XSAVES/XRSTORS', |
Paolo Bonzini | 025533f | 2017-02-21 09:35:45 +0100 | [diff] [blame] | 191 | 22: 'Mode-based execute control (XS/XU)', |
Jan Kiszka | fc7d2b4 | 2019-08-13 08:29:33 +0200 | [diff] [blame] | 192 | 23: 'Sub-page write permissions', |
| 193 | 24: 'GPA translation for PT', |
Eduardo Habkost | 349cb2f | 2016-08-25 23:10:25 -0400 | [diff] [blame] | 194 | 25: 'TSC scaling', |
Jan Kiszka | fc7d2b4 | 2019-08-13 08:29:33 +0200 | [diff] [blame] | 195 | 26: 'User wait and pause', |
| 196 | 28: 'ENCLV exiting', |
Jan Kiszka | 5f6caa4 | 2011-10-07 09:37:57 +0200 | [diff] [blame] | 197 | }, |
| 198 | cap_msr = MSR_IA32_VMX_PROCBASED_CTLS2, |
| 199 | ), |
| 200 | |
Paolo Bonzini | 333dbac | 2022-05-11 18:39:12 +0200 | [diff] [blame] | 201 | Allowed1Control( |
| 202 | name = 'tertiary processor-based controls', |
| 203 | bits = { |
| 204 | 4: 'Enable IPI virtualization' |
| 205 | }, |
| 206 | cap_msr = MSR_IA32_VMX_PROCBASED_CTLS3, |
| 207 | ), |
| 208 | |
Jan Kiszka | 5f6caa4 | 2011-10-07 09:37:57 +0200 | [diff] [blame] | 209 | Control( |
| 210 | name = 'VM-Exit controls', |
| 211 | bits = { |
| 212 | 2: 'Save debug controls', |
| 213 | 9: 'Host address-space size', |
| 214 | 12: 'Load IA32_PERF_GLOBAL_CTRL', |
| 215 | 15: 'Acknowledge interrupt on exit', |
| 216 | 18: 'Save IA32_PAT', |
| 217 | 19: 'Load IA32_PAT', |
| 218 | 20: 'Save IA32_EFER', |
| 219 | 21: 'Load IA32_EFER', |
| 220 | 22: 'Save VMX-preemption timer value', |
Paolo Bonzini | 025533f | 2017-02-21 09:35:45 +0100 | [diff] [blame] | 221 | 23: 'Clear IA32_BNDCFGS', |
| 222 | 24: 'Conceal VM exits from PT', |
Jan Kiszka | fc7d2b4 | 2019-08-13 08:29:33 +0200 | [diff] [blame] | 223 | 25: 'Clear IA32_RTIT_CTL', |
Xin Li | 2e64187 | 2023-11-08 23:20:10 -0800 | [diff] [blame] | 224 | 31: 'Activate secondary VM-exit controls', |
Jan Kiszka | 5f6caa4 | 2011-10-07 09:37:57 +0200 | [diff] [blame] | 225 | }, |
| 226 | cap_msr = MSR_IA32_VMX_EXIT_CTLS, |
| 227 | true_cap_msr = MSR_IA32_VMX_TRUE_EXIT_CTLS, |
| 228 | ), |
| 229 | |
Xin Li | 2e64187 | 2023-11-08 23:20:10 -0800 | [diff] [blame] | 230 | Allowed1Control( |
| 231 | name = 'secondary VM-Exit controls', |
| 232 | bits = { |
| 233 | 0: 'Save IA32 FRED MSRs', |
| 234 | 1: 'Load IA32 FRED MSRs', |
| 235 | }, |
| 236 | cap_msr = MSR_IA32_VMX_EXIT_CTLS2, |
| 237 | ), |
| 238 | |
Jan Kiszka | 5f6caa4 | 2011-10-07 09:37:57 +0200 | [diff] [blame] | 239 | Control( |
| 240 | name = 'VM-Entry controls', |
| 241 | bits = { |
| 242 | 2: 'Load debug controls', |
Adrian-Ken Rueegsegger | c5d1e2c | 2014-09-17 20:54:11 +0200 | [diff] [blame] | 243 | 9: 'IA-32e mode guest', |
Jan Kiszka | 5f6caa4 | 2011-10-07 09:37:57 +0200 | [diff] [blame] | 244 | 10: 'Entry to SMM', |
| 245 | 11: 'Deactivate dual-monitor treatment', |
| 246 | 13: 'Load IA32_PERF_GLOBAL_CTRL', |
| 247 | 14: 'Load IA32_PAT', |
| 248 | 15: 'Load IA32_EFER', |
Paolo Bonzini | 025533f | 2017-02-21 09:35:45 +0100 | [diff] [blame] | 249 | 16: 'Load IA32_BNDCFGS', |
| 250 | 17: 'Conceal VM entries from PT', |
Jan Kiszka | fc7d2b4 | 2019-08-13 08:29:33 +0200 | [diff] [blame] | 251 | 18: 'Load IA32_RTIT_CTL', |
Xin Li | 2e64187 | 2023-11-08 23:20:10 -0800 | [diff] [blame] | 252 | 23: 'Load IA32 FRED MSRs', |
Jan Kiszka | 5f6caa4 | 2011-10-07 09:37:57 +0200 | [diff] [blame] | 253 | }, |
| 254 | cap_msr = MSR_IA32_VMX_ENTRY_CTLS, |
| 255 | true_cap_msr = MSR_IA32_VMX_TRUE_ENTRY_CTLS, |
| 256 | ), |
| 257 | |
| 258 | Misc( |
| 259 | name = 'Miscellaneous data', |
| 260 | bits = { |
| 261 | (0,4): 'VMX-preemption timer scale (log2)', |
| 262 | 5: 'Store EFER.LMA into IA-32e mode guest control', |
| 263 | 6: 'HLT activity state', |
| 264 | 7: 'Shutdown activity state', |
| 265 | 8: 'Wait-for-SIPI activity state', |
Jan Kiszka | fc7d2b4 | 2019-08-13 08:29:33 +0200 | [diff] [blame] | 266 | 14: 'PT in VMX operation', |
Jan Kiszka | 007e986 | 2013-03-17 11:45:50 +0100 | [diff] [blame] | 267 | 15: 'IA32_SMBASE support', |
Jan Kiszka | 5f6caa4 | 2011-10-07 09:37:57 +0200 | [diff] [blame] | 268 | (16,24): 'Number of CR3-target values', |
Adrian-Ken Rueegsegger | c5d1e2c | 2014-09-17 20:54:11 +0200 | [diff] [blame] | 269 | (25,27): 'MSR-load/store count recommendation', |
Avi Kivity | 287d55c | 2012-05-16 14:31:37 +0300 | [diff] [blame] | 270 | 28: 'IA32_SMM_MONITOR_CTL[2] can be set to 1', |
Jan Kiszka | 007e986 | 2013-03-17 11:45:50 +0100 | [diff] [blame] | 271 | 29: 'VMWRITE to VM-exit information fields', |
Paolo Bonzini | 025533f | 2017-02-21 09:35:45 +0100 | [diff] [blame] | 272 | 30: 'Inject event with insn length=0', |
Jan Kiszka | 007e986 | 2013-03-17 11:45:50 +0100 | [diff] [blame] | 273 | (32,63): 'MSEG revision identifier', |
Jan Kiszka | 5f6caa4 | 2011-10-07 09:37:57 +0200 | [diff] [blame] | 274 | }, |
| 275 | msr = MSR_IA32_VMX_MISC_CTLS, |
| 276 | ), |
| 277 | |
| 278 | Misc( |
| 279 | name = 'VPID and EPT capabilities', |
| 280 | bits = { |
| 281 | 0: 'Execute-only EPT translations', |
| 282 | 6: 'Page-walk length 4', |
Vitaly Kuznetsov | d312378 | 2022-02-21 15:53:16 +0100 | [diff] [blame] | 283 | 7: 'Page-walk length 5', |
Jan Kiszka | 5f6caa4 | 2011-10-07 09:37:57 +0200 | [diff] [blame] | 284 | 8: 'Paging-structure memory type UC', |
| 285 | 14: 'Paging-structure memory type WB', |
| 286 | 16: '2MB EPT pages', |
| 287 | 17: '1GB EPT pages', |
| 288 | 20: 'INVEPT supported', |
Avi Kivity | 287d55c | 2012-05-16 14:31:37 +0300 | [diff] [blame] | 289 | 21: 'EPT accessed and dirty flags', |
Jan Kiszka | fc7d2b4 | 2019-08-13 08:29:33 +0200 | [diff] [blame] | 290 | 22: 'Advanced VM-exit information for EPT violations', |
Jan Kiszka | 5f6caa4 | 2011-10-07 09:37:57 +0200 | [diff] [blame] | 291 | 25: 'Single-context INVEPT', |
| 292 | 26: 'All-context INVEPT', |
| 293 | 32: 'INVVPID supported', |
| 294 | 40: 'Individual-address INVVPID', |
| 295 | 41: 'Single-context INVVPID', |
| 296 | 42: 'All-context INVVPID', |
| 297 | 43: 'Single-context-retaining-globals INVVPID', |
| 298 | }, |
| 299 | msr = MSR_IA32_VMX_EPT_VPID_CAP, |
| 300 | ), |
Avi Kivity | 287d55c | 2012-05-16 14:31:37 +0300 | [diff] [blame] | 301 | Misc( |
| 302 | name = 'VM Functions', |
| 303 | bits = { |
| 304 | 0: 'EPTP Switching', |
| 305 | }, |
| 306 | msr = MSR_IA32_VMX_VMFUNC, |
| 307 | ), |
Jan Kiszka | 5f6caa4 | 2011-10-07 09:37:57 +0200 | [diff] [blame] | 308 | ] |
| 309 | |
Philippe Mathieu-Daudé | e57a707 | 2020-05-12 12:32:36 +0200 | [diff] [blame] | 310 | if __name__ == '__main__': |
| 311 | for c in controls: |
| 312 | c.show() |