blob: b25176d384576cbc1e392de2e9e4afd18322c70f [file] [log] [blame]
Tammo Spalink9a96b8a2012-04-03 11:10:41 +08001#!/usr/bin/python
Tammo Spalink01e11722012-07-24 10:17:54 -07002# pylint: disable=E1101
Tammo Spalink9a96b8a2012-04-03 11:10:41 +08003#
4# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
5# Use of this source code is governed by a BSD-style license that can be
6# found in the LICENSE file.
7
8"""Google Factory Tool.
9
10This tool is indended to be used on factory assembly lines. It
11provides all of the Google required test functionality and must be run
12on each device as part of the assembly process.
13"""
14
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080015import logging
16import os
Jon Salz65266432012-07-30 19:02:49 +080017import pipes
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080018import re
19import sys
Hung-Te Lin6bd16472012-06-20 16:26:47 +080020import time
Ricky Liang7905f272013-03-16 01:57:10 +080021import yaml
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080022
Andy Cheng2582d292012-12-04 17:38:28 +080023from tempfile import gettempdir
Tammo Spalink86a61c62012-05-25 15:10:35 +080024
Tammo Spalinka40293e2012-07-04 14:58:56 +080025import factory_common # pylint: disable=W0611
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080026
Andy Cheng0465d132013-03-20 12:12:06 +080027from cros.factory import event_log
Jon Salz0f8a6842012-09-25 11:28:22 +080028from cros.factory.common import Error, SetupLogging, Shell
Tammo Spalink394e4492012-08-01 10:20:30 -070029from cros.factory.common import YamlWrite
Andy Chengc531e2f2012-10-15 19:09:17 +080030from cros.factory.gooftool import Gooftool
Ricky Liang53390232013-03-08 15:37:57 +080031from cros.factory.gooftool import crosfw
Tammo Spalink01e11722012-07-24 10:17:54 -070032from cros.factory.gooftool import report_upload
Andy Cheng8ece7382012-08-22 16:25:42 +080033from cros.factory.gooftool.probe import Probe, PROBEABLE_COMPONENT_CLASSES
Jon Salz0f8a6842012-09-25 11:28:22 +080034from cros.factory.gooftool.probe import ReadRoVpd, ReadRwVpd
Jon Salz193d7c62013-03-07 13:40:19 +080035from cros.factory.gooftool.vpd_data import KNOWN_VPD_FIELD_DATA
Tammo Spalinka40293e2012-07-04 14:58:56 +080036from cros.factory.hacked_argparse import CmdArg, Command, ParseCmdline
37from cros.factory.hacked_argparse import verbosity_cmd_arg
Tammo Spalink01e11722012-07-24 10:17:54 -070038from cros.factory.hwdb import hwid_tool
cychiang7fe09372012-07-04 14:31:23 +080039from cros.factory.test.factory import FACTORY_LOG_PATH
Jon Salzff88c022012-11-03 12:19:58 +080040from cros.factory.utils.process_utils import Spawn
Jon Salz8baad8b2013-03-11 20:01:45 +080041from cros.factory.privacy import FilterDict
Tammo Spalink86a61c62012-05-25 15:10:35 +080042
Tammo Spalink5c699832012-07-03 17:50:39 +080043
Tammo Spalink5c699832012-07-03 17:50:39 +080044# TODO(tammo): Replace calls to sys.exit with raise Exit, and maybe
45# treat that specially (as a smoot exit, as opposed to the more
46# verbose output for generic Error).
47
48
Ricky Lianga70a1202013-03-15 15:03:17 +080049def GetGooftool(options):
50 if options.hwid_version == 2:
51 hwdb_path = getattr(options, 'hwdb_path', None)
52 component_db = (
53 hwid_tool.HardwareDb(options.hwdb_path).comp_db if hwdb_path else None)
54 return Gooftool(hwid_version=2, component_db=component_db)
55 elif options.hwid_version == 3:
56 board = getattr(options, 'board', None)
57 hwdb_path = getattr(options, 'hwdb_path', None)
58 return Gooftool(hwid_version=3, board=board, hwdb_path=hwdb_path)
59 else:
60 raise Error, 'Invalid HWID version: %r' % options.hwid_version
61
62
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080063@Command('write_hwid',
64 CmdArg('hwid', metavar='HWID', help='HWID string'))
Andy Chengc92e6f92012-11-20 16:55:53 +080065def WriteHWID(options):
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080066 """Write specified HWID value into the system BB."""
Andy Cheng7a76cb82012-11-19 18:08:19 +080067
Tammo Spalink95c43732012-07-25 15:57:14 -070068 logging.info('writing hwid string %r', options.hwid)
Ricky Lianga70a1202013-03-15 15:03:17 +080069 GetGooftool(options).WriteHWID(options.hwid)
Andy Cheng0465d132013-03-20 12:12:06 +080070 event_log.Log('write_hwid', hwid=options.hwid)
Tammo Spalink95c43732012-07-25 15:57:14 -070071 print 'Wrote HWID: %r' % options.hwid
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080072
73
Ricky Liang53390232013-03-08 15:37:57 +080074_board_cmd_arg = CmdArg(
75 '--board', metavar='BOARD',
76 default=None, help='Board name to test.')
77
Tammo Spalink8fab5312012-05-28 18:33:30 +080078_hwdb_path_cmd_arg = CmdArg(
79 '--hwdb_path', metavar='PATH',
80 default=hwid_tool.DEFAULT_HWID_DATA_PATH,
81 help='Path to the HWID database.')
82
Tammo Spalink95c43732012-07-25 15:57:14 -070083_hwid_status_list_cmd_arg = CmdArg(
84 '--status', nargs='*', default=['supported'],
85 help='allow only HWIDs with these status values')
86
Jon Salzce124fb2012-10-02 17:42:03 +080087_probe_results_cmd_arg = CmdArg(
88 '--probe_results', metavar='RESULTS.yaml',
89 help=('Output from "gooftool probe" (used instead of '
90 'probing this system).'))
91
Ricky Liang53390232013-03-08 15:37:57 +080092_device_info_cmd_arg = CmdArg(
Ricky Liangf89f73a2013-03-19 05:00:24 +080093 '--device_info', metavar='DEVICE_INFO.yaml', default=None,
Ricky Liang53390232013-03-08 15:37:57 +080094 help='A dict of device info to use instead of fetching from shopfllor '
95 'server.')
96
Jon Salzce124fb2012-10-02 17:42:03 +080097_hwid_cmd_arg = CmdArg(
98 '--hwid', metavar='HWID',
Ricky Lianga70a1202013-03-15 15:03:17 +080099 help='HWID to verify (instead of the currently set HWID of this system).')
Jon Salzce124fb2012-10-02 17:42:03 +0800100
Tammo Spalink95c43732012-07-25 15:57:14 -0700101
102@Command('best_match_hwids',
Tammo Spalink8fab5312012-05-28 18:33:30 +0800103 _hwdb_path_cmd_arg,
104 CmdArg('-b', '--board', metavar='BOARD',
Tammo Spalink95c43732012-07-25 15:57:14 -0700105 help='optional BOARD name, needed only if data is present '
106 'for more than one'),
Tammo Spalink8fab5312012-05-28 18:33:30 +0800107 CmdArg('--bom', metavar='BOM', help='BOM name'),
108 CmdArg('--variant', metavar='VARIANT', help='VARIANT code'),
Tammo Spalink5c699832012-07-03 17:50:39 +0800109 CmdArg('--optimistic', action='store_true',
110 help='do not probe; assume singletons match'),
Tammo Spalink95c43732012-07-25 15:57:14 -0700111 CmdArg('--comps', nargs='*', default=[],
112 help='list of canonical component names'),
113 CmdArg('--missing', nargs='*', default=[],
114 help='list component classes to be assumed missing'),
Tammo Spalink5c699832012-07-03 17:50:39 +0800115 CmdArg('--status', nargs='*', default=['supported'],
Tammo Spalink95c43732012-07-25 15:57:14 -0700116 help='consider only HWIDs within this list of status values'))
117def BestMatchHwids(options):
Tammo Spalink8fab5312012-05-28 18:33:30 +0800118 """Determine a list of possible HWIDs using provided args and probeing.
119
120 VOLATILE can always be determined by probing. To get a unique
121 result, VARIANT must be specified for all cases where the matching
122 BOM has more than one associated variant code, otherwise all HWID
123 variants will be returned. Both VARIANT and BOM information can
Tammo Spalink95c43732012-07-25 15:57:14 -0700124 alternatively be specified using the --stdin_comps argument, which
125 allows specifying a list of canonical names (one per line) on stdin,
126 one per line. Based on what is known from BOM and stdin_comps,
127 determine a list of components to probe for, and use those probe
128 results to resolve a list of matching HWIDs. If no boms,
129 components, or variant codes are specified, then a list of all HWIDs
Andy Cheng8ece7382012-08-22 16:25:42 +0800130 that match probeable components will be returned.
Tammo Spalink8fab5312012-05-28 18:33:30 +0800131
132 Returns (on stdout): A list of HWIDs that match the available probe
133 results and argument contraints, one per line.
Tammo Spalink70b48a52012-08-08 16:54:51 -0700134
135 Example:
136
137 // Three ways to specify a keyboard (assuming it is a variant component)
138 gooftool best_match_hwids --missing keyboard
139 gooftool best_match_hwids --variant A or
140 gooftool best_match_hwids --comps us_kbd
Tammo Spalink8fab5312012-05-28 18:33:30 +0800141 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800142
Tammo Spalink5c699832012-07-03 17:50:39 +0800143 map(hwid_tool.Validate.Status, options.status)
Tammo Spalink95c43732012-07-25 15:57:14 -0700144 hw_db = hwid_tool.HardwareDb(options.hwdb_path)
Tammo Spalink5c699832012-07-03 17:50:39 +0800145 comp_db = hw_db.comp_db
Tammo Spalink3a7e9022012-06-27 14:08:40 +0800146 device = hw_db.GetDevice(options.board)
Tammo Spalink5c699832012-07-03 17:50:39 +0800147 component_spec = hwid_tool.ComponentSpec.New()
Tammo Spalink8fab5312012-05-28 18:33:30 +0800148 if options.bom:
Tammo Spalink5c699832012-07-03 17:50:39 +0800149 device.BomExists(options.bom)
Tammo Spalink01e11722012-07-24 10:17:54 -0700150 component_spec = hwid_tool.CombineComponentSpecs(
Tammo Spalink5c699832012-07-03 17:50:39 +0800151 component_spec, device.boms[options.bom].primary)
Tammo Spalink8fab5312012-05-28 18:33:30 +0800152 if options.variant:
Tammo Spalink5c699832012-07-03 17:50:39 +0800153 device.VariantExists(options.variant)
154 variant_spec = device.variants[options.variant]
Tammo Spalink01e11722012-07-24 10:17:54 -0700155 if hwid_tool.ComponentSpecsConflict(component_spec, variant_spec):
Tammo Spalink95c43732012-07-25 15:57:14 -0700156 sys.exit('ERROR: multiple specifications for these components:\n%s'
Tammo Spalink394e4492012-08-01 10:20:30 -0700157 % YamlWrite(sorted(
158 hwid_tool.ComponentSpecClasses(component_spec) &
159 hwid_tool.ComponentSpecClasses(variant_spec))))
Tammo Spalink01e11722012-07-24 10:17:54 -0700160 component_spec = hwid_tool.CombineComponentSpecs(
161 component_spec, variant_spec)
Tammo Spalink95c43732012-07-25 15:57:14 -0700162 if options.comps or options.missing:
163 map(comp_db.CompExists, options.comps)
164 map(comp_db.CompClassExists, options.missing)
165 extra_comp_spec = comp_db.CreateComponentSpec(
166 components=options.comps,
167 missing=options.missing)
168 print 'cmdline asserted components:\n%s' % extra_comp_spec.Encode()
169 if hwid_tool.ComponentSpecsConflict(component_spec, extra_comp_spec):
170 sys.exit('ERROR: multiple specifications for these components:\n%s'
Tammo Spalink394e4492012-08-01 10:20:30 -0700171 % YamlWrite(sorted(
172 hwid_tool.ComponentSpecClasses(component_spec) &
173 hwid_tool.ComponentSpecClasses(extra_comp_spec))))
Tammo Spalink95c43732012-07-25 15:57:14 -0700174 component_spec = hwid_tool.CombineComponentSpecs(
175 component_spec, extra_comp_spec)
Tammo Spalink01e11722012-07-24 10:17:54 -0700176 spec_classes = hwid_tool.ComponentSpecClasses(component_spec)
Tammo Spalink95c43732012-07-25 15:57:14 -0700177 missing_classes = set(comp_db.all_comp_classes) - spec_classes
Tammo Spalink5c699832012-07-03 17:50:39 +0800178 if missing_classes and not options.optimistic:
Andy Cheng8ece7382012-08-22 16:25:42 +0800179 non_probeable_missing = missing_classes - PROBEABLE_COMPONENT_CLASSES
180 if non_probeable_missing:
Tammo Spalink95c43732012-07-25 15:57:14 -0700181 sys.exit('FAILURE: these classes are necessary, were not specified '
Tammo Spalink70b48a52012-08-08 16:54:51 -0700182 'as inputs, and cannot be probed for:\n%s'
183 'This problem can often be addressed by specifying all of '
184 'the missing components on the command line (see the command '
Andy Cheng8ece7382012-08-22 16:25:42 +0800185 'help).' % YamlWrite(list(non_probeable_missing)))
Tammo Spalink95c43732012-07-25 15:57:14 -0700186 print 'probing for missing classes:'
187 print YamlWrite(list(missing_classes))
188 probe_results = Probe(target_comp_classes=list(missing_classes),
189 probe_volatile=False, probe_initial_config=False)
190 cooked_components = comp_db.MatchComponentProbeValues(
191 probe_results.found_probe_value_map)
192 if cooked_components.unmatched:
193 sys.exit('ERROR: some probed components are unrecognized:\n%s'
194 % YamlWrite(cooked_components.unmatched))
195 probed_comp_spec = comp_db.CreateComponentSpec(
196 components=cooked_components.matched,
197 missing=probe_results.missing_component_classes)
198 component_spec = hwid_tool.CombineComponentSpecs(
199 component_spec, probed_comp_spec)
200 print YamlWrite({'component data used for matching': {
201 'missing component classes': component_spec.classes_missing,
202 'found components': component_spec.components}})
203 component_data = hwid_tool.ComponentData(
204 extant_components=hwid_tool.ComponentSpecCompClassMap(
205 component_spec).keys(),
206 classes_missing=component_spec.classes_missing)
207 match_tree = device.BuildMatchTree(component_data)
208 if not match_tree:
209 sys.exit('FAILURE: NO matching BOMs found')
210 print 'potential BOMs/VARIANTs:'
211 potential_variants = set()
212 potential_volatiles = set()
213 for bom_name, variant_tree in match_tree.items():
214 print ' BOM: %-8s VARIANTS: %s' % (
215 bom_name, ', '.join(sorted(variant_tree)))
216 for variant_code in variant_tree:
217 potential_variants.add(variant_code)
218 for volatile_code in device.volatiles:
219 status = device.GetHwidStatus(bom_name, variant_code, volatile_code)
220 if status in options.status:
221 potential_volatiles.add(volatile_code)
222 print ''
223 if len(potential_variants) == 0:
224 sys.exit('FAILURE: no matching VARIANTs found')
225 if len(potential_volatiles) == 0:
226 sys.exit('FAILURE: no VOLATILEs found for potential matching BOMs/VARIANTS '
227 '(with specified status)')
Tammo Spalink394e4492012-08-01 10:20:30 -0700228 if (options.optimistic and
229 len(match_tree) == 1 and
230 len(potential_variants) == 1 and
231 len(potential_volatiles) == 1):
232 print ('MATCHING HWID: %s' % device.FmtHwid(match_tree.keys().pop(),
233 potential_variants.pop(),
234 potential_volatiles.pop()))
Tammo Spalink5c699832012-07-03 17:50:39 +0800235 return
Tammo Spalink95c43732012-07-25 15:57:14 -0700236 print ('probing VOLATILEs to resolve potential matches: %s\n' %
237 ', '.join(sorted(potential_volatiles)))
238 vol_probe_results = Probe(
239 target_comp_classes=[],
240 probe_volatile=True,
241 probe_initial_config=False)
242 cooked_volatiles = device.MatchVolatileValues(
243 vol_probe_results.found_volatile_values)
244 match_tree = device.BuildMatchTree(
245 component_data, cooked_volatiles.matched_tags)
246 matched_hwids = device.GetMatchTreeHwids(match_tree)
247 if matched_hwids:
248 for hwid in matched_hwids:
Ricky Liang02f3bd72012-09-21 14:33:01 +0800249 if matched_hwids[hwid] in options.status:
250 print 'MATCHING HWID: %s' % hwid
Tammo Spalink95c43732012-07-25 15:57:14 -0700251 return
252 print 'exact HWID matching failed, but the following BOMs match: %s' % (
253 ', '.join(sorted(match_tree)))
254 if options.optimistic and len(match_tree) == 1:
255 bom_name = set(match_tree).pop()
Tammo Spalink5c699832012-07-03 17:50:39 +0800256 bom = device.boms[bom_name]
Tammo Spalink95c43732012-07-25 15:57:14 -0700257 variant_matches = match_tree[bom_name]
Tammo Spalink5c699832012-07-03 17:50:39 +0800258 if len(variant_matches) == 1:
259 var_code = set(variant_matches).pop()
260 elif len(bom.variants) == 1:
261 var_code = set(bom.variants).pop()
262 else:
Tammo Spalink95c43732012-07-25 15:57:14 -0700263 sys.exit('FAILURE: NO matching HWIDs found; optimistic matching failed '
264 'because there were too many variants to choose from for BOM %r'
265 % bom_name)
266 hwids = [device.FmtHwid(bom_name, var_code, vol_code)
267 for vol_code in device.volatiles
268 if device.GetHwidStatus(bom_name, var_code, vol_code)
269 in options.status]
270 for hwid in hwids:
271 print 'MATCHING HWID: %s' % hwid
Tammo Spalink5c699832012-07-03 17:50:39 +0800272 return
273 else:
Tammo Spalink95c43732012-07-25 15:57:14 -0700274 print ('optimistic matching not attempted because either it was '
275 'not requested, or because the number of BOMs was <> 1\n')
276 sys.exit('FAILURE: NO matching HWIDs found')
Tammo Spalink8fab5312012-05-28 18:33:30 +0800277
278
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800279@Command('probe',
280 CmdArg('--comps', nargs='*',
281 help='List of keys from the component_db registry.'),
282 CmdArg('--no_vol', action='store_true',
283 help='Do not probe volatile data.'),
284 CmdArg('--no_ic', action='store_true',
Jon Salz0f8a6842012-09-25 11:28:22 +0800285 help='Do not probe initial_config data.'),
286 CmdArg('--include_vpd', action='store_true',
287 help='Include VPD data in volatiles.'))
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800288def RunProbe(options):
289 """Print yaml-formatted breakdown of probed device properties."""
Ricky Lianga70a1202013-03-15 15:03:17 +0800290 print GetGooftool(options).Probe(
291 target_comp_classes=options.comps,
292 probe_volatile=not options.no_vol,
293 probe_initial_config=not options.no_ic,
294 probe_vpd=options.include_vpd).Encode()
Ricky Liang53390232013-03-08 15:37:57 +0800295
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800296
Tammo Spalink214caf42012-05-28 10:45:00 +0800297@Command('verify_components',
298 _hwdb_path_cmd_arg,
Tammo Spalink5c699832012-07-03 17:50:39 +0800299 CmdArg('target_comps', nargs='*'))
Tammo Spalink214caf42012-05-28 10:45:00 +0800300def VerifyComponents(options):
Andy Cheng8ece7382012-08-22 16:25:42 +0800301 """Verify that probeable components all match entries in the component_db.
Tammo Spalink214caf42012-05-28 10:45:00 +0800302
Tammo Spalink5c699832012-07-03 17:50:39 +0800303 Probe for each component class in the target_comps and verify
Tammo Spalink214caf42012-05-28 10:45:00 +0800304 that a corresponding match exists in the component_db -- make sure
305 that these components are present, that they have been approved, but
306 do not check against any specific BOM/HWID configurations.
307 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800308
Andy Chengc531e2f2012-10-15 19:09:17 +0800309 try:
Ricky Lianga70a1202013-03-15 15:03:17 +0800310 result = GetGooftool(options).VerifyComponents(
Andy Chengc531e2f2012-10-15 19:09:17 +0800311 options.target_comps)
312 except ValueError, e:
313 sys.exit(e)
314
Ricky Liang53390232013-03-08 15:37:57 +0800315 PrintVerifyComponentsResults(result)
316
317
318def PrintVerifyComponentsResults(result):
319 """Prints out the results of VerifyComponents method call.
320
321 Groups the results into two groups: 'matches' and 'errors', and prints out
322 their values.
323 """
Andy Chengc531e2f2012-10-15 19:09:17 +0800324 # group by matches and errors
Tammo Spalink214caf42012-05-28 10:45:00 +0800325 matches = []
Andy Chengc531e2f2012-10-15 19:09:17 +0800326 errors = []
327 for result_list in result.values():
328 for component_name, _, error in result_list:
329 if component_name:
330 matches.append(component_name)
Tammo Spalink214caf42012-05-28 10:45:00 +0800331 else:
Andy Chengc531e2f2012-10-15 19:09:17 +0800332 errors.append(error)
333
Andy Cheng228a8c92012-08-27 10:53:57 +0800334 if matches:
335 print 'found probeable components:\n %s' % '\n '.join(matches)
Tammo Spalink214caf42012-05-28 10:45:00 +0800336 if errors:
Andy Cheng228a8c92012-08-27 10:53:57 +0800337 print '\nerrors:\n %s' % '\n '.join(errors)
338 sys.exit('\ncomponent verification FAILURE')
Tammo Spalink214caf42012-05-28 10:45:00 +0800339 else:
Andy Cheng228a8c92012-08-27 10:53:57 +0800340 print "\ncomponent verification SUCCESS"
Tammo Spalink214caf42012-05-28 10:45:00 +0800341
342
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800343@Command('verify_hwid',
Tammo Spalink95c43732012-07-25 15:57:14 -0700344 _hwid_status_list_cmd_arg,
Jon Salz0f8a6842012-09-25 11:28:22 +0800345 _hwdb_path_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800346 _probe_results_cmd_arg,
347 _hwid_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800348def VerifyHwid(options):
349 """Verify system HWID properties match probed device properties.
350
351 First probe components, volatile and initial_config parameters for
352 the DUT. Then use the available device data to produce a list of
353 candidate HWIDs. Then verify the HWID from the DUT is present in
354 that list. Then verify that the DUT initial config values match
355 those specified for its HWID. Finally, verify that VPD contains all
356 the necessary fields as specified by the board data, and when
357 possible verify that values are legitimate.
358 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800359
Ricky Liangf7857c12012-09-17 13:34:41 +0800360 def VerifyVpd(ro_vpd_keys, rw_vpd_keys):
Tammo Spalink5c699832012-07-03 17:50:39 +0800361 for key in ro_vpd_keys:
362 if key not in ro_vpd:
Ricky Liangf7857c12012-09-17 13:34:41 +0800363 sys.exit('Missing required RO VPD field: %s' % key)
Tammo Spalink01e11722012-07-24 10:17:54 -0700364 known_valid_values = KNOWN_VPD_FIELD_DATA.get(key, None)
Tammo Spalink5c699832012-07-03 17:50:39 +0800365 value = ro_vpd[key]
Ricky Liangf7857c12012-09-17 13:34:41 +0800366 if (known_valid_values is not None) and (value not in known_valid_values):
367 sys.exit('Invalid RO VPD entry : key %r, value %r' % (key, value))
Ricky Liangf7857c12012-09-17 13:34:41 +0800368 for key in rw_vpd_keys:
369 if key not in rw_vpd:
370 sys.exit('Missing required RW VPD field: %s' % key)
371 known_valid_values = KNOWN_VPD_FIELD_DATA.get(key, None)
372 value = rw_vpd[key]
373 if (known_valid_values is not None) and (value not in known_valid_values):
374 sys.exit('Invalid RW VPD entry : key %r, value %r' % (key, value))
Andy Cheng0465d132013-03-20 12:12:06 +0800375 event_log.Log('vpd', ro_vpd=FilterDict(ro_vpd), rw_vpd=FilterDict(rw_vpd))
Tammo Spalink5c699832012-07-03 17:50:39 +0800376 map(hwid_tool.Validate.Status, options.status)
Jon Salz0f8a6842012-09-25 11:28:22 +0800377
Jon Salz81350812012-10-11 16:13:22 +0800378 if not options.hwid or not options.probe_results:
379 main_fw_file = crosfw.LoadMainFirmware().GetFileName()
Jon Salz0f8a6842012-09-25 11:28:22 +0800380
381 if options.hwid:
382 hwid_str = options.hwid
383 else:
384 gbb_result = Shell('gbb_utility -g --hwid %s' % main_fw_file).stdout
385 hwid_str = re.findall(r'hardware_id:(.*)', gbb_result)[0].strip()
Tammo Spalink95c43732012-07-25 15:57:14 -0700386 hwid = hwid_tool.ParseHwid(hwid_str)
Tammo Spalink5c699832012-07-03 17:50:39 +0800387 hw_db = hwid_tool.HardwareDb(options.hwdb_path)
Jon Salz0f8a6842012-09-25 11:28:22 +0800388 print 'Verifying HWID: %r\n' % hwid.hwid
Tammo Spalink95c43732012-07-25 15:57:14 -0700389 device = hw_db.GetDevice(hwid.board)
390 hwid_status = device.GetHwidStatus(hwid.bom, hwid.variant, hwid.volatile)
391 if hwid_status not in options.status:
Tammo Spalink5c699832012-07-03 17:50:39 +0800392 sys.exit('HWID status must be one of [%s], found %r' %
Hung-Te Lin4f5beb12012-08-20 14:48:06 +0800393 (', '.join(options.status), hwid_status))
Jon Salz0f8a6842012-09-25 11:28:22 +0800394 if options.probe_results:
395 # Pull in probe results (including VPD data) from the given file
396 # rather than probing the current system.
397 probe_results = hwid_tool.ProbeResults.Decode(
398 open(options.probe_results).read())
399 ro_vpd = {}
400 rw_vpd = {}
401 for k, v in probe_results.found_volatile_values.items():
402 match = re.match('^vpd\.(ro|rw)\.(\w+)$', k)
403 if match:
404 del probe_results.found_volatile_values[k]
405 (ro_vpd if match.group(1) == 'ro' else rw_vpd)[match.group(2)] = v
406 else:
407 probe_results = Probe()
408 ro_vpd = ReadRoVpd(main_fw_file)
409 rw_vpd = ReadRwVpd(main_fw_file)
Tammo Spalink95c43732012-07-25 15:57:14 -0700410 cooked_components = hw_db.comp_db.MatchComponentProbeValues(
411 probe_results.found_probe_value_map)
412 cooked_volatiles = device.MatchVolatileValues(
413 probe_results.found_volatile_values)
414 cooked_initial_configs = device.MatchInitialConfigValues(
415 probe_results.initial_configs)
416 component_data = hwid_tool.ComponentData(
417 extant_components=cooked_components.matched,
418 classes_missing=probe_results.missing_component_classes)
419 match_tree = device.BuildMatchTree(
420 component_data, cooked_volatiles.matched_tags)
421 matched_hwids = device.GetMatchTreeHwids(match_tree)
422 print 'HWID status: %s\n' % hwid_status
423 print 'probed system components:'
424 print YamlWrite(cooked_components.__dict__)
425 print 'missing component classes:'
426 print YamlWrite(probe_results.missing_component_classes)
427 print 'probed volatiles:'
428 print YamlWrite(cooked_volatiles.__dict__)
429 print 'probed initial_configs:'
430 print YamlWrite(cooked_initial_configs)
431 print 'hwid match tree:'
432 print YamlWrite(match_tree)
Andy Cheng0465d132013-03-20 12:12:06 +0800433 event_log.Log(
Tammo Spalink5c699832012-07-03 17:50:39 +0800434 'probe',
Tammo Spalink95c43732012-07-25 15:57:14 -0700435 found_components=cooked_components.__dict__,
436 missing_component_classes=probe_results.missing_component_classes,
437 volatiles=cooked_volatiles.__dict__,
438 initial_configs=cooked_initial_configs)
439 if hwid.hwid not in matched_hwids:
Tammo Spalink5c699832012-07-03 17:50:39 +0800440 err_msg = 'HWID verification FAILED.\n'
Tammo Spalink95c43732012-07-25 15:57:14 -0700441 if cooked_components.unmatched:
Tammo Spalink5c699832012-07-03 17:50:39 +0800442 sys.exit(err_msg + 'some components could not be indentified:\n%s' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700443 YamlWrite(cooked_components.unmatched))
444 if not match_tree:
Tammo Spalink5c699832012-07-03 17:50:39 +0800445 sys.exit(err_msg + 'no matching boms were found for components:\n%s' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700446 component_data.Encode())
447 if hwid.bom not in match_tree:
Tammo Spalink5c699832012-07-03 17:50:39 +0800448 sys.exit(err_msg + 'matching boms [%s] do not include target bom %r' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700449 (', '.join(sorted(match_tree)), hwid.bom))
450 err_msg += 'target bom %r matches components' % hwid.bom
451 if hwid.bom not in device.IntersectBomsAndInitialConfigs(
452 cooked_initial_configs):
Tammo Spalink5c699832012-07-03 17:50:39 +0800453 sys.exit(err_msg + ', but failed initial config verification')
Tammo Spalink95c43732012-07-25 15:57:14 -0700454 matched_variants = match_tree.get(hwid.bom, {})
455 if hwid.variant not in matched_variants:
Tammo Spalink5c699832012-07-03 17:50:39 +0800456 sys.exit(err_msg + ', but target variant_code %r did not match' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700457 hwid.variant)
458 matched_volatiles = matched_variants.get(hwid.variant, {})
459 if hwid.volatile not in matched_volatiles:
Tammo Spalink5c699832012-07-03 17:50:39 +0800460 sys.exit(err_msg + ', but target volatile_code %r did not match' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700461 hwid.volatile)
462 found_status = matched_volatiles.get(hwid.volatile, None)
Tammo Spalink5c699832012-07-03 17:50:39 +0800463 sys.exit(err_msg + ', but hwid status %r was unacceptable' % found_status)
Ricky Liangf7857c12012-09-17 13:34:41 +0800464 VerifyVpd(device.vpd_ro_fields, device.vpd_rw_fields)
Andy Cheng0465d132013-03-20 12:12:06 +0800465 event_log.Log('verified_hwid', hwid=hwid)
Tammo Spalink95c43732012-07-25 15:57:14 -0700466 print 'Verification SUCCESS!'
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800467
468
469@Command('verify_keys')
Tammo Spalink01e11722012-07-24 10:17:54 -0700470def VerifyKeys(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800471 """Verify keys in firmware and SSD match."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800472
Ricky Lianga70a1202013-03-15 15:03:17 +0800473 return GetGooftool(options).VerifyKeys()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800474
475
476@Command('set_fw_bitmap_locale')
Tammo Spalink01e11722012-07-24 10:17:54 -0700477def SetFirmwareBitmapLocale(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800478 """Use VPD locale value to set firmware bitmap default language."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800479
Ricky Lianga70a1202013-03-15 15:03:17 +0800480 (index, locale) = GetGooftool(options).SetFirmwareBitmapLocale()
Andy Cheng2582d292012-12-04 17:38:28 +0800481 logging.info('Firmware bitmap initial locale set to %d (%s).',
482 index, locale)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800483
484
485@Command('verify_system_time')
Tammo Spalink01e11722012-07-24 10:17:54 -0700486def VerifySystemTime(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800487 """Verify system time is later than release filesystem creation time."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800488
Ricky Lianga70a1202013-03-15 15:03:17 +0800489 return GetGooftool(options).VerifySystemTime()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800490
491
492@Command('verify_rootfs')
Tammo Spalink01e11722012-07-24 10:17:54 -0700493def VerifyRootFs(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800494 """Verify rootfs on SSD is valid by checking hash."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800495
Ricky Lianga70a1202013-03-15 15:03:17 +0800496 return GetGooftool(options).VerifyRootFs()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800497
498
499@Command('verify_switch_wp')
Andy Chengc92e6f92012-11-20 16:55:53 +0800500def VerifyWPSwitch(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800501 """Verify hardware write protection switch is enabled."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800502
Ricky Lianga70a1202013-03-15 15:03:17 +0800503 GetGooftool(options).VerifyWPSwitch()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800504
505
506@Command('verify_switch_dev')
Tammo Spalink01e11722012-07-24 10:17:54 -0700507def VerifyDevSwitch(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800508 """Verify developer switch is disabled."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800509
Ricky Lianga70a1202013-03-15 15:03:17 +0800510 if GetGooftool(options).CheckDevSwitchForDisabling():
Hung-Te Lind7d34722012-07-26 16:48:35 +0800511 logging.warn('VerifyDevSwitch: No physical switch.')
Andy Cheng0465d132013-03-20 12:12:06 +0800512 event_log.Log('switch_dev', type='virtual switch')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800513
514
515@Command('write_protect')
Tammo Spalink01e11722012-07-24 10:17:54 -0700516def EnableFwWp(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800517 """Enable then verify firmware write protection."""
518
Hung-Te Linb21c6682012-08-01 13:53:57 +0800519 def CalculateLegacyRange(fw_type, length, section_data,
520 section_name):
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800521 ro_size = length / 2
522 ro_a = int(section_data[0] / ro_size)
523 ro_b = int((section_data[0] + section_data[1] - 1) / ro_size)
524 if ro_a != ro_b:
525 raise Error("%s firmware section %s has illegal size" %
Hung-Te Linb21c6682012-08-01 13:53:57 +0800526 (fw_type, section_name))
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800527 ro_offset = ro_a * ro_size
528 return (ro_offset, ro_size)
529
530 def WriteProtect(fw_file_path, fw_type, legacy_section):
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800531 """Calculate protection size, then invoke flashrom.
532
533 Our supported chips only allow write protecting half their total
534 size, so we parition the flash chipset space accordingly.
535 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800536
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800537 raw_image = open(fw_file_path, 'rb').read()
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800538 wp_section = 'WP_RO'
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800539 image = crosfw.FirmwareImage(raw_image)
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800540 if image.has_section(wp_section):
541 section_data = image.get_section_area(wp_section)
542 ro_offset = section_data[0]
543 ro_size = section_data[1]
544 elif image.has_section(legacy_section):
545 section_data = image.get_section_area(legacy_section)
546 (ro_offset, ro_size) = CalculateLegacyRange(
Hung-Te Linb21c6682012-08-01 13:53:57 +0800547 fw_type, len(raw_image), section_data, legacy_section)
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800548 else:
549 raise Error('could not find %s firmware section %s or %s' %
550 (fw_type, wp_section, legacy_section))
551
552 logging.debug('write protecting %s [off=%x size=%x]', fw_type,
553 ro_offset, ro_size)
554 crosfw.Flashrom(fw_type).EnableWriteProtection(ro_offset, ro_size)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800555
556 WriteProtect(crosfw.LoadMainFirmware().GetFileName(), 'main', 'RO_SECTION')
Andy Cheng0465d132013-03-20 12:12:06 +0800557 event_log.Log('wp', fw='main')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800558 ec_fw_file = crosfw.LoadEcFirmware().GetFileName()
559 if ec_fw_file is not None:
560 WriteProtect(ec_fw_file, 'ec', 'EC_RO')
Andy Cheng0465d132013-03-20 12:12:06 +0800561 event_log.Log('wp', fw='ec')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800562 else:
563 logging.warning('EC not write protected (seems there is no EC flash).')
564
565
566@Command('clear_gbb_flags')
Andy Chengc92e6f92012-11-20 16:55:53 +0800567def ClearGBBFlags(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800568 """Zero out the GBB flags, in preparation for transition to release state.
569
570 No GBB flags are set in release/shipping state, but they are useful
571 for factory/development. See "gbb_utility --flags" for details.
572 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800573
Ricky Lianga70a1202013-03-15 15:03:17 +0800574 GetGooftool(options).ClearGBBFlags()
Andy Cheng0465d132013-03-20 12:12:06 +0800575 event_log.Log('clear_gbb_flags')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800576
577
578@Command('prepare_wipe',
579 CmdArg('--fast', action='store_true',
580 help='use non-secure but faster wipe method.'))
581def PrepareWipe(options):
582 """Prepare system for transition to release state in next reboot."""
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800583
Ricky Lianga70a1202013-03-15 15:03:17 +0800584 GetGooftool(options).PrepareWipe(options.fast)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800585
586@Command('verify',
Hung-Te Lin6d827542012-07-19 11:50:41 +0800587 CmdArg('--no_write_protect', action='store_true',
588 help='Do not check write protection switch state.'),
Tammo Spalink95c43732012-07-25 15:57:14 -0700589 _hwid_status_list_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800590 _hwdb_path_cmd_arg,
Ricky Lianga70a1202013-03-15 15:03:17 +0800591 _board_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800592 _probe_results_cmd_arg,
593 _hwid_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800594def Verify(options):
595 """Verifies if whole factory process is ready for finalization.
596
597 This routine performs all the necessary checks to make sure the
598 device is ready to be finalized, but does not modify state. These
599 checks include dev switch, firmware write protection switch, hwid,
600 system time, keys, and root file system.
601 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800602
Hung-Te Lin6d827542012-07-19 11:50:41 +0800603 if not options.no_write_protect:
Ricky Lianga70a1202013-03-15 15:03:17 +0800604 VerifyWPSwitch(options)
605 VerifyDevSwitch(options)
606 if options.hwid_version == 2:
607 VerifyHwid(options)
608 elif options.hwid_version == 3:
609 VerifyHwidV3(options)
610 else:
611 raise Error, 'Invalid HWID version: %r' % options.hwid_version
612 VerifySystemTime(options)
613 VerifyKeys(options)
614 VerifyRootFs(options)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800615
616
Tammo Spalink86a61c62012-05-25 15:10:35 +0800617@Command('log_system_details')
Tammo Spalink01e11722012-07-24 10:17:54 -0700618def LogSystemDetails(options): # pylint: disable=W0613
Tammo Spalink86a61c62012-05-25 15:10:35 +0800619 """Write miscellaneous system details to the event log."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800620
Andy Cheng0465d132013-03-20 12:12:06 +0800621 event_log.Log('system_details', **Gooftool(
Ricky Lianga70a1202013-03-15 15:03:17 +0800622 hwid_version=options.hwid_version).GetSystemDetails())
Tammo Spalink86a61c62012-05-25 15:10:35 +0800623
624
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800625_upload_method_cmd_arg = CmdArg(
626 '--upload_method', metavar='METHOD:PARAM',
627 help=('How to perform the upload. METHOD should be one of '
cychiang3b15bd52012-09-08 13:58:18 +0800628 '{ftp, shopfloor, ftps, cpfe}.'))
Jon Salz65266432012-07-30 19:02:49 +0800629_add_file_cmd_arg = CmdArg(
630 '--add_file', metavar='FILE', action='append',
631 help='Extra file to include in report (must be an absolute path)')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800632
633@Command('upload_report',
Jon Salz65266432012-07-30 19:02:49 +0800634 _upload_method_cmd_arg,
635 _add_file_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800636def UploadReport(options):
637 """Create and a report containing key device details."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800638
Hung-Te Lin6bd16472012-06-20 16:26:47 +0800639 def NormalizeAsFileName(token):
640 return re.sub(r'\W+', '', token).strip()
Tammo Spalink86a61c62012-05-25 15:10:35 +0800641 ro_vpd = ReadRoVpd(crosfw.LoadMainFirmware().GetFileName())
642 device_sn = ro_vpd.get('serial_number', None)
643 if device_sn is None:
644 logging.warning('RO_VPD missing device serial number')
Andy Cheng0465d132013-03-20 12:12:06 +0800645 device_sn = 'MISSING_SN_' + event_log.TimedUuid()
Vic Yang85199e72013-01-28 14:33:11 +0800646 target_name = '%s_%s.tar.xz' % (time.strftime('%Y%m%dT%H%M%SZ',
647 time.gmtime()),
648 NormalizeAsFileName(device_sn))
Tammo Spalink86a61c62012-05-25 15:10:35 +0800649 target_path = os.path.join(gettempdir(), target_name)
650 # Intentionally ignoring dotfiles in EVENT_LOG_DIR.
Andy Cheng0465d132013-03-20 12:12:06 +0800651 tar_cmd = 'cd %s ; tar cJf %s *' % (event_log.EVENT_LOG_DIR, target_path)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800652 tar_cmd += ' --add-file %s' % FACTORY_LOG_PATH
Jon Salz65266432012-07-30 19:02:49 +0800653 if options.add_file:
654 for f in options.add_file:
655 # Require absolute paths since the tar command may change the
656 # directory.
657 if not f.startswith('/'):
658 raise Error('Not an absolute path: %s' % f)
659 if not os.path.exists(f):
660 raise Error('File does not exist: %s' % f)
661 tar_cmd += ' --add-file %s' % pipes.quote(f)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800662 cmd_result = Shell(tar_cmd)
Jon Salzff88c022012-11-03 12:19:58 +0800663
664 if ((cmd_result.status == 1) and
665 all((x == '' or
666 'file changed as we read it' in x or
667 "Removing leading `/' from member names" in x)
668 for x in cmd_result.stderr.split('\n'))):
669 # That's OK. Make sure it's valid though.
Vic Yang85199e72013-01-28 14:33:11 +0800670 Spawn(['tar', 'tfJ', target_path], check_call=True, log=True,
Jon Salzff88c022012-11-03 12:19:58 +0800671 ignore_stdout=True)
672 elif not cmd_result.success:
Tammo Spalink86a61c62012-05-25 15:10:35 +0800673 raise Error('unable to tar event logs, cmd %r failed, stderr: %r' %
674 (tar_cmd, cmd_result.stderr))
Jon Salzff88c022012-11-03 12:19:58 +0800675
Tammo Spalink86a61c62012-05-25 15:10:35 +0800676 if options.upload_method is None or options.upload_method == 'none':
677 logging.warning('REPORT UPLOAD SKIPPED (report left at %s)', target_path)
678 return
679 method, param = options.upload_method.split(':', 1)
680 if method == 'shopfloor':
681 report_upload.ShopFloorUpload(target_path, param)
682 elif method == 'ftp':
Jay Kim360c1dd2012-06-25 10:58:11 -0700683 report_upload.FtpUpload(target_path, 'ftp:' + param)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800684 elif method == 'ftps':
685 report_upload.CurlUrlUpload(target_path, '--ftp-ssl-reqd ftp:%s' % param)
686 elif method == 'cpfe':
Shawn Nematbakhsh3404a092013-01-28 16:49:09 -0800687 report_upload.CpfeUpload(target_path, pipes.quote(param))
Tammo Spalink86a61c62012-05-25 15:10:35 +0800688 else:
689 raise Error('unknown report upload method %r', method)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800690
691
692@Command('finalize',
Hung-Te Lin6d827542012-07-19 11:50:41 +0800693 CmdArg('--no_write_protect', action='store_true',
694 help='Do not enable firmware write protection.'),
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800695 CmdArg('--fast', action='store_true',
696 help='use non-secure but faster wipe method.'),
697 _hwdb_path_cmd_arg,
Tammo Spalink95c43732012-07-25 15:57:14 -0700698 _hwid_status_list_cmd_arg,
Jon Salz65266432012-07-30 19:02:49 +0800699 _upload_method_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800700 _add_file_cmd_arg,
Ricky Lianga70a1202013-03-15 15:03:17 +0800701 _board_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800702 _probe_results_cmd_arg,
703 _hwid_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800704def Finalize(options):
705 """Verify system readiness and trigger transition into release state.
706
Hung-Te Lin6d827542012-07-19 11:50:41 +0800707 This routine first verifies system state (see verify command), modifies
708 firmware bitmaps to match locale, and then clears all of the factory-friendly
709 flags from the GBB. If everything is fine, it enables firmware write
710 protection (cannot rollback after this stage), uploads system logs & reports,
711 and sets the necessary boot flags to cause wipe of the factory image on the
712 next boot.
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800713 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800714
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800715 Verify(options)
Ricky Lianga70a1202013-03-15 15:03:17 +0800716 SetFirmwareBitmapLocale(options)
717 ClearGBBFlags(options)
Hung-Te Lin6d827542012-07-19 11:50:41 +0800718 if options.no_write_protect:
719 logging.warn('WARNING: Firmware Write Protection is SKIPPED.')
Andy Cheng0465d132013-03-20 12:12:06 +0800720 event_log.Log('wp', fw='both', status='skipped')
Hung-Te Lin6d827542012-07-19 11:50:41 +0800721 else:
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800722 EnableFwWp({})
Jon Salza0f58e02012-05-29 19:33:39 +0800723 LogSystemDetails(options)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800724 UploadReport(options)
725 PrepareWipe(options)
726
727
Ricky Liang53390232013-03-08 15:37:57 +0800728@Command('verify_components_v3',
729 _board_cmd_arg,
730 _hwdb_path_cmd_arg,
731 CmdArg('target_comps', nargs='*'))
732def VerifyComponentsV3(options):
733 """Verify that probeable components all match entries in the component_db.
734
735 This method uses the HWIDv3 component database to verify components.
736
737 Probe for each component class in the target_comps and verify
738 that a corresponding match exists in the component_db -- make sure
739 that these components are present, that they have been approved, but
740 do not check against any specific BOM/HWID configurations.
741 """
742
Ricky Lianga70a1202013-03-15 15:03:17 +0800743 result = GetGooftool(options).VerifyComponentsV3(options.target_comps)
Ricky Liang53390232013-03-08 15:37:57 +0800744 PrintVerifyComponentsResults(result)
745
746
747@Command('generate_hwid_v3',
748 _board_cmd_arg,
749 _hwdb_path_cmd_arg,
Ricky Liang7905f272013-03-16 01:57:10 +0800750 _probe_results_cmd_arg,
Ricky Liang53390232013-03-08 15:37:57 +0800751 _device_info_cmd_arg)
752def GenerateHwidV3(options):
753 """Generates the HWID of the DUT.
754
755 The HWID is generated based on the given device info and the probe results
756 retrieved by probing the DUT. If there are conflits of component information
757 between device info and probe result, priority is given to device info.
758 """
759 try:
Ricky Liang7905f272013-03-16 01:57:10 +0800760 with open(options.device_info) as f:
761 device_info = yaml.load(f.read())
Ricky Liang53390232013-03-08 15:37:57 +0800762 except Exception, e:
763 raise Error, 'Invalid device_info: %s' % e
Ricky Liang7905f272013-03-16 01:57:10 +0800764 if options.probe_results:
765 with open(options.probe_results) as f:
766 probe_results = hwid_tool.ProbeResults.Decode(f.read())
767 else:
768 probe_results = Probe()
Ricky Liang53390232013-03-08 15:37:57 +0800769 print 'device_info:'
770 print device_info
771 print 'probe result:'
772 print probe_results.Encode()
773
774 # Do not log device_info for now until we're sure that it does not contain
775 # any sensitive infomation.
776 # TODO(jcliang): Add logging for device_info when appropriate.
777
Andy Cheng0465d132013-03-20 12:12:06 +0800778 event_log.Log(
Ricky Liang53390232013-03-08 15:37:57 +0800779 'probe',
780 found_components=probe_results.found_probe_value_map,
781 missing_component_classes=probe_results.missing_component_classes,
782 volatiles=probe_results.found_volatile_values,
783 initial_configs=probe_results.initial_configs)
784
Ricky Lianga70a1202013-03-15 15:03:17 +0800785 hwid_object = GetGooftool(options).GenerateHwidV3(
Ricky Liangab9d0b82013-03-19 02:15:32 +0800786 device_info, probe_results)
Ricky Liang53390232013-03-08 15:37:57 +0800787
788 final_bom = {}
789 for component_class, component_values in (
790 hwid_object.bom.components.iteritems()):
791 final_bom[component_class] = [v.probed_string for v in component_values]
Andy Cheng0465d132013-03-20 12:12:06 +0800792 event_log.Log(
Ricky Liang53390232013-03-08 15:37:57 +0800793 'final_bom',
794 final_bom=final_bom)
Andy Cheng0465d132013-03-20 12:12:06 +0800795 event_log.Log(
Ricky Liang53390232013-03-08 15:37:57 +0800796 'generated_hwid',
797 encoded_string=hwid_object.encoded_string,
798 binary_string=hwid_object.binary_string)
799 print 'Encoded HWID string:', hwid_object.encoded_string
800 print 'Binary HWID string:', hwid_object.binary_string
801
802
803@Command('verify_hwid_v3',
804 _board_cmd_arg,
805 _hwdb_path_cmd_arg,
Ricky Liang7905f272013-03-16 01:57:10 +0800806 _probe_results_cmd_arg,
Ricky Liang53390232013-03-08 15:37:57 +0800807 _hwid_cmd_arg)
808def VerifyHwidV3(options):
809 """Verify system HWID properties match probed device properties.
810
811 First probe components, volatile and initial_config parameters for
812 the DUT. Then use the available device data to produce a list of
813 candidate HWIDs. Then verify the HWID from the DUT is present in
814 that list. Then verify that the DUT initial config values match
815 those specified for its HWID. Finally, verify that VPD contains all
816 the necessary fields as specified by the board data, and when
817 possible verify that values are legitimate.
818 """
Ricky Liang7905f272013-03-16 01:57:10 +0800819 if not options.probe_results:
820 main_fw_file = crosfw.LoadMainFirmware().GetFileName()
Ricky Liang53390232013-03-08 15:37:57 +0800821 if options.hwid:
822 hwid_str = options.hwid
823 else:
824 gbb_result = Shell('gbb_utility -g --hwid %s' % main_fw_file).stdout
825 hwid_str = re.findall(r'hardware_id:(.*)', gbb_result)[0].strip()
826 print 'Verifying HWID: %r\n' % hwid_str
Ricky Liang7905f272013-03-16 01:57:10 +0800827 if options.probe_results:
828 # Pull in probe results (including VPD data) from the given file
829 # rather than probing the current system.
830 with open(options.probe_results) as f:
831 probe_results = hwid_tool.ProbeResults.Decode(f.read())
832 probed_ro_vpd = {}
833 probed_rw_vpd = {}
834 for k, v in probe_results.found_volatile_values.items():
835 # Use items(), not iteritems(), since we will be modifying the dict in the
836 # loop.
837 match = re.match('^vpd\.(ro|rw)\.(\w+)$', k)
838 if match:
839 del probe_results.found_volatile_values[k]
840 (probed_ro_vpd if match.group(1) == 'ro'
841 else probed_rw_vpd)[match.group(2)] = v
842 else:
843 probe_results = Probe()
844 probed_ro_vpd = ReadRoVpd(main_fw_file)
845 probed_rw_vpd = ReadRwVpd(main_fw_file)
Ricky Liang53390232013-03-08 15:37:57 +0800846 print 'probe result:'
847 print probe_results.Encode()
Andy Cheng0465d132013-03-20 12:12:06 +0800848 event_log.Log(
Ricky Liang53390232013-03-08 15:37:57 +0800849 'probe',
850 found_components=probe_results.found_probe_value_map,
851 missing_component_classes=probe_results.missing_component_classes,
852 volatiles=probe_results.found_volatile_values,
853 initial_configs=probe_results.initial_configs)
Andy Cheng0465d132013-03-20 12:12:06 +0800854 event_log.Log('vpd', probed_ro_vpd=FilterDict(probed_ro_vpd),
Ricky Liang53390232013-03-08 15:37:57 +0800855 probed_rw_vpd=FilterDict(probed_rw_vpd))
856
Ricky Lianga70a1202013-03-15 15:03:17 +0800857 GetGooftool(options).VerifyHwidV3(
Ricky Liangab9d0b82013-03-19 02:15:32 +0800858 hwid_str, probe_results, probed_ro_vpd, probed_rw_vpd)
Ricky Liang53390232013-03-08 15:37:57 +0800859
Andy Cheng0465d132013-03-20 12:12:06 +0800860 event_log.Log('verified_hwid', hwid=hwid_str)
Ricky Liang53390232013-03-08 15:37:57 +0800861 print 'Verification SUCCESS!'
862
863
Ricky Liang7905f272013-03-16 01:57:10 +0800864@Command('decode_hwid_v3',
865 _board_cmd_arg,
866 _hwdb_path_cmd_arg,
867 _hwid_cmd_arg)
868def DecodeHwidV3(options):
869 """Decodes the given v3 HWID and prints out decoded information.
870
871 If no HWID is given, the HWID stored on the device will be loaded and used
872 instead.
873 """
874 decoded_hwid_context = Gooftool(hwid_version=3, board=options.board,
875 hwdb_path=options.hwdb_path).DecodeHwidV3(
876 options.hwid)
877
878 print 'board: %s' % decoded_hwid_context.database.board
879 print 'binary_string: %s' % decoded_hwid_context.binary_string
880 print 'components:'
881 components = decoded_hwid_context.bom.components
882 for comp_cls in sorted(components):
883 print '%s:' % comp_cls
884 for (comp_name, probed_value, _) in sorted(components[comp_cls]):
885 if not probed_value:
886 # Some components (e.g. dram) does have probed value but is not
887 # probeable in the sense that the probed value does not contain enough
888 # information.
889 db_components = decoded_hwid_context.database.components
890 probed_value = db_components[comp_cls][comp_name]['value']
891 print ' - %s: %s' % (comp_name,
892 probed_value if probed_value else 'UNPROBEABLE')
893
894
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800895def Main():
896 """Run sub-command specified by the command line args."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800897
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800898 options = ParseCmdline(
899 'Perform Google required factory tests.',
900 CmdArg('-l', '--log', metavar='PATH',
901 help='Write logs to this file.'),
Jon Salza4bea382012-10-29 13:00:34 +0800902 CmdArg('--suppress-event-logs', action='store_true',
903 help='Suppress event logging.'),
Ricky Lianga70a1202013-03-15 15:03:17 +0800904 CmdArg('-i', '--hwid-version', default=2, choices=[2, 3], type=int,
905 help='Version of HWID to operate on.'),
Tammo Spalink8fab5312012-05-28 18:33:30 +0800906 verbosity_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800907 SetupLogging(options.verbosity, options.log)
Andy Cheng0465d132013-03-20 12:12:06 +0800908 event_log.SetGlobalLoggerDefaultPrefix('gooftool')
909 event_log.GetGlobalLogger().suppress = options.suppress_event_logs
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800910 logging.debug('gooftool options: %s', repr(options))
911 try:
912 logging.debug('GOOFTOOL command %r', options.command_name)
913 options.command(options)
914 logging.info('GOOFTOOL command %r SUCCESS', options.command_name)
915 except Error, e:
916 logging.exception(e)
917 sys.exit('GOOFTOOL command %r ERROR: %s' % (options.command_name, e))
918 except Exception, e:
919 logging.exception(e)
920 sys.exit('UNCAUGHT RUNTIME EXCEPTION %s' % e)
921
922
923if __name__ == '__main__':
924 Main()