1# Copyright (c) 2021 The Chromium OS Authors. All rights reserved. 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4 5import array 6import fcntl 7import os 8import struct 9import uuid 10 11from autotest_lib.client.bin import test, utils 12from autotest_lib.client.common_lib import error 13 14 15class firmware_CheckEOPState(test.test): 16 """Validates that the ME has been told by firmware that POST is done""" 17 # Needed by autotest 18 version = 1 19 20 def read_post_boot_state(self): 21 """Fail if the ME should be capable of reporting EOP but doesn't.""" 22 HECI_MKHI = uuid.UUID('{8e6a6715-9abc-4043-88ef-9e39c6f63e0f}') 23 IOCTL_MEI_CONNECT_CLIENT = 0xc0104801 # _IOWR('H', 1, 16); 24 25 try: 26 mei_dev = os.open('/dev/mei0', os.O_RDWR) 27 except OSError: 28 raise error.TestFail('ME device not found, probably old kernel.') 29 30 # Connect to MKHI 31 buf = array.array('B', 16 * [0]) 32 struct.pack_into('<16s', buf, 0, HECI_MKHI.bytes_le) 33 fcntl.ioctl(mei_dev, IOCTL_MEI_CONNECT_CLIENT, buf) 34 max_msg_length, protocol_version = struct.unpack_from('<IB', buf) 35 36 # Protocol 2 appears to be the minimum version that allows querying EOP 37 if protocol_version < 2: 38 os.close(mei_dev) 39 raise error.TestNAError( 40 'ME protocol too old. Not checking for EOP.') 41 42 # query EOP State 43 group_id = 0xff 44 command = 0x1d 45 os.write(mei_dev, struct.pack('<BBBB', group_id, command, 0, 0)) 46 inb = os.read(mei_dev, max_msg_length) 47 os.close(mei_dev) 48 49 if len(inb) != 8: 50 raise error.TestFail('Unknown response by ME.') 51 52 group_id_resp, command_plus_80, rsvd, result, eop_state = struct.unpack( 53 '<BBBBI', inb) 54 55 if (group_id_resp != group_id) or (command_plus_80 != command | 0x80): 56 raise error.TestFail('ME didn\'t respond to Query EOP State.') 57 if result == 0x8d: 58 raise error.TestFail('ME didn\'t understand Query EOP State.') 59 if result == 0x8e: 60 raise error.TestFail('ME reported failure on Query EOP State.') 61 if result != 0: 62 raise error.TestFail( 63 'ME gave unknown response to Query EOP State.') 64 65 # if True, EOP has been issued by firmware and we're in Post-Boot State 66 eop_state = (eop_state & 0xff) == 0 67 68 return eop_state 69 70 def run_once(self): 71 """Fail unless ME returns Post-Boot State""" 72 cpu_family = utils.get_cpu_soc_family() 73 if cpu_family not in ('x86_64', 'i386'): 74 raise error.TestNAError( 75 'This test is not applicable, ' 76 'because a non-Intel device has been detected. ' 77 'Such devices do not have an ME (Management Engine)') 78 79 if utils.is_intel_uarch_older_than('Tiger Lake'): 80 raise error.TestNAError('Skipping test on pre-TGL') 81 if utils.is_intel_uarch_older_than('Gracemont'): 82 raise error.TestNAError('Skipping test on production Atom designs') 83 84 self.read_post_boot_state() 85