blob: 79175f26a52b7a93b456f8905a9e218595fe4c61 [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
15
16import logging
17import os
Jon Salz65266432012-07-30 19:02:49 +080018import pipes
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080019import re
20import sys
Hung-Te Lin6bd16472012-06-20 16:26:47 +080021import time
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080022
Tammo Spalink8fab5312012-05-28 18:33:30 +080023from tempfile import gettempdir, NamedTemporaryFile
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
Tammo Spalinka40293e2012-07-04 14:58:56 +080027from cros.factory.common import Error, ParseKeyValueData, SetupLogging, Shell
Tammo Spalink394e4492012-08-01 10:20:30 -070028from cros.factory.common import YamlWrite
Tammo Spalink01e11722012-07-24 10:17:54 -070029from cros.factory.gooftool import crosfw
30from cros.factory.gooftool import report_upload
31from cros.factory.gooftool.bmpblk import unpack_bmpblock
Andy Cheng8ece7382012-08-22 16:25:42 +080032from cros.factory.gooftool.probe import Probe, PROBEABLE_COMPONENT_CLASSES
Tammo Spalink01e11722012-07-24 10:17:54 -070033from cros.factory.gooftool.vpd_data import KNOWN_VPD_FIELD_DATA
Tammo Spalinka40293e2012-07-04 14:58:56 +080034from cros.factory.hacked_argparse import CmdArg, Command, ParseCmdline
35from cros.factory.hacked_argparse import verbosity_cmd_arg
Tammo Spalink01e11722012-07-24 10:17:54 -070036from cros.factory.hwdb import hwid_tool
Jon Salz83591782012-06-26 11:09:58 +080037from cros.factory.event_log import EventLog, EVENT_LOG_DIR
38from cros.factory.event_log import TimedUuid
cychiang7fe09372012-07-04 14:31:23 +080039from cros.factory.test.factory import FACTORY_LOG_PATH
Tammo Spalink86a61c62012-05-25 15:10:35 +080040
Tammo Spalink5c699832012-07-03 17:50:39 +080041
Tammo Spalink86a61c62012-05-25 15:10:35 +080042# Use a global event log, so that only a single log is created when
43# gooftool is called programmatically.
44_event_log = EventLog('gooftool')
45
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080046
47def GetPrimaryDevicePath(partition=None):
48 def IsFixed(dev):
49 sysfs_path = '/sys/block/%s/removable' % dev
50 return (os.path.exists(sysfs_path) and
51 open(sysfs_path).read().strip() == '0')
52 alpha_re = re.compile(r'^/dev/([a-zA-Z]+)[0-9]+$')
53 alnum_re = re.compile(r'^/dev/([a-zA-Z]+[0-9]+)p[0-9]+$')
cychiangde1dee22012-05-22 09:42:09 +080054 matched_alnum = False
55 dev_set = set()
56 for path in Shell('cgpt find -t rootfs').stdout.strip().split():
57 for dev in alpha_re.findall(path):
58 if IsFixed(dev):
59 dev_set.add(dev)
60 matched_alnum = False
61 for dev in alnum_re.findall(path):
62 if IsFixed(dev):
63 dev_set.add(dev)
64 matched_alnum = True
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080065 if len(dev_set) != 1:
66 raise Error('zero or multiple primary devs: %s' % dev_set)
67 dev_path = os.path.join('/dev', dev_set.pop())
68 if partition is None:
69 return dev_path
cychiangde1dee22012-05-22 09:42:09 +080070 fmt_str = '%sp%d' if matched_alnum else '%s%d'
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080071 return fmt_str % (dev_path, partition)
72
73
74def GetReleaseRootPartitionPath():
75 return GetPrimaryDevicePath(5)
76
77
78def GetReleaseKernelPartitionPath():
79 return GetPrimaryDevicePath(4)
80
81
82def FindScript(script_name):
Hung-Te Linb7313ca2012-07-31 15:27:57 +080083 # __file__ is in /usr/local/factory/py/gooftool/gooftool.py
84 # scripts should be in /usr/local/factory/sh/*
85 factory_base = os.path.realpath(os.path.join(
86 os.path.dirname(os.path.realpath(__file__)), '..', '..'))
87 script_path = os.path.join(factory_base, 'sh', script_name)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080088 if not os.path.exists(script_path):
89 raise Error('Needed script %s does not exist.' % script_path)
90 return script_path
91
92
Tammo Spalink86a61c62012-05-25 15:10:35 +080093def ReadVpd(fw_image_file, kind):
94 raw_vpd_data = Shell('vpd -i %s -l -f %s' % (kind, fw_image_file)).stdout
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080095 return ParseKeyValueData('"(.*)"="(.*)"$', raw_vpd_data)
96
97
Tammo Spalink86a61c62012-05-25 15:10:35 +080098def ReadRoVpd(fw_image_file):
99 return ReadVpd(fw_image_file, 'RO_VPD')
100
101
102def ReadRwVpd(fw_image_file):
103 return ReadVpd(fw_image_file, 'RW_VPD')
104
105
Tammo Spalink5c699832012-07-03 17:50:39 +0800106# TODO(tammo): Replace calls to sys.exit with raise Exit, and maybe
107# treat that specially (as a smoot exit, as opposed to the more
108# verbose output for generic Error).
109
110
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800111@Command('write_hwid',
112 CmdArg('hwid', metavar='HWID', help='HWID string'))
113def WriteHwid(options):
114 """Write specified HWID value into the system BB."""
Tammo Spalink95c43732012-07-25 15:57:14 -0700115 logging.info('writing hwid string %r', options.hwid)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800116 main_fw = crosfw.LoadMainFirmware()
117 Shell('gbb_utility --set --hwid="%s" "%s"' %
118 (options.hwid, main_fw.GetFileName()))
119 main_fw.Write(sections=['GBB'])
Tammo Spalink86a61c62012-05-25 15:10:35 +0800120 _event_log.Log('write_hwid', hwid=options.hwid)
Tammo Spalink95c43732012-07-25 15:57:14 -0700121 print 'Wrote HWID: %r' % options.hwid
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800122
123
Tammo Spalink8fab5312012-05-28 18:33:30 +0800124_hwdb_path_cmd_arg = CmdArg(
125 '--hwdb_path', metavar='PATH',
126 default=hwid_tool.DEFAULT_HWID_DATA_PATH,
127 help='Path to the HWID database.')
128
129
Tammo Spalink95c43732012-07-25 15:57:14 -0700130_hwid_status_list_cmd_arg = CmdArg(
131 '--status', nargs='*', default=['supported'],
132 help='allow only HWIDs with these status values')
133
134
135@Command('best_match_hwids',
Tammo Spalink8fab5312012-05-28 18:33:30 +0800136 _hwdb_path_cmd_arg,
137 CmdArg('-b', '--board', metavar='BOARD',
Tammo Spalink95c43732012-07-25 15:57:14 -0700138 help='optional BOARD name, needed only if data is present '
139 'for more than one'),
Tammo Spalink8fab5312012-05-28 18:33:30 +0800140 CmdArg('--bom', metavar='BOM', help='BOM name'),
141 CmdArg('--variant', metavar='VARIANT', help='VARIANT code'),
Tammo Spalink5c699832012-07-03 17:50:39 +0800142 CmdArg('--optimistic', action='store_true',
143 help='do not probe; assume singletons match'),
Tammo Spalink95c43732012-07-25 15:57:14 -0700144 CmdArg('--comps', nargs='*', default=[],
145 help='list of canonical component names'),
146 CmdArg('--missing', nargs='*', default=[],
147 help='list component classes to be assumed missing'),
Tammo Spalink5c699832012-07-03 17:50:39 +0800148 CmdArg('--status', nargs='*', default=['supported'],
Tammo Spalink95c43732012-07-25 15:57:14 -0700149 help='consider only HWIDs within this list of status values'))
150def BestMatchHwids(options):
Tammo Spalink8fab5312012-05-28 18:33:30 +0800151 """Determine a list of possible HWIDs using provided args and probeing.
152
153 VOLATILE can always be determined by probing. To get a unique
154 result, VARIANT must be specified for all cases where the matching
155 BOM has more than one associated variant code, otherwise all HWID
156 variants will be returned. Both VARIANT and BOM information can
Tammo Spalink95c43732012-07-25 15:57:14 -0700157 alternatively be specified using the --stdin_comps argument, which
158 allows specifying a list of canonical names (one per line) on stdin,
159 one per line. Based on what is known from BOM and stdin_comps,
160 determine a list of components to probe for, and use those probe
161 results to resolve a list of matching HWIDs. If no boms,
162 components, or variant codes are specified, then a list of all HWIDs
Andy Cheng8ece7382012-08-22 16:25:42 +0800163 that match probeable components will be returned.
Tammo Spalink8fab5312012-05-28 18:33:30 +0800164
165 Returns (on stdout): A list of HWIDs that match the available probe
166 results and argument contraints, one per line.
Tammo Spalink70b48a52012-08-08 16:54:51 -0700167
168 Example:
169
170 // Three ways to specify a keyboard (assuming it is a variant component)
171 gooftool best_match_hwids --missing keyboard
172 gooftool best_match_hwids --variant A or
173 gooftool best_match_hwids --comps us_kbd
Tammo Spalink8fab5312012-05-28 18:33:30 +0800174 """
Tammo Spalink5c699832012-07-03 17:50:39 +0800175 map(hwid_tool.Validate.Status, options.status)
Tammo Spalink95c43732012-07-25 15:57:14 -0700176 hw_db = hwid_tool.HardwareDb(options.hwdb_path)
Tammo Spalink5c699832012-07-03 17:50:39 +0800177 comp_db = hw_db.comp_db
Tammo Spalink3a7e9022012-06-27 14:08:40 +0800178 device = hw_db.GetDevice(options.board)
Tammo Spalink5c699832012-07-03 17:50:39 +0800179 component_spec = hwid_tool.ComponentSpec.New()
Tammo Spalink8fab5312012-05-28 18:33:30 +0800180 if options.bom:
Tammo Spalink5c699832012-07-03 17:50:39 +0800181 device.BomExists(options.bom)
Tammo Spalink01e11722012-07-24 10:17:54 -0700182 component_spec = hwid_tool.CombineComponentSpecs(
Tammo Spalink5c699832012-07-03 17:50:39 +0800183 component_spec, device.boms[options.bom].primary)
Tammo Spalink8fab5312012-05-28 18:33:30 +0800184 if options.variant:
Tammo Spalink5c699832012-07-03 17:50:39 +0800185 device.VariantExists(options.variant)
186 variant_spec = device.variants[options.variant]
Tammo Spalink01e11722012-07-24 10:17:54 -0700187 if hwid_tool.ComponentSpecsConflict(component_spec, variant_spec):
Tammo Spalink95c43732012-07-25 15:57:14 -0700188 sys.exit('ERROR: multiple specifications for these components:\n%s'
Tammo Spalink394e4492012-08-01 10:20:30 -0700189 % YamlWrite(sorted(
190 hwid_tool.ComponentSpecClasses(component_spec) &
191 hwid_tool.ComponentSpecClasses(variant_spec))))
Tammo Spalink01e11722012-07-24 10:17:54 -0700192 component_spec = hwid_tool.CombineComponentSpecs(
193 component_spec, variant_spec)
Tammo Spalink95c43732012-07-25 15:57:14 -0700194 if options.comps or options.missing:
195 map(comp_db.CompExists, options.comps)
196 map(comp_db.CompClassExists, options.missing)
197 extra_comp_spec = comp_db.CreateComponentSpec(
198 components=options.comps,
199 missing=options.missing)
200 print 'cmdline asserted components:\n%s' % extra_comp_spec.Encode()
201 if hwid_tool.ComponentSpecsConflict(component_spec, extra_comp_spec):
202 sys.exit('ERROR: multiple specifications for these components:\n%s'
Tammo Spalink394e4492012-08-01 10:20:30 -0700203 % YamlWrite(sorted(
204 hwid_tool.ComponentSpecClasses(component_spec) &
205 hwid_tool.ComponentSpecClasses(extra_comp_spec))))
Tammo Spalink95c43732012-07-25 15:57:14 -0700206 component_spec = hwid_tool.CombineComponentSpecs(
207 component_spec, extra_comp_spec)
Tammo Spalink01e11722012-07-24 10:17:54 -0700208 spec_classes = hwid_tool.ComponentSpecClasses(component_spec)
Tammo Spalink95c43732012-07-25 15:57:14 -0700209 missing_classes = set(comp_db.all_comp_classes) - spec_classes
Tammo Spalink5c699832012-07-03 17:50:39 +0800210 if missing_classes and not options.optimistic:
Andy Cheng8ece7382012-08-22 16:25:42 +0800211 non_probeable_missing = missing_classes - PROBEABLE_COMPONENT_CLASSES
212 if non_probeable_missing:
Tammo Spalink95c43732012-07-25 15:57:14 -0700213 sys.exit('FAILURE: these classes are necessary, were not specified '
Tammo Spalink70b48a52012-08-08 16:54:51 -0700214 'as inputs, and cannot be probed for:\n%s'
215 'This problem can often be addressed by specifying all of '
216 'the missing components on the command line (see the command '
Andy Cheng8ece7382012-08-22 16:25:42 +0800217 'help).' % YamlWrite(list(non_probeable_missing)))
Tammo Spalink95c43732012-07-25 15:57:14 -0700218 print 'probing for missing classes:'
219 print YamlWrite(list(missing_classes))
220 probe_results = Probe(target_comp_classes=list(missing_classes),
221 probe_volatile=False, probe_initial_config=False)
222 cooked_components = comp_db.MatchComponentProbeValues(
223 probe_results.found_probe_value_map)
224 if cooked_components.unmatched:
225 sys.exit('ERROR: some probed components are unrecognized:\n%s'
226 % YamlWrite(cooked_components.unmatched))
227 probed_comp_spec = comp_db.CreateComponentSpec(
228 components=cooked_components.matched,
229 missing=probe_results.missing_component_classes)
230 component_spec = hwid_tool.CombineComponentSpecs(
231 component_spec, probed_comp_spec)
232 print YamlWrite({'component data used for matching': {
233 'missing component classes': component_spec.classes_missing,
234 'found components': component_spec.components}})
235 component_data = hwid_tool.ComponentData(
236 extant_components=hwid_tool.ComponentSpecCompClassMap(
237 component_spec).keys(),
238 classes_missing=component_spec.classes_missing)
239 match_tree = device.BuildMatchTree(component_data)
240 if not match_tree:
241 sys.exit('FAILURE: NO matching BOMs found')
242 print 'potential BOMs/VARIANTs:'
243 potential_variants = set()
244 potential_volatiles = set()
245 for bom_name, variant_tree in match_tree.items():
246 print ' BOM: %-8s VARIANTS: %s' % (
247 bom_name, ', '.join(sorted(variant_tree)))
248 for variant_code in variant_tree:
249 potential_variants.add(variant_code)
250 for volatile_code in device.volatiles:
251 status = device.GetHwidStatus(bom_name, variant_code, volatile_code)
252 if status in options.status:
253 potential_volatiles.add(volatile_code)
254 print ''
255 if len(potential_variants) == 0:
256 sys.exit('FAILURE: no matching VARIANTs found')
257 if len(potential_volatiles) == 0:
258 sys.exit('FAILURE: no VOLATILEs found for potential matching BOMs/VARIANTS '
259 '(with specified status)')
Tammo Spalink394e4492012-08-01 10:20:30 -0700260 if (options.optimistic and
261 len(match_tree) == 1 and
262 len(potential_variants) == 1 and
263 len(potential_volatiles) == 1):
264 print ('MATCHING HWID: %s' % device.FmtHwid(match_tree.keys().pop(),
265 potential_variants.pop(),
266 potential_volatiles.pop()))
Tammo Spalink5c699832012-07-03 17:50:39 +0800267 return
Tammo Spalink95c43732012-07-25 15:57:14 -0700268 print ('probing VOLATILEs to resolve potential matches: %s\n' %
269 ', '.join(sorted(potential_volatiles)))
270 vol_probe_results = Probe(
271 target_comp_classes=[],
272 probe_volatile=True,
273 probe_initial_config=False)
274 cooked_volatiles = device.MatchVolatileValues(
275 vol_probe_results.found_volatile_values)
276 match_tree = device.BuildMatchTree(
277 component_data, cooked_volatiles.matched_tags)
278 matched_hwids = device.GetMatchTreeHwids(match_tree)
279 if matched_hwids:
280 for hwid in matched_hwids:
Ricky Liang02f3bd72012-09-21 14:33:01 +0800281 if matched_hwids[hwid] in options.status:
282 print 'MATCHING HWID: %s' % hwid
Tammo Spalink95c43732012-07-25 15:57:14 -0700283 return
284 print 'exact HWID matching failed, but the following BOMs match: %s' % (
285 ', '.join(sorted(match_tree)))
286 if options.optimistic and len(match_tree) == 1:
287 bom_name = set(match_tree).pop()
Tammo Spalink5c699832012-07-03 17:50:39 +0800288 bom = device.boms[bom_name]
Tammo Spalink95c43732012-07-25 15:57:14 -0700289 variant_matches = match_tree[bom_name]
Tammo Spalink5c699832012-07-03 17:50:39 +0800290 if len(variant_matches) == 1:
291 var_code = set(variant_matches).pop()
292 elif len(bom.variants) == 1:
293 var_code = set(bom.variants).pop()
294 else:
Tammo Spalink95c43732012-07-25 15:57:14 -0700295 sys.exit('FAILURE: NO matching HWIDs found; optimistic matching failed '
296 'because there were too many variants to choose from for BOM %r'
297 % bom_name)
298 hwids = [device.FmtHwid(bom_name, var_code, vol_code)
299 for vol_code in device.volatiles
300 if device.GetHwidStatus(bom_name, var_code, vol_code)
301 in options.status]
302 for hwid in hwids:
303 print 'MATCHING HWID: %s' % hwid
Tammo Spalink5c699832012-07-03 17:50:39 +0800304 return
305 else:
Tammo Spalink95c43732012-07-25 15:57:14 -0700306 print ('optimistic matching not attempted because either it was '
307 'not requested, or because the number of BOMs was <> 1\n')
308 sys.exit('FAILURE: NO matching HWIDs found')
Tammo Spalink8fab5312012-05-28 18:33:30 +0800309
310
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800311@Command('probe',
312 CmdArg('--comps', nargs='*',
313 help='List of keys from the component_db registry.'),
314 CmdArg('--no_vol', action='store_true',
315 help='Do not probe volatile data.'),
316 CmdArg('--no_ic', action='store_true',
317 help='Do not probe initial_config data.'))
318def RunProbe(options):
319 """Print yaml-formatted breakdown of probed device properties."""
Tammo Spalink01e11722012-07-24 10:17:54 -0700320 probe_results = Probe(target_comp_classes=options.comps,
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800321 probe_volatile=not options.no_vol,
322 probe_initial_config=not options.no_ic)
Tammo Spalink3a7e9022012-06-27 14:08:40 +0800323 print probe_results.Encode()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800324
325
Tammo Spalink214caf42012-05-28 10:45:00 +0800326@Command('verify_components',
327 _hwdb_path_cmd_arg,
Tammo Spalink5c699832012-07-03 17:50:39 +0800328 CmdArg('target_comps', nargs='*'))
Tammo Spalink214caf42012-05-28 10:45:00 +0800329def VerifyComponents(options):
Andy Cheng8ece7382012-08-22 16:25:42 +0800330 """Verify that probeable components all match entries in the component_db.
Tammo Spalink214caf42012-05-28 10:45:00 +0800331
Tammo Spalink5c699832012-07-03 17:50:39 +0800332 Probe for each component class in the target_comps and verify
Tammo Spalink214caf42012-05-28 10:45:00 +0800333 that a corresponding match exists in the component_db -- make sure
334 that these components are present, that they have been approved, but
335 do not check against any specific BOM/HWID configurations.
336 """
Tammo Spalink5c699832012-07-03 17:50:39 +0800337 comp_db = hwid_tool.HardwareDb(options.hwdb_path).comp_db
338 if not options.target_comps:
339 sys.exit('ERROR: no target component classes specified; possible choices:\n'
Andy Cheng228a8c92012-08-27 10:53:57 +0800340 + '\n '.join(sorted(comp_db.probeable_components)))
Tammo Spalink5c699832012-07-03 17:50:39 +0800341 for comp_class in options.target_comps:
Andy Cheng228a8c92012-08-27 10:53:57 +0800342 if comp_class not in comp_db.probeable_components:
Tammo Spalink5c699832012-07-03 17:50:39 +0800343 sys.exit('ERROR: specified component class %r does not exist'
Tammo Spalink214caf42012-05-28 10:45:00 +0800344 ' in the component DB.' % comp_class)
Tammo Spalink01e11722012-07-24 10:17:54 -0700345 probe_results = Probe(target_comp_classes=options.target_comps,
Tammo Spalink214caf42012-05-28 10:45:00 +0800346 probe_volatile=False, probe_initial_config=False)
Tammo Spalink214caf42012-05-28 10:45:00 +0800347 errors = []
348 matches = []
Tammo Spalink5c699832012-07-03 17:50:39 +0800349 for comp_class in sorted(options.target_comps):
Andy Cheng228a8c92012-08-27 10:53:57 +0800350 probe_val = probe_results.found_probe_value_map.get(comp_class, None)
Tammo Spalink214caf42012-05-28 10:45:00 +0800351 if probe_val is not None:
Tammo Spalink5c699832012-07-03 17:50:39 +0800352 comp_name = comp_db.result_name_map.get(probe_val, None)
Tammo Spalink214caf42012-05-28 10:45:00 +0800353 if comp_name is not None:
354 matches.append(comp_name)
355 else:
356 errors.append('unsupported %r component found with probe result'
357 ' %r (no matching name in the component DB)' %
358 (comp_class, probe_val))
359 else:
360 errors.append('missing %r component' % comp_class)
Andy Cheng228a8c92012-08-27 10:53:57 +0800361 if matches:
362 print 'found probeable components:\n %s' % '\n '.join(matches)
363
Tammo Spalink214caf42012-05-28 10:45:00 +0800364 if errors:
Andy Cheng228a8c92012-08-27 10:53:57 +0800365 print '\nerrors:\n %s' % '\n '.join(errors)
366 sys.exit('\ncomponent verification FAILURE')
Tammo Spalink214caf42012-05-28 10:45:00 +0800367 else:
Andy Cheng228a8c92012-08-27 10:53:57 +0800368 print "\ncomponent verification SUCCESS"
Tammo Spalink214caf42012-05-28 10:45:00 +0800369
370
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800371@Command('verify_hwid',
Tammo Spalink95c43732012-07-25 15:57:14 -0700372 _hwid_status_list_cmd_arg,
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800373 _hwdb_path_cmd_arg)
374def VerifyHwid(options):
375 """Verify system HWID properties match probed device properties.
376
377 First probe components, volatile and initial_config parameters for
378 the DUT. Then use the available device data to produce a list of
379 candidate HWIDs. Then verify the HWID from the DUT is present in
380 that list. Then verify that the DUT initial config values match
381 those specified for its HWID. Finally, verify that VPD contains all
382 the necessary fields as specified by the board data, and when
383 possible verify that values are legitimate.
384 """
Ricky Liangf7857c12012-09-17 13:34:41 +0800385 def VerifyVpd(ro_vpd_keys, rw_vpd_keys):
Tammo Spalink5c699832012-07-03 17:50:39 +0800386 ro_vpd = ReadRoVpd(main_fw_file)
387 for key in ro_vpd_keys:
388 if key not in ro_vpd:
Ricky Liangf7857c12012-09-17 13:34:41 +0800389 sys.exit('Missing required RO VPD field: %s' % key)
Tammo Spalink01e11722012-07-24 10:17:54 -0700390 known_valid_values = KNOWN_VPD_FIELD_DATA.get(key, None)
Tammo Spalink5c699832012-07-03 17:50:39 +0800391 value = ro_vpd[key]
Ricky Liangf7857c12012-09-17 13:34:41 +0800392 if (known_valid_values is not None) and (value not in known_valid_values):
393 sys.exit('Invalid RO VPD entry : key %r, value %r' % (key, value))
Tammo Spalink5c699832012-07-03 17:50:39 +0800394 rw_vpd = ReadRwVpd(main_fw_file)
Ricky Liangf7857c12012-09-17 13:34:41 +0800395 for key in rw_vpd_keys:
396 if key not in rw_vpd:
397 sys.exit('Missing required RW VPD field: %s' % key)
398 known_valid_values = KNOWN_VPD_FIELD_DATA.get(key, None)
399 value = rw_vpd[key]
400 if (known_valid_values is not None) and (value not in known_valid_values):
401 sys.exit('Invalid RW VPD entry : key %r, value %r' % (key, value))
Tammo Spalink5c699832012-07-03 17:50:39 +0800402 _event_log.Log('vpd', ro_vpd=ro_vpd, rw_vpd=rw_vpd)
403 map(hwid_tool.Validate.Status, options.status)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800404 main_fw_file = crosfw.LoadMainFirmware().GetFileName()
405 gbb_result = Shell('gbb_utility -g --hwid %s' % main_fw_file).stdout
Tammo Spalink95c43732012-07-25 15:57:14 -0700406 hwid_str = re.findall(r'hardware_id:(.*)', gbb_result)[0].strip()
407 hwid = hwid_tool.ParseHwid(hwid_str)
Tammo Spalink5c699832012-07-03 17:50:39 +0800408 hw_db = hwid_tool.HardwareDb(options.hwdb_path)
Tammo Spalink95c43732012-07-25 15:57:14 -0700409 print 'Verifying system HWID: %r\n' % hwid.hwid
410 device = hw_db.GetDevice(hwid.board)
411 hwid_status = device.GetHwidStatus(hwid.bom, hwid.variant, hwid.volatile)
412 if hwid_status not in options.status:
Tammo Spalink5c699832012-07-03 17:50:39 +0800413 sys.exit('HWID status must be one of [%s], found %r' %
Hung-Te Lin4f5beb12012-08-20 14:48:06 +0800414 (', '.join(options.status), hwid_status))
Tammo Spalink95c43732012-07-25 15:57:14 -0700415 probe_results = Probe()
416 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."""
Tammo Spalink461ddce2012-05-10 19:28:55 +0800478 script = FindScript('verify_keys.sh')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800479 kernel_device = GetReleaseKernelPartitionPath()
480 main_fw_file = crosfw.LoadMainFirmware().GetFileName()
481 result = Shell('%s %s %s' % (script, kernel_device, main_fw_file))
482 if not result.success:
483 raise Error, '%r failed, stderr: %r' % (script, result.stderr)
484
485
486@Command('set_fw_bitmap_locale')
Tammo Spalink01e11722012-07-24 10:17:54 -0700487def SetFirmwareBitmapLocale(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800488 """Use VPD locale value to set firmware bitmap default language."""
489 image_file = crosfw.LoadMainFirmware().GetFileName()
490 locale = ReadRoVpd(image_file).get('initial_locale', None)
491 if locale is None:
492 raise Error, 'Missing initial_locale VPD.'
493 bitmap_locales = []
494 with NamedTemporaryFile() as f:
495 Shell('gbb_utility -g --bmpfv=%s %s' % (f.name, image_file))
Tammo Spalink01e11722012-07-24 10:17:54 -0700496 bmpblk_data = unpack_bmpblock(f.read())
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800497 bitmap_locales = bmpblk_data.get('locales', bitmap_locales)
498 # Some locale values are just a language code and others are a
499 # hyphen-separated language code and country code pair. We care
500 # only about the language code part.
501 language_code = locale.partition('-')[0]
502 if language_code not in bitmap_locales:
503 raise Error, ('Firmware bitmaps do not contain support for the specified '
504 'initial locale language %r' % language_code)
505 else:
506 locale_index = bitmap_locales.index(language_code)
507 logging.info('Firmware bitmap initial locale set to %d (%s).',
508 locale_index, bitmap_locales[locale_index])
509 Shell('crossystem loc_idx=%d' % locale_index)
510
511
512@Command('verify_system_time')
Tammo Spalink01e11722012-07-24 10:17:54 -0700513def VerifySystemTime(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800514 """Verify system time is later than release filesystem creation time."""
Tammo Spalink461ddce2012-05-10 19:28:55 +0800515 script = FindScript('verify_system_time.sh')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800516 rootfs_device = GetReleaseRootPartitionPath()
517 result = Shell('%s %s' % (script, rootfs_device))
518 if not result.success:
519 raise Error, '%r failed, stderr: %r' % (script, result.stderr)
520
521
522@Command('verify_rootfs')
Tammo Spalink01e11722012-07-24 10:17:54 -0700523def VerifyRootFs(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800524 """Verify rootfs on SSD is valid by checking hash."""
Tammo Spalink461ddce2012-05-10 19:28:55 +0800525 script = FindScript('verify_rootfs.sh')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800526 rootfs_device = GetReleaseRootPartitionPath()
527 result = Shell('%s %s' % (script, rootfs_device))
528 if not result.success:
Jon Salzb52ae702012-09-20 13:57:52 +0800529 raise Error, '%r failed, stdout: %r, stderr: %r' % (
530 script, result.stdout, result.stderr)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800531
532
533@Command('verify_switch_wp')
Tammo Spalink01e11722012-07-24 10:17:54 -0700534def VerifyWpSwitch(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800535 """Verify hardware write protection switch is enabled."""
536 if Shell('crossystem wpsw_cur').stdout.strip() != '1':
Hung-Te Lin6d827542012-07-19 11:50:41 +0800537 raise Error, 'write protection switch is disabled'
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800538
539
540@Command('verify_switch_dev')
Tammo Spalink01e11722012-07-24 10:17:54 -0700541def VerifyDevSwitch(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800542 """Verify developer switch is disabled."""
Hung-Te Lind7d34722012-07-26 16:48:35 +0800543 VBSD_HONOR_VIRT_DEV_SWITCH = 0x400
544 flags = int(Shell('crossystem vdat_flags').stdout.strip(), 0)
545 if (flags & VBSD_HONOR_VIRT_DEV_SWITCH) != 0:
546 # System is using virtual developer switch. That will be handled in
547 # prepare_wipe.sh by setting "crossystem disable_dev_request=1" -- although
548 # we can't verify that until next reboot, because the real values are stored
549 # in TPM.
550 logging.warn('VerifyDevSwitch: No physical switch.')
551 _event_log.Log('switch_dev', type='virtual switch')
552 return
553 if Shell('crossystem devsw_cur').stdout.strip() != '0':
554 raise Error, 'developer mode is not disabled'
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800555
556
557@Command('write_protect')
Tammo Spalink01e11722012-07-24 10:17:54 -0700558def EnableFwWp(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800559 """Enable then verify firmware write protection."""
560
Hung-Te Linb21c6682012-08-01 13:53:57 +0800561 def CalculateLegacyRange(fw_type, length, section_data,
562 section_name):
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800563 ro_size = length / 2
564 ro_a = int(section_data[0] / ro_size)
565 ro_b = int((section_data[0] + section_data[1] - 1) / ro_size)
566 if ro_a != ro_b:
567 raise Error("%s firmware section %s has illegal size" %
Hung-Te Linb21c6682012-08-01 13:53:57 +0800568 (fw_type, section_name))
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800569 ro_offset = ro_a * ro_size
570 return (ro_offset, ro_size)
571
572 def WriteProtect(fw_file_path, fw_type, legacy_section):
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800573 """Calculate protection size, then invoke flashrom.
574
575 Our supported chips only allow write protecting half their total
576 size, so we parition the flash chipset space accordingly.
577 """
578 raw_image = open(fw_file_path, 'rb').read()
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800579 wp_section = 'WP_RO'
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800580 image = crosfw.FirmwareImage(raw_image)
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800581 if image.has_section(wp_section):
582 section_data = image.get_section_area(wp_section)
583 ro_offset = section_data[0]
584 ro_size = section_data[1]
585 elif image.has_section(legacy_section):
586 section_data = image.get_section_area(legacy_section)
587 (ro_offset, ro_size) = CalculateLegacyRange(
Hung-Te Linb21c6682012-08-01 13:53:57 +0800588 fw_type, len(raw_image), section_data, legacy_section)
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800589 else:
590 raise Error('could not find %s firmware section %s or %s' %
591 (fw_type, wp_section, legacy_section))
592
593 logging.debug('write protecting %s [off=%x size=%x]', fw_type,
594 ro_offset, ro_size)
595 crosfw.Flashrom(fw_type).EnableWriteProtection(ro_offset, ro_size)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800596
597 WriteProtect(crosfw.LoadMainFirmware().GetFileName(), 'main', 'RO_SECTION')
Tammo Spalink86a61c62012-05-25 15:10:35 +0800598 _event_log.Log('wp', fw='main')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800599 ec_fw_file = crosfw.LoadEcFirmware().GetFileName()
600 if ec_fw_file is not None:
601 WriteProtect(ec_fw_file, 'ec', 'EC_RO')
Tammo Spalink86a61c62012-05-25 15:10:35 +0800602 _event_log.Log('wp', fw='ec')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800603 else:
604 logging.warning('EC not write protected (seems there is no EC flash).')
605
606
607@Command('clear_gbb_flags')
Tammo Spalink01e11722012-07-24 10:17:54 -0700608def ClearGbbFlags(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800609 """Zero out the GBB flags, in preparation for transition to release state.
610
611 No GBB flags are set in release/shipping state, but they are useful
612 for factory/development. See "gbb_utility --flags" for details.
613 """
Tammo Spalink461ddce2012-05-10 19:28:55 +0800614 script = FindScript('clear_gbb_flags.sh')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800615 result = Shell(script)
616 if not result.success:
617 raise Error, '%r failed, stderr: %r' % (script, result.stderr)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800618 _event_log.Log('clear_gbb_flags')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800619
620
621@Command('prepare_wipe',
622 CmdArg('--fast', action='store_true',
623 help='use non-secure but faster wipe method.'))
624def PrepareWipe(options):
625 """Prepare system for transition to release state in next reboot."""
Tammo Spalink461ddce2012-05-10 19:28:55 +0800626 script = FindScript('prepare_wipe.sh')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800627 tag = 'fast' if options.fast else ''
628 rootfs_device = GetReleaseRootPartitionPath()
629 result = Shell('FACTORY_WIPE_TAGS=%s %s %s' % (tag, script, rootfs_device))
630 if not result.success:
631 raise Error, '%r failed, stderr: %r' % (script, result.stderr)
632
633
634@Command('verify',
Hung-Te Lin6d827542012-07-19 11:50:41 +0800635 CmdArg('--no_write_protect', action='store_true',
636 help='Do not check write protection switch state.'),
Tammo Spalink95c43732012-07-25 15:57:14 -0700637 _hwid_status_list_cmd_arg,
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800638 _hwdb_path_cmd_arg)
639def Verify(options):
640 """Verifies if whole factory process is ready for finalization.
641
642 This routine performs all the necessary checks to make sure the
643 device is ready to be finalized, but does not modify state. These
644 checks include dev switch, firmware write protection switch, hwid,
645 system time, keys, and root file system.
646 """
Hung-Te Lin6d827542012-07-19 11:50:41 +0800647 if not options.no_write_protect:
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800648 VerifyWpSwitch({})
Hung-Te Lin6d827542012-07-19 11:50:41 +0800649 VerifyDevSwitch({})
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800650 VerifyHwid(options)
651 VerifySystemTime({})
652 VerifyKeys({})
653 VerifyRootFs({})
654
655
Tammo Spalink86a61c62012-05-25 15:10:35 +0800656@Command('log_system_details')
Tammo Spalink01e11722012-07-24 10:17:54 -0700657def LogSystemDetails(options): # pylint: disable=W0613
Tammo Spalink86a61c62012-05-25 15:10:35 +0800658 """Write miscellaneous system details to the event log."""
659 raw_cs_data = Shell('crossystem').stdout.strip().splitlines()
660 # The crossytem output contains many lines like:
661 # 'key = value # description'
662 # Use regexps to pull out the key-value pairs and build a dict.
663 cs_data = dict((k, v.strip()) for k, v in
664 map(lambda x: re.findall(r'\A(\S+)\s+=\s+(.*)#.*\Z', x)[0],
665 raw_cs_data))
666 _event_log.Log(
667 'system_details',
668 platform_name=Shell('mosys platform name').stdout.strip(),
669 crossystem=cs_data,
670 modem_status=Shell('modem status').stdout.splitlines(),
671 ec_wp_status=Shell(
672 'flashrom -p internal:bus=lpc --get-size 2>/dev/null && '
673 'flashrom -p internal:bus=lpc --wp-status || '
674 'echo "EC is not available."').stdout,
675 bios_wp_status = Shell(
676 'flashrom -p internal:bus=spi --wp-status').stdout)
677
678
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800679_upload_method_cmd_arg = CmdArg(
680 '--upload_method', metavar='METHOD:PARAM',
681 help=('How to perform the upload. METHOD should be one of '
cychiang3b15bd52012-09-08 13:58:18 +0800682 '{ftp, shopfloor, ftps, cpfe}.'))
Jon Salz65266432012-07-30 19:02:49 +0800683_add_file_cmd_arg = CmdArg(
684 '--add_file', metavar='FILE', action='append',
685 help='Extra file to include in report (must be an absolute path)')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800686
687@Command('upload_report',
Jon Salz65266432012-07-30 19:02:49 +0800688 _upload_method_cmd_arg,
689 _add_file_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800690def UploadReport(options):
691 """Create and a report containing key device details."""
Hung-Te Lin6bd16472012-06-20 16:26:47 +0800692 def NormalizeAsFileName(token):
693 return re.sub(r'\W+', '', token).strip()
Tammo Spalink86a61c62012-05-25 15:10:35 +0800694 ro_vpd = ReadRoVpd(crosfw.LoadMainFirmware().GetFileName())
695 device_sn = ro_vpd.get('serial_number', None)
696 if device_sn is None:
697 logging.warning('RO_VPD missing device serial number')
698 device_sn = 'MISSING_SN_' + TimedUuid()
Hung-Te Lin6bd16472012-06-20 16:26:47 +0800699 target_name = '%s_%s.tbz2' % (time.strftime('%Y%m%dT%H%M%SZ', time.gmtime()),
700 NormalizeAsFileName(device_sn))
Tammo Spalink86a61c62012-05-25 15:10:35 +0800701 target_path = os.path.join(gettempdir(), target_name)
702 # Intentionally ignoring dotfiles in EVENT_LOG_DIR.
703 tar_cmd = 'cd %s ; tar cjf %s *' % (EVENT_LOG_DIR, target_path)
704 tar_cmd += ' --add-file %s' % FACTORY_LOG_PATH
Jon Salz65266432012-07-30 19:02:49 +0800705 if options.add_file:
706 for f in options.add_file:
707 # Require absolute paths since the tar command may change the
708 # directory.
709 if not f.startswith('/'):
710 raise Error('Not an absolute path: %s' % f)
711 if not os.path.exists(f):
712 raise Error('File does not exist: %s' % f)
713 tar_cmd += ' --add-file %s' % pipes.quote(f)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800714 cmd_result = Shell(tar_cmd)
715 if not cmd_result.success:
716 raise Error('unable to tar event logs, cmd %r failed, stderr: %r' %
717 (tar_cmd, cmd_result.stderr))
718 if options.upload_method is None or options.upload_method == 'none':
719 logging.warning('REPORT UPLOAD SKIPPED (report left at %s)', target_path)
720 return
721 method, param = options.upload_method.split(':', 1)
722 if method == 'shopfloor':
723 report_upload.ShopFloorUpload(target_path, param)
724 elif method == 'ftp':
Jay Kim360c1dd2012-06-25 10:58:11 -0700725 report_upload.FtpUpload(target_path, 'ftp:' + param)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800726 elif method == 'ftps':
727 report_upload.CurlUrlUpload(target_path, '--ftp-ssl-reqd ftp:%s' % param)
728 elif method == 'cpfe':
729 report_upload.CpfeUpload(target_path, param)
730 else:
731 raise Error('unknown report upload method %r', method)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800732
733
734@Command('finalize',
Hung-Te Lin6d827542012-07-19 11:50:41 +0800735 CmdArg('--no_write_protect', action='store_true',
736 help='Do not enable firmware write protection.'),
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800737 CmdArg('--fast', action='store_true',
738 help='use non-secure but faster wipe method.'),
739 _hwdb_path_cmd_arg,
Tammo Spalink95c43732012-07-25 15:57:14 -0700740 _hwid_status_list_cmd_arg,
Jon Salz65266432012-07-30 19:02:49 +0800741 _upload_method_cmd_arg,
742 _add_file_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800743def Finalize(options):
744 """Verify system readiness and trigger transition into release state.
745
Hung-Te Lin6d827542012-07-19 11:50:41 +0800746 This routine first verifies system state (see verify command), modifies
747 firmware bitmaps to match locale, and then clears all of the factory-friendly
748 flags from the GBB. If everything is fine, it enables firmware write
749 protection (cannot rollback after this stage), uploads system logs & reports,
750 and sets the necessary boot flags to cause wipe of the factory image on the
751 next boot.
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800752 """
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800753 Verify(options)
754 SetFirmwareBitmapLocale({})
Hung-Te Lin6d827542012-07-19 11:50:41 +0800755 ClearGbbFlags({})
756 if options.no_write_protect:
757 logging.warn('WARNING: Firmware Write Protection is SKIPPED.')
758 _event_log.Log('wp', fw='both', status='skipped')
759 else:
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800760 EnableFwWp({})
Jon Salza0f58e02012-05-29 19:33:39 +0800761 LogSystemDetails(options)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800762 UploadReport(options)
763 PrepareWipe(options)
764
765
766def Main():
767 """Run sub-command specified by the command line args."""
768 options = ParseCmdline(
769 'Perform Google required factory tests.',
770 CmdArg('-l', '--log', metavar='PATH',
771 help='Write logs to this file.'),
Tammo Spalink8fab5312012-05-28 18:33:30 +0800772 verbosity_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800773 SetupLogging(options.verbosity, options.log)
774 logging.debug('gooftool options: %s', repr(options))
775 try:
776 logging.debug('GOOFTOOL command %r', options.command_name)
777 options.command(options)
778 logging.info('GOOFTOOL command %r SUCCESS', options.command_name)
779 except Error, e:
780 logging.exception(e)
781 sys.exit('GOOFTOOL command %r ERROR: %s' % (options.command_name, e))
782 except Exception, e:
783 logging.exception(e)
784 sys.exit('UNCAUGHT RUNTIME EXCEPTION %s' % e)
785
786
787if __name__ == '__main__':
788 Main()