blob: 7a93085cf43102ba09b913fc98d9b8e1493f751f [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
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -070033class FAFTClient(object):
34 """A class of FAFT client which aggregates some useful functions of SAFT.
35
36 This class can be exposed via a XMLRPC server such that its functions can
37 be accessed remotely.
38
39 Attributes:
40 _chromeos_interface: An object to encapsulate OS services functions.
41 _flashrom_handler: An object to automate flashrom testing.
42 _kernel_handler: An object to provide kernel related actions.
43 _tpm_handler: An object to control TPM device.
44 """
45
46 def __init__(self):
47 """Initialize the data attributes of this class."""
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -070048 # TODO(waihong): Move the explicit object.init() methods to the
49 # objects' constructors (ChromeOSInterface, FlashromHandler,
50 # KernelHandler, and TpmHandler).
51 self._chromeos_interface = chromeos_interface.ChromeOSInterface(False)
Tom Wai-Hong Tam48958832011-12-30 10:16:57 +080052 # We keep the state of FAFT test in a permanent directory over reboots.
Tom Wai-Hong Tam07278c22012-02-08 16:53:00 +080053 state_dir = '/var/tmp/faft'
54 self._chromeos_interface.init(state_dir, log_file='/tmp/faft_log.txt')
55 os.chdir(state_dir)
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -070056
57 self._flashrom_handler = flashrom_handler.FlashromHandler()
58 self._flashrom_handler.init(saft_flashrom_util,
Tom Wai-Hong Tam46d03b12012-02-08 12:02:17 +080059 self._chromeos_interface,
60 None,
61 '/usr/share/vboot/devkeys')
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -070062 self._flashrom_handler.new_image()
63
64 self._kernel_handler = kernel_handler.KernelHandler()
Tom Wai-Hong Tam07278c22012-02-08 16:53:00 +080065 # TODO(waihong): The dev_key_path is a new argument. We do that in
66 # order not to break the old image and still be able to run.
67 try:
68 self._kernel_handler.init(self._chromeos_interface,
69 dev_key_path='/usr/share/vboot/devkeys')
70 except:
71 # Copy the key to the current working directory.
72 shutil.copy('/usr/share/vboot/devkeys/kernel_data_key.vbprivk', '.')
73 self._kernel_handler.init(self._chromeos_interface)
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -070074
75 self._tpm_handler = tpm_handler.TpmHandler()
76 self._tpm_handler.init(self._chromeos_interface)
77
Tom Wai-Hong Tam48958832011-12-30 10:16:57 +080078 self._cgpt_state = cgpt_state.CgptState(
79 'AUTO', self._chromeos_interface, self.get_root_dev())
80
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -070081
Tom Wai-Hong Tame8f291a2011-12-08 22:03:53 +080082 def _dispatch(self, method, params):
83 """This _dispatch method handles string conversion especially.
84
85 Since we turn off allow_dotted_names option. So any string conversion,
86 like str(FAFTClient.method), i.e. FAFTClient.method.__str__, failed
87 via XML RPC call.
88 """
89 is_str = method.endswith('.__str__')
90 if is_str:
91 method = method.rsplit('.', 1)[0]
92 try:
93 func = getattr(self, method)
94 except AttributeError:
95 raise Exception('method "%s" is not supported' % method)
96 else:
97 if is_str:
98 return str(func)
99 else:
100 return func(*params)
101
102
Tom Wai-Hong Tambea57b32011-09-02 18:27:47 +0800103 def is_available(self):
104 """Function for polling the RPC server availability.
105
106 Returns:
107 Always True.
108 """
109 return True
110
111
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700112 def run_shell_command(self, command):
113 """Run shell command.
114
115 Args:
116 command: A shell command to be run.
117 """
118 self._chromeos_interface.log('Requesting run shell command')
119 self._chromeos_interface.run_shell_command(command)
120
121
122 def run_shell_command_get_output(self, command):
123 """Run shell command and get its console output.
124
125 Args:
126 command: A shell command to be run.
127
128 Returns:
129 A list of strings stripped of the newline characters.
130 """
131 self._chromeos_interface.log(
132 'Requesting run shell command and get its console output')
133 return self._chromeos_interface.run_shell_command_get_output(command)
134
135
136 def software_reboot(self):
137 """Request software reboot."""
138 self._chromeos_interface.log('Requesting software reboot')
139 self._chromeos_interface.run_shell_command('reboot')
140
141
Tom Wai-Hong Tam678ab152011-12-14 15:27:24 +0800142 def get_platform_name(self):
143 """Get the platform name of the current system.
144
145 Returns:
146 A string of the platform name.
147 """
148 self._chromeos_interface.log('Requesting get platform name')
149 return self._chromeos_interface.run_shell_command_get_output(
150 'mosys platform name')[0]
151
152
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700153 def get_crossystem_value(self, key):
154 """Get crossystem value of the requested key.
155
156 Args:
157 key: A crossystem key.
158
159 Returns:
160 A string of the requested crossystem value.
161 """
162 self._chromeos_interface.log('Requesting get crossystem value')
163 return self._chromeos_interface.run_shell_command_get_output(
164 'crossystem %s' % key)[0]
165
166
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800167 def get_root_dev(self):
168 """Get the name of root device without partition number.
169
170 Returns:
171 A string of the root device without partition number.
172 """
173 self._chromeos_interface.log('Requesting get root device')
174 return self._chromeos_interface.get_root_dev()
175
176
177 def get_root_part(self):
178 """Get the name of root device with partition number.
179
180 Returns:
181 A string of the root device with partition number.
182 """
183 self._chromeos_interface.log('Requesting get root part')
184 return self._chromeos_interface.get_root_part()
185
186
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700187 def set_try_fw_b(self):
188 """Set 'Try Frimware B' flag in crossystem."""
189 self._chromeos_interface.log('Requesting restart with firmware B')
190 self._chromeos_interface.cs.fwb_tries = 1
191
192
Tom Wai-Hong Tam76c75072011-10-25 18:00:12 +0800193 def request_recovery_boot(self):
194 """Request running in recovery mode on the restart."""
195 self._chromeos_interface.log('Requesting restart in recovery mode')
196 self._chromeos_interface.cs.request_recovery()
197
198
Tom Wai-Hong Tam8c9eed62011-12-28 15:05:05 +0800199 def get_gbb_flags(self):
200 """Get the GBB flags.
201
202 Returns:
203 An integer of the GBB flags.
204 """
205 self._chromeos_interface.log('Getting GBB flags')
206 return self._flashrom_handler.get_gbb_flags()
207
208
Tom Wai-Hong Tam81f70002011-12-13 12:29:46 +0800209 def get_firmware_flags(self, section):
210 """Get the preamble flags of a firmware section.
211
212 Args:
213 section: A firmware section, either 'a' or 'b'.
214
215 Returns:
216 An integer of the preamble flags.
217 """
218 self._chromeos_interface.log('Getting preamble flags of firmware %s' %
219 section)
220 return self._flashrom_handler.get_section_flags(section)
221
222
Tom Wai-Hong Tam0e680af2011-10-26 14:32:55 +0800223 @allow_multiple_section_input
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700224 def corrupt_firmware(self, section):
Tom Wai-Hong Tam9aea8212011-12-12 15:08:45 +0800225 """Corrupt the requested firmware section signature.
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700226
227 Args:
228 section: A firmware section, either 'a' or 'b'.
229 """
Tom Wai-Hong Tam9aea8212011-12-12 15:08:45 +0800230 self._chromeos_interface.log('Corrupting firmware signature %s' %
231 section)
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700232 self._flashrom_handler.corrupt_firmware(section)
233
234
Tom Wai-Hong Tam0e680af2011-10-26 14:32:55 +0800235 @allow_multiple_section_input
Tom Wai-Hong Tam81f70002011-12-13 12:29:46 +0800236 def corrupt_firmware_body(self, section):
237 """Corrupt the requested firmware section body.
238
239 Args:
240 section: A firmware section, either 'a' or 'b'.
241 """
242 self._chromeos_interface.log('Corrupting firmware body %s' %
243 section)
244 self._flashrom_handler.corrupt_firmware_body(section)
245
246
247 @allow_multiple_section_input
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700248 def restore_firmware(self, section):
Tom Wai-Hong Tam9aea8212011-12-12 15:08:45 +0800249 """Restore the previously corrupted firmware section signature.
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700250
251 Args:
252 section: A firmware section, either 'a' or 'b'.
253 """
Tom Wai-Hong Tam9aea8212011-12-12 15:08:45 +0800254 self._chromeos_interface.log('Restoring firmware signature %s' %
255 section)
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700256 self._flashrom_handler.restore_firmware(section)
257
258
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800259 @allow_multiple_section_input
Tom Wai-Hong Tam81f70002011-12-13 12:29:46 +0800260 def restore_firmware_body(self, section):
261 """Restore the previously corrupted firmware section body.
262
263 Args:
264 section: A firmware section, either 'a' or 'b'.
265 """
266 self._chromeos_interface.log('Restoring firmware body %s' %
267 section)
268 self._flashrom_handler.restore_firmware_body(section)
269
270
Tom Wai-Hong Tam46d03b12012-02-08 12:02:17 +0800271 def _modify_firmware_version(self, section, delta):
272 """Modify firmware version for the requested section, by adding delta.
273
274 The passed in delta, a positive or a negative number, is added to the
275 original firmware version.
276 """
277 original_version = self._flashrom_handler.get_section_version(section)
278 new_version = original_version + delta
279 flags = self._flashrom_handler.get_section_flags(section)
280 self._chromeos_interface.log(
281 'Setting firmware section %s version from %d to %d' % (
282 section, original_version, new_version))
283 self._flashrom_handler.set_section_version(section, new_version, flags,
284 write_through=True)
285
286 @allow_multiple_section_input
287 def move_firmware_backward(self, section):
288 """Decrement firmware version for the requested section."""
289 self._modify_firmware_version(section, -1)
290
291
292 @allow_multiple_section_input
293 def move_firmware_forward(self, section):
294 """Increase firmware version for the requested section."""
295 self._modify_firmware_version(section, 1)
296
297
Tom Wai-Hong Tam81f70002011-12-13 12:29:46 +0800298 @allow_multiple_section_input
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800299 def corrupt_kernel(self, section):
300 """Corrupt the requested kernel section.
301
302 Args:
303 section: A kernel section, either 'a' or 'b'.
304 """
305 self._chromeos_interface.log('Corrupting kernel %s' % section)
306 self._kernel_handler.corrupt_kernel(section)
307
308
309 @allow_multiple_section_input
310 def restore_kernel(self, section):
311 """Restore the requested kernel section (previously corrupted).
312
313 Args:
314 section: A kernel section, either 'a' or 'b'.
315 """
316 self._chromeos_interface.log('restoring kernel %s' % section)
317 self._kernel_handler.restore_kernel(section)
318
319
Tom Wai-Hong Tam07278c22012-02-08 16:53:00 +0800320 def _modify_kernel_version(self, section, delta):
321 """Modify kernel version for the requested section, by adding delta.
322
323 The passed in delta, a positive or a negative number, is added to the
324 original kernel version.
325 """
326 original_version = self._kernel_handler.get_version(section)
327 new_version = original_version + delta
328 self._chromeos_interface.log(
329 'Setting kernel section %s version from %d to %d' % (
330 section, original_version, new_version))
331 self._kernel_handler.set_version(section, new_version)
332
333
334 @allow_multiple_section_input
335 def move_kernel_backward(self, section):
336 """Decrement kernel version for the requested section."""
337 self._modify_kernel_version(section, -1)
338
339
340 @allow_multiple_section_input
341 def move_kernel_forward(self, section):
342 """Increase kernel version for the requested section."""
343 self._modify_kernel_version(section, 1)
344
345
Tom Wai-Hong Tam48958832011-12-30 10:16:57 +0800346 def run_cgpt_test_loop(self):
347 """Run the CgptState test loop. The tst logic is handled in the client.
348
349 Returns:
350 0: there are more cgpt tests to execute.
351 1: no more CgptState test, finished.
352 """
353 return self._cgpt_state.test_loop()
354
355
356 def set_cgpt_test_step(self, step):
357 """Set the CgptState test step.
358
359 Args:
360 step: A test step number.
361 """
362 self._cgpt_state.set_step(step)
363
364
365 def get_cgpt_test_step(self):
366 """Get the CgptState test step.
367
368 Returns:
369 A test step number.
370 """
371 return self._cgpt_state.get_step()
372
373
Tom Wai-Hong Tambea57b32011-09-02 18:27:47 +0800374 def cleanup(self):
375 """Cleanup for the RPC server. Currently nothing."""
376 pass
377
378
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700379def main():
380 parser = OptionParser(usage='Usage: %prog [options]')
381 parser.add_option('--port', type='int', dest='port', default=9990,
382 help='port number of XMLRPC server')
383 (options, args) = parser.parse_args()
384
385 faft_client = FAFTClient()
386
387 # Launch the XMLRPC server to provide FAFTClient commands.
Tom Wai-Hong Tam4a257e52011-11-12 08:36:22 +0800388 server = SimpleXMLRPCServer(('localhost', options.port), allow_none=True,
389 logRequests=False)
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700390 server.register_introspection_functions()
391 server.register_instance(faft_client)
392 print 'XMLRPC Server: Serving FAFTClient on port %s' % options.port
393 server.serve_forever()
394
395
396if __name__ == '__main__':
397 main()