blob: 5717ff9233f93691e909945e13472ff6fbf7b23d [file] [log] [blame]
Tom Wai-Hong Tamc1e0b9a2012-11-01 13:52:39 +08001#!/usr/bin/python -u
barfab@chromium.orgb6d29932012-04-11 09:46:43 +02002# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -07003# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6"""Exposes the FAFTClient interface over XMLRPC.
7
8It launches a XMLRPC server and exposes the interface of FAFTClient object.
9The FAFTClient object aggreates some useful functions of exisintg SAFT
10libraries.
11"""
12
ctchang38ae4922012-09-03 17:01:16 +080013import functools, os, shutil, sys, tempfile
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -070014from optparse import OptionParser
15from SimpleXMLRPCServer import SimpleXMLRPCServer
16
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +080017from saft import cgpt_state, chromeos_interface, flashrom_handler
18from saft import kernel_handler, saft_flashrom_util, tpm_handler
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -070019
20
Tom Wai-Hong Tam0e680af2011-10-26 14:32:55 +080021def allow_multiple_section_input(image_operator):
22 @functools.wraps(image_operator)
23 def wrapper(self, section):
24 if type(section) in (tuple, list):
25 for sec in section:
26 image_operator(self, sec)
27 else:
28 image_operator(self, section)
29 return wrapper
30
31
Vic Yang13d22ec2012-06-18 15:12:47 +080032class LazyFlashromHandlerProxy:
33 _loaded = False
34 _obj = None
35
36 def __init__(self, *args, **kargs):
37 self._args = args
38 self._kargs = kargs
39
40 def _load(self):
41 self._obj = flashrom_handler.FlashromHandler()
42 self._obj.init(*self._args, **self._kargs)
43 self._obj.new_image()
44 self._loaded = True
45
46 def __getattr__(self, name):
47 if not self._loaded:
48 self._load()
49 return getattr(self._obj, name)
50
Tom Wai-Hong Tamc1c4deb2012-07-26 14:28:11 +080051 def reload(self):
52 self._loaded = False
53
Vic Yang13d22ec2012-06-18 15:12:47 +080054
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -070055class FAFTClient(object):
56 """A class of FAFT client which aggregates some useful functions of SAFT.
57
58 This class can be exposed via a XMLRPC server such that its functions can
59 be accessed remotely.
60
61 Attributes:
62 _chromeos_interface: An object to encapsulate OS services functions.
Vic Yang59cac9c2012-05-21 15:28:42 +080063 _bios_handler: An object to automate BIOS flashrom testing.
64 _ec_handler: An object to automate EC flashrom testing.
Tom Wai-Hong Tam23870e02012-08-24 16:15:34 +080065 _ec_image: An object to automate EC image for autest.
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -070066 _kernel_handler: An object to provide kernel related actions.
67 _tpm_handler: An object to control TPM device.
ctchangc7e55ea2012-08-09 16:19:14 +080068 _temp_path: Path of a temp directory.
69 _keys_path: Path of a directory, keys/, in temp directory.
70 _work_path: Path of a directory, work/, in temp directory.
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -070071 """
72
73 def __init__(self):
74 """Initialize the data attributes of this class."""
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -070075 # TODO(waihong): Move the explicit object.init() methods to the
76 # objects' constructors (ChromeOSInterface, FlashromHandler,
77 # KernelHandler, and TpmHandler).
78 self._chromeos_interface = chromeos_interface.ChromeOSInterface(False)
Tom Wai-Hong Tam48958832011-12-30 10:16:57 +080079 # We keep the state of FAFT test in a permanent directory over reboots.
Tom Wai-Hong Tam07278c22012-02-08 16:53:00 +080080 state_dir = '/var/tmp/faft'
81 self._chromeos_interface.init(state_dir, log_file='/tmp/faft_log.txt')
82 os.chdir(state_dir)
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -070083
Vic Yang13d22ec2012-06-18 15:12:47 +080084 self._bios_handler = LazyFlashromHandlerProxy(
85 saft_flashrom_util,
Vic Yang59cac9c2012-05-21 15:28:42 +080086 self._chromeos_interface,
87 None,
88 '/usr/share/vboot/devkeys',
89 'bios')
Vic Yang59cac9c2012-05-21 15:28:42 +080090
Todd Brochf2b1d012012-06-14 12:55:21 -070091 self._ec_handler = None
92 if not os.system("mosys ec info"):
Vic Yang13d22ec2012-06-18 15:12:47 +080093 self._ec_handler = LazyFlashromHandlerProxy(
94 saft_flashrom_util,
Todd Brochf2b1d012012-06-14 12:55:21 -070095 self._chromeos_interface,
Vic Yang13d22ec2012-06-18 15:12:47 +080096 'ec_root_key.vpubk',
Todd Brochf2b1d012012-06-14 12:55:21 -070097 '/usr/share/vboot/devkeys',
98 'ec')
Todd Brochf2b1d012012-06-14 12:55:21 -070099
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700100
101 self._kernel_handler = kernel_handler.KernelHandler()
Tom Wai-Hong Tam07278c22012-02-08 16:53:00 +0800102 # TODO(waihong): The dev_key_path is a new argument. We do that in
103 # order not to break the old image and still be able to run.
104 try:
105 self._kernel_handler.init(self._chromeos_interface,
ctchangd60030f2012-08-29 15:39:56 +0800106 dev_key_path='/usr/share/vboot/devkeys',
107 internal_disk=True)
Tom Wai-Hong Tam07278c22012-02-08 16:53:00 +0800108 except:
109 # Copy the key to the current working directory.
110 shutil.copy('/usr/share/vboot/devkeys/kernel_data_key.vbprivk', '.')
ctchangd60030f2012-08-29 15:39:56 +0800111 self._kernel_handler.init(self._chromeos_interface,
112 internal_disk=True)
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700113
114 self._tpm_handler = tpm_handler.TpmHandler()
115 self._tpm_handler.init(self._chromeos_interface)
116
Tom Wai-Hong Tam48958832011-12-30 10:16:57 +0800117 self._cgpt_state = cgpt_state.CgptState(
Tom Wai-Hong Tamed2231c2012-07-27 14:39:46 +0800118 'SHORT', self._chromeos_interface, self.get_root_dev())
Tom Wai-Hong Tam48958832011-12-30 10:16:57 +0800119
ctchangc7e55ea2012-08-09 16:19:14 +0800120 # Initialize temporary directory path
121 self._temp_path = '/var/tmp/faft/autest'
122 self._keys_path = os.path.join(self._temp_path, 'keys')
123 self._work_path = os.path.join(self._temp_path, 'work')
124
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700125
Tom Wai-Hong Tame8f291a2011-12-08 22:03:53 +0800126 def _dispatch(self, method, params):
127 """This _dispatch method handles string conversion especially.
128
129 Since we turn off allow_dotted_names option. So any string conversion,
130 like str(FAFTClient.method), i.e. FAFTClient.method.__str__, failed
131 via XML RPC call.
132 """
133 is_str = method.endswith('.__str__')
134 if is_str:
135 method = method.rsplit('.', 1)[0]
136 try:
137 func = getattr(self, method)
138 except AttributeError:
139 raise Exception('method "%s" is not supported' % method)
140 else:
141 if is_str:
142 return str(func)
143 else:
144 return func(*params)
145
146
Tom Wai-Hong Tambea57b32011-09-02 18:27:47 +0800147 def is_available(self):
148 """Function for polling the RPC server availability.
149
150 Returns:
151 Always True.
152 """
153 return True
154
155
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700156 def run_shell_command(self, command):
157 """Run shell command.
158
159 Args:
160 command: A shell command to be run.
161 """
162 self._chromeos_interface.log('Requesting run shell command')
163 self._chromeos_interface.run_shell_command(command)
164
165
166 def run_shell_command_get_output(self, command):
167 """Run shell command and get its console output.
168
169 Args:
170 command: A shell command to be run.
171
172 Returns:
173 A list of strings stripped of the newline characters.
174 """
175 self._chromeos_interface.log(
176 'Requesting run shell command and get its console output')
177 return self._chromeos_interface.run_shell_command_get_output(command)
178
179
180 def software_reboot(self):
181 """Request software reboot."""
182 self._chromeos_interface.log('Requesting software reboot')
183 self._chromeos_interface.run_shell_command('reboot')
184
185
Tom Wai-Hong Tam678ab152011-12-14 15:27:24 +0800186 def get_platform_name(self):
187 """Get the platform name of the current system.
188
189 Returns:
190 A string of the platform name.
191 """
192 self._chromeos_interface.log('Requesting get platform name')
Vic Yang2bbb8672012-11-12 12:14:53 +0800193 # 'mosys platform name' sometimes fails. Let's get the verbose output.
194 lines = self._chromeos_interface.run_shell_command_get_output(
195 '(mosys -vvv platform name 2>&1) || echo Failed')
196 if lines[-1].strip() == 'Failed':
197 raise Exception('Failed getting platform name: ' + '\n'.join(lines))
198 return lines[-1]
Tom Wai-Hong Tam678ab152011-12-14 15:27:24 +0800199
200
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700201 def get_crossystem_value(self, key):
202 """Get crossystem value of the requested key.
203
204 Args:
205 key: A crossystem key.
206
207 Returns:
208 A string of the requested crossystem value.
209 """
210 self._chromeos_interface.log('Requesting get crossystem value')
211 return self._chromeos_interface.run_shell_command_get_output(
212 'crossystem %s' % key)[0]
213
214
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800215 def get_root_dev(self):
216 """Get the name of root device without partition number.
217
218 Returns:
219 A string of the root device without partition number.
220 """
221 self._chromeos_interface.log('Requesting get root device')
222 return self._chromeos_interface.get_root_dev()
223
224
225 def get_root_part(self):
226 """Get the name of root device with partition number.
227
228 Returns:
229 A string of the root device with partition number.
230 """
231 self._chromeos_interface.log('Requesting get root part')
232 return self._chromeos_interface.get_root_part()
233
234
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700235 def set_try_fw_b(self):
236 """Set 'Try Frimware B' flag in crossystem."""
237 self._chromeos_interface.log('Requesting restart with firmware B')
238 self._chromeos_interface.cs.fwb_tries = 1
239
240
Tom Wai-Hong Tam76c75072011-10-25 18:00:12 +0800241 def request_recovery_boot(self):
242 """Request running in recovery mode on the restart."""
243 self._chromeos_interface.log('Requesting restart in recovery mode')
244 self._chromeos_interface.cs.request_recovery()
245
246
Tom Wai-Hong Tam0a7b2be2012-10-15 16:44:12 +0800247 def get_dev_boot_usb(self):
248 """Get dev_boot_usb value which controls developer mode boot from USB.
249
250 Returns:
251 True if enable, False if disable.
252 """
253 self._chromeos_interface.log('Getting dev_boot_usb')
254 return self._chromeos_interface.cs.dev_boot_usb == '1'
255
256
257 def set_dev_boot_usb(self, value):
258 """Set dev_boot_usb value which controls developer mode boot from USB.
259
260 Args:
261 value: True to enable, False to disable.
262 """
263 self._chromeos_interface.log('Setting dev_boot_usb to %s' % str(value))
264 self._chromeos_interface.cs.dev_boot_usb = 1 if value else 0
265
266
Tom Wai-Hong Tam8c9eed62011-12-28 15:05:05 +0800267 def get_gbb_flags(self):
268 """Get the GBB flags.
269
270 Returns:
271 An integer of the GBB flags.
272 """
273 self._chromeos_interface.log('Getting GBB flags')
Vic Yang59cac9c2012-05-21 15:28:42 +0800274 return self._bios_handler.get_gbb_flags()
Tom Wai-Hong Tam8c9eed62011-12-28 15:05:05 +0800275
276
Tom Wai-Hong Tam81f70002011-12-13 12:29:46 +0800277 def get_firmware_flags(self, section):
278 """Get the preamble flags of a firmware section.
279
280 Args:
281 section: A firmware section, either 'a' or 'b'.
282
283 Returns:
284 An integer of the preamble flags.
285 """
286 self._chromeos_interface.log('Getting preamble flags of firmware %s' %
287 section)
Vic Yang59cac9c2012-05-21 15:28:42 +0800288 return self._bios_handler.get_section_flags(section)
289
290
Vic Yang91b73cf2012-07-31 17:18:11 +0800291 def set_firmware_flags(self, section, flags):
292 """Set the preamble flags of a firmware section.
293
294 Args:
295 section: A firmware section, either 'a' or 'b'.
296 flags: An integer of preamble flags.
297 """
298 self._chromeos_interface.log(
299 'Setting preamble flags of firmware %s to %s' % (section, flags))
300 version = self.get_firmware_version(section)
301 self._bios_handler.set_section_version(section, version, flags,
302 write_through=True)
303
304
Tom Wai-Hong Tam4e10b9f2012-09-06 16:23:02 +0800305 def get_firmware_sha(self, section):
306 """Get SHA1 hash of BIOS RW firmware section.
307
308 Args:
309 section: A firmware section, either 'a' or 'b'.
310 flags: An integer of preamble flags.
311 """
312 return self._bios_handler.get_section_sha(section)
313
314
ctchang38ae4922012-09-03 17:01:16 +0800315 def get_firmware_sig_sha(self, section):
316 """Get SHA1 hash of firmware vblock in section."""
317 return self._bios_handler.get_section_sig_sha(section)
318
319
Vic Yang91b73cf2012-07-31 17:18:11 +0800320 def get_EC_firmware_sha(self):
Tom Wai-Hong Tam4e10b9f2012-09-06 16:23:02 +0800321 """Get SHA1 hash of EC RW firmware section."""
Vic Yang91b73cf2012-07-31 17:18:11 +0800322 return self._ec_handler.get_section_sha('rw')
323
324
Tom Wai-Hong Tamc1c4deb2012-07-26 14:28:11 +0800325 def reload_firmware(self):
326 """Reload the firmware image that may be changed."""
327 self._bios_handler.reload()
328
329
Vic Yang59cac9c2012-05-21 15:28:42 +0800330 @allow_multiple_section_input
331 def corrupt_EC(self, section):
332 """Corrupt the requested EC section signature.
333
334 Args:
335 section: A EC section, either 'a' or 'b'.
336 """
337 self._chromeos_interface.log('Corrupting EC signature %s' %
338 section)
Vic Yang37a55462012-06-29 14:00:28 +0800339 self._ec_handler.corrupt_firmware(section, corrupt_all=True)
Vic Yang59cac9c2012-05-21 15:28:42 +0800340
341
342 @allow_multiple_section_input
343 def corrupt_EC_body(self, section):
344 """Corrupt the requested EC section body.
345
346 Args:
347 section: An EC section, either 'a' or 'b'.
348 """
349 self._chromeos_interface.log('Corrupting EC body %s' %
350 section)
Vic Yang37a55462012-06-29 14:00:28 +0800351 self._ec_handler.corrupt_firmware_body(section, corrupt_all=True)
Vic Yang59cac9c2012-05-21 15:28:42 +0800352
353
354 @allow_multiple_section_input
355 def restore_EC(self, section):
356 """Restore the previously corrupted EC section signature.
357
358 Args:
359 section: An EC section, either 'a' or 'b'.
360 """
361 self._chromeos_interface.log('Restoring EC signature %s' %
362 section)
Vic Yang37a55462012-06-29 14:00:28 +0800363 self._ec_handler.restore_firmware(section, restore_all=True)
Vic Yang59cac9c2012-05-21 15:28:42 +0800364
365
366 @allow_multiple_section_input
367 def restore_EC_body(self, section):
368 """Restore the previously corrupted EC section body.
369
370 Args:
371 section: An EC section, either 'a' or 'b'.
372 """
373 self._chromeos_interface.log('Restoring EC body %s' %
374 section)
Vic Yang37a55462012-06-29 14:00:28 +0800375 self._ec_handler.restore_firmware_body(section, restore_all=True)
Tom Wai-Hong Tam81f70002011-12-13 12:29:46 +0800376
377
Tom Wai-Hong Tam0e680af2011-10-26 14:32:55 +0800378 @allow_multiple_section_input
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700379 def corrupt_firmware(self, section):
Tom Wai-Hong Tam9aea8212011-12-12 15:08:45 +0800380 """Corrupt the requested firmware section signature.
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700381
382 Args:
383 section: A firmware section, either 'a' or 'b'.
384 """
Tom Wai-Hong Tam9aea8212011-12-12 15:08:45 +0800385 self._chromeos_interface.log('Corrupting firmware signature %s' %
386 section)
Vic Yang59cac9c2012-05-21 15:28:42 +0800387 self._bios_handler.corrupt_firmware(section)
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700388
389
Tom Wai-Hong Tam0e680af2011-10-26 14:32:55 +0800390 @allow_multiple_section_input
Tom Wai-Hong Tam81f70002011-12-13 12:29:46 +0800391 def corrupt_firmware_body(self, section):
392 """Corrupt the requested firmware section body.
393
394 Args:
395 section: A firmware section, either 'a' or 'b'.
396 """
397 self._chromeos_interface.log('Corrupting firmware body %s' %
398 section)
Vic Yang59cac9c2012-05-21 15:28:42 +0800399 self._bios_handler.corrupt_firmware_body(section)
Tom Wai-Hong Tam81f70002011-12-13 12:29:46 +0800400
401
402 @allow_multiple_section_input
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700403 def restore_firmware(self, section):
Tom Wai-Hong Tam9aea8212011-12-12 15:08:45 +0800404 """Restore the previously corrupted firmware section signature.
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700405
406 Args:
407 section: A firmware section, either 'a' or 'b'.
408 """
Tom Wai-Hong Tam9aea8212011-12-12 15:08:45 +0800409 self._chromeos_interface.log('Restoring firmware signature %s' %
410 section)
Vic Yang59cac9c2012-05-21 15:28:42 +0800411 self._bios_handler.restore_firmware(section)
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700412
413
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800414 @allow_multiple_section_input
Tom Wai-Hong Tam81f70002011-12-13 12:29:46 +0800415 def restore_firmware_body(self, section):
416 """Restore the previously corrupted firmware section body.
417
418 Args:
419 section: A firmware section, either 'a' or 'b'.
420 """
421 self._chromeos_interface.log('Restoring firmware body %s' %
422 section)
Vic Yang59cac9c2012-05-21 15:28:42 +0800423 self._bios_handler.restore_firmware_body(section)
Tom Wai-Hong Tam81f70002011-12-13 12:29:46 +0800424
425
Vic Yang91b73cf2012-07-31 17:18:11 +0800426 def get_firmware_version(self, section):
427 """Retrieve firmware version of a section."""
428 return self._bios_handler.get_section_version(section)
429
430
Chun-ting Changa4f65532012-10-17 16:57:28 +0800431 def get_tpm_firmware_version(self):
432 """Retrieve tpm firmware body version."""
433 return self._tpm_handler.get_fw_version()
434
435
Tom Wai-Hong Tam46d03b12012-02-08 12:02:17 +0800436 def _modify_firmware_version(self, section, delta):
437 """Modify firmware version for the requested section, by adding delta.
438
439 The passed in delta, a positive or a negative number, is added to the
440 original firmware version.
441 """
Vic Yang91b73cf2012-07-31 17:18:11 +0800442 original_version = self.get_firmware_version(section)
Tom Wai-Hong Tam46d03b12012-02-08 12:02:17 +0800443 new_version = original_version + delta
Vic Yang59cac9c2012-05-21 15:28:42 +0800444 flags = self._bios_handler.get_section_flags(section)
Tom Wai-Hong Tam46d03b12012-02-08 12:02:17 +0800445 self._chromeos_interface.log(
446 'Setting firmware section %s version from %d to %d' % (
447 section, original_version, new_version))
Vic Yang59cac9c2012-05-21 15:28:42 +0800448 self._bios_handler.set_section_version(section, new_version, flags,
449 write_through=True)
Tom Wai-Hong Tam46d03b12012-02-08 12:02:17 +0800450
451 @allow_multiple_section_input
452 def move_firmware_backward(self, section):
453 """Decrement firmware version for the requested section."""
454 self._modify_firmware_version(section, -1)
455
456
457 @allow_multiple_section_input
458 def move_firmware_forward(self, section):
459 """Increase firmware version for the requested section."""
460 self._modify_firmware_version(section, 1)
461
Chun-ting Changa4f65532012-10-17 16:57:28 +0800462 def get_firmware_datakey_version(self, section):
ctchangc7e55ea2012-08-09 16:19:14 +0800463 """Return firmware data key version."""
464 return self._bios_handler.get_section_datakey_version(section)
465
Chun-ting Changa4f65532012-10-17 16:57:28 +0800466 def get_tpm_firmware_datakey_version(self):
467 """Retrieve tpm firmware data key version."""
468 return self._tpm_handler.get_fw_body_version()
469
ctchangc7e55ea2012-08-09 16:19:14 +0800470 def retrieve_kernel_subkey_version(self,section):
471 """Return kernel subkey version."""
472 return self._bios_handler.get_section_kernel_subkey_version(section)
Tom Wai-Hong Tam46d03b12012-02-08 12:02:17 +0800473
Tom Wai-Hong Tam81f70002011-12-13 12:29:46 +0800474 @allow_multiple_section_input
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800475 def corrupt_kernel(self, section):
476 """Corrupt the requested kernel section.
477
478 Args:
479 section: A kernel section, either 'a' or 'b'.
480 """
481 self._chromeos_interface.log('Corrupting kernel %s' % section)
482 self._kernel_handler.corrupt_kernel(section)
483
484
485 @allow_multiple_section_input
486 def restore_kernel(self, section):
487 """Restore the requested kernel section (previously corrupted).
488
489 Args:
490 section: A kernel section, either 'a' or 'b'.
491 """
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800492 self._kernel_handler.restore_kernel(section)
493
494
Tom Wai-Hong Tam07278c22012-02-08 16:53:00 +0800495 def _modify_kernel_version(self, section, delta):
496 """Modify kernel version for the requested section, by adding delta.
497
498 The passed in delta, a positive or a negative number, is added to the
499 original kernel version.
500 """
501 original_version = self._kernel_handler.get_version(section)
502 new_version = original_version + delta
503 self._chromeos_interface.log(
504 'Setting kernel section %s version from %d to %d' % (
505 section, original_version, new_version))
506 self._kernel_handler.set_version(section, new_version)
507
508
509 @allow_multiple_section_input
510 def move_kernel_backward(self, section):
511 """Decrement kernel version for the requested section."""
512 self._modify_kernel_version(section, -1)
513
514
515 @allow_multiple_section_input
516 def move_kernel_forward(self, section):
517 """Increase kernel version for the requested section."""
518 self._modify_kernel_version(section, 1)
519
ctchangcc88d112012-08-23 17:56:15 +0800520
521 def retrieve_kernel_version(self, section):
522 """Return kernel version."""
523 return self._kernel_handler.get_version(section)
524
525
526 def retrieve_kernel_datakey_version(self, section):
527 """Return kernel datakey version."""
528 return self._kernel_handler.get_datakey_version(section)
529
530
Tom Wai-Hong Tam622d0ba2012-08-15 16:29:05 +0800531 def diff_kernel_a_b(self):
532 """Compare kernel A with B.
533
534 Returns:
535 True: if kernel A is different with B.
536 False: if kernel A is the same as B.
537 """
538 rootdev = self._chromeos_interface.get_root_dev()
539 kernel_a = self._chromeos_interface.join_part(rootdev, '3')
540 kernel_b = self._chromeos_interface.join_part(rootdev, '5')
541
542 # The signature (some kind of hash) for the kernel body is stored in
543 # the beginning. So compare the first 64KB (including header, preamble,
544 # and signature) should be enough to check them identical.
545 header_a = self._chromeos_interface.read_partition(kernel_a, 0x10000)
546 header_b = self._chromeos_interface.read_partition(kernel_b, 0x10000)
547
548 return header_a != header_b
Tom Wai-Hong Tam07278c22012-02-08 16:53:00 +0800549
Tom Wai-Hong Tam23870e02012-08-24 16:15:34 +0800550
Tom Wai-Hong Tam0a7b2be2012-10-15 16:44:12 +0800551 def is_removable_device_boot(self):
552 """Check the current boot device is removable.
553
554 Returns:
555 True: if a removable device boots.
556 False: if a non-removable device boots.
557 """
558 root_part = self._chromeos_interface.get_root_part()
559 return self._chromeos_interface.is_removable_device(root_part)
560
561
Tom Wai-Hong Tam23870e02012-08-24 16:15:34 +0800562 def setup_EC_image(self, ec_path):
563 """Setup the new EC image for later update.
564
565 Args:
566 ec_path: The path of the EC image to be updated.
567 """
568 self._ec_image = flashrom_handler.FlashromHandler()
569 self._ec_image.init(saft_flashrom_util,
570 self._chromeos_interface,
571 'ec_root_key.vpubk',
572 '/usr/share/vboot/devkeys',
573 'ec')
574 self._ec_image.new_image(ec_path)
575
576
577 def get_EC_image_sha(self):
578 """Get SHA1 hash of RW firmware section of the EC autest image."""
579 return self._ec_image.get_section_sha('rw')
580
581
582 def update_EC_from_image(self, section, flags):
583 """Update EC via software sync design.
584
585 It copys the RW section from the EC image, which is loaded by calling
586 setup_EC_image(), to the EC area of the specified RW section on the
587 current AP firmware.
588
589 Args:
590 section: A firmware section on current BIOS, either 'a' or 'b'.
591 flags: An integer of preamble flags.
592 """
593 blob = self._ec_image.get_section_body('rw')
594 self._bios_handler.set_section_ecbin(section, blob,
595 write_through=True)
596 self.set_firmware_flags(section, flags)
597
598
Tom Wai-Hong Tamb63bc742012-08-30 20:41:30 +0800599 def dump_firmware(self, bios_path):
600 """Dump the current BIOS firmware to a file, specified by bios_path.
601
602 Args:
603 bios_path: The path of the BIOS image to be written.
604 """
605 self._bios_handler.dump_whole(bios_path)
606
607
ctchang38ae4922012-09-03 17:01:16 +0800608 def dump_firmware_rw(self, dir_path):
609 """Dump the current BIOS firmware RW to dir_path.
610
611 VBOOTA, VBOOTB, FVMAIN, FVMAINB need to be dumped.
612
613 Args:
614 dir_path: The path of directory which contains files to be written.
615 """
616 if not os.path.isdir(dir_path):
617 raise Exception("%s doesn't exist" % dir_path)
618
619 VBOOTA_blob = self._bios_handler.get_section_sig('a')
620 VBOOTB_blob = self._bios_handler.get_section_sig('b')
621 FVMAIN_blob = self._bios_handler.get_section_body('a')
622 FVMAINB_blob = self._bios_handler.get_section_body('b')
623
624 open(os.path.join(dir_path, 'VBOOTA'), 'w').write(VBOOTA_blob)
625 open(os.path.join(dir_path, 'VBOOTB'), 'w').write(VBOOTB_blob)
626 open(os.path.join(dir_path, 'FVMAIN'), 'w').write(FVMAIN_blob)
627 open(os.path.join(dir_path, 'FVMAINB'), 'w').write(FVMAINB_blob)
628
629
Tom Wai-Hong Tamb63bc742012-08-30 20:41:30 +0800630 def write_firmware(self, bios_path):
631 """Write the firmware from bios_path to the current system.
632
633 Args:
634 bios_path: The path of the source BIOS image.
635 """
636 self._bios_handler.new_image(bios_path)
637 self._bios_handler.write_whole()
638
639
ctchang38ae4922012-09-03 17:01:16 +0800640 def write_firmware_rw(self, dir_path):
641 """Write the firmware RW from dir_path to the current system.
642
643 VBOOTA, VBOOTB, FVMAIN, FVMAINB need to be written.
644
645 Args:
646 dir_path: The path of directory which contains the source files.
647 """
648 if not os.path.exists(os.path.join(dir_path, 'VBOOTA')) or \
649 not os.path.exists(os.path.join(dir_path, 'VBOOTB')) or \
650 not os.path.exists(os.path.join(dir_path, 'FVMAIN')) or \
651 not os.path.exists(os.path.join(dir_path, 'FVMAINB')):
652 raise Exception("Source firmware file(s) doesn't exist.")
653
654 VBOOTA_blob = open(os.path.join(dir_path, 'VBOOTA'), 'rb').read()
655 VBOOTB_blob = open(os.path.join(dir_path, 'VBOOTB'), 'rb').read()
656 FVMAIN_blob = open(os.path.join(dir_path, 'FVMAIN'), 'rb').read()
657 FVMAINB_blob = open(os.path.join(dir_path, 'FVMAINB'), 'rb').read()
658
659 self._bios_handler.set_section_sig('a', VBOOTA_blob,
660 write_through=True)
661 self._bios_handler.set_section_sig('b', VBOOTB_blob,
662 write_through=True)
663 self._bios_handler.set_section_body('a', FVMAIN_blob,
664 write_through=True)
665 self._bios_handler.set_section_body('b', FVMAINB_blob,
666 write_through=True)
667
668
Tom Wai-Hong Tam23870e02012-08-24 16:15:34 +0800669 def dump_EC_firmware(self, ec_path):
670 """Dump the current EC firmware to a file, specified by ec_path.
671
672 Args:
673 ec_path: The path of the EC image to be written.
674 """
675 self._ec_handler.dump_whole(ec_path)
676
677
Tom Wai-Hong Tam44204b32012-11-20 13:55:40 +0800678 def set_EC_write_protect(self, enable):
679 """Enable write protect of the EC flash chip.
680
681 Args:
682 enable: True if activating EC write protect. Otherwise, False.
683 """
684 self._chromeos_interface.log('Requesting set EC write protect to %s' %
685 ('enable' if enable else 'disable'))
686 if enable:
687 self._ec_handler.enable_write_protect()
688 else:
689 self._ec_handler.disable_write_protect()
690
691
Tom Wai-Hong Tam48958832011-12-30 10:16:57 +0800692 def run_cgpt_test_loop(self):
693 """Run the CgptState test loop. The tst logic is handled in the client.
694
695 Returns:
696 0: there are more cgpt tests to execute.
697 1: no more CgptState test, finished.
698 """
699 return self._cgpt_state.test_loop()
700
701
702 def set_cgpt_test_step(self, step):
703 """Set the CgptState test step.
704
705 Args:
706 step: A test step number.
707 """
708 self._cgpt_state.set_step(step)
709
710
711 def get_cgpt_test_step(self):
712 """Get the CgptState test step.
713
714 Returns:
715 A test step number.
716 """
717 return self._cgpt_state.get_step()
718
719
Chun-ting Changf91ee0f2012-09-17 18:31:54 +0800720 def setup_firmwareupdate_temp_dir(self, shellball=None):
ctchangc7e55ea2012-08-09 16:19:14 +0800721 """Setup temporary directory.
722
Chun-ting Changf91ee0f2012-09-17 18:31:54 +0800723 Devkeys are copied to _key_path. Then, shellball (default:
724 /usr/sbin/chromeos-firmwareupdate) is extracted to _work_path.
725
726 Args:
727 shellball: Path of shellball.
ctchangc7e55ea2012-08-09 16:19:14 +0800728 """
ctchang6b700df2012-08-20 13:48:07 +0800729
730 self.cleanup_firmwareupdate_temp_dir()
731
ctchangc7e55ea2012-08-09 16:19:14 +0800732 os.mkdir(self._temp_path)
733 os.chdir(self._temp_path)
734
735 os.mkdir(self._work_path)
736 shutil.copytree('/usr/share/vboot/devkeys/', self._keys_path)
Chun-ting Changf91ee0f2012-09-17 18:31:54 +0800737
738 shellball_path = os.path.join(self._temp_path,
739 'chromeos-firmwareupdate')
740
741 if shellball:
742 shutil.copyfile(shellball, shellball_path)
743 else:
744 shutil.copyfile('/usr/sbin/chromeos-firmwareupdate',
745 shellball_path)
ctchangc7e55ea2012-08-09 16:19:14 +0800746 self.run_shell_command(
Chun-ting Changf91ee0f2012-09-17 18:31:54 +0800747 'sh %s --sb_extract %s' % (shellball_path, self._work_path))
ctchangc7e55ea2012-08-09 16:19:14 +0800748
749
750 def retrieve_shellball_fwid(self):
751 """Retrieve shellball's fwid.
752
753 This method should be called after setup_firmwareupdate_temp_dir.
754
755 Returns:
756 Shellball's fwid.
757 """
758 self.run_shell_command('dump_fmap -x %s %s' %
759 (os.path.join(self._work_path, 'bios.bin'),
760 'RW_FWID_A'))
761
762 [fwid] = self.run_shell_command_get_output(
ctchangcc88d112012-08-23 17:56:15 +0800763 "cat RW_FWID_A | tr '\\0' '\\t' | cut -f1")
ctchangc7e55ea2012-08-09 16:19:14 +0800764
765 return fwid
766
767
768 def cleanup_firmwareupdate_temp_dir(self):
769 """Cleanup temporary directory."""
ctchang6b700df2012-08-20 13:48:07 +0800770 if os.path.isdir(self._temp_path):
771 shutil.rmtree(self._temp_path)
ctchangc7e55ea2012-08-09 16:19:14 +0800772
773
774 def repack_firmwareupdate_shellball(self, append):
775 """Repack shellball with new fwid.
776
777 New fwid follows the rule: [orignal_fwid]-[append].
778
779 Args:
780 append: use for new fwid naming.
781 """
782 shutil.copy('/usr/sbin/chromeos-firmwareupdate', '%s' %
783 os.path.join(self._temp_path,
784 'chromeos-firmwareupdate-%s' % append))
785
ctchang6b700df2012-08-20 13:48:07 +0800786 self.run_shell_command('sh %s --sb_repack %s' % (
787 os.path.join(self._temp_path,
788 'chromeos-firmwareupdate-%s' % append),
789 self._work_path))
ctchangc7e55ea2012-08-09 16:19:14 +0800790
791 args = ['-i']
792 args.append('"s/TARGET_FWID=\\"\\(.*\\)\\"/TARGET_FWID=\\"\\1.%s\\"/g"'
793 % append)
794 args.append('%s'
795 % os.path.join(self._temp_path,
796 'chromeos-firmwareupdate-%s' % append))
797 cmd = 'sed %s' % ' '.join(args)
798 self.run_shell_command(cmd)
799
800 args = ['-i']
801 args.append('"s/TARGET_UNSTABLE=\\".*\\"/TARGET_UNSTABLE=\\"\\"/g"')
802 args.append('%s'
803 % os.path.join(self._temp_path,
804 'chromeos-firmwareupdate-%s' % append))
805 cmd = 'sed %s' % ' '.join(args)
806 self.run_shell_command(cmd)
807
808
809 def resign_firmware(self, version):
810 """Resign firmware with version.
811
812 Args:
813 version: new firmware version number.
814 """
815 args = [os.path.join(self._work_path, 'bios.bin')]
816 args.append(os.path.join(self._temp_path, 'output.bin'))
817 args.append(os.path.join(self._keys_path, 'firmware_data_key.vbprivk'))
818 args.append(os.path.join(self._keys_path, 'firmware.keyblock'))
819 args.append(os.path.join(self._keys_path,
820 'dev_firmware_data_key.vbprivk'))
821 args.append(os.path.join(self._keys_path, 'dev_firmware.keyblock'))
822 args.append(os.path.join(self._keys_path, 'kernel_subkey.vbpubk'))
823 args.append('%d' % version)
824 args.append('1')
825 cmd = '/usr/share/vboot/bin/resign_firmwarefd.sh %s' % ' '.join(args)
826 self.run_shell_command(cmd)
827
828 shutil.copyfile('%s' % os.path.join(self._temp_path, 'output.bin'),
829 '%s' % os.path.join(self._work_path, 'bios.bin'))
830
831
832 def run_firmware_autoupdate(self, append):
833 """Do firmwareupdate with autoupdate mode using new shellball.
834
835 Args:
836 append: decide which shellball to use with format
837 chromeos-firmwareupdate-[append]
838 """
839 self.run_shell_command(
Chun-ting Changa4f65532012-10-17 16:57:28 +0800840 '/bin/sh %s --mode autoupdate '
841 '--noupdate_ec --nocheck_rw_compatible'
842 % os.path.join(self._temp_path,
ctchangc7e55ea2012-08-09 16:19:14 +0800843 'chromeos-firmwareupdate-%s' % append))
844
845
Chun-ting Changf91ee0f2012-09-17 18:31:54 +0800846 def run_firmware_factory_install(self):
847 """ Do firmwareupdate with factory_install mode using new shellball."""
848 self.run_shell_command(
849 '/bin/sh %s --mode factory_install --noupdate_ec'
850 % os.path.join(self._temp_path, 'chromeos-firmwareupdate'))
851
852
ctchangc7e55ea2012-08-09 16:19:14 +0800853 def run_firmware_bootok(self, append):
854 """Do bootok mode using new shellball.
855
856 Copy firmware B to firmware A if reboot success.
857 """
858 self.run_shell_command(
859 '/bin/sh %s --mode bootok' % os.path.join(self._temp_path,
860 'chromeos-firmwareupdate-%s' % append))
861
862
863 def run_firmware_recovery(self):
864 """Recovery to original shellball."""
Chun-ting Changf91ee0f2012-09-17 18:31:54 +0800865 self.run_shell_command(
Chun-ting Changa4f65532012-10-17 16:57:28 +0800866 '/bin/sh %s --mode recovery --noupdate_ec --nocheck_rw_compatible'
867 % os.path.join(self._temp_path, 'chromeos-firmwareupdate'))
ctchangc7e55ea2012-08-09 16:19:14 +0800868
869
870 def get_temp_path(self):
871 """Get temporary directory path."""
872 return self._temp_path
873
874
ctchangcc88d112012-08-23 17:56:15 +0800875 def get_keys_path(self):
876 """Get keys path in temporary directory."""
877 return self._keys_path
878
879
880 def resign_kernel_with_keys(self, section, key_path=None):
881 """Resign kernel with temporary key."""
882 self._kernel_handler.resign_kernel(section, key_path)
883
884
ctchang38ae4922012-09-03 17:01:16 +0800885 def create_temp_dir(self, prefix='backup_'):
886 """Create a temporary directory and return the path."""
887 return tempfile.mkdtemp(prefix=prefix)
888
889
Tom Wai-Hong Tambea57b32011-09-02 18:27:47 +0800890 def cleanup(self):
891 """Cleanup for the RPC server. Currently nothing."""
892 pass
893
894
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700895def main():
896 parser = OptionParser(usage='Usage: %prog [options]')
897 parser.add_option('--port', type='int', dest='port', default=9990,
898 help='port number of XMLRPC server')
899 (options, args) = parser.parse_args()
900
901 faft_client = FAFTClient()
902
903 # Launch the XMLRPC server to provide FAFTClient commands.
Tom Wai-Hong Tam4a257e52011-11-12 08:36:22 +0800904 server = SimpleXMLRPCServer(('localhost', options.port), allow_none=True,
Tom Wai-Hong Tamc1e0b9a2012-11-01 13:52:39 +0800905 logRequests=True)
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700906 server.register_introspection_functions()
907 server.register_instance(faft_client)
908 print 'XMLRPC Server: Serving FAFTClient on port %s' % options.port
909 server.serve_forever()
910
911
912if __name__ == '__main__':
913 main()