blob: c5a7832a2dccf754d8ff8f49b7387ccbdecbc9b2 [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
barfab@chromium.orgb6d29932012-04-11 09:46:43 +020012import functools, os, shutil, sys
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -070013from optparse import OptionParser
14from SimpleXMLRPCServer import SimpleXMLRPCServer
15
16# Import libraries from SAFT.
Tom Wai-Hong Tamc1576b72011-11-08 11:36:16 +080017sys.path.append('/usr/local/sbin/firmware/saft')
barfab@chromium.orgb6d29932012-04-11 09:46:43 +020018import cgpt_state, chromeos_interface, flashrom_handler, kernel_handler
19import saft_flashrom_util, tpm_handler
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -070020
21
Tom Wai-Hong Tam0e680af2011-10-26 14:32:55 +080022def allow_multiple_section_input(image_operator):
23 @functools.wraps(image_operator)
24 def wrapper(self, section):
25 if type(section) in (tuple, list):
26 for sec in section:
27 image_operator(self, sec)
28 else:
29 image_operator(self, section)
30 return wrapper
31
32
Vic Yang13d22ec2012-06-18 15:12:47 +080033class LazyFlashromHandlerProxy:
34 _loaded = False
35 _obj = None
36
37 def __init__(self, *args, **kargs):
38 self._args = args
39 self._kargs = kargs
40
41 def _load(self):
42 self._obj = flashrom_handler.FlashromHandler()
43 self._obj.init(*self._args, **self._kargs)
44 self._obj.new_image()
45 self._loaded = True
46
47 def __getattr__(self, name):
48 if not self._loaded:
49 self._load()
50 return getattr(self._obj, name)
51
Tom Wai-Hong Tamc1c4deb2012-07-26 14:28:11 +080052 def reload(self):
53 self._loaded = False
54
Vic Yang13d22ec2012-06-18 15:12:47 +080055
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -070056class FAFTClient(object):
57 """A class of FAFT client which aggregates some useful functions of SAFT.
58
59 This class can be exposed via a XMLRPC server such that its functions can
60 be accessed remotely.
61
62 Attributes:
63 _chromeos_interface: An object to encapsulate OS services functions.
Vic Yang59cac9c2012-05-21 15:28:42 +080064 _bios_handler: An object to automate BIOS flashrom testing.
65 _ec_handler: An object to automate EC flashrom testing.
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.
68 """
69
70 def __init__(self):
71 """Initialize the data attributes of this class."""
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -070072 # TODO(waihong): Move the explicit object.init() methods to the
73 # objects' constructors (ChromeOSInterface, FlashromHandler,
74 # KernelHandler, and TpmHandler).
75 self._chromeos_interface = chromeos_interface.ChromeOSInterface(False)
Tom Wai-Hong Tam48958832011-12-30 10:16:57 +080076 # We keep the state of FAFT test in a permanent directory over reboots.
Tom Wai-Hong Tam07278c22012-02-08 16:53:00 +080077 state_dir = '/var/tmp/faft'
78 self._chromeos_interface.init(state_dir, log_file='/tmp/faft_log.txt')
79 os.chdir(state_dir)
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -070080
Vic Yang13d22ec2012-06-18 15:12:47 +080081 self._bios_handler = LazyFlashromHandlerProxy(
82 saft_flashrom_util,
Vic Yang59cac9c2012-05-21 15:28:42 +080083 self._chromeos_interface,
84 None,
85 '/usr/share/vboot/devkeys',
86 'bios')
Vic Yang59cac9c2012-05-21 15:28:42 +080087
Todd Brochf2b1d012012-06-14 12:55:21 -070088 self._ec_handler = None
89 if not os.system("mosys ec info"):
Vic Yang13d22ec2012-06-18 15:12:47 +080090 self._ec_handler = LazyFlashromHandlerProxy(
91 saft_flashrom_util,
Todd Brochf2b1d012012-06-14 12:55:21 -070092 self._chromeos_interface,
Vic Yang13d22ec2012-06-18 15:12:47 +080093 'ec_root_key.vpubk',
Todd Brochf2b1d012012-06-14 12:55:21 -070094 '/usr/share/vboot/devkeys',
95 'ec')
Todd Brochf2b1d012012-06-14 12:55:21 -070096
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -070097
98 self._kernel_handler = kernel_handler.KernelHandler()
Tom Wai-Hong Tam07278c22012-02-08 16:53:00 +080099 # TODO(waihong): The dev_key_path is a new argument. We do that in
100 # order not to break the old image and still be able to run.
101 try:
102 self._kernel_handler.init(self._chromeos_interface,
103 dev_key_path='/usr/share/vboot/devkeys')
104 except:
105 # Copy the key to the current working directory.
106 shutil.copy('/usr/share/vboot/devkeys/kernel_data_key.vbprivk', '.')
107 self._kernel_handler.init(self._chromeos_interface)
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700108
109 self._tpm_handler = tpm_handler.TpmHandler()
110 self._tpm_handler.init(self._chromeos_interface)
111
Tom Wai-Hong Tam48958832011-12-30 10:16:57 +0800112 self._cgpt_state = cgpt_state.CgptState(
Tom Wai-Hong Tamed2231c2012-07-27 14:39:46 +0800113 'SHORT', self._chromeos_interface, self.get_root_dev())
Tom Wai-Hong Tam48958832011-12-30 10:16:57 +0800114
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700115
Tom Wai-Hong Tame8f291a2011-12-08 22:03:53 +0800116 def _dispatch(self, method, params):
117 """This _dispatch method handles string conversion especially.
118
119 Since we turn off allow_dotted_names option. So any string conversion,
120 like str(FAFTClient.method), i.e. FAFTClient.method.__str__, failed
121 via XML RPC call.
122 """
123 is_str = method.endswith('.__str__')
124 if is_str:
125 method = method.rsplit('.', 1)[0]
126 try:
127 func = getattr(self, method)
128 except AttributeError:
129 raise Exception('method "%s" is not supported' % method)
130 else:
131 if is_str:
132 return str(func)
133 else:
134 return func(*params)
135
136
Tom Wai-Hong Tambea57b32011-09-02 18:27:47 +0800137 def is_available(self):
138 """Function for polling the RPC server availability.
139
140 Returns:
141 Always True.
142 """
143 return True
144
145
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700146 def run_shell_command(self, command):
147 """Run shell command.
148
149 Args:
150 command: A shell command to be run.
151 """
152 self._chromeos_interface.log('Requesting run shell command')
153 self._chromeos_interface.run_shell_command(command)
154
155
156 def run_shell_command_get_output(self, command):
157 """Run shell command and get its console output.
158
159 Args:
160 command: A shell command to be run.
161
162 Returns:
163 A list of strings stripped of the newline characters.
164 """
165 self._chromeos_interface.log(
166 'Requesting run shell command and get its console output')
167 return self._chromeos_interface.run_shell_command_get_output(command)
168
169
170 def software_reboot(self):
171 """Request software reboot."""
172 self._chromeos_interface.log('Requesting software reboot')
173 self._chromeos_interface.run_shell_command('reboot')
174
175
Tom Wai-Hong Tam678ab152011-12-14 15:27:24 +0800176 def get_platform_name(self):
177 """Get the platform name of the current system.
178
179 Returns:
180 A string of the platform name.
181 """
182 self._chromeos_interface.log('Requesting get platform name')
183 return self._chromeos_interface.run_shell_command_get_output(
184 'mosys platform name')[0]
185
186
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700187 def get_crossystem_value(self, key):
188 """Get crossystem value of the requested key.
189
190 Args:
191 key: A crossystem key.
192
193 Returns:
194 A string of the requested crossystem value.
195 """
196 self._chromeos_interface.log('Requesting get crossystem value')
197 return self._chromeos_interface.run_shell_command_get_output(
198 'crossystem %s' % key)[0]
199
200
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800201 def get_root_dev(self):
202 """Get the name of root device without partition number.
203
204 Returns:
205 A string of the root device without partition number.
206 """
207 self._chromeos_interface.log('Requesting get root device')
208 return self._chromeos_interface.get_root_dev()
209
210
211 def get_root_part(self):
212 """Get the name of root device with partition number.
213
214 Returns:
215 A string of the root device with partition number.
216 """
217 self._chromeos_interface.log('Requesting get root part')
218 return self._chromeos_interface.get_root_part()
219
220
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700221 def set_try_fw_b(self):
222 """Set 'Try Frimware B' flag in crossystem."""
223 self._chromeos_interface.log('Requesting restart with firmware B')
224 self._chromeos_interface.cs.fwb_tries = 1
225
226
Tom Wai-Hong Tam76c75072011-10-25 18:00:12 +0800227 def request_recovery_boot(self):
228 """Request running in recovery mode on the restart."""
229 self._chromeos_interface.log('Requesting restart in recovery mode')
230 self._chromeos_interface.cs.request_recovery()
231
232
Tom Wai-Hong Tam8c9eed62011-12-28 15:05:05 +0800233 def get_gbb_flags(self):
234 """Get the GBB flags.
235
236 Returns:
237 An integer of the GBB flags.
238 """
239 self._chromeos_interface.log('Getting GBB flags')
Vic Yang59cac9c2012-05-21 15:28:42 +0800240 return self._bios_handler.get_gbb_flags()
Tom Wai-Hong Tam8c9eed62011-12-28 15:05:05 +0800241
242
Tom Wai-Hong Tam81f70002011-12-13 12:29:46 +0800243 def get_firmware_flags(self, section):
244 """Get the preamble flags of a firmware section.
245
246 Args:
247 section: A firmware section, either 'a' or 'b'.
248
249 Returns:
250 An integer of the preamble flags.
251 """
252 self._chromeos_interface.log('Getting preamble flags of firmware %s' %
253 section)
Vic Yang59cac9c2012-05-21 15:28:42 +0800254 return self._bios_handler.get_section_flags(section)
255
256
Tom Wai-Hong Tamc1c4deb2012-07-26 14:28:11 +0800257 def reload_firmware(self):
258 """Reload the firmware image that may be changed."""
259 self._bios_handler.reload()
260
261
Vic Yang59cac9c2012-05-21 15:28:42 +0800262 @allow_multiple_section_input
263 def corrupt_EC(self, section):
264 """Corrupt the requested EC section signature.
265
266 Args:
267 section: A EC section, either 'a' or 'b'.
268 """
269 self._chromeos_interface.log('Corrupting EC signature %s' %
270 section)
Vic Yang37a55462012-06-29 14:00:28 +0800271 self._ec_handler.corrupt_firmware(section, corrupt_all=True)
Vic Yang59cac9c2012-05-21 15:28:42 +0800272
273
274 @allow_multiple_section_input
275 def corrupt_EC_body(self, section):
276 """Corrupt the requested EC section body.
277
278 Args:
279 section: An EC section, either 'a' or 'b'.
280 """
281 self._chromeos_interface.log('Corrupting EC body %s' %
282 section)
Vic Yang37a55462012-06-29 14:00:28 +0800283 self._ec_handler.corrupt_firmware_body(section, corrupt_all=True)
Vic Yang59cac9c2012-05-21 15:28:42 +0800284
285
286 @allow_multiple_section_input
287 def restore_EC(self, section):
288 """Restore the previously corrupted EC section signature.
289
290 Args:
291 section: An EC section, either 'a' or 'b'.
292 """
293 self._chromeos_interface.log('Restoring EC signature %s' %
294 section)
Vic Yang37a55462012-06-29 14:00:28 +0800295 self._ec_handler.restore_firmware(section, restore_all=True)
Vic Yang59cac9c2012-05-21 15:28:42 +0800296
297
298 @allow_multiple_section_input
299 def restore_EC_body(self, section):
300 """Restore the previously corrupted EC section body.
301
302 Args:
303 section: An EC section, either 'a' or 'b'.
304 """
305 self._chromeos_interface.log('Restoring EC body %s' %
306 section)
Vic Yang37a55462012-06-29 14:00:28 +0800307 self._ec_handler.restore_firmware_body(section, restore_all=True)
Tom Wai-Hong Tam81f70002011-12-13 12:29:46 +0800308
309
Tom Wai-Hong Tam0e680af2011-10-26 14:32:55 +0800310 @allow_multiple_section_input
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700311 def corrupt_firmware(self, section):
Tom Wai-Hong Tam9aea8212011-12-12 15:08:45 +0800312 """Corrupt the requested firmware section signature.
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700313
314 Args:
315 section: A firmware section, either 'a' or 'b'.
316 """
Tom Wai-Hong Tam9aea8212011-12-12 15:08:45 +0800317 self._chromeos_interface.log('Corrupting firmware signature %s' %
318 section)
Vic Yang59cac9c2012-05-21 15:28:42 +0800319 self._bios_handler.corrupt_firmware(section)
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700320
321
Tom Wai-Hong Tam0e680af2011-10-26 14:32:55 +0800322 @allow_multiple_section_input
Tom Wai-Hong Tam81f70002011-12-13 12:29:46 +0800323 def corrupt_firmware_body(self, section):
324 """Corrupt the requested firmware section body.
325
326 Args:
327 section: A firmware section, either 'a' or 'b'.
328 """
329 self._chromeos_interface.log('Corrupting firmware body %s' %
330 section)
Vic Yang59cac9c2012-05-21 15:28:42 +0800331 self._bios_handler.corrupt_firmware_body(section)
Tom Wai-Hong Tam81f70002011-12-13 12:29:46 +0800332
333
334 @allow_multiple_section_input
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700335 def restore_firmware(self, section):
Tom Wai-Hong Tam9aea8212011-12-12 15:08:45 +0800336 """Restore the previously corrupted firmware section signature.
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700337
338 Args:
339 section: A firmware section, either 'a' or 'b'.
340 """
Tom Wai-Hong Tam9aea8212011-12-12 15:08:45 +0800341 self._chromeos_interface.log('Restoring firmware signature %s' %
342 section)
Vic Yang59cac9c2012-05-21 15:28:42 +0800343 self._bios_handler.restore_firmware(section)
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700344
345
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800346 @allow_multiple_section_input
Tom Wai-Hong Tam81f70002011-12-13 12:29:46 +0800347 def restore_firmware_body(self, section):
348 """Restore the previously corrupted firmware section body.
349
350 Args:
351 section: A firmware section, either 'a' or 'b'.
352 """
353 self._chromeos_interface.log('Restoring firmware body %s' %
354 section)
Vic Yang59cac9c2012-05-21 15:28:42 +0800355 self._bios_handler.restore_firmware_body(section)
Tom Wai-Hong Tam81f70002011-12-13 12:29:46 +0800356
357
Tom Wai-Hong Tam46d03b12012-02-08 12:02:17 +0800358 def _modify_firmware_version(self, section, delta):
359 """Modify firmware version for the requested section, by adding delta.
360
361 The passed in delta, a positive or a negative number, is added to the
362 original firmware version.
363 """
Vic Yang59cac9c2012-05-21 15:28:42 +0800364 original_version = self._bios_handler.get_section_version(section)
Tom Wai-Hong Tam46d03b12012-02-08 12:02:17 +0800365 new_version = original_version + delta
Vic Yang59cac9c2012-05-21 15:28:42 +0800366 flags = self._bios_handler.get_section_flags(section)
Tom Wai-Hong Tam46d03b12012-02-08 12:02:17 +0800367 self._chromeos_interface.log(
368 'Setting firmware section %s version from %d to %d' % (
369 section, original_version, new_version))
Vic Yang59cac9c2012-05-21 15:28:42 +0800370 self._bios_handler.set_section_version(section, new_version, flags,
371 write_through=True)
Tom Wai-Hong Tam46d03b12012-02-08 12:02:17 +0800372
373 @allow_multiple_section_input
374 def move_firmware_backward(self, section):
375 """Decrement firmware version for the requested section."""
376 self._modify_firmware_version(section, -1)
377
378
379 @allow_multiple_section_input
380 def move_firmware_forward(self, section):
381 """Increase firmware version for the requested section."""
382 self._modify_firmware_version(section, 1)
383
384
Tom Wai-Hong Tam81f70002011-12-13 12:29:46 +0800385 @allow_multiple_section_input
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800386 def corrupt_kernel(self, section):
387 """Corrupt the requested kernel section.
388
389 Args:
390 section: A kernel section, either 'a' or 'b'.
391 """
392 self._chromeos_interface.log('Corrupting kernel %s' % section)
393 self._kernel_handler.corrupt_kernel(section)
394
395
396 @allow_multiple_section_input
397 def restore_kernel(self, section):
398 """Restore the requested kernel section (previously corrupted).
399
400 Args:
401 section: A kernel section, either 'a' or 'b'.
402 """
403 self._chromeos_interface.log('restoring kernel %s' % section)
404 self._kernel_handler.restore_kernel(section)
405
406
Tom Wai-Hong Tam07278c22012-02-08 16:53:00 +0800407 def _modify_kernel_version(self, section, delta):
408 """Modify kernel version for the requested section, by adding delta.
409
410 The passed in delta, a positive or a negative number, is added to the
411 original kernel version.
412 """
413 original_version = self._kernel_handler.get_version(section)
414 new_version = original_version + delta
415 self._chromeos_interface.log(
416 'Setting kernel section %s version from %d to %d' % (
417 section, original_version, new_version))
418 self._kernel_handler.set_version(section, new_version)
419
420
421 @allow_multiple_section_input
422 def move_kernel_backward(self, section):
423 """Decrement kernel version for the requested section."""
424 self._modify_kernel_version(section, -1)
425
426
427 @allow_multiple_section_input
428 def move_kernel_forward(self, section):
429 """Increase kernel version for the requested section."""
430 self._modify_kernel_version(section, 1)
431
432
Tom Wai-Hong Tam48958832011-12-30 10:16:57 +0800433 def run_cgpt_test_loop(self):
434 """Run the CgptState test loop. The tst logic is handled in the client.
435
436 Returns:
437 0: there are more cgpt tests to execute.
438 1: no more CgptState test, finished.
439 """
440 return self._cgpt_state.test_loop()
441
442
443 def set_cgpt_test_step(self, step):
444 """Set the CgptState test step.
445
446 Args:
447 step: A test step number.
448 """
449 self._cgpt_state.set_step(step)
450
451
452 def get_cgpt_test_step(self):
453 """Get the CgptState test step.
454
455 Returns:
456 A test step number.
457 """
458 return self._cgpt_state.get_step()
459
460
Tom Wai-Hong Tambea57b32011-09-02 18:27:47 +0800461 def cleanup(self):
462 """Cleanup for the RPC server. Currently nothing."""
463 pass
464
465
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700466def main():
467 parser = OptionParser(usage='Usage: %prog [options]')
468 parser.add_option('--port', type='int', dest='port', default=9990,
469 help='port number of XMLRPC server')
470 (options, args) = parser.parse_args()
471
472 faft_client = FAFTClient()
473
474 # Launch the XMLRPC server to provide FAFTClient commands.
Tom Wai-Hong Tam4a257e52011-11-12 08:36:22 +0800475 server = SimpleXMLRPCServer(('localhost', options.port), allow_none=True,
476 logRequests=False)
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700477 server.register_introspection_functions()
478 server.register_instance(faft_client)
479 print 'XMLRPC Server: Serving FAFTClient on port %s' % options.port
480 server.serve_forever()
481
482
483if __name__ == '__main__':
484 main()