1*05caa062SThomas Huth# Copyright (c) 2015, Intel Corporation 2*05caa062SThomas Huth# All rights reserved. 3*05caa062SThomas Huth# 4*05caa062SThomas Huth# SPDX-License-Identifier: BSD-3-Clause 5*05caa062SThomas Huth 6*05caa062SThomas Huth# Redistribution and use in source and binary forms, with or without 7*05caa062SThomas Huth# modification, are permitted provided that the following conditions are met: 8*05caa062SThomas Huth# 9*05caa062SThomas Huth# * Redistributions of source code must retain the above copyright notice, 10*05caa062SThomas Huth# this list of conditions and the following disclaimer. 11*05caa062SThomas Huth# * Redistributions in binary form must reproduce the above copyright notice, 12*05caa062SThomas Huth# this list of conditions and the following disclaimer in the documentation 13*05caa062SThomas Huth# and/or other materials provided with the distribution. 14*05caa062SThomas Huth# * Neither the name of Intel Corporation nor the names of its contributors 15*05caa062SThomas Huth# may be used to endorse or promote products derived from this software 16*05caa062SThomas Huth# without specific prior written permission. 17*05caa062SThomas Huth# 18*05caa062SThomas Huth# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 19*05caa062SThomas Huth# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20*05caa062SThomas Huth# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21*05caa062SThomas Huth# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 22*05caa062SThomas Huth# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23*05caa062SThomas Huth# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24*05caa062SThomas Huth# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 25*05caa062SThomas Huth# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26*05caa062SThomas Huth# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 27*05caa062SThomas Huth# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28*05caa062SThomas Huth 29*05caa062SThomas Huth# This script runs only from the biosbits VM. 30*05caa062SThomas Huth 31*05caa062SThomas Huth"""SMI latency test.""" 32*05caa062SThomas Huth 33*05caa062SThomas Huthimport bits 34*05caa062SThomas Huthfrom collections import namedtuple 35*05caa062SThomas Huthimport testsuite 36*05caa062SThomas Huthimport time 37*05caa062SThomas Huthimport usb 38*05caa062SThomas Huth 39*05caa062SThomas Huthdef register_tests(): 40*05caa062SThomas Huth pass 41*05caa062SThomas Huth# testsuite.add_test("SMI latency test", smi_latency); 42*05caa062SThomas Huth# testsuite.add_test("SMI latency test with USB disabled via BIOS handoff", test_with_usb_disabled, runall=False); 43*05caa062SThomas Huth 44*05caa062SThomas Huthdef smi_latency(): 45*05caa062SThomas Huth MSR_SMI_COUNT = 0x34 46*05caa062SThomas Huth 47*05caa062SThomas Huth print "Warning: touching the keyboard can affect the results of this test." 48*05caa062SThomas Huth 49*05caa062SThomas Huth tsc_per_sec = bits.tsc_per_sec() 50*05caa062SThomas Huth tsc_per_usec = tsc_per_sec / (1000 * 1000) 51*05caa062SThomas Huth bins = [long(tsc_per_usec * 10**i) for i in range(9)] 52*05caa062SThomas Huth bin_descs = [ 53*05caa062SThomas Huth "0 < t <= 1us", 54*05caa062SThomas Huth "1us < t <= 10us", 55*05caa062SThomas Huth "10us < t <= 100us", 56*05caa062SThomas Huth "100us < t <= 1ms", 57*05caa062SThomas Huth "1ms < t <= 10ms", 58*05caa062SThomas Huth "10ms < t <= 100ms", 59*05caa062SThomas Huth "100ms < t <= 1s ", 60*05caa062SThomas Huth "1s < t <= 10s ", 61*05caa062SThomas Huth "10s < t <= 100s ", 62*05caa062SThomas Huth "100s < t ", 63*05caa062SThomas Huth ] 64*05caa062SThomas Huth 65*05caa062SThomas Huth print "Starting test. Wait here, I will be back in 15 seconds." 66*05caa062SThomas Huth (max_latency, smi_count_delta, bins) = bits.smi_latency(long(15 * tsc_per_sec), bins) 67*05caa062SThomas Huth BinType = namedtuple('BinType', ("max", "total", "count", "times")) 68*05caa062SThomas Huth bins = [BinType(*b) for b in bins] 69*05caa062SThomas Huth 70*05caa062SThomas Huth testsuite.test("SMI latency < 150us to minimize risk of OS timeouts", max_latency / tsc_per_usec <= 150) 71*05caa062SThomas Huth if not testsuite.show_detail(): 72*05caa062SThomas Huth return 73*05caa062SThomas Huth 74*05caa062SThomas Huth for bin, desc in zip(bins, bin_descs): 75*05caa062SThomas Huth if bin.count == 0: 76*05caa062SThomas Huth continue 77*05caa062SThomas Huth testsuite.print_detail("{}; average = {}; count = {}".format(desc, bits.format_tsc(bin.total/bin.count), bin.count)) 78*05caa062SThomas Huth deltas = (bits.format_tsc(t2 - t1) for t1,t2 in zip(bin.times, bin.times[1:])) 79*05caa062SThomas Huth testsuite.print_detail(" Times between first few observations: {}".format(" ".join("{:>6}".format(delta) for delta in deltas))) 80*05caa062SThomas Huth 81*05caa062SThomas Huth if smi_count_delta is not None: 82*05caa062SThomas Huth testsuite.print_detail("{} SMI detected using MSR_SMI_COUNT (MSR {:#x})".format(smi_count_delta, MSR_SMI_COUNT)) 83*05caa062SThomas Huth 84*05caa062SThomas Huth testsuite.print_detail("Summary of impact: observed maximum latency = {}".format(bits.format_tsc(max_latency))) 85*05caa062SThomas Huth 86*05caa062SThomas Huthdef test_with_usb_disabled(): 87*05caa062SThomas Huth if usb.handoff_to_os(): 88*05caa062SThomas Huth smi_latency() 89*05caa062SThomas Huth 90*05caa062SThomas Huthdef average_io_smi(port, value, count): 91*05caa062SThomas Huth def f(): 92*05caa062SThomas Huth tsc_start = bits.rdtsc() 93*05caa062SThomas Huth bits.outb(port, value) 94*05caa062SThomas Huth return bits.rdtsc() - tsc_start 95*05caa062SThomas Huth counts = [f() for i in range(count)] 96*05caa062SThomas Huth return sum(counts)/len(counts) 97*05caa062SThomas Huth 98*05caa062SThomas Huthdef time_io_smi(port=0xb2, value=0, count=1000): 99*05caa062SThomas Huth count_for_estimate = 10 100*05caa062SThomas Huth start = time.time() 101*05caa062SThomas Huth average_io_smi(port, value, count_for_estimate) 102*05caa062SThomas Huth avg10 = time.time() - start 103*05caa062SThomas Huth estimate = avg10 * count/count_for_estimate 104*05caa062SThomas Huth if estimate > 1: 105*05caa062SThomas Huth print "Running test, estimated time: {}s".format(int(estimate)) 106*05caa062SThomas Huth average = average_io_smi(port, value, count) 107*05caa062SThomas Huth print "Average of {} SMIs (via outb, port={:#x}, value={:#x}): {}".format(count, port, value, bits.format_tsc(average)) 108