Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(64)

Side by Side Diff: client/common_lib/flashrom_util.py

Issue 3246002: Add flashrom memory layout detection by FMAP (using fmap_decode) (Closed) Base URL: ssh://git@gitrw.chromium.org:9222/autotest.git
Patch Set: change site_fmap license header Created 10 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | client/common_lib/site_fmap.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved. 2 # 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 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 """ 6 """
7 This module provides convenience routines to access Flash ROM (EEPROM). 7 This module provides convenience routines to access Flash ROM (EEPROM).
8 - flashrom_util is a low level wrapper of flashrom(8) program. 8 - flashrom_util is a low level wrapper of flashrom(8) program.
9 - FlashromUtility is a high level object which provides more advanced 9 - FlashromUtility is a high level object which provides more advanced
10 features like journaling-alike (log-based) changing. 10 features like journaling-alike (log-based) changing.
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
60 FV_GBB = 0x20000, 60 FV_GBB = 0x20000,
61 FV_BSTUB = 0x40000, 61 FV_BSTUB = 0x40000,
62 """, 62 """,
63 "ec": """ 63 "ec": """
64 EC_RO 64 EC_RO
65 | 65 |
66 EC_RW 66 EC_RW
67 """, 67 """,
68 } 68 }
69 69
70 # The default conversion table for fmap_decode.
71 DEFAULT_CHROMEOS_FMAP_CONVERSION = {
72 "Boot Stub": "FV_BSTUB",
73 "GBB Area": "FV_GBB",
74 "Recovery Firmware": "FVDEV",
75 "RO VPD": "RO_VPD",
76 "Firmware A Key": "VBOOTA",
77 "Firmware A Data": "FVMAIN",
78 "Firmware B Key": "VBOOTB",
79 "Firmware B Data": "FVMAINB",
80 "Log Volume": "FV_LOG",
81 }
82
70 # Default "skip" sections when verifying section data. 83 # Default "skip" sections when verifying section data.
71 # This is required because some flashrom chip may create timestamps (or checksum 84 # This is required because some flashrom chip may create timestamps (or checksum
72 # values) when (or immediately after) we change flashrom content. 85 # values) when (or immediately after) we change flashrom content.
73 # The syntax is a comma-separated list of string tuples (separated by ':'): 86 # The syntax is a comma-separated list of string tuples (separated by ':'):
74 # PARTNAME:OFFSET:SIZE 87 # PARTNAME:OFFSET:SIZE
75 # If there's no need to skip anything, provide an empty list []. 88 # If there's no need to skip anything, provide an empty list [].
76 DEFAULT_CHROMEOS_FIRMWARE_SKIP_VERIFY_LIST = { 89 DEFAULT_CHROMEOS_FIRMWARE_SKIP_VERIFY_LIST = {
77 "bios": [], 90 "bios": [],
78 "ec": "EC_RO:0x48:4", 91 "ec": "EC_RO:0x48:4",
79 } 92 }
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
173 # fill sections 186 # fill sections
174 for i in range(len(names)): 187 for i in range(len(names)):
175 # ignore unamed sections 188 # ignore unamed sections
176 if names[i] != '*': 189 if names[i] != '*':
177 layout[names[i]] = (offset, offset + sizes[i] - 1) 190 layout[names[i]] = (offset, offset + sizes[i] - 1)
178 offset = offset + sizes[i] 191 offset = offset + sizes[i]
179 192
180 return layout 193 return layout
181 194
182 195
196 def _convert_fmap_layout(conversion_map, fmap_areas):
197 """
198 (internal utility) Converts a FMAP areas structure to flashrom layout format
199 by conversion_map.
200 Args:
201 conversion_map: dictionary of names to convert.
202 fmap_areas: a list of {name, offset, size} dictionary.
203
204 Returns: layout structure for flashrom_util, or empty for failure.
205 """
206 layout = {}
207 for entry in fmap_areas:
208 name = entry['name']
209 offset = entry['offset']
210 size = entry['size']
211 if name in conversion_map:
212 name = conversion_map[name]
213 name = name.replace(' ', '%20')
214 layout[name] = (offset, offset + size - 1)
215 return layout
216
217
218 def decode_fmap_layout_external(conversion_map, image_file_name):
219 """
220 (Utility) Decodes layout by an external fmap_decode command provided by
221 system PATH.
222 Args:
223 conversion_map: dictionary for FMAP area name conversion
224 image_file_name: file name of firmware image with FMAP structure for
225 parsing layout.
226
227 Returns: layout structure for flashrom_util, or empty for failure.
228 """
229 if os.system('type fmap_decode 2>/dev/null') != 0:
230 # print 'error: no fmap_decode in system.'
231 return {}
232 fmap_object = []
233 fmap = os.popen("fmap_decode %s 2>/dev/null" % image_file_name).readlines()
234 for entry in fmap:
235 if 'area_name' not in entry:
236 continue
237 # format: area_offset="HEX" area_size="HEX" area_name="NAME" ...
238 offset = int(re.findall('area_offset="([^"]*)"', entry)[0], 0)
239 size = int(re.findall('area_size="([^"]*)"', entry)[0], 0)
240 name = re.findall('area_name="([^"]*)"', entry)[0]
241 # print 'off=%s, size=%s, name=%s' % (offset, size, name)
242 fmap_object.append({'offset':offset, 'size':size, 'name':name})
243 return _convert_fmap_layout(conversion_map, fmap_object)
244
245
246 def decode_fmap_layout(conversion_map, image_blob):
247 """
248 (Utility) Uses fmap_decode to retrieve embedded layout of a prepared
249 firmware image.
250 Args:
251 conversion_map: dictionary for FMAP area name conversion
252 image_blob: binary data of firmware image containing FMAP
253
254 Returns: layout structure for flashrom_util, or empty for failure.
255 """
256 try:
257 import site_fmap
258 fmap_object = site_fmap.fmap_decode(image_blob)['areas']
259 except:
260 # print 'decode_fmap_layout: failed to decode from image blob'
261 fmap_object = []
262 return _convert_fmap_layout(conversion_map, fmap_object)
263
264
183 def csv_to_list(csv, delimiter=','): 265 def csv_to_list(csv, delimiter=','):
184 """ 266 """
185 (Utility) Converts a comma-separated-value (or list) to a list. 267 (Utility) Converts a comma-separated-value (or list) to a list.
186 268
187 To use symbols other that comma, customize with delimiter. 269 To use symbols other that comma, customize with delimiter.
188 """ 270 """
189 if isinstance(csv, types.StringTypes): 271 if isinstance(csv, types.StringTypes):
190 return [i.strip() for i in csv.split(delimiter)] 272 return [i.strip() for i in csv.split(delimiter)]
191 return csv 273 return csv
192 274
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
258 verbose=False, 340 verbose=False,
259 keep_temp_files=False, 341 keep_temp_files=False,
260 target_map=None): 342 target_map=None):
261 """ constructor of flashrom_util. help(flashrom_util) for more info """ 343 """ constructor of flashrom_util. help(flashrom_util) for more info """
262 self.tool_path = tool_path 344 self.tool_path = tool_path
263 self.cmd_prefix = cmd_prefix 345 self.cmd_prefix = cmd_prefix
264 self.tmp_root = tmp_root 346 self.tmp_root = tmp_root
265 self.verbose = verbose 347 self.verbose = verbose
266 self.keep_temp_files = keep_temp_files 348 self.keep_temp_files = keep_temp_files
267 self.target_map = target_map 349 self.target_map = target_map
350 self.is_debug = False
268 # detect bbs map if target_map is None. 351 # detect bbs map if target_map is None.
269 # NOTE when target_map == {}, that means "do not execute commands", 352 # NOTE when target_map == {}, that means "do not execute commands",
270 # different to default value. 353 # different to default value.
271 if isinstance(target_map, types.NoneType): 354 if isinstance(target_map, types.NoneType):
272 # generate default target map 355 # generate default target map
273 self.target_map = self.detect_target_map() 356 self.target_map = self.detect_target_map()
274 357
275 def _get_temp_filename(self, prefix): 358 def _get_temp_filename(self, prefix):
276 ''' (internal) Returns name of a temporary file in self.tmp_root ''' 359 ''' (internal) Returns name of a temporary file in self.tmp_root '''
277 (fd, name) = tempfile.mkstemp(prefix=prefix, dir=self.tmp_root) 360 (fd, name) = tempfile.mkstemp(prefix=prefix, dir=self.tmp_root)
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
335 """ 418 """
336 Detects the target selection map. 419 Detects the target selection map.
337 Use machine architecture in current implementation. 420 Use machine architecture in current implementation.
338 """ 421 """
339 arch = utils.get_arch() 422 arch = utils.get_arch()
340 for regex, target_map in DEFAULT_ARCH_TARGET_MAP.items(): 423 for regex, target_map in DEFAULT_ARCH_TARGET_MAP.items():
341 if re.match(regex, arch): 424 if re.match(regex, arch):
342 return target_map 425 return target_map
343 raise TestError('INTERNAL ERROR: unknown architecture, need target_map') 426 raise TestError('INTERNAL ERROR: unknown architecture, need target_map')
344 427
345 def detect_layout(self, layout_desciption, size=None): 428 def detect_layout(self, layout_desciption, size, image):
346 """ 429 """
347 Detects and builds layout according to current flash ROM size 430 Detects and builds layout according to current flash ROM size
348 and a simple layout description language. 431 (or image) and a simple layout description language.
349 If parameter 'size' is omitted, self.get_size() will be called.
350 432
351 See help(flashrom_util.compile_layout) for the syntax of description. 433 NOTE: if you don't trust any available FMAP layout information in
434 flashrom image, pass image = None.
435
436 Args:
437 layout_description: Pre-defined layout description. See
438 help(flashrom_util.compile_layout) for syntax detail.
439 size: Size of flashrom. If size is None, self.get_size()
440 will be called.
441 image: (optional) Flash ROM image that contains FMAP layout info.
442 If image is None, layout will be calculated by size only.
352 443
353 Returns the layout map (empty if any error). 444 Returns the layout map (empty if any error).
354 """ 445 """
355 if not size: 446 ret = None
356 size = self.get_size() 447 if image:
357 return compile_layout(layout_desciption, size) 448 if self.is_debug:
449 print " * detect_layout: try FMAP"
450 ret = decode_fmap_layout(DEFAULT_CHROMEOS_FMAP_CONVERSION, image)
451 if not ret:
452 if not size:
453 size = self.get_size()
454 ret = compile_layout(layout_desciption, size)
455 if self.is_debug:
456 print " * detect_layout: using pre-defined memory layout"
457 elif self.is_debug:
458 print " * detect_layout: using FMAP layout in firmware image."
459 return ret
358 460
359 def detect_chromeos_layout(self, target, size=None): 461 def detect_chromeos_layout(self, target, size, image):
360 """ 462 """
361 Detects and builds ChromeOS firmware layout according to current flash 463 Detects and builds ChromeOS firmware layout according to current flash
362 ROM size. If parameter 'size' is None, self.get_size() will be called. 464 ROM size. Currently supported targets are: 'bios' or 'ec'.
363 465
364 Currently supported targets are: 'bios' or 'ec'. 466 See help(flashrom_util.flashrom_util.detect_layout) for detail
467 information of argument size and image.
365 468
366 Returns the layout map (empty if any error). 469 Returns the layout map (empty if any error).
367 """ 470 """
368 assert target in DEFAULT_CHROMEOS_FIRMWARE_LAYOUT_DESCRIPTIONS, \ 471 assert target in DEFAULT_CHROMEOS_FIRMWARE_LAYOUT_DESCRIPTIONS, \
369 'unknown layout target: ' + test 472 'unknown layout target: ' + test
370 chromeos_target = DEFAULT_CHROMEOS_FIRMWARE_LAYOUT_DESCRIPTIONS[target] 473 chromeos_target = DEFAULT_CHROMEOS_FIRMWARE_LAYOUT_DESCRIPTIONS[target]
371 return self.detect_layout(chromeos_target, size) 474 return self.detect_layout(chromeos_target, size, image)
372 475
373 def detect_chromeos_bios_layout(self, size=None): 476 def detect_chromeos_bios_layout(self, size, image):
374 """ Detects standard ChromeOS BIOS layout """ 477 """ Detects standard ChromeOS BIOS layout.
375 return self.detect_chromeos_layout(self.TARGET_BIOS, size) 478 A short cut to detect_chromeos_layout(TARGET_BIOS, size, image). """
479 return self.detect_chromeos_layout(self.TARGET_BIOS, size, image)
376 480
377 def detect_chromeos_ec_layout(self, size=None): 481 def detect_chromeos_ec_layout(self, size, image):
378 """ Detects standard ChromeOS Embedded Controller layout """ 482 """ Detects standard ChromeOS Embedded Controller layout.
379 return self.detect_chromeos_layout(self.TARGET_EC, size) 483 A short cut to detect_chromeos_layout(TARGET_EC, size, image). """
484 return self.detect_chromeos_layout(self.TARGET_EC, size, image)
380 485
381 def read_whole(self): 486 def read_whole(self):
382 ''' 487 '''
383 Reads whole flash ROM data. 488 Reads whole flash ROM data.
384 Returns the data read from flash ROM, or empty string for other error. 489 Returns the data read from flash ROM, or empty string for other error.
385 ''' 490 '''
386 tmpfn = self._get_temp_filename('rd_') 491 tmpfn = self._get_temp_filename('rd_')
387 cmd = '%s"%s" -r "%s"' % (self.cmd_prefix, self.tool_path, tmpfn) 492 cmd = '%s"%s" -r "%s"' % (self.cmd_prefix, self.tool_path, tmpfn)
388 if self.verbose: 493 if self.verbose:
389 print 'flashrom_util.read_whole(): ', cmd 494 print 'flashrom_util.read_whole(): ', cmd
(...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after
543 648
544 TARGET_BIOS = DEFAULT_TARGET_NAME_BIOS 649 TARGET_BIOS = DEFAULT_TARGET_NAME_BIOS
545 TARGET_EC = DEFAULT_TARGET_NAME_EC 650 TARGET_EC = DEFAULT_TARGET_NAME_EC
546 651
547 def __init__(self, flashrom_util_instance=None, is_verbose=False): 652 def __init__(self, flashrom_util_instance=None, is_verbose=False):
548 """ 653 """
549 Initializes internal variables and states. 654 Initializes internal variables and states.
550 655
551 Arguments: 656 Arguments:
552 flashrom_util_instance: An instance of existing flashrom_util. If 657 flashrom_util_instance: An instance of existing flashrom_util. If
553 not provided, FirmwareUpdater will create 658 not provided, FlashromUtility will create
554 one with all default values. 659 one with all default values.
555 is_verbose: Flag to control outputting verbose messages. 660 is_verbose: Flag to control outputting verbose messages.
556 """ 661 """
557 self.flashrom = flashrom_util_instance 662 self.flashrom = flashrom_util_instance
558 if not self.flashrom: 663 if not self.flashrom:
559 self.flashrom = flashrom_util(verbose=is_verbose) 664 self.flashrom = flashrom_util(verbose=is_verbose)
560 self.current_image = None 665 self.current_image = None
561 self.layout = None 666 self.layout = None
562 self.whole_flash_layout = None 667 self.whole_flash_layout = None
563 self.skip_verify = None 668 self.skip_verify = None
564 self.change_history = [] 669 self.change_history = []
565 self.is_verbose = is_verbose 670 self.is_verbose = is_verbose
566 self.is_debug = False 671 self.is_debug = False
567 672
568 def initialize(self, target, layout_desc=None, skip_verify=None): 673 def initialize(self, target, layout_image=None, layout_desc=None,
569 """ Starts flashrom initialization with given target. """ 674 use_fmap_layout=True, skip_verify=None):
675 """
676 Starts flashrom initialization with given target.
677
678 Args:
679 target: Name of the target you are dealing with (check TARGET_*)
680 layout_desc: (optional) Description of pre-defined layout
681 layout_image: (optional) A image blob containing FMAP for building
682 layout. None if you want to use current system flash content
683 use_fmap_layout: Use True (default) if you trust the FMAP in
684 layout_image.
685 skip_verify: Description of what data must be skipped when
686 doing comparison / verification.
687 """
570 flashrom = self.flashrom 688 flashrom = self.flashrom
571 if not flashrom.select_target(target): 689 if not flashrom.select_target(target):
572 raise TestError("Cannot Select Target. Abort.") 690 raise TestError("Cannot Select Target. Abort.")
691
573 if self.is_verbose: 692 if self.is_verbose:
574 print " - reading current content" 693 print " - reading current content"
575 self.current_image = flashrom.read_whole() 694 self.current_image = flashrom.read_whole()
576 if not self.current_image: 695 if not self.current_image:
577 raise TestError("Cannot read flashrom image. Abort.") 696 raise TestError("Cannot read flashrom image. Abort.")
578 flashrom_size = len(self.current_image) 697 flashrom_size = len(self.current_image)
698
699 if not use_fmap_layout:
700 layout_image = None
701 elif not layout_image:
702 layout_image = current_image
703
579 if layout_desc: 704 if layout_desc:
580 layout = flashrom.detect_layout(layout_desc, flashrom_size) 705 layout = flashrom.detect_layout(
706 layout_desc, flashrom_size, layout_image)
581 else: 707 else:
582 layout = flashrom.detect_chromeos_layout(target, flashrom_size) 708 layout = flashrom.detect_chromeos_layout(
709 target, flashrom_size, layout_image)
583 self.layout = layout 710 self.layout = layout
584 self.whole_flash_layout = flashrom.detect_layout('all', flashrom_size) 711 self.whole_flash_layout = flashrom.detect_layout('all', flashrom_size)
585 if not skip_verify: 712 if not skip_verify:
586 skip_verify = DEFAULT_CHROMEOS_FIRMWARE_SKIP_VERIFY_LIST[target] 713 skip_verify = DEFAULT_CHROMEOS_FIRMWARE_SKIP_VERIFY_LIST[target]
587 self.skip_verify = skip_verify 714 self.skip_verify = skip_verify
588 self.change_history = [] # reset list 715 self.change_history = [] # reset list
589 716
590 def get_current_image(self): 717 def get_current_image(self):
591 """ Returns current flashrom image (physically, not changed) """ 718 """ Returns current flashrom image (physically, not changed) """
592 return self.current_image 719 return self.current_image
(...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after
780 except ImportError: 907 except ImportError:
781 # print 'using mocks' 908 # print 'using mocks'
782 utils = mock_utils() 909 utils = mock_utils()
783 TestError = mock_TestError 910 TestError = mock_TestError
784 911
785 912
786 # main stub 913 # main stub
787 if __name__ == "__main__": 914 if __name__ == "__main__":
788 # TODO(hungte) provide unit tests or command line usage 915 # TODO(hungte) provide unit tests or command line usage
789 pass 916 pass
OLDNEW
« no previous file with comments | « no previous file | client/common_lib/site_fmap.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698