1 # Copyright (c) 2014 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 5 import logging 6 import re 7 8 from autotest_lib.client.common_lib import error 9 from autotest_lib.client.common_lib import utils 10 from autotest_lib.server.cros.faft.firmware_test import FirmwareTest 11 12 13 class firmware_Mosys(FirmwareTest): 14 """ 15 Mosys commands test for Firmware values. 16 17 Execute 18 a. mosys -k smbios info bios 19 b. mosys -k ec info 20 c. mosys platform name 21 d. mosys eeprom map 22 e. mosys platform vendor 23 f. mosys -k pd info 24 25 """ 26 version = 1 27 28 29 def initialize(self, host, cmdline_args, dev_mode=False): 30 # Parse arguments from command line 31 dict_args = utils.args_to_dict(cmdline_args) 32 super(firmware_Mosys, self).initialize(host, cmdline_args) 33 self.switcher.setup_mode('dev' if dev_mode else 'normal') 34 # a list contain failed execution. 35 self.failed_command = [] 36 # Get a list of available mosys commands. 37 lines = self.run_cmd('mosys help') 38 self.command_list = [] 39 cmdlist_start = False 40 for line in lines: 41 if cmdlist_start: 42 cmdlst = re.split('\s+', line) 43 if len(cmdlst) > 2: 44 self.command_list.append(cmdlst[1]) 45 elif 'Commands:' in line: 46 cmdlist_start = True 47 logging.info('Availabe commands: %s', ' '.join(self.command_list)) 48 49 def run_cmd(self, command): 50 """ 51 Log and execute command and return the output. 52 53 @param command: Command to executeon device. 54 @returns the output of command. 55 56 """ 57 logging.info('Execute %s', command) 58 output = self.faft_client.system.run_shell_command_get_output(command) 59 logging.info('Output %s', output) 60 return output 61 62 def check_ec_version(self, command, exp_ec_version): 63 """ 64 Compare output of 'ectool version' for the current firmware 65 copy to exp_ec_version. 66 67 @param command: command string 68 @param exp_ec_version: The exepected EC version string. 69 70 """ 71 if self.faft_client.system.has_host(): 72 lines = self.run_cmd('fwtool ec version') 73 else: 74 lines = self.run_cmd('ectool version') 75 fwcopy_pattern = re.compile('Firmware copy: (.*)$') 76 ver_pattern = re.compile('(R[OW]) version: (.*)$') 77 version = {} 78 for line in lines: 79 ver_matched = ver_pattern.match(line) 80 if ver_matched: 81 version[ver_matched.group(1)] = ver_matched.group(2) 82 fwcopy_matched = fwcopy_pattern.match(line) 83 if fwcopy_matched: 84 fwcopy = fwcopy_matched.group(1) 85 if fwcopy in version: 86 actual_version = version[fwcopy] 87 logging.info('Expected ec version %s actual_version %s', 88 exp_ec_version, actual_version) 89 if exp_ec_version != actual_version: 90 self._tag_failure(command) 91 else: 92 self._tag_failure(command) 93 logging.error('Failed to locate version from ectool') 94 95 def check_pd_version(self, command, exp_pd_version): 96 """ 97 Compare output of 'ectool --dev 1 version' for the current PD firmware 98 copy to exp_pd_version. 99 100 @param command: command string 101 @param exp_pd_version: The exepected PD version string. 102 103 """ 104 lines = self.run_cmd('ectool --dev 1 version') 105 fwcopy_pattern = re.compile('Firmware copy: (.*)$') 106 ver_pattern = re.compile('(R[OW]) version: (.*)$') 107 version = {} 108 for line in lines: 109 ver_matched = ver_pattern.match(line) 110 if ver_matched: 111 version[ver_matched.group(1)] = ver_matched.group(2) 112 fwcopy_matched = fwcopy_pattern.match(line) 113 if fwcopy_matched: 114 fwcopy = fwcopy_matched.group(1) 115 if fwcopy in version: 116 actual_version = version[fwcopy] 117 logging.info('Expected pd version %s actual_version %s', 118 exp_pd_version, actual_version) 119 if exp_pd_version != actual_version: 120 self._tag_failure(command) 121 else: 122 self._tag_failure(command) 123 logging.error('Failed to locate version from ectool') 124 125 def check_lsb_info(self, command, fieldname, exp_value): 126 """ 127 Comapre output of fieldname in /etc/lsb-release to exp_value. 128 129 @param command: command string 130 @param fieldname: field name in lsd-release file. 131 @param exp_value: expected value for fieldname 132 133 """ 134 lsb_info = 'cat /etc/lsb-release' 135 lines = self.run_cmd(lsb_info) 136 pattern = re.compile(fieldname + '=(.*)$') 137 for line in lines: 138 matched = pattern.match(line) 139 if matched: 140 actual = matched.group(1) 141 logging.info('Expected %s %s actual %s', 142 fieldname, exp_value, actual) 143 # Some board will have prefix. Example nyan_big for big. 144 if exp_value.lower() in actual.lower(): 145 return 146 self._tag_failure(command) 147 148 def check_adb_devices(self, command, fieldname, exp_value): 149 """ 150 Compare output of fieldname in adb devices -l to exp_value. 151 152 @param command: command string 153 @param fieldname: field name from adb devices -l output. 154 @param exp_value: expected value for fieldname 155 156 """ 157 device_info = 'adb devices -l' 158 lines = self.faft_client.host.run_shell_command_get_output(device_info) 159 logging.info(lines) 160 pattern = re.compile(fieldname + ':(\S+)\s+') 161 logging.info(pattern) 162 for line in lines: 163 matched = pattern.search(line) 164 if matched: 165 actual = matched.group(1) 166 logging.info('Expected %s %s actual %s', 167 fieldname, exp_value, actual) 168 # Some board will have prefix. Example nyan_big for big. 169 if exp_value.lower() in actual.lower(): 170 return 171 self._tag_failure(command) 172 173 def _tag_failure(self, cmd): 174 self.failed_command.append(cmd) 175 logging.error('Execute %s failed', cmd) 176 177 def run_once(self, dev_mode=False): 178 # a. mosys -k smbios info bios 179 command = 'mosys -k smbios info bios' 180 if 'smbios' in self.command_list: 181 output = self.run_cmd(command)[0] 182 p = re.compile('vendor="coreboot" version="(.*)"' 183 ' release_date="[/0-9]+" size="[0-9]+ KB"') 184 v = p.match(output) 185 if not v: 186 self._tag_failure(command) 187 version = v.group(1) 188 if not self.checkers.crossystem_checker({'fwid': version}): 189 self._tag_failure(command) 190 else: 191 logging.warning('Skip "%s", command not available.', command) 192 193 # b. mosys -k ec info 194 command = 'mosys -k ec info' 195 if self.faft_config.chrome_ec: 196 output = self.run_cmd(command)[0] 197 p = re.compile('vendor="[a-z]+" name="[ -~]+" fw_version="(.*)"') 198 v = p.match(output) 199 if v: 200 version = v.group(1) 201 self.check_ec_version(command, version) 202 else: 203 self._tag_failure(command) 204 else: 205 logging.info('Skip "%s", command not available.', command) 206 207 # c. mosys platform name 208 command = 'mosys platform name' 209 output = self.run_cmd(command)[0] 210 if self.faft_client.system.has_host(): 211 self.check_adb_devices(command, 'product', output) 212 else: 213 self.check_lsb_info(command, 'CHROMEOS_RELEASE_BOARD', output) 214 215 # d. mosys eeprom map 216 command = 'mosys eeprom map|egrep "RW_SHARED|RW_SECTION_[AB]"' 217 lines = self.run_cmd(command) 218 if len(lines) != 3: 219 logging.error('Expect RW_SHARED|RW_SECTION_[AB] got "%s"', lines) 220 self._tag_failure(command) 221 emap = {'RW_SECTION_A': 0, 'RW_SECTION_B': 0, 'RW_SHARED': 0} 222 for line in lines: 223 row = line.split(' | ') 224 if row[1] in emap: 225 emap[row[1]] += 1 226 if row[2] == '0x00000000': 227 logging.error('Expect non zero but got %s instead(%s)', 228 (row[2], line)) 229 self._tag_failure(command) 230 if row[3] == '0x00000000': 231 logging.error('Expect non zero but got %s instead(%s)', 232 (row[3], line)) 233 self._tag_failure(command) 234 # Check that there are one A and one B. 235 if emap['RW_SECTION_A'] != 1 or emap['RW_SECTION_B'] != 1: 236 logging.error('Missing RW_SECTION A or B, %s', lines) 237 self._tag_failure(command) 238 239 # e. mosys platform vendor 240 # Output will be GOOGLE until launch, see crosbug/p/29755 241 command = 'mosys platform vendor' 242 output = self.run_cmd(command)[0] 243 p = re.compile('^[-\w\s]+$') 244 if not p.match(output): 245 logging.error('output is not a string Expect GOOGLE' 246 'or name of maker.') 247 self._tag_failure(command) 248 249 # f. mosys -k pd info 250 command = 'mosys -k pd info' 251 if 'pd' in self.command_list: 252 output = self.run_cmd(command)[0] 253 p = re.compile('vendor="[a-z]+" name="[ -~]+" fw_version="(.*)"') 254 v = p.match(output) 255 if v: 256 version = v.group(1) 257 self.check_pd_version(command, version) 258 else: 259 self._tag_failure(command) 260 else: 261 logging.info('Skip "%s", command not available.', command) 262 263 # Add any other mosys commands or tests before this section. 264 # empty failed_command indicate all passed. 265 if self.failed_command: 266 raise error.TestFail('%d commands failed, detail above. ' 267 'Failed commands are "%s"' % 268 (len(self.failed_command), 269 ','.join(self.failed_command))) 270