blob: 21a85c2c8d336f36a8a26b849e8143450450b7e7 [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
Ricky Liang5b4568d2013-04-23 17:15:23 +080015import collections
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080016import logging
17import os
Jon Salz65266432012-07-30 19:02:49 +080018import pipes
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080019import re
20import sys
Hung-Te Lin6bd16472012-06-20 16:26:47 +080021import time
Ricky Liang7905f272013-03-16 01:57:10 +080022import yaml
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080023
Andy Cheng2582d292012-12-04 17:38:28 +080024from tempfile import gettempdir
Tammo Spalink86a61c62012-05-25 15:10:35 +080025
Tammo Spalinka40293e2012-07-04 14:58:56 +080026import factory_common # pylint: disable=W0611
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080027
Andy Cheng0465d132013-03-20 12:12:06 +080028from cros.factory import event_log
Jon Salz0f8a6842012-09-25 11:28:22 +080029from cros.factory.common import Error, SetupLogging, Shell
Tammo Spalink394e4492012-08-01 10:20:30 -070030from cros.factory.common import YamlWrite
Andy Chengc531e2f2012-10-15 19:09:17 +080031from cros.factory.gooftool import Gooftool
Ricky Liang53390232013-03-08 15:37:57 +080032from cros.factory.gooftool import crosfw
Tammo Spalink01e11722012-07-24 10:17:54 -070033from cros.factory.gooftool import report_upload
Andy Cheng8ece7382012-08-22 16:25:42 +080034from cros.factory.gooftool.probe import Probe, PROBEABLE_COMPONENT_CLASSES
Jon Salz0f8a6842012-09-25 11:28:22 +080035from cros.factory.gooftool.probe import ReadRoVpd, ReadRwVpd
Jon Salz193d7c62013-03-07 13:40:19 +080036from cros.factory.gooftool.vpd_data import KNOWN_VPD_FIELD_DATA
Tammo Spalinka40293e2012-07-04 14:58:56 +080037from cros.factory.hacked_argparse import CmdArg, Command, ParseCmdline
38from cros.factory.hacked_argparse import verbosity_cmd_arg
Tammo Spalink01e11722012-07-24 10:17:54 -070039from cros.factory.hwdb import hwid_tool
cychiang7fe09372012-07-04 14:31:23 +080040from cros.factory.test.factory import FACTORY_LOG_PATH
Jon Salzff88c022012-11-03 12:19:58 +080041from cros.factory.utils.process_utils import Spawn
Jon Salz8baad8b2013-03-11 20:01:45 +080042from cros.factory.privacy import FilterDict
Tammo Spalink86a61c62012-05-25 15:10:35 +080043
Tammo Spalink5c699832012-07-03 17:50:39 +080044
Tammo Spalink5c699832012-07-03 17:50:39 +080045# TODO(tammo): Replace calls to sys.exit with raise Exit, and maybe
46# treat that specially (as a smoot exit, as opposed to the more
47# verbose output for generic Error).
48
49
Ricky Lianga70a1202013-03-15 15:03:17 +080050def GetGooftool(options):
51 if options.hwid_version == 2:
52 hwdb_path = getattr(options, 'hwdb_path', None)
53 component_db = (
54 hwid_tool.HardwareDb(options.hwdb_path).comp_db if hwdb_path else None)
55 return Gooftool(hwid_version=2, component_db=component_db)
56 elif options.hwid_version == 3:
57 board = getattr(options, 'board', None)
58 hwdb_path = getattr(options, 'hwdb_path', None)
59 return Gooftool(hwid_version=3, board=board, hwdb_path=hwdb_path)
60 else:
61 raise Error, 'Invalid HWID version: %r' % options.hwid_version
62
63
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080064@Command('write_hwid',
65 CmdArg('hwid', metavar='HWID', help='HWID string'))
Andy Chengc92e6f92012-11-20 16:55:53 +080066def WriteHWID(options):
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080067 """Write specified HWID value into the system BB."""
Andy Cheng7a76cb82012-11-19 18:08:19 +080068
Tammo Spalink95c43732012-07-25 15:57:14 -070069 logging.info('writing hwid string %r', options.hwid)
Ricky Lianga70a1202013-03-15 15:03:17 +080070 GetGooftool(options).WriteHWID(options.hwid)
Andy Cheng0465d132013-03-20 12:12:06 +080071 event_log.Log('write_hwid', hwid=options.hwid)
Tammo Spalink95c43732012-07-25 15:57:14 -070072 print 'Wrote HWID: %r' % options.hwid
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080073
74
Ricky Liang53390232013-03-08 15:37:57 +080075_board_cmd_arg = CmdArg(
76 '--board', metavar='BOARD',
77 default=None, help='Board name to test.')
78
Tammo Spalink8fab5312012-05-28 18:33:30 +080079_hwdb_path_cmd_arg = CmdArg(
80 '--hwdb_path', metavar='PATH',
81 default=hwid_tool.DEFAULT_HWID_DATA_PATH,
82 help='Path to the HWID database.')
83
Tammo Spalink95c43732012-07-25 15:57:14 -070084_hwid_status_list_cmd_arg = CmdArg(
85 '--status', nargs='*', default=['supported'],
86 help='allow only HWIDs with these status values')
87
Jon Salzce124fb2012-10-02 17:42:03 +080088_probe_results_cmd_arg = CmdArg(
89 '--probe_results', metavar='RESULTS.yaml',
90 help=('Output from "gooftool probe" (used instead of '
91 'probing this system).'))
92
Ricky Liang53390232013-03-08 15:37:57 +080093_device_info_cmd_arg = CmdArg(
Ricky Liangf89f73a2013-03-19 05:00:24 +080094 '--device_info', metavar='DEVICE_INFO.yaml', default=None,
Ricky Liang53390232013-03-08 15:37:57 +080095 help='A dict of device info to use instead of fetching from shopfllor '
96 'server.')
97
Jon Salzce124fb2012-10-02 17:42:03 +080098_hwid_cmd_arg = CmdArg(
99 '--hwid', metavar='HWID',
Ricky Lianga70a1202013-03-15 15:03:17 +0800100 help='HWID to verify (instead of the currently set HWID of this system).')
Jon Salzce124fb2012-10-02 17:42:03 +0800101
Tammo Spalink95c43732012-07-25 15:57:14 -0700102
103@Command('best_match_hwids',
Tammo Spalink8fab5312012-05-28 18:33:30 +0800104 _hwdb_path_cmd_arg,
105 CmdArg('-b', '--board', metavar='BOARD',
Tammo Spalink95c43732012-07-25 15:57:14 -0700106 help='optional BOARD name, needed only if data is present '
107 'for more than one'),
Tammo Spalink8fab5312012-05-28 18:33:30 +0800108 CmdArg('--bom', metavar='BOM', help='BOM name'),
109 CmdArg('--variant', metavar='VARIANT', help='VARIANT code'),
Tammo Spalink5c699832012-07-03 17:50:39 +0800110 CmdArg('--optimistic', action='store_true',
111 help='do not probe; assume singletons match'),
Tammo Spalink95c43732012-07-25 15:57:14 -0700112 CmdArg('--comps', nargs='*', default=[],
113 help='list of canonical component names'),
114 CmdArg('--missing', nargs='*', default=[],
115 help='list component classes to be assumed missing'),
Tammo Spalink5c699832012-07-03 17:50:39 +0800116 CmdArg('--status', nargs='*', default=['supported'],
Tammo Spalink95c43732012-07-25 15:57:14 -0700117 help='consider only HWIDs within this list of status values'))
118def BestMatchHwids(options):
Tammo Spalink8fab5312012-05-28 18:33:30 +0800119 """Determine a list of possible HWIDs using provided args and probeing.
120
121 VOLATILE can always be determined by probing. To get a unique
122 result, VARIANT must be specified for all cases where the matching
123 BOM has more than one associated variant code, otherwise all HWID
124 variants will be returned. Both VARIANT and BOM information can
Tammo Spalink95c43732012-07-25 15:57:14 -0700125 alternatively be specified using the --stdin_comps argument, which
126 allows specifying a list of canonical names (one per line) on stdin,
127 one per line. Based on what is known from BOM and stdin_comps,
128 determine a list of components to probe for, and use those probe
129 results to resolve a list of matching HWIDs. If no boms,
130 components, or variant codes are specified, then a list of all HWIDs
Andy Cheng8ece7382012-08-22 16:25:42 +0800131 that match probeable components will be returned.
Tammo Spalink8fab5312012-05-28 18:33:30 +0800132
133 Returns (on stdout): A list of HWIDs that match the available probe
134 results and argument contraints, one per line.
Tammo Spalink70b48a52012-08-08 16:54:51 -0700135
136 Example:
137
138 // Three ways to specify a keyboard (assuming it is a variant component)
139 gooftool best_match_hwids --missing keyboard
140 gooftool best_match_hwids --variant A or
141 gooftool best_match_hwids --comps us_kbd
Tammo Spalink8fab5312012-05-28 18:33:30 +0800142 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800143
Tammo Spalink5c699832012-07-03 17:50:39 +0800144 map(hwid_tool.Validate.Status, options.status)
Tammo Spalink95c43732012-07-25 15:57:14 -0700145 hw_db = hwid_tool.HardwareDb(options.hwdb_path)
Tammo Spalink5c699832012-07-03 17:50:39 +0800146 comp_db = hw_db.comp_db
Tammo Spalink3a7e9022012-06-27 14:08:40 +0800147 device = hw_db.GetDevice(options.board)
Tammo Spalink5c699832012-07-03 17:50:39 +0800148 component_spec = hwid_tool.ComponentSpec.New()
Tammo Spalink8fab5312012-05-28 18:33:30 +0800149 if options.bom:
Tammo Spalink5c699832012-07-03 17:50:39 +0800150 device.BomExists(options.bom)
Tammo Spalink01e11722012-07-24 10:17:54 -0700151 component_spec = hwid_tool.CombineComponentSpecs(
Tammo Spalink5c699832012-07-03 17:50:39 +0800152 component_spec, device.boms[options.bom].primary)
Tammo Spalink8fab5312012-05-28 18:33:30 +0800153 if options.variant:
Tammo Spalink5c699832012-07-03 17:50:39 +0800154 device.VariantExists(options.variant)
155 variant_spec = device.variants[options.variant]
Tammo Spalink01e11722012-07-24 10:17:54 -0700156 if hwid_tool.ComponentSpecsConflict(component_spec, variant_spec):
Tammo Spalink95c43732012-07-25 15:57:14 -0700157 sys.exit('ERROR: multiple specifications for these components:\n%s'
Tammo Spalink394e4492012-08-01 10:20:30 -0700158 % YamlWrite(sorted(
159 hwid_tool.ComponentSpecClasses(component_spec) &
160 hwid_tool.ComponentSpecClasses(variant_spec))))
Tammo Spalink01e11722012-07-24 10:17:54 -0700161 component_spec = hwid_tool.CombineComponentSpecs(
162 component_spec, variant_spec)
Tammo Spalink95c43732012-07-25 15:57:14 -0700163 if options.comps or options.missing:
164 map(comp_db.CompExists, options.comps)
165 map(comp_db.CompClassExists, options.missing)
166 extra_comp_spec = comp_db.CreateComponentSpec(
167 components=options.comps,
168 missing=options.missing)
169 print 'cmdline asserted components:\n%s' % extra_comp_spec.Encode()
170 if hwid_tool.ComponentSpecsConflict(component_spec, extra_comp_spec):
171 sys.exit('ERROR: multiple specifications for these components:\n%s'
Tammo Spalink394e4492012-08-01 10:20:30 -0700172 % YamlWrite(sorted(
173 hwid_tool.ComponentSpecClasses(component_spec) &
174 hwid_tool.ComponentSpecClasses(extra_comp_spec))))
Tammo Spalink95c43732012-07-25 15:57:14 -0700175 component_spec = hwid_tool.CombineComponentSpecs(
176 component_spec, extra_comp_spec)
Tammo Spalink01e11722012-07-24 10:17:54 -0700177 spec_classes = hwid_tool.ComponentSpecClasses(component_spec)
Tammo Spalink95c43732012-07-25 15:57:14 -0700178 missing_classes = set(comp_db.all_comp_classes) - spec_classes
Tammo Spalink5c699832012-07-03 17:50:39 +0800179 if missing_classes and not options.optimistic:
Andy Cheng8ece7382012-08-22 16:25:42 +0800180 non_probeable_missing = missing_classes - PROBEABLE_COMPONENT_CLASSES
181 if non_probeable_missing:
Tammo Spalink95c43732012-07-25 15:57:14 -0700182 sys.exit('FAILURE: these classes are necessary, were not specified '
Tammo Spalink70b48a52012-08-08 16:54:51 -0700183 'as inputs, and cannot be probed for:\n%s'
184 'This problem can often be addressed by specifying all of '
185 'the missing components on the command line (see the command '
Andy Cheng8ece7382012-08-22 16:25:42 +0800186 'help).' % YamlWrite(list(non_probeable_missing)))
Tammo Spalink95c43732012-07-25 15:57:14 -0700187 print 'probing for missing classes:'
188 print YamlWrite(list(missing_classes))
189 probe_results = Probe(target_comp_classes=list(missing_classes),
190 probe_volatile=False, probe_initial_config=False)
191 cooked_components = comp_db.MatchComponentProbeValues(
192 probe_results.found_probe_value_map)
193 if cooked_components.unmatched:
194 sys.exit('ERROR: some probed components are unrecognized:\n%s'
195 % YamlWrite(cooked_components.unmatched))
196 probed_comp_spec = comp_db.CreateComponentSpec(
197 components=cooked_components.matched,
198 missing=probe_results.missing_component_classes)
199 component_spec = hwid_tool.CombineComponentSpecs(
200 component_spec, probed_comp_spec)
201 print YamlWrite({'component data used for matching': {
202 'missing component classes': component_spec.classes_missing,
203 'found components': component_spec.components}})
204 component_data = hwid_tool.ComponentData(
205 extant_components=hwid_tool.ComponentSpecCompClassMap(
206 component_spec).keys(),
207 classes_missing=component_spec.classes_missing)
208 match_tree = device.BuildMatchTree(component_data)
209 if not match_tree:
210 sys.exit('FAILURE: NO matching BOMs found')
211 print 'potential BOMs/VARIANTs:'
212 potential_variants = set()
213 potential_volatiles = set()
214 for bom_name, variant_tree in match_tree.items():
215 print ' BOM: %-8s VARIANTS: %s' % (
216 bom_name, ', '.join(sorted(variant_tree)))
217 for variant_code in variant_tree:
218 potential_variants.add(variant_code)
219 for volatile_code in device.volatiles:
220 status = device.GetHwidStatus(bom_name, variant_code, volatile_code)
221 if status in options.status:
222 potential_volatiles.add(volatile_code)
223 print ''
224 if len(potential_variants) == 0:
225 sys.exit('FAILURE: no matching VARIANTs found')
226 if len(potential_volatiles) == 0:
227 sys.exit('FAILURE: no VOLATILEs found for potential matching BOMs/VARIANTS '
228 '(with specified status)')
Tammo Spalink394e4492012-08-01 10:20:30 -0700229 if (options.optimistic and
230 len(match_tree) == 1 and
231 len(potential_variants) == 1 and
232 len(potential_volatiles) == 1):
233 print ('MATCHING HWID: %s' % device.FmtHwid(match_tree.keys().pop(),
234 potential_variants.pop(),
235 potential_volatiles.pop()))
Tammo Spalink5c699832012-07-03 17:50:39 +0800236 return
Tammo Spalink95c43732012-07-25 15:57:14 -0700237 print ('probing VOLATILEs to resolve potential matches: %s\n' %
238 ', '.join(sorted(potential_volatiles)))
239 vol_probe_results = Probe(
240 target_comp_classes=[],
241 probe_volatile=True,
242 probe_initial_config=False)
243 cooked_volatiles = device.MatchVolatileValues(
244 vol_probe_results.found_volatile_values)
245 match_tree = device.BuildMatchTree(
246 component_data, cooked_volatiles.matched_tags)
247 matched_hwids = device.GetMatchTreeHwids(match_tree)
248 if matched_hwids:
249 for hwid in matched_hwids:
Ricky Liang02f3bd72012-09-21 14:33:01 +0800250 if matched_hwids[hwid] in options.status:
251 print 'MATCHING HWID: %s' % hwid
Tammo Spalink95c43732012-07-25 15:57:14 -0700252 return
253 print 'exact HWID matching failed, but the following BOMs match: %s' % (
254 ', '.join(sorted(match_tree)))
255 if options.optimistic and len(match_tree) == 1:
256 bom_name = set(match_tree).pop()
Tammo Spalink5c699832012-07-03 17:50:39 +0800257 bom = device.boms[bom_name]
Tammo Spalink95c43732012-07-25 15:57:14 -0700258 variant_matches = match_tree[bom_name]
Tammo Spalink5c699832012-07-03 17:50:39 +0800259 if len(variant_matches) == 1:
260 var_code = set(variant_matches).pop()
261 elif len(bom.variants) == 1:
262 var_code = set(bom.variants).pop()
263 else:
Tammo Spalink95c43732012-07-25 15:57:14 -0700264 sys.exit('FAILURE: NO matching HWIDs found; optimistic matching failed '
265 'because there were too many variants to choose from for BOM %r'
266 % bom_name)
267 hwids = [device.FmtHwid(bom_name, var_code, vol_code)
268 for vol_code in device.volatiles
269 if device.GetHwidStatus(bom_name, var_code, vol_code)
270 in options.status]
271 for hwid in hwids:
272 print 'MATCHING HWID: %s' % hwid
Tammo Spalink5c699832012-07-03 17:50:39 +0800273 return
274 else:
Tammo Spalink95c43732012-07-25 15:57:14 -0700275 print ('optimistic matching not attempted because either it was '
276 'not requested, or because the number of BOMs was <> 1\n')
277 sys.exit('FAILURE: NO matching HWIDs found')
Tammo Spalink8fab5312012-05-28 18:33:30 +0800278
279
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800280@Command('probe',
281 CmdArg('--comps', nargs='*',
282 help='List of keys from the component_db registry.'),
283 CmdArg('--no_vol', action='store_true',
284 help='Do not probe volatile data.'),
285 CmdArg('--no_ic', action='store_true',
Jon Salz0f8a6842012-09-25 11:28:22 +0800286 help='Do not probe initial_config data.'),
287 CmdArg('--include_vpd', action='store_true',
288 help='Include VPD data in volatiles.'))
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800289def RunProbe(options):
290 """Print yaml-formatted breakdown of probed device properties."""
Ricky Lianga70a1202013-03-15 15:03:17 +0800291 print GetGooftool(options).Probe(
292 target_comp_classes=options.comps,
293 probe_volatile=not options.no_vol,
294 probe_initial_config=not options.no_ic,
295 probe_vpd=options.include_vpd).Encode()
Ricky Liang53390232013-03-08 15:37:57 +0800296
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800297
Tammo Spalink214caf42012-05-28 10:45:00 +0800298@Command('verify_components',
299 _hwdb_path_cmd_arg,
Tammo Spalink5c699832012-07-03 17:50:39 +0800300 CmdArg('target_comps', nargs='*'))
Tammo Spalink214caf42012-05-28 10:45:00 +0800301def VerifyComponents(options):
Andy Cheng8ece7382012-08-22 16:25:42 +0800302 """Verify that probeable components all match entries in the component_db.
Tammo Spalink214caf42012-05-28 10:45:00 +0800303
Tammo Spalink5c699832012-07-03 17:50:39 +0800304 Probe for each component class in the target_comps and verify
Tammo Spalink214caf42012-05-28 10:45:00 +0800305 that a corresponding match exists in the component_db -- make sure
306 that these components are present, that they have been approved, but
307 do not check against any specific BOM/HWID configurations.
308 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800309
Andy Chengc531e2f2012-10-15 19:09:17 +0800310 try:
Ricky Lianga70a1202013-03-15 15:03:17 +0800311 result = GetGooftool(options).VerifyComponents(
Andy Chengc531e2f2012-10-15 19:09:17 +0800312 options.target_comps)
313 except ValueError, e:
314 sys.exit(e)
315
Ricky Liang53390232013-03-08 15:37:57 +0800316 PrintVerifyComponentsResults(result)
317
318
319def PrintVerifyComponentsResults(result):
320 """Prints out the results of VerifyComponents method call.
321
322 Groups the results into two groups: 'matches' and 'errors', and prints out
323 their values.
324 """
Andy Chengc531e2f2012-10-15 19:09:17 +0800325 # group by matches and errors
Tammo Spalink214caf42012-05-28 10:45:00 +0800326 matches = []
Andy Chengc531e2f2012-10-15 19:09:17 +0800327 errors = []
328 for result_list in result.values():
329 for component_name, _, error in result_list:
330 if component_name:
331 matches.append(component_name)
Tammo Spalink214caf42012-05-28 10:45:00 +0800332 else:
Andy Chengc531e2f2012-10-15 19:09:17 +0800333 errors.append(error)
334
Andy Cheng228a8c92012-08-27 10:53:57 +0800335 if matches:
336 print 'found probeable components:\n %s' % '\n '.join(matches)
Tammo Spalink214caf42012-05-28 10:45:00 +0800337 if errors:
Andy Cheng228a8c92012-08-27 10:53:57 +0800338 print '\nerrors:\n %s' % '\n '.join(errors)
339 sys.exit('\ncomponent verification FAILURE')
Tammo Spalink214caf42012-05-28 10:45:00 +0800340 else:
Andy Cheng228a8c92012-08-27 10:53:57 +0800341 print "\ncomponent verification SUCCESS"
Tammo Spalink214caf42012-05-28 10:45:00 +0800342
343
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800344@Command('verify_hwid',
Tammo Spalink95c43732012-07-25 15:57:14 -0700345 _hwid_status_list_cmd_arg,
Jon Salz0f8a6842012-09-25 11:28:22 +0800346 _hwdb_path_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800347 _probe_results_cmd_arg,
348 _hwid_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800349def VerifyHwid(options):
350 """Verify system HWID properties match probed device properties.
351
352 First probe components, volatile and initial_config parameters for
353 the DUT. Then use the available device data to produce a list of
354 candidate HWIDs. Then verify the HWID from the DUT is present in
355 that list. Then verify that the DUT initial config values match
356 those specified for its HWID. Finally, verify that VPD contains all
357 the necessary fields as specified by the board data, and when
358 possible verify that values are legitimate.
359 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800360
Ricky Liangf7857c12012-09-17 13:34:41 +0800361 def VerifyVpd(ro_vpd_keys, rw_vpd_keys):
Tammo Spalink5c699832012-07-03 17:50:39 +0800362 for key in ro_vpd_keys:
363 if key not in ro_vpd:
Ricky Liangf7857c12012-09-17 13:34:41 +0800364 sys.exit('Missing required RO VPD field: %s' % key)
Tammo Spalink01e11722012-07-24 10:17:54 -0700365 known_valid_values = KNOWN_VPD_FIELD_DATA.get(key, None)
Tammo Spalink5c699832012-07-03 17:50:39 +0800366 value = ro_vpd[key]
Ricky Liangf7857c12012-09-17 13:34:41 +0800367 if (known_valid_values is not None) and (value not in known_valid_values):
368 sys.exit('Invalid RO VPD entry : key %r, value %r' % (key, value))
Ricky Liangf7857c12012-09-17 13:34:41 +0800369 for key in rw_vpd_keys:
370 if key not in rw_vpd:
371 sys.exit('Missing required RW VPD field: %s' % key)
372 known_valid_values = KNOWN_VPD_FIELD_DATA.get(key, None)
373 value = rw_vpd[key]
374 if (known_valid_values is not None) and (value not in known_valid_values):
375 sys.exit('Invalid RW VPD entry : key %r, value %r' % (key, value))
Andy Cheng0465d132013-03-20 12:12:06 +0800376 event_log.Log('vpd', ro_vpd=FilterDict(ro_vpd), rw_vpd=FilterDict(rw_vpd))
Tammo Spalink5c699832012-07-03 17:50:39 +0800377 map(hwid_tool.Validate.Status, options.status)
Jon Salz0f8a6842012-09-25 11:28:22 +0800378
Jon Salz81350812012-10-11 16:13:22 +0800379 if not options.hwid or not options.probe_results:
380 main_fw_file = crosfw.LoadMainFirmware().GetFileName()
Jon Salz0f8a6842012-09-25 11:28:22 +0800381
382 if options.hwid:
383 hwid_str = options.hwid
384 else:
385 gbb_result = Shell('gbb_utility -g --hwid %s' % main_fw_file).stdout
386 hwid_str = re.findall(r'hardware_id:(.*)', gbb_result)[0].strip()
Tammo Spalink95c43732012-07-25 15:57:14 -0700387 hwid = hwid_tool.ParseHwid(hwid_str)
Tammo Spalink5c699832012-07-03 17:50:39 +0800388 hw_db = hwid_tool.HardwareDb(options.hwdb_path)
Jon Salz0f8a6842012-09-25 11:28:22 +0800389 print 'Verifying HWID: %r\n' % hwid.hwid
Tammo Spalink95c43732012-07-25 15:57:14 -0700390 device = hw_db.GetDevice(hwid.board)
391 hwid_status = device.GetHwidStatus(hwid.bom, hwid.variant, hwid.volatile)
392 if hwid_status not in options.status:
Tammo Spalink5c699832012-07-03 17:50:39 +0800393 sys.exit('HWID status must be one of [%s], found %r' %
Hung-Te Lin4f5beb12012-08-20 14:48:06 +0800394 (', '.join(options.status), hwid_status))
Jon Salz0f8a6842012-09-25 11:28:22 +0800395 if options.probe_results:
396 # Pull in probe results (including VPD data) from the given file
397 # rather than probing the current system.
398 probe_results = hwid_tool.ProbeResults.Decode(
399 open(options.probe_results).read())
400 ro_vpd = {}
401 rw_vpd = {}
402 for k, v in probe_results.found_volatile_values.items():
403 match = re.match('^vpd\.(ro|rw)\.(\w+)$', k)
404 if match:
405 del probe_results.found_volatile_values[k]
406 (ro_vpd if match.group(1) == 'ro' else rw_vpd)[match.group(2)] = v
407 else:
408 probe_results = Probe()
409 ro_vpd = ReadRoVpd(main_fw_file)
410 rw_vpd = ReadRwVpd(main_fw_file)
Tammo Spalink95c43732012-07-25 15:57:14 -0700411 cooked_components = hw_db.comp_db.MatchComponentProbeValues(
412 probe_results.found_probe_value_map)
413 cooked_volatiles = device.MatchVolatileValues(
414 probe_results.found_volatile_values)
415 cooked_initial_configs = device.MatchInitialConfigValues(
416 probe_results.initial_configs)
417 component_data = hwid_tool.ComponentData(
418 extant_components=cooked_components.matched,
419 classes_missing=probe_results.missing_component_classes)
420 match_tree = device.BuildMatchTree(
421 component_data, cooked_volatiles.matched_tags)
422 matched_hwids = device.GetMatchTreeHwids(match_tree)
423 print 'HWID status: %s\n' % hwid_status
424 print 'probed system components:'
425 print YamlWrite(cooked_components.__dict__)
426 print 'missing component classes:'
427 print YamlWrite(probe_results.missing_component_classes)
428 print 'probed volatiles:'
429 print YamlWrite(cooked_volatiles.__dict__)
430 print 'probed initial_configs:'
431 print YamlWrite(cooked_initial_configs)
432 print 'hwid match tree:'
433 print YamlWrite(match_tree)
Andy Cheng0465d132013-03-20 12:12:06 +0800434 event_log.Log(
Tammo Spalink5c699832012-07-03 17:50:39 +0800435 'probe',
Tammo Spalink95c43732012-07-25 15:57:14 -0700436 found_components=cooked_components.__dict__,
437 missing_component_classes=probe_results.missing_component_classes,
438 volatiles=cooked_volatiles.__dict__,
439 initial_configs=cooked_initial_configs)
440 if hwid.hwid not in matched_hwids:
Tammo Spalink5c699832012-07-03 17:50:39 +0800441 err_msg = 'HWID verification FAILED.\n'
Tammo Spalink95c43732012-07-25 15:57:14 -0700442 if cooked_components.unmatched:
Tammo Spalink5c699832012-07-03 17:50:39 +0800443 sys.exit(err_msg + 'some components could not be indentified:\n%s' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700444 YamlWrite(cooked_components.unmatched))
445 if not match_tree:
Tammo Spalink5c699832012-07-03 17:50:39 +0800446 sys.exit(err_msg + 'no matching boms were found for components:\n%s' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700447 component_data.Encode())
448 if hwid.bom not in match_tree:
Tammo Spalink5c699832012-07-03 17:50:39 +0800449 sys.exit(err_msg + 'matching boms [%s] do not include target bom %r' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700450 (', '.join(sorted(match_tree)), hwid.bom))
451 err_msg += 'target bom %r matches components' % hwid.bom
452 if hwid.bom not in device.IntersectBomsAndInitialConfigs(
453 cooked_initial_configs):
Tammo Spalink5c699832012-07-03 17:50:39 +0800454 sys.exit(err_msg + ', but failed initial config verification')
Tammo Spalink95c43732012-07-25 15:57:14 -0700455 matched_variants = match_tree.get(hwid.bom, {})
456 if hwid.variant not in matched_variants:
Tammo Spalink5c699832012-07-03 17:50:39 +0800457 sys.exit(err_msg + ', but target variant_code %r did not match' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700458 hwid.variant)
459 matched_volatiles = matched_variants.get(hwid.variant, {})
460 if hwid.volatile not in matched_volatiles:
Tammo Spalink5c699832012-07-03 17:50:39 +0800461 sys.exit(err_msg + ', but target volatile_code %r did not match' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700462 hwid.volatile)
463 found_status = matched_volatiles.get(hwid.volatile, None)
Tammo Spalink5c699832012-07-03 17:50:39 +0800464 sys.exit(err_msg + ', but hwid status %r was unacceptable' % found_status)
Ricky Liangf7857c12012-09-17 13:34:41 +0800465 VerifyVpd(device.vpd_ro_fields, device.vpd_rw_fields)
Andy Cheng0465d132013-03-20 12:12:06 +0800466 event_log.Log('verified_hwid', hwid=hwid)
Tammo Spalink95c43732012-07-25 15:57:14 -0700467 print 'Verification SUCCESS!'
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800468
469
470@Command('verify_keys')
Tammo Spalink01e11722012-07-24 10:17:54 -0700471def VerifyKeys(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800472 """Verify keys in firmware and SSD match."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800473
Ricky Lianga70a1202013-03-15 15:03:17 +0800474 return GetGooftool(options).VerifyKeys()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800475
476
477@Command('set_fw_bitmap_locale')
Tammo Spalink01e11722012-07-24 10:17:54 -0700478def SetFirmwareBitmapLocale(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800479 """Use VPD locale value to set firmware bitmap default language."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800480
Ricky Lianga70a1202013-03-15 15:03:17 +0800481 (index, locale) = GetGooftool(options).SetFirmwareBitmapLocale()
Andy Cheng2582d292012-12-04 17:38:28 +0800482 logging.info('Firmware bitmap initial locale set to %d (%s).',
483 index, locale)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800484
485
486@Command('verify_system_time')
Tammo Spalink01e11722012-07-24 10:17:54 -0700487def VerifySystemTime(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800488 """Verify system time is later than release filesystem creation time."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800489
Ricky Lianga70a1202013-03-15 15:03:17 +0800490 return GetGooftool(options).VerifySystemTime()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800491
492
493@Command('verify_rootfs')
Tammo Spalink01e11722012-07-24 10:17:54 -0700494def VerifyRootFs(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800495 """Verify rootfs on SSD is valid by checking hash."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800496
Ricky Lianga70a1202013-03-15 15:03:17 +0800497 return GetGooftool(options).VerifyRootFs()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800498
499
500@Command('verify_switch_wp')
Andy Chengc92e6f92012-11-20 16:55:53 +0800501def VerifyWPSwitch(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800502 """Verify hardware write protection switch is enabled."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800503
Ricky Lianga70a1202013-03-15 15:03:17 +0800504 GetGooftool(options).VerifyWPSwitch()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800505
506
507@Command('verify_switch_dev')
Tammo Spalink01e11722012-07-24 10:17:54 -0700508def VerifyDevSwitch(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800509 """Verify developer switch is disabled."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800510
Ricky Lianga70a1202013-03-15 15:03:17 +0800511 if GetGooftool(options).CheckDevSwitchForDisabling():
Hung-Te Lind7d34722012-07-26 16:48:35 +0800512 logging.warn('VerifyDevSwitch: No physical switch.')
Andy Cheng0465d132013-03-20 12:12:06 +0800513 event_log.Log('switch_dev', type='virtual switch')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800514
515
516@Command('write_protect')
Tammo Spalink01e11722012-07-24 10:17:54 -0700517def EnableFwWp(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800518 """Enable then verify firmware write protection."""
519
Hung-Te Linb21c6682012-08-01 13:53:57 +0800520 def CalculateLegacyRange(fw_type, length, section_data,
521 section_name):
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800522 ro_size = length / 2
523 ro_a = int(section_data[0] / ro_size)
524 ro_b = int((section_data[0] + section_data[1] - 1) / ro_size)
525 if ro_a != ro_b:
526 raise Error("%s firmware section %s has illegal size" %
Hung-Te Linb21c6682012-08-01 13:53:57 +0800527 (fw_type, section_name))
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800528 ro_offset = ro_a * ro_size
529 return (ro_offset, ro_size)
530
531 def WriteProtect(fw_file_path, fw_type, legacy_section):
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800532 """Calculate protection size, then invoke flashrom.
533
534 Our supported chips only allow write protecting half their total
535 size, so we parition the flash chipset space accordingly.
536 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800537
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800538 raw_image = open(fw_file_path, 'rb').read()
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800539 wp_section = 'WP_RO'
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800540 image = crosfw.FirmwareImage(raw_image)
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800541 if image.has_section(wp_section):
542 section_data = image.get_section_area(wp_section)
543 ro_offset = section_data[0]
544 ro_size = section_data[1]
545 elif image.has_section(legacy_section):
546 section_data = image.get_section_area(legacy_section)
547 (ro_offset, ro_size) = CalculateLegacyRange(
Hung-Te Linb21c6682012-08-01 13:53:57 +0800548 fw_type, len(raw_image), section_data, legacy_section)
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800549 else:
550 raise Error('could not find %s firmware section %s or %s' %
551 (fw_type, wp_section, legacy_section))
552
553 logging.debug('write protecting %s [off=%x size=%x]', fw_type,
554 ro_offset, ro_size)
555 crosfw.Flashrom(fw_type).EnableWriteProtection(ro_offset, ro_size)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800556
557 WriteProtect(crosfw.LoadMainFirmware().GetFileName(), 'main', 'RO_SECTION')
Andy Cheng0465d132013-03-20 12:12:06 +0800558 event_log.Log('wp', fw='main')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800559 ec_fw_file = crosfw.LoadEcFirmware().GetFileName()
560 if ec_fw_file is not None:
561 WriteProtect(ec_fw_file, 'ec', 'EC_RO')
Andy Cheng0465d132013-03-20 12:12:06 +0800562 event_log.Log('wp', fw='ec')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800563 else:
564 logging.warning('EC not write protected (seems there is no EC flash).')
565
566
567@Command('clear_gbb_flags')
Andy Chengc92e6f92012-11-20 16:55:53 +0800568def ClearGBBFlags(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800569 """Zero out the GBB flags, in preparation for transition to release state.
570
571 No GBB flags are set in release/shipping state, but they are useful
572 for factory/development. See "gbb_utility --flags" for details.
573 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800574
Ricky Lianga70a1202013-03-15 15:03:17 +0800575 GetGooftool(options).ClearGBBFlags()
Andy Cheng0465d132013-03-20 12:12:06 +0800576 event_log.Log('clear_gbb_flags')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800577
578
Jon Salzaa3a30e2013-05-15 15:56:28 +0800579@Command('clear_factory_vpd_entries')
580def ClearFactoryVPDEntries(options): # pylint: disable=W0613
581 """Clears factory.* items in the RW VPD."""
582 entries = GetGooftool(options).ClearFactoryVPDEntries()
583 event_log.Log('clear_factory_vpd_entries', entries=FilterDict(entries))
584
585
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800586@Command('prepare_wipe',
587 CmdArg('--fast', action='store_true',
588 help='use non-secure but faster wipe method.'))
589def PrepareWipe(options):
590 """Prepare system for transition to release state in next reboot."""
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800591
Ricky Lianga70a1202013-03-15 15:03:17 +0800592 GetGooftool(options).PrepareWipe(options.fast)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800593
594@Command('verify',
Hung-Te Lin6d827542012-07-19 11:50:41 +0800595 CmdArg('--no_write_protect', action='store_true',
596 help='Do not check write protection switch state.'),
Tammo Spalink95c43732012-07-25 15:57:14 -0700597 _hwid_status_list_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800598 _hwdb_path_cmd_arg,
Ricky Lianga70a1202013-03-15 15:03:17 +0800599 _board_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800600 _probe_results_cmd_arg,
601 _hwid_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800602def Verify(options):
603 """Verifies if whole factory process is ready for finalization.
604
605 This routine performs all the necessary checks to make sure the
606 device is ready to be finalized, but does not modify state. These
607 checks include dev switch, firmware write protection switch, hwid,
608 system time, keys, and root file system.
609 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800610
Hung-Te Lin6d827542012-07-19 11:50:41 +0800611 if not options.no_write_protect:
Ricky Lianga70a1202013-03-15 15:03:17 +0800612 VerifyWPSwitch(options)
613 VerifyDevSwitch(options)
614 if options.hwid_version == 2:
615 VerifyHwid(options)
616 elif options.hwid_version == 3:
617 VerifyHwidV3(options)
618 else:
619 raise Error, 'Invalid HWID version: %r' % options.hwid_version
620 VerifySystemTime(options)
621 VerifyKeys(options)
622 VerifyRootFs(options)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800623
624
Tammo Spalink86a61c62012-05-25 15:10:35 +0800625@Command('log_system_details')
Tammo Spalink01e11722012-07-24 10:17:54 -0700626def LogSystemDetails(options): # pylint: disable=W0613
Tammo Spalink86a61c62012-05-25 15:10:35 +0800627 """Write miscellaneous system details to the event log."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800628
Andy Cheng0465d132013-03-20 12:12:06 +0800629 event_log.Log('system_details', **Gooftool(
Ricky Lianga70a1202013-03-15 15:03:17 +0800630 hwid_version=options.hwid_version).GetSystemDetails())
Tammo Spalink86a61c62012-05-25 15:10:35 +0800631
632
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800633_upload_method_cmd_arg = CmdArg(
634 '--upload_method', metavar='METHOD:PARAM',
635 help=('How to perform the upload. METHOD should be one of '
cychiang3b15bd52012-09-08 13:58:18 +0800636 '{ftp, shopfloor, ftps, cpfe}.'))
Jon Salz65266432012-07-30 19:02:49 +0800637_add_file_cmd_arg = CmdArg(
638 '--add_file', metavar='FILE', action='append',
639 help='Extra file to include in report (must be an absolute path)')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800640
641@Command('upload_report',
Jon Salz65266432012-07-30 19:02:49 +0800642 _upload_method_cmd_arg,
643 _add_file_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800644def UploadReport(options):
645 """Create and a report containing key device details."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800646
Hung-Te Lin6bd16472012-06-20 16:26:47 +0800647 def NormalizeAsFileName(token):
648 return re.sub(r'\W+', '', token).strip()
Tammo Spalink86a61c62012-05-25 15:10:35 +0800649 ro_vpd = ReadRoVpd(crosfw.LoadMainFirmware().GetFileName())
650 device_sn = ro_vpd.get('serial_number', None)
651 if device_sn is None:
652 logging.warning('RO_VPD missing device serial number')
Andy Cheng0465d132013-03-20 12:12:06 +0800653 device_sn = 'MISSING_SN_' + event_log.TimedUuid()
Vic Yang85199e72013-01-28 14:33:11 +0800654 target_name = '%s_%s.tar.xz' % (time.strftime('%Y%m%dT%H%M%SZ',
655 time.gmtime()),
656 NormalizeAsFileName(device_sn))
Tammo Spalink86a61c62012-05-25 15:10:35 +0800657 target_path = os.path.join(gettempdir(), target_name)
658 # Intentionally ignoring dotfiles in EVENT_LOG_DIR.
Andy Cheng0465d132013-03-20 12:12:06 +0800659 tar_cmd = 'cd %s ; tar cJf %s *' % (event_log.EVENT_LOG_DIR, target_path)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800660 tar_cmd += ' --add-file %s' % FACTORY_LOG_PATH
Jon Salz65266432012-07-30 19:02:49 +0800661 if options.add_file:
662 for f in options.add_file:
663 # Require absolute paths since the tar command may change the
664 # directory.
665 if not f.startswith('/'):
666 raise Error('Not an absolute path: %s' % f)
667 if not os.path.exists(f):
668 raise Error('File does not exist: %s' % f)
669 tar_cmd += ' --add-file %s' % pipes.quote(f)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800670 cmd_result = Shell(tar_cmd)
Jon Salzff88c022012-11-03 12:19:58 +0800671
672 if ((cmd_result.status == 1) and
673 all((x == '' or
674 'file changed as we read it' in x or
675 "Removing leading `/' from member names" in x)
676 for x in cmd_result.stderr.split('\n'))):
677 # That's OK. Make sure it's valid though.
Vic Yang85199e72013-01-28 14:33:11 +0800678 Spawn(['tar', 'tfJ', target_path], check_call=True, log=True,
Jon Salzff88c022012-11-03 12:19:58 +0800679 ignore_stdout=True)
680 elif not cmd_result.success:
Tammo Spalink86a61c62012-05-25 15:10:35 +0800681 raise Error('unable to tar event logs, cmd %r failed, stderr: %r' %
682 (tar_cmd, cmd_result.stderr))
Jon Salzff88c022012-11-03 12:19:58 +0800683
Tammo Spalink86a61c62012-05-25 15:10:35 +0800684 if options.upload_method is None or options.upload_method == 'none':
685 logging.warning('REPORT UPLOAD SKIPPED (report left at %s)', target_path)
686 return
687 method, param = options.upload_method.split(':', 1)
688 if method == 'shopfloor':
689 report_upload.ShopFloorUpload(target_path, param)
690 elif method == 'ftp':
Jay Kim360c1dd2012-06-25 10:58:11 -0700691 report_upload.FtpUpload(target_path, 'ftp:' + param)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800692 elif method == 'ftps':
693 report_upload.CurlUrlUpload(target_path, '--ftp-ssl-reqd ftp:%s' % param)
694 elif method == 'cpfe':
Shawn Nematbakhsh3404a092013-01-28 16:49:09 -0800695 report_upload.CpfeUpload(target_path, pipes.quote(param))
Tammo Spalink86a61c62012-05-25 15:10:35 +0800696 else:
697 raise Error('unknown report upload method %r', method)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800698
699
700@Command('finalize',
Hung-Te Lin6d827542012-07-19 11:50:41 +0800701 CmdArg('--no_write_protect', action='store_true',
702 help='Do not enable firmware write protection.'),
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800703 CmdArg('--fast', action='store_true',
704 help='use non-secure but faster wipe method.'),
705 _hwdb_path_cmd_arg,
Tammo Spalink95c43732012-07-25 15:57:14 -0700706 _hwid_status_list_cmd_arg,
Jon Salz65266432012-07-30 19:02:49 +0800707 _upload_method_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800708 _add_file_cmd_arg,
Ricky Lianga70a1202013-03-15 15:03:17 +0800709 _board_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800710 _probe_results_cmd_arg,
711 _hwid_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800712def Finalize(options):
713 """Verify system readiness and trigger transition into release state.
714
Jon Salzaa3a30e2013-05-15 15:56:28 +0800715 This routine does the following:
716 - Verifies system state (see verify command)
717 - Modifies firmware bitmaps to match locale
718 - Clears all factory-friendly flags from the GBB
719 - Removes factory-specific entries from RW_VPD (factory.*)
720 - Enables firmware write protection (cannot rollback after this)
721 - Uploads system logs & reports
722 - Sets the necessary boot flags to cause wipe of the factory image on the
723 next boot.
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800724 """
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800725 Verify(options)
Ricky Lianga70a1202013-03-15 15:03:17 +0800726 SetFirmwareBitmapLocale(options)
727 ClearGBBFlags(options)
Jon Salzaa3a30e2013-05-15 15:56:28 +0800728 ClearFactoryVPDEntries(options)
Hung-Te Lin6d827542012-07-19 11:50:41 +0800729 if options.no_write_protect:
730 logging.warn('WARNING: Firmware Write Protection is SKIPPED.')
Andy Cheng0465d132013-03-20 12:12:06 +0800731 event_log.Log('wp', fw='both', status='skipped')
Hung-Te Lin6d827542012-07-19 11:50:41 +0800732 else:
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800733 EnableFwWp({})
Jon Salza0f58e02012-05-29 19:33:39 +0800734 LogSystemDetails(options)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800735 UploadReport(options)
736 PrepareWipe(options)
737
738
Ricky Liang53390232013-03-08 15:37:57 +0800739@Command('verify_components_v3',
740 _board_cmd_arg,
741 _hwdb_path_cmd_arg,
742 CmdArg('target_comps', nargs='*'))
743def VerifyComponentsV3(options):
744 """Verify that probeable components all match entries in the component_db.
745
746 This method uses the HWIDv3 component database to verify components.
747
748 Probe for each component class in the target_comps and verify
749 that a corresponding match exists in the component_db -- make sure
750 that these components are present, that they have been approved, but
751 do not check against any specific BOM/HWID configurations.
752 """
753
Ricky Lianga70a1202013-03-15 15:03:17 +0800754 result = GetGooftool(options).VerifyComponentsV3(options.target_comps)
Ricky Liang53390232013-03-08 15:37:57 +0800755 PrintVerifyComponentsResults(result)
756
757
758@Command('generate_hwid_v3',
759 _board_cmd_arg,
760 _hwdb_path_cmd_arg,
Ricky Liang7905f272013-03-16 01:57:10 +0800761 _probe_results_cmd_arg,
Ricky Liang53390232013-03-08 15:37:57 +0800762 _device_info_cmd_arg)
763def GenerateHwidV3(options):
764 """Generates the HWID of the DUT.
765
766 The HWID is generated based on the given device info and the probe results
767 retrieved by probing the DUT. If there are conflits of component information
768 between device info and probe result, priority is given to device info.
769 """
770 try:
Ricky Liang7905f272013-03-16 01:57:10 +0800771 with open(options.device_info) as f:
772 device_info = yaml.load(f.read())
Ricky Liang53390232013-03-08 15:37:57 +0800773 except Exception, e:
774 raise Error, 'Invalid device_info: %s' % e
Ricky Liang7905f272013-03-16 01:57:10 +0800775 if options.probe_results:
776 with open(options.probe_results) as f:
777 probe_results = hwid_tool.ProbeResults.Decode(f.read())
778 else:
779 probe_results = Probe()
Ricky Liang53390232013-03-08 15:37:57 +0800780 print 'device_info:'
781 print device_info
Ricky Liang5b4568d2013-04-23 17:15:23 +0800782 print 'probe results:'
Ricky Liang53390232013-03-08 15:37:57 +0800783 print probe_results.Encode()
784
785 # Do not log device_info for now until we're sure that it does not contain
786 # any sensitive infomation.
787 # TODO(jcliang): Add logging for device_info when appropriate.
788
Andy Cheng0465d132013-03-20 12:12:06 +0800789 event_log.Log(
Ricky Liang53390232013-03-08 15:37:57 +0800790 'probe',
791 found_components=probe_results.found_probe_value_map,
792 missing_component_classes=probe_results.missing_component_classes,
793 volatiles=probe_results.found_volatile_values,
794 initial_configs=probe_results.initial_configs)
795
Ricky Lianga70a1202013-03-15 15:03:17 +0800796 hwid_object = GetGooftool(options).GenerateHwidV3(
Ricky Liangab9d0b82013-03-19 02:15:32 +0800797 device_info, probe_results)
Ricky Liang53390232013-03-08 15:37:57 +0800798
799 final_bom = {}
800 for component_class, component_values in (
801 hwid_object.bom.components.iteritems()):
Ricky Liang5b4568d2013-04-23 17:15:23 +0800802 final_bom[component_class] = [v.probed_values for v in component_values]
Andy Cheng0465d132013-03-20 12:12:06 +0800803 event_log.Log(
Ricky Liang53390232013-03-08 15:37:57 +0800804 'final_bom',
805 final_bom=final_bom)
Andy Cheng0465d132013-03-20 12:12:06 +0800806 event_log.Log(
Ricky Liang53390232013-03-08 15:37:57 +0800807 'generated_hwid',
808 encoded_string=hwid_object.encoded_string,
809 binary_string=hwid_object.binary_string)
810 print 'Encoded HWID string:', hwid_object.encoded_string
811 print 'Binary HWID string:', hwid_object.binary_string
812
813
814@Command('verify_hwid_v3',
815 _board_cmd_arg,
816 _hwdb_path_cmd_arg,
Ricky Liang7905f272013-03-16 01:57:10 +0800817 _probe_results_cmd_arg,
Ricky Liang53390232013-03-08 15:37:57 +0800818 _hwid_cmd_arg)
819def VerifyHwidV3(options):
820 """Verify system HWID properties match probed device properties.
821
822 First probe components, volatile and initial_config parameters for
823 the DUT. Then use the available device data to produce a list of
824 candidate HWIDs. Then verify the HWID from the DUT is present in
825 that list. Then verify that the DUT initial config values match
826 those specified for its HWID. Finally, verify that VPD contains all
827 the necessary fields as specified by the board data, and when
828 possible verify that values are legitimate.
829 """
Ricky Liang7905f272013-03-16 01:57:10 +0800830 if not options.probe_results:
831 main_fw_file = crosfw.LoadMainFirmware().GetFileName()
Ricky Liang53390232013-03-08 15:37:57 +0800832 if options.hwid:
833 hwid_str = options.hwid
834 else:
835 gbb_result = Shell('gbb_utility -g --hwid %s' % main_fw_file).stdout
836 hwid_str = re.findall(r'hardware_id:(.*)', gbb_result)[0].strip()
837 print 'Verifying HWID: %r\n' % hwid_str
Ricky Liang7905f272013-03-16 01:57:10 +0800838 if options.probe_results:
839 # Pull in probe results (including VPD data) from the given file
840 # rather than probing the current system.
841 with open(options.probe_results) as f:
842 probe_results = hwid_tool.ProbeResults.Decode(f.read())
843 probed_ro_vpd = {}
844 probed_rw_vpd = {}
845 for k, v in probe_results.found_volatile_values.items():
846 # Use items(), not iteritems(), since we will be modifying the dict in the
847 # loop.
848 match = re.match('^vpd\.(ro|rw)\.(\w+)$', k)
849 if match:
850 del probe_results.found_volatile_values[k]
851 (probed_ro_vpd if match.group(1) == 'ro'
852 else probed_rw_vpd)[match.group(2)] = v
853 else:
854 probe_results = Probe()
855 probed_ro_vpd = ReadRoVpd(main_fw_file)
856 probed_rw_vpd = ReadRwVpd(main_fw_file)
Ricky Liang53390232013-03-08 15:37:57 +0800857 print 'probe result:'
858 print probe_results.Encode()
Andy Cheng0465d132013-03-20 12:12:06 +0800859 event_log.Log(
Ricky Liang53390232013-03-08 15:37:57 +0800860 'probe',
861 found_components=probe_results.found_probe_value_map,
862 missing_component_classes=probe_results.missing_component_classes,
863 volatiles=probe_results.found_volatile_values,
864 initial_configs=probe_results.initial_configs)
Andy Cheng0465d132013-03-20 12:12:06 +0800865 event_log.Log('vpd', probed_ro_vpd=FilterDict(probed_ro_vpd),
Ricky Liang53390232013-03-08 15:37:57 +0800866 probed_rw_vpd=FilterDict(probed_rw_vpd))
867
Ricky Lianga70a1202013-03-15 15:03:17 +0800868 GetGooftool(options).VerifyHwidV3(
Ricky Liangab9d0b82013-03-19 02:15:32 +0800869 hwid_str, probe_results, probed_ro_vpd, probed_rw_vpd)
Ricky Liang53390232013-03-08 15:37:57 +0800870
Andy Cheng0465d132013-03-20 12:12:06 +0800871 event_log.Log('verified_hwid', hwid=hwid_str)
Ricky Liang53390232013-03-08 15:37:57 +0800872 print 'Verification SUCCESS!'
873
874
Ricky Liang7905f272013-03-16 01:57:10 +0800875@Command('decode_hwid_v3',
876 _board_cmd_arg,
877 _hwdb_path_cmd_arg,
878 _hwid_cmd_arg)
879def DecodeHwidV3(options):
880 """Decodes the given v3 HWID and prints out decoded information.
881
882 If no HWID is given, the HWID stored on the device will be loaded and used
883 instead.
884 """
885 decoded_hwid_context = Gooftool(hwid_version=3, board=options.board,
886 hwdb_path=options.hwdb_path).DecodeHwidV3(
887 options.hwid)
888
Ricky Liang5b4568d2013-04-23 17:15:23 +0800889 results = {}
890 results['board'] = decoded_hwid_context.database.board
891 results['binary_string'] = decoded_hwid_context.binary_string
892 results['components'] = collections.defaultdict(list)
Ricky Liang7905f272013-03-16 01:57:10 +0800893 components = decoded_hwid_context.bom.components
894 for comp_cls in sorted(components):
Ricky Liang5b4568d2013-04-23 17:15:23 +0800895 for (comp_name, probed_values, _) in sorted(components[comp_cls]):
896 if not probed_values:
Ricky Liang7905f272013-03-16 01:57:10 +0800897 db_components = decoded_hwid_context.database.components
Ricky Liang5b4568d2013-04-23 17:15:23 +0800898 probed_values = db_components.GetComponentAttributes(
899 comp_cls, comp_name)['values']
900 results['components'][comp_cls].append(
901 {comp_name: probed_values if probed_values else None})
902 # Convert defaultdict to dict.
903 results['components'] = dict(results['components'])
904 print yaml.dump(results, default_flow_style=False)
Ricky Liang7905f272013-03-16 01:57:10 +0800905
906
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800907def Main():
908 """Run sub-command specified by the command line args."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800909
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800910 options = ParseCmdline(
911 'Perform Google required factory tests.',
912 CmdArg('-l', '--log', metavar='PATH',
913 help='Write logs to this file.'),
Jon Salza4bea382012-10-29 13:00:34 +0800914 CmdArg('--suppress-event-logs', action='store_true',
915 help='Suppress event logging.'),
Jon Salzfb61b1d2013-05-15 16:04:13 +0800916 CmdArg('-i', '--hwid-version', default=3, choices=[2, 3], type=int,
Ricky Lianga70a1202013-03-15 15:03:17 +0800917 help='Version of HWID to operate on.'),
Tammo Spalink8fab5312012-05-28 18:33:30 +0800918 verbosity_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800919 SetupLogging(options.verbosity, options.log)
Andy Cheng0465d132013-03-20 12:12:06 +0800920 event_log.SetGlobalLoggerDefaultPrefix('gooftool')
921 event_log.GetGlobalLogger().suppress = options.suppress_event_logs
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800922 logging.debug('gooftool options: %s', repr(options))
923 try:
924 logging.debug('GOOFTOOL command %r', options.command_name)
925 options.command(options)
926 logging.info('GOOFTOOL command %r SUCCESS', options.command_name)
927 except Error, e:
928 logging.exception(e)
929 sys.exit('GOOFTOOL command %r ERROR: %s' % (options.command_name, e))
930 except Exception, e:
931 logging.exception(e)
932 sys.exit('UNCAUGHT RUNTIME EXCEPTION %s' % e)
933
934
935if __name__ == '__main__':
936 Main()