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