From a6614e7e2fd7ddcbc9d20838de1bf8b0f402302c Mon Sep 17 00:00:00 2001 From: Junjie Mao Date: Tue, 2 Aug 2022 00:52:40 +0800 Subject: [PATCH] config_tools: board_inspector: refactors MSR utilities In v3.0 the msrfield class has its initializer changed in a way that is incompatible with the parameter names or the getter/setter. When introduced from the BITS project, that class allows specifying an MSR field of arbitrary length by being given the index of the most and least significant bits. This patch restores the original behavior of that msrfield class and moves the use-case specific methods, namely is_vmx_cap_supported and is_ctrl_setting_allowed, to a helper class. Parsing of the VMX capability reporting MSRs in msr.py are updated accordingly, and brief documentation of the MSR fields are added as well. Tracked-On: #7948 Signed-off-by: Junjie Mao --- .../board_inspector/cpuparser/msr.py | 170 +++++++++++------- .../board_inspector/cpuparser/platformbase.py | 17 +- .../schema/checks/platform_capabilities.xsd | 4 +- 3 files changed, 110 insertions(+), 81 deletions(-) diff --git a/misc/config_tools/board_inspector/cpuparser/msr.py b/misc/config_tools/board_inspector/cpuparser/msr.py index 8fff698fa..21d2ba6b4 100644 --- a/misc/config_tools/board_inspector/cpuparser/msr.py +++ b/misc/config_tools/board_inspector/cpuparser/msr.py @@ -7,7 +7,7 @@ from cpuparser.platformbase import MSR, msrfield class MSR_IA32_MISC_ENABLE(MSR): addr = 0x1a0 - fast_string = msrfield(1, 0, doc=None) + fast_string = msrfield(0, 0, doc="Fast-strings enable") capability_bits = [ "fast_string", @@ -15,39 +15,76 @@ class MSR_IA32_MISC_ENABLE(MSR): class MSR_IA32_FEATURE_CONTROL(MSR): addr = 0x03a - msr_ia32_feature_control_lock = msrfield(1, 0, doc=None) - msr_ia32_feature_control_vmx_no_smx = msrfield(1, 2, doc=None) + lock = msrfield(0, 0, doc="Lock bit") + vmx_outside_smx = msrfield(2, 2, doc="Enable VMX outside SMX operation") @property def disable_vmx(self): - return self.msr_ia32_feature_control_lock and not self.msr_ia32_feature_control_vmx_no_smx + return self.lock and not self.vmx_outside_smx capability_bits = [ "disable_vmx", ] -class MSR_IA32_VMX_PROCBASED_CTLS2(MSR): +class VMXCapabilityReportingMSR(MSR): + def get_field_idx(self, field): + if isinstance(field, int): + return field + if isinstance(field, str): + return getattr(type(self), field).lsb + assert False, f"Invalid field type: {field}, {type(field)}" + + def allows_0_setting(self, field): + field_idx = self.get_field_idx(field) + if field_idx >= 32: + return False + + bit_mask = (1 << field_idx) + return (self.value & bit_mask) == 0 + + def allows_1_setting(self, field): + field_idx = self.get_field_idx(field) + if field_idx >= 32: + return False + + bit_mask = (1 << field_idx) + high = self.value >> 32 + return (high & bit_mask) == bit_mask + + def allows_flexible_setting(self, field): + field_idx = self.get_field_idx(field) + return self.allows_0_setting(field_idx) and self.allows_1_setting(field_idx) + +class MSR_IA32_VMX_PROCBASED_CTLS2(VMXCapabilityReportingMSR): addr = 0x0000048B + vapic_access = msrfield(0, 0, doc="Virtualize APIC accesses") + ept = msrfield(1, 1, doc="Enable EPT") + rdtscp = msrfield(3, 3, doc="Enable RDTSCP") + vx2apic = msrfield(4, 4, doc="Virtualize x2APIC mode") + vpid = msrfield(5, 5, doc="Enable VPID") + unrestricted_guest = msrfield(7, 7, doc="Unrestricted guest") + apic_reg_virt = msrfield(8, 8, doc="APIC-register virtualization") + @property def vmx_procbased_ctls2_vapic(self): - return msrfield.is_vmx_cap_supported(self, 1 << 0) + return self.allows_flexible_setting("vapic_access") @property def vmx_procbased_ctls2_ept(self): - return msrfield.is_vmx_cap_supported(self, 1 << 1) + return self.allows_flexible_setting("ept") @property def vmx_procbased_ctls2_vpid(self): - return msrfield.is_vmx_cap_supported(self, 1 << 5) + return self.allows_flexible_setting("vpid") @property def vmx_procbased_ctls2_rdtscp(self): - return msrfield.is_vmx_cap_supported(self, 1 << 3) + return self.allows_flexible_setting("rdtscp") @property def vmx_procbased_ctls2_unrestrict(self): - return msrfield.is_vmx_cap_supported(self, 1 << 7) + return self.allows_flexible_setting("unrestricted_guest") capability_bits = [ "vmx_procbased_ctls2_vapic", @@ -57,82 +94,69 @@ class MSR_IA32_VMX_PROCBASED_CTLS2(MSR): "vmx_procbased_ctls2_unrestrict", ] -class MSR_IA32_VMX_PINBASED_CTLS(MSR): +class MSR_IA32_VMX_PINBASED_CTLS(VMXCapabilityReportingMSR): addr = 0x00000481 + irq_exiting = msrfield(0, 0, doc="External-interrupt existing") + @property def vmx_pinbased_ctls_irq_exit(self): - return msrfield.is_vmx_cap_supported(self, 1 << 0) + return self.allows_flexible_setting("irq_exiting") capability_bits = [ "vmx_pinbased_ctls_irq_exit", ] -class MSR_IA32_VMX_PROCBASED_CTLS(MSR): +class MSR_IA32_VMX_PROCBASED_CTLS(VMXCapabilityReportingMSR): addr = 0x00000482 + tsc_offsetting = msrfield(3, 3, doc="Use TSC offsetting") + hlt_exiting = msrfield(7, 7, doc="HLT exiting") + tpr_shadow = msrfield(21, 21, doc="Use TPR shadow") + io_bitmaps = msrfield(25, 25, doc="Use I/O bitmaps") + msr_bitmaps = msrfield(28, 28, doc="Use MSR bitmaps") + secondary_ctrls = msrfield(31, 31, doc="Activate secondary controls") + @property def vmx_procbased_ctls_tsc_off(self): - return msrfield.is_vmx_cap_supported(self, 1 << 3) + return self.allows_flexible_setting("tsc_offsetting") @property def vmx_procbased_ctls_tpr_shadow(self): - return msrfield.is_vmx_cap_supported(self, 1 << 21) + return self.allows_flexible_setting("tpr_shadow") @property def vmx_procbased_ctls_io_bitmap(self): - return msrfield.is_vmx_cap_supported(self, 1 << 25) + return self.allows_flexible_setting("io_bitmaps") @property def vmx_procbased_ctls_msr_bitmap(self): - return msrfield.is_vmx_cap_supported(self, 1 << 28) + return self.allows_flexible_setting("msr_bitmaps") @property def vmx_procbased_ctls_hlt(self): - return msrfield.is_vmx_cap_supported(self, 1 << 7) + return self.allows_flexible_setting("hlt_exiting") @property def vmx_procbased_ctls_secondary(self): - return msrfield.is_vmx_cap_supported(self, 1 << 31) + return self.allows_flexible_setting("secondary_ctrls") @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 + if self.allows_1_setting("secondary_ctrls"): + ctls2 = MSR_IA32_VMX_PROCBASED_CTLS2.rdmsr(self.cpu_id) + return ctls2.allows_1_setting("ept") + return False @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 not self.allows_1_setting("tpr_shadow"): + return False - 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 + ctls2 = MSR_IA32_VMX_PROCBASED_CTLS2.rdmsr(self.cpu_id) + return \ + ctls2.allows_1_setting("vapic_access") and \ + ctls2.allows_1_setting("vx2apic") capability_bits = [ "ept", @@ -148,10 +172,16 @@ class MSR_IA32_VMX_PROCBASED_CTLS(MSR): 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) + invept = msrfield(20, 20, doc="INVEPT instruction supported") + ept_2mb_page = msrfield(16, 16, doc="EPT 2-Mbyte page supported") + vmx_ept_1gb_page = msrfield(17, 17, doc="EPT 1-Gbyte page supported") + invvpid_inst = msrfield(32, 32, doc="INVVPID instruction supported") + invvpid_single_context = msrfield(41, 41, doc="single-context INVVPID type supported") + invvpid_all_context = msrfield(42, 42, doc="all-context INVVPID type supported") + + @property + def invvpid(self): + return self.invvpid_inst and self.invvpid_single_context and self.invvpid_all_context capability_bits = [ "invept", @@ -162,38 +192,43 @@ class MSR_IA32_VMX_EPT_VPID_CAP(MSR): class MSR_IA32_VMX_MISC(MSR): addr = 0x00000485 - unrestricted_guest = msrfield(1, 5) + stores_lma_on_exit = msrfield(5, 5, doc="VM exits stores the value of IA32_EFER.LMA into the 'IA-32e mode guest' VM-entry control") capability_bits = [ - "unrestricted_guest", + "stores_lma_on_exit", ] class MSR_IA32_VMX_BASIC(MSR): addr = 0x00000480 - set_32bit_addr_width = msrfield(1, 48) + set_32bit_addr_width = msrfield(48, 48, doc="Addresses of VMXON, VMCS and referenced structures limited to 32-bit") capability_bits = [ "set_32bit_addr_width", ] -class MSR_IA32_VMX_EXIT_CTLS(MSR): +class MSR_IA32_VMX_EXIT_CTLS(VMXCapabilityReportingMSR): addr = 0x00000483 + host_addr_size = msrfield(9, 9, doc="Host address-space size") + ack_irq_on_exit = msrfield(15, 15, doc="Acknowledge interrupt on exit") + save_pat = msrfield(18, 18, doc="Save IA32_PAT") + load_pat = msrfield(19, 19, doc="Load IA32_PAT") + @property def vmx_exit_ctls_ack_irq(self): - return msrfield.is_vmx_cap_supported(self, 1 << 15) + return self.allows_flexible_setting("ack_irq_on_exit") @property def vmx_exit_ctls_save_pat(self): - return msrfield.is_vmx_cap_supported(self, 1 << 18) + return self.allows_flexible_setting("save_pat") @property def vmx_exit_ctls_load_pat(self): - return msrfield.is_vmx_cap_supported(self, 1 << 19) + return self.allows_flexible_setting("load_pat") @property def vmx_exit_ctls_host_addr64(self): - return msrfield.is_vmx_cap_supported(self, 1 << 9) + return self.allows_flexible_setting("host_addr_size") capability_bits = [ "vmx_exit_ctls_ack_irq", @@ -202,16 +237,19 @@ class MSR_IA32_VMX_EXIT_CTLS(MSR): "vmx_exit_ctls_host_addr64", ] -class MSR_IA32_VMX_ENTRY_CTLS(MSR): +class MSR_IA32_VMX_ENTRY_CTLS(VMXCapabilityReportingMSR): addr = 0x00000484 + ia32e_mode_guest = msrfield(9, 9, doc="IA-32e mode guest") + load_pat = msrfield(14, 14, doc="Load IA32_PAT") + @property def vmx_entry_ctls_load_pat(self): - return msrfield.is_vmx_cap_supported(self, 1 << 14) + return self.allows_flexible_setting("load_pat") @property def vmx_entry_ctls_ia32e_mode(self): - return msrfield.is_vmx_cap_supported(self, 1 << 9) + return self.allows_flexible_setting("ia32e_mode_guest") capability_bits = [ "vmx_entry_ctls_load_pat", diff --git a/misc/config_tools/board_inspector/cpuparser/platformbase.py b/misc/config_tools/board_inspector/cpuparser/platformbase.py index 28dba44d7..308edf477 100644 --- a/misc/config_tools/board_inspector/cpuparser/platformbase.py +++ b/misc/config_tools/board_inspector/cpuparser/platformbase.py @@ -202,10 +202,12 @@ class msrfield(property): def __init__(self, msb, lsb, doc=None): self.msb = msb self.lsb = lsb - bit_mask = self.msb << self.lsb + + max_value = (1 << (msb - lsb + 1)) - 1 + field_mask = max_value << lsb def getter(self): - return (self.value & bit_mask) != 0 + return (self.value & field_mask) >> lsb def setter(self, value): if value > max_value: @@ -219,14 +221,3 @@ 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/schema/checks/platform_capabilities.xsd b/misc/config_tools/board_inspector/schema/checks/platform_capabilities.xsd index ac3142629..a194538cd 100644 --- a/misc/config_tools/board_inspector/schema/checks/platform_capabilities.xsd +++ b/misc/config_tools/board_inspector/schema/checks/platform_capabilities.xsd @@ -147,9 +147,9 @@ ACRN requires this feature to function properly. Please enable it in BIOS. - + - Unrestricted guest is not supported on this processor. ACRN requires this feature to function properly. + The value of IA32_EFER.LMA is not saved upon VM exit on this processor. ACRN requires this feature to function properly.