blob: 938952ae7fcceaf46c226e60bdbe8dc4385f6e03 [file] [log] [blame]
Hung-Te Linc83105f2011-03-16 18:38:04 +08001#!/usr/bin/env python
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
4# found in the LICENSE file.
5"""
6This module provides basic encode and decode functionality to the flashrom
7memory map (FMAP) structure.
8
9Usage:
10 (decode)
11 obj = fmap_decode(blob)
12 print obj
13
14 (encode)
15 blob = fmap_encode(obj)
16 open('output.bin', 'w').write(blob)
17
18 The object returned by fmap_decode is a dictionary with names defined in
19 fmap.h. A special property 'FLAGS' is provided as a readable and read-only
20 tuple of decoded area flags.
21"""
22
Tammo Spalink01e11722012-07-24 10:17:54 -070023
Hung-Te Linc83105f2011-03-16 18:38:04 +080024import struct
Tammo Spalink01e11722012-07-24 10:17:54 -070025
Hung-Te Linc83105f2011-03-16 18:38:04 +080026
27# constants imported from lib/fmap.h
28FMAP_SIGNATURE = "__FMAP__"
29FMAP_VER_MAJOR = 1
30FMAP_VER_MINOR_MIN = 0
31FMAP_VER_MINOR_MAX = 1
32FMAP_STRLEN = 32
33
34FMAP_FLAGS = {
35 'FMAP_AREA_STATIC': 1 << 0,
36 'FMAP_AREA_COMPRESSED': 1 << 1,
37}
38
39FMAP_HEADER_NAMES = (
40 'signature',
41 'ver_major',
42 'ver_minor',
43 'base',
44 'size',
45 'name',
46 'nareas',
47)
48
49FMAP_AREA_NAMES = (
50 'offset',
51 'size',
52 'name',
53 'flags',
54)
55
Tammo Spalink01e11722012-07-24 10:17:54 -070056
Hung-Te Linc83105f2011-03-16 18:38:04 +080057# format string
58FMAP_HEADER_FORMAT = "<8sBBQI%dsH" % (FMAP_STRLEN)
59FMAP_AREA_FORMAT = "<II%dsH" % (FMAP_STRLEN)
60
61
62def _fmap_decode_header(blob, offset):
63 """ (internal) Decodes a FMAP header from blob by offset"""
64 header = {}
65 for (name, value) in zip(FMAP_HEADER_NAMES,
66 struct.unpack_from(FMAP_HEADER_FORMAT,
67 blob,
68 offset)):
69 header[name] = value
70
71 if header['signature'] != FMAP_SIGNATURE:
72 raise struct.error('Invalid signature')
73 if (header['ver_major'] != FMAP_VER_MAJOR or
74 header['ver_minor'] < FMAP_VER_MINOR_MIN or
75 header['ver_minor'] > FMAP_VER_MINOR_MAX):
76 raise struct.error('Incompatible version')
77
78 # convert null-terminated names
79 header['name'] = header['name'].strip(chr(0))
80 return (header, struct.calcsize(FMAP_HEADER_FORMAT))
81
82
83def _fmap_decode_area(blob, offset):
84 """ (internal) Decodes a FMAP area record from blob by offset """
85 area = {}
86 for (name, value) in zip(FMAP_AREA_NAMES,
87 struct.unpack_from(FMAP_AREA_FORMAT, blob, offset)):
88 area[name] = value
89 # convert null-terminated names
90 area['name'] = area['name'].strip(chr(0))
91 # add a (readonly) readable FLAGS
92 area['FLAGS'] = _fmap_decode_area_flags(area['flags'])
93 return (area, struct.calcsize(FMAP_AREA_FORMAT))
94
95
96def _fmap_decode_area_flags(area_flags):
97 """ (internal) Decodes a FMAP flags property """
98 return tuple([name for name in FMAP_FLAGS if area_flags & FMAP_FLAGS[name]])
99
100
101def fmap_decode(blob, offset=None):
102 """ Decodes a blob to FMAP dictionary object.
103
104 Arguments:
105 blob: a binary data containing FMAP structure.
106 offset: starting offset of FMAP. When omitted, fmap_decode will search in
107 the blob.
108 """
109 fmap = {}
110 if offset == None:
111 # try search magic in fmap
112 offset = blob.find(FMAP_SIGNATURE)
113 (fmap, size) = _fmap_decode_header(blob, offset)
114 fmap['areas'] = []
115 offset = offset + size
Tammo Spalink01e11722012-07-24 10:17:54 -0700116 for _ in range(fmap['nareas']):
Hung-Te Linc83105f2011-03-16 18:38:04 +0800117 (area, size) = _fmap_decode_area(blob, offset)
118 offset = offset + size
119 fmap['areas'].append(area)
120 return fmap
121
122
123def _fmap_encode_header(obj):
124 """ (internal) Encodes a FMAP header """
125 values = [obj[name] for name in FMAP_HEADER_NAMES]
126 return struct.pack(FMAP_HEADER_FORMAT, *values)
127
128
129def _fmap_encode_area(obj):
130 """ (internal) Encodes a FMAP area entry """
131 values = [obj[name] for name in FMAP_AREA_NAMES]
132 return struct.pack(FMAP_AREA_FORMAT, *values)
133
134
135def fmap_encode(obj):
136 """ Encodes a FMAP dictionary object to blob.
137
138 Arguments
139 obj: a FMAP dictionary object.
140 """
141 # fix up values
142 obj['nareas'] = len(obj['areas'])
143 # TODO(hungte) re-assign signature / version?
144 blob = _fmap_encode_header(obj)
145 for area in obj['areas']:
146 blob = blob + _fmap_encode_area(area)
147 return blob
148
149
Tammo Spalink01e11722012-07-24 10:17:54 -0700150def main():
151 """Unit test."""
Hung-Te Linc83105f2011-03-16 18:38:04 +0800152 blob = open('bin/example.bin').read()
153 obj = fmap_decode(blob)
154 print obj
155 blob2 = fmap_encode(obj)
156 obj2 = fmap_decode(blob2)
157 print obj2
158 assert obj == obj2
Tammo Spalink01e11722012-07-24 10:17:54 -0700159
160
161if __name__ == '__main__':
162 main()