blob: c68203f76b4ceb3ddc98c84c8bf780ab40cd7621 [file] [log] [blame]
Tammo Spalink9a96b8a2012-04-03 11:10:41 +08001#!/usr/bin/python
Tammo Spalink01e11722012-07-24 10:17:54 -07002# pylint: disable=E1101
Tammo Spalink9a96b8a2012-04-03 11:10:41 +08003#
4# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
5# Use of this source code is governed by a BSD-style license that can be
6# found in the LICENSE file.
7
8"""Google Factory Tool.
9
10This tool is indended to be used on factory assembly lines. It
11provides all of the Google required test functionality and must be run
12on each device as part of the assembly process.
13"""
14
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080015import logging
16import os
Jon Salz65266432012-07-30 19:02:49 +080017import pipes
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080018import re
19import sys
Hung-Te Lin6bd16472012-06-20 16:26:47 +080020import time
Ricky Liang7905f272013-03-16 01:57:10 +080021import yaml
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080022
Andy Cheng2582d292012-12-04 17:38:28 +080023from tempfile import gettempdir
Tammo Spalink86a61c62012-05-25 15:10:35 +080024
Tammo Spalinka40293e2012-07-04 14:58:56 +080025import factory_common # pylint: disable=W0611
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080026
Jon Salz0f8a6842012-09-25 11:28:22 +080027from cros.factory.common import Error, SetupLogging, Shell
Tammo Spalink394e4492012-08-01 10:20:30 -070028from cros.factory.common import YamlWrite
Ricky Liang53390232013-03-08 15:37:57 +080029from cros.factory.event_log import EventLog, EVENT_LOG_DIR
30from cros.factory.event_log import TimedUuid
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 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
Ricky Lianga70a1202013-03-15 15:03:17 +080055def GetGooftool(options):
56 if options.hwid_version == 2:
57 hwdb_path = getattr(options, 'hwdb_path', None)
58 component_db = (
59 hwid_tool.HardwareDb(options.hwdb_path).comp_db if hwdb_path else None)
60 return Gooftool(hwid_version=2, component_db=component_db)
61 elif options.hwid_version == 3:
62 board = getattr(options, 'board', None)
63 hwdb_path = getattr(options, 'hwdb_path', None)
64 return Gooftool(hwid_version=3, board=board, hwdb_path=hwdb_path)
65 else:
66 raise Error, 'Invalid HWID version: %r' % options.hwid_version
67
68
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080069@Command('write_hwid',
70 CmdArg('hwid', metavar='HWID', help='HWID string'))
Andy Chengc92e6f92012-11-20 16:55:53 +080071def WriteHWID(options):
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080072 """Write specified HWID value into the system BB."""
Andy Cheng7a76cb82012-11-19 18:08:19 +080073
Tammo Spalink95c43732012-07-25 15:57:14 -070074 logging.info('writing hwid string %r', options.hwid)
Ricky Lianga70a1202013-03-15 15:03:17 +080075 GetGooftool(options).WriteHWID(options.hwid)
Tammo Spalink86a61c62012-05-25 15:10:35 +080076 _event_log.Log('write_hwid', hwid=options.hwid)
Tammo Spalink95c43732012-07-25 15:57:14 -070077 print 'Wrote HWID: %r' % options.hwid
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080078
79
Ricky Liang53390232013-03-08 15:37:57 +080080_board_cmd_arg = CmdArg(
81 '--board', metavar='BOARD',
82 default=None, help='Board name to test.')
83
Tammo Spalink8fab5312012-05-28 18:33:30 +080084_hwdb_path_cmd_arg = CmdArg(
85 '--hwdb_path', metavar='PATH',
86 default=hwid_tool.DEFAULT_HWID_DATA_PATH,
87 help='Path to the HWID database.')
88
Tammo Spalink95c43732012-07-25 15:57:14 -070089_hwid_status_list_cmd_arg = CmdArg(
90 '--status', nargs='*', default=['supported'],
91 help='allow only HWIDs with these status values')
92
Jon Salzce124fb2012-10-02 17:42:03 +080093_probe_results_cmd_arg = CmdArg(
94 '--probe_results', metavar='RESULTS.yaml',
95 help=('Output from "gooftool probe" (used instead of '
96 'probing this system).'))
97
Ricky Liang53390232013-03-08 15:37:57 +080098_device_info_cmd_arg = CmdArg(
99 '--device_info', metavar='DEVICE_INFO', default=None,
100 help='A dict of device info to use instead of fetching from shopfllor '
101 'server.')
102
Jon Salzce124fb2012-10-02 17:42:03 +0800103_hwid_cmd_arg = CmdArg(
104 '--hwid', metavar='HWID',
Ricky Lianga70a1202013-03-15 15:03:17 +0800105 help='HWID to verify (instead of the currently set HWID of this system).')
Jon Salzce124fb2012-10-02 17:42:03 +0800106
Tammo Spalink95c43732012-07-25 15:57:14 -0700107
108@Command('best_match_hwids',
Tammo Spalink8fab5312012-05-28 18:33:30 +0800109 _hwdb_path_cmd_arg,
110 CmdArg('-b', '--board', metavar='BOARD',
Tammo Spalink95c43732012-07-25 15:57:14 -0700111 help='optional BOARD name, needed only if data is present '
112 'for more than one'),
Tammo Spalink8fab5312012-05-28 18:33:30 +0800113 CmdArg('--bom', metavar='BOM', help='BOM name'),
114 CmdArg('--variant', metavar='VARIANT', help='VARIANT code'),
Tammo Spalink5c699832012-07-03 17:50:39 +0800115 CmdArg('--optimistic', action='store_true',
116 help='do not probe; assume singletons match'),
Tammo Spalink95c43732012-07-25 15:57:14 -0700117 CmdArg('--comps', nargs='*', default=[],
118 help='list of canonical component names'),
119 CmdArg('--missing', nargs='*', default=[],
120 help='list component classes to be assumed missing'),
Tammo Spalink5c699832012-07-03 17:50:39 +0800121 CmdArg('--status', nargs='*', default=['supported'],
Tammo Spalink95c43732012-07-25 15:57:14 -0700122 help='consider only HWIDs within this list of status values'))
123def BestMatchHwids(options):
Tammo Spalink8fab5312012-05-28 18:33:30 +0800124 """Determine a list of possible HWIDs using provided args and probeing.
125
126 VOLATILE can always be determined by probing. To get a unique
127 result, VARIANT must be specified for all cases where the matching
128 BOM has more than one associated variant code, otherwise all HWID
129 variants will be returned. Both VARIANT and BOM information can
Tammo Spalink95c43732012-07-25 15:57:14 -0700130 alternatively be specified using the --stdin_comps argument, which
131 allows specifying a list of canonical names (one per line) on stdin,
132 one per line. Based on what is known from BOM and stdin_comps,
133 determine a list of components to probe for, and use those probe
134 results to resolve a list of matching HWIDs. If no boms,
135 components, or variant codes are specified, then a list of all HWIDs
Andy Cheng8ece7382012-08-22 16:25:42 +0800136 that match probeable components will be returned.
Tammo Spalink8fab5312012-05-28 18:33:30 +0800137
138 Returns (on stdout): A list of HWIDs that match the available probe
139 results and argument contraints, one per line.
Tammo Spalink70b48a52012-08-08 16:54:51 -0700140
141 Example:
142
143 // Three ways to specify a keyboard (assuming it is a variant component)
144 gooftool best_match_hwids --missing keyboard
145 gooftool best_match_hwids --variant A or
146 gooftool best_match_hwids --comps us_kbd
Tammo Spalink8fab5312012-05-28 18:33:30 +0800147 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800148
Tammo Spalink5c699832012-07-03 17:50:39 +0800149 map(hwid_tool.Validate.Status, options.status)
Tammo Spalink95c43732012-07-25 15:57:14 -0700150 hw_db = hwid_tool.HardwareDb(options.hwdb_path)
Tammo Spalink5c699832012-07-03 17:50:39 +0800151 comp_db = hw_db.comp_db
Tammo Spalink3a7e9022012-06-27 14:08:40 +0800152 device = hw_db.GetDevice(options.board)
Tammo Spalink5c699832012-07-03 17:50:39 +0800153 component_spec = hwid_tool.ComponentSpec.New()
Tammo Spalink8fab5312012-05-28 18:33:30 +0800154 if options.bom:
Tammo Spalink5c699832012-07-03 17:50:39 +0800155 device.BomExists(options.bom)
Tammo Spalink01e11722012-07-24 10:17:54 -0700156 component_spec = hwid_tool.CombineComponentSpecs(
Tammo Spalink5c699832012-07-03 17:50:39 +0800157 component_spec, device.boms[options.bom].primary)
Tammo Spalink8fab5312012-05-28 18:33:30 +0800158 if options.variant:
Tammo Spalink5c699832012-07-03 17:50:39 +0800159 device.VariantExists(options.variant)
160 variant_spec = device.variants[options.variant]
Tammo Spalink01e11722012-07-24 10:17:54 -0700161 if hwid_tool.ComponentSpecsConflict(component_spec, variant_spec):
Tammo Spalink95c43732012-07-25 15:57:14 -0700162 sys.exit('ERROR: multiple specifications for these components:\n%s'
Tammo Spalink394e4492012-08-01 10:20:30 -0700163 % YamlWrite(sorted(
164 hwid_tool.ComponentSpecClasses(component_spec) &
165 hwid_tool.ComponentSpecClasses(variant_spec))))
Tammo Spalink01e11722012-07-24 10:17:54 -0700166 component_spec = hwid_tool.CombineComponentSpecs(
167 component_spec, variant_spec)
Tammo Spalink95c43732012-07-25 15:57:14 -0700168 if options.comps or options.missing:
169 map(comp_db.CompExists, options.comps)
170 map(comp_db.CompClassExists, options.missing)
171 extra_comp_spec = comp_db.CreateComponentSpec(
172 components=options.comps,
173 missing=options.missing)
174 print 'cmdline asserted components:\n%s' % extra_comp_spec.Encode()
175 if hwid_tool.ComponentSpecsConflict(component_spec, extra_comp_spec):
176 sys.exit('ERROR: multiple specifications for these components:\n%s'
Tammo Spalink394e4492012-08-01 10:20:30 -0700177 % YamlWrite(sorted(
178 hwid_tool.ComponentSpecClasses(component_spec) &
179 hwid_tool.ComponentSpecClasses(extra_comp_spec))))
Tammo Spalink95c43732012-07-25 15:57:14 -0700180 component_spec = hwid_tool.CombineComponentSpecs(
181 component_spec, extra_comp_spec)
Tammo Spalink01e11722012-07-24 10:17:54 -0700182 spec_classes = hwid_tool.ComponentSpecClasses(component_spec)
Tammo Spalink95c43732012-07-25 15:57:14 -0700183 missing_classes = set(comp_db.all_comp_classes) - spec_classes
Tammo Spalink5c699832012-07-03 17:50:39 +0800184 if missing_classes and not options.optimistic:
Andy Cheng8ece7382012-08-22 16:25:42 +0800185 non_probeable_missing = missing_classes - PROBEABLE_COMPONENT_CLASSES
186 if non_probeable_missing:
Tammo Spalink95c43732012-07-25 15:57:14 -0700187 sys.exit('FAILURE: these classes are necessary, were not specified '
Tammo Spalink70b48a52012-08-08 16:54:51 -0700188 'as inputs, and cannot be probed for:\n%s'
189 'This problem can often be addressed by specifying all of '
190 'the missing components on the command line (see the command '
Andy Cheng8ece7382012-08-22 16:25:42 +0800191 'help).' % YamlWrite(list(non_probeable_missing)))
Tammo Spalink95c43732012-07-25 15:57:14 -0700192 print 'probing for missing classes:'
193 print YamlWrite(list(missing_classes))
194 probe_results = Probe(target_comp_classes=list(missing_classes),
195 probe_volatile=False, probe_initial_config=False)
196 cooked_components = comp_db.MatchComponentProbeValues(
197 probe_results.found_probe_value_map)
198 if cooked_components.unmatched:
199 sys.exit('ERROR: some probed components are unrecognized:\n%s'
200 % YamlWrite(cooked_components.unmatched))
201 probed_comp_spec = comp_db.CreateComponentSpec(
202 components=cooked_components.matched,
203 missing=probe_results.missing_component_classes)
204 component_spec = hwid_tool.CombineComponentSpecs(
205 component_spec, probed_comp_spec)
206 print YamlWrite({'component data used for matching': {
207 'missing component classes': component_spec.classes_missing,
208 'found components': component_spec.components}})
209 component_data = hwid_tool.ComponentData(
210 extant_components=hwid_tool.ComponentSpecCompClassMap(
211 component_spec).keys(),
212 classes_missing=component_spec.classes_missing)
213 match_tree = device.BuildMatchTree(component_data)
214 if not match_tree:
215 sys.exit('FAILURE: NO matching BOMs found')
216 print 'potential BOMs/VARIANTs:'
217 potential_variants = set()
218 potential_volatiles = set()
219 for bom_name, variant_tree in match_tree.items():
220 print ' BOM: %-8s VARIANTS: %s' % (
221 bom_name, ', '.join(sorted(variant_tree)))
222 for variant_code in variant_tree:
223 potential_variants.add(variant_code)
224 for volatile_code in device.volatiles:
225 status = device.GetHwidStatus(bom_name, variant_code, volatile_code)
226 if status in options.status:
227 potential_volatiles.add(volatile_code)
228 print ''
229 if len(potential_variants) == 0:
230 sys.exit('FAILURE: no matching VARIANTs found')
231 if len(potential_volatiles) == 0:
232 sys.exit('FAILURE: no VOLATILEs found for potential matching BOMs/VARIANTS '
233 '(with specified status)')
Tammo Spalink394e4492012-08-01 10:20:30 -0700234 if (options.optimistic and
235 len(match_tree) == 1 and
236 len(potential_variants) == 1 and
237 len(potential_volatiles) == 1):
238 print ('MATCHING HWID: %s' % device.FmtHwid(match_tree.keys().pop(),
239 potential_variants.pop(),
240 potential_volatiles.pop()))
Tammo Spalink5c699832012-07-03 17:50:39 +0800241 return
Tammo Spalink95c43732012-07-25 15:57:14 -0700242 print ('probing VOLATILEs to resolve potential matches: %s\n' %
243 ', '.join(sorted(potential_volatiles)))
244 vol_probe_results = Probe(
245 target_comp_classes=[],
246 probe_volatile=True,
247 probe_initial_config=False)
248 cooked_volatiles = device.MatchVolatileValues(
249 vol_probe_results.found_volatile_values)
250 match_tree = device.BuildMatchTree(
251 component_data, cooked_volatiles.matched_tags)
252 matched_hwids = device.GetMatchTreeHwids(match_tree)
253 if matched_hwids:
254 for hwid in matched_hwids:
Ricky Liang02f3bd72012-09-21 14:33:01 +0800255 if matched_hwids[hwid] in options.status:
256 print 'MATCHING HWID: %s' % hwid
Tammo Spalink95c43732012-07-25 15:57:14 -0700257 return
258 print 'exact HWID matching failed, but the following BOMs match: %s' % (
259 ', '.join(sorted(match_tree)))
260 if options.optimistic and len(match_tree) == 1:
261 bom_name = set(match_tree).pop()
Tammo Spalink5c699832012-07-03 17:50:39 +0800262 bom = device.boms[bom_name]
Tammo Spalink95c43732012-07-25 15:57:14 -0700263 variant_matches = match_tree[bom_name]
Tammo Spalink5c699832012-07-03 17:50:39 +0800264 if len(variant_matches) == 1:
265 var_code = set(variant_matches).pop()
266 elif len(bom.variants) == 1:
267 var_code = set(bom.variants).pop()
268 else:
Tammo Spalink95c43732012-07-25 15:57:14 -0700269 sys.exit('FAILURE: NO matching HWIDs found; optimistic matching failed '
270 'because there were too many variants to choose from for BOM %r'
271 % bom_name)
272 hwids = [device.FmtHwid(bom_name, var_code, vol_code)
273 for vol_code in device.volatiles
274 if device.GetHwidStatus(bom_name, var_code, vol_code)
275 in options.status]
276 for hwid in hwids:
277 print 'MATCHING HWID: %s' % hwid
Tammo Spalink5c699832012-07-03 17:50:39 +0800278 return
279 else:
Tammo Spalink95c43732012-07-25 15:57:14 -0700280 print ('optimistic matching not attempted because either it was '
281 'not requested, or because the number of BOMs was <> 1\n')
282 sys.exit('FAILURE: NO matching HWIDs found')
Tammo Spalink8fab5312012-05-28 18:33:30 +0800283
284
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800285@Command('probe',
286 CmdArg('--comps', nargs='*',
287 help='List of keys from the component_db registry.'),
288 CmdArg('--no_vol', action='store_true',
289 help='Do not probe volatile data.'),
290 CmdArg('--no_ic', action='store_true',
Jon Salz0f8a6842012-09-25 11:28:22 +0800291 help='Do not probe initial_config data.'),
292 CmdArg('--include_vpd', action='store_true',
293 help='Include VPD data in volatiles.'))
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800294def RunProbe(options):
295 """Print yaml-formatted breakdown of probed device properties."""
Ricky Lianga70a1202013-03-15 15:03:17 +0800296 print GetGooftool(options).Probe(
297 target_comp_classes=options.comps,
298 probe_volatile=not options.no_vol,
299 probe_initial_config=not options.no_ic,
300 probe_vpd=options.include_vpd).Encode()
Ricky Liang53390232013-03-08 15:37:57 +0800301
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800302
Tammo Spalink214caf42012-05-28 10:45:00 +0800303@Command('verify_components',
304 _hwdb_path_cmd_arg,
Tammo Spalink5c699832012-07-03 17:50:39 +0800305 CmdArg('target_comps', nargs='*'))
Tammo Spalink214caf42012-05-28 10:45:00 +0800306def VerifyComponents(options):
Andy Cheng8ece7382012-08-22 16:25:42 +0800307 """Verify that probeable components all match entries in the component_db.
Tammo Spalink214caf42012-05-28 10:45:00 +0800308
Tammo Spalink5c699832012-07-03 17:50:39 +0800309 Probe for each component class in the target_comps and verify
Tammo Spalink214caf42012-05-28 10:45:00 +0800310 that a corresponding match exists in the component_db -- make sure
311 that these components are present, that they have been approved, but
312 do not check against any specific BOM/HWID configurations.
313 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800314
Andy Chengc531e2f2012-10-15 19:09:17 +0800315 try:
Ricky Lianga70a1202013-03-15 15:03:17 +0800316 result = GetGooftool(options).VerifyComponents(
Andy Chengc531e2f2012-10-15 19:09:17 +0800317 options.target_comps)
318 except ValueError, e:
319 sys.exit(e)
320
Ricky Liang53390232013-03-08 15:37:57 +0800321 PrintVerifyComponentsResults(result)
322
323
324def PrintVerifyComponentsResults(result):
325 """Prints out the results of VerifyComponents method call.
326
327 Groups the results into two groups: 'matches' and 'errors', and prints out
328 their values.
329 """
Andy Chengc531e2f2012-10-15 19:09:17 +0800330 # group by matches and errors
Tammo Spalink214caf42012-05-28 10:45:00 +0800331 matches = []
Andy Chengc531e2f2012-10-15 19:09:17 +0800332 errors = []
333 for result_list in result.values():
334 for component_name, _, error in result_list:
335 if component_name:
336 matches.append(component_name)
Tammo Spalink214caf42012-05-28 10:45:00 +0800337 else:
Andy Chengc531e2f2012-10-15 19:09:17 +0800338 errors.append(error)
339
Andy Cheng228a8c92012-08-27 10:53:57 +0800340 if matches:
341 print 'found probeable components:\n %s' % '\n '.join(matches)
Tammo Spalink214caf42012-05-28 10:45:00 +0800342 if errors:
Andy Cheng228a8c92012-08-27 10:53:57 +0800343 print '\nerrors:\n %s' % '\n '.join(errors)
344 sys.exit('\ncomponent verification FAILURE')
Tammo Spalink214caf42012-05-28 10:45:00 +0800345 else:
Andy Cheng228a8c92012-08-27 10:53:57 +0800346 print "\ncomponent verification SUCCESS"
Tammo Spalink214caf42012-05-28 10:45:00 +0800347
348
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800349@Command('verify_hwid',
Tammo Spalink95c43732012-07-25 15:57:14 -0700350 _hwid_status_list_cmd_arg,
Jon Salz0f8a6842012-09-25 11:28:22 +0800351 _hwdb_path_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800352 _probe_results_cmd_arg,
353 _hwid_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800354def VerifyHwid(options):
355 """Verify system HWID properties match probed device properties.
356
357 First probe components, volatile and initial_config parameters for
358 the DUT. Then use the available device data to produce a list of
359 candidate HWIDs. Then verify the HWID from the DUT is present in
360 that list. Then verify that the DUT initial config values match
361 those specified for its HWID. Finally, verify that VPD contains all
362 the necessary fields as specified by the board data, and when
363 possible verify that values are legitimate.
364 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800365
Ricky Liangf7857c12012-09-17 13:34:41 +0800366 def VerifyVpd(ro_vpd_keys, rw_vpd_keys):
Tammo Spalink5c699832012-07-03 17:50:39 +0800367 for key in ro_vpd_keys:
368 if key not in ro_vpd:
Ricky Liangf7857c12012-09-17 13:34:41 +0800369 sys.exit('Missing required RO VPD field: %s' % key)
Tammo Spalink01e11722012-07-24 10:17:54 -0700370 known_valid_values = KNOWN_VPD_FIELD_DATA.get(key, None)
Tammo Spalink5c699832012-07-03 17:50:39 +0800371 value = ro_vpd[key]
Ricky Liangf7857c12012-09-17 13:34:41 +0800372 if (known_valid_values is not None) and (value not in known_valid_values):
373 sys.exit('Invalid RO VPD entry : key %r, value %r' % (key, value))
Ricky Liangf7857c12012-09-17 13:34:41 +0800374 for key in rw_vpd_keys:
375 if key not in rw_vpd:
376 sys.exit('Missing required RW VPD field: %s' % key)
377 known_valid_values = KNOWN_VPD_FIELD_DATA.get(key, None)
378 value = rw_vpd[key]
379 if (known_valid_values is not None) and (value not in known_valid_values):
380 sys.exit('Invalid RW VPD entry : key %r, value %r' % (key, value))
Jon Salz8baad8b2013-03-11 20:01:45 +0800381 _event_log.Log('vpd', ro_vpd=FilterDict(ro_vpd), rw_vpd=FilterDict(rw_vpd))
Tammo Spalink5c699832012-07-03 17:50:39 +0800382 map(hwid_tool.Validate.Status, options.status)
Jon Salz0f8a6842012-09-25 11:28:22 +0800383
Jon Salz81350812012-10-11 16:13:22 +0800384 if not options.hwid or not options.probe_results:
385 main_fw_file = crosfw.LoadMainFirmware().GetFileName()
Jon Salz0f8a6842012-09-25 11:28:22 +0800386
387 if options.hwid:
388 hwid_str = options.hwid
389 else:
390 gbb_result = Shell('gbb_utility -g --hwid %s' % main_fw_file).stdout
391 hwid_str = re.findall(r'hardware_id:(.*)', gbb_result)[0].strip()
Tammo Spalink95c43732012-07-25 15:57:14 -0700392 hwid = hwid_tool.ParseHwid(hwid_str)
Tammo Spalink5c699832012-07-03 17:50:39 +0800393 hw_db = hwid_tool.HardwareDb(options.hwdb_path)
Jon Salz0f8a6842012-09-25 11:28:22 +0800394 print 'Verifying HWID: %r\n' % hwid.hwid
Tammo Spalink95c43732012-07-25 15:57:14 -0700395 device = hw_db.GetDevice(hwid.board)
396 hwid_status = device.GetHwidStatus(hwid.bom, hwid.variant, hwid.volatile)
397 if hwid_status not in options.status:
Tammo Spalink5c699832012-07-03 17:50:39 +0800398 sys.exit('HWID status must be one of [%s], found %r' %
Hung-Te Lin4f5beb12012-08-20 14:48:06 +0800399 (', '.join(options.status), hwid_status))
Jon Salz0f8a6842012-09-25 11:28:22 +0800400 if options.probe_results:
401 # Pull in probe results (including VPD data) from the given file
402 # rather than probing the current system.
403 probe_results = hwid_tool.ProbeResults.Decode(
404 open(options.probe_results).read())
405 ro_vpd = {}
406 rw_vpd = {}
407 for k, v in probe_results.found_volatile_values.items():
408 match = re.match('^vpd\.(ro|rw)\.(\w+)$', k)
409 if match:
410 del probe_results.found_volatile_values[k]
411 (ro_vpd if match.group(1) == 'ro' else rw_vpd)[match.group(2)] = v
412 else:
413 probe_results = Probe()
414 ro_vpd = ReadRoVpd(main_fw_file)
415 rw_vpd = ReadRwVpd(main_fw_file)
Tammo Spalink95c43732012-07-25 15:57:14 -0700416 cooked_components = hw_db.comp_db.MatchComponentProbeValues(
417 probe_results.found_probe_value_map)
418 cooked_volatiles = device.MatchVolatileValues(
419 probe_results.found_volatile_values)
420 cooked_initial_configs = device.MatchInitialConfigValues(
421 probe_results.initial_configs)
422 component_data = hwid_tool.ComponentData(
423 extant_components=cooked_components.matched,
424 classes_missing=probe_results.missing_component_classes)
425 match_tree = device.BuildMatchTree(
426 component_data, cooked_volatiles.matched_tags)
427 matched_hwids = device.GetMatchTreeHwids(match_tree)
428 print 'HWID status: %s\n' % hwid_status
429 print 'probed system components:'
430 print YamlWrite(cooked_components.__dict__)
431 print 'missing component classes:'
432 print YamlWrite(probe_results.missing_component_classes)
433 print 'probed volatiles:'
434 print YamlWrite(cooked_volatiles.__dict__)
435 print 'probed initial_configs:'
436 print YamlWrite(cooked_initial_configs)
437 print 'hwid match tree:'
438 print YamlWrite(match_tree)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800439 _event_log.Log(
Tammo Spalink5c699832012-07-03 17:50:39 +0800440 'probe',
Tammo Spalink95c43732012-07-25 15:57:14 -0700441 found_components=cooked_components.__dict__,
442 missing_component_classes=probe_results.missing_component_classes,
443 volatiles=cooked_volatiles.__dict__,
444 initial_configs=cooked_initial_configs)
445 if hwid.hwid not in matched_hwids:
Tammo Spalink5c699832012-07-03 17:50:39 +0800446 err_msg = 'HWID verification FAILED.\n'
Tammo Spalink95c43732012-07-25 15:57:14 -0700447 if cooked_components.unmatched:
Tammo Spalink5c699832012-07-03 17:50:39 +0800448 sys.exit(err_msg + 'some components could not be indentified:\n%s' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700449 YamlWrite(cooked_components.unmatched))
450 if not match_tree:
Tammo Spalink5c699832012-07-03 17:50:39 +0800451 sys.exit(err_msg + 'no matching boms were found for components:\n%s' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700452 component_data.Encode())
453 if hwid.bom not in match_tree:
Tammo Spalink5c699832012-07-03 17:50:39 +0800454 sys.exit(err_msg + 'matching boms [%s] do not include target bom %r' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700455 (', '.join(sorted(match_tree)), hwid.bom))
456 err_msg += 'target bom %r matches components' % hwid.bom
457 if hwid.bom not in device.IntersectBomsAndInitialConfigs(
458 cooked_initial_configs):
Tammo Spalink5c699832012-07-03 17:50:39 +0800459 sys.exit(err_msg + ', but failed initial config verification')
Tammo Spalink95c43732012-07-25 15:57:14 -0700460 matched_variants = match_tree.get(hwid.bom, {})
461 if hwid.variant not in matched_variants:
Tammo Spalink5c699832012-07-03 17:50:39 +0800462 sys.exit(err_msg + ', but target variant_code %r did not match' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700463 hwid.variant)
464 matched_volatiles = matched_variants.get(hwid.variant, {})
465 if hwid.volatile not in matched_volatiles:
Tammo Spalink5c699832012-07-03 17:50:39 +0800466 sys.exit(err_msg + ', but target volatile_code %r did not match' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700467 hwid.volatile)
468 found_status = matched_volatiles.get(hwid.volatile, None)
Tammo Spalink5c699832012-07-03 17:50:39 +0800469 sys.exit(err_msg + ', but hwid status %r was unacceptable' % found_status)
Ricky Liangf7857c12012-09-17 13:34:41 +0800470 VerifyVpd(device.vpd_ro_fields, device.vpd_rw_fields)
Tammo Spalink5c699832012-07-03 17:50:39 +0800471 _event_log.Log('verified_hwid', hwid=hwid)
Tammo Spalink95c43732012-07-25 15:57:14 -0700472 print 'Verification SUCCESS!'
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800473
474
475@Command('verify_keys')
Tammo Spalink01e11722012-07-24 10:17:54 -0700476def VerifyKeys(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800477 """Verify keys in firmware and SSD match."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800478
Ricky Lianga70a1202013-03-15 15:03:17 +0800479 return GetGooftool(options).VerifyKeys()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800480
481
482@Command('set_fw_bitmap_locale')
Tammo Spalink01e11722012-07-24 10:17:54 -0700483def SetFirmwareBitmapLocale(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800484 """Use VPD locale value to set firmware bitmap default language."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800485
Ricky Lianga70a1202013-03-15 15:03:17 +0800486 (index, locale) = GetGooftool(options).SetFirmwareBitmapLocale()
Andy Cheng2582d292012-12-04 17:38:28 +0800487 logging.info('Firmware bitmap initial locale set to %d (%s).',
488 index, locale)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800489
490
491@Command('verify_system_time')
Tammo Spalink01e11722012-07-24 10:17:54 -0700492def VerifySystemTime(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800493 """Verify system time is later than release filesystem creation time."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800494
Ricky Lianga70a1202013-03-15 15:03:17 +0800495 return GetGooftool(options).VerifySystemTime()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800496
497
498@Command('verify_rootfs')
Tammo Spalink01e11722012-07-24 10:17:54 -0700499def VerifyRootFs(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800500 """Verify rootfs on SSD is valid by checking hash."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800501
Ricky Lianga70a1202013-03-15 15:03:17 +0800502 return GetGooftool(options).VerifyRootFs()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800503
504
505@Command('verify_switch_wp')
Andy Chengc92e6f92012-11-20 16:55:53 +0800506def VerifyWPSwitch(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800507 """Verify hardware write protection switch is enabled."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800508
Ricky Lianga70a1202013-03-15 15:03:17 +0800509 GetGooftool(options).VerifyWPSwitch()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800510
511
512@Command('verify_switch_dev')
Tammo Spalink01e11722012-07-24 10:17:54 -0700513def VerifyDevSwitch(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800514 """Verify developer switch is disabled."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800515
Ricky Lianga70a1202013-03-15 15:03:17 +0800516 if GetGooftool(options).CheckDevSwitchForDisabling():
Hung-Te Lind7d34722012-07-26 16:48:35 +0800517 logging.warn('VerifyDevSwitch: No physical switch.')
518 _event_log.Log('switch_dev', type='virtual switch')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800519
520
521@Command('write_protect')
Tammo Spalink01e11722012-07-24 10:17:54 -0700522def EnableFwWp(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800523 """Enable then verify firmware write protection."""
524
Hung-Te Linb21c6682012-08-01 13:53:57 +0800525 def CalculateLegacyRange(fw_type, length, section_data,
526 section_name):
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800527 ro_size = length / 2
528 ro_a = int(section_data[0] / ro_size)
529 ro_b = int((section_data[0] + section_data[1] - 1) / ro_size)
530 if ro_a != ro_b:
531 raise Error("%s firmware section %s has illegal size" %
Hung-Te Linb21c6682012-08-01 13:53:57 +0800532 (fw_type, section_name))
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800533 ro_offset = ro_a * ro_size
534 return (ro_offset, ro_size)
535
536 def WriteProtect(fw_file_path, fw_type, legacy_section):
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800537 """Calculate protection size, then invoke flashrom.
538
539 Our supported chips only allow write protecting half their total
540 size, so we parition the flash chipset space accordingly.
541 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800542
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800543 raw_image = open(fw_file_path, 'rb').read()
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800544 wp_section = 'WP_RO'
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800545 image = crosfw.FirmwareImage(raw_image)
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800546 if image.has_section(wp_section):
547 section_data = image.get_section_area(wp_section)
548 ro_offset = section_data[0]
549 ro_size = section_data[1]
550 elif image.has_section(legacy_section):
551 section_data = image.get_section_area(legacy_section)
552 (ro_offset, ro_size) = CalculateLegacyRange(
Hung-Te Linb21c6682012-08-01 13:53:57 +0800553 fw_type, len(raw_image), section_data, legacy_section)
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800554 else:
555 raise Error('could not find %s firmware section %s or %s' %
556 (fw_type, wp_section, legacy_section))
557
558 logging.debug('write protecting %s [off=%x size=%x]', fw_type,
559 ro_offset, ro_size)
560 crosfw.Flashrom(fw_type).EnableWriteProtection(ro_offset, ro_size)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800561
562 WriteProtect(crosfw.LoadMainFirmware().GetFileName(), 'main', 'RO_SECTION')
Tammo Spalink86a61c62012-05-25 15:10:35 +0800563 _event_log.Log('wp', fw='main')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800564 ec_fw_file = crosfw.LoadEcFirmware().GetFileName()
565 if ec_fw_file is not None:
566 WriteProtect(ec_fw_file, 'ec', 'EC_RO')
Tammo Spalink86a61c62012-05-25 15:10:35 +0800567 _event_log.Log('wp', fw='ec')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800568 else:
569 logging.warning('EC not write protected (seems there is no EC flash).')
570
571
572@Command('clear_gbb_flags')
Andy Chengc92e6f92012-11-20 16:55:53 +0800573def ClearGBBFlags(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800574 """Zero out the GBB flags, in preparation for transition to release state.
575
576 No GBB flags are set in release/shipping state, but they are useful
577 for factory/development. See "gbb_utility --flags" for details.
578 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800579
Ricky Lianga70a1202013-03-15 15:03:17 +0800580 GetGooftool(options).ClearGBBFlags()
Tammo Spalink86a61c62012-05-25 15:10:35 +0800581 _event_log.Log('clear_gbb_flags')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800582
583
584@Command('prepare_wipe',
585 CmdArg('--fast', action='store_true',
586 help='use non-secure but faster wipe method.'))
587def PrepareWipe(options):
588 """Prepare system for transition to release state in next reboot."""
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800589
Ricky Lianga70a1202013-03-15 15:03:17 +0800590 GetGooftool(options).PrepareWipe(options.fast)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800591
592@Command('verify',
Hung-Te Lin6d827542012-07-19 11:50:41 +0800593 CmdArg('--no_write_protect', action='store_true',
594 help='Do not check write protection switch state.'),
Tammo Spalink95c43732012-07-25 15:57:14 -0700595 _hwid_status_list_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800596 _hwdb_path_cmd_arg,
Ricky Lianga70a1202013-03-15 15:03:17 +0800597 _board_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800598 _probe_results_cmd_arg,
599 _hwid_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800600def Verify(options):
601 """Verifies if whole factory process is ready for finalization.
602
603 This routine performs all the necessary checks to make sure the
604 device is ready to be finalized, but does not modify state. These
605 checks include dev switch, firmware write protection switch, hwid,
606 system time, keys, and root file system.
607 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800608
Hung-Te Lin6d827542012-07-19 11:50:41 +0800609 if not options.no_write_protect:
Ricky Lianga70a1202013-03-15 15:03:17 +0800610 VerifyWPSwitch(options)
611 VerifyDevSwitch(options)
612 if options.hwid_version == 2:
613 VerifyHwid(options)
614 elif options.hwid_version == 3:
615 VerifyHwidV3(options)
616 else:
617 raise Error, 'Invalid HWID version: %r' % options.hwid_version
618 VerifySystemTime(options)
619 VerifyKeys(options)
620 VerifyRootFs(options)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800621
622
Tammo Spalink86a61c62012-05-25 15:10:35 +0800623@Command('log_system_details')
Tammo Spalink01e11722012-07-24 10:17:54 -0700624def LogSystemDetails(options): # pylint: disable=W0613
Tammo Spalink86a61c62012-05-25 15:10:35 +0800625 """Write miscellaneous system details to the event log."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800626
Ricky Lianga70a1202013-03-15 15:03:17 +0800627 _event_log.Log('system_details', **Gooftool(
628 hwid_version=options.hwid_version).GetSystemDetails())
Tammo Spalink86a61c62012-05-25 15:10:35 +0800629
630
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800631_upload_method_cmd_arg = CmdArg(
632 '--upload_method', metavar='METHOD:PARAM',
633 help=('How to perform the upload. METHOD should be one of '
cychiang3b15bd52012-09-08 13:58:18 +0800634 '{ftp, shopfloor, ftps, cpfe}.'))
Jon Salz65266432012-07-30 19:02:49 +0800635_add_file_cmd_arg = CmdArg(
636 '--add_file', metavar='FILE', action='append',
637 help='Extra file to include in report (must be an absolute path)')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800638
639@Command('upload_report',
Jon Salz65266432012-07-30 19:02:49 +0800640 _upload_method_cmd_arg,
641 _add_file_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800642def UploadReport(options):
643 """Create and a report containing key device details."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800644
Hung-Te Lin6bd16472012-06-20 16:26:47 +0800645 def NormalizeAsFileName(token):
646 return re.sub(r'\W+', '', token).strip()
Tammo Spalink86a61c62012-05-25 15:10:35 +0800647 ro_vpd = ReadRoVpd(crosfw.LoadMainFirmware().GetFileName())
648 device_sn = ro_vpd.get('serial_number', None)
649 if device_sn is None:
650 logging.warning('RO_VPD missing device serial number')
651 device_sn = 'MISSING_SN_' + TimedUuid()
Vic Yang85199e72013-01-28 14:33:11 +0800652 target_name = '%s_%s.tar.xz' % (time.strftime('%Y%m%dT%H%M%SZ',
653 time.gmtime()),
654 NormalizeAsFileName(device_sn))
Tammo Spalink86a61c62012-05-25 15:10:35 +0800655 target_path = os.path.join(gettempdir(), target_name)
656 # Intentionally ignoring dotfiles in EVENT_LOG_DIR.
Vic Yang85199e72013-01-28 14:33:11 +0800657 tar_cmd = 'cd %s ; tar cJf %s *' % (EVENT_LOG_DIR, target_path)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800658 tar_cmd += ' --add-file %s' % FACTORY_LOG_PATH
Jon Salz65266432012-07-30 19:02:49 +0800659 if options.add_file:
660 for f in options.add_file:
661 # Require absolute paths since the tar command may change the
662 # directory.
663 if not f.startswith('/'):
664 raise Error('Not an absolute path: %s' % f)
665 if not os.path.exists(f):
666 raise Error('File does not exist: %s' % f)
667 tar_cmd += ' --add-file %s' % pipes.quote(f)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800668 cmd_result = Shell(tar_cmd)
Jon Salzff88c022012-11-03 12:19:58 +0800669
670 if ((cmd_result.status == 1) and
671 all((x == '' or
672 'file changed as we read it' in x or
673 "Removing leading `/' from member names" in x)
674 for x in cmd_result.stderr.split('\n'))):
675 # That's OK. Make sure it's valid though.
Vic Yang85199e72013-01-28 14:33:11 +0800676 Spawn(['tar', 'tfJ', target_path], check_call=True, log=True,
Jon Salzff88c022012-11-03 12:19:58 +0800677 ignore_stdout=True)
678 elif not cmd_result.success:
Tammo Spalink86a61c62012-05-25 15:10:35 +0800679 raise Error('unable to tar event logs, cmd %r failed, stderr: %r' %
680 (tar_cmd, cmd_result.stderr))
Jon Salzff88c022012-11-03 12:19:58 +0800681
Tammo Spalink86a61c62012-05-25 15:10:35 +0800682 if options.upload_method is None or options.upload_method == 'none':
683 logging.warning('REPORT UPLOAD SKIPPED (report left at %s)', target_path)
684 return
685 method, param = options.upload_method.split(':', 1)
686 if method == 'shopfloor':
687 report_upload.ShopFloorUpload(target_path, param)
688 elif method == 'ftp':
Jay Kim360c1dd2012-06-25 10:58:11 -0700689 report_upload.FtpUpload(target_path, 'ftp:' + param)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800690 elif method == 'ftps':
691 report_upload.CurlUrlUpload(target_path, '--ftp-ssl-reqd ftp:%s' % param)
692 elif method == 'cpfe':
Shawn Nematbakhsh3404a092013-01-28 16:49:09 -0800693 report_upload.CpfeUpload(target_path, pipes.quote(param))
Tammo Spalink86a61c62012-05-25 15:10:35 +0800694 else:
695 raise Error('unknown report upload method %r', method)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800696
697
698@Command('finalize',
Hung-Te Lin6d827542012-07-19 11:50:41 +0800699 CmdArg('--no_write_protect', action='store_true',
700 help='Do not enable firmware write protection.'),
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800701 CmdArg('--fast', action='store_true',
702 help='use non-secure but faster wipe method.'),
703 _hwdb_path_cmd_arg,
Tammo Spalink95c43732012-07-25 15:57:14 -0700704 _hwid_status_list_cmd_arg,
Jon Salz65266432012-07-30 19:02:49 +0800705 _upload_method_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800706 _add_file_cmd_arg,
Ricky Lianga70a1202013-03-15 15:03:17 +0800707 _board_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800708 _probe_results_cmd_arg,
709 _hwid_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800710def Finalize(options):
711 """Verify system readiness and trigger transition into release state.
712
Hung-Te Lin6d827542012-07-19 11:50:41 +0800713 This routine first verifies system state (see verify command), modifies
714 firmware bitmaps to match locale, and then clears all of the factory-friendly
715 flags from the GBB. If everything is fine, it enables firmware write
716 protection (cannot rollback after this stage), uploads system logs & reports,
717 and sets the necessary boot flags to cause wipe of the factory image on the
718 next boot.
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800719 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800720
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800721 Verify(options)
Ricky Lianga70a1202013-03-15 15:03:17 +0800722 SetFirmwareBitmapLocale(options)
723 ClearGBBFlags(options)
Hung-Te Lin6d827542012-07-19 11:50:41 +0800724 if options.no_write_protect:
725 logging.warn('WARNING: Firmware Write Protection is SKIPPED.')
726 _event_log.Log('wp', fw='both', status='skipped')
727 else:
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800728 EnableFwWp({})
Jon Salza0f58e02012-05-29 19:33:39 +0800729 LogSystemDetails(options)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800730 UploadReport(options)
731 PrepareWipe(options)
732
733
Ricky Liang53390232013-03-08 15:37:57 +0800734@Command('verify_components_v3',
735 _board_cmd_arg,
736 _hwdb_path_cmd_arg,
737 CmdArg('target_comps', nargs='*'))
738def VerifyComponentsV3(options):
739 """Verify that probeable components all match entries in the component_db.
740
741 This method uses the HWIDv3 component database to verify components.
742
743 Probe for each component class in the target_comps and verify
744 that a corresponding match exists in the component_db -- make sure
745 that these components are present, that they have been approved, but
746 do not check against any specific BOM/HWID configurations.
747 """
748
Ricky Lianga70a1202013-03-15 15:03:17 +0800749 result = GetGooftool(options).VerifyComponentsV3(options.target_comps)
Ricky Liang53390232013-03-08 15:37:57 +0800750 PrintVerifyComponentsResults(result)
751
752
753@Command('generate_hwid_v3',
754 _board_cmd_arg,
755 _hwdb_path_cmd_arg,
Ricky Liang7905f272013-03-16 01:57:10 +0800756 _probe_results_cmd_arg,
Ricky Liang53390232013-03-08 15:37:57 +0800757 _device_info_cmd_arg)
758def GenerateHwidV3(options):
759 """Generates the HWID of the DUT.
760
761 The HWID is generated based on the given device info and the probe results
762 retrieved by probing the DUT. If there are conflits of component information
763 between device info and probe result, priority is given to device info.
764 """
765 try:
Ricky Liang7905f272013-03-16 01:57:10 +0800766 with open(options.device_info) as f:
767 device_info = yaml.load(f.read())
Ricky Liang53390232013-03-08 15:37:57 +0800768 except Exception, e:
769 raise Error, 'Invalid device_info: %s' % e
Ricky Liang7905f272013-03-16 01:57:10 +0800770 if options.probe_results:
771 with open(options.probe_results) as f:
772 probe_results = hwid_tool.ProbeResults.Decode(f.read())
773 else:
774 probe_results = Probe()
Ricky Liang53390232013-03-08 15:37:57 +0800775 print 'device_info:'
776 print device_info
777 print 'probe result:'
778 print probe_results.Encode()
779
780 # Do not log device_info for now until we're sure that it does not contain
781 # any sensitive infomation.
782 # TODO(jcliang): Add logging for device_info when appropriate.
783
784 _event_log.Log(
785 'probe',
786 found_components=probe_results.found_probe_value_map,
787 missing_component_classes=probe_results.missing_component_classes,
788 volatiles=probe_results.found_volatile_values,
789 initial_configs=probe_results.initial_configs)
790
Ricky Lianga70a1202013-03-15 15:03:17 +0800791 hwid_object = GetGooftool(options).GenerateHwidV3(
792 device_info, probe_results.Encode())
Ricky Liang53390232013-03-08 15:37:57 +0800793
794 final_bom = {}
795 for component_class, component_values in (
796 hwid_object.bom.components.iteritems()):
797 final_bom[component_class] = [v.probed_string for v in component_values]
798 _event_log.Log(
799 'final_bom',
800 final_bom=final_bom)
801 _event_log.Log(
802 'generated_hwid',
803 encoded_string=hwid_object.encoded_string,
804 binary_string=hwid_object.binary_string)
805 print 'Encoded HWID string:', hwid_object.encoded_string
806 print 'Binary HWID string:', hwid_object.binary_string
807
808
809@Command('verify_hwid_v3',
810 _board_cmd_arg,
811 _hwdb_path_cmd_arg,
Ricky Liang7905f272013-03-16 01:57:10 +0800812 _probe_results_cmd_arg,
Ricky Liang53390232013-03-08 15:37:57 +0800813 _hwid_cmd_arg)
814def VerifyHwidV3(options):
815 """Verify system HWID properties match probed device properties.
816
817 First probe components, volatile and initial_config parameters for
818 the DUT. Then use the available device data to produce a list of
819 candidate HWIDs. Then verify the HWID from the DUT is present in
820 that list. Then verify that the DUT initial config values match
821 those specified for its HWID. Finally, verify that VPD contains all
822 the necessary fields as specified by the board data, and when
823 possible verify that values are legitimate.
824 """
Ricky Liang7905f272013-03-16 01:57:10 +0800825 if not options.probe_results:
826 main_fw_file = crosfw.LoadMainFirmware().GetFileName()
Ricky Liang53390232013-03-08 15:37:57 +0800827 if options.hwid:
828 hwid_str = options.hwid
829 else:
830 gbb_result = Shell('gbb_utility -g --hwid %s' % main_fw_file).stdout
831 hwid_str = re.findall(r'hardware_id:(.*)', gbb_result)[0].strip()
832 print 'Verifying HWID: %r\n' % hwid_str
Ricky Liang7905f272013-03-16 01:57:10 +0800833 if options.probe_results:
834 # Pull in probe results (including VPD data) from the given file
835 # rather than probing the current system.
836 with open(options.probe_results) as f:
837 probe_results = hwid_tool.ProbeResults.Decode(f.read())
838 probed_ro_vpd = {}
839 probed_rw_vpd = {}
840 for k, v in probe_results.found_volatile_values.items():
841 # Use items(), not iteritems(), since we will be modifying the dict in the
842 # loop.
843 match = re.match('^vpd\.(ro|rw)\.(\w+)$', k)
844 if match:
845 del probe_results.found_volatile_values[k]
846 (probed_ro_vpd if match.group(1) == 'ro'
847 else probed_rw_vpd)[match.group(2)] = v
848 else:
849 probe_results = Probe()
850 probed_ro_vpd = ReadRoVpd(main_fw_file)
851 probed_rw_vpd = ReadRwVpd(main_fw_file)
Ricky Liang53390232013-03-08 15:37:57 +0800852 print 'probe result:'
853 print probe_results.Encode()
854 _event_log.Log(
855 'probe',
856 found_components=probe_results.found_probe_value_map,
857 missing_component_classes=probe_results.missing_component_classes,
858 volatiles=probe_results.found_volatile_values,
859 initial_configs=probe_results.initial_configs)
860 _event_log.Log('vpd', probed_ro_vpd=FilterDict(probed_ro_vpd),
861 probed_rw_vpd=FilterDict(probed_rw_vpd))
862
Ricky Lianga70a1202013-03-15 15:03:17 +0800863 GetGooftool(options).VerifyHwidV3(
864 hwid_str, probe_results.Encode(), probed_ro_vpd, probed_rw_vpd)
Ricky Liang53390232013-03-08 15:37:57 +0800865
866 _event_log.Log('verified_hwid', hwid=hwid_str)
867 print 'Verification SUCCESS!'
868
869
Ricky Liang7905f272013-03-16 01:57:10 +0800870@Command('decode_hwid_v3',
871 _board_cmd_arg,
872 _hwdb_path_cmd_arg,
873 _hwid_cmd_arg)
874def DecodeHwidV3(options):
875 """Decodes the given v3 HWID and prints out decoded information.
876
877 If no HWID is given, the HWID stored on the device will be loaded and used
878 instead.
879 """
880 decoded_hwid_context = Gooftool(hwid_version=3, board=options.board,
881 hwdb_path=options.hwdb_path).DecodeHwidV3(
882 options.hwid)
883
884 print 'board: %s' % decoded_hwid_context.database.board
885 print 'binary_string: %s' % decoded_hwid_context.binary_string
886 print 'components:'
887 components = decoded_hwid_context.bom.components
888 for comp_cls in sorted(components):
889 print '%s:' % comp_cls
890 for (comp_name, probed_value, _) in sorted(components[comp_cls]):
891 if not probed_value:
892 # Some components (e.g. dram) does have probed value but is not
893 # probeable in the sense that the probed value does not contain enough
894 # information.
895 db_components = decoded_hwid_context.database.components
896 probed_value = db_components[comp_cls][comp_name]['value']
897 print ' - %s: %s' % (comp_name,
898 probed_value if probed_value else 'UNPROBEABLE')
899
900
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800901def Main():
902 """Run sub-command specified by the command line args."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800903
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800904 options = ParseCmdline(
905 'Perform Google required factory tests.',
906 CmdArg('-l', '--log', metavar='PATH',
907 help='Write logs to this file.'),
Jon Salza4bea382012-10-29 13:00:34 +0800908 CmdArg('--suppress-event-logs', action='store_true',
909 help='Suppress event logging.'),
Ricky Lianga70a1202013-03-15 15:03:17 +0800910 CmdArg('-i', '--hwid-version', default=2, choices=[2, 3], type=int,
911 help='Version of HWID to operate on.'),
Tammo Spalink8fab5312012-05-28 18:33:30 +0800912 verbosity_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800913 SetupLogging(options.verbosity, options.log)
Jon Salza4bea382012-10-29 13:00:34 +0800914 _event_log.suppress = options.suppress_event_logs
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800915 logging.debug('gooftool options: %s', repr(options))
916 try:
917 logging.debug('GOOFTOOL command %r', options.command_name)
918 options.command(options)
919 logging.info('GOOFTOOL command %r SUCCESS', options.command_name)
920 except Error, e:
921 logging.exception(e)
922 sys.exit('GOOFTOOL command %r ERROR: %s' % (options.command_name, e))
923 except Exception, e:
924 logging.exception(e)
925 sys.exit('UNCAUGHT RUNTIME EXCEPTION %s' % e)
926
927
928if __name__ == '__main__':
929 Main()