def residency(residency_counters, residency_counter_msr, sleep_time=3): bsp_apicid = bits.bsp_apicid() sockets = dict( (skt_index, min(apic_list)) for skt_index, apic_list in bits.socket_apic_ids().iteritems()) rc = {} rc_start = {} delta = {} def read_rc(apic_id): return residency_counters(*(bits.rdmsr(apic_id, msr) for msr in residency_counter_msr)) tsc = bits.rdmsr(bsp_apicid, 0x10) for apic_id in sockets.itervalues(): rc_start[apic_id] = read_rc(apic_id) bits.blocking_sleep(sleep_time * 1000 * 1000) tsc = float(bits.rdmsr(bsp_apicid, 0x10) - tsc) for apic_id in sockets.itervalues(): rc[apic_id] = read_rc(apic_id) for apic_id in sockets.itervalues(): delta[apic_id] = residency_counters( *((end - start) / tsc for end, start in zip(rc[apic_id], rc_start[apic_id]))) return delta
def show_autodemotion(): with ttypager.page(): if bitfields.getbits(bits.rdmsr(bits.bsp_apicid(), 0xe2), 26, 25) == 0x3: print("C1 and C3 autodemotion are enabled") else: print("C1 and C3 autodemotion are disabled")
def rdmsr_consistent(msr_blacklist=set(), msr_masklist=dict()): """Rdmsr for all CPU and verify consistent value""" cpulist = sorted(bits.cpus()) for r in [range(0, 0x1000), range(0xC0000000, 0xC0001000)]: for msr in r: if msr in msr_blacklist: continue mask = msr_masklist.get(msr, ~0) uniques = {} for cpu in cpulist: value = bits.rdmsr(cpu, msr) if value is not None: value &= mask uniques.setdefault(value, []).append(cpu) testsuite.test("MSR 0x{0:x} consistent".format(msr), len(uniques) == 1) # Avoid doing any extra work formatting output when not necessary if testsuite.show_detail(): testsuite.print_detail("{0} unique values".format(len(uniques))) for value, cpus in uniques.iteritems(): testsuite.print_detail("{0} CPUs: {1}".format(len(cpus), ",".join(str(c) for c in cpus))) if value is None: testsuite.print_detail("MSR 0x{0:x}: GPF".format(msr)) else: testsuite.print_detail("MSR 0x{0:x}: 0x{1:x}".format(msr, value))
def rdmsr_consistent(msr_blacklist=set(), msr_masklist=dict()): """Rdmsr for all CPU and verify consistent value""" cpulist = sorted(bits.cpus()) for r in [range(0, 0x1000), range(0xC0000000, 0xC0001000)]: for msr in r: if msr in msr_blacklist: continue mask = msr_masklist.get(msr, ~0) uniques = {} for cpu in cpulist: value = bits.rdmsr(cpu, msr) if value is not None: value &= mask uniques.setdefault(value, []).append(cpu) testsuite.test("MSR 0x{0:x} consistent".format(msr), len(uniques) == 1) # Avoid doing any extra work formatting output when not necessary if testsuite.show_detail(): testsuite.print_detail("{0} unique values".format( len(uniques))) for value, cpus in uniques.iteritems(): testsuite.print_detail("{0} CPUs: {1}".format( len(cpus), ",".join(str(c) for c in cpus))) if value is None: testsuite.print_detail("MSR 0x{0:x}: GPF".format(msr)) else: testsuite.print_detail("MSR 0x{0:x}: 0x{1:x}".format( msr, value))
def rdmsr_helper(msr, cpu=None, shift=0, mask=~0, highbit=63, lowbit=0): """Collate the unique values of an MSR across all CPUs. Returns a dict mapping MSR values to lists of APIC IDs, and a list of strings describing the unique values and the CPUs they occurred on. Each string in the list of descriptions works as an argument to testsuite.print_detail, and the first string also works as a test description for testsuite.test if no more specific description exists.""" if (highbit != 63 or lowbit != 0) and (shift != 0 or mask != ~0): raise ValueError('Input parameter usage is limited to \"highbit and lowbit\" OR \"shift and mask\".') if cpu is None: cpus = bits.cpus() else: cpus = [cpu] uniques = {} for cpu in cpus: value = bits.rdmsr(cpu, msr) if value is not None: if highbit != 63 or lowbit != 0: value = (value & ((1 << (highbit + 1)) - 1)) >> lowbit else: value = (value >> shift) & mask uniques.setdefault(value, []).append(cpu) msr_desc = "MSR {:#x}".format(msr) if shift == 0 and mask == ~0: if highbit == lowbit: msr_desc += " [{:d}]".format(highbit) else: msr_desc += " [{:d}:{:d}]".format(highbit, lowbit) else: if shift != 0: msr_desc += " >> {}".format(shift) if mask != ~0: msr_desc += " & {:#x}".format(mask) test_desc = msr_desc + " = " if len(uniques) > 1: test_desc += "Value Varies" elif value is None: test_desc += "GPF" else: test_desc += "{0:#x}".format(value) desc = [test_desc] if len(uniques) > 1 and (None not in uniques): mask = testutil.find_common_mask(uniques.iterkeys(), 64) desc.append('MSR value is not unique across all logical processors') desc.append("Common bits for all processors = {0:#018x}".format(uniques.keys()[0] & mask)) desc.append("Mask of common bits = {0:#018x}".format(mask)) for value in sorted(uniques.iterkeys()): cpus = uniques[value] desc.append(msr_desc + " = " + ("GPF" if value is None else "{0:#x}".format(value))) desc.append("On {0} CPUs: {1}".format(len(cpus), testutil.apicid_list(cpus))) return uniques, desc
def rdmsr_test(): """Test the rdmsr function""" for cpu in cpulist: for msr in [0x10, 0x40000000]: value = bits.rdmsr(cpu, msr) if value is None: print "CPU 0x%x MSR 0x%x: GPF" % (cpu, msr) else: print "CPU 0x%x MSR 0x%x: 0x%x" % (cpu, msr, value)
def residency(residency_counters, residency_counter_msr, sleep_time=3): bsp_apicid = bits.bsp_apicid() sockets = dict((skt_index, min(apic_list)) for skt_index, apic_list in bits.socket_apic_ids().iteritems()) rc = {} rc_start = {} delta = {} def read_rc(apic_id): return residency_counters(*(bits.rdmsr(apic_id, msr) for msr in residency_counter_msr)) tsc = bits.rdmsr(bsp_apicid, 0x10) for apic_id in sockets.itervalues(): rc_start[apic_id] = read_rc(apic_id) bits.blocking_sleep(sleep_time*1000*1000) tsc = float(bits.rdmsr(bsp_apicid, 0x10) - tsc) for apic_id in sockets.itervalues(): rc[apic_id] = read_rc(apic_id) for apic_id in sockets.itervalues(): delta[apic_id] = residency_counters(*((end - start) / tsc for end, start in zip(rc[apic_id], rc_start[apic_id]))) return delta
def toggle_autodemotion(): value = bits.rdmsr(bits.bsp_apicid(), 0xe2) if bitfields.getbits(value, 26, 25) == 0x3: fieldvalue = 0 else: fieldvalue = 0x3 value = bitfields.setbits(value, fieldvalue, 26, 25) for cpu in bits.cpus(): bits.wrmsr(cpu, 0xe2, value) show_autodemotion()
def variable_mtrrs(apicid=bits.bsp_apicid()): assert apicid in bits.cpus() ia32_mtrrcap_msr = IA32_MTRRCAP( bits.rdmsr(apicid, IA32_MTRRCAP_REG) ) ia32_mtrr_def_type_msr = IA32_MTRR_DEF_TYPE(bits.rdmsr(apicid, IA32_MTRR_DEF_TYPE_REG)) with ttypager.page(): print("Summary:") print("Default memory type: {}".format(_memory_type_str(ia32_mtrr_def_type_msr.type))) for i in range(ia32_mtrrcap_msr.VCNT): ia32_mtrr_physbase_msr = IA32_MTRR_PHYSBASE(bits.rdmsr(apicid, IA32_MTRR_PHYSBASEn_REG(i))) ia32_mtrr_physmask_msr = IA32_MTRR_PHYSMASK(bits.rdmsr(apicid, IA32_MTRR_PHYSMASKn_REG(i))) if (ia32_mtrr_physmask_msr.V): print("MTRR{}: type={:20} base={:10} size={:10}".format(i, _memory_type_str(ia32_mtrr_physbase_msr.Type), _physbase_str(ia32_mtrr_physbase_msr.PhysBase), _physmask_str(ia32_mtrr_physmask_msr.PhysMask))) print() print(ia32_mtrrcap_msr, end='\n\n') print(ia32_mtrr_def_type_msr, end='\n\n') for i in range(ia32_mtrrcap_msr.VCNT): msr_num = IA32_MTRR_PHYSBASEn_REG(i) ia32_mtrr_physbase_msr = IA32_MTRR_PHYSBASE( bits.rdmsr(apicid, msr_num) ) print("IA32_MTRR_PHYSBASE[{}] MSR {:#x}".format(i, msr_num)) print(ia32_mtrr_physbase_msr, end='\n\n') msr_num = IA32_MTRR_PHYSMASKn_REG(i) ia32_mtrr_physmask_msr = IA32_MTRR_PHYSMASK( bits.rdmsr(apicid, msr_num) ) print("IA32_MTRR_PHYSMASK[{}] MSR {:#x}".format(i, msr_num)) print(ia32_mtrr_physmask_msr, end='\n\n')
def rdmsr_helper(msr, shift=0, mask=~0, highbit=63, lowbit=0): """Collate the unique values of an MSR across all CPUs. Returns a dict mapping MSR values to lists of APIC IDs, and a list of strings describing the unique values and the CPUs they occurred on. Each string in the list of descriptions works as an argument to testsuite.print_detail, and the first string also works as a test description for testsuite.test if no more specific description exists.""" if (highbit != 63 or lowbit != 0) and (shift != 0 or mask != ~0): raise ValueError( 'Input parameter usage is limited to \"highbit and lowbit\" OR \"shift and mask\".' ) uniques = {} for cpu in bits.cpus(): value = bits.rdmsr(cpu, msr) if value is not None: if highbit != 63 or lowbit != 0: value = (value & ((1 << (highbit + 1)) - 1)) >> lowbit else: value = (value >> shift) & mask uniques.setdefault(value, []).append(cpu) msr_desc = "MSR {:#x}".format(msr) if shift == 0 and mask == ~0: if highbit == lowbit: msr_desc += " [{:d}]".format(highbit) else: msr_desc += " [{:d}:{:d}]".format(highbit, lowbit) else: if shift != 0: msr_desc += " >> {}".format(shift) if mask != ~0: msr_desc += " & {:#x}".format(mask) desc = [] if len(uniques) > 1 and (None not in uniques): mask = testutil.find_common_mask(uniques.iterkeys(), 64) desc.append('MSR value is not unique across all logical processors') desc.append("Common bits for all processors = {0:#018x}".format( uniques.keys()[0] & mask)) desc.append("Mask of common bits = {0:#018x}".format(mask)) for value in sorted(uniques.iterkeys()): cpus = uniques[value] desc.append(msr_desc + " = " + ("GPF" if value is None else "{0:#x}".format(value))) desc.append("On {0} CPUs: {1}".format(len(cpus), testutil.apicid_list(cpus))) return uniques, desc
def process_wrmsr(apicid): wr_value = 0 if args.rmw: rd_value = bits.rdmsr(apicid, args.msr) if rd_value is None: rd_fail.append(apicid) return wr_value = rd_value & ~(args.mask << args.shift) wr_value |= (args.value & args.mask) << args.shift if bits.wrmsr(apicid, args.msr, wr_value): success.append(apicid) else: wr_fail.append(apicid)
def MSR(name, apicid, msr, highbit=63, lowbit=0): value = bits.rdmsr(apicid, msr) if value is not None: value = (value & ((1 << (highbit + 1)) - 1)) >> lowbit if highbit == 63 and lowbit == 0: detail = "{0} (MSR {1:#x}, apicid={2:#x})".format(name, msr, apicid) elif highbit == lowbit: detail = "{0} (MSR {1:#x} [{2:d}], apicid={3:#x})".format(name, msr, highbit, apicid) else: detail = "{0} (MSR {1:#x} [{2:d}:{3:d}], apicid={4:#x})".format(name, msr, highbit, lowbit, apicid) detail += " = " if value is None: detail += "GPF" else: detail += "0x{0:x}".format(value) return value, detail
def MSR(name, apicid, msr, highbit=63, lowbit=0): value = bits.rdmsr(apicid, msr) if value is not None: value = (value & ((1 << (highbit + 1)) - 1)) >> lowbit if highbit == 63 and lowbit == 0: detail = "{0} (MSR {1:#x}, apicid={2:#x})".format(name, msr, apicid) elif highbit == lowbit: detail = "{0} (MSR {1:#x} [{2:d}], apicid={3:#x})".format( name, msr, highbit, apicid) else: detail = "{0} (MSR {1:#x} [{2:d}:{3:d}], apicid={4:#x})".format( name, msr, highbit, lowbit, apicid) detail += " = " if value is None: detail += "GPF" else: detail += "0x{0:x}".format(value) return value, detail
def test_smrr(): """Test the SMRR-related configuration""" cpus = sorted(bits.cpus()) if not testmsr.test_msr_consistency( text="IA32_MTRRCAP Bit [11] (SMRR Supported) must be consistent", first_msr=0xFE, shift=11, mask=1 ): return ia32_mtrrcap = bits.rdmsr(cpus[0], 0xFE) if ia32_mtrrcap is not None and not ia32_mtrrcap & (1 << 11): return if testmsr.msr_available(0x1F2) and testmsr.msr_available(0x1F3): MSR_SMRR_PHYS_BASE = 0x1F2 MSR_SMRR_PHYS_MASK = 0x1F3 elif testmsr.msr_available(0xA0) and testmsr.msr_available(0xA1): MSR_SMRR_PHYS_BASE = 0xA0 MSR_SMRR_PHYS_MASK = 0xA1 return else: return testmsr.test_msr_consistency( text="SMRR must be consistent across all processors", first_msr=MSR_SMRR_PHYS_BASE, last_msr=MSR_SMRR_PHYS_MASK ) for apicid in cpus: smrr_physbase, smrr_physbase_str = testmsr.MSR("SMRR Physbase", apicid, MSR_SMRR_PHYS_BASE, 31, 12) smrr_type, smrr_type_str = testmsr.MSR("SMRR Type", apicid, MSR_SMRR_PHYS_BASE, 2, 0) smrr_physmask, smrr_physmask_str = testmsr.MSR("SMRR Physmask", apicid, MSR_SMRR_PHYS_MASK, 31, 12) smrr_valid, smrr_valid_str = testmsr.MSR("SMRR Valid", apicid, MSR_SMRR_PHYS_MASK, 11, 11) testsuite.test("SMRR_PHYSBASE must be aligned on an 8MB boundary", (smrr_physbase % 0x800) == 0) testsuite.print_detail(smrr_physbase_str) testsuite.print_detail("SMRR_PHYSBASE % 0x800 must be 0") testsuite.test("SMRR Type must be Write-Back (Best performance)", smrr_type == 6) testsuite.print_detail(smrr_type_str) testsuite.print_detail("SMRR Type must be 6") testsuite.test("SMRR size must be at least 8MB", smrr_physmask >= 0x800) testsuite.print_detail(smrr_physmask_str) testsuite.print_detail("SMRR Physmask must be >= 0x800") testsuite.test("SMRR Valid bit must be 1", smrr_valid) testsuite.print_detail(smrr_valid_str)
def msr_available(msr): """Return True if the specified MSR exists on all CPUs""" return all(bits.rdmsr(cpu_num, msr) is not None for cpu_num in bits.cpus())
def rdmsr(cls, apicid): r = cls(bits.rdmsr(apicid, cls.addr)) r.apicid = apicid return r
def smi_latency(): IA32_TSC_MSR = 0x10 MSR_SMI_COUNT = 0x34 bsp_apicid = bits.bsp_apicid() if bits.rdmsr(bsp_apicid, IA32_TSC_MSR) is None: raise RuntimeError("Reading of IA32_TSC MSR caused a GPF") print "Warning: touching the keyboard can affect the results of this test." print "Starting pass #1. Calibrating the TSC." start = time.time() tsc1 = bits.rdmsr(bsp_apicid, IA32_TSC_MSR) while time.time() - start < 1: pass stop = time.time() tsc2 = bits.rdmsr(bsp_apicid, IA32_TSC_MSR) tsc_per_sec = (tsc2 - tsc1) / (stop - start) tsc_per_usec = tsc_per_sec / (1000*1000) def show_time(tscs): units = [(1000*1000*1000, "ns"), (1000*1000, "us"), (1000, "ms")] for divisor, unit in units: temp = tscs / (tsc_per_sec / divisor) if temp < 10000: return "{}{}".format(int(temp), unit) return "{}s".format(int(tscs / tsc_per_sec)) bins = [long(tsc_per_usec * 10**i) for i in range(9)] bin_descs = [ "0 < t <= 1us", "1us < t <= 10us", "10us < t <= 100us", "100us < t <= 1ms", "1ms < t <= 10ms", "10ms < t <= 100ms", "100ms < t <= 1s ", "1s < t <= 10s ", "10s < t <= 100s ", "100s < t ", ] print "Starting pass #2. Wait here, I will be back in 15 seconds." (max_latency, smi_count_delta, bins) = bits.smi_latency(long(15 * tsc_per_sec), bins) BinType = namedtuple('BinType', ("max", "total", "count", "times")) bins = [BinType(*b) for b in bins] testsuite.test("SMI latency < 150us to minimize risk of OS timeouts", max_latency / tsc_per_usec <= 150) if not testsuite.show_detail(): return for bin, desc in zip(bins, bin_descs): if bin.count == 0: continue testsuite.print_detail("{}; average = {}; count = {}".format(desc, show_time(bin.total/bin.count), bin.count)) deltas = (show_time(t2 - t1) for t1,t2 in zip(bin.times, bin.times[1:])) testsuite.print_detail(" Times between first few observations: {}".format(" ".join("{:>6}".format(delta) for delta in deltas))) if smi_count_delta is not None: testsuite.print_detail("{} SMI detected using MSR_SMI_COUNT (MSR {:#x})".format(smi_count_delta, MSR_SMI_COUNT)) testsuite.print_detail("Summary of impact: observed maximum latency = {}".format(show_time(max_latency)))
def read_rc(apic_id): return residency_counters(*(bits.rdmsr(apic_id, msr) for msr in residency_counter_msr))