blob: a4280cd864ad7db4eb012e3a1d91ec5aa37e3f93 [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
Tom Wai-Hong Tam44204b32012-11-20 13:55:40 +0800397 def enable_write_protect(self):
398 """Enable write protect of the flash chip"""
399 self.fum.enable_write_protect()
400
401 def disable_write_protect(self):
402 """Disable write protect of the flash chip"""
403 self.fum.disable_write_protect()
404
ctchang38ae4922012-09-03 17:01:16 +0800405 def get_section_sig_sha(self, section):
406 """Retrieve SHA1 hash of a firmware vblock section"""
407 return self.fv_sections[section].get_sig_sha()
408
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800409 def get_section_sha(self, section):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800410 """Retrieve SHA1 hash of a firmware body section"""
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800411 return self.fv_sections[section].get_sha()
412
413 def get_section_version(self, section):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800414 """Retrieve version number of a firmware section"""
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800415 return self.fv_sections[section].get_version()
416
417 def get_section_flags(self, section):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800418 """Retrieve preamble flags of a firmware section"""
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800419 return self.fv_sections[section].get_flags()
420
421 def get_section_datakey_version(self, section):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800422 """Retrieve data key version number of a firmware section"""
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800423 return self.fv_sections[section].get_datakey_version()
424
425 def get_section_kernel_subkey_version(self, section):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800426 """Retrieve kernel subkey version number of a firmware section"""
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800427 return self.fv_sections[section].get_kernel_subkey_version()
428
429 def get_section_body(self, section):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800430 """Retrieve body of a firmware section"""
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800431 subsection_name = self.fv_sections[section].get_body_name()
432 blob = self.fum.get_section(self.image, subsection_name)
433 return blob
434
ctchang38ae4922012-09-03 17:01:16 +0800435 def get_section_sig(self, section):
436 """Retrieve vblock of a firmware section"""
437 subsection_name = self.fv_sections[section].get_sig_name()
438 blob = self.fum.get_section(self.image, subsection_name)
439 return blob
440
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800441 def _find_ecbin_offset(self, blob):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800442 """Return the offset of EC binary from the given firmware blob"""
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800443 # The RW firmware is concatenated from u-boot, dtb, and ecbin.
444 # Search the magic of dtb to locate the dtb bloc.
Gabe Black23048032013-01-13 07:33:00 -0800445 dtb_offset = blob.find("\xD0\x0D\xFE\xED\x00")
446 # If the device tree was found, use it. Otherwise assume an index
447 # structure.
448 if dtb_offset != -1:
449 # The dtb size is a 32-bit integer which follows the magic.
450 _, dtb_size = struct.unpack_from(">2L", blob, dtb_offset)
451 # The ecbin part is aligned to 4-byte.
452 return (dtb_offset + dtb_size + 3) & ~3
453 else:
454 # The index will have a count, an offset and size for the system
455 # firmware, and then an offset and size for the EC binary.
456 return struct.unpack_from("<I", blob, 3 * 4)[0]
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800457
458 def _find_ecbin_size_offset_on_dtb(self, blob):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800459 """Return the offset of EC binary size on the DTB blob"""
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800460 # We now temporarily use this hack to find the offset.
461 # TODO(waihong@chromium.org): Should use fdtget to get the field and
462 # fdtput to change it.
Gabe Black23048032013-01-13 07:33:00 -0800463 dtb_offset = blob.find("\xD0\x0D\xFE\xED\x00")
464 # If the device tree wasn't found, give up and return an error.
465 if dtb_offset == -1:
466 return -1
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800467 prop_offset = blob.index("blob boot,dtb,ecbin", dtb_offset) + 0x18
468 ecbin_size_offset = blob.index("ecbin", prop_offset) + 0x18
469 return ecbin_size_offset
470
471 def get_section_ecbin(self, section):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800472 """Retrieve EC binary of a firmware section"""
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800473 blob = self.get_section_body(section)
474 ecbin_offset = self._find_ecbin_offset(blob)
475 # Remove the pads of ecbin.
476 pad = blob[-1]
477 ecbin = blob[ecbin_offset :].rstrip(pad)
478 return ecbin
479
ctchang38ae4922012-09-03 17:01:16 +0800480 def set_section_body(self, section, blob, write_through=False):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800481 """Put the supplied blob to the body of the firmware section"""
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800482 subsection_name = self.fv_sections[section].get_body_name()
483 self.image = self.fum.put_section(self.image, subsection_name, blob)
484
ctchang38ae4922012-09-03 17:01:16 +0800485 if write_through:
486 self.dump_partial(subsection_name,
487 self.chros_if.state_dir_file(subsection_name))
488 self.fum.write_partial(self.image, (subsection_name, ))
489
490 def set_section_sig(self, section, blob, write_through=False):
491 """Put the supplied blob to the vblock of the firmware section"""
492 subsection_name = self.fv_sections[section].get_sig_name()
493 self.image = self.fum.put_section(self.image, subsection_name, blob)
494
495 if write_through:
496 self.dump_partial(subsection_name,
497 self.chros_if.state_dir_file(subsection_name))
498 self.fum.write_partial(self.image, (subsection_name, ))
499
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800500 def set_section_ecbin(self, section, ecbin, write_through=False):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800501 """Put the supplied EC binary to the firwmare section.
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800502
503 Note that the updated firmware image is not signed yet. Should call
504 set_section_version() afterward.
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800505 """
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800506 # Remove unncessary padding bytes.
507 pad = '\xff'
508 ecbin_align = 4
509 ecbin = ecbin.rstrip(pad)
510 ecbin += pad * ((ecbin_align - 1) - (len(ecbin) - 1) % ecbin_align)
511 ecbin_size = len(ecbin)
512
513 # Put the ecbin into the firmware body.
514 old_blob = self.get_section_body(section)
515 ecbin_offset = self._find_ecbin_offset(old_blob)
516 pad = old_blob[-1]
517 pad_size = len(old_blob) - ecbin_offset - ecbin_size
518 new_blob = old_blob[0 : ecbin_offset] + ecbin + pad * pad_size
519
520 # Modify the ecbin size on dtb.
521 size_offset = self._find_ecbin_size_offset_on_dtb(new_blob)
Gabe Black23048032013-01-13 07:33:00 -0800522 if size_offset != -1:
523 new_blob = (new_blob[0 : size_offset] +
524 struct.pack('>L', ecbin_size) +
525 new_blob[size_offset + 4 :])
526 else:
527 # The index will have a count, an offset and size for the system
528 # firmware, and then an offset and size for the EC binary.
529 new_blob = (new_blob[0 : 4 * 4] +
530 struct.pack('<I', ecbin_size) +
531 new_blob[5 * 4 :])
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800532
533 self.set_section_body(section, new_blob)
534 if write_through:
535 subsection_name = self.fv_sections[section].get_body_name()
536 self.dump_partial(subsection_name,
537 self.chros_if.state_dir_file(subsection_name))
538 self.fum.write_partial(self.image, (subsection_name, ))
539
540 def set_section_version(self, section, version, flags,
541 write_through=False):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800542 """
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800543 Re-sign the firmware section using the supplied version number and
544 flag.
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800545 """
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800546 if (self.get_section_version(section) == version and
547 self.get_section_flags(section) == flags):
548 return # No version or flag change, nothing to do.
549 if version < 0:
550 raise FlashromHandlerError(
551 'Attempt to set version %d on section %s' % (version, section))
552 fv_section = self.fv_sections[section]
553 sig_name = self.chros_if.state_dir_file(fv_section.get_sig_name())
554 sig_size = os.path.getsize(sig_name)
555
556 # Construct the command line
557 args = ['--vblock %s' % sig_name]
558 args.append('--keyblock %s' % os.path.join(
559 self.dev_key_path, self.FW_KEYBLOCK_FILE_NAME))
560 args.append('--fv %s' % self.chros_if.state_dir_file(
561 fv_section.get_body_name()))
562 args.append('--version %d' % version)
563 args.append('--kernelkey %s' % os.path.join(
564 self.dev_key_path, self.KERNEL_SUBKEY_FILE_NAME))
565 args.append('--signprivate %s' % os.path.join(
566 self.dev_key_path, self.FW_PRIV_DATA_KEY_FILE_NAME))
567 args.append('--flags %d' % flags)
568 cmd = 'vbutil_firmware %s' % ' '.join(args)
569 self.chros_if.run_shell_command(cmd)
570
571 # Pad the new signature.
572 new_sig = open(sig_name, 'a')
Tom Wai-Hong Tamdc2d8072012-12-18 10:50:55 +0800573 pad = ('%c' % 0) * (sig_size - os.path.getsize(sig_name))
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800574 new_sig.write(pad)
575 new_sig.close()
576
577 # Inject the new signature block into the image
578 new_sig = open(sig_name, 'r').read()
579 self.image = self.fum.put_section(
580 self.image, fv_section.get_sig_name(), new_sig)
581 if write_through:
582 self.fum.write_partial(self.image, (fv_section.get_sig_name(), ))