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

Side by Side Diff: x86-generic/flashrom_util.py

Issue 3328008: Make SAFT use layout retrieved from the BIOS image. (Closed) Base URL: http://git.chromium.org/git/firmware.git
Patch Set: Cosmetic changes before committing. 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 | « saft/test_kernel_handler.py ('k') | no next file » | 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 """ This module provides convenience routines to access Flash ROM (EEPROM) 6 """ This module provides convenience routines to access Flash ROM (EEPROM)
7 7
8 flashrom_util is based on utility 'flashrom'. 8 flashrom_util is based on utility 'flashrom'.
9 9
10 Original tool syntax: 10 Original tool syntax:
11 (read ) flashrom -r <file> 11 (read ) flashrom -r <file>
12 (write) flashrom -l <layout_fn> [-i <image_name> ...] -w <file> 12 (write) flashrom -l <layout_fn> [-i <image_name> ...] -w <file>
13 13
14 The layout_fn is in format of 14 The layout_fn is in format of
15 address_begin:address_end image_name 15 address_begin:address_end image_name
16 which defines a region between (address_begin, address_end) and can 16 which defines a region between (address_begin, address_end) and can
17 be accessed by the name image_name. 17 be accessed by the name image_name.
18 18
19 Currently the tool supports multiple partial write but not partial read. 19 Currently the tool supports multiple partial write but not partial read.
20 20
21 In the flashrom_util, we provide read and partial write abilities. 21 In the flashrom_util, we provide read and partial write abilities.
22 For more information, see help(flashrom_util.flashrom_util). 22 For more information, see help(flashrom_util.flashrom_util).
23 """ 23 """
24 24
25 import os 25 import os
26 import re 26 import re
27 import stat
27 import subprocess 28 import subprocess
28 import sys 29 import sys
29 import tempfile 30 import tempfile
30 import types 31 import types
31 32
33 import chromeos_interface
32 34
33 # simple layout description language compiler 35 class TestError(Exception):
34 def compile_layout(desc, size): 36 pass
35 """ compile_layout(desc, size) -> layout
36 37
37 Compiles a flashrom layout by simple description language.
38 Returns the result as a map. Empty map for any error.
39 38
40 syntax: <desc> ::= <partitions> 39 class LayoutScraper(object):
41 <partitions> ::= <partition> 40 '''Object of this class is used to retrieve layout from a BIOS file.'''
42 | <partitions> '|' <partition>
43 <partition> ::= <spare_section>
44 | <partition> ',' <section>
45 | <section> ',' <partition>
46 <section> ::= <name> '=' <size>
47 <spare_section> ::= '*'
48 | <name>
49 | <name> '=' '*'
50 41
51 * Example: 'ro|rw', 'ro=0x1000,*|*,rw=0x1000' 42 # The default conversion table for mosys.
52 * Each partition share same space from total size of flashrom. 43 DEFAULT_CHROMEOS_FMAP_CONVERSION = {
53 * Sections are fix sized, or "spare" which consumes all remaining 44 "Boot Stub": "FV_BSTUB",
54 space from a partition. 45 "GBB Area": "FV_GBB",
55 * You can use any non-zero decimal or heximal (0xXXXX) in <size>. 46 "Recovery Firmware": "FVDEV",
56 (size as zero is reserved now) 47 "RO VPD": "RO_VPD",
57 * You can use '*' as <name> for "unamed" items which will be ignored in 48 "Firmware A Key": "VBOOTA",
58 final layout output. 49 "Firmware A Data": "FVMAIN",
59 * You can use "<name>=*" or simply "<name>" (including '*', the 50 "Firmware B Key": "VBOOTB",
60 'unamed section') to define spare section. 51 "Firmware B Data": "FVMAINB",
61 * There must be always one (no more, no less) spare section in 52 "Log Volume": "FV_LOG",
62 each partition. 53 }
63 """
64 # create an empty layout first
65 layout = {}
66 err_ret = {}
67 54
68 # prepare: remove all spaces (literal from string.whitespace) 55 def __init__(self, os_if):
69 desc = ''.join([c for c in desc if c not in '\t\n\x0b\x0c\r ']) 56 self.image = None
70 # find equally-sized partitions 57 self.os_if = os_if
71 parts = desc.split('|')
72 block_size = size / len(parts)
73 offset = 0
74 58
75 for part in parts: 59 def _get_text_layout(self, file_name):
76 sections = part.split(',') 60 '''Retrieve text layout from a firmware image file.
77 sizes = []
78 names = []
79 spares = 0
80 61
81 for section in sections: 62 This function uses the 'mosys' utility to scan the firmware image and
82 # skip empty section to allow final ',' 63 retrieve the section layout information.
83 if section == '': 64
65 The layout is reported as a set of lines with multiple
66 "<name>"="value" pairs, all this output is passed to the caller.
67 '''
68
69 mosys_cmd = 'mosys -k eeprom map %s' % file_name
70 return self.os_if.run_shell_command_get_output(mosys_cmd)
71
72 def _line_to_dictionary(self, line):
73 '''Convert a text layout line into a dictionary.
74
75 Get a string consisting of single space separated "<name>"="value>"
76 pairs and convert it into a dictionary where keys are the <name>
77 fields, and values are the corresponding <value> fields.
78
79 Return the dictionary to the caller.
80 '''
81
82 rv = {}
83
84 items = line.replace('" ', '"^').split('^')
85 for item in items:
86 pieces = item.split('=')
87 if len(pieces) != 2:
84 continue 88 continue
85 # format name=v or name ? 89 rv[pieces[0]] = pieces[1].strip('"')
86 if section.find('=') >= 0: 90 return rv
87 k, v = section.split('=')
88 if v == '*':
89 v = 0 # spare section
90 else:
91 v = int(v, 0)
92 if v == 0:
93 raise TestError('Using size as 0 is prohibited now.')
94 else:
95 k, v = (section, 0) # spare, should appear for only one.
96 if v == 0:
97 spares = spares + 1
98 names.append(k)
99 sizes.append(v)
100 91
101 if spares != 1: 92 def check_layout(self, layout, file_size):
102 # each partition should have exactly one spare field 93 '''Verify the layout to be consistent.
103 return err_ret
104 94
105 spare_size = block_size - sum(sizes) 95 The layout is consistent if there is no overlapping sections and the
106 sizes[sizes.index(0)] = spare_size 96 section boundaries do not exceed the file size.
107 # fill sections
108 for i in range(len(names)):
109 # ignore unamed sections
110 if names[i] != '*':
111 layout[names[i]] = (offset, offset + sizes[i] - 1)
112 offset = offset + sizes[i]
113 97
114 return layout 98 Inputs:
99 layout: a dictionary keyed by a string (the section name) with
100 values being two integers tuples, the first and the last
101 bites' offset in the file.
102 file_size: and integer, the size of the file the layout describes
103 the sections in.
115 104
105 Raises:
106 TestError in case the layout is not consistent.
107 '''
108
109 # Generate a list of section range tuples.
110 ost = sorted([layout[section] for section in layout])
111 base = 0
112 for section_base, section_end in ost:
113 if section_base < base or section_end < section_base:
114 raise TestError('bad section at 0x%x..0x%x' % (
115 section_base, section_end))
116 base = section_end
117 if base > file_size:
118 raise TestError('Section end 0x%x exceeds file size %x' % (
119 base, file_size))
120
121 def get_layout(self, file_name):
122 '''Generate layout for a firmware file.
123
124 First retrieve the text layout as reported by 'mosys' and then convert
125 it into a dictionary, replacing section names reported by mosys into
126 matching names from DEFAULT_CHROMEOS_FMAP_CONVERSION dictionary above,
127 using the names as keys in the layout dictionary. The elements of the
128 layout dictionary are the offsets of the first ans last bytes of the
129 section in the firmware file.
130
131 Then verify the generated layout's consistency and return it to the
132 caller.
133 '''
134
135 layout_data = {} # keyed by the section name, elements - tuples of
136 # (<section start addr>, <section end addr>)
137
138 for line in self._get_text_layout(file_name):
139 d = self._line_to_dictionary(line)
140 try:
141 name = self.DEFAULT_CHROMEOS_FMAP_CONVERSION[d['area_name']]
142 except KeyError:
143 continue # This line does not contain an area of interest.
144
145 if name in layout_data:
146 raise TestError('%s duplicated in the layout' % area_name)
147
148 offset = int(d['area_offset'], 0)
149 size = int(d['area_size'], 0)
150 layout_data[name] = (offset, offset + size - 1)
151
152 self.check_layout(layout_data, os.stat(file_name)[stat.ST_SIZE])
153 return layout_data
116 154
117 # flashrom utility wrapper 155 # flashrom utility wrapper
118 class flashrom_util(object): 156 class flashrom_util(object):
119 """ a wrapper for "flashrom" utility. 157 """ a wrapper for "flashrom" utility.
120 158
121 You can read, write, or query flash ROM size with this utility. 159 You can read, write, or query flash ROM size with this utility.
122 Although you can do "partial-write", the tools always takes a 160 Although you can do "partial-write", the tools always takes a
123 full ROM image as input parameter. 161 full ROM image as input parameter.
124 162
125 NOTE before accessing flash ROM, you may need to first "select" 163 NOTE before accessing flash ROM, you may need to first "select"
126 your target - usually BIOS or EC. That part is not handled by 164 your target - usually BIOS or EC. That part is not handled by
127 this utility. Please find other external script to do it. 165 this utility. Please find other external script to do it.
128 166
129 To perform a read, you need to: 167 To perform a read, you need to:
130 1. Prepare a flashrom_util object 168 1. Prepare a flashrom_util object
131 ex: flashrom = flashrom_util.flashrom_util() 169 ex: flashrom = flashrom_util.flashrom_util()
132 2. Decide target (BIOS/EC) 170 2. Perform read operation
133 ex: flashrom.select_bios_flashrom()
134 3. Perform read operation
135 ex: image = flashrom.read_whole() 171 ex: image = flashrom.read_whole()
136 172
137 To perform a (partial) write, you need to: 173 When the contents of the flashrom is read off the target, it's map
138 1. Select target (BIOS/EC) 174 gets created automatically (read from the flashrom image using
139 ex: flashrom.select_ec_flashrom() 175 'mosys'). If the user wants this object to operate on some other file,
140 2. Create or load a layout map (see explain of layout below) 176 he could either have the map for the file created explicitly by
141 ex: layout_map = { 'all': (0, rom_size - 1) } 177 invoking flashrom.set_bios_layout(filename), or supply his own map
178 (which is a dictionary where keys are section names, and values are
179 tuples of integers, base address of the section and the last address
180 of the section).
181
182 By default this object operates on the map retrieved from the image and
183 stored locally, this map can be overwritten by an explicitly passed user
184 map.
185
186 To perform a (partial) write:
187
188 1. Prepare a buffer storing an image to be written into the flashrom.
189 2. Have the map generated automatically or prepare your own, for instance:
190 ex: layout_map_all = { 'all': (0, rom_size - 1) }
142 ex: layout_map = { 'ro': (0, 0xFFF), 'rw': (0x1000, rom_size-1) } 191 ex: layout_map = { 'ro': (0, 0xFFF), 'rw': (0x1000, rom_size-1) }
143 You can also use built-in layout like detect_chromeos_bios_layout(), 192 4. Perform write operation
144 detect_chromeos_layout(), or detect_layout() to build the layout maps.
145 3. Prepare a full base image
146 ex: image = flashrom.read_whole()
147 ex: image = chr(0xFF) * rom_size
148 4. (optional) Modify data in base image
149 ex: new_image = flashrom.put_section(image, layout_map, 'all', mydata)
150 5. Perform write operation
151 ex: flashrom.write_partial(new_image, layout_map, ('all',))
152 193
153 P.S: you can also create the new_image in your own way, for example: 194 ex using default map:
154 rom_size = flashrom_util.get_size() 195 flashrom.write_partial(new_image, (<section_name>, ...))
155 erase_image = chr(0xFF) * rom_size 196 ex using explicitly provided map:
156 flashrom.write_partial(erase_image, layout_map, ('all',)) 197 flashrom.write_partial(new_image, layout_map_all, ('all',))
157
158 The layout is a dictionary of { 'name': (address_begin, addres_end) }.
159 Note that address_end IS included in the range.
160 See help(detect_layout) for easier way to generate layout maps.
161 198
162 Attributes: 199 Attributes:
163 tool_path: file path to the tool 'flashrom'
164 cmd_prefix: prefix of every shell cmd, ex: "PATH=.:$PATH;export PATH;"
165 tmp_root: a folder name for mkstemp (for temp of layout and images)
166 verbose: print debug and helpful messages 200 verbose: print debug and helpful messages
167 keep_temp_files: boolean flag to control cleaning of temporary files 201 keep_temp_files: boolean flag to control cleaning of temporary files
168 target_map: map of what commands should be invoked to switch targets.
169 if you don't need any commands, use empty dict {}.
170 if you want default detection, use None (default param).
171 """ 202 """
172 203
173 # default target selection commands, by machine architecture 204 def __init__(self, verbose=False, keep_temp_files=False):
174 # syntax: { 'arch_regex': exec_script, ... }
175 default_arch_target_map = {
176 '^x86|^i\d86': {
177 # The magic numbers here are register indexes and values that apply
178 # to all current known x86 based ChromeOS devices.
179 # Detail information is defined in section #"10.1.50 GCS-General
180 # Control and Status Register" of document "Intel NM10 Express
181 # Chipsets".
182 "bios": 'iotools mmio_write32 0xfed1f410 ' +
183 '`iotools mmio_read32 0xfed1f410 |head -c 6`0460',
184 "ec": 'iotools mmio_write32 0xfed1f410 ' +
185 '`iotools mmio_read32 0xfed1f410 |head -c 6`0c60',
186 },
187 }
188
189 default_chromeos_layout_desc = {
190 "bios": """
191 FV_LOG = 0x20000,
192 NV_COMMON_STORE = 0x10000,
193 VBOOTA = 0x02000,
194 FVMAIN = 0xB0000,
195 VBOOTB = 0x02000,
196 FVMAINB = 0xB0000,
197 NVSTORAGE = 0x10000,
198 FV_RW_RESERVED = *,
199 |
200 FV_RO_RESERVED = *,
201 FVDEV = 0xB0000,
202 FV_GBB = 0x20000,
203 FV_BSTUB = 0x40000,
204 """,
205 "ec": """
206 EC_RO
207 |
208 EC_RW
209 """,
210 }
211
212 def __init__(self,
213 tool_path='/usr/sbin/flashrom',
214 cmd_prefix='',
215 tmp_root=None,
216 verbose=False,
217 keep_temp_files=False,
218 target_map=None):
219 """ constructor of flashrom_util. help(flashrom_util) for more info """ 205 """ constructor of flashrom_util. help(flashrom_util) for more info """
220 self.tool_path = tool_path
221 self.cmd_prefix = cmd_prefix
222 self.tmp_root = tmp_root
223 self.verbose = verbose 206 self.verbose = verbose
224 self.keep_temp_files = keep_temp_files 207 self.keep_temp_files = keep_temp_files
225 self.target_map = target_map 208 self.bios_layout = {}
226 # detect bbs map if target_map is None. 209 self.os_if = chromeos_interface.ChromeOSInterface(True)
227 # NOTE when target_map == {}, that means "do not execute commands", 210 self.os_if.init(tempfile.gettempdir())
228 # different to default value. 211 self._enable_bios_access()
229 if isinstance(target_map, types.NoneType): 212
230 # generate default target map 213 def _enable_bios_access(self):
231 self.target_map = self.detect_target_map() 214 if not self.os_if.target_hosted():
215 return
216 value = int(self.os_if.run_shell_command_get_output(
217 'iotools mmio_read32 0xfed1f410')[0], 0)
218 value = (value & 0xffff0000) + 0x460
219 self.os_if.run_shell_command(
220 'iotools mmio_write32 0xfed1f410 0x%x' % value)
232 221
233 def get_temp_filename(self, prefix): 222 def get_temp_filename(self, prefix):
234 ''' (internal) Returns name of a temporary file in self.tmp_root ''' 223 ''' (internal) Returns name of a temporary file in self.tmp_root '''
235 (fd, name) = tempfile.mkstemp(prefix=prefix, dir=self.tmp_root) 224 (fd, name) = tempfile.mkstemp(prefix=prefix)
236 os.close(fd) 225 os.close(fd)
237 return name 226 return name
238 227
239 def remove_temp_file(self, filename): 228 def remove_temp_file(self, filename):
240 """ (internal) Removes a temp file if self.keep_temp_files is false. """ 229 """ (internal) Removes a temp file if self.keep_temp_files is false. """
241 if self.keep_temp_files: 230 if self.keep_temp_files:
242 return 231 return
243 if os.path.exists(filename): 232 if os.path.exists(filename):
244 os.remove(filename) 233 os.remove(filename)
245 234
246 def create_layout_file(self, layout_map): 235 def create_layout_file(self, layout_map):
247 ''' 236 '''
248 (internal) Creates a layout file based on layout_map. 237 (internal) Creates a layout file based on layout_map.
249 Returns the file name containing layout information. 238 Returns the file name containing layout information.
250 ''' 239 '''
251 layout_text = ['0x%08lX:0x%08lX %s' % (v[0], v[1], k) 240 layout_text = ['0x%08lX:0x%08lX %s' % (v[0], v[1], k)
252 for k, v in layout_map.items()] 241 for k, v in layout_map.items()]
253 layout_text.sort() # XXX unstable if range exceeds 2^32 242 layout_text.sort() # XXX unstable if range exceeds 2^32
254 tmpfn = self.get_temp_filename('lay') 243 tmpfn = self.get_temp_filename('lay')
255 open(tmpfn, 'wb').write('\n'.join(layout_text) + '\n') 244 open(tmpfn, 'wb').write('\n'.join(layout_text) + '\n')
256 return tmpfn 245 return tmpfn
257 246
258 def get_section(self, base_image, layout_map, section_name): 247 def get_section(self, base_image, section_name):
259 ''' 248 '''
260 Retrieves a section of data based on section_name in layout_map. 249 Retrieves a section of data based on section_name in layout_map.
261 Raises error if unknown section or invalid layout_map. 250 Raises error if unknown section or invalid layout_map.
262 ''' 251 '''
263 pos = layout_map[section_name] 252 pos = self.bios_layout[section_name]
264 if pos[0] >= pos[1] or pos[1] >= len(base_image): 253 if pos[0] >= pos[1] or pos[1] >= len(base_image):
265 raise TestError('INTERNAL ERROR: invalid layout map: %s.' % 254 raise TestError('INTERNAL ERROR: invalid layout map: %s.' %
266 section_name) 255 section_name)
267 return base_image[pos[0] : pos[1] + 1] 256 return base_image[pos[0] : pos[1] + 1]
268 257
269 def put_section(self, base_image, layout_map, section_name, data): 258 def put_section(self, base_image, section_name, data):
270 ''' 259 '''
271 Updates a section of data based on section_name in layout_map. 260 Updates a section of data based on section_name in bios_layout.
272 Raises error if unknown section or invalid layout_map. 261 Raises error if unknown section.
273 Returns the full updated image data. 262 Returns the full updated image data.
274 ''' 263 '''
275 pos = layout_map[section_name] 264 pos = self.bios_layout[section_name]
276 if pos[0] >= pos[1] or pos[1] >= len(base_image): 265 if pos[0] >= pos[1] or pos[1] >= len(base_image):
277 raise TestError('INTERNAL ERROR: invalid layout map.') 266 raise TestError('INTERNAL ERROR: invalid layout map.')
278 if len(data) != pos[1] - pos[0] + 1: 267 if len(data) != pos[1] - pos[0] + 1:
279 raise TestError('INTERNAL ERROR: unmatched data size.') 268 raise TestError('INTERNAL ERROR: unmatched data size.')
280 return base_image[0 : pos[0]] + data + base_image[pos[1] + 1 :] 269 return base_image[0 : pos[0]] + data + base_image[pos[1] + 1 :]
281 270
282 def get_size(self): 271 def get_size(self):
283 """ Gets size of current flash ROM """ 272 """ Gets size of current flash ROM """
284 # TODO(hungte) Newer version of tool (flashrom) may support --get-size 273 # TODO(hungte) Newer version of tool (flashrom) may support --get-size
285 # command which is faster in future. Right now we use back-compatible 274 # command which is faster in future. Right now we use back-compatible
286 # method: read whole and then get length. 275 # method: read whole and then get length.
287 image = self.read_whole() 276 image = self.read_whole()
288 return len(image) 277 return len(image)
289 278
290 def detect_target_map(self): 279 def set_bios_layout(self, file_name):
291 """ 280 """get layout read from the BIOS """
292 Detects the target selection map.
293 Use machine architecture in current implementation.
294 """
295 arch = utils.get_arch()
296 for regex, target_map in self.default_arch_target_map.items():
297 if re.match(regex, arch):
298 return target_map
299 raise TestError('INTERNAL ERROR: unknown architecture, need target_map')
300 281
301 def detect_layout(self, layout_desciption, size=None): 282 scraper = LayoutScraper(self.os_if)
302 """ 283 self.bios_layout = scraper.get_layout(file_name)
303 Detects and builds layout according to current flash ROM size
304 and a simple layout description language.
305 If parameter 'size' is omitted, self.get_size() will be called.
306
307 See help(flashrom_util.compile_layout) for the syntax of description.
308
309 Returns the layout map (empty if any error).
310 """
311 if not size:
312 size = self.get_size()
313 return compile_layout(layout_desciption, size)
314
315 def detect_chromeos_layout(self, target, size=None):
316 """
317 Detects and builds ChromeOS firmware layout according to current flash
318 ROM size. If parameter 'size' is None, self.get_size() will be called.
319
320 Currently supported targets are: 'bios' or 'ec'.
321
322 Returns the layout map (empty if any error).
323 """
324 if target not in self.default_chromeos_layout_desc:
325 raise TestError('INTERNAL ERROR: unknown layout target: %s' % test)
326 chromeos_target = self.default_chromeos_layout_desc[target]
327 return self.detect_layout(chromeos_target, size)
328
329 def detect_chromeos_bios_layout(self, size=None):
330 """ Detects standard ChromeOS BIOS layout """
331 return self.detect_chromeos_layout('bios', size)
332
333 def detect_chromeos_ec_layout(self, size=None):
334 """ Detects standard ChromeOS Embedded Controller layout """
335 return self.detect_chromeos_layout('ec', size)
336 284
337 def read_whole(self): 285 def read_whole(self):
338 ''' 286 '''
339 Reads whole flash ROM data. 287 Reads whole flash ROM data.
340 Returns the data read from flash ROM, or empty string for other error. 288 Returns the data read from flash ROM, or empty string for other error.
341 ''' 289 '''
342 tmpfn = self.get_temp_filename('rd_') 290 tmpfn = self.get_temp_filename('rd_')
343 cmd = '%s"%s" -r "%s"' % (self.cmd_prefix, self.tool_path, tmpfn) 291 cmd = 'flashrom -r "%s"' % (tmpfn)
344 if self.verbose: 292 if self.verbose:
345 print 'flashrom_util.read_whole(): ', cmd 293 print 'flashrom_util.read_whole(): ', cmd
346 result = ''
347 294
348 if utils.system(cmd, ignore_status=True) == 0: # failure for non-zero 295 self.os_if.run_shell_command(cmd)
349 try: 296 result = open(tmpfn, 'rb').read()
350 result = open(tmpfn, 'rb').read() 297 self.set_bios_layout(tmpfn)
351 except IOError:
352 result = ''
353 298
354 # clean temporary resources 299 # clean temporary resources
355 self.remove_temp_file(tmpfn) 300 self.remove_temp_file(tmpfn)
356 return result 301 return result
357 302
358 def write_partial(self, base_image, layout_map, write_list): 303 def write_partial(self, base_image, write_list, write_layout_map=None):
359 ''' 304 '''
360 Writes data in sections of write_list to flash ROM. 305 Writes data in sections of write_list to flash ROM.
361 Returns True on success, otherwise False. 306 An exception is raised if write operation fails.
362 ''' 307 '''
308
309 if write_layout_map:
310 layout_map = write_layout_map
311 else:
312 layout_map = self.bios_layout
313
363 tmpfn = self.get_temp_filename('wr_') 314 tmpfn = self.get_temp_filename('wr_')
364 open(tmpfn, 'wb').write(base_image) 315 open(tmpfn, 'wb').write(base_image)
365 layout_fn = self.create_layout_file(layout_map) 316 layout_fn = self.create_layout_file(layout_map)
366 317
367 cmd = '%s"%s" -l "%s" -i %s -w "%s"' % ( 318 cmd = 'flashrom -l "%s" -i %s -w "%s"' % (
368 self.cmd_prefix, self.tool_path,
369 layout_fn, ' -i '.join(write_list), tmpfn) 319 layout_fn, ' -i '.join(write_list), tmpfn)
370 if self.verbose: 320 if self.verbose:
371 print 'flashrom.write_partial(): ', cmd 321 print 'flashrom.write_partial(): ', cmd
372 result = False
373 322
374 if utils.system(cmd, ignore_status=True) == 0: # failure for non-zero 323 self.os_if.run_shell_command(cmd)
375 result = True
376 324
377 # clean temporary resources 325 # clean temporary resources
378 self.remove_temp_file(tmpfn) 326 self.remove_temp_file(tmpfn)
379 self.remove_temp_file(layout_fn) 327 self.remove_temp_file(layout_fn)
380 return result
381 328
382 def select_target(self, target): 329 def write_whole(self, base_image):
383 ''' 330 '''Write the whole base image. '''
384 Selects (usually by setting BBS register) a target defined in target_map 331 layout_map = { 'all': (0, len(base_image) - 1) }
385 and then directs all further firmware access to certain region. 332 self.write_partial(base_image, ('all',), layout_map)
386 '''
387 if target not in self.target_map:
388 return True
389 if self.verbose:
390 print 'flashrom.select_target("%s"): %s' % (target,
391 self.target_map[target])
392 if utils.system(self.cmd_prefix + self.target_map[target],
393 ignore_status=True) == 0:
394 return True
395 return False
396
397 def select_bios_flashrom(self):
398 ''' Directs all further accesses to BIOS flash ROM. '''
399 return self.select_target('bios')
400
401 def select_ec_flashrom(self):
402 ''' Directs all further accesses to Embedded Controller flash ROM. '''
403 return self.select_target('ec')
404
405
406 # ---------------------------------------------------------------------------
407 # The flashrom_util supports both running inside and outside 'autotest'
408 # framework, so we need to provide some mocks and dynamically load
409 # autotest components here.
410
411
412 class mock_TestError(object):
413 """ a mock for error.TestError """
414 def __init__(self, msg):
415 print msg
416 sys.exit(1)
417
418
419 class mock_utils(object):
420 """ a mock for autotest_li.client.bin.utils """
421 def get_arch(self):
422 arch = os.popen('uname -m').read().rstrip()
423 arch = re.sub(r"i\d86", r"i386", arch, 1)
424 return arch
425
426 def system(self, cmd, ignore_status=False):
427 p = subprocess.Popen(cmd, shell=True,
428 stdout=subprocess.PIPE,
429 stderr=subprocess.PIPE)
430 p.wait()
431 if p.returncode:
432 print p.stdout.read()
433 if not ignore_status:
434 raise TestError("failed to execute: %s\nError messages: %s" % (
435 cmd, p.stderr.read()))
436 return p.returncode
437
438
439 # import autotest or mock utilities
440 try:
441 # print 'using autotest'
442 from autotest_lib.client.bin import test, utils
443 from autotest_lib.client.common_lib.error import TestError
444 except ImportError:
445 # print 'using mocks'
446 utils = mock_utils()
447 TestError = mock_TestError
448
449
450 # main stub
451 if __name__ == "__main__":
452 # TODO(hungte) provide unit tests or command line usage
453 pass
OLDNEW
« no previous file with comments | « saft/test_kernel_handler.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698