From 7dfc3c683c015d4e542581514c6d686f1b725e16 Mon Sep 17 00:00:00 2001 From: Kunhui-Li Date: Tue, 8 Mar 2022 16:26:40 +0800 Subject: [PATCH] config_tools: add CPU capability checks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add CPU capability checks. If a feature is not supported on this processor, the board inspector will show error message because it would impact ACRN’s ability to function properly. v3-->v4: Update the error messages. v2-->v3: 1. For VMX features, split each feature as a separate property, capability checks in XML schema will then check all those features. 2. Use the class names instead of addresses, and invoke the rdmsr method of each class. v1-->v2: 1. Define each register as a class inheriting the `MSR` class defined in platformbase.py, and define each bit as fields of that class. 2. The board inspector simply collects the CPU capability and attribute, and the XSD does the actual check Tracked-On: #6689 Signed-off-by: Kunhui-Li Reviewed-by: Junjie Mao --- .../board_inspector/cpuparser/cpuids.py | 8 + .../board_inspector/cpuparser/msr.py | 206 ++++++++++++++ .../board_inspector/cpuparser/platformbase.py | 32 ++- .../extractors/10-processors.py | 12 +- .../schema/checks/platform_capabilities.xsd | 257 +++++++++++++++++- 5 files changed, 507 insertions(+), 8 deletions(-) create mode 100644 misc/config_tools/board_inspector/cpuparser/msr.py diff --git a/misc/config_tools/board_inspector/cpuparser/cpuids.py b/misc/config_tools/board_inspector/cpuparser/cpuids.py index b8a074f2e..b2af4d101 100644 --- a/misc/config_tools/board_inspector/cpuparser/cpuids.py +++ b/misc/config_tools/board_inspector/cpuparser/cpuids.py @@ -19,11 +19,19 @@ class LEAF_0(CPUID): leaf = 0x0 max_leaf = cpuidfield(EAX, 31, 0, doc="Highest value the CPUID recognizes for returning basic processor information") + @property + def cpuid_level(self): + return hex(self.regs.eax) + @property def vendor(self): """Vendor identification string""" return struct.pack('III', self.regs.ebx, self.regs.edx, self.regs.ecx) + attribute_bits = [ + "cpuid_level", + ] + class LEAF_1(CPUID): """Basic CPUID Information diff --git a/misc/config_tools/board_inspector/cpuparser/msr.py b/misc/config_tools/board_inspector/cpuparser/msr.py new file mode 100644 index 000000000..f6f8f9729 --- /dev/null +++ b/misc/config_tools/board_inspector/cpuparser/msr.py @@ -0,0 +1,206 @@ +# Copyright (C) 2022 Intel Corporation. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +from cpuparser.platformbase import MSR, msrfield + +class MSR_IA32_MISC_ENABLE(MSR): + addr = 0x1a0 + fast_string = msrfield(1, 0, doc=None) + + capability_bits = [ + "fast_string", + ] + +class MSR_IA32_VMX_PROCBASED_CTLS2(MSR): + addr = 0x0000048B + + @property + def vmx_procbased_ctls2_vapic(self): + return msrfield.is_vmx_cap_supported(self, 1 << 0) + + @property + def vmx_procbased_ctls2_ept(self): + return msrfield.is_vmx_cap_supported(self, 1 << 1) + + @property + def vmx_procbased_ctls2_vpid(self): + return msrfield.is_vmx_cap_supported(self, 1 << 5) + + @property + def vmx_procbased_ctls2_rdtscp(self): + return msrfield.is_vmx_cap_supported(self, 1 << 3) + + @property + def vmx_procbased_ctls2_unrestrict(self): + return msrfield.is_vmx_cap_supported(self, 1 << 7) + + capability_bits = [ + "vmx_procbased_ctls2_vapic", + "vmx_procbased_ctls2_ept", + "vmx_procbased_ctls2_vpid", + "vmx_procbased_ctls2_rdtscp", + "vmx_procbased_ctls2_unrestrict", + ] + +class MSR_IA32_VMX_PINBASED_CTLS(MSR): + addr = 0x00000481 + + @property + def vmx_pinbased_ctls_irq_exit(self): + return msrfield.is_vmx_cap_supported(self, 1 << 0) + + capability_bits = [ + "vmx_pinbased_ctls_irq_exit", + ] + +class MSR_IA32_VMX_PROCBASED_CTLS(MSR): + addr = 0x00000482 + + @property + def vmx_procbased_ctls_tsc_off(self): + return msrfield.is_vmx_cap_supported(self, 1 << 3) + + @property + def vmx_procbased_ctls_tpr_shadow(self): + return msrfield.is_vmx_cap_supported(self, 1 << 21) + + @property + def vmx_procbased_ctls_io_bitmap(self): + return msrfield.is_vmx_cap_supported(self, 1 << 25) + + @property + def vmx_procbased_ctls_msr_bitmap(self): + return msrfield.is_vmx_cap_supported(self, 1 << 28) + + @property + def vmx_procbased_ctls_hlt(self): + return msrfield.is_vmx_cap_supported(self, 1 << 7) + + @property + def vmx_procbased_ctls_secondary(self): + return msrfield.is_vmx_cap_supported(self, 1 << 31) + + @property + def ept(self): + is_ept_supported = False + if ((self.value >> 32) & (1 << 31)) != 0: + msr_val = MSR_IA32_VMX_PROCBASED_CTLS2.rdmsr(self.cpu_id) + if msrfield.is_ctrl_setting_allowed(msr_val.value, 1 << 1): + is_ept_supported = True + return is_ept_supported + + @property + def apicv(self): + features = 0 + vapic_feature_tpr_shadow = 1 << 3 + vapic_feature_virt_access = 1 << 0 + vapic_feature_vx2apic_mode = 1 << 5 + vapic_feature_virt_reg = 1 << 1 + vapic_feature_intr_delivery = 1 << 2 + vapic_feature_post_intr = 1 << 4 + + if msrfield.is_ctrl_setting_allowed(self.value, 1 << 21): + features |= vapic_feature_tpr_shadow + + msr_val = MSR_IA32_VMX_PROCBASED_CTLS2.rdmsr(self.cpu_id) + if msrfield.is_ctrl_setting_allowed(msr_val.value, 1 << 0): + features |= vapic_feature_virt_access + if msrfield.is_ctrl_setting_allowed(msr_val.value, 1 << 4): + features |= vapic_feature_vx2apic_mode + if msrfield.is_ctrl_setting_allowed(msr_val.value, 1 << 8): + features |= vapic_feature_virt_reg + if msrfield.is_ctrl_setting_allowed(msr_val.value, 1 << 9): + features |= vapic_feature_intr_delivery + + msr_val = MSR_IA32_VMX_PINBASED_CTLS.rdmsr(self.cpu_id) + if msrfield.is_ctrl_setting_allowed(msr_val.value, 1 << 7): + features |= vapic_feature_post_intr + + apicv_basic_feature = (vapic_feature_tpr_shadow | vapic_feature_virt_access | vapic_feature_vx2apic_mode) + return (features & apicv_basic_feature) == apicv_basic_feature + + capability_bits = [ + "ept", + "apicv", + "vmx_procbased_ctls_tsc_off", + "vmx_procbased_ctls_tpr_shadow", + "vmx_procbased_ctls_io_bitmap", + "vmx_procbased_ctls_msr_bitmap", + "vmx_procbased_ctls_hlt", + "vmx_procbased_ctls_secondary", + ] + +class MSR_IA32_VMX_EPT_VPID_CAP(MSR): + addr = 0x0000048C + + invept = msrfield(1, 20) + ept_2mb_page = msrfield(1, 16) + vmx_ept_1gb_page = msrfield(1, 17) + invvpid = msrfield(1, 32) and msrfield(1, 41) and msrfield(1, 42) + + capability_bits = [ + "invept", + "invvpid", + "ept_2mb_page", + "vmx_ept_1gb_page", + ] + +class MSR_IA32_VMX_MISC(MSR): + addr = 0x00000485 + unrestricted_guest = msrfield(1, 5) + + capability_bits = [ + "unrestricted_guest", + ] + +class MSR_IA32_VMX_BASIC(MSR): + addr = 0x00000480 + set_32bit_addr_width = msrfield(1, 48) + + capability_bits = [ + "set_32bit_addr_width", + ] + +class MSR_IA32_VMX_EXIT_CTLS(MSR): + addr = 0x00000483 + + @property + def vmx_exit_ctls_ack_irq(self): + return msrfield.is_vmx_cap_supported(self, 1 << 15) + + @property + def vmx_exit_ctls_save_pat(self): + return msrfield.is_vmx_cap_supported(self, 1 << 18) + + @property + def vmx_exit_ctls_load_pat(self): + return msrfield.is_vmx_cap_supported(self, 1 << 19) + + @property + def vmx_exit_ctls_host_addr64(self): + return msrfield.is_vmx_cap_supported(self, 1 << 9) + + capability_bits = [ + "vmx_exit_ctls_ack_irq", + "vmx_exit_ctls_save_pat", + "vmx_exit_ctls_load_pat", + "vmx_exit_ctls_host_addr64", + ] + +class MSR_IA32_VMX_ENTRY_CTLS(MSR): + addr = 0x00000484 + + @property + def vmx_entry_ctls_load_pat(self): + return msrfield.is_vmx_cap_supported(self, 1 << 14) + + @property + def vmx_entry_ctls_ia32e_mode(self): + return msrfield.is_vmx_cap_supported(self, 1 << 9) + + capability_bits = [ + "vmx_entry_ctls_load_pat", + "vmx_entry_ctls_ia32e_mode", + ] diff --git a/misc/config_tools/board_inspector/cpuparser/platformbase.py b/misc/config_tools/board_inspector/cpuparser/platformbase.py index 154f66289..73552a836 100644 --- a/misc/config_tools/board_inspector/cpuparser/platformbase.py +++ b/misc/config_tools/board_inspector/cpuparser/platformbase.py @@ -12,6 +12,7 @@ import functools import inspect import operator import textwrap +import logging from collections import namedtuple _wrapper = textwrap.TextWrapper(width=78, initial_indent=' ', subsequent_indent=' ') @@ -135,8 +136,17 @@ class MSR(object): return self.value != other.value @classmethod - def rdmsr(cls, cpu_id): - r = cls(bits.rdmsr(cpu_id, cls.addr)) + def rdmsr(cls, cpu_id: int) -> int: + try: + with open(f'/dev/cpu/{cpu_id}/msr', 'rb') as msr_reader: + msr_reader.seek(cls.addr) + r = msr_reader.read(8) + r = cls(int.from_bytes(r, 'little')) + except IOError: + logging.critical(f"Missing CPU MSR file at /dev/cpu/{cpu_id}/msr. Check the value of CONFIG_X86_MSR " \ + "in the kernel config. Set it to 'Y' and rebuild the kernel. Then rerun the Board Inspector.") + sys.exit(1) + r.cpu_id = cpu_id return r @@ -187,15 +197,14 @@ class MSR(object): return s class msrfield(property): + def __init__(self, msb, lsb, doc=None): self.msb = msb self.lsb = lsb - - max_value = (1 << (msb - lsb + 1)) - 1 - field_mask = max_value << lsb + bit_mask = self.msb << self.lsb def getter(self): - return (self.value & field_mask) >> lsb + return (self.value & bit_mask) != 0 def setter(self, value): if value > max_value: @@ -209,3 +218,14 @@ class msrfield(property): self.value = (self.value & ~field_mask) | (value << lsb) super(msrfield, self).__init__(getter, setter, doc=doc) + + def is_vmx_cap_supported(self, bits): + vmx_msr = self.value + vmx_msr_bin = int.to_bytes(vmx_msr, 8, 'big') + vmx_msr_low = int.from_bytes(vmx_msr_bin[4:], 'big') + vmx_msr_high = int.from_bytes(vmx_msr_bin[:4], 'big') + return ((vmx_msr_high & bits) == bits) and ((vmx_msr_low & bits) == 0) + + @staticmethod + def is_ctrl_setting_allowed(msr_val, ctrl): + return ((msr_val >> 32) & ctrl) == ctrl diff --git a/misc/config_tools/board_inspector/extractors/10-processors.py b/misc/config_tools/board_inspector/extractors/10-processors.py index 73d9997a3..150f806da 100644 --- a/misc/config_tools/board_inspector/extractors/10-processors.py +++ b/misc/config_tools/board_inspector/extractors/10-processors.py @@ -7,6 +7,7 @@ import logging import lxml.etree from cpuparser import parse_cpuid, get_online_cpu_ids +from cpuparser.msr import * from extractors.helpers import add_child, get_node level_types = { @@ -52,7 +53,16 @@ def extract_model(processors_node, cpu_id, family_id, model_id, core_type, nativ if getattr(leaf_data, cap) == 1: add_child(n, "capability", id=cap) - leaves = [(0x80000008, 0)] + msr_regs = [MSR_IA32_MISC_ENABLE, MSR_IA32_VMX_BASIC, MSR_IA32_VMX_PINBASED_CTLS, + MSR_IA32_VMX_PROCBASED_CTLS, MSR_IA32_VMX_EXIT_CTLS, MSR_IA32_VMX_ENTRY_CTLS, + MSR_IA32_VMX_MISC, MSR_IA32_VMX_PROCBASED_CTLS2, MSR_IA32_VMX_EPT_VPID_CAP] + for msr_reg in msr_regs: + msr_data = msr_reg.rdmsr(cpu_id) + for cap in msr_data.capability_bits: + if getattr(msr_data, cap) == 1: + add_child(n, "capability", id=cap) + + leaves = [(0, 0), (0x80000008, 0)] for leaf in leaves: leaf_data = parse_cpuid(leaf[0], leaf[1], cpu_id) for cap in leaf_data.attribute_bits: diff --git a/misc/config_tools/board_inspector/schema/checks/platform_capabilities.xsd b/misc/config_tools/board_inspector/schema/checks/platform_capabilities.xsd index 6af0241e6..bfb8d322a 100644 --- a/misc/config_tools/board_inspector/schema/checks/platform_capabilities.xsd +++ b/misc/config_tools/board_inspector/schema/checks/platform_capabilities.xsd @@ -5,7 +5,262 @@ - Intel(R) Virtualization Technology Extension shall be enabled in BIOS. + Virtual Machine Extensions (VMX) feature is not supported on this processor. ACRN requires this feature to function properly. + + + + + + Long mode (x86-64, 64-bit) feature is not supported on this processor. ACRN requires this feature to function properly. + + + + + + The width of the physical addresses used for the VMXON region is limited to 32bit. "Intel 64 architecture" feature is not enabled. ACRN requires this feature to function properly. + + + + + + Instruction CPUID time stamp counter, nominal core crystal clock information leaf and processor frequency information leaf are not supported. ACRN requires this feature to function properly. + + + + + + "Zero linear/physical address size" feature is not supported on this processor. ACRN requires this feature to function properly. + + + + + + "1GB large page(Physical-address width > 39)" feature is not supported on this processor. ACRN requires this feature to function properly. + + + + + + "Fast string" feature is not supported on this processor. ACRN requires this feature to function properly. + + + + + + Enhanced rep movsb/stosb feature is not supported on this processor. ACRN requires this feature to function properly. + + + + + + Invariant TSC feature is not supported on this processor. ACRN requires this feature to function properly. + + + + + + TSC deadline feature is not supported on this processor. ACRN requires this feature to function properly. + + + + + + NX feature is not supported on this processor. ACRN requires this feature to function properly. + + + + + + SMEP feature is not supported on this processor. ACRN requires this feature to function properly. + + + + + + SMAP feature is not supported on this processor. ACRN requires this feature to function properly. + + + + + + MTRR feature is not supported on this processor. ACRN requires this feature to function properly. + + + + + + CLFLUSHOPT feature is not supported on this processor. ACRN requires this feature to function properly. + + + + + + x2APIC feature is not supported on this processor. ACRN requires this feature to function properly. + + + + + + POPCNT feature is not supported on this processor. ACRN requires this feature to function properly. + + + + + + SSE feature is not supported on this processor. ACRN requires this feature to function properly. + + + + + + RDRAND feature is not supported on this processor. ACRN requires this feature to function properly. + + + + + + INVEPT is not supported on this processor. ACRN requires this feature to function properly. + + + + + + Unrestricted guest is not supported on this processor. ACRN requires this feature to function properly. + + + + + + EPT feature is not supported on this processor. ACRN requires this feature to function properly. + + + + + + EPT does not support 2MB large pages on this processor. ACRN requires this feature to function properly. + + + + + + INVVPID feature is not supported on this processor. ACRN requires this feature to function properly. + + + + + + APICV feature is not supported on this processor. ACRN requires this feature to function properly. + + + + + + VMX capability External-interrupt exiting for VM execution controls feature is not supported on this processor. ACRN requires this feature to function properly. + + + + + + VMX capability Use TSC offsetting for VM execution controls feature is not supported on this processor. ACRN requires this feature to function properly. + + + + + + VMX capability Use TPR shadow for VM execution controls feature is not supported on this processor. ACRN requires this feature to function properly. + + + + + + VMX capability Use I/O bitmaps for VM execution controls feature is not supported on this processor. ACRN requires this feature to function properly. + + + + + + VMX capability Use MSR bitmaps for VM execution controls feature is not supported on this processor. ACRN requires this feature to function properly. + + + + + + VMX capability HLT exiting for VM execution controls feature is not supported on this processor. ACRN requires this feature to function properly. + + + + + + VMX capability Activate secondary controls for VM execution controls feature is not supported on this processor. ACRN requires this feature to function properly. + + + + + + VMX capability acknowledge interrupt on exit feature is not supported on this processor. ACRN requires this feature to function properly. + + + + + + VMX capability save IA32_PAT on VM exit feature is not supported on this processor. ACRN requires this feature to function properly. + + + + + + VMX capability load IA32_PAT on VM exit feature is not supported on this processor. ACRN requires this feature to function properly. + + + + + + VMX capability Host address-space size on VM exit feature is not supported on this processor. ACRN requires this feature to function properly. + + + + + + VMX capability IA32_PAT MSR load on VM entry feature is not supported on this processor. ACRN requires this feature to function properly. + + + + + + VMX capability IA-32e mode guest support after VM entry feature is not supported on this processor. ACRN requires this feature to function properly. + + + + + + VMX capability Virtualize APIC accesses for VM execution controls feature is not supported on this processor. ACRN requires this feature to function properly. + + + + + + VMX capability Enable EPT for VM execution controls feature is not supported on this processor. ACRN requires this feature to function properly. + + + + + + VMX capability Enable VPID for VM execution controls feature is not supported on this processor. ACRN requires this feature to function properly. + + + + + + VMX capability Enable RDTSCP for VM execution controls feature is not supported on this processor. ACRN requires this feature to function properly. + + + + + + VMX capability Unrestricted guest for VM execution controls feature is not supported on this processor. ACRN requires this feature to function properly.