blob: c1f09bc2e80aa71fddec3666f89c0f97b3689ab4 [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
52
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -070053class FAFTClient(object):
54 """A class of FAFT client which aggregates some useful functions of SAFT.
55
56 This class can be exposed via a XMLRPC server such that its functions can
57 be accessed remotely.
58
59 Attributes:
60 _chromeos_interface: An object to encapsulate OS services functions.
Vic Yang59cac9c2012-05-21 15:28:42 +080061 _bios_handler: An object to automate BIOS flashrom testing.
62 _ec_handler: An object to automate EC flashrom testing.
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -070063 _kernel_handler: An object to provide kernel related actions.
64 _tpm_handler: An object to control TPM device.
65 """
66
67 def __init__(self):
68 """Initialize the data attributes of this class."""
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -070069 # TODO(waihong): Move the explicit object.init() methods to the
70 # objects' constructors (ChromeOSInterface, FlashromHandler,
71 # KernelHandler, and TpmHandler).
72 self._chromeos_interface = chromeos_interface.ChromeOSInterface(False)
Tom Wai-Hong Tam48958832011-12-30 10:16:57 +080073 # We keep the state of FAFT test in a permanent directory over reboots.
Tom Wai-Hong Tam07278c22012-02-08 16:53:00 +080074 state_dir = '/var/tmp/faft'
75 self._chromeos_interface.init(state_dir, log_file='/tmp/faft_log.txt')
76 os.chdir(state_dir)
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -070077
Vic Yang13d22ec2012-06-18 15:12:47 +080078 self._bios_handler = LazyFlashromHandlerProxy(
79 saft_flashrom_util,
Vic Yang59cac9c2012-05-21 15:28:42 +080080 self._chromeos_interface,
81 None,
82 '/usr/share/vboot/devkeys',
83 'bios')
Vic Yang59cac9c2012-05-21 15:28:42 +080084
Todd Brochf2b1d012012-06-14 12:55:21 -070085 self._ec_handler = None
86 if not os.system("mosys ec info"):
Vic Yang13d22ec2012-06-18 15:12:47 +080087 self._ec_handler = LazyFlashromHandlerProxy(
88 saft_flashrom_util,
Todd Brochf2b1d012012-06-14 12:55:21 -070089 self._chromeos_interface,
Vic Yang13d22ec2012-06-18 15:12:47 +080090 'ec_root_key.vpubk',
Todd Brochf2b1d012012-06-14 12:55:21 -070091 '/usr/share/vboot/devkeys',
92 'ec')
Todd Brochf2b1d012012-06-14 12:55:21 -070093
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -070094
95 self._kernel_handler = kernel_handler.KernelHandler()
Tom Wai-Hong Tam07278c22012-02-08 16:53:00 +080096 # TODO(waihong): The dev_key_path is a new argument. We do that in
97 # order not to break the old image and still be able to run.
98 try:
99 self._kernel_handler.init(self._chromeos_interface,
100 dev_key_path='/usr/share/vboot/devkeys')
101 except:
102 # Copy the key to the current working directory.
103 shutil.copy('/usr/share/vboot/devkeys/kernel_data_key.vbprivk', '.')
104 self._kernel_handler.init(self._chromeos_interface)
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700105
106 self._tpm_handler = tpm_handler.TpmHandler()
107 self._tpm_handler.init(self._chromeos_interface)
108
Tom Wai-Hong Tam48958832011-12-30 10:16:57 +0800109 self._cgpt_state = cgpt_state.CgptState(
110 'AUTO', self._chromeos_interface, self.get_root_dev())
111
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700112
Tom Wai-Hong Tame8f291a2011-12-08 22:03:53 +0800113 def _dispatch(self, method, params):
114 """This _dispatch method handles string conversion especially.
115
116 Since we turn off allow_dotted_names option. So any string conversion,
117 like str(FAFTClient.method), i.e. FAFTClient.method.__str__, failed
118 via XML RPC call.
119 """
120 is_str = method.endswith('.__str__')
121 if is_str:
122 method = method.rsplit('.', 1)[0]
123 try:
124 func = getattr(self, method)
125 except AttributeError:
126 raise Exception('method "%s" is not supported' % method)
127 else:
128 if is_str:
129 return str(func)
130 else:
131 return func(*params)
132
133
Tom Wai-Hong Tambea57b32011-09-02 18:27:47 +0800134 def is_available(self):
135 """Function for polling the RPC server availability.
136
137 Returns:
138 Always True.
139 """
140 return True
141
142
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700143 def run_shell_command(self, command):
144 """Run shell command.
145
146 Args:
147 command: A shell command to be run.
148 """
149 self._chromeos_interface.log('Requesting run shell command')
150 self._chromeos_interface.run_shell_command(command)
151
152
153 def run_shell_command_get_output(self, command):
154 """Run shell command and get its console output.
155
156 Args:
157 command: A shell command to be run.
158
159 Returns:
160 A list of strings stripped of the newline characters.
161 """
162 self._chromeos_interface.log(
163 'Requesting run shell command and get its console output')
164 return self._chromeos_interface.run_shell_command_get_output(command)
165
166
167 def software_reboot(self):
168 """Request software reboot."""
169 self._chromeos_interface.log('Requesting software reboot')
170 self._chromeos_interface.run_shell_command('reboot')
171
172
Tom Wai-Hong Tam678ab152011-12-14 15:27:24 +0800173 def get_platform_name(self):
174 """Get the platform name of the current system.
175
176 Returns:
177 A string of the platform name.
178 """
179 self._chromeos_interface.log('Requesting get platform name')
180 return self._chromeos_interface.run_shell_command_get_output(
181 'mosys platform name')[0]
182
183
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700184 def get_crossystem_value(self, key):
185 """Get crossystem value of the requested key.
186
187 Args:
188 key: A crossystem key.
189
190 Returns:
191 A string of the requested crossystem value.
192 """
193 self._chromeos_interface.log('Requesting get crossystem value')
194 return self._chromeos_interface.run_shell_command_get_output(
195 'crossystem %s' % key)[0]
196
197
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800198 def get_root_dev(self):
199 """Get the name of root device without partition number.
200
201 Returns:
202 A string of the root device without partition number.
203 """
204 self._chromeos_interface.log('Requesting get root device')
205 return self._chromeos_interface.get_root_dev()
206
207
208 def get_root_part(self):
209 """Get the name of root device with partition number.
210
211 Returns:
212 A string of the root device with partition number.
213 """
214 self._chromeos_interface.log('Requesting get root part')
215 return self._chromeos_interface.get_root_part()
216
217
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700218 def set_try_fw_b(self):
219 """Set 'Try Frimware B' flag in crossystem."""
220 self._chromeos_interface.log('Requesting restart with firmware B')
221 self._chromeos_interface.cs.fwb_tries = 1
222
223
Tom Wai-Hong Tam76c75072011-10-25 18:00:12 +0800224 def request_recovery_boot(self):
225 """Request running in recovery mode on the restart."""
226 self._chromeos_interface.log('Requesting restart in recovery mode')
227 self._chromeos_interface.cs.request_recovery()
228
229
Tom Wai-Hong Tam8c9eed62011-12-28 15:05:05 +0800230 def get_gbb_flags(self):
231 """Get the GBB flags.
232
233 Returns:
234 An integer of the GBB flags.
235 """
236 self._chromeos_interface.log('Getting GBB flags')
Vic Yang59cac9c2012-05-21 15:28:42 +0800237 return self._bios_handler.get_gbb_flags()
Tom Wai-Hong Tam8c9eed62011-12-28 15:05:05 +0800238
239
Tom Wai-Hong Tam81f70002011-12-13 12:29:46 +0800240 def get_firmware_flags(self, section):
241 """Get the preamble flags of a firmware section.
242
243 Args:
244 section: A firmware section, either 'a' or 'b'.
245
246 Returns:
247 An integer of the preamble flags.
248 """
249 self._chromeos_interface.log('Getting preamble flags of firmware %s' %
250 section)
Vic Yang59cac9c2012-05-21 15:28:42 +0800251 return self._bios_handler.get_section_flags(section)
252
253
254 @allow_multiple_section_input
255 def corrupt_EC(self, section):
256 """Corrupt the requested EC section signature.
257
258 Args:
259 section: A EC section, either 'a' or 'b'.
260 """
261 self._chromeos_interface.log('Corrupting EC signature %s' %
262 section)
Vic Yang37a55462012-06-29 14:00:28 +0800263 self._ec_handler.corrupt_firmware(section, corrupt_all=True)
Vic Yang59cac9c2012-05-21 15:28:42 +0800264
265
266 @allow_multiple_section_input
267 def corrupt_EC_body(self, section):
268 """Corrupt the requested EC section body.
269
270 Args:
271 section: An EC section, either 'a' or 'b'.
272 """
273 self._chromeos_interface.log('Corrupting EC body %s' %
274 section)
Vic Yang37a55462012-06-29 14:00:28 +0800275 self._ec_handler.corrupt_firmware_body(section, corrupt_all=True)
Vic Yang59cac9c2012-05-21 15:28:42 +0800276
277
278 @allow_multiple_section_input
279 def restore_EC(self, section):
280 """Restore the previously corrupted EC section signature.
281
282 Args:
283 section: An EC section, either 'a' or 'b'.
284 """
285 self._chromeos_interface.log('Restoring EC signature %s' %
286 section)
Vic Yang37a55462012-06-29 14:00:28 +0800287 self._ec_handler.restore_firmware(section, restore_all=True)
Vic Yang59cac9c2012-05-21 15:28:42 +0800288
289
290 @allow_multiple_section_input
291 def restore_EC_body(self, section):
292 """Restore the previously corrupted EC section body.
293
294 Args:
295 section: An EC section, either 'a' or 'b'.
296 """
297 self._chromeos_interface.log('Restoring EC body %s' %
298 section)
Vic Yang37a55462012-06-29 14:00:28 +0800299 self._ec_handler.restore_firmware_body(section, restore_all=True)
Tom Wai-Hong Tam81f70002011-12-13 12:29:46 +0800300
301
Tom Wai-Hong Tam0e680af2011-10-26 14:32:55 +0800302 @allow_multiple_section_input
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700303 def corrupt_firmware(self, section):
Tom Wai-Hong Tam9aea8212011-12-12 15:08:45 +0800304 """Corrupt the requested firmware section signature.
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700305
306 Args:
307 section: A firmware section, either 'a' or 'b'.
308 """
Tom Wai-Hong Tam9aea8212011-12-12 15:08:45 +0800309 self._chromeos_interface.log('Corrupting firmware signature %s' %
310 section)
Vic Yang59cac9c2012-05-21 15:28:42 +0800311 self._bios_handler.corrupt_firmware(section)
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700312
313
Tom Wai-Hong Tam0e680af2011-10-26 14:32:55 +0800314 @allow_multiple_section_input
Tom Wai-Hong Tam81f70002011-12-13 12:29:46 +0800315 def corrupt_firmware_body(self, section):
316 """Corrupt the requested firmware section body.
317
318 Args:
319 section: A firmware section, either 'a' or 'b'.
320 """
321 self._chromeos_interface.log('Corrupting firmware body %s' %
322 section)
Vic Yang59cac9c2012-05-21 15:28:42 +0800323 self._bios_handler.corrupt_firmware_body(section)
Tom Wai-Hong Tam81f70002011-12-13 12:29:46 +0800324
325
326 @allow_multiple_section_input
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700327 def restore_firmware(self, section):
Tom Wai-Hong Tam9aea8212011-12-12 15:08:45 +0800328 """Restore the previously corrupted firmware section signature.
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700329
330 Args:
331 section: A firmware section, either 'a' or 'b'.
332 """
Tom Wai-Hong Tam9aea8212011-12-12 15:08:45 +0800333 self._chromeos_interface.log('Restoring firmware signature %s' %
334 section)
Vic Yang59cac9c2012-05-21 15:28:42 +0800335 self._bios_handler.restore_firmware(section)
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700336
337
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800338 @allow_multiple_section_input
Tom Wai-Hong Tam81f70002011-12-13 12:29:46 +0800339 def restore_firmware_body(self, section):
340 """Restore the previously corrupted firmware section body.
341
342 Args:
343 section: A firmware section, either 'a' or 'b'.
344 """
345 self._chromeos_interface.log('Restoring firmware body %s' %
346 section)
Vic Yang59cac9c2012-05-21 15:28:42 +0800347 self._bios_handler.restore_firmware_body(section)
Tom Wai-Hong Tam81f70002011-12-13 12:29:46 +0800348
349
Tom Wai-Hong Tam46d03b12012-02-08 12:02:17 +0800350 def _modify_firmware_version(self, section, delta):
351 """Modify firmware version for the requested section, by adding delta.
352
353 The passed in delta, a positive or a negative number, is added to the
354 original firmware version.
355 """
Vic Yang59cac9c2012-05-21 15:28:42 +0800356 original_version = self._bios_handler.get_section_version(section)
Tom Wai-Hong Tam46d03b12012-02-08 12:02:17 +0800357 new_version = original_version + delta
Vic Yang59cac9c2012-05-21 15:28:42 +0800358 flags = self._bios_handler.get_section_flags(section)
Tom Wai-Hong Tam46d03b12012-02-08 12:02:17 +0800359 self._chromeos_interface.log(
360 'Setting firmware section %s version from %d to %d' % (
361 section, original_version, new_version))
Vic Yang59cac9c2012-05-21 15:28:42 +0800362 self._bios_handler.set_section_version(section, new_version, flags,
363 write_through=True)
Tom Wai-Hong Tam46d03b12012-02-08 12:02:17 +0800364
365 @allow_multiple_section_input
366 def move_firmware_backward(self, section):
367 """Decrement firmware version for the requested section."""
368 self._modify_firmware_version(section, -1)
369
370
371 @allow_multiple_section_input
372 def move_firmware_forward(self, section):
373 """Increase firmware version for the requested section."""
374 self._modify_firmware_version(section, 1)
375
376
Tom Wai-Hong Tam81f70002011-12-13 12:29:46 +0800377 @allow_multiple_section_input
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800378 def corrupt_kernel(self, section):
379 """Corrupt the requested kernel section.
380
381 Args:
382 section: A kernel section, either 'a' or 'b'.
383 """
384 self._chromeos_interface.log('Corrupting kernel %s' % section)
385 self._kernel_handler.corrupt_kernel(section)
386
387
388 @allow_multiple_section_input
389 def restore_kernel(self, section):
390 """Restore the requested kernel section (previously corrupted).
391
392 Args:
393 section: A kernel section, either 'a' or 'b'.
394 """
395 self._chromeos_interface.log('restoring kernel %s' % section)
396 self._kernel_handler.restore_kernel(section)
397
398
Tom Wai-Hong Tam07278c22012-02-08 16:53:00 +0800399 def _modify_kernel_version(self, section, delta):
400 """Modify kernel version for the requested section, by adding delta.
401
402 The passed in delta, a positive or a negative number, is added to the
403 original kernel version.
404 """
405 original_version = self._kernel_handler.get_version(section)
406 new_version = original_version + delta
407 self._chromeos_interface.log(
408 'Setting kernel section %s version from %d to %d' % (
409 section, original_version, new_version))
410 self._kernel_handler.set_version(section, new_version)
411
412
413 @allow_multiple_section_input
414 def move_kernel_backward(self, section):
415 """Decrement kernel version for the requested section."""
416 self._modify_kernel_version(section, -1)
417
418
419 @allow_multiple_section_input
420 def move_kernel_forward(self, section):
421 """Increase kernel version for the requested section."""
422 self._modify_kernel_version(section, 1)
423
424
Tom Wai-Hong Tam48958832011-12-30 10:16:57 +0800425 def run_cgpt_test_loop(self):
426 """Run the CgptState test loop. The tst logic is handled in the client.
427
428 Returns:
429 0: there are more cgpt tests to execute.
430 1: no more CgptState test, finished.
431 """
432 return self._cgpt_state.test_loop()
433
434
435 def set_cgpt_test_step(self, step):
436 """Set the CgptState test step.
437
438 Args:
439 step: A test step number.
440 """
441 self._cgpt_state.set_step(step)
442
443
444 def get_cgpt_test_step(self):
445 """Get the CgptState test step.
446
447 Returns:
448 A test step number.
449 """
450 return self._cgpt_state.get_step()
451
452
Tom Wai-Hong Tambea57b32011-09-02 18:27:47 +0800453 def cleanup(self):
454 """Cleanup for the RPC server. Currently nothing."""
455 pass
456
457
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700458def main():
459 parser = OptionParser(usage='Usage: %prog [options]')
460 parser.add_option('--port', type='int', dest='port', default=9990,
461 help='port number of XMLRPC server')
462 (options, args) = parser.parse_args()
463
464 faft_client = FAFTClient()
465
466 # Launch the XMLRPC server to provide FAFTClient commands.
Tom Wai-Hong Tam4a257e52011-11-12 08:36:22 +0800467 server = SimpleXMLRPCServer(('localhost', options.port), allow_none=True,
468 logRequests=False)
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700469 server.register_introspection_functions()
470 server.register_instance(faft_client)
471 print 'XMLRPC Server: Serving FAFTClient on port %s' % options.port
472 server.serve_forever()
473
474
475if __name__ == '__main__':
476 main()