blob: 923712f1d8bf7841ae14ad01bb5d963e2ab7d643 [file] [log] [blame]
barfab@chromium.orgb6d29932012-04-11 09:46:43 +02001# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -07002# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Exposes the FAFTClient interface over XMLRPC.
6
7It launches a XMLRPC server and exposes the interface of FAFTClient object.
8The FAFTClient object aggreates some useful functions of exisintg SAFT
9libraries.
10"""
11
ctchang38ae4922012-09-03 17:01:16 +080012import functools, os, shutil, sys, tempfile
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -070013from optparse import OptionParser
14from SimpleXMLRPCServer import SimpleXMLRPCServer
15
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +080016from saft import cgpt_state, chromeos_interface, flashrom_handler
17from saft import kernel_handler, saft_flashrom_util, tpm_handler
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -070018
19
Tom Wai-Hong Tam0e680af2011-10-26 14:32:55 +080020def allow_multiple_section_input(image_operator):
21 @functools.wraps(image_operator)
22 def wrapper(self, section):
23 if type(section) in (tuple, list):
24 for sec in section:
25 image_operator(self, sec)
26 else:
27 image_operator(self, section)
28 return wrapper
29
30
Vic Yang13d22ec2012-06-18 15:12:47 +080031class LazyFlashromHandlerProxy:
32 _loaded = False
33 _obj = None
34
35 def __init__(self, *args, **kargs):
36 self._args = args
37 self._kargs = kargs
38
39 def _load(self):
40 self._obj = flashrom_handler.FlashromHandler()
41 self._obj.init(*self._args, **self._kargs)
42 self._obj.new_image()
43 self._loaded = True
44
45 def __getattr__(self, name):
46 if not self._loaded:
47 self._load()
48 return getattr(self._obj, name)
49
Tom Wai-Hong Tamc1c4deb2012-07-26 14:28:11 +080050 def reload(self):
51 self._loaded = False
52
Vic Yang13d22ec2012-06-18 15:12:47 +080053
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -070054class FAFTClient(object):
55 """A class of FAFT client which aggregates some useful functions of SAFT.
56
57 This class can be exposed via a XMLRPC server such that its functions can
58 be accessed remotely.
59
60 Attributes:
61 _chromeos_interface: An object to encapsulate OS services functions.
Vic Yang59cac9c2012-05-21 15:28:42 +080062 _bios_handler: An object to automate BIOS flashrom testing.
63 _ec_handler: An object to automate EC flashrom testing.
Tom Wai-Hong Tam23870e02012-08-24 16:15:34 +080064 _ec_image: An object to automate EC image for autest.
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -070065 _kernel_handler: An object to provide kernel related actions.
66 _tpm_handler: An object to control TPM device.
ctchangc7e55ea2012-08-09 16:19:14 +080067 _temp_path: Path of a temp directory.
68 _keys_path: Path of a directory, keys/, in temp directory.
69 _work_path: Path of a directory, work/, in temp directory.
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -070070 """
71
72 def __init__(self):
73 """Initialize the data attributes of this class."""
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -070074 # TODO(waihong): Move the explicit object.init() methods to the
75 # objects' constructors (ChromeOSInterface, FlashromHandler,
76 # KernelHandler, and TpmHandler).
77 self._chromeos_interface = chromeos_interface.ChromeOSInterface(False)
Tom Wai-Hong Tam48958832011-12-30 10:16:57 +080078 # We keep the state of FAFT test in a permanent directory over reboots.
Tom Wai-Hong Tam07278c22012-02-08 16:53:00 +080079 state_dir = '/var/tmp/faft'
80 self._chromeos_interface.init(state_dir, log_file='/tmp/faft_log.txt')
81 os.chdir(state_dir)
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -070082
Vic Yang13d22ec2012-06-18 15:12:47 +080083 self._bios_handler = LazyFlashromHandlerProxy(
84 saft_flashrom_util,
Vic Yang59cac9c2012-05-21 15:28:42 +080085 self._chromeos_interface,
86 None,
87 '/usr/share/vboot/devkeys',
88 'bios')
Vic Yang59cac9c2012-05-21 15:28:42 +080089
Todd Brochf2b1d012012-06-14 12:55:21 -070090 self._ec_handler = None
91 if not os.system("mosys ec info"):
Vic Yang13d22ec2012-06-18 15:12:47 +080092 self._ec_handler = LazyFlashromHandlerProxy(
93 saft_flashrom_util,
Todd Brochf2b1d012012-06-14 12:55:21 -070094 self._chromeos_interface,
Vic Yang13d22ec2012-06-18 15:12:47 +080095 'ec_root_key.vpubk',
Todd Brochf2b1d012012-06-14 12:55:21 -070096 '/usr/share/vboot/devkeys',
97 'ec')
Todd Brochf2b1d012012-06-14 12:55:21 -070098
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -070099
100 self._kernel_handler = kernel_handler.KernelHandler()
Tom Wai-Hong Tam07278c22012-02-08 16:53:00 +0800101 # TODO(waihong): The dev_key_path is a new argument. We do that in
102 # order not to break the old image and still be able to run.
103 try:
104 self._kernel_handler.init(self._chromeos_interface,
ctchangd60030f2012-08-29 15:39:56 +0800105 dev_key_path='/usr/share/vboot/devkeys',
106 internal_disk=True)
Tom Wai-Hong Tam07278c22012-02-08 16:53:00 +0800107 except:
108 # Copy the key to the current working directory.
109 shutil.copy('/usr/share/vboot/devkeys/kernel_data_key.vbprivk', '.')
ctchangd60030f2012-08-29 15:39:56 +0800110 self._kernel_handler.init(self._chromeos_interface,
111 internal_disk=True)
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700112
113 self._tpm_handler = tpm_handler.TpmHandler()
114 self._tpm_handler.init(self._chromeos_interface)
115
Tom Wai-Hong Tam48958832011-12-30 10:16:57 +0800116 self._cgpt_state = cgpt_state.CgptState(
Tom Wai-Hong Tamed2231c2012-07-27 14:39:46 +0800117 'SHORT', self._chromeos_interface, self.get_root_dev())
Tom Wai-Hong Tam48958832011-12-30 10:16:57 +0800118
ctchangc7e55ea2012-08-09 16:19:14 +0800119 # Initialize temporary directory path
120 self._temp_path = '/var/tmp/faft/autest'
121 self._keys_path = os.path.join(self._temp_path, 'keys')
122 self._work_path = os.path.join(self._temp_path, 'work')
123
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700124
Tom Wai-Hong Tame8f291a2011-12-08 22:03:53 +0800125 def _dispatch(self, method, params):
126 """This _dispatch method handles string conversion especially.
127
128 Since we turn off allow_dotted_names option. So any string conversion,
129 like str(FAFTClient.method), i.e. FAFTClient.method.__str__, failed
130 via XML RPC call.
131 """
132 is_str = method.endswith('.__str__')
133 if is_str:
134 method = method.rsplit('.', 1)[0]
135 try:
136 func = getattr(self, method)
137 except AttributeError:
138 raise Exception('method "%s" is not supported' % method)
139 else:
140 if is_str:
141 return str(func)
142 else:
143 return func(*params)
144
145
Tom Wai-Hong Tambea57b32011-09-02 18:27:47 +0800146 def is_available(self):
147 """Function for polling the RPC server availability.
148
149 Returns:
150 Always True.
151 """
152 return True
153
154
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700155 def run_shell_command(self, command):
156 """Run shell command.
157
158 Args:
159 command: A shell command to be run.
160 """
161 self._chromeos_interface.log('Requesting run shell command')
162 self._chromeos_interface.run_shell_command(command)
163
164
165 def run_shell_command_get_output(self, command):
166 """Run shell command and get its console output.
167
168 Args:
169 command: A shell command to be run.
170
171 Returns:
172 A list of strings stripped of the newline characters.
173 """
174 self._chromeos_interface.log(
175 'Requesting run shell command and get its console output')
176 return self._chromeos_interface.run_shell_command_get_output(command)
177
178
179 def software_reboot(self):
180 """Request software reboot."""
181 self._chromeos_interface.log('Requesting software reboot')
182 self._chromeos_interface.run_shell_command('reboot')
183
184
Tom Wai-Hong Tam678ab152011-12-14 15:27:24 +0800185 def get_platform_name(self):
186 """Get the platform name of the current system.
187
188 Returns:
189 A string of the platform name.
190 """
191 self._chromeos_interface.log('Requesting get platform name')
192 return self._chromeos_interface.run_shell_command_get_output(
193 'mosys platform name')[0]
194
195
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700196 def get_crossystem_value(self, key):
197 """Get crossystem value of the requested key.
198
199 Args:
200 key: A crossystem key.
201
202 Returns:
203 A string of the requested crossystem value.
204 """
205 self._chromeos_interface.log('Requesting get crossystem value')
206 return self._chromeos_interface.run_shell_command_get_output(
207 'crossystem %s' % key)[0]
208
209
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800210 def get_root_dev(self):
211 """Get the name of root device without partition number.
212
213 Returns:
214 A string of the root device without partition number.
215 """
216 self._chromeos_interface.log('Requesting get root device')
217 return self._chromeos_interface.get_root_dev()
218
219
220 def get_root_part(self):
221 """Get the name of root device with partition number.
222
223 Returns:
224 A string of the root device with partition number.
225 """
226 self._chromeos_interface.log('Requesting get root part')
227 return self._chromeos_interface.get_root_part()
228
229
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700230 def set_try_fw_b(self):
231 """Set 'Try Frimware B' flag in crossystem."""
232 self._chromeos_interface.log('Requesting restart with firmware B')
233 self._chromeos_interface.cs.fwb_tries = 1
234
235
Tom Wai-Hong Tam76c75072011-10-25 18:00:12 +0800236 def request_recovery_boot(self):
237 """Request running in recovery mode on the restart."""
238 self._chromeos_interface.log('Requesting restart in recovery mode')
239 self._chromeos_interface.cs.request_recovery()
240
241
Tom Wai-Hong Tam0a7b2be2012-10-15 16:44:12 +0800242 def get_dev_boot_usb(self):
243 """Get dev_boot_usb value which controls developer mode boot from USB.
244
245 Returns:
246 True if enable, False if disable.
247 """
248 self._chromeos_interface.log('Getting dev_boot_usb')
249 return self._chromeos_interface.cs.dev_boot_usb == '1'
250
251
252 def set_dev_boot_usb(self, value):
253 """Set dev_boot_usb value which controls developer mode boot from USB.
254
255 Args:
256 value: True to enable, False to disable.
257 """
258 self._chromeos_interface.log('Setting dev_boot_usb to %s' % str(value))
259 self._chromeos_interface.cs.dev_boot_usb = 1 if value else 0
260
261
Tom Wai-Hong Tam8c9eed62011-12-28 15:05:05 +0800262 def get_gbb_flags(self):
263 """Get the GBB flags.
264
265 Returns:
266 An integer of the GBB flags.
267 """
268 self._chromeos_interface.log('Getting GBB flags')
Vic Yang59cac9c2012-05-21 15:28:42 +0800269 return self._bios_handler.get_gbb_flags()
Tom Wai-Hong Tam8c9eed62011-12-28 15:05:05 +0800270
271
Tom Wai-Hong Tam81f70002011-12-13 12:29:46 +0800272 def get_firmware_flags(self, section):
273 """Get the preamble flags of a firmware section.
274
275 Args:
276 section: A firmware section, either 'a' or 'b'.
277
278 Returns:
279 An integer of the preamble flags.
280 """
281 self._chromeos_interface.log('Getting preamble flags of firmware %s' %
282 section)
Vic Yang59cac9c2012-05-21 15:28:42 +0800283 return self._bios_handler.get_section_flags(section)
284
285
Vic Yang91b73cf2012-07-31 17:18:11 +0800286 def set_firmware_flags(self, section, flags):
287 """Set the preamble flags of a firmware section.
288
289 Args:
290 section: A firmware section, either 'a' or 'b'.
291 flags: An integer of preamble flags.
292 """
293 self._chromeos_interface.log(
294 'Setting preamble flags of firmware %s to %s' % (section, flags))
295 version = self.get_firmware_version(section)
296 self._bios_handler.set_section_version(section, version, flags,
297 write_through=True)
298
299
Tom Wai-Hong Tam4e10b9f2012-09-06 16:23:02 +0800300 def get_firmware_sha(self, section):
301 """Get SHA1 hash of BIOS RW firmware section.
302
303 Args:
304 section: A firmware section, either 'a' or 'b'.
305 flags: An integer of preamble flags.
306 """
307 return self._bios_handler.get_section_sha(section)
308
309
ctchang38ae4922012-09-03 17:01:16 +0800310 def get_firmware_sig_sha(self, section):
311 """Get SHA1 hash of firmware vblock in section."""
312 return self._bios_handler.get_section_sig_sha(section)
313
314
Vic Yang91b73cf2012-07-31 17:18:11 +0800315 def get_EC_firmware_sha(self):
Tom Wai-Hong Tam4e10b9f2012-09-06 16:23:02 +0800316 """Get SHA1 hash of EC RW firmware section."""
Vic Yang91b73cf2012-07-31 17:18:11 +0800317 return self._ec_handler.get_section_sha('rw')
318
319
Tom Wai-Hong Tamc1c4deb2012-07-26 14:28:11 +0800320 def reload_firmware(self):
321 """Reload the firmware image that may be changed."""
322 self._bios_handler.reload()
323
324
Vic Yang59cac9c2012-05-21 15:28:42 +0800325 @allow_multiple_section_input
326 def corrupt_EC(self, section):
327 """Corrupt the requested EC section signature.
328
329 Args:
330 section: A EC section, either 'a' or 'b'.
331 """
332 self._chromeos_interface.log('Corrupting EC signature %s' %
333 section)
Vic Yang37a55462012-06-29 14:00:28 +0800334 self._ec_handler.corrupt_firmware(section, corrupt_all=True)
Vic Yang59cac9c2012-05-21 15:28:42 +0800335
336
337 @allow_multiple_section_input
338 def corrupt_EC_body(self, section):
339 """Corrupt the requested EC section body.
340
341 Args:
342 section: An EC section, either 'a' or 'b'.
343 """
344 self._chromeos_interface.log('Corrupting EC body %s' %
345 section)
Vic Yang37a55462012-06-29 14:00:28 +0800346 self._ec_handler.corrupt_firmware_body(section, corrupt_all=True)
Vic Yang59cac9c2012-05-21 15:28:42 +0800347
348
349 @allow_multiple_section_input
350 def restore_EC(self, section):
351 """Restore the previously corrupted EC section signature.
352
353 Args:
354 section: An EC section, either 'a' or 'b'.
355 """
356 self._chromeos_interface.log('Restoring EC signature %s' %
357 section)
Vic Yang37a55462012-06-29 14:00:28 +0800358 self._ec_handler.restore_firmware(section, restore_all=True)
Vic Yang59cac9c2012-05-21 15:28:42 +0800359
360
361 @allow_multiple_section_input
362 def restore_EC_body(self, section):
363 """Restore the previously corrupted EC section body.
364
365 Args:
366 section: An EC section, either 'a' or 'b'.
367 """
368 self._chromeos_interface.log('Restoring EC body %s' %
369 section)
Vic Yang37a55462012-06-29 14:00:28 +0800370 self._ec_handler.restore_firmware_body(section, restore_all=True)
Tom Wai-Hong Tam81f70002011-12-13 12:29:46 +0800371
372
Tom Wai-Hong Tam0e680af2011-10-26 14:32:55 +0800373 @allow_multiple_section_input
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700374 def corrupt_firmware(self, section):
Tom Wai-Hong Tam9aea8212011-12-12 15:08:45 +0800375 """Corrupt the requested firmware section signature.
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700376
377 Args:
378 section: A firmware section, either 'a' or 'b'.
379 """
Tom Wai-Hong Tam9aea8212011-12-12 15:08:45 +0800380 self._chromeos_interface.log('Corrupting firmware signature %s' %
381 section)
Vic Yang59cac9c2012-05-21 15:28:42 +0800382 self._bios_handler.corrupt_firmware(section)
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700383
384
Tom Wai-Hong Tam0e680af2011-10-26 14:32:55 +0800385 @allow_multiple_section_input
Tom Wai-Hong Tam81f70002011-12-13 12:29:46 +0800386 def corrupt_firmware_body(self, section):
387 """Corrupt the requested firmware section body.
388
389 Args:
390 section: A firmware section, either 'a' or 'b'.
391 """
392 self._chromeos_interface.log('Corrupting firmware body %s' %
393 section)
Vic Yang59cac9c2012-05-21 15:28:42 +0800394 self._bios_handler.corrupt_firmware_body(section)
Tom Wai-Hong Tam81f70002011-12-13 12:29:46 +0800395
396
397 @allow_multiple_section_input
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700398 def restore_firmware(self, section):
Tom Wai-Hong Tam9aea8212011-12-12 15:08:45 +0800399 """Restore the previously corrupted firmware section signature.
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700400
401 Args:
402 section: A firmware section, either 'a' or 'b'.
403 """
Tom Wai-Hong Tam9aea8212011-12-12 15:08:45 +0800404 self._chromeos_interface.log('Restoring firmware signature %s' %
405 section)
Vic Yang59cac9c2012-05-21 15:28:42 +0800406 self._bios_handler.restore_firmware(section)
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700407
408
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800409 @allow_multiple_section_input
Tom Wai-Hong Tam81f70002011-12-13 12:29:46 +0800410 def restore_firmware_body(self, section):
411 """Restore the previously corrupted firmware section body.
412
413 Args:
414 section: A firmware section, either 'a' or 'b'.
415 """
416 self._chromeos_interface.log('Restoring firmware body %s' %
417 section)
Vic Yang59cac9c2012-05-21 15:28:42 +0800418 self._bios_handler.restore_firmware_body(section)
Tom Wai-Hong Tam81f70002011-12-13 12:29:46 +0800419
420
Vic Yang91b73cf2012-07-31 17:18:11 +0800421 def get_firmware_version(self, section):
422 """Retrieve firmware version of a section."""
423 return self._bios_handler.get_section_version(section)
424
425
Chun-ting Changa4f65532012-10-17 16:57:28 +0800426 def get_tpm_firmware_version(self):
427 """Retrieve tpm firmware body version."""
428 return self._tpm_handler.get_fw_version()
429
430
Tom Wai-Hong Tam46d03b12012-02-08 12:02:17 +0800431 def _modify_firmware_version(self, section, delta):
432 """Modify firmware version for the requested section, by adding delta.
433
434 The passed in delta, a positive or a negative number, is added to the
435 original firmware version.
436 """
Vic Yang91b73cf2012-07-31 17:18:11 +0800437 original_version = self.get_firmware_version(section)
Tom Wai-Hong Tam46d03b12012-02-08 12:02:17 +0800438 new_version = original_version + delta
Vic Yang59cac9c2012-05-21 15:28:42 +0800439 flags = self._bios_handler.get_section_flags(section)
Tom Wai-Hong Tam46d03b12012-02-08 12:02:17 +0800440 self._chromeos_interface.log(
441 'Setting firmware section %s version from %d to %d' % (
442 section, original_version, new_version))
Vic Yang59cac9c2012-05-21 15:28:42 +0800443 self._bios_handler.set_section_version(section, new_version, flags,
444 write_through=True)
Tom Wai-Hong Tam46d03b12012-02-08 12:02:17 +0800445
446 @allow_multiple_section_input
447 def move_firmware_backward(self, section):
448 """Decrement firmware version for the requested section."""
449 self._modify_firmware_version(section, -1)
450
451
452 @allow_multiple_section_input
453 def move_firmware_forward(self, section):
454 """Increase firmware version for the requested section."""
455 self._modify_firmware_version(section, 1)
456
Chun-ting Changa4f65532012-10-17 16:57:28 +0800457 def get_firmware_datakey_version(self, section):
ctchangc7e55ea2012-08-09 16:19:14 +0800458 """Return firmware data key version."""
459 return self._bios_handler.get_section_datakey_version(section)
460
Chun-ting Changa4f65532012-10-17 16:57:28 +0800461 def get_tpm_firmware_datakey_version(self):
462 """Retrieve tpm firmware data key version."""
463 return self._tpm_handler.get_fw_body_version()
464
ctchangc7e55ea2012-08-09 16:19:14 +0800465 def retrieve_kernel_subkey_version(self,section):
466 """Return kernel subkey version."""
467 return self._bios_handler.get_section_kernel_subkey_version(section)
Tom Wai-Hong Tam46d03b12012-02-08 12:02:17 +0800468
Tom Wai-Hong Tam81f70002011-12-13 12:29:46 +0800469 @allow_multiple_section_input
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800470 def corrupt_kernel(self, section):
471 """Corrupt the requested kernel section.
472
473 Args:
474 section: A kernel section, either 'a' or 'b'.
475 """
476 self._chromeos_interface.log('Corrupting kernel %s' % section)
477 self._kernel_handler.corrupt_kernel(section)
478
479
480 @allow_multiple_section_input
481 def restore_kernel(self, section):
482 """Restore the requested kernel section (previously corrupted).
483
484 Args:
485 section: A kernel section, either 'a' or 'b'.
486 """
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800487 self._kernel_handler.restore_kernel(section)
488
489
Tom Wai-Hong Tam07278c22012-02-08 16:53:00 +0800490 def _modify_kernel_version(self, section, delta):
491 """Modify kernel version for the requested section, by adding delta.
492
493 The passed in delta, a positive or a negative number, is added to the
494 original kernel version.
495 """
496 original_version = self._kernel_handler.get_version(section)
497 new_version = original_version + delta
498 self._chromeos_interface.log(
499 'Setting kernel section %s version from %d to %d' % (
500 section, original_version, new_version))
501 self._kernel_handler.set_version(section, new_version)
502
503
504 @allow_multiple_section_input
505 def move_kernel_backward(self, section):
506 """Decrement kernel version for the requested section."""
507 self._modify_kernel_version(section, -1)
508
509
510 @allow_multiple_section_input
511 def move_kernel_forward(self, section):
512 """Increase kernel version for the requested section."""
513 self._modify_kernel_version(section, 1)
514
ctchangcc88d112012-08-23 17:56:15 +0800515
516 def retrieve_kernel_version(self, section):
517 """Return kernel version."""
518 return self._kernel_handler.get_version(section)
519
520
521 def retrieve_kernel_datakey_version(self, section):
522 """Return kernel datakey version."""
523 return self._kernel_handler.get_datakey_version(section)
524
525
Tom Wai-Hong Tam622d0ba2012-08-15 16:29:05 +0800526 def diff_kernel_a_b(self):
527 """Compare kernel A with B.
528
529 Returns:
530 True: if kernel A is different with B.
531 False: if kernel A is the same as B.
532 """
533 rootdev = self._chromeos_interface.get_root_dev()
534 kernel_a = self._chromeos_interface.join_part(rootdev, '3')
535 kernel_b = self._chromeos_interface.join_part(rootdev, '5')
536
537 # The signature (some kind of hash) for the kernel body is stored in
538 # the beginning. So compare the first 64KB (including header, preamble,
539 # and signature) should be enough to check them identical.
540 header_a = self._chromeos_interface.read_partition(kernel_a, 0x10000)
541 header_b = self._chromeos_interface.read_partition(kernel_b, 0x10000)
542
543 return header_a != header_b
Tom Wai-Hong Tam07278c22012-02-08 16:53:00 +0800544
Tom Wai-Hong Tam23870e02012-08-24 16:15:34 +0800545
Tom Wai-Hong Tam0a7b2be2012-10-15 16:44:12 +0800546 def is_removable_device_boot(self):
547 """Check the current boot device is removable.
548
549 Returns:
550 True: if a removable device boots.
551 False: if a non-removable device boots.
552 """
553 root_part = self._chromeos_interface.get_root_part()
554 return self._chromeos_interface.is_removable_device(root_part)
555
556
Tom Wai-Hong Tam23870e02012-08-24 16:15:34 +0800557 def setup_EC_image(self, ec_path):
558 """Setup the new EC image for later update.
559
560 Args:
561 ec_path: The path of the EC image to be updated.
562 """
563 self._ec_image = flashrom_handler.FlashromHandler()
564 self._ec_image.init(saft_flashrom_util,
565 self._chromeos_interface,
566 'ec_root_key.vpubk',
567 '/usr/share/vboot/devkeys',
568 'ec')
569 self._ec_image.new_image(ec_path)
570
571
572 def get_EC_image_sha(self):
573 """Get SHA1 hash of RW firmware section of the EC autest image."""
574 return self._ec_image.get_section_sha('rw')
575
576
577 def update_EC_from_image(self, section, flags):
578 """Update EC via software sync design.
579
580 It copys the RW section from the EC image, which is loaded by calling
581 setup_EC_image(), to the EC area of the specified RW section on the
582 current AP firmware.
583
584 Args:
585 section: A firmware section on current BIOS, either 'a' or 'b'.
586 flags: An integer of preamble flags.
587 """
588 blob = self._ec_image.get_section_body('rw')
589 self._bios_handler.set_section_ecbin(section, blob,
590 write_through=True)
591 self.set_firmware_flags(section, flags)
592
593
Tom Wai-Hong Tamb63bc742012-08-30 20:41:30 +0800594 def dump_firmware(self, bios_path):
595 """Dump the current BIOS firmware to a file, specified by bios_path.
596
597 Args:
598 bios_path: The path of the BIOS image to be written.
599 """
600 self._bios_handler.dump_whole(bios_path)
601
602
ctchang38ae4922012-09-03 17:01:16 +0800603 def dump_firmware_rw(self, dir_path):
604 """Dump the current BIOS firmware RW to dir_path.
605
606 VBOOTA, VBOOTB, FVMAIN, FVMAINB need to be dumped.
607
608 Args:
609 dir_path: The path of directory which contains files to be written.
610 """
611 if not os.path.isdir(dir_path):
612 raise Exception("%s doesn't exist" % dir_path)
613
614 VBOOTA_blob = self._bios_handler.get_section_sig('a')
615 VBOOTB_blob = self._bios_handler.get_section_sig('b')
616 FVMAIN_blob = self._bios_handler.get_section_body('a')
617 FVMAINB_blob = self._bios_handler.get_section_body('b')
618
619 open(os.path.join(dir_path, 'VBOOTA'), 'w').write(VBOOTA_blob)
620 open(os.path.join(dir_path, 'VBOOTB'), 'w').write(VBOOTB_blob)
621 open(os.path.join(dir_path, 'FVMAIN'), 'w').write(FVMAIN_blob)
622 open(os.path.join(dir_path, 'FVMAINB'), 'w').write(FVMAINB_blob)
623
624
Tom Wai-Hong Tamb63bc742012-08-30 20:41:30 +0800625 def write_firmware(self, bios_path):
626 """Write the firmware from bios_path to the current system.
627
628 Args:
629 bios_path: The path of the source BIOS image.
630 """
631 self._bios_handler.new_image(bios_path)
632 self._bios_handler.write_whole()
633
634
ctchang38ae4922012-09-03 17:01:16 +0800635 def write_firmware_rw(self, dir_path):
636 """Write the firmware RW from dir_path to the current system.
637
638 VBOOTA, VBOOTB, FVMAIN, FVMAINB need to be written.
639
640 Args:
641 dir_path: The path of directory which contains the source files.
642 """
643 if not os.path.exists(os.path.join(dir_path, 'VBOOTA')) or \
644 not os.path.exists(os.path.join(dir_path, 'VBOOTB')) or \
645 not os.path.exists(os.path.join(dir_path, 'FVMAIN')) or \
646 not os.path.exists(os.path.join(dir_path, 'FVMAINB')):
647 raise Exception("Source firmware file(s) doesn't exist.")
648
649 VBOOTA_blob = open(os.path.join(dir_path, 'VBOOTA'), 'rb').read()
650 VBOOTB_blob = open(os.path.join(dir_path, 'VBOOTB'), 'rb').read()
651 FVMAIN_blob = open(os.path.join(dir_path, 'FVMAIN'), 'rb').read()
652 FVMAINB_blob = open(os.path.join(dir_path, 'FVMAINB'), 'rb').read()
653
654 self._bios_handler.set_section_sig('a', VBOOTA_blob,
655 write_through=True)
656 self._bios_handler.set_section_sig('b', VBOOTB_blob,
657 write_through=True)
658 self._bios_handler.set_section_body('a', FVMAIN_blob,
659 write_through=True)
660 self._bios_handler.set_section_body('b', FVMAINB_blob,
661 write_through=True)
662
663
Tom Wai-Hong Tam23870e02012-08-24 16:15:34 +0800664 def dump_EC_firmware(self, ec_path):
665 """Dump the current EC firmware to a file, specified by ec_path.
666
667 Args:
668 ec_path: The path of the EC image to be written.
669 """
670 self._ec_handler.dump_whole(ec_path)
671
672
Tom Wai-Hong Tam48958832011-12-30 10:16:57 +0800673 def run_cgpt_test_loop(self):
674 """Run the CgptState test loop. The tst logic is handled in the client.
675
676 Returns:
677 0: there are more cgpt tests to execute.
678 1: no more CgptState test, finished.
679 """
680 return self._cgpt_state.test_loop()
681
682
683 def set_cgpt_test_step(self, step):
684 """Set the CgptState test step.
685
686 Args:
687 step: A test step number.
688 """
689 self._cgpt_state.set_step(step)
690
691
692 def get_cgpt_test_step(self):
693 """Get the CgptState test step.
694
695 Returns:
696 A test step number.
697 """
698 return self._cgpt_state.get_step()
699
700
Chun-ting Changf91ee0f2012-09-17 18:31:54 +0800701 def setup_firmwareupdate_temp_dir(self, shellball=None):
ctchangc7e55ea2012-08-09 16:19:14 +0800702 """Setup temporary directory.
703
Chun-ting Changf91ee0f2012-09-17 18:31:54 +0800704 Devkeys are copied to _key_path. Then, shellball (default:
705 /usr/sbin/chromeos-firmwareupdate) is extracted to _work_path.
706
707 Args:
708 shellball: Path of shellball.
ctchangc7e55ea2012-08-09 16:19:14 +0800709 """
ctchang6b700df2012-08-20 13:48:07 +0800710
711 self.cleanup_firmwareupdate_temp_dir()
712
ctchangc7e55ea2012-08-09 16:19:14 +0800713 os.mkdir(self._temp_path)
714 os.chdir(self._temp_path)
715
716 os.mkdir(self._work_path)
717 shutil.copytree('/usr/share/vboot/devkeys/', self._keys_path)
Chun-ting Changf91ee0f2012-09-17 18:31:54 +0800718
719 shellball_path = os.path.join(self._temp_path,
720 'chromeos-firmwareupdate')
721
722 if shellball:
723 shutil.copyfile(shellball, shellball_path)
724 else:
725 shutil.copyfile('/usr/sbin/chromeos-firmwareupdate',
726 shellball_path)
ctchangc7e55ea2012-08-09 16:19:14 +0800727 self.run_shell_command(
Chun-ting Changf91ee0f2012-09-17 18:31:54 +0800728 'sh %s --sb_extract %s' % (shellball_path, self._work_path))
ctchangc7e55ea2012-08-09 16:19:14 +0800729
730
731 def retrieve_shellball_fwid(self):
732 """Retrieve shellball's fwid.
733
734 This method should be called after setup_firmwareupdate_temp_dir.
735
736 Returns:
737 Shellball's fwid.
738 """
739 self.run_shell_command('dump_fmap -x %s %s' %
740 (os.path.join(self._work_path, 'bios.bin'),
741 'RW_FWID_A'))
742
743 [fwid] = self.run_shell_command_get_output(
ctchangcc88d112012-08-23 17:56:15 +0800744 "cat RW_FWID_A | tr '\\0' '\\t' | cut -f1")
ctchangc7e55ea2012-08-09 16:19:14 +0800745
746 return fwid
747
748
749 def cleanup_firmwareupdate_temp_dir(self):
750 """Cleanup temporary directory."""
ctchang6b700df2012-08-20 13:48:07 +0800751 if os.path.isdir(self._temp_path):
752 shutil.rmtree(self._temp_path)
ctchangc7e55ea2012-08-09 16:19:14 +0800753
754
755 def repack_firmwareupdate_shellball(self, append):
756 """Repack shellball with new fwid.
757
758 New fwid follows the rule: [orignal_fwid]-[append].
759
760 Args:
761 append: use for new fwid naming.
762 """
763 shutil.copy('/usr/sbin/chromeos-firmwareupdate', '%s' %
764 os.path.join(self._temp_path,
765 'chromeos-firmwareupdate-%s' % append))
766
ctchang6b700df2012-08-20 13:48:07 +0800767 self.run_shell_command('sh %s --sb_repack %s' % (
768 os.path.join(self._temp_path,
769 'chromeos-firmwareupdate-%s' % append),
770 self._work_path))
ctchangc7e55ea2012-08-09 16:19:14 +0800771
772 args = ['-i']
773 args.append('"s/TARGET_FWID=\\"\\(.*\\)\\"/TARGET_FWID=\\"\\1.%s\\"/g"'
774 % append)
775 args.append('%s'
776 % os.path.join(self._temp_path,
777 'chromeos-firmwareupdate-%s' % append))
778 cmd = 'sed %s' % ' '.join(args)
779 self.run_shell_command(cmd)
780
781 args = ['-i']
782 args.append('"s/TARGET_UNSTABLE=\\".*\\"/TARGET_UNSTABLE=\\"\\"/g"')
783 args.append('%s'
784 % os.path.join(self._temp_path,
785 'chromeos-firmwareupdate-%s' % append))
786 cmd = 'sed %s' % ' '.join(args)
787 self.run_shell_command(cmd)
788
789
790 def resign_firmware(self, version):
791 """Resign firmware with version.
792
793 Args:
794 version: new firmware version number.
795 """
796 args = [os.path.join(self._work_path, 'bios.bin')]
797 args.append(os.path.join(self._temp_path, 'output.bin'))
798 args.append(os.path.join(self._keys_path, 'firmware_data_key.vbprivk'))
799 args.append(os.path.join(self._keys_path, 'firmware.keyblock'))
800 args.append(os.path.join(self._keys_path,
801 'dev_firmware_data_key.vbprivk'))
802 args.append(os.path.join(self._keys_path, 'dev_firmware.keyblock'))
803 args.append(os.path.join(self._keys_path, 'kernel_subkey.vbpubk'))
804 args.append('%d' % version)
805 args.append('1')
806 cmd = '/usr/share/vboot/bin/resign_firmwarefd.sh %s' % ' '.join(args)
807 self.run_shell_command(cmd)
808
809 shutil.copyfile('%s' % os.path.join(self._temp_path, 'output.bin'),
810 '%s' % os.path.join(self._work_path, 'bios.bin'))
811
812
813 def run_firmware_autoupdate(self, append):
814 """Do firmwareupdate with autoupdate mode using new shellball.
815
816 Args:
817 append: decide which shellball to use with format
818 chromeos-firmwareupdate-[append]
819 """
820 self.run_shell_command(
Chun-ting Changa4f65532012-10-17 16:57:28 +0800821 '/bin/sh %s --mode autoupdate '
822 '--noupdate_ec --nocheck_rw_compatible'
823 % os.path.join(self._temp_path,
ctchangc7e55ea2012-08-09 16:19:14 +0800824 'chromeos-firmwareupdate-%s' % append))
825
826
Chun-ting Changf91ee0f2012-09-17 18:31:54 +0800827 def run_firmware_factory_install(self):
828 """ Do firmwareupdate with factory_install mode using new shellball."""
829 self.run_shell_command(
830 '/bin/sh %s --mode factory_install --noupdate_ec'
831 % os.path.join(self._temp_path, 'chromeos-firmwareupdate'))
832
833
ctchangc7e55ea2012-08-09 16:19:14 +0800834 def run_firmware_bootok(self, append):
835 """Do bootok mode using new shellball.
836
837 Copy firmware B to firmware A if reboot success.
838 """
839 self.run_shell_command(
840 '/bin/sh %s --mode bootok' % os.path.join(self._temp_path,
841 'chromeos-firmwareupdate-%s' % append))
842
843
844 def run_firmware_recovery(self):
845 """Recovery to original shellball."""
Chun-ting Changf91ee0f2012-09-17 18:31:54 +0800846 self.run_shell_command(
Chun-ting Changa4f65532012-10-17 16:57:28 +0800847 '/bin/sh %s --mode recovery --noupdate_ec --nocheck_rw_compatible'
848 % os.path.join(self._temp_path, 'chromeos-firmwareupdate'))
ctchangc7e55ea2012-08-09 16:19:14 +0800849
850
851 def get_temp_path(self):
852 """Get temporary directory path."""
853 return self._temp_path
854
855
ctchangcc88d112012-08-23 17:56:15 +0800856 def get_keys_path(self):
857 """Get keys path in temporary directory."""
858 return self._keys_path
859
860
861 def resign_kernel_with_keys(self, section, key_path=None):
862 """Resign kernel with temporary key."""
863 self._kernel_handler.resign_kernel(section, key_path)
864
865
ctchang38ae4922012-09-03 17:01:16 +0800866 def create_temp_dir(self, prefix='backup_'):
867 """Create a temporary directory and return the path."""
868 return tempfile.mkdtemp(prefix=prefix)
869
870
Tom Wai-Hong Tambea57b32011-09-02 18:27:47 +0800871 def cleanup(self):
872 """Cleanup for the RPC server. Currently nothing."""
873 pass
874
875
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700876def main():
877 parser = OptionParser(usage='Usage: %prog [options]')
878 parser.add_option('--port', type='int', dest='port', default=9990,
879 help='port number of XMLRPC server')
880 (options, args) = parser.parse_args()
881
882 faft_client = FAFTClient()
883
884 # Launch the XMLRPC server to provide FAFTClient commands.
Tom Wai-Hong Tam4a257e52011-11-12 08:36:22 +0800885 server = SimpleXMLRPCServer(('localhost', options.port), allow_none=True,
886 logRequests=False)
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700887 server.register_introspection_functions()
888 server.register_instance(faft_client)
889 print 'XMLRPC Server: Serving FAFTClient on port %s' % options.port
890 server.serve_forever()
891
892
893if __name__ == '__main__':
894 main()