Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 #!/usr/bin/env python2.6 | |
|
gauravsh
2011/01/04 21:14:39
make this version independent
Hung-Te
2011/01/05 03:33:54
That reminds me something. Che-Liang used "with" w
Che-Liang Chiou
2011/01/05 08:01:55
The coding style asks for the shebang line with a
gauravsh
2011/01/06 02:06:45
Chromium OS follows PEP-8, not Google python style
| |
| 2 | |
| 3 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved. | |
|
gauravsh
2011/01/04 21:14:39
2011
Che-Liang Chiou
2011/01/05 08:01:55
Done.
| |
| 4 # Use of this source code is governed by a BSD-style license that can be | |
| 5 # found in the LICENSE file. | |
| 6 | |
| 7 import mmap | |
| 8 import os | |
| 9 import re | |
| 10 import struct | |
| 11 import subprocess | |
| 12 import sys | |
| 13 import tempfile | |
| 14 | |
| 15 # TODO(clchiou): Rewrite this part by importing fmap after David's fmap | |
|
Hung-Te
2011/01/04 10:05:23
Please use "official" instead of "David's"
Che-Liang Chiou
2011/01/05 08:01:55
Done.
| |
| 16 # implementation is pulled into Chromium OS code base | |
| 17 | |
| 18 FMAP_SIGNATURE = "__FMAP__" | |
| 19 | |
| 20 FMAP_AREA_STATIC = 1 << 0 | |
| 21 FMAP_AREA_COMPRESSED = 1 << 1 | |
| 22 FMAP_AREA_RO = 1 << 2 | |
| 23 | |
| 24 FMAP_STRLEN = 32 | |
| 25 FMAP_HEADER_FORMAT = "<8sBBQI%dsH" % FMAP_STRLEN | |
| 26 FMAP_AREA_FORMAT = "<II%dsH" % FMAP_STRLEN | |
| 27 | |
| 28 FMAP_HEADER_NAMES = ( | |
| 29 'signature', | |
| 30 'ver_major', | |
| 31 'ver_minor', | |
| 32 'base', | |
| 33 'size', | |
| 34 'name', | |
| 35 'nareas', | |
| 36 ) | |
| 37 | |
| 38 FMAP_AREA_NAMES = ( | |
| 39 'offset', | |
| 40 'size', | |
| 41 'name', | |
| 42 'flags', | |
| 43 ) | |
| 44 | |
| 45 RE_ASSIGNMENT = re.compile(r'^(\w+)=(.*)$') | |
| 46 | |
| 47 VERBOSE = False | |
| 48 | |
| 49 | |
| 50 class ConfigError(Exception): | |
| 51 pass | |
| 52 | |
| 53 | |
| 54 class PackError(Exception): | |
| 55 pass | |
| 56 | |
| 57 | |
| 58 class Entry(dict): | |
|
gauravsh
2011/01/04 21:14:39
general comment our python style - Chromium OS fol
Che-Liang Chiou
2011/01/05 08:01:55
Done.
| |
| 59 | |
| 60 @staticmethod | |
| 61 def _check_fields(kwargs, fields): | |
| 62 for f in fields: | |
| 63 if f not in kwargs: | |
| 64 raise ConfigError('Entry: missing required field: %s' % f) | |
| 65 | |
| 66 def __init__(self, **kwargs): | |
| 67 Entry._check_fields(kwargs, ('offset', 'length', 'name')) | |
| 68 super(Entry, self).__init__(kwargs) | |
| 69 | |
| 70 def __getattr__(self, name): | |
| 71 return self[name] | |
| 72 | |
| 73 def is_overlapped(self, entry): | |
| 74 return entry.offset <= self.offset < entry.offset + entry.length or \ | |
|
gauravsh
2011/01/04 21:14:39
you can get rid of the \ and use implicit line bre
Che-Liang Chiou
2011/01/05 08:01:55
Done.
| |
| 75 self.offset <= entry.offset < self.offset + self.length | |
| 76 | |
| 77 def pack(self, fw_image, entries): | |
| 78 raise PackError('class Entry does not implement pack()') | |
| 79 | |
| 80 | |
| 81 class EntryFmap(Entry): | |
| 82 | |
| 83 def __init__(self, **kwargs): | |
| 84 Entry._check_fields(kwargs, ('ver_major', 'ver_minor', 'base', 'size')) | |
| 85 super(EntryFmap, self).__init__(**kwargs) | |
| 86 | |
| 87 def pack(self, fw_image, entries): | |
| 88 areas = [e for e in entries | |
| 89 if isinstance(e, EntryBlob) or isinstance(e, EntryKeyBlock)] | |
| 90 areas.sort(key=lambda a: a.offset) | |
| 91 | |
| 92 offset = 0 | |
| 93 | |
| 94 # pack header | |
| 95 values = [] | |
| 96 for name in FMAP_HEADER_NAMES: | |
| 97 if name == 'nareas': | |
| 98 v = len(areas) | |
| 99 elif name == 'signature': | |
| 100 v = FMAP_SIGNATURE | |
| 101 else: | |
| 102 v = self[name] | |
| 103 values.append(v) | |
| 104 offset = self._append(fw_image, offset, | |
| 105 struct.pack(FMAP_HEADER_FORMAT, *values)) | |
| 106 | |
| 107 # pack areas | |
| 108 for a in areas: | |
| 109 values = [a.length if name == 'size' else a[name] | |
| 110 for name in FMAP_AREA_NAMES] | |
| 111 offset = self._append(fw_image, offset, | |
| 112 struct.pack(FMAP_AREA_FORMAT, *values)) | |
| 113 | |
| 114 if offset > self.length: | |
| 115 raise PackError('fmap too large: %d > %d' % (offset, self.length)) | |
| 116 | |
| 117 def _append(self, fw_image, offset, blob): | |
| 118 size = len(blob) | |
| 119 fw_image[self.offset+offset:self.offset+offset+size] = blob | |
| 120 return offset + size | |
| 121 | |
| 122 | |
| 123 class EntryBlob(Entry): | |
| 124 | |
| 125 def __init__(self, **kwargs): | |
| 126 Entry._check_fields(kwargs, ('flags', 'path')) | |
| 127 super(EntryBlob, self).__init__(**kwargs) | |
| 128 | |
| 129 def pack(self, fw_image, entries): | |
| 130 size = os.stat(self.path).st_size | |
| 131 if size > 0: | |
| 132 size = min(size, self.length) | |
| 133 else: | |
| 134 size = self.length | |
| 135 with open(self.path, 'r+b') as f: | |
| 136 fvimg = mmap.mmap(f.fileno(), size, mmap.MAP_PRIVATE, mmap.PROT_READ) | |
|
gauravsh
2011/01/04 21:14:39
i am not sure the performance improvement from mma
Che-Liang Chiou
2011/01/05 08:01:55
Done.
| |
| 137 fw_image.seek(self.offset) | |
| 138 fw_image.write(fvimg[0:size]) | |
| 139 fvimg.close() | |
| 140 | |
| 141 | |
| 142 class EntryKeyBlock(Entry): | |
| 143 | |
| 144 def __init__(self, **kwargs): | |
| 145 Entry._check_fields(kwargs, | |
| 146 ('flags', 'keyblock', 'signprivate', 'version', 'fv', 'kernelkey')) | |
| 147 super(EntryKeyBlock, self).__init__(**kwargs) | |
| 148 | |
| 149 def pack(self, fw_image, entries): | |
| 150 fd, path = tempfile.mkstemp() | |
| 151 try: | |
| 152 args = [ | |
| 153 'vbutil_firmware', | |
| 154 '--vblock', path, | |
| 155 '--keyblock', self.keyblock, | |
| 156 '--signprivate', self.signprivate, | |
| 157 '--version', '%d' % self.version, | |
| 158 '--fv', self.fv, | |
| 159 '--kernelkey', self.kernelkey, | |
| 160 ] | |
| 161 if VERBOSE: | |
| 162 stdout = sys.stdout | |
| 163 stderr = sys.stderr | |
| 164 else: | |
| 165 stdout = None | |
|
gauravsh
2011/01/04 21:14:39
this could be declared as a class variable right a
Che-Liang Chiou
2011/01/05 08:01:55
Done.
| |
| 166 stderr = None | |
| 167 info('run: %s' % ' '.join(args)) | |
| 168 proc = subprocess.Popen(args, stdout=stdout, stderr=stderr) | |
| 169 proc.wait() | |
| 170 if proc.returncode != 0: | |
| 171 raise PackError('cannot make key block: vbutil_firmware returns %d' % | |
| 172 proc.returncode) | |
| 173 | |
| 174 img = mmap.mmap(fd, 0, mmap.MAP_PRIVATE, mmap.PROT_READ) | |
|
gauravsh
2011/01/04 21:14:39
in general, Google style recommends not using shor
Che-Liang Chiou
2011/01/05 08:01:55
Done.
| |
| 175 size = img.size() | |
| 176 if size > self.length: | |
| 177 img.close() | |
| 178 raise PackError('key block too large: %d > %d' % (size, self.length)) | |
| 179 fw_image.seek(self.offset) | |
| 180 fw_image.write(img) | |
| 181 img.close() | |
| 182 finally: | |
| 183 os.unlink(path) | |
| 184 | |
| 185 | |
| 186 def parse_assignment(stmt): | |
| 187 m = RE_ASSIGNMENT.match(stmt) | |
| 188 if m is None: | |
| 189 raise ConfigError('illegal statement: %s' % repr(stmt)) | |
| 190 return (m.group(1), parse_value(m.group(2))) | |
| 191 | |
| 192 | |
| 193 def parse_value(expr): | |
| 194 if (expr.startswith('"') and expr.endswith('"')) or \ | |
|
Hung-Te
2011/01/04 10:05:23
You can use implicit multi-line expression, like
Che-Liang Chiou
2011/01/05 08:01:55
Done.
| |
| 195 (expr.startswith("'") and expr.endswith("'")): | |
| 196 expr = expr[1:-1] | |
|
Hung-Te
2011/01/04 10:05:23
return expr[1:-1] ?
Otherwise it'll be converted t
Che-Liang Chiou
2011/01/05 08:01:55
Done.
| |
| 197 try: | |
| 198 return int(expr, 0) | |
| 199 except ValueError: | |
| 200 return expr # if not a number, interpret as string literals | |
| 201 | |
| 202 | |
| 203 def pack_image(entries, output_path, image_size): | |
| 204 entries = sorted(entries, key=lambda e: e.offset) | |
| 205 for e1, e2 in zip(entries, entries[1:]): | |
| 206 if e1.is_overlapped(e2): | |
| 207 raise PackError('overlapped entries: [%08x:%08x], [%08x:%08x]' % | |
| 208 (e1.offset, e1.offset + e1.length, e2.offset, e2.offset + e2.length)) | |
| 209 | |
| 210 # create image so that mmap will succeed | |
| 211 with open(output_path, 'w+b') as f: | |
|
gauravsh
2011/01/04 21:14:39
again don't use 'f' here. Use 'file'. The only pla
Hung-Te
2011/01/05 03:33:54
P.S: 'file' is a special keyword in python -- some
Che-Liang Chiou
2011/01/05 08:01:55
Done; avoid use 'file'.
| |
| 212 f.write('\0') | |
| 213 | |
| 214 with open(output_path, 'rw+b') as f: | |
| 215 fw_image = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_WRITE) | |
| 216 fw_image.resize(image_size) | |
| 217 for entry in entries: | |
| 218 entry.pack(fw_image, entries) | |
| 219 fw_image.flush() | |
| 220 fw_image.close() | |
| 221 | |
| 222 | |
| 223 def info(msg): | |
| 224 if VERBOSE: | |
| 225 print >>sys.stderr, 'INFO: %s' % msg | |
| 226 | |
| 227 | |
| 228 def main(): | |
| 229 global VERBOSE | |
| 230 | |
| 231 if len(sys.argv) < 2: | |
| 232 print 'Usage: %s [-v] CONFIG_FILE [NAME=VALUE...]' % sys.argv[0] | |
| 233 sys.exit(1) | |
| 234 | |
| 235 if sys.argv[1] == '-v': | |
| 236 VERBOSE = True | |
| 237 argv = sys.argv[0:1] + sys.argv[2:] | |
| 238 else: | |
| 239 argv = sys.argv | |
| 240 | |
| 241 if len(argv) > 2: | |
| 242 env = dict(parse_assignment(stmt) for stmt in argv[2:]) | |
| 243 else: | |
| 244 env = {} | |
| 245 | |
| 246 execfile(argv[1], globals(), env) | |
| 247 | |
| 248 for varname in ('ENTRIES', 'OUTPUT', 'SIZE'): | |
| 249 if varname not in env: | |
| 250 raise ConfigError('undefined variable: %s' % varname) | |
| 251 info('%s = %s' % (varname, repr(env[varname]))) | |
| 252 | |
| 253 pack_image(env['ENTRIES'], env['OUTPUT'], env['SIZE']) | |
| 254 | |
| 255 sys.exit(0) | |
| 256 | |
| 257 | |
| 258 if __name__ == '__main__': | |
| 259 main() | |
| OLD | NEW |