1*05caa062SThomas Huth# Copyright (c) 2012, 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"""Tests and helpers for CPUID."""
32*05caa062SThomas Huth
33*05caa062SThomas Huthimport bits
34*05caa062SThomas Huthimport testsuite
35*05caa062SThomas Huthimport testutil
36*05caa062SThomas Huth
37*05caa062SThomas Huthdef cpuid_helper(function, index=None, shift=0, mask=~0, eax_mask=~0, ebx_mask=~0, ecx_mask=~0, edx_mask=~0):
38*05caa062SThomas Huth    if index is None:
39*05caa062SThomas Huth        index = 0
40*05caa062SThomas Huth        indexdesc = ""
41*05caa062SThomas Huth    else:
42*05caa062SThomas Huth        indexdesc = " index {0:#x}".format(index)
43*05caa062SThomas Huth
44*05caa062SThomas Huth    def find_mask(m):
45*05caa062SThomas Huth        if m == ~0:
46*05caa062SThomas Huth            return mask
47*05caa062SThomas Huth        return m
48*05caa062SThomas Huth    masks = map(find_mask, [eax_mask, ebx_mask, ecx_mask, edx_mask])
49*05caa062SThomas Huth
50*05caa062SThomas Huth    uniques = {}
51*05caa062SThomas Huth    for cpu in bits.cpus():
52*05caa062SThomas Huth        regs = bits.cpuid_result(*[(r >> shift) & m for r, m in zip(bits.cpuid(cpu, function, index), masks)])
53*05caa062SThomas Huth        uniques.setdefault(regs, []).append(cpu)
54*05caa062SThomas Huth
55*05caa062SThomas Huth    desc = ["CPUID function {:#x}{}".format(function, indexdesc)]
56*05caa062SThomas Huth
57*05caa062SThomas Huth    if shift != 0:
58*05caa062SThomas Huth        desc.append("Register values have been shifted by {}".format(shift))
59*05caa062SThomas Huth    if mask != ~0 or eax_mask != ~0 or ebx_mask != ~0 or ecx_mask != ~0 or edx_mask != ~0:
60*05caa062SThomas Huth        desc.append("Register values have been masked:")
61*05caa062SThomas Huth        shifted_masks = bits.cpuid_result(*[m << shift for m in masks])
62*05caa062SThomas Huth        desc.append("Masks:           eax={eax:#010x} ebx={ebx:#010x} ecx={ecx:#010x} edx={edx:#010x}".format(**shifted_masks._asdict()))
63*05caa062SThomas Huth
64*05caa062SThomas Huth    if len(uniques) > 1:
65*05caa062SThomas Huth        regvalues = zip(*uniques.iterkeys())
66*05caa062SThomas Huth        common_masks = bits.cpuid_result(*map(testutil.find_common_mask, regvalues))
67*05caa062SThomas Huth        common_values = bits.cpuid_result(*[v[0] & m for v, m in zip(regvalues, common_masks)])
68*05caa062SThomas Huth        desc.append('Register values are not unique across all logical processors')
69*05caa062SThomas Huth        desc.append("Common bits:     eax={eax:#010x} ebx={ebx:#010x} ecx={ecx:#010x} edx={edx:#010x}".format(**common_values._asdict()))
70*05caa062SThomas Huth        desc.append("Mask of common bits: {eax:#010x}     {ebx:#010x}     {ecx:#010x}     {edx:#010x}".format(**common_masks._asdict()))
71*05caa062SThomas Huth
72*05caa062SThomas Huth    for regs in sorted(uniques.iterkeys()):
73*05caa062SThomas Huth        cpus = uniques[regs]
74*05caa062SThomas Huth        desc.append("Register value:  eax={eax:#010x} ebx={ebx:#010x} ecx={ecx:#010x} edx={edx:#010x}".format(**regs._asdict()))
75*05caa062SThomas Huth        desc.append("On {0} CPUs: {1}".format(len(cpus), testutil.apicid_list(cpus)))
76*05caa062SThomas Huth
77*05caa062SThomas Huth    return uniques, desc
78*05caa062SThomas Huth
79*05caa062SThomas Huthdef test_cpuid_consistency(text, function, index=None, shift=0, mask=~0, eax_mask=~0, ebx_mask=~0, ecx_mask=~0, edx_mask=~0):
80*05caa062SThomas Huth    uniques, desc = cpuid_helper(function, index, shift, mask, eax_mask, ebx_mask, ecx_mask, edx_mask)
81*05caa062SThomas Huth    desc[0] += " Consistency Check"
82*05caa062SThomas Huth    if text:
83*05caa062SThomas Huth        desc.insert(0, text)
84*05caa062SThomas Huth    status = testsuite.test(desc[0], len(uniques) == 1)
85*05caa062SThomas Huth    for line in desc[1:]:
86*05caa062SThomas Huth        testsuite.print_detail(line)
87*05caa062SThomas Huth    return status
88