blob: 36c81a634281e082637f568795a7ebe190db84c5 [file] [log] [blame]
ctchang38ae4922012-09-03 17:01:16 +08001#!/usr/bin/python
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +08002# Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +08006"""A module to support automated testing of ChromeOS firmware.
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +08007
8Utilizes services provided by saft_flashrom_util.py read/write the
9flashrom chip and to parse the flash rom image.
10
11See docstring for FlashromHandler class below.
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +080012"""
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +080013
14import hashlib
15import os
16import struct
17
18class FvSection(object):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +080019 """An object to hold information about a firmware section.
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +080020
21 This includes file names for the signature header and the body, and the
22 version number.
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +080023 """
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +080024
25 def __init__(self, sig_name, body_name):
26 self._sig_name = sig_name
27 self._body_name = body_name
28 self._version = -1 # Is not set on construction.
29 self._flags = 0 # Is not set on construction.
30 self._sha = None # Is not set on construction.
ctchang38ae4922012-09-03 17:01:16 +080031 self._sig_sha = None # Is not set on construction.
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +080032 self._datakey_version = -1 # Is not set on construction.
33 self._kernel_subkey_version = -1 # Is not set on construction.
34
35 def names(self):
36 return (self._sig_name, self._body_name)
37
38 def get_sig_name(self):
39 return self._sig_name
40
41 def get_body_name(self):
42 return self._body_name
43
44 def get_version(self):
45 return self._version
46
47 def get_flags(self):
48 return self._flags
49
50 def get_sha(self):
51 return self._sha
52
ctchang38ae4922012-09-03 17:01:16 +080053 def get_sig_sha(self):
54 return self._sig_sha
55
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +080056 def get_datakey_version(self):
57 return self._datakey_version
58
59 def get_kernel_subkey_version(self):
60 return self._kernel_subkey_version
61
62 def set_version(self, version):
63 self._version = version
64
65 def set_flags(self, flags):
66 self._flags = flags
67
68 def set_sha(self, sha):
69 self._sha = sha
70
ctchang38ae4922012-09-03 17:01:16 +080071 def set_sig_sha(self, sha):
72 self._sig_sha = sha
73
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +080074 def set_datakey_version(self, version):
75 self._datakey_version = version
76
77 def set_kernel_subkey_version(self, version):
78 self._kernel_subkey_version = version
79
80class FlashromHandlerError(Exception):
81 pass
82
83
84class FlashromHandler(object):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +080085 """An object to provide logical services for automated flashrom testing."""
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +080086
87 DELTA = 1 # value to add to a byte to corrupt a section contents
88
89 # File in the state directory to store public root key.
90 PUB_KEY_FILE_NAME = 'root.pubkey'
91 FW_KEYBLOCK_FILE_NAME = 'firmware.keyblock'
92 FW_PRIV_DATA_KEY_FILE_NAME = 'firmware_data_key.vbprivk'
93 KERNEL_SUBKEY_FILE_NAME = 'kernel_subkey.vbpubk'
94
95 def __init__(self):
96 # make sure it does not accidentally overwrite the image.
97 self.fum = None
98 self.chros_if = None
99 self.image = ''
100 self.pub_key_file = ''
101
102 def init(self, flashrom_util_module,
103 chros_if,
104 pub_key_file=None,
105 dev_key_path='./',
106 target='bios'):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800107 """Flashrom handler initializer.
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800108
109 Args:
110 flashrom_util_module - a module providing flashrom access utilities.
111 chros_if - a module providing interface to Chromium OS services
112 pub_key_file - a string, name of the file contaning a public key to
113 use for verifying both existing and new firmware.
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800114 """
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800115 if target == 'bios':
116 self.fum = flashrom_util_module.flashrom_util(target_is_ec=False)
117 self.fv_sections = {
118 'a': FvSection('VBOOTA', 'FVMAIN'),
119 'b': FvSection('VBOOTB', 'FVMAINB'),
120 }
121 elif target == 'ec':
122 self.fum = flashrom_util_module.flashrom_util(target_is_ec=True)
123 self.fv_sections = {
124 'rw': FvSection(None, 'EC_RW'),
125 }
126 else:
127 raise FlashromHandlerError("Invalid target.")
128 self.chros_if = chros_if
129 self.pub_key_file = pub_key_file
130 self.dev_key_path = dev_key_path
131
132 def new_image(self, image_file=None):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800133 """Parse the full flashrom image and store sections into files.
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800134
135 Args:
136 image_file - a string, the name of the file contaning full ChromeOS
137 flashrom image. If not passed in or empty - the actual
138 flashrom is read and its contents are saved into a
139 temporary file which is used instead.
140
141 The input file is parsed and the sections of importance (as defined in
142 self.fv_sections) are saved in separate files in the state directory
143 as defined in the chros_if object.
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800144 """
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800145
146 if image_file:
147 self.image = open(image_file, 'rb').read()
148 self.fum.set_firmware_layout(image_file)
149 else:
150 self.image = self.fum.read_whole()
151
152 for section in self.fv_sections.itervalues():
153 for subsection_name in section.names():
154 if not subsection_name:
155 continue
156 f = open(self.chros_if.state_dir_file(subsection_name), 'wb')
157 f.write(self.fum.get_section(self.image, subsection_name))
158 f.close()
159
160 s = hashlib.sha1()
161 s.update(self.fum.get_section(self.image, section.get_body_name()))
162 section.set_sha(s.hexdigest())
163
164 # If there is no "sig" subsection, skip reading version and flags.
165 if not section.get_sig_name():
166 continue
167
168 # Now determine this section's version number.
169 vb_section = self.fum.get_section(
170 self.image, section.get_sig_name())
171
172 section.set_version(self.chros_if.retrieve_body_version(vb_section))
173 section.set_flags(self.chros_if.retrieve_preamble_flags(vb_section))
174 section.set_datakey_version(
175 self.chros_if.retrieve_datakey_version(vb_section))
176 section.set_kernel_subkey_version(
177 self.chros_if.retrieve_kernel_subkey_version(vb_section))
178
ctchang38ae4922012-09-03 17:01:16 +0800179 s = hashlib.sha1()
180 s.update(self.fum.get_section(self.image, section.get_sig_name()))
181 section.set_sig_sha(s.hexdigest())
182
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800183 if not self.pub_key_file:
184 self._retrieve_pub_key()
185
186 def _retrieve_pub_key(self):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800187 """Retrieve root public key from the firmware GBB section."""
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800188
189 gbb_header_format = '<4s20s2I'
190 pubk_header_format = '<2Q'
191
192 gbb_section = self.fum.get_section(self.image, 'FV_GBB')
193
194 # do some sanity checks
195 try:
196 sig, _, rootk_offs, rootk_size = struct.unpack_from(
197 gbb_header_format, gbb_section)
198 except struct.error, e:
199 raise FlashromHandlerError(e)
200
201 if sig != '$GBB' or (rootk_offs + rootk_size) > len(gbb_section):
202 raise FlashromHandlerError('Bad gbb header')
203
204 key_body_offset, key_body_size = struct.unpack_from(
205 pubk_header_format, gbb_section, rootk_offs)
206
207 # Generally speaking the offset field can be anything, but in case of
208 # GBB section the key is stored as a standalone entity, so the offset
209 # of the key body is expected to be equal to the key header size of
210 # 0x20.
211 # Should this convention change, the check below would fail, which
212 # would be a good prompt for revisiting this test's behavior and
213 # algorithms.
214 if key_body_offset != 0x20 or key_body_size > rootk_size:
215 raise FlashromHandlerError('Bad public key format')
216
217 # All checks passed, let's store the key in a file.
218 self.pub_key_file = self.chros_if.state_dir_file(self.PUB_KEY_FILE_NAME)
219 keyf = open(self.pub_key_file, 'w')
220 key = gbb_section[
221 rootk_offs:rootk_offs + key_body_offset + key_body_size]
222 keyf.write(key)
223 keyf.close()
224
225 def verify_image(self):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800226 """Confirm the image's validity.
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800227
228 Using the file supplied to init() as the public key container verify
229 the two sections' (FirmwareA and FirmwareB) integrity. The contents of
230 the sections is taken from the files created by new_image()
231
232 In case there is an integrity error raises FlashromHandlerError
233 exception with the appropriate error message text.
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800234 """
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800235
236 for section in self.fv_sections.itervalues():
237 cmd = 'vbutil_firmware --verify %s --signpubkey %s --fv %s' % (
238 self.chros_if.state_dir_file(section.get_sig_name()),
239 self.pub_key_file,
240 self.chros_if.state_dir_file(section.get_body_name()))
241 self.chros_if.run_shell_command(cmd)
242
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800243 def _modify_section(self, section, delta, body_or_sig=False,
244 corrupt_all=False):
245 """Modify a firmware section inside the image, either body or signature.
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800246
247 If corrupt_all is set, the passed in delta is added to all bytes in the
248 section. Otherwise, the delta is added to the value located at 2% offset
249 into the section blob, either body or signature.
250
251 Calling this function again for the same section the complimentary
252 delta value would restore the section contents.
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800253 """
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800254
255 if not self.image:
256 raise FlashromHandlerError(
257 'Attempt at using an uninitialized object')
258 if section not in self.fv_sections:
259 raise FlashromHandlerError('Unknown FW section %s'
260 % section)
261
262 # Get the appropriate section of the image.
263 if body_or_sig:
264 subsection_name = self.fv_sections[section].get_body_name()
265 else:
266 subsection_name = self.fv_sections[section].get_sig_name()
267 blob = self.fum.get_section(self.image, subsection_name)
268
269 # Modify the byte in it within 2% of the section blob.
270 modified_index = len(blob) / 50
271 if corrupt_all:
272 blob_list = [('%c' % ((ord(x) + delta) % 0x100)) for x in blob]
273 else:
274 blob_list = list(blob)
275 blob_list[modified_index] = ('%c' %
276 ((ord(blob[modified_index]) + delta) % 0x100))
277 self.image = self.fum.put_section(self.image,
278 subsection_name, ''.join(blob_list))
279
280 return subsection_name
281
282 def corrupt_section(self, section, corrupt_all=False):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800283 """Corrupt a section signature of the image"""
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800284
285 return self._modify_section(section, self.DELTA, body_or_sig=False,
286 corrupt_all=corrupt_all)
287
288 def corrupt_section_body(self, section, corrupt_all=False):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800289 """Corrupt a section body of the image"""
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800290
291 return self._modify_section(section, self.DELTA, body_or_sig=True,
292 corrupt_all=corrupt_all)
293
294 def restore_section(self, section, restore_all=False):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800295 """Restore a previously corrupted section signature of the image."""
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800296
297 return self._modify_section(section, -self.DELTA, body_or_sig=False,
298 corrupt_all=restore_all)
299
300 def restore_section_body(self, section, restore_all=False):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800301 """Restore a previously corrupted section body of the image."""
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800302
303 return self._modify_section(section, -self.DELTA, body_or_sig=True,
304 corrupt_all=restore_all)
305
306 def corrupt_firmware(self, section, corrupt_all=False):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800307 """Corrupt a section signature in the FLASHROM!!!"""
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800308
309 subsection_name = self.corrupt_section(section, corrupt_all=corrupt_all)
310 self.fum.write_partial(self.image, (subsection_name, ))
311
312 def corrupt_firmware_body(self, section, corrupt_all=False):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800313 """Corrupt a section body in the FLASHROM!!!"""
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800314
315 subsection_name = self.corrupt_section_body(section,
316 corrupt_all=corrupt_all)
317 self.fum.write_partial(self.image, (subsection_name, ))
318
319 def restore_firmware(self, section, restore_all=False):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800320 """Restore the previously corrupted section sig in the FLASHROM!!!"""
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800321
322 subsection_name = self.restore_section(section, restore_all=restore_all)
323 self.fum.write_partial(self.image, (subsection_name, ))
324
325 def restore_firmware_body(self, section, restore_all=False):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800326 """Restore the previously corrupted section body in the FLASHROM!!!"""
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800327
328 subsection_name = self.restore_section_body(section,
329 restore_all=False)
330 self.fum.write_partial(self.image, (subsection_name, ))
331
332 def firmware_sections_equal(self):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800333 """Check if firmware sections A and B are equal.
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800334
335 This function presumes that the entire BIOS image integrity has been
336 verified, so different signature sections mean different images and
337 vice versa.
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800338 """
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800339 sig_a = self.fum.get_section(self.image,
340 self.fv_sections['a'].get_sig_name())
341 sig_b = self.fum.get_section(self.image,
342 self.fv_sections['b'].get_sig_name())
343 return sig_a == sig_b
344
345 def copy_from_to(self, src, dst):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800346 """Copy one firmware image section to another.
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800347
348 This function copies both signature and body of one firmware section
349 into another. After this function runs both sections are identical.
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800350 """
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800351 src_sect = self.fv_sections[src]
352 dst_sect = self.fv_sections[dst]
353 self.image = self.fum.put_section(
354 self.image,
355 dst_sect.get_body_name(),
356 self.fum.get_section(self.image, src_sect.get_body_name()))
357 self.image = self.fum.put_section(
358 self.image,
359 dst_sect.get_sig_name(),
360 self.fum.get_section(self.image, src_sect.get_sig_name()))
361
362 def write_whole(self):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800363 """Write the whole image into the flashrom."""
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800364
365 if not self.image:
366 raise FlashromHandlerError(
367 'Attempt at using an uninitialized object')
368 self.fum.write_whole(self.image)
369
370 def dump_whole(self, filename):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800371 """Write the whole image into a file."""
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800372
373 if not self.image:
374 raise FlashromHandlerError(
375 'Attempt at using an uninitialized object')
376 open(filename, 'w').write(self.image)
377
378 def dump_partial(self, subsection_name, filename):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800379 """Write the subsection part into a file."""
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800380
381 if not self.image:
382 raise FlashromHandlerError(
383 'Attempt at using an uninitialized object')
384 blob = self.fum.get_section(self.image, subsection_name)
385 open(filename, 'w').write(blob)
386
387 def get_gbb_flags(self):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800388 """Retrieve the GBB flags"""
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800389 gbb_header_format = '<12sL'
390 gbb_section = self.fum.get_section(self.image, 'FV_GBB')
391 try:
392 _, gbb_flags = struct.unpack_from(gbb_header_format, gbb_section)
393 except struct.error, e:
394 raise FlashromHandlerError(e)
395 return gbb_flags
396
ctchang38ae4922012-09-03 17:01:16 +0800397 def get_section_sig_sha(self, section):
398 """Retrieve SHA1 hash of a firmware vblock section"""
399 return self.fv_sections[section].get_sig_sha()
400
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800401 def get_section_sha(self, section):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800402 """Retrieve SHA1 hash of a firmware body section"""
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800403 return self.fv_sections[section].get_sha()
404
405 def get_section_version(self, section):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800406 """Retrieve version number of a firmware section"""
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800407 return self.fv_sections[section].get_version()
408
409 def get_section_flags(self, section):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800410 """Retrieve preamble flags of a firmware section"""
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800411 return self.fv_sections[section].get_flags()
412
413 def get_section_datakey_version(self, section):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800414 """Retrieve data key version number of a firmware section"""
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800415 return self.fv_sections[section].get_datakey_version()
416
417 def get_section_kernel_subkey_version(self, section):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800418 """Retrieve kernel subkey version number of a firmware section"""
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800419 return self.fv_sections[section].get_kernel_subkey_version()
420
421 def get_section_body(self, section):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800422 """Retrieve body of a firmware section"""
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800423 subsection_name = self.fv_sections[section].get_body_name()
424 blob = self.fum.get_section(self.image, subsection_name)
425 return blob
426
ctchang38ae4922012-09-03 17:01:16 +0800427 def get_section_sig(self, section):
428 """Retrieve vblock of a firmware section"""
429 subsection_name = self.fv_sections[section].get_sig_name()
430 blob = self.fum.get_section(self.image, subsection_name)
431 return blob
432
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800433 def _find_ecbin_offset(self, blob):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800434 """Return the offset of EC binary from the given firmware blob"""
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800435 # The RW firmware is concatenated from u-boot, dtb, and ecbin.
436 # Search the magic of dtb to locate the dtb bloc.
437 dtb_offset = blob.index("\xD0\x0D\xFE\xED\x00")
438 # The dtb size is a 32-bit integer which follows the magic.
439 _, dtb_size = struct.unpack_from(">2L", blob, dtb_offset)
440 # The ecbin part is aligned to 4-byte.
441 ecbin_offset = (dtb_offset + dtb_size + 3) & ~3
442 return ecbin_offset
443
444 def _find_ecbin_size_offset_on_dtb(self, blob):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800445 """Return the offset of EC binary size on the DTB blob"""
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800446 # We now temporarily use this hack to find the offset.
447 # TODO(waihong@chromium.org): Should use fdtget to get the field and
448 # fdtput to change it.
449 dtb_offset = blob.index("\xD0\x0D\xFE\xED\x00")
450 prop_offset = blob.index("blob boot,dtb,ecbin", dtb_offset) + 0x18
451 ecbin_size_offset = blob.index("ecbin", prop_offset) + 0x18
452 return ecbin_size_offset
453
454 def get_section_ecbin(self, section):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800455 """Retrieve EC binary of a firmware section"""
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800456 blob = self.get_section_body(section)
457 ecbin_offset = self._find_ecbin_offset(blob)
458 # Remove the pads of ecbin.
459 pad = blob[-1]
460 ecbin = blob[ecbin_offset :].rstrip(pad)
461 return ecbin
462
ctchang38ae4922012-09-03 17:01:16 +0800463 def set_section_body(self, section, blob, write_through=False):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800464 """Put the supplied blob to the body of the firmware section"""
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800465 subsection_name = self.fv_sections[section].get_body_name()
466 self.image = self.fum.put_section(self.image, subsection_name, blob)
467
ctchang38ae4922012-09-03 17:01:16 +0800468 if write_through:
469 self.dump_partial(subsection_name,
470 self.chros_if.state_dir_file(subsection_name))
471 self.fum.write_partial(self.image, (subsection_name, ))
472
473 def set_section_sig(self, section, blob, write_through=False):
474 """Put the supplied blob to the vblock of the firmware section"""
475 subsection_name = self.fv_sections[section].get_sig_name()
476 self.image = self.fum.put_section(self.image, subsection_name, blob)
477
478 if write_through:
479 self.dump_partial(subsection_name,
480 self.chros_if.state_dir_file(subsection_name))
481 self.fum.write_partial(self.image, (subsection_name, ))
482
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800483 def set_section_ecbin(self, section, ecbin, write_through=False):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800484 """Put the supplied EC binary to the firwmare section.
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800485
486 Note that the updated firmware image is not signed yet. Should call
487 set_section_version() afterward.
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800488 """
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800489 # Remove unncessary padding bytes.
490 pad = '\xff'
491 ecbin_align = 4
492 ecbin = ecbin.rstrip(pad)
493 ecbin += pad * ((ecbin_align - 1) - (len(ecbin) - 1) % ecbin_align)
494 ecbin_size = len(ecbin)
495
496 # Put the ecbin into the firmware body.
497 old_blob = self.get_section_body(section)
498 ecbin_offset = self._find_ecbin_offset(old_blob)
499 pad = old_blob[-1]
500 pad_size = len(old_blob) - ecbin_offset - ecbin_size
501 new_blob = old_blob[0 : ecbin_offset] + ecbin + pad * pad_size
502
503 # Modify the ecbin size on dtb.
504 size_offset = self._find_ecbin_size_offset_on_dtb(new_blob)
505 new_blob = (new_blob[0 : size_offset] + struct.pack('>L', ecbin_size) +
506 new_blob[size_offset + 4 :])
507
508 self.set_section_body(section, new_blob)
509 if write_through:
510 subsection_name = self.fv_sections[section].get_body_name()
511 self.dump_partial(subsection_name,
512 self.chros_if.state_dir_file(subsection_name))
513 self.fum.write_partial(self.image, (subsection_name, ))
514
515 def set_section_version(self, section, version, flags,
516 write_through=False):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800517 """
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800518 Re-sign the firmware section using the supplied version number and
519 flag.
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800520 """
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800521 if (self.get_section_version(section) == version and
522 self.get_section_flags(section) == flags):
523 return # No version or flag change, nothing to do.
524 if version < 0:
525 raise FlashromHandlerError(
526 'Attempt to set version %d on section %s' % (version, section))
527 fv_section = self.fv_sections[section]
528 sig_name = self.chros_if.state_dir_file(fv_section.get_sig_name())
529 sig_size = os.path.getsize(sig_name)
530
531 # Construct the command line
532 args = ['--vblock %s' % sig_name]
533 args.append('--keyblock %s' % os.path.join(
534 self.dev_key_path, self.FW_KEYBLOCK_FILE_NAME))
535 args.append('--fv %s' % self.chros_if.state_dir_file(
536 fv_section.get_body_name()))
537 args.append('--version %d' % version)
538 args.append('--kernelkey %s' % os.path.join(
539 self.dev_key_path, self.KERNEL_SUBKEY_FILE_NAME))
540 args.append('--signprivate %s' % os.path.join(
541 self.dev_key_path, self.FW_PRIV_DATA_KEY_FILE_NAME))
542 args.append('--flags %d' % flags)
543 cmd = 'vbutil_firmware %s' % ' '.join(args)
544 self.chros_if.run_shell_command(cmd)
545
546 # Pad the new signature.
547 new_sig = open(sig_name, 'a')
548 pad = ('%c' % 0xff) * (sig_size - os.path.getsize(sig_name))
549 new_sig.write(pad)
550 new_sig.close()
551
552 # Inject the new signature block into the image
553 new_sig = open(sig_name, 'r').read()
554 self.image = self.fum.put_section(
555 self.image, fv_section.get_sig_name(), new_sig)
556 if write_through:
557 self.fum.write_partial(self.image, (fv_section.get_sig_name(), ))