def test_msr_consistency(text, first_msr, last_msr=None, shift=0, mask=~0, highbit=63, lowbit=0): """Test the consistency of an MSR or range of MSRs across all CPUs.""" if last_msr is None: last_msr = first_msr ret = True for msr in range(first_msr, last_msr + 1): uniques, desc = rdmsr_helper(msr=msr, shift=shift, mask=mask, highbit=highbit, lowbit=lowbit) desc[0] += " Consistency Check" if text: desc = [text] + desc status = testsuite.test(desc[0], len(uniques) == 1) for line in desc[1:]: testsuite.print_detail(line) ret = ret and status return ret
def test_msr(text, msr, expected_value, shift=0, mask=~0, highbit=63, lowbit=0): """Test the value of an MSR. Fails if any CPU does not match expected_value. Pass expected_value=None to expect a GPF.""" uniques, desc = rdmsr_helper(msr=msr, shift=shift, mask=mask, highbit=highbit, lowbit=lowbit) if expected_value is None: desc[0] += " (Expected GPF)" else: desc[0] += " (Expected {:#x})".format(expected_value) if text: desc.insert(0, text) status = testsuite.test( desc[0], len(uniques) == 1 and uniques.keys()[0] == expected_value) for line in desc[1:]: testsuite.print_detail(line) return status
def test_cpuid_consistency(text, function, index=None, shift=0, mask=~0, eax_mask=~0, ebx_mask=~0, ecx_mask=~0, edx_mask=~0): uniques, desc = cpuid_helper(function, index, None, shift, mask, eax_mask, ebx_mask, ecx_mask, edx_mask) desc[0] += " Consistency Check" if text: desc.insert(0, text) status = testsuite.test(desc[0], len(uniques) == 1) for line in desc[1:]: testsuite.print_detail(line) return status
def test_cpuid_consistency(text, function, index=None, shift=0, mask=~0, eax_mask=~0, ebx_mask=~0, ecx_mask=~0, edx_mask=~0): uniques, desc = cpuid_helper(function, index, shift, mask, eax_mask, ebx_mask, ecx_mask, edx_mask) desc[0] += " Consistency Check" if text: desc.insert(0, text) status = testsuite.test(desc[0], len(uniques) == 1) for line in desc[1:]: testsuite.print_detail(line) return status
def test_pci(text, bus, dev, fn, reg, expected_value, bytes=None, mask=~0, shift=0): value, desc = pci_read_helper(bus, dev, fn, reg, pci_read_func=bits.pci_read, bytes=bytes, mask=mask, shift=shift) status = value == expected_value desc += " (Expected {:#x})".format(expected_value) if text: testsuite.test(text, status) testsuite.print_detail(desc) else: testsuite.test(desc, status) return status
def test_pm_generic_profile(): testmsr.test_msr_consistency("Max non-turbo ratio must be consistent", 0xce, mask=0xff00) testpci.test_pci("Bus master disable", 0, 31, 0, 0xa9, bytes=1, shift=2, mask=1, expected_value=1) testmsr.test_msr("C1 Auto Undemotion Enable", 0xe2, shift=28, mask=1, expected_value=1) testmsr.test_msr("C3 Auto Undemotion Enable", 0xe2, shift=27, mask=1, expected_value=1) testmsr.test_msr("C1 Auto Demotion Enable", 0xe2, shift=26, mask=1, expected_value=1) testmsr.test_msr("C3 Auto Demotion Enable", 0xe2, shift=25, mask=1, expected_value=1) testmsr.test_msr("IO MWAIT Redirection Enable", 0xe2, shift=10, mask=1, expected_value=1) testmsr.test_msr("C1E Enable", 0x1fc, shift=1, mask=1, expected_value=1) testmsr.test_msr("EIST Enable", 0x1a0, shift=16, mask=1, expected_value=1) testmsr.test_msr("Turbo Enable", 0x1a0, shift=38, mask=1, expected_value=0) testmsr.test_msr("EIST Hardware Coordination Enable", 0x1aa, mask=1, expected_value=0) testmsr.test_msr_consistency("IO Capture C-state Range Consistent", 0xe4, shift=16, mask=7) io_capture_range, io_capture_range_str = testmsr.MSR( "IO Capture C-state Range", bits.bsp_apicid(), 0xe4, 18, 16) testsuite.test("IO Capture C-state Range <= 2", io_capture_range <= 2) testsuite.print_detail(io_capture_range_str)
def test_rsdp(): data = acpi.get_table("RSD PTR ") if data is None: return # Checksum the first 20 bytes per ACPI 1.0 csum = sum(ord(c) for c in data[:20]) % 0x100 testsuite.test('ACPI 1.0 table first 20 bytes cummulative checksum must equal 0', csum == 0) testsuite.print_detail("Cummulative checksum = {} (Expected 0)".format(csum)) test_table_checksum(data) rsdp = acpi.RSDP(data)
def test_rsdp(): data = acpi.get_table("RSD PTR ") if data is None: return # Checksum the first 20 bytes per ACPI 1.0 csum = sum(ord(c) for c in data[:20]) % 0x100 testsuite.test('ACPI 1.0 table first 20 bytes cummulative checksum must equal 0', csum == 0) testsuite.print_detail("Cummulative checksum = {} (Expected 0)".format(csum)) test_table_checksum(data) rsdp = acpi.parse_rsdp()
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 test_pm_generic_profile(): testmsr.test_msr_consistency("Max non-turbo ratio must be consistent", 0xce, mask=0xff00) testpci.test_pci("Bus master disable", 0, 31, 0, 0xa9, bytes=1, shift=2, mask=1, expected_value=1) testmsr.test_msr("C1 Auto Demotion Enable", 0xe2, shift=26, mask=1, expected_value=1) testmsr.test_msr("C3 Auto Demotion Enable", 0xe2, shift=25, mask=1, expected_value=1) testmsr.test_msr("IO MWAIT Redirection Enable", 0xe2, shift=10, mask=1, expected_value=1) testmsr.test_msr("C1E Enable", 0x1fc, shift=1, mask=1, expected_value=1) testmsr.test_msr("EIST Enable", 0x1a0, shift=16, mask=1, expected_value=1) testmsr.test_msr("Turbo Enable", 0x1a0, shift=38, mask=1, expected_value=0) testmsr.test_msr("EIST Hardware Coordination Enable", 0x1aa, mask=1, expected_value=0) testmsr.test_msr_consistency("IO Capture C-state Range Consistent", 0xe4, shift=16, mask=7) io_capture_range, io_capture_range_str = testmsr.MSR("IO Capture C-state Range", bits.bsp_apicid(), 0xe4, 18, 16) testsuite.test("IO Capture C-state Range <= 2", io_capture_range <= 2) testsuite.print_detail(io_capture_range_str)
def test_msr(text, msr, expected_value, cpu=None, shift=0, mask=~0, highbit=63, lowbit=0): """Test the value of an MSR. Fails if any CPU does not match expected_value. Pass expected_value=None to expect a GPF.""" uniques, desc = rdmsr_helper(msr=msr, cpu=cpu, shift=shift, mask=mask, highbit=highbit, lowbit=lowbit) if expected_value is None: desc[0] += " (Expected GPF)" else: desc[0] += " (Expected {:#x})".format(expected_value) if text: desc.insert(0, text) status = testsuite.test(desc[0], len(uniques) == 1 and uniques.keys()[0] == expected_value) for line in desc[1:]: testsuite.print_detail(line) return status
def smi_latency(): MSR_SMI_COUNT = 0x34 print "Warning: touching the keyboard can affect the results of this test." tsc_per_sec = bits.tsc_per_sec() tsc_per_usec = tsc_per_sec / (1000 * 1000) 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 test. 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, bits.format_tsc(bin.total / bin.count), bin.count)) deltas = (bits.format_tsc(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( bits.format_tsc(max_latency)))
def test_psd_thread_scope(): uniques = acpi.parse_cpu_method("_PSD") if not testsuite.test("_PSD (P-State Dependency) must exist for each processor", None not in uniques): testsuite.print_detail(acpi.factor_commonprefix(uniques[None])) testsuite.print_detail('No _PSD exists') return unique_num_dependencies = {} unique_num_entries = {} unique_revision = {} unique_domain = {} unique_coordination_type = {} unique_num_processors = {} for value, cpupaths in uniques.iteritems(): unique_num_dependencies.setdefault(len(value.dependencies), []).extend(cpupaths) unique_num_entries.setdefault(value.dependencies[0].num_entries, []).extend(cpupaths) unique_revision.setdefault(value.dependencies[0].revision, []).extend(cpupaths) unique_domain.setdefault(value.dependencies[0].domain, []).extend(cpupaths) unique_coordination_type.setdefault(value.dependencies[0].coordination_type, []).extend(cpupaths) unique_num_processors.setdefault(value.dependencies[0].num_processors, []).extend(cpupaths) def detail(d, fmt): for value, cpupaths in sorted(d.iteritems(), key=(lambda (k,v): v)): testsuite.print_detail(acpi.factor_commonprefix(cpupaths)) testsuite.print_detail(fmt.format(value)) testsuite.test('Dependency count for each processor must be 1', unique_num_dependencies.keys() == [1]) detail(unique_num_dependencies, 'Dependency count for each processor = {} (Expected 1)') testsuite.test('_PSD.num_entries must be 5', unique_num_entries.keys() == [5]) detail(unique_num_entries, 'num_entries = {} (Expected 5)') testsuite.test('_PSD.revision must be 0', unique_revision.keys() == [0]) detail(unique_revision, 'revision = {}') testsuite.test('_PSD.coordination_type must be 0xFE (HW_ALL)', unique_coordination_type.keys() == [0xfe]) detail(unique_coordination_type, 'coordination_type = {:#x} (Expected 0xFE HW_ALL)') testsuite.test('_PSD.domain must be unique (thread-scoped) for each processor', len(unique_domain) == len(acpi.get_cpupaths())) detail(unique_domain, 'domain = {:#x} (Expected a unique value for each processor)') testsuite.test('_PSD.num_processors must be 1', unique_num_processors.keys() == [1]) detail(unique_num_processors, 'num_processors = {} (Expected 1)')
def smi_latency(): MSR_SMI_COUNT = 0x34 print "Warning: touching the keyboard can affect the results of this test." tsc_per_sec = bits.tsc_per_sec() tsc_per_usec = tsc_per_sec / (1000 * 1000) 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 test. 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, bits.format_tsc(bin.total/bin.count), bin.count)) deltas = (bits.format_tsc(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(bits.format_tsc(max_latency)))
def test_pirtable(): """Test the PCI Interrupt Routing Table""" pir = PIRTable() if pir is None: return addr = bits.memory_addr(pir._table_memory) for address, size in bad_address_ranges: if addr >= address and addr < address + size: bad_address = True break else: bad_address = False testsuite.test('PCI Interrupt Routing Table spec-compliant address', not bad_address) testsuite.print_detail('Found PCI Interrupt Routing Table at bad address {:#x}'.format(addr)) testsuite.print_detail('$PIR Structure must appear at a 16-byte-aligned address') testsuite.print_detail('located in the 0xF0000 to 0xFFFFF block')
def test_pirtable(): """Test the PCI Interrupt Routing Table""" pir = PIRTable() if pir is None: return addr = bits.memory_addr(pir._table_memory) for address, size in bad_address_ranges: if addr >= address and addr < address + size: bad_address = True break else: bad_address = False testsuite.test('PCI Interrupt Routing Table spec-compliant address', not bad_address) testsuite.print_detail( 'Found PCI Interrupt Routing Table at bad address {:#x}'.format(addr)) testsuite.print_detail( '$PIR Structure must appear at a 16-byte-aligned address') testsuite.print_detail('located in the 0xF0000 to 0xFFFFF block')
def test_pss(): uniques = acpi.parse_cpu_method("_PSS") for pss, cpupaths in uniques.iteritems(): if not testsuite.test("_PSS must exist", pss is not None): testsuite.print_detail(acpi.factor_commonprefix(cpupaths)) testsuite.print_detail('No _PSS exists') continue if not testsuite.test("_PSS must not be empty", pss.pstates): testsuite.print_detail(acpi.factor_commonprefix(cpupaths)) testsuite.print_detail('_PSS is empty') continue testsuite.test("_PSS must contain at most 16 Pstates", len(pss.pstates) <= 16) testsuite.print_detail(acpi.factor_commonprefix(cpupaths)) map(testsuite.print_detail, repr(pss)) testsuite.test("_PSS must have no duplicate Pstates", len(pss.pstates) == len(set(pss.pstates))) testsuite.print_detail(acpi.factor_commonprefix(cpupaths)) map(testsuite.print_detail, repr(pss)) frequencies = [p.core_frequency for p in pss.pstates] testsuite.test("_PSS must list Pstates in descending order of frequency", frequencies == sorted(frequencies, reverse=True)) testsuite.print_detail(acpi.factor_commonprefix(cpupaths)) map(testsuite.print_detail, repr(pss)) testsuite.test("_PSS must have Pstates with no duplicate frequencies", len(frequencies) == len(set(frequencies))) testsuite.print_detail(acpi.factor_commonprefix(cpupaths)) map(testsuite.print_detail, repr(pss)) dissipations = [p.power for p in pss.pstates] testsuite.test("_PSS must list Pstates in descending order of power dissipation", dissipations == sorted(dissipations, reverse=True)) testsuite.print_detail(acpi.factor_commonprefix(cpupaths)) map(testsuite.print_detail, repr(pss))
def test_mat(): cpupaths = acpi.get_cpupaths() procid_apicid, uid_x2apicid = acpi.parse_apic() for cpupath in cpupaths: # Find the ProcId defined by the processor object processor = acpi.evaluate(cpupath) # Find the UID defined by the processor object's _UID method uid = acpi.evaluate(cpupath + "._UID") mat_buffer = acpi.evaluate(cpupath + "._MAT") if mat_buffer is None: continue # Process each _MAT subtable mat = acpi._MAT(mat_buffer) for index, subtable in enumerate(mat.subtables): if subtable.type == acpi.MADT_TYPE_LOCAL_APIC: if subtable.enabled: testsuite.test("{} Processor declaration ProcId = _MAT ProcId".format(cpupath), processor.ProcId == subtable.proc_id) testsuite.print_detail("{} ProcId ({:#02x}) != _MAT ProcId ({:#02x})".format(cpupath, processor.ProcId, subtable.proc_id)) testsuite.print_detail("Processor Declaration: {}".format(processor)) testsuite.print_detail("_MAT entry[{}]: {}".format(index, subtable)) if testsuite.test("{} with local APIC in _MAT has local APIC in MADT".format(cpupath), processor.ProcId in procid_apicid): testsuite.test("{} ApicId derived using Processor declaration ProcId = _MAT ApicId".format(cpupath), procid_apicid[processor.ProcId] == subtable.apic_id) testsuite.print_detail("{} ApicId derived from MADT ({:#02x}) != _MAT ApicId ({:#02x})".format(cpupath, procid_apicid[processor.ProcId], subtable.apic_id)) testsuite.print_detail("Processor Declaration: {}".format(processor)) testsuite.print_detail("_MAT entry[{}]: {}".format(index, subtable)) if subtable.type == acpi.MADT_TYPE_LOCAL_X2APIC: if subtable.enabled: if testsuite.test("{} with x2Apic in _MAT has _UID".format(cpupath), uid is not None): testsuite.test("{}._UID = _MAT UID".format(cpupath), uid == subtable.uid) testsuite.print_detail("{}._UID ({:#x}) != _MAT UID ({:#x})".format(cpupath, uid, subtable.uid)) testsuite.print_detail("_MAT entry[{}]: {}".format(index, subtable)) if testsuite.test("{} with _MAT x2Apic has x2Apic in MADT".format(cpupath), subtable.uid in uid_x2apicid): testsuite.test("{} x2ApicId derived from MADT using UID = _MAT x2ApicId".format(cpupath), uid_x2apicid[subtable.uid] == subtable.x2apicid) testsuite.print_detail("{} x2ApicId derived from MADT ({:#02x}) != _MAT x2ApicId ({:#02x})".format(cpupath, uid_x2apicid[subtable.uid], subtable.x2apicid)) testsuite.print_detail("_MAT entry[{}]: {}".format(index, x2Apic))
def test_pss(): uniques = acpi.parse_cpu_method("_PSS") # We special-case None here to avoid a double-failure for CPUs without a _PSS testsuite.test("_PSS must be identical for all CPUs", len(uniques) <= 1 or (len(uniques) == 2 and None in uniques)) for pss, cpupaths in uniques.iteritems(): if not testsuite.test("_PSS must exist", pss is not None): testsuite.print_detail(acpi.factor_commonprefix(cpupaths)) testsuite.print_detail('No _PSS exists') continue if not testsuite.test("_PSS must not be empty", pss.pstates): testsuite.print_detail(acpi.factor_commonprefix(cpupaths)) testsuite.print_detail('_PSS is empty') continue testsuite.print_detail(acpi.factor_commonprefix(cpupaths)) for index, pstate in enumerate(pss.pstates): testsuite.print_detail("P[{}]: {}".format(index, pstate)) testsuite.test("_PSS must contain at most 16 Pstates", len(pss.pstates) <= 16) testsuite.test("_PSS must have no duplicate Pstates", len(pss.pstates) == len(set(pss.pstates))) frequencies = [p.core_frequency for p in pss.pstates] testsuite.test("_PSS must list Pstates in descending order of frequency", frequencies == sorted(frequencies, reverse=True)) testsuite.test("_PSS must have Pstates with no duplicate frequencies", len(frequencies) == len(set(frequencies))) dissipations = [p.power for p in pss.pstates] testsuite.test("_PSS must list Pstates in descending order of power dissipation", dissipations == sorted(dissipations, reverse=True))
def test_table_checksum(data): csum = sum(ord(c) for c in data) % 0x100 testsuite.test('ACPI table cumulative checksum must equal 0', csum == 0) testsuite.print_detail("Cumulative checksum = {} (Expected 0)".format(csum))
def detail(d, fmt): for value, cpupaths in sorted(d.iteritems(), key=(lambda (k,v): v)): testsuite.print_detail(acpi.factor_commonprefix(cpupaths)) testsuite.print_detail(fmt.format(value))
def test_pstates(): """Execute and verify frequency for each Pstate in the _PSS""" old_mwait = {} try: IA32_PERF_CTL = 0x199 # Force use of MWAIT C3 hint = 0x20 cpus = bits.cpus() for apicid in cpus: old_mwait[apicid] = bits.get_mwait(apicid) bits.set_mwait(apicid, True, hint) cpupath_procid = acpi.find_procid() cpupath_uid = acpi.find_uid() procid_apicid, uid_x2apicid = acpi.parse_apic() def cpupath_apicid(cpupath): if procid_apicid is not None: procid = cpupath_procid.get(cpupath, None) if procid is not None: apicid = procid_apicid.get(procid, None) if apicid is not None: return apicid if uid_x2apicid is not None: uid = cpupath_uid.get(cpupath, None) if uid is not None: apicid = uid_x2apicid.get(uid, None) if apicid is not None: return apicid return bits.cpus()[0] bclk = testutil.adjust_to_nearest(bits.bclk(), 100.0/12) * 1000000 uniques = acpi.parse_cpu_method("_PSS") for pss, cpupaths in uniques.iteritems(): if not testsuite.test("_PSS must exist", pss is not None): testsuite.print_detail(acpi.factor_commonprefix(cpupaths)) testsuite.print_detail('No _PSS exists') continue print "Test duration is ~{} seconds...".format(len(pss.pstates) + 2) for n, pstate in enumerate(pss.pstates): for cpupath in cpupaths: apicid = cpupath_apicid(cpupath) if apicid is None: print 'Failed to find apicid for cpupath {}'.format(cpupath) continue bits.wrmsr(apicid, IA32_PERF_CTL, pstate.control) # Detecting Turbo frequency requires at least 2 pstates # since turbo frequency = max non-turbo frequency + 1 turbo = False if len(pss.pstates) >= 2: turbo = (n == 0 and pstate.core_frequency == (pss.pstates[1].core_frequency + 1)) if turbo: # Needs to busywait, not sleep start = time.time() while (time.time() - start < 2): pass # Abort the test if no cpu frequency is not available if bits.cpu_frequency() is None: continue aperf = bits.cpu_frequency()[1] aperf = testutil.adjust_to_nearest(aperf, bclk/2) aperf = int(aperf / 1000000) if turbo: testsuite.test("P{}: Turbo measured frequency {} >= expected {} MHz".format(n, aperf, pstate.core_frequency), aperf >= pstate.core_frequency) else: testsuite.test("P{}: measured frequency {} MHz == expected {} MHz".format(n, aperf, pstate.core_frequency), aperf == pstate.core_frequency) finally: for apicid, old_mwait_values in old_mwait.iteritems(): bits.set_mwait(apicid, *old_mwait_values)
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 test_pstates(): """Execute and verify frequency for each Pstate in the _PSS""" IA32_PERF_CTL = 0x199 with bits.mwait.use_hint(), bits.preserve_msr(IA32_PERF_CTL): cpupath_procid = acpi.find_procid() cpupath_uid = acpi.find_uid() apic = acpi.parse_apic() procid_apicid = apic.procid_apicid uid_x2apicid = apic.uid_x2apicid def cpupath_apicid(cpupath): if procid_apicid is not None: procid = cpupath_procid.get(cpupath, None) if procid is not None: apicid = procid_apicid.get(procid, None) if apicid is not None: return apicid if uid_x2apicid is not None: uid = cpupath_uid.get(cpupath, None) if uid is not None: apicid = uid_x2apicid.get(uid, None) if apicid is not None: return apicid return bits.cpus()[0] bclk = testutil.adjust_to_nearest(bits.bclk(), 100.0/12) * 1000000 uniques = acpi.parse_cpu_method("_PSS") for pss, cpupaths in uniques.iteritems(): if not testsuite.test("_PSS must exist", pss is not None): testsuite.print_detail(acpi.factor_commonprefix(cpupaths)) testsuite.print_detail('No _PSS exists') continue for n, pstate in enumerate(pss.pstates): for cpupath in cpupaths: apicid = cpupath_apicid(cpupath) if apicid is None: print 'Failed to find apicid for cpupath {}'.format(cpupath) continue bits.wrmsr(apicid, IA32_PERF_CTL, pstate.control) # Detecting Turbo frequency requires at least 2 pstates # since turbo frequency = max non-turbo frequency + 1 turbo = False if len(pss.pstates) >= 2: turbo = (n == 0 and pstate.core_frequency == (pss.pstates[1].core_frequency + 1)) if turbo: # Needs to busywait, not sleep start = time.time() while (time.time() - start < 2): pass for duration in (0.1, 1.0): frequency_data = bits.cpu_frequency(duration) # Abort the test if no cpu frequency is not available if frequency_data is None: continue aperf = frequency_data[1] aperf = testutil.adjust_to_nearest(aperf, bclk/2) aperf = int(aperf / 1000000) if turbo: if aperf >= pstate.core_frequency: break else: if aperf == pstate.core_frequency: break if turbo: testsuite.test("P{}: Turbo measured frequency {} >= expected {} MHz".format(n, aperf, pstate.core_frequency), aperf >= pstate.core_frequency) else: testsuite.test("P{}: measured frequency {} MHz == expected {} MHz".format(n, aperf, pstate.core_frequency), aperf == pstate.core_frequency)
def test_mat(): cpupaths = acpi.get_cpupaths() apic = acpi.parse_apic() procid_apicid = apic.procid_apicid uid_x2apicid = apic.uid_x2apicid for cpupath in cpupaths: # Find the ProcId defined by the processor object processor = acpi.evaluate(cpupath) # Find the UID defined by the processor object's _UID method uid = acpi.evaluate(cpupath + "._UID") mat_buffer = acpi.evaluate(cpupath + "._MAT") if mat_buffer is None: continue # Process each _MAT subtable mat = acpi._MAT(mat_buffer) for index, subtable in enumerate(mat): if subtable.subtype == acpi.MADT_TYPE_LOCAL_APIC: if subtable.flags.bits.enabled: testsuite.test("{} Processor declaration ProcId = _MAT ProcId".format(cpupath), processor.ProcId == subtable.proc_id) testsuite.print_detail("{} ProcId ({:#02x}) != _MAT ProcId ({:#02x})".format(cpupath, processor.ProcId, subtable.proc_id)) testsuite.print_detail("Processor Declaration: {}".format(processor)) testsuite.print_detail("_MAT entry[{}]: {}".format(index, subtable)) if testsuite.test("{} with local APIC in _MAT has local APIC in MADT".format(cpupath), processor.ProcId in procid_apicid): testsuite.test("{} ApicId derived using Processor declaration ProcId = _MAT ApicId".format(cpupath), procid_apicid[processor.ProcId] == subtable.apic_id) testsuite.print_detail("{} ApicId derived from MADT ({:#02x}) != _MAT ApicId ({:#02x})".format(cpupath, procid_apicid[processor.ProcId], subtable.apic_id)) testsuite.print_detail("Processor Declaration: {}".format(processor)) testsuite.print_detail("_MAT entry[{}]: {}".format(index, subtable)) if subtable.subtype == acpi.MADT_TYPE_LOCAL_X2APIC: if subtable.flags.bits.enabled: if testsuite.test("{} with x2Apic in _MAT has _UID".format(cpupath), uid is not None): testsuite.test("{}._UID = _MAT UID".format(cpupath), uid == subtable.uid) testsuite.print_detail("{}._UID ({:#x}) != _MAT UID ({:#x})".format(cpupath, uid, subtable.uid)) testsuite.print_detail("_MAT entry[{}]: {}".format(index, subtable)) if testsuite.test("{} with _MAT x2Apic has x2Apic in MADT".format(cpupath), subtable.uid in uid_x2apicid): testsuite.test("{} x2ApicId derived from MADT using UID = _MAT x2ApicId".format(cpupath), uid_x2apicid[subtable.uid] == subtable.x2apicid) testsuite.print_detail("{} x2ApicId derived from MADT ({:#02x}) != _MAT x2ApicId ({:#02x})".format(cpupath, uid_x2apicid[subtable.uid], subtable.x2apicid)) testsuite.print_detail("_MAT entry[{}]: {}".format(index, subtable))
def test_mptable(): """Test the MP Table""" mp = MPTable() if mp is None: return addr = bits.memory_addr(mp._floating_pointer_memory) for address, size in bad_address_ranges: if addr >= address and addr < address + size: bad_address = True break else: bad_address = False testsuite.test('MP Floating Pointer Structure at spec-compliant address', not bad_address) testsuite.print_detail( 'Found MP Floating Pointer Structure at bad address {:#x}'.format( addr)) testsuite.print_detail( 'MP Floating Pointer Structure must appear at a 16-byte-aligned address' ) testsuite.print_detail('located, in order of preference, in:') testsuite.print_detail('- the first kilobyte of the EBDA') testsuite.print_detail( '- the last kilobyte of system base memory (639k to 640k)') testsuite.print_detail('- the 0xF0000 to 0xFFFFF block')
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 test_mptable(): """Test the MP Table""" mp = MPTable() if mp is None: return addr = bits.memory_addr(mp._floating_pointer_memory) for address, size in bad_address_ranges: if addr >= address and addr < address + size: bad_address = True break else: bad_address = False testsuite.test('MP Floating Pointer Structure at spec-compliant address', not bad_address) testsuite.print_detail('Found MP Floating Pointer Structure at bad address {:#x}'.format(addr)) testsuite.print_detail('MP Floating Pointer Structure must appear at a 16-byte-aligned address') testsuite.print_detail('located, in order of preference, in:') testsuite.print_detail('- the first kilobyte of the EBDA') testsuite.print_detail('- the last kilobyte of system base memory (639k to 640k)') testsuite.print_detail('- the 0xF0000 to 0xFFFFF block')