blob: 91589632569bdc562110fdef8dcd4cd0f5012b65 [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
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080021
Andy Cheng2582d292012-12-04 17:38:28 +080022from tempfile import gettempdir
Tammo Spalink86a61c62012-05-25 15:10:35 +080023
Tammo Spalinka40293e2012-07-04 14:58:56 +080024import factory_common # pylint: disable=W0611
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080025
Jon Salz0f8a6842012-09-25 11:28:22 +080026from cros.factory.common import Error, SetupLogging, Shell
Tammo Spalink394e4492012-08-01 10:20:30 -070027from cros.factory.common import YamlWrite
Ricky Liang53390232013-03-08 15:37:57 +080028from cros.factory.event_log import EventLog, EVENT_LOG_DIR
29from cros.factory.event_log import TimedUuid
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
Ricky Liang53390232013-03-08 15:37:57 +080039from cros.factory.hwdb.yaml_datastore import InvalidDataError
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 Spalink86a61c62012-05-25 15:10:35 +080045# Use a global event log, so that only a single log is created when
46# gooftool is called programmatically.
47_event_log = EventLog('gooftool')
48
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080049
Tammo Spalink5c699832012-07-03 17:50:39 +080050# TODO(tammo): Replace calls to sys.exit with raise Exit, and maybe
51# treat that specially (as a smoot exit, as opposed to the more
52# verbose output for generic Error).
53
54
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080055@Command('write_hwid',
56 CmdArg('hwid', metavar='HWID', help='HWID string'))
Andy Chengc92e6f92012-11-20 16:55:53 +080057def WriteHWID(options):
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080058 """Write specified HWID value into the system BB."""
Andy Cheng7a76cb82012-11-19 18:08:19 +080059
Tammo Spalink95c43732012-07-25 15:57:14 -070060 logging.info('writing hwid string %r', options.hwid)
Andy Chengc92e6f92012-11-20 16:55:53 +080061 Gooftool().WriteHWID(options.hwid)
Tammo Spalink86a61c62012-05-25 15:10:35 +080062 _event_log.Log('write_hwid', hwid=options.hwid)
Tammo Spalink95c43732012-07-25 15:57:14 -070063 print 'Wrote HWID: %r' % options.hwid
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080064
65
Ricky Liang53390232013-03-08 15:37:57 +080066_board_cmd_arg = CmdArg(
67 '--board', metavar='BOARD',
68 default=None, help='Board name to test.')
69
Tammo Spalink8fab5312012-05-28 18:33:30 +080070_hwdb_path_cmd_arg = CmdArg(
71 '--hwdb_path', metavar='PATH',
72 default=hwid_tool.DEFAULT_HWID_DATA_PATH,
73 help='Path to the HWID database.')
74
Tammo Spalink95c43732012-07-25 15:57:14 -070075_hwid_status_list_cmd_arg = CmdArg(
76 '--status', nargs='*', default=['supported'],
77 help='allow only HWIDs with these status values')
78
Jon Salzce124fb2012-10-02 17:42:03 +080079_probe_results_cmd_arg = CmdArg(
80 '--probe_results', metavar='RESULTS.yaml',
81 help=('Output from "gooftool probe" (used instead of '
82 'probing this system).'))
83
Ricky Liang53390232013-03-08 15:37:57 +080084_device_info_cmd_arg = CmdArg(
85 '--device_info', metavar='DEVICE_INFO', default=None,
86 help='A dict of device info to use instead of fetching from shopfllor '
87 'server.')
88
Jon Salzce124fb2012-10-02 17:42:03 +080089_hwid_cmd_arg = CmdArg(
90 '--hwid', metavar='HWID',
91 help=('HWID to verify (instead of the currently set HWID of '
92 'this system)'))
93
Tammo Spalink95c43732012-07-25 15:57:14 -070094
95@Command('best_match_hwids',
Tammo Spalink8fab5312012-05-28 18:33:30 +080096 _hwdb_path_cmd_arg,
97 CmdArg('-b', '--board', metavar='BOARD',
Tammo Spalink95c43732012-07-25 15:57:14 -070098 help='optional BOARD name, needed only if data is present '
99 'for more than one'),
Tammo Spalink8fab5312012-05-28 18:33:30 +0800100 CmdArg('--bom', metavar='BOM', help='BOM name'),
101 CmdArg('--variant', metavar='VARIANT', help='VARIANT code'),
Tammo Spalink5c699832012-07-03 17:50:39 +0800102 CmdArg('--optimistic', action='store_true',
103 help='do not probe; assume singletons match'),
Tammo Spalink95c43732012-07-25 15:57:14 -0700104 CmdArg('--comps', nargs='*', default=[],
105 help='list of canonical component names'),
106 CmdArg('--missing', nargs='*', default=[],
107 help='list component classes to be assumed missing'),
Tammo Spalink5c699832012-07-03 17:50:39 +0800108 CmdArg('--status', nargs='*', default=['supported'],
Tammo Spalink95c43732012-07-25 15:57:14 -0700109 help='consider only HWIDs within this list of status values'))
110def BestMatchHwids(options):
Tammo Spalink8fab5312012-05-28 18:33:30 +0800111 """Determine a list of possible HWIDs using provided args and probeing.
112
113 VOLATILE can always be determined by probing. To get a unique
114 result, VARIANT must be specified for all cases where the matching
115 BOM has more than one associated variant code, otherwise all HWID
116 variants will be returned. Both VARIANT and BOM information can
Tammo Spalink95c43732012-07-25 15:57:14 -0700117 alternatively be specified using the --stdin_comps argument, which
118 allows specifying a list of canonical names (one per line) on stdin,
119 one per line. Based on what is known from BOM and stdin_comps,
120 determine a list of components to probe for, and use those probe
121 results to resolve a list of matching HWIDs. If no boms,
122 components, or variant codes are specified, then a list of all HWIDs
Andy Cheng8ece7382012-08-22 16:25:42 +0800123 that match probeable components will be returned.
Tammo Spalink8fab5312012-05-28 18:33:30 +0800124
125 Returns (on stdout): A list of HWIDs that match the available probe
126 results and argument contraints, one per line.
Tammo Spalink70b48a52012-08-08 16:54:51 -0700127
128 Example:
129
130 // Three ways to specify a keyboard (assuming it is a variant component)
131 gooftool best_match_hwids --missing keyboard
132 gooftool best_match_hwids --variant A or
133 gooftool best_match_hwids --comps us_kbd
Tammo Spalink8fab5312012-05-28 18:33:30 +0800134 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800135
Tammo Spalink5c699832012-07-03 17:50:39 +0800136 map(hwid_tool.Validate.Status, options.status)
Tammo Spalink95c43732012-07-25 15:57:14 -0700137 hw_db = hwid_tool.HardwareDb(options.hwdb_path)
Tammo Spalink5c699832012-07-03 17:50:39 +0800138 comp_db = hw_db.comp_db
Tammo Spalink3a7e9022012-06-27 14:08:40 +0800139 device = hw_db.GetDevice(options.board)
Tammo Spalink5c699832012-07-03 17:50:39 +0800140 component_spec = hwid_tool.ComponentSpec.New()
Tammo Spalink8fab5312012-05-28 18:33:30 +0800141 if options.bom:
Tammo Spalink5c699832012-07-03 17:50:39 +0800142 device.BomExists(options.bom)
Tammo Spalink01e11722012-07-24 10:17:54 -0700143 component_spec = hwid_tool.CombineComponentSpecs(
Tammo Spalink5c699832012-07-03 17:50:39 +0800144 component_spec, device.boms[options.bom].primary)
Tammo Spalink8fab5312012-05-28 18:33:30 +0800145 if options.variant:
Tammo Spalink5c699832012-07-03 17:50:39 +0800146 device.VariantExists(options.variant)
147 variant_spec = device.variants[options.variant]
Tammo Spalink01e11722012-07-24 10:17:54 -0700148 if hwid_tool.ComponentSpecsConflict(component_spec, variant_spec):
Tammo Spalink95c43732012-07-25 15:57:14 -0700149 sys.exit('ERROR: multiple specifications for these components:\n%s'
Tammo Spalink394e4492012-08-01 10:20:30 -0700150 % YamlWrite(sorted(
151 hwid_tool.ComponentSpecClasses(component_spec) &
152 hwid_tool.ComponentSpecClasses(variant_spec))))
Tammo Spalink01e11722012-07-24 10:17:54 -0700153 component_spec = hwid_tool.CombineComponentSpecs(
154 component_spec, variant_spec)
Tammo Spalink95c43732012-07-25 15:57:14 -0700155 if options.comps or options.missing:
156 map(comp_db.CompExists, options.comps)
157 map(comp_db.CompClassExists, options.missing)
158 extra_comp_spec = comp_db.CreateComponentSpec(
159 components=options.comps,
160 missing=options.missing)
161 print 'cmdline asserted components:\n%s' % extra_comp_spec.Encode()
162 if hwid_tool.ComponentSpecsConflict(component_spec, extra_comp_spec):
163 sys.exit('ERROR: multiple specifications for these components:\n%s'
Tammo Spalink394e4492012-08-01 10:20:30 -0700164 % YamlWrite(sorted(
165 hwid_tool.ComponentSpecClasses(component_spec) &
166 hwid_tool.ComponentSpecClasses(extra_comp_spec))))
Tammo Spalink95c43732012-07-25 15:57:14 -0700167 component_spec = hwid_tool.CombineComponentSpecs(
168 component_spec, extra_comp_spec)
Tammo Spalink01e11722012-07-24 10:17:54 -0700169 spec_classes = hwid_tool.ComponentSpecClasses(component_spec)
Tammo Spalink95c43732012-07-25 15:57:14 -0700170 missing_classes = set(comp_db.all_comp_classes) - spec_classes
Tammo Spalink5c699832012-07-03 17:50:39 +0800171 if missing_classes and not options.optimistic:
Andy Cheng8ece7382012-08-22 16:25:42 +0800172 non_probeable_missing = missing_classes - PROBEABLE_COMPONENT_CLASSES
173 if non_probeable_missing:
Tammo Spalink95c43732012-07-25 15:57:14 -0700174 sys.exit('FAILURE: these classes are necessary, were not specified '
Tammo Spalink70b48a52012-08-08 16:54:51 -0700175 'as inputs, and cannot be probed for:\n%s'
176 'This problem can often be addressed by specifying all of '
177 'the missing components on the command line (see the command '
Andy Cheng8ece7382012-08-22 16:25:42 +0800178 'help).' % YamlWrite(list(non_probeable_missing)))
Tammo Spalink95c43732012-07-25 15:57:14 -0700179 print 'probing for missing classes:'
180 print YamlWrite(list(missing_classes))
181 probe_results = Probe(target_comp_classes=list(missing_classes),
182 probe_volatile=False, probe_initial_config=False)
183 cooked_components = comp_db.MatchComponentProbeValues(
184 probe_results.found_probe_value_map)
185 if cooked_components.unmatched:
186 sys.exit('ERROR: some probed components are unrecognized:\n%s'
187 % YamlWrite(cooked_components.unmatched))
188 probed_comp_spec = comp_db.CreateComponentSpec(
189 components=cooked_components.matched,
190 missing=probe_results.missing_component_classes)
191 component_spec = hwid_tool.CombineComponentSpecs(
192 component_spec, probed_comp_spec)
193 print YamlWrite({'component data used for matching': {
194 'missing component classes': component_spec.classes_missing,
195 'found components': component_spec.components}})
196 component_data = hwid_tool.ComponentData(
197 extant_components=hwid_tool.ComponentSpecCompClassMap(
198 component_spec).keys(),
199 classes_missing=component_spec.classes_missing)
200 match_tree = device.BuildMatchTree(component_data)
201 if not match_tree:
202 sys.exit('FAILURE: NO matching BOMs found')
203 print 'potential BOMs/VARIANTs:'
204 potential_variants = set()
205 potential_volatiles = set()
206 for bom_name, variant_tree in match_tree.items():
207 print ' BOM: %-8s VARIANTS: %s' % (
208 bom_name, ', '.join(sorted(variant_tree)))
209 for variant_code in variant_tree:
210 potential_variants.add(variant_code)
211 for volatile_code in device.volatiles:
212 status = device.GetHwidStatus(bom_name, variant_code, volatile_code)
213 if status in options.status:
214 potential_volatiles.add(volatile_code)
215 print ''
216 if len(potential_variants) == 0:
217 sys.exit('FAILURE: no matching VARIANTs found')
218 if len(potential_volatiles) == 0:
219 sys.exit('FAILURE: no VOLATILEs found for potential matching BOMs/VARIANTS '
220 '(with specified status)')
Tammo Spalink394e4492012-08-01 10:20:30 -0700221 if (options.optimistic and
222 len(match_tree) == 1 and
223 len(potential_variants) == 1 and
224 len(potential_volatiles) == 1):
225 print ('MATCHING HWID: %s' % device.FmtHwid(match_tree.keys().pop(),
226 potential_variants.pop(),
227 potential_volatiles.pop()))
Tammo Spalink5c699832012-07-03 17:50:39 +0800228 return
Tammo Spalink95c43732012-07-25 15:57:14 -0700229 print ('probing VOLATILEs to resolve potential matches: %s\n' %
230 ', '.join(sorted(potential_volatiles)))
231 vol_probe_results = Probe(
232 target_comp_classes=[],
233 probe_volatile=True,
234 probe_initial_config=False)
235 cooked_volatiles = device.MatchVolatileValues(
236 vol_probe_results.found_volatile_values)
237 match_tree = device.BuildMatchTree(
238 component_data, cooked_volatiles.matched_tags)
239 matched_hwids = device.GetMatchTreeHwids(match_tree)
240 if matched_hwids:
241 for hwid in matched_hwids:
Ricky Liang02f3bd72012-09-21 14:33:01 +0800242 if matched_hwids[hwid] in options.status:
243 print 'MATCHING HWID: %s' % hwid
Tammo Spalink95c43732012-07-25 15:57:14 -0700244 return
245 print 'exact HWID matching failed, but the following BOMs match: %s' % (
246 ', '.join(sorted(match_tree)))
247 if options.optimistic and len(match_tree) == 1:
248 bom_name = set(match_tree).pop()
Tammo Spalink5c699832012-07-03 17:50:39 +0800249 bom = device.boms[bom_name]
Tammo Spalink95c43732012-07-25 15:57:14 -0700250 variant_matches = match_tree[bom_name]
Tammo Spalink5c699832012-07-03 17:50:39 +0800251 if len(variant_matches) == 1:
252 var_code = set(variant_matches).pop()
253 elif len(bom.variants) == 1:
254 var_code = set(bom.variants).pop()
255 else:
Tammo Spalink95c43732012-07-25 15:57:14 -0700256 sys.exit('FAILURE: NO matching HWIDs found; optimistic matching failed '
257 'because there were too many variants to choose from for BOM %r'
258 % bom_name)
259 hwids = [device.FmtHwid(bom_name, var_code, vol_code)
260 for vol_code in device.volatiles
261 if device.GetHwidStatus(bom_name, var_code, vol_code)
262 in options.status]
263 for hwid in hwids:
264 print 'MATCHING HWID: %s' % hwid
Tammo Spalink5c699832012-07-03 17:50:39 +0800265 return
266 else:
Tammo Spalink95c43732012-07-25 15:57:14 -0700267 print ('optimistic matching not attempted because either it was '
268 'not requested, or because the number of BOMs was <> 1\n')
269 sys.exit('FAILURE: NO matching HWIDs found')
Tammo Spalink8fab5312012-05-28 18:33:30 +0800270
271
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800272@Command('probe',
273 CmdArg('--comps', nargs='*',
274 help='List of keys from the component_db registry.'),
275 CmdArg('--no_vol', action='store_true',
276 help='Do not probe volatile data.'),
277 CmdArg('--no_ic', action='store_true',
Jon Salz0f8a6842012-09-25 11:28:22 +0800278 help='Do not probe initial_config data.'),
279 CmdArg('--include_vpd', action='store_true',
280 help='Include VPD data in volatiles.'))
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800281def RunProbe(options):
282 """Print yaml-formatted breakdown of probed device properties."""
Ricky Liang53390232013-03-08 15:37:57 +0800283 try:
284 print Gooftool().Probe(target_comp_classes=options.comps,
285 probe_volatile=not options.no_vol,
286 probe_initial_config=not options.no_ic,
287 probe_vpd=options.include_vpd).Encode()
288 except InvalidDataError:
289 print Gooftool(hwid_version=3).Probe(target_comp_classes=options.comps,
290 probe_volatile=not options.no_vol,
291 probe_initial_config=not options.no_ic,
292 probe_vpd=options.include_vpd).Encode()
293
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800294
Tammo Spalink214caf42012-05-28 10:45:00 +0800295@Command('verify_components',
296 _hwdb_path_cmd_arg,
Tammo Spalink5c699832012-07-03 17:50:39 +0800297 CmdArg('target_comps', nargs='*'))
Tammo Spalink214caf42012-05-28 10:45:00 +0800298def VerifyComponents(options):
Andy Cheng8ece7382012-08-22 16:25:42 +0800299 """Verify that probeable components all match entries in the component_db.
Tammo Spalink214caf42012-05-28 10:45:00 +0800300
Tammo Spalink5c699832012-07-03 17:50:39 +0800301 Probe for each component class in the target_comps and verify
Tammo Spalink214caf42012-05-28 10:45:00 +0800302 that a corresponding match exists in the component_db -- make sure
303 that these components are present, that they have been approved, but
304 do not check against any specific BOM/HWID configurations.
305 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800306
Tammo Spalink5c699832012-07-03 17:50:39 +0800307 comp_db = hwid_tool.HardwareDb(options.hwdb_path).comp_db
Andy Chengc531e2f2012-10-15 19:09:17 +0800308 try:
309 result = Gooftool(component_db=comp_db).VerifyComponents(
310 options.target_comps)
311 except ValueError, e:
312 sys.exit(e)
313
Ricky Liang53390232013-03-08 15:37:57 +0800314 PrintVerifyComponentsResults(result)
315
316
317def PrintVerifyComponentsResults(result):
318 """Prints out the results of VerifyComponents method call.
319
320 Groups the results into two groups: 'matches' and 'errors', and prints out
321 their values.
322 """
Andy Chengc531e2f2012-10-15 19:09:17 +0800323 # group by matches and errors
Tammo Spalink214caf42012-05-28 10:45:00 +0800324 matches = []
Andy Chengc531e2f2012-10-15 19:09:17 +0800325 errors = []
326 for result_list in result.values():
327 for component_name, _, error in result_list:
328 if component_name:
329 matches.append(component_name)
Tammo Spalink214caf42012-05-28 10:45:00 +0800330 else:
Andy Chengc531e2f2012-10-15 19:09:17 +0800331 errors.append(error)
332
Andy Cheng228a8c92012-08-27 10:53:57 +0800333 if matches:
334 print 'found probeable components:\n %s' % '\n '.join(matches)
Tammo Spalink214caf42012-05-28 10:45:00 +0800335 if errors:
Andy Cheng228a8c92012-08-27 10:53:57 +0800336 print '\nerrors:\n %s' % '\n '.join(errors)
337 sys.exit('\ncomponent verification FAILURE')
Tammo Spalink214caf42012-05-28 10:45:00 +0800338 else:
Andy Cheng228a8c92012-08-27 10:53:57 +0800339 print "\ncomponent verification SUCCESS"
Tammo Spalink214caf42012-05-28 10:45:00 +0800340
341
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800342@Command('verify_hwid',
Tammo Spalink95c43732012-07-25 15:57:14 -0700343 _hwid_status_list_cmd_arg,
Jon Salz0f8a6842012-09-25 11:28:22 +0800344 _hwdb_path_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800345 _probe_results_cmd_arg,
346 _hwid_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800347def VerifyHwid(options):
348 """Verify system HWID properties match probed device properties.
349
350 First probe components, volatile and initial_config parameters for
351 the DUT. Then use the available device data to produce a list of
352 candidate HWIDs. Then verify the HWID from the DUT is present in
353 that list. Then verify that the DUT initial config values match
354 those specified for its HWID. Finally, verify that VPD contains all
355 the necessary fields as specified by the board data, and when
356 possible verify that values are legitimate.
357 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800358
Ricky Liangf7857c12012-09-17 13:34:41 +0800359 def VerifyVpd(ro_vpd_keys, rw_vpd_keys):
Tammo Spalink5c699832012-07-03 17:50:39 +0800360 for key in ro_vpd_keys:
361 if key not in ro_vpd:
Ricky Liangf7857c12012-09-17 13:34:41 +0800362 sys.exit('Missing required RO VPD field: %s' % key)
Tammo Spalink01e11722012-07-24 10:17:54 -0700363 known_valid_values = KNOWN_VPD_FIELD_DATA.get(key, None)
Tammo Spalink5c699832012-07-03 17:50:39 +0800364 value = ro_vpd[key]
Ricky Liangf7857c12012-09-17 13:34:41 +0800365 if (known_valid_values is not None) and (value not in known_valid_values):
366 sys.exit('Invalid RO VPD entry : key %r, value %r' % (key, value))
Ricky Liangf7857c12012-09-17 13:34:41 +0800367 for key in rw_vpd_keys:
368 if key not in rw_vpd:
369 sys.exit('Missing required RW VPD field: %s' % key)
370 known_valid_values = KNOWN_VPD_FIELD_DATA.get(key, None)
371 value = rw_vpd[key]
372 if (known_valid_values is not None) and (value not in known_valid_values):
373 sys.exit('Invalid RW VPD entry : key %r, value %r' % (key, value))
Jon Salz8baad8b2013-03-11 20:01:45 +0800374 _event_log.Log('vpd', ro_vpd=FilterDict(ro_vpd), rw_vpd=FilterDict(rw_vpd))
Tammo Spalink5c699832012-07-03 17:50:39 +0800375 map(hwid_tool.Validate.Status, options.status)
Jon Salz0f8a6842012-09-25 11:28:22 +0800376
Jon Salz81350812012-10-11 16:13:22 +0800377 if not options.hwid or not options.probe_results:
378 main_fw_file = crosfw.LoadMainFirmware().GetFileName()
Jon Salz0f8a6842012-09-25 11:28:22 +0800379
380 if options.hwid:
381 hwid_str = options.hwid
382 else:
383 gbb_result = Shell('gbb_utility -g --hwid %s' % main_fw_file).stdout
384 hwid_str = re.findall(r'hardware_id:(.*)', gbb_result)[0].strip()
Tammo Spalink95c43732012-07-25 15:57:14 -0700385 hwid = hwid_tool.ParseHwid(hwid_str)
Tammo Spalink5c699832012-07-03 17:50:39 +0800386 hw_db = hwid_tool.HardwareDb(options.hwdb_path)
Jon Salz0f8a6842012-09-25 11:28:22 +0800387 print 'Verifying HWID: %r\n' % hwid.hwid
Tammo Spalink95c43732012-07-25 15:57:14 -0700388 device = hw_db.GetDevice(hwid.board)
389 hwid_status = device.GetHwidStatus(hwid.bom, hwid.variant, hwid.volatile)
390 if hwid_status not in options.status:
Tammo Spalink5c699832012-07-03 17:50:39 +0800391 sys.exit('HWID status must be one of [%s], found %r' %
Hung-Te Lin4f5beb12012-08-20 14:48:06 +0800392 (', '.join(options.status), hwid_status))
Jon Salz0f8a6842012-09-25 11:28:22 +0800393 if options.probe_results:
394 # Pull in probe results (including VPD data) from the given file
395 # rather than probing the current system.
396 probe_results = hwid_tool.ProbeResults.Decode(
397 open(options.probe_results).read())
398 ro_vpd = {}
399 rw_vpd = {}
400 for k, v in probe_results.found_volatile_values.items():
401 match = re.match('^vpd\.(ro|rw)\.(\w+)$', k)
402 if match:
403 del probe_results.found_volatile_values[k]
404 (ro_vpd if match.group(1) == 'ro' else rw_vpd)[match.group(2)] = v
405 else:
406 probe_results = Probe()
407 ro_vpd = ReadRoVpd(main_fw_file)
408 rw_vpd = ReadRwVpd(main_fw_file)
Tammo Spalink95c43732012-07-25 15:57:14 -0700409 cooked_components = hw_db.comp_db.MatchComponentProbeValues(
410 probe_results.found_probe_value_map)
411 cooked_volatiles = device.MatchVolatileValues(
412 probe_results.found_volatile_values)
413 cooked_initial_configs = device.MatchInitialConfigValues(
414 probe_results.initial_configs)
415 component_data = hwid_tool.ComponentData(
416 extant_components=cooked_components.matched,
417 classes_missing=probe_results.missing_component_classes)
418 match_tree = device.BuildMatchTree(
419 component_data, cooked_volatiles.matched_tags)
420 matched_hwids = device.GetMatchTreeHwids(match_tree)
421 print 'HWID status: %s\n' % hwid_status
422 print 'probed system components:'
423 print YamlWrite(cooked_components.__dict__)
424 print 'missing component classes:'
425 print YamlWrite(probe_results.missing_component_classes)
426 print 'probed volatiles:'
427 print YamlWrite(cooked_volatiles.__dict__)
428 print 'probed initial_configs:'
429 print YamlWrite(cooked_initial_configs)
430 print 'hwid match tree:'
431 print YamlWrite(match_tree)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800432 _event_log.Log(
Tammo Spalink5c699832012-07-03 17:50:39 +0800433 'probe',
Tammo Spalink95c43732012-07-25 15:57:14 -0700434 found_components=cooked_components.__dict__,
435 missing_component_classes=probe_results.missing_component_classes,
436 volatiles=cooked_volatiles.__dict__,
437 initial_configs=cooked_initial_configs)
438 if hwid.hwid not in matched_hwids:
Tammo Spalink5c699832012-07-03 17:50:39 +0800439 err_msg = 'HWID verification FAILED.\n'
Tammo Spalink95c43732012-07-25 15:57:14 -0700440 if cooked_components.unmatched:
Tammo Spalink5c699832012-07-03 17:50:39 +0800441 sys.exit(err_msg + 'some components could not be indentified:\n%s' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700442 YamlWrite(cooked_components.unmatched))
443 if not match_tree:
Tammo Spalink5c699832012-07-03 17:50:39 +0800444 sys.exit(err_msg + 'no matching boms were found for components:\n%s' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700445 component_data.Encode())
446 if hwid.bom not in match_tree:
Tammo Spalink5c699832012-07-03 17:50:39 +0800447 sys.exit(err_msg + 'matching boms [%s] do not include target bom %r' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700448 (', '.join(sorted(match_tree)), hwid.bom))
449 err_msg += 'target bom %r matches components' % hwid.bom
450 if hwid.bom not in device.IntersectBomsAndInitialConfigs(
451 cooked_initial_configs):
Tammo Spalink5c699832012-07-03 17:50:39 +0800452 sys.exit(err_msg + ', but failed initial config verification')
Tammo Spalink95c43732012-07-25 15:57:14 -0700453 matched_variants = match_tree.get(hwid.bom, {})
454 if hwid.variant not in matched_variants:
Tammo Spalink5c699832012-07-03 17:50:39 +0800455 sys.exit(err_msg + ', but target variant_code %r did not match' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700456 hwid.variant)
457 matched_volatiles = matched_variants.get(hwid.variant, {})
458 if hwid.volatile not in matched_volatiles:
Tammo Spalink5c699832012-07-03 17:50:39 +0800459 sys.exit(err_msg + ', but target volatile_code %r did not match' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700460 hwid.volatile)
461 found_status = matched_volatiles.get(hwid.volatile, None)
Tammo Spalink5c699832012-07-03 17:50:39 +0800462 sys.exit(err_msg + ', but hwid status %r was unacceptable' % found_status)
Ricky Liangf7857c12012-09-17 13:34:41 +0800463 VerifyVpd(device.vpd_ro_fields, device.vpd_rw_fields)
Tammo Spalink5c699832012-07-03 17:50:39 +0800464 _event_log.Log('verified_hwid', hwid=hwid)
Tammo Spalink95c43732012-07-25 15:57:14 -0700465 print 'Verification SUCCESS!'
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800466
467
468@Command('verify_keys')
Tammo Spalink01e11722012-07-24 10:17:54 -0700469def VerifyKeys(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800470 """Verify keys in firmware and SSD match."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800471
472 return Gooftool().VerifyKeys()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800473
474
475@Command('set_fw_bitmap_locale')
Tammo Spalink01e11722012-07-24 10:17:54 -0700476def SetFirmwareBitmapLocale(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800477 """Use VPD locale value to set firmware bitmap default language."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800478
Andy Cheng2582d292012-12-04 17:38:28 +0800479 (index, locale) = Gooftool().SetFirmwareBitmapLocale()
480 logging.info('Firmware bitmap initial locale set to %d (%s).',
481 index, locale)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800482
483
484@Command('verify_system_time')
Tammo Spalink01e11722012-07-24 10:17:54 -0700485def VerifySystemTime(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800486 """Verify system time is later than release filesystem creation time."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800487
488 return Gooftool().VerifySystemTime()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800489
490
491@Command('verify_rootfs')
Tammo Spalink01e11722012-07-24 10:17:54 -0700492def VerifyRootFs(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800493 """Verify rootfs on SSD is valid by checking hash."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800494
495 return Gooftool().VerifyRootFs()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800496
497
498@Command('verify_switch_wp')
Andy Chengc92e6f92012-11-20 16:55:53 +0800499def VerifyWPSwitch(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800500 """Verify hardware write protection switch is enabled."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800501
Andy Chengc92e6f92012-11-20 16:55:53 +0800502 Gooftool().VerifyWPSwitch()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800503
504
505@Command('verify_switch_dev')
Tammo Spalink01e11722012-07-24 10:17:54 -0700506def VerifyDevSwitch(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800507 """Verify developer switch is disabled."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800508
Andy Chengaf30a1b2012-12-03 16:50:09 +0800509 if Gooftool().CheckDevSwitchForDisabling():
Hung-Te Lind7d34722012-07-26 16:48:35 +0800510 logging.warn('VerifyDevSwitch: No physical switch.')
511 _event_log.Log('switch_dev', type='virtual switch')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800512
513
514@Command('write_protect')
Tammo Spalink01e11722012-07-24 10:17:54 -0700515def EnableFwWp(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800516 """Enable then verify firmware write protection."""
517
Hung-Te Linb21c6682012-08-01 13:53:57 +0800518 def CalculateLegacyRange(fw_type, length, section_data,
519 section_name):
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800520 ro_size = length / 2
521 ro_a = int(section_data[0] / ro_size)
522 ro_b = int((section_data[0] + section_data[1] - 1) / ro_size)
523 if ro_a != ro_b:
524 raise Error("%s firmware section %s has illegal size" %
Hung-Te Linb21c6682012-08-01 13:53:57 +0800525 (fw_type, section_name))
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800526 ro_offset = ro_a * ro_size
527 return (ro_offset, ro_size)
528
529 def WriteProtect(fw_file_path, fw_type, legacy_section):
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800530 """Calculate protection size, then invoke flashrom.
531
532 Our supported chips only allow write protecting half their total
533 size, so we parition the flash chipset space accordingly.
534 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800535
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800536 raw_image = open(fw_file_path, 'rb').read()
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800537 wp_section = 'WP_RO'
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800538 image = crosfw.FirmwareImage(raw_image)
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800539 if image.has_section(wp_section):
540 section_data = image.get_section_area(wp_section)
541 ro_offset = section_data[0]
542 ro_size = section_data[1]
543 elif image.has_section(legacy_section):
544 section_data = image.get_section_area(legacy_section)
545 (ro_offset, ro_size) = CalculateLegacyRange(
Hung-Te Linb21c6682012-08-01 13:53:57 +0800546 fw_type, len(raw_image), section_data, legacy_section)
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800547 else:
548 raise Error('could not find %s firmware section %s or %s' %
549 (fw_type, wp_section, legacy_section))
550
551 logging.debug('write protecting %s [off=%x size=%x]', fw_type,
552 ro_offset, ro_size)
553 crosfw.Flashrom(fw_type).EnableWriteProtection(ro_offset, ro_size)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800554
555 WriteProtect(crosfw.LoadMainFirmware().GetFileName(), 'main', 'RO_SECTION')
Tammo Spalink86a61c62012-05-25 15:10:35 +0800556 _event_log.Log('wp', fw='main')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800557 ec_fw_file = crosfw.LoadEcFirmware().GetFileName()
558 if ec_fw_file is not None:
559 WriteProtect(ec_fw_file, 'ec', 'EC_RO')
Tammo Spalink86a61c62012-05-25 15:10:35 +0800560 _event_log.Log('wp', fw='ec')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800561 else:
562 logging.warning('EC not write protected (seems there is no EC flash).')
563
564
565@Command('clear_gbb_flags')
Andy Chengc92e6f92012-11-20 16:55:53 +0800566def ClearGBBFlags(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800567 """Zero out the GBB flags, in preparation for transition to release state.
568
569 No GBB flags are set in release/shipping state, but they are useful
570 for factory/development. See "gbb_utility --flags" for details.
571 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800572
Andy Chengc92e6f92012-11-20 16:55:53 +0800573 Gooftool().ClearGBBFlags()
Tammo Spalink86a61c62012-05-25 15:10:35 +0800574 _event_log.Log('clear_gbb_flags')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800575
576
577@Command('prepare_wipe',
578 CmdArg('--fast', action='store_true',
579 help='use non-secure but faster wipe method.'))
580def PrepareWipe(options):
581 """Prepare system for transition to release state in next reboot."""
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800582
Andy Cheng7a76cb82012-11-19 18:08:19 +0800583 Gooftool().PrepareWipe(options.fast)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800584
585@Command('verify',
Hung-Te Lin6d827542012-07-19 11:50:41 +0800586 CmdArg('--no_write_protect', action='store_true',
587 help='Do not check write protection switch state.'),
Tammo Spalink95c43732012-07-25 15:57:14 -0700588 _hwid_status_list_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800589 _hwdb_path_cmd_arg,
590 _probe_results_cmd_arg,
591 _hwid_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800592def Verify(options):
593 """Verifies if whole factory process is ready for finalization.
594
595 This routine performs all the necessary checks to make sure the
596 device is ready to be finalized, but does not modify state. These
597 checks include dev switch, firmware write protection switch, hwid,
598 system time, keys, and root file system.
599 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800600
Hung-Te Lin6d827542012-07-19 11:50:41 +0800601 if not options.no_write_protect:
Andy Chengc92e6f92012-11-20 16:55:53 +0800602 VerifyWPSwitch({})
Hung-Te Lin6d827542012-07-19 11:50:41 +0800603 VerifyDevSwitch({})
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800604 VerifyHwid(options)
605 VerifySystemTime({})
606 VerifyKeys({})
607 VerifyRootFs({})
608
609
Tammo Spalink86a61c62012-05-25 15:10:35 +0800610@Command('log_system_details')
Tammo Spalink01e11722012-07-24 10:17:54 -0700611def LogSystemDetails(options): # pylint: disable=W0613
Tammo Spalink86a61c62012-05-25 15:10:35 +0800612 """Write miscellaneous system details to the event log."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800613
Andy Cheng5b0e9882012-12-10 12:43:18 +0800614 _event_log.Log('system_details', **Gooftool().GetSystemDetails())
Tammo Spalink86a61c62012-05-25 15:10:35 +0800615
616
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800617_upload_method_cmd_arg = CmdArg(
618 '--upload_method', metavar='METHOD:PARAM',
619 help=('How to perform the upload. METHOD should be one of '
cychiang3b15bd52012-09-08 13:58:18 +0800620 '{ftp, shopfloor, ftps, cpfe}.'))
Jon Salz65266432012-07-30 19:02:49 +0800621_add_file_cmd_arg = CmdArg(
622 '--add_file', metavar='FILE', action='append',
623 help='Extra file to include in report (must be an absolute path)')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800624
625@Command('upload_report',
Jon Salz65266432012-07-30 19:02:49 +0800626 _upload_method_cmd_arg,
627 _add_file_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800628def UploadReport(options):
629 """Create and a report containing key device details."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800630
Hung-Te Lin6bd16472012-06-20 16:26:47 +0800631 def NormalizeAsFileName(token):
632 return re.sub(r'\W+', '', token).strip()
Tammo Spalink86a61c62012-05-25 15:10:35 +0800633 ro_vpd = ReadRoVpd(crosfw.LoadMainFirmware().GetFileName())
634 device_sn = ro_vpd.get('serial_number', None)
635 if device_sn is None:
636 logging.warning('RO_VPD missing device serial number')
637 device_sn = 'MISSING_SN_' + TimedUuid()
Vic Yang85199e72013-01-28 14:33:11 +0800638 target_name = '%s_%s.tar.xz' % (time.strftime('%Y%m%dT%H%M%SZ',
639 time.gmtime()),
640 NormalizeAsFileName(device_sn))
Tammo Spalink86a61c62012-05-25 15:10:35 +0800641 target_path = os.path.join(gettempdir(), target_name)
642 # Intentionally ignoring dotfiles in EVENT_LOG_DIR.
Vic Yang85199e72013-01-28 14:33:11 +0800643 tar_cmd = 'cd %s ; tar cJf %s *' % (EVENT_LOG_DIR, target_path)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800644 tar_cmd += ' --add-file %s' % FACTORY_LOG_PATH
Jon Salz65266432012-07-30 19:02:49 +0800645 if options.add_file:
646 for f in options.add_file:
647 # Require absolute paths since the tar command may change the
648 # directory.
649 if not f.startswith('/'):
650 raise Error('Not an absolute path: %s' % f)
651 if not os.path.exists(f):
652 raise Error('File does not exist: %s' % f)
653 tar_cmd += ' --add-file %s' % pipes.quote(f)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800654 cmd_result = Shell(tar_cmd)
Jon Salzff88c022012-11-03 12:19:58 +0800655
656 if ((cmd_result.status == 1) and
657 all((x == '' or
658 'file changed as we read it' in x or
659 "Removing leading `/' from member names" in x)
660 for x in cmd_result.stderr.split('\n'))):
661 # That's OK. Make sure it's valid though.
Vic Yang85199e72013-01-28 14:33:11 +0800662 Spawn(['tar', 'tfJ', target_path], check_call=True, log=True,
Jon Salzff88c022012-11-03 12:19:58 +0800663 ignore_stdout=True)
664 elif not cmd_result.success:
Tammo Spalink86a61c62012-05-25 15:10:35 +0800665 raise Error('unable to tar event logs, cmd %r failed, stderr: %r' %
666 (tar_cmd, cmd_result.stderr))
Jon Salzff88c022012-11-03 12:19:58 +0800667
Tammo Spalink86a61c62012-05-25 15:10:35 +0800668 if options.upload_method is None or options.upload_method == 'none':
669 logging.warning('REPORT UPLOAD SKIPPED (report left at %s)', target_path)
670 return
671 method, param = options.upload_method.split(':', 1)
672 if method == 'shopfloor':
673 report_upload.ShopFloorUpload(target_path, param)
674 elif method == 'ftp':
Jay Kim360c1dd2012-06-25 10:58:11 -0700675 report_upload.FtpUpload(target_path, 'ftp:' + param)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800676 elif method == 'ftps':
677 report_upload.CurlUrlUpload(target_path, '--ftp-ssl-reqd ftp:%s' % param)
678 elif method == 'cpfe':
Shawn Nematbakhsh3404a092013-01-28 16:49:09 -0800679 report_upload.CpfeUpload(target_path, pipes.quote(param))
Tammo Spalink86a61c62012-05-25 15:10:35 +0800680 else:
681 raise Error('unknown report upload method %r', method)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800682
683
684@Command('finalize',
Hung-Te Lin6d827542012-07-19 11:50:41 +0800685 CmdArg('--no_write_protect', action='store_true',
686 help='Do not enable firmware write protection.'),
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800687 CmdArg('--fast', action='store_true',
688 help='use non-secure but faster wipe method.'),
689 _hwdb_path_cmd_arg,
Tammo Spalink95c43732012-07-25 15:57:14 -0700690 _hwid_status_list_cmd_arg,
Jon Salz65266432012-07-30 19:02:49 +0800691 _upload_method_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800692 _add_file_cmd_arg,
693 _probe_results_cmd_arg,
694 _hwid_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800695def Finalize(options):
696 """Verify system readiness and trigger transition into release state.
697
Hung-Te Lin6d827542012-07-19 11:50:41 +0800698 This routine first verifies system state (see verify command), modifies
699 firmware bitmaps to match locale, and then clears all of the factory-friendly
700 flags from the GBB. If everything is fine, it enables firmware write
701 protection (cannot rollback after this stage), uploads system logs & reports,
702 and sets the necessary boot flags to cause wipe of the factory image on the
703 next boot.
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800704 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800705
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800706 Verify(options)
707 SetFirmwareBitmapLocale({})
Andy Chengc92e6f92012-11-20 16:55:53 +0800708 ClearGBBFlags({})
Hung-Te Lin6d827542012-07-19 11:50:41 +0800709 if options.no_write_protect:
710 logging.warn('WARNING: Firmware Write Protection is SKIPPED.')
711 _event_log.Log('wp', fw='both', status='skipped')
712 else:
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800713 EnableFwWp({})
Jon Salza0f58e02012-05-29 19:33:39 +0800714 LogSystemDetails(options)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800715 UploadReport(options)
716 PrepareWipe(options)
717
718
Ricky Liang53390232013-03-08 15:37:57 +0800719@Command('verify_components_v3',
720 _board_cmd_arg,
721 _hwdb_path_cmd_arg,
722 CmdArg('target_comps', nargs='*'))
723def VerifyComponentsV3(options):
724 """Verify that probeable components all match entries in the component_db.
725
726 This method uses the HWIDv3 component database to verify components.
727
728 Probe for each component class in the target_comps and verify
729 that a corresponding match exists in the component_db -- make sure
730 that these components are present, that they have been approved, but
731 do not check against any specific BOM/HWID configurations.
732 """
733
734 result = Gooftool(hwid_version=3, board=options.board,
735 hwdb_path=options.hwdb_path).VerifyComponentsV3(
736 options.target_comps)
737
738 PrintVerifyComponentsResults(result)
739
740
741@Command('generate_hwid_v3',
742 _board_cmd_arg,
743 _hwdb_path_cmd_arg,
744 _device_info_cmd_arg)
745def GenerateHwidV3(options):
746 """Generates the HWID of the DUT.
747
748 The HWID is generated based on the given device info and the probe results
749 retrieved by probing the DUT. If there are conflits of component information
750 between device info and probe result, priority is given to device info.
751 """
752 try:
753 device_info = eval(options.device_info)
754 except Exception, e:
755 raise Error, 'Invalid device_info: %s' % e
756 probe_results = Probe()
757 print 'device_info:'
758 print device_info
759 print 'probe result:'
760 print probe_results.Encode()
761
762 # Do not log device_info for now until we're sure that it does not contain
763 # any sensitive infomation.
764 # TODO(jcliang): Add logging for device_info when appropriate.
765
766 _event_log.Log(
767 'probe',
768 found_components=probe_results.found_probe_value_map,
769 missing_component_classes=probe_results.missing_component_classes,
770 volatiles=probe_results.found_volatile_values,
771 initial_configs=probe_results.initial_configs)
772
773 hwid_object = Gooftool(hwid_version=3, board=options.board,
774 hwdb_path=options.hwdb_path).GenerateHwidV3(
775 device_info, probe_results.Encode())
776
777 final_bom = {}
778 for component_class, component_values in (
779 hwid_object.bom.components.iteritems()):
780 final_bom[component_class] = [v.probed_string for v in component_values]
781 _event_log.Log(
782 'final_bom',
783 final_bom=final_bom)
784 _event_log.Log(
785 'generated_hwid',
786 encoded_string=hwid_object.encoded_string,
787 binary_string=hwid_object.binary_string)
788 print 'Encoded HWID string:', hwid_object.encoded_string
789 print 'Binary HWID string:', hwid_object.binary_string
790
791
792@Command('verify_hwid_v3',
793 _board_cmd_arg,
794 _hwdb_path_cmd_arg,
795 _hwid_cmd_arg)
796def VerifyHwidV3(options):
797 """Verify system HWID properties match probed device properties.
798
799 First probe components, volatile and initial_config parameters for
800 the DUT. Then use the available device data to produce a list of
801 candidate HWIDs. Then verify the HWID from the DUT is present in
802 that list. Then verify that the DUT initial config values match
803 those specified for its HWID. Finally, verify that VPD contains all
804 the necessary fields as specified by the board data, and when
805 possible verify that values are legitimate.
806 """
807 main_fw_file = crosfw.LoadMainFirmware().GetFileName()
808 if options.hwid:
809 hwid_str = options.hwid
810 else:
811 gbb_result = Shell('gbb_utility -g --hwid %s' % main_fw_file).stdout
812 hwid_str = re.findall(r'hardware_id:(.*)', gbb_result)[0].strip()
813 print 'Verifying HWID: %r\n' % hwid_str
814 probe_results = Probe()
815 probed_ro_vpd = ReadRoVpd(main_fw_file)
816 probed_rw_vpd = ReadRwVpd(main_fw_file)
817 print 'probe result:'
818 print probe_results.Encode()
819 _event_log.Log(
820 'probe',
821 found_components=probe_results.found_probe_value_map,
822 missing_component_classes=probe_results.missing_component_classes,
823 volatiles=probe_results.found_volatile_values,
824 initial_configs=probe_results.initial_configs)
825 _event_log.Log('vpd', probed_ro_vpd=FilterDict(probed_ro_vpd),
826 probed_rw_vpd=FilterDict(probed_rw_vpd))
827
828 Gooftool(hwid_version=3, board=options.board,
829 hwdb_path=options.hwdb_path).VerifyHwidV3(
830 hwid_str, probe_results.Encode(), probed_ro_vpd, probed_rw_vpd)
831
832 _event_log.Log('verified_hwid', hwid=hwid_str)
833 print 'Verification SUCCESS!'
834
835
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800836def Main():
837 """Run sub-command specified by the command line args."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800838
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800839 options = ParseCmdline(
840 'Perform Google required factory tests.',
841 CmdArg('-l', '--log', metavar='PATH',
842 help='Write logs to this file.'),
Jon Salza4bea382012-10-29 13:00:34 +0800843 CmdArg('--suppress-event-logs', action='store_true',
844 help='Suppress event logging.'),
Tammo Spalink8fab5312012-05-28 18:33:30 +0800845 verbosity_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800846 SetupLogging(options.verbosity, options.log)
Jon Salza4bea382012-10-29 13:00:34 +0800847 _event_log.suppress = options.suppress_event_logs
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800848 logging.debug('gooftool options: %s', repr(options))
849 try:
850 logging.debug('GOOFTOOL command %r', options.command_name)
851 options.command(options)
852 logging.info('GOOFTOOL command %r SUCCESS', options.command_name)
853 except Error, e:
854 logging.exception(e)
855 sys.exit('GOOFTOOL command %r ERROR: %s' % (options.command_name, e))
856 except Exception, e:
857 logging.exception(e)
858 sys.exit('UNCAUGHT RUNTIME EXCEPTION %s' % e)
859
860
861if __name__ == '__main__':
862 Main()