blob: 99150c1b92aec7f584405841f4325edcd0873adb [file] [log] [blame]
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -07001# Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
2# 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
Tom Wai-Hong Tam0e680af2011-10-26 14:32:55 +080012import functools
Tom Wai-Hong Tam07278c22012-02-08 16:53:00 +080013import os
14import shutil
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -070015import sys
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -070016from optparse import OptionParser
17from SimpleXMLRPCServer import SimpleXMLRPCServer
18
19# Import libraries from SAFT.
Tom Wai-Hong Tamc1576b72011-11-08 11:36:16 +080020sys.path.append('/usr/local/sbin/firmware/saft')
Tom Wai-Hong Tam48958832011-12-30 10:16:57 +080021import cgpt_state
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -070022import chromeos_interface
23import flashrom_handler
24import kernel_handler
25import saft_flashrom_util
26import tpm_handler
27
28
Tom Wai-Hong Tam0e680af2011-10-26 14:32:55 +080029def allow_multiple_section_input(image_operator):
30 @functools.wraps(image_operator)
31 def wrapper(self, section):
32 if type(section) in (tuple, list):
33 for sec in section:
34 image_operator(self, sec)
35 else:
36 image_operator(self, section)
37 return wrapper
38
39
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -070040class FAFTClient(object):
41 """A class of FAFT client which aggregates some useful functions of SAFT.
42
43 This class can be exposed via a XMLRPC server such that its functions can
44 be accessed remotely.
45
46 Attributes:
47 _chromeos_interface: An object to encapsulate OS services functions.
48 _flashrom_handler: An object to automate flashrom testing.
49 _kernel_handler: An object to provide kernel related actions.
50 _tpm_handler: An object to control TPM device.
51 """
52
53 def __init__(self):
54 """Initialize the data attributes of this class."""
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -070055 # TODO(waihong): Move the explicit object.init() methods to the
56 # objects' constructors (ChromeOSInterface, FlashromHandler,
57 # KernelHandler, and TpmHandler).
58 self._chromeos_interface = chromeos_interface.ChromeOSInterface(False)
Tom Wai-Hong Tam48958832011-12-30 10:16:57 +080059 # We keep the state of FAFT test in a permanent directory over reboots.
Tom Wai-Hong Tam07278c22012-02-08 16:53:00 +080060 state_dir = '/var/tmp/faft'
61 self._chromeos_interface.init(state_dir, log_file='/tmp/faft_log.txt')
62 os.chdir(state_dir)
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -070063
64 self._flashrom_handler = flashrom_handler.FlashromHandler()
65 self._flashrom_handler.init(saft_flashrom_util,
Tom Wai-Hong Tam46d03b12012-02-08 12:02:17 +080066 self._chromeos_interface,
67 None,
68 '/usr/share/vboot/devkeys')
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -070069 self._flashrom_handler.new_image()
70
71 self._kernel_handler = kernel_handler.KernelHandler()
Tom Wai-Hong Tam07278c22012-02-08 16:53:00 +080072 # TODO(waihong): The dev_key_path is a new argument. We do that in
73 # order not to break the old image and still be able to run.
74 try:
75 self._kernel_handler.init(self._chromeos_interface,
76 dev_key_path='/usr/share/vboot/devkeys')
77 except:
78 # Copy the key to the current working directory.
79 shutil.copy('/usr/share/vboot/devkeys/kernel_data_key.vbprivk', '.')
80 self._kernel_handler.init(self._chromeos_interface)
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -070081
82 self._tpm_handler = tpm_handler.TpmHandler()
83 self._tpm_handler.init(self._chromeos_interface)
84
Tom Wai-Hong Tam48958832011-12-30 10:16:57 +080085 self._cgpt_state = cgpt_state.CgptState(
86 'AUTO', self._chromeos_interface, self.get_root_dev())
87
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -070088
Tom Wai-Hong Tame8f291a2011-12-08 22:03:53 +080089 def _dispatch(self, method, params):
90 """This _dispatch method handles string conversion especially.
91
92 Since we turn off allow_dotted_names option. So any string conversion,
93 like str(FAFTClient.method), i.e. FAFTClient.method.__str__, failed
94 via XML RPC call.
95 """
96 is_str = method.endswith('.__str__')
97 if is_str:
98 method = method.rsplit('.', 1)[0]
99 try:
100 func = getattr(self, method)
101 except AttributeError:
102 raise Exception('method "%s" is not supported' % method)
103 else:
104 if is_str:
105 return str(func)
106 else:
107 return func(*params)
108
109
Tom Wai-Hong Tambea57b32011-09-02 18:27:47 +0800110 def is_available(self):
111 """Function for polling the RPC server availability.
112
113 Returns:
114 Always True.
115 """
116 return True
117
118
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700119 def run_shell_command(self, command):
120 """Run shell command.
121
122 Args:
123 command: A shell command to be run.
124 """
125 self._chromeos_interface.log('Requesting run shell command')
126 self._chromeos_interface.run_shell_command(command)
127
128
129 def run_shell_command_get_output(self, command):
130 """Run shell command and get its console output.
131
132 Args:
133 command: A shell command to be run.
134
135 Returns:
136 A list of strings stripped of the newline characters.
137 """
138 self._chromeos_interface.log(
139 'Requesting run shell command and get its console output')
140 return self._chromeos_interface.run_shell_command_get_output(command)
141
142
143 def software_reboot(self):
144 """Request software reboot."""
145 self._chromeos_interface.log('Requesting software reboot')
146 self._chromeos_interface.run_shell_command('reboot')
147
148
Tom Wai-Hong Tam678ab152011-12-14 15:27:24 +0800149 def get_platform_name(self):
150 """Get the platform name of the current system.
151
152 Returns:
153 A string of the platform name.
154 """
155 self._chromeos_interface.log('Requesting get platform name')
156 return self._chromeos_interface.run_shell_command_get_output(
157 'mosys platform name')[0]
158
159
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700160 def get_crossystem_value(self, key):
161 """Get crossystem value of the requested key.
162
163 Args:
164 key: A crossystem key.
165
166 Returns:
167 A string of the requested crossystem value.
168 """
169 self._chromeos_interface.log('Requesting get crossystem value')
170 return self._chromeos_interface.run_shell_command_get_output(
171 'crossystem %s' % key)[0]
172
173
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800174 def get_root_dev(self):
175 """Get the name of root device without partition number.
176
177 Returns:
178 A string of the root device without partition number.
179 """
180 self._chromeos_interface.log('Requesting get root device')
181 return self._chromeos_interface.get_root_dev()
182
183
184 def get_root_part(self):
185 """Get the name of root device with partition number.
186
187 Returns:
188 A string of the root device with partition number.
189 """
190 self._chromeos_interface.log('Requesting get root part')
191 return self._chromeos_interface.get_root_part()
192
193
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700194 def set_try_fw_b(self):
195 """Set 'Try Frimware B' flag in crossystem."""
196 self._chromeos_interface.log('Requesting restart with firmware B')
197 self._chromeos_interface.cs.fwb_tries = 1
198
199
Tom Wai-Hong Tam76c75072011-10-25 18:00:12 +0800200 def request_recovery_boot(self):
201 """Request running in recovery mode on the restart."""
202 self._chromeos_interface.log('Requesting restart in recovery mode')
203 self._chromeos_interface.cs.request_recovery()
204
205
Tom Wai-Hong Tam8c9eed62011-12-28 15:05:05 +0800206 def get_gbb_flags(self):
207 """Get the GBB flags.
208
209 Returns:
210 An integer of the GBB flags.
211 """
212 self._chromeos_interface.log('Getting GBB flags')
213 return self._flashrom_handler.get_gbb_flags()
214
215
Tom Wai-Hong Tam81f70002011-12-13 12:29:46 +0800216 def get_firmware_flags(self, section):
217 """Get the preamble flags of a firmware section.
218
219 Args:
220 section: A firmware section, either 'a' or 'b'.
221
222 Returns:
223 An integer of the preamble flags.
224 """
225 self._chromeos_interface.log('Getting preamble flags of firmware %s' %
226 section)
227 return self._flashrom_handler.get_section_flags(section)
228
229
Tom Wai-Hong Tam0e680af2011-10-26 14:32:55 +0800230 @allow_multiple_section_input
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700231 def corrupt_firmware(self, section):
Tom Wai-Hong Tam9aea8212011-12-12 15:08:45 +0800232 """Corrupt the requested firmware section signature.
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700233
234 Args:
235 section: A firmware section, either 'a' or 'b'.
236 """
Tom Wai-Hong Tam9aea8212011-12-12 15:08:45 +0800237 self._chromeos_interface.log('Corrupting firmware signature %s' %
238 section)
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700239 self._flashrom_handler.corrupt_firmware(section)
240
241
Tom Wai-Hong Tam0e680af2011-10-26 14:32:55 +0800242 @allow_multiple_section_input
Tom Wai-Hong Tam81f70002011-12-13 12:29:46 +0800243 def corrupt_firmware_body(self, section):
244 """Corrupt the requested firmware section body.
245
246 Args:
247 section: A firmware section, either 'a' or 'b'.
248 """
249 self._chromeos_interface.log('Corrupting firmware body %s' %
250 section)
251 self._flashrom_handler.corrupt_firmware_body(section)
252
253
254 @allow_multiple_section_input
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700255 def restore_firmware(self, section):
Tom Wai-Hong Tam9aea8212011-12-12 15:08:45 +0800256 """Restore the previously corrupted firmware section signature.
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700257
258 Args:
259 section: A firmware section, either 'a' or 'b'.
260 """
Tom Wai-Hong Tam9aea8212011-12-12 15:08:45 +0800261 self._chromeos_interface.log('Restoring firmware signature %s' %
262 section)
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700263 self._flashrom_handler.restore_firmware(section)
264
265
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800266 @allow_multiple_section_input
Tom Wai-Hong Tam81f70002011-12-13 12:29:46 +0800267 def restore_firmware_body(self, section):
268 """Restore the previously corrupted firmware section body.
269
270 Args:
271 section: A firmware section, either 'a' or 'b'.
272 """
273 self._chromeos_interface.log('Restoring firmware body %s' %
274 section)
275 self._flashrom_handler.restore_firmware_body(section)
276
277
Tom Wai-Hong Tam46d03b12012-02-08 12:02:17 +0800278 def _modify_firmware_version(self, section, delta):
279 """Modify firmware version for the requested section, by adding delta.
280
281 The passed in delta, a positive or a negative number, is added to the
282 original firmware version.
283 """
284 original_version = self._flashrom_handler.get_section_version(section)
285 new_version = original_version + delta
286 flags = self._flashrom_handler.get_section_flags(section)
287 self._chromeos_interface.log(
288 'Setting firmware section %s version from %d to %d' % (
289 section, original_version, new_version))
290 self._flashrom_handler.set_section_version(section, new_version, flags,
291 write_through=True)
292
293 @allow_multiple_section_input
294 def move_firmware_backward(self, section):
295 """Decrement firmware version for the requested section."""
296 self._modify_firmware_version(section, -1)
297
298
299 @allow_multiple_section_input
300 def move_firmware_forward(self, section):
301 """Increase firmware version for the requested section."""
302 self._modify_firmware_version(section, 1)
303
304
Tom Wai-Hong Tam81f70002011-12-13 12:29:46 +0800305 @allow_multiple_section_input
Tom Wai-Hong Tamcfda61f2011-11-02 17:41:01 +0800306 def corrupt_kernel(self, section):
307 """Corrupt the requested kernel section.
308
309 Args:
310 section: A kernel section, either 'a' or 'b'.
311 """
312 self._chromeos_interface.log('Corrupting kernel %s' % section)
313 self._kernel_handler.corrupt_kernel(section)
314
315
316 @allow_multiple_section_input
317 def restore_kernel(self, section):
318 """Restore the requested kernel section (previously corrupted).
319
320 Args:
321 section: A kernel section, either 'a' or 'b'.
322 """
323 self._chromeos_interface.log('restoring kernel %s' % section)
324 self._kernel_handler.restore_kernel(section)
325
326
Tom Wai-Hong Tam07278c22012-02-08 16:53:00 +0800327 def _modify_kernel_version(self, section, delta):
328 """Modify kernel version for the requested section, by adding delta.
329
330 The passed in delta, a positive or a negative number, is added to the
331 original kernel version.
332 """
333 original_version = self._kernel_handler.get_version(section)
334 new_version = original_version + delta
335 self._chromeos_interface.log(
336 'Setting kernel section %s version from %d to %d' % (
337 section, original_version, new_version))
338 self._kernel_handler.set_version(section, new_version)
339
340
341 @allow_multiple_section_input
342 def move_kernel_backward(self, section):
343 """Decrement kernel version for the requested section."""
344 self._modify_kernel_version(section, -1)
345
346
347 @allow_multiple_section_input
348 def move_kernel_forward(self, section):
349 """Increase kernel version for the requested section."""
350 self._modify_kernel_version(section, 1)
351
352
Tom Wai-Hong Tam48958832011-12-30 10:16:57 +0800353 def run_cgpt_test_loop(self):
354 """Run the CgptState test loop. The tst logic is handled in the client.
355
356 Returns:
357 0: there are more cgpt tests to execute.
358 1: no more CgptState test, finished.
359 """
360 return self._cgpt_state.test_loop()
361
362
363 def set_cgpt_test_step(self, step):
364 """Set the CgptState test step.
365
366 Args:
367 step: A test step number.
368 """
369 self._cgpt_state.set_step(step)
370
371
372 def get_cgpt_test_step(self):
373 """Get the CgptState test step.
374
375 Returns:
376 A test step number.
377 """
378 return self._cgpt_state.get_step()
379
380
Tom Wai-Hong Tambea57b32011-09-02 18:27:47 +0800381 def cleanup(self):
382 """Cleanup for the RPC server. Currently nothing."""
383 pass
384
385
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700386def main():
387 parser = OptionParser(usage='Usage: %prog [options]')
388 parser.add_option('--port', type='int', dest='port', default=9990,
389 help='port number of XMLRPC server')
390 (options, args) = parser.parse_args()
391
392 faft_client = FAFTClient()
393
394 # Launch the XMLRPC server to provide FAFTClient commands.
Tom Wai-Hong Tam4a257e52011-11-12 08:36:22 +0800395 server = SimpleXMLRPCServer(('localhost', options.port), allow_none=True,
396 logRequests=False)
Tom Wai-Hong Tamb8a58ef2011-10-11 23:53:10 -0700397 server.register_introspection_functions()
398 server.register_instance(faft_client)
399 print 'XMLRPC Server: Serving FAFTClient on port %s' % options.port
400 server.serve_forever()
401
402
403if __name__ == '__main__':
404 main()