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"""Tests for ACPI"""
32*05caa062SThomas Huth
33*05caa062SThomas Huthimport acpi
34*05caa062SThomas Huthimport bits
35*05caa062SThomas Huthimport bits.mwait
36*05caa062SThomas Huthimport struct
37*05caa062SThomas Huthimport testutil
38*05caa062SThomas Huthimport testsuite
39*05caa062SThomas Huthimport time
40*05caa062SThomas Huth
41*05caa062SThomas Huthdef register_tests():
42*05caa062SThomas Huth    testsuite.add_test("ACPI _MAT (Multiple APIC Table Entry) under Processor objects", test_mat, submenu="ACPI Tests")
43*05caa062SThomas Huth#    testsuite.add_test("ACPI _PSS (Pstate) table conformance tests", test_pss, submenu="ACPI Tests")
44*05caa062SThomas Huth#    testsuite.add_test("ACPI _PSS (Pstate) runtime tests", test_pstates, submenu="ACPI Tests")
45*05caa062SThomas Huth    testsuite.add_test("ACPI DSDT (Differentiated System Description Table)", test_dsdt, submenu="ACPI Tests")
46*05caa062SThomas Huth    testsuite.add_test("ACPI FACP (Fixed ACPI Description Table)", test_facp, submenu="ACPI Tests")
47*05caa062SThomas Huth    testsuite.add_test("ACPI HPET (High Precision Event Timer Table)", test_hpet, submenu="ACPI Tests")
48*05caa062SThomas Huth    testsuite.add_test("ACPI MADT (Multiple APIC Description Table)", test_apic, submenu="ACPI Tests")
49*05caa062SThomas Huth    testsuite.add_test("ACPI MPST (Memory Power State Table)", test_mpst, submenu="ACPI Tests")
50*05caa062SThomas Huth    testsuite.add_test("ACPI RSDP (Root System Description Pointer Structure)", test_rsdp, submenu="ACPI Tests")
51*05caa062SThomas Huth    testsuite.add_test("ACPI XSDT (Extended System Description Table)", test_xsdt, submenu="ACPI Tests")
52*05caa062SThomas Huth
53*05caa062SThomas Huthdef test_mat():
54*05caa062SThomas Huth    cpupaths = acpi.get_cpupaths()
55*05caa062SThomas Huth    apic = acpi.parse_apic()
56*05caa062SThomas Huth    procid_apicid = apic.procid_apicid
57*05caa062SThomas Huth    uid_x2apicid = apic.uid_x2apicid
58*05caa062SThomas Huth    for cpupath in cpupaths:
59*05caa062SThomas Huth        # Find the ProcId defined by the processor object
60*05caa062SThomas Huth        processor = acpi.evaluate(cpupath)
61*05caa062SThomas Huth        # Find the UID defined by the processor object's _UID method
62*05caa062SThomas Huth        uid = acpi.evaluate(cpupath + "._UID")
63*05caa062SThomas Huth        mat_buffer = acpi.evaluate(cpupath + "._MAT")
64*05caa062SThomas Huth        if mat_buffer is None:
65*05caa062SThomas Huth            continue
66*05caa062SThomas Huth        # Process each _MAT subtable
67*05caa062SThomas Huth        mat = acpi._MAT(mat_buffer)
68*05caa062SThomas Huth        for index, subtable in enumerate(mat):
69*05caa062SThomas Huth            if subtable.subtype == acpi.MADT_TYPE_LOCAL_APIC:
70*05caa062SThomas Huth                if subtable.flags.bits.enabled:
71*05caa062SThomas Huth                    testsuite.test("{} Processor declaration ProcId = _MAT ProcId".format(cpupath), processor.ProcId == subtable.proc_id)
72*05caa062SThomas Huth                    testsuite.print_detail("{} ProcId ({:#02x}) != _MAT ProcId ({:#02x})".format(cpupath, processor.ProcId, subtable.proc_id))
73*05caa062SThomas Huth                    testsuite.print_detail("Processor Declaration: {}".format(processor))
74*05caa062SThomas Huth                    testsuite.print_detail("_MAT entry[{}]: {}".format(index, subtable))
75*05caa062SThomas Huth                    if testsuite.test("{} with local APIC in _MAT has local APIC in MADT".format(cpupath), processor.ProcId in procid_apicid):
76*05caa062SThomas Huth                        testsuite.test("{} ApicId derived using Processor declaration ProcId = _MAT ApicId".format(cpupath), procid_apicid[processor.ProcId] == subtable.apic_id)
77*05caa062SThomas Huth                        testsuite.print_detail("{} ApicId derived from MADT ({:#02x}) != _MAT ApicId ({:#02x})".format(cpupath, procid_apicid[processor.ProcId], subtable.apic_id))
78*05caa062SThomas Huth                        testsuite.print_detail("Processor Declaration: {}".format(processor))
79*05caa062SThomas Huth                        testsuite.print_detail("_MAT entry[{}]: {}".format(index, subtable))
80*05caa062SThomas Huth            if subtable.subtype == acpi.MADT_TYPE_LOCAL_X2APIC:
81*05caa062SThomas Huth                if subtable.flags.bits.enabled:
82*05caa062SThomas Huth                    if testsuite.test("{} with x2Apic in _MAT has _UID".format(cpupath), uid is not None):
83*05caa062SThomas Huth                        testsuite.test("{}._UID = _MAT UID".format(cpupath), uid == subtable.uid)
84*05caa062SThomas Huth                        testsuite.print_detail("{}._UID ({:#x}) != _MAT UID ({:#x})".format(cpupath, uid, subtable.uid))
85*05caa062SThomas Huth                        testsuite.print_detail("_MAT entry[{}]: {}".format(index, subtable))
86*05caa062SThomas Huth                    if testsuite.test("{} with _MAT x2Apic has x2Apic in MADT".format(cpupath), subtable.uid in uid_x2apicid):
87*05caa062SThomas Huth                        testsuite.test("{} x2ApicId derived from MADT using UID = _MAT x2ApicId".format(cpupath), uid_x2apicid[subtable.uid] == subtable.x2apicid)
88*05caa062SThomas Huth                        testsuite.print_detail("{} x2ApicId derived from MADT ({:#02x}) != _MAT x2ApicId ({:#02x})".format(cpupath, uid_x2apicid[subtable.uid], subtable.x2apicid))
89*05caa062SThomas Huth                        testsuite.print_detail("_MAT entry[{}]: {}".format(index, subtable))
90*05caa062SThomas Huth
91*05caa062SThomas Huthdef test_pss():
92*05caa062SThomas Huth    uniques = acpi.parse_cpu_method("_PSS")
93*05caa062SThomas Huth    # We special-case None here to avoid a double-failure for CPUs without a _PSS
94*05caa062SThomas Huth    testsuite.test("_PSS must be identical for all CPUs", len(uniques) <= 1 or (len(uniques) == 2 and None in uniques))
95*05caa062SThomas Huth    for pss, cpupaths in uniques.iteritems():
96*05caa062SThomas Huth        if not testsuite.test("_PSS must exist", pss is not None):
97*05caa062SThomas Huth            testsuite.print_detail(acpi.factor_commonprefix(cpupaths))
98*05caa062SThomas Huth            testsuite.print_detail('No _PSS exists')
99*05caa062SThomas Huth            continue
100*05caa062SThomas Huth
101*05caa062SThomas Huth        if not testsuite.test("_PSS must not be empty", pss.pstates):
102*05caa062SThomas Huth            testsuite.print_detail(acpi.factor_commonprefix(cpupaths))
103*05caa062SThomas Huth            testsuite.print_detail('_PSS is empty')
104*05caa062SThomas Huth            continue
105*05caa062SThomas Huth
106*05caa062SThomas Huth        testsuite.print_detail(acpi.factor_commonprefix(cpupaths))
107*05caa062SThomas Huth        for index, pstate in enumerate(pss.pstates):
108*05caa062SThomas Huth            testsuite.print_detail("P[{}]: {}".format(index, pstate))
109*05caa062SThomas Huth
110*05caa062SThomas Huth        testsuite.test("_PSS must contain at most 16 Pstates", len(pss.pstates) <= 16)
111*05caa062SThomas Huth        testsuite.test("_PSS must have no duplicate Pstates", len(pss.pstates) == len(set(pss.pstates)))
112*05caa062SThomas Huth
113*05caa062SThomas Huth        frequencies = [p.core_frequency for p in pss.pstates]
114*05caa062SThomas Huth        testsuite.test("_PSS must list Pstates in descending order of frequency", frequencies == sorted(frequencies, reverse=True))
115*05caa062SThomas Huth
116*05caa062SThomas Huth        testsuite.test("_PSS must have Pstates with no duplicate frequencies", len(frequencies) == len(set(frequencies)))
117*05caa062SThomas Huth
118*05caa062SThomas Huth        dissipations = [p.power for p in pss.pstates]
119*05caa062SThomas Huth        testsuite.test("_PSS must list Pstates in descending order of power dissipation", dissipations == sorted(dissipations, reverse=True))
120*05caa062SThomas Huth
121*05caa062SThomas Huthdef test_pstates():
122*05caa062SThomas Huth    """Execute and verify frequency for each Pstate in the _PSS"""
123*05caa062SThomas Huth    IA32_PERF_CTL = 0x199
124*05caa062SThomas Huth    with bits.mwait.use_hint(), bits.preserve_msr(IA32_PERF_CTL):
125*05caa062SThomas Huth        cpupath_procid = acpi.find_procid()
126*05caa062SThomas Huth        cpupath_uid = acpi.find_uid()
127*05caa062SThomas Huth        apic = acpi.parse_apic()
128*05caa062SThomas Huth        procid_apicid = apic.procid_apicid
129*05caa062SThomas Huth        uid_x2apicid = apic.uid_x2apicid
130*05caa062SThomas Huth        def cpupath_apicid(cpupath):
131*05caa062SThomas Huth            if procid_apicid is not None:
132*05caa062SThomas Huth                procid = cpupath_procid.get(cpupath, None)
133*05caa062SThomas Huth                if procid is not None:
134*05caa062SThomas Huth                    apicid = procid_apicid.get(procid, None)
135*05caa062SThomas Huth                    if apicid is not None:
136*05caa062SThomas Huth                        return apicid
137*05caa062SThomas Huth            if uid_x2apicid is not None:
138*05caa062SThomas Huth                uid = cpupath_uid.get(cpupath, None)
139*05caa062SThomas Huth                if uid is not None:
140*05caa062SThomas Huth                    apicid = uid_x2apicid.get(uid, None)
141*05caa062SThomas Huth                    if apicid is not None:
142*05caa062SThomas Huth                        return apicid
143*05caa062SThomas Huth            return bits.cpus()[0]
144*05caa062SThomas Huth
145*05caa062SThomas Huth        bclk = testutil.adjust_to_nearest(bits.bclk(), 100.0/12) * 1000000
146*05caa062SThomas Huth
147*05caa062SThomas Huth        uniques = acpi.parse_cpu_method("_PSS")
148*05caa062SThomas Huth        for pss, cpupaths in uniques.iteritems():
149*05caa062SThomas Huth            if not testsuite.test("_PSS must exist", pss is not None):
150*05caa062SThomas Huth                testsuite.print_detail(acpi.factor_commonprefix(cpupaths))
151*05caa062SThomas Huth                testsuite.print_detail('No _PSS exists')
152*05caa062SThomas Huth                continue
153*05caa062SThomas Huth
154*05caa062SThomas Huth            for n, pstate in enumerate(pss.pstates):
155*05caa062SThomas Huth                for cpupath in cpupaths:
156*05caa062SThomas Huth                    apicid = cpupath_apicid(cpupath)
157*05caa062SThomas Huth                    if apicid is None:
158*05caa062SThomas Huth                        print 'Failed to find apicid for cpupath {}'.format(cpupath)
159*05caa062SThomas Huth                        continue
160*05caa062SThomas Huth                    bits.wrmsr(apicid, IA32_PERF_CTL, pstate.control)
161*05caa062SThomas Huth
162*05caa062SThomas Huth                # Detecting Turbo frequency requires at least 2 pstates
163*05caa062SThomas Huth                # since turbo frequency = max non-turbo frequency + 1
164*05caa062SThomas Huth                turbo = False
165*05caa062SThomas Huth                if len(pss.pstates) >= 2:
166*05caa062SThomas Huth                    turbo = (n == 0 and pstate.core_frequency == (pss.pstates[1].core_frequency + 1))
167*05caa062SThomas Huth                    if turbo:
168*05caa062SThomas Huth                        # Needs to busywait, not sleep
169*05caa062SThomas Huth                        start = time.time()
170*05caa062SThomas Huth                        while (time.time() - start < 2):
171*05caa062SThomas Huth                            pass
172*05caa062SThomas Huth
173*05caa062SThomas Huth                for duration in (0.1, 1.0):
174*05caa062SThomas Huth                    frequency_data = bits.cpu_frequency(duration)
175*05caa062SThomas Huth                    # Abort the test if no cpu frequency is not available
176*05caa062SThomas Huth                    if frequency_data is None:
177*05caa062SThomas Huth                        continue
178*05caa062SThomas Huth                    aperf = frequency_data[1]
179*05caa062SThomas Huth                    aperf = testutil.adjust_to_nearest(aperf, bclk/2)
180*05caa062SThomas Huth                    aperf = int(aperf / 1000000)
181*05caa062SThomas Huth                    if turbo:
182*05caa062SThomas Huth                        if aperf >= pstate.core_frequency:
183*05caa062SThomas Huth                            break
184*05caa062SThomas Huth                    else:
185*05caa062SThomas Huth                        if aperf == pstate.core_frequency:
186*05caa062SThomas Huth                            break
187*05caa062SThomas Huth
188*05caa062SThomas Huth                if turbo:
189*05caa062SThomas Huth                    testsuite.test("P{}: Turbo measured frequency {} >= expected {} MHz".format(n, aperf, pstate.core_frequency), aperf >= pstate.core_frequency)
190*05caa062SThomas Huth                else:
191*05caa062SThomas Huth                    testsuite.test("P{}: measured frequency {} MHz == expected {} MHz".format(n, aperf, pstate.core_frequency), aperf == pstate.core_frequency)
192*05caa062SThomas Huth
193*05caa062SThomas Huthdef test_psd_thread_scope():
194*05caa062SThomas Huth    uniques = acpi.parse_cpu_method("_PSD")
195*05caa062SThomas Huth    if not testsuite.test("_PSD (P-State Dependency) must exist for each processor", None not in uniques):
196*05caa062SThomas Huth        testsuite.print_detail(acpi.factor_commonprefix(uniques[None]))
197*05caa062SThomas Huth        testsuite.print_detail('No _PSD exists')
198*05caa062SThomas Huth        return
199*05caa062SThomas Huth    unique_num_dependencies = {}
200*05caa062SThomas Huth    unique_num_entries = {}
201*05caa062SThomas Huth    unique_revision = {}
202*05caa062SThomas Huth    unique_domain = {}
203*05caa062SThomas Huth    unique_coordination_type = {}
204*05caa062SThomas Huth    unique_num_processors = {}
205*05caa062SThomas Huth    for value, cpupaths in uniques.iteritems():
206*05caa062SThomas Huth        unique_num_dependencies.setdefault(len(value.dependencies), []).extend(cpupaths)
207*05caa062SThomas Huth        unique_num_entries.setdefault(value.dependencies[0].num_entries, []).extend(cpupaths)
208*05caa062SThomas Huth        unique_revision.setdefault(value.dependencies[0].revision, []).extend(cpupaths)
209*05caa062SThomas Huth        unique_domain.setdefault(value.dependencies[0].domain, []).extend(cpupaths)
210*05caa062SThomas Huth        unique_coordination_type.setdefault(value.dependencies[0].coordination_type, []).extend(cpupaths)
211*05caa062SThomas Huth        unique_num_processors.setdefault(value.dependencies[0].num_processors, []).extend(cpupaths)
212*05caa062SThomas Huth    def detail(d, fmt):
213*05caa062SThomas Huth        for value, cpupaths in sorted(d.iteritems(), key=(lambda (k,v): v)):
214*05caa062SThomas Huth            testsuite.print_detail(acpi.factor_commonprefix(cpupaths))
215*05caa062SThomas Huth            testsuite.print_detail(fmt.format(value))
216*05caa062SThomas Huth
217*05caa062SThomas Huth    testsuite.test('Dependency count for each processor must be 1', unique_num_dependencies.keys() == [1])
218*05caa062SThomas Huth    detail(unique_num_dependencies, 'Dependency count for each processor = {} (Expected 1)')
219*05caa062SThomas Huth    testsuite.test('_PSD.num_entries must be 5', unique_num_entries.keys() == [5])
220*05caa062SThomas Huth    detail(unique_num_entries, 'num_entries = {} (Expected 5)')
221*05caa062SThomas Huth    testsuite.test('_PSD.revision must be 0', unique_revision.keys() == [0])
222*05caa062SThomas Huth    detail(unique_revision, 'revision = {}')
223*05caa062SThomas Huth    testsuite.test('_PSD.coordination_type must be 0xFE (HW_ALL)', unique_coordination_type.keys() == [0xfe])
224*05caa062SThomas Huth    detail(unique_coordination_type, 'coordination_type = {:#x} (Expected 0xFE HW_ALL)')
225*05caa062SThomas Huth    testsuite.test('_PSD.domain must be unique (thread-scoped) for each processor', len(unique_domain) == len(acpi.get_cpupaths()))
226*05caa062SThomas Huth    detail(unique_domain, 'domain = {:#x} (Expected a unique value for each processor)')
227*05caa062SThomas Huth    testsuite.test('_PSD.num_processors must be 1', unique_num_processors.keys() == [1])
228*05caa062SThomas Huth    detail(unique_num_processors, 'num_processors = {} (Expected 1)')
229*05caa062SThomas Huth
230*05caa062SThomas Huthdef test_table_checksum(data):
231*05caa062SThomas Huth    csum = sum(ord(c) for c in data) % 0x100
232*05caa062SThomas Huth    testsuite.test('ACPI table cumulative checksum must equal 0', csum == 0)
233*05caa062SThomas Huth    testsuite.print_detail("Cumulative checksum = {} (Expected 0)".format(csum))
234*05caa062SThomas Huth
235*05caa062SThomas Huthdef test_apic():
236*05caa062SThomas Huth    data = acpi.get_table("APIC")
237*05caa062SThomas Huth    if data is None:
238*05caa062SThomas Huth        return
239*05caa062SThomas Huth    test_table_checksum(data)
240*05caa062SThomas Huth    apic = acpi.parse_apic()
241*05caa062SThomas Huth
242*05caa062SThomas Huthdef test_dsdt():
243*05caa062SThomas Huth    data = acpi.get_table("DSDT")
244*05caa062SThomas Huth    if data is None:
245*05caa062SThomas Huth        return
246*05caa062SThomas Huth    test_table_checksum(data)
247*05caa062SThomas Huth
248*05caa062SThomas Huthdef test_facp():
249*05caa062SThomas Huth    data = acpi.get_table("FACP")
250*05caa062SThomas Huth    if data is None:
251*05caa062SThomas Huth        return
252*05caa062SThomas Huth    test_table_checksum(data)
253*05caa062SThomas Huth    facp = acpi.parse_facp()
254*05caa062SThomas Huth
255*05caa062SThomas Huthdef test_hpet():
256*05caa062SThomas Huth    data = acpi.get_table("HPET")
257*05caa062SThomas Huth    if data is None:
258*05caa062SThomas Huth        return
259*05caa062SThomas Huth    test_table_checksum(data)
260*05caa062SThomas Huth    hpet = acpi.parse_hpet()
261*05caa062SThomas Huth
262*05caa062SThomas Huthdef test_mpst():
263*05caa062SThomas Huth    data = acpi.get_table("MPST")
264*05caa062SThomas Huth    if data is None:
265*05caa062SThomas Huth        return
266*05caa062SThomas Huth    test_table_checksum(data)
267*05caa062SThomas Huth    mpst = acpi.MPST(data)
268*05caa062SThomas Huth
269*05caa062SThomas Huthdef test_rsdp():
270*05caa062SThomas Huth    data = acpi.get_table("RSD PTR ")
271*05caa062SThomas Huth    if data is None:
272*05caa062SThomas Huth        return
273*05caa062SThomas Huth
274*05caa062SThomas Huth    # Checksum the first 20 bytes per ACPI 1.0
275*05caa062SThomas Huth    csum = sum(ord(c) for c in data[:20]) % 0x100
276*05caa062SThomas Huth    testsuite.test('ACPI 1.0 table first 20 bytes cumulative checksum must equal 0', csum == 0)
277*05caa062SThomas Huth    testsuite.print_detail("Cumulative checksum = {} (Expected 0)".format(csum))
278*05caa062SThomas Huth
279*05caa062SThomas Huth    test_table_checksum(data)
280*05caa062SThomas Huth    rsdp = acpi.parse_rsdp()
281*05caa062SThomas Huth
282*05caa062SThomas Huthdef test_xsdt():
283*05caa062SThomas Huth    data = acpi.get_table("XSDT")
284*05caa062SThomas Huth    if data is None:
285*05caa062SThomas Huth        return
286*05caa062SThomas Huth    test_table_checksum(data)
287*05caa062SThomas Huth    xsdt = acpi.parse_xsdt()
288