blob: 4dc95d8bc7d3edd86683dd49a4754165ad841ac0 [file] [log] [blame]
Steve Kondik2cd36232016-07-14 14:53:51 -07001# Copyright (C) 2009 The Android Open Source Project
2# Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
16"""Emit commands needed for QCOM devices during OTA installation
17(installing the radio image)."""
18
19import common
20import re
21
22
23bootImages = {}
24binImages = {}
25fwImages = {}
Louis Popic6a3c3e2016-07-16 16:19:13 +020026imgImages = {}
Steve Kondik2cd36232016-07-14 14:53:51 -070027
28# Parse filesmap file containing firmware residing places
29def LoadFilesMap(zip, name="RADIO/filesmap"):
30 try:
31 data = zip.read(name)
32 except KeyError:
33 print "Warning: could not find %s in %s." % (name, zip)
34 data = ""
35 d = {}
36 for line in data.split("\n"):
37 line = line.strip()
38 if not line or line.startswith("#"):
39 continue
40 pieces = line.split()
41 if not (len(pieces) == 2):
42 raise ValueError("malformed filesmap line: \"%s\"" % (line,))
43 d[pieces[0]] = pieces[1]
44 return d
45
46
47# Read firmware images from target files zip
48def GetRadioFiles(z):
49 out = {}
50 for info in z.infolist():
51 f = info.filename
52 if f.startswith("RADIO/") and (f.__len__() > len("RADIO/")):
53 fn = f[6:]
54 if fn.startswith("filesmap"):
55 continue
56 data = z.read(f)
57 out[fn] = common.File(f, data)
58 return out
59
60
61# Get firmware residing place from filesmap
62def GetFileDestination(fn, filesmap):
63 # if file is encoded disregard the .enc extention
64 if fn.endswith('.enc'):
65 fn = fn[:-4]
66
67 # get backup destination as well if present
68 backup = None
69 if fn + ".bak" in filesmap:
70 backup = filesmap[fn + ".bak"]
71
72 # If full filename is not specified in filesmap get only the name part
73 # and look for this token
74 if fn not in filesmap:
75 fn = fn.split(".")[0] + ".*"
76 if fn not in filesmap:
77 print "warning radio-update: '%s' not found in filesmap" % (fn)
78 return None, backup
79 return filesmap[fn], backup
80
81
82# Separate image types as each type needs different handling
83def SplitFwTypes(files):
84 boot = {}
85 bin = {}
86 fw = {}
Louis Popic6a3c3e2016-07-16 16:19:13 +020087 img = {}
Steve Kondik2cd36232016-07-14 14:53:51 -070088
89 for f in files:
90 extIdx = -1
91 dotSeparated = f.split(".")
92 while True:
93 if dotSeparated[extIdx] != 'p' and dotSeparated[extIdx] != 'enc':
94 break
95 extIdx -= 1
96
97 if dotSeparated[extIdx] == 'mbn' or dotSeparated[extIdx] == 'elf':
98 boot[f] = files[f]
99 elif dotSeparated[extIdx] == 'bin':
100 bin[f] = files[f]
Louis Popic6a3c3e2016-07-16 16:19:13 +0200101 elif dotSeparated[extIdx] == 'img':
102 img[f] = files[f]
Steve Kondik2cd36232016-07-14 14:53:51 -0700103 else:
104 fw[f] = files[f]
Louis Popic6a3c3e2016-07-16 16:19:13 +0200105 return boot, bin, fw, img
Steve Kondik2cd36232016-07-14 14:53:51 -0700106
107
108# Prepare radio-update files and verify them
109def OTA_VerifyEnd(info, api_version, target_zip, source_zip=None):
110 if api_version < 3:
111 print "warning radio-update: no support for api_version less than 3"
112 return False
113
114 print "Loading radio filesmap..."
115 filesmap = LoadFilesMap(target_zip)
116 if filesmap == {}:
117 print "warning radio-update: no or invalid filesmap file found"
118 return False
119
120 print "Loading radio target..."
121 tgt_files = GetRadioFiles(target_zip)
122 if tgt_files == {}:
123 print "warning radio-update: no radio images in input target_files"
124 return False
125
126 src_files = None
127 if source_zip is not None:
128 print "Loading radio source..."
129 src_files = GetRadioFiles(source_zip)
130
131 update_list = {}
132 largest_source_size = 0
133
134 print "Preparing radio-update files..."
135 for fn in tgt_files:
136 dest, destBak = GetFileDestination(fn, filesmap)
137 if dest is None:
138 continue
139
140 tf = tgt_files[fn]
141 sf = None
142 if src_files is not None:
143 sf = src_files.get(fn, None)
144
145 full = sf is None or fn.endswith('.enc')
146 if not full:
147 # no difference - skip this file
148 if tf.sha1 == sf.sha1:
149 continue
150 d = common.Difference(tf, sf)
151 _, _, d = d.ComputePatch()
152 # no difference - skip this file
153 if d is None:
154 continue
155 # if patch is almost as big as the file - don't bother patching
156 full = len(d) > tf.size * common.OPTIONS.patch_threshold
157 if not full:
158 f = "patch/firmware-update/" + fn + ".p"
159 common.ZipWriteStr(info.output_zip, f, d)
160 update_list[f] = (dest, destBak, tf, sf)
161 largest_source_size = max(largest_source_size, sf.size)
162 if full:
163 f = "firmware-update/" + fn
164 common.ZipWriteStr(info.output_zip, f, tf.data)
165 update_list[f] = (dest, destBak, None, None)
166
167 global bootImages
168 global binImages
169 global fwImages
Louis Popic6a3c3e2016-07-16 16:19:13 +0200170 global imgImages
171 bootImages, binImages, fwImages, imgImages = SplitFwTypes(update_list)
Steve Kondik2cd36232016-07-14 14:53:51 -0700172
173 # If there are incremental patches verify them
174 if largest_source_size != 0:
175 info.script.Comment("---- radio update verification ----")
176 info.script.Print("Verifying radio-update...")
177
178 for f in bootImages:
179 dest, destBak, tf, sf = bootImages[f]
180 # Not incremental
181 if sf is None:
182 continue
183 info.script.PatchCheck("EMMC:%s:%d:%s:%d:%s" %
184 (dest, sf.size, sf.sha1, tf.size, tf.sha1))
185 if destBak is not None:
186 info.script.PatchCheck("EMMC:%s:%d:%s:%d:%s" %
187 (destBak, sf.size, sf.sha1, tf.size, tf.sha1))
188 for f in binImages:
189 dest, destBak, tf, sf = binImages[f]
190 # Not incremental
191 if sf is None:
192 continue
193 info.script.PatchCheck("EMMC:%s:%d:%s:%d:%s" %
194 (dest, sf.size, sf.sha1, tf.size, tf.sha1))
Steve Kondik2cd36232016-07-14 14:53:51 -0700195 last_mounted = ""
196 for f in fwImages:
197 dest, destBak, tf, sf = fwImages[f]
198 # Not incremental
199 if sf is None:
200 continue
201 # Get the filename without the path and the patch (.p) extention
202 f = f.split("/")[-1][:-2]
203 # Parse filesmap destination paths for "/dev/" pattern in the beginng.
204 # This would mean that the file must be written to block device -
205 # fs mount needed
206 if dest.startswith("/dev/"):
207 if last_mounted != dest:
208 info.script.AppendExtra('unmount("/firmware");')
209 info.script.AppendExtra('mount("vfat", "EMMC", "%s", "/firmware");' %
210 (dest))
211 last_mounted = dest
212 dest = "/firmware/image/" + f
213 else:
214 dest = dest + "/" + f
215 info.script.PatchCheck(dest, tf.sha1, sf.sha1)
Louis Popic6a3c3e2016-07-16 16:19:13 +0200216 for f in imgImages:
217 dest, tf, sf = imgImages[f]
218 # Not incremental
219 if sf is None:
220 continue
221 info.script.PatchCheck("EMMC:%s:%d:%s:%d:%s" %
222 (dest, sf.size, sf.sha1, tf.size, tf.sha1))
223 last_mounted = ""
Steve Kondik2cd36232016-07-14 14:53:51 -0700224
225 info.script.CacheFreeSpaceCheck(largest_source_size)
226 return True
227
228
229def FullOTA_Assertions(info):
230 #TODO: Implement device specific asserstions.
231 return
232
233
234def IncrementalOTA_Assertions(info):
235 #TODO: Implement device specific asserstions.
236 return
237
238
239def IncrementalOTA_VerifyEnd(info):
240 OTA_VerifyEnd(info, info.target_version, info.target_zip, info.source_zip)
241 return
242
243
244# This function handles only non-HLOS whole partition images
245def InstallRawImage(script, f, dest, tf, sf):
246 if f.endswith('.p'):
247 script.ApplyPatch("EMMC:%s:%d:%s:%d:%s" %
248 (dest, sf.size, sf.sha1, tf.size, tf.sha1),
249 "-", tf.size, tf.sha1, sf.sha1, f)
250 elif f.endswith('.enc'):
251 # Get the filename without the path
252 fn = f.split("/")[-1]
253 script.AppendExtra('package_extract_file("%s", "/tmp/%s");' % (f, fn))
254 script.AppendExtra('msm.decrypt("/tmp/%s", "%s");' % (fn, dest))
255 else:
256 script.AppendExtra('package_extract_file("%s", "%s");' % (f, dest))
257 return
258
259
260# This function handles only non-HLOS boot images - files list must contain
261# only such images (aboot, tz, etc)
262def InstallBootImages(script, files):
263 bakExists = False
264 # update main partitions
265 script.AppendExtra('ifelse(msm.boot_update("main"), (')
266 for f in files:
267 dest, destBak, tf, sf = files[f]
268 if destBak is not None:
269 bakExists = True
270 InstallRawImage(script, f, dest, tf, sf)
271 script.AppendExtra('), "");')
272
273 # update backup partitions
274 if bakExists:
275 script.AppendExtra('ifelse(msm.boot_update("backup"), (')
276 for f in files:
277 dest, destBak, tf, sf = files[f]
278 if destBak is not None:
279 InstallRawImage(script, f, destBak, tf, sf)
280 script.AppendExtra('), "");')
281 # just finalize primary update stage
282 else:
283 script.AppendExtra('msm.boot_update("backup");')
284
285 # finalize partitions update
286 script.AppendExtra('msm.boot_update("finalize");')
287 return
288
289
290# This function handles only non-HLOS bin images
291def InstallBinImages(script, files):
292 for f in files:
293 dest, _, tf, sf = files[f]
294 InstallRawImage(script, f, dest, tf, sf)
295 return
296
297
298# This function handles only non-HLOS firmware files that are not whole
299# partition images (modem, dsp, etc)
300def InstallFwImages(script, files):
301 last_mounted = ""
302
303 for f in files:
304 dest, _, tf, sf = files[f]
305 # Get the filename without the path
306 fn = f.split("/")[-1]
307 # Parse filesmap destination paths for "/dev/" pattern in the beginng.
308 # This would mean that the file must be written to block device -
309 # fs mount needed
310 if dest.startswith("/dev/"):
311 if last_mounted != dest:
312 script.AppendExtra('unmount("/firmware");')
313 script.AppendExtra('mount("vfat", "EMMC", "%s", "/firmware");' %
314 (dest))
315 last_mounted = dest
316 dest = "/firmware/image/" + fn
317 else:
318 dest = dest + "/" + fn
319
320 if f.endswith('.p'):
321 script.ApplyPatch(dest[:-2], "-", tf.size, tf.sha1, sf.sha1, f)
322 elif f.endswith('.enc'):
323 script.AppendExtra('package_extract_file("%s", "/tmp/%s");' % (f, fn))
324 script.AppendExtra('msm.decrypt("/tmp/%s", "%s");' % (fn, dest[:-4]))
325 else:
326 script.AppendExtra('package_extract_file("%s", "%s");' % (f, dest))
327
328 if last_mounted != "":
329 script.AppendExtra('unmount("/firmware");')
330 return
331
Louis Popic6a3c3e2016-07-16 16:19:13 +0200332# This function handles *.img images
333def InstallImgImages(script, files):
334 for f in files:
335 dest, _, tf, sf = files[f]
336 InstallRawImage(script, f, dest, tf, sf)
337 return
338
Steve Kondik2cd36232016-07-14 14:53:51 -0700339
340def OTA_InstallEnd(info):
341 print "Applying radio-update script modifications..."
342 info.script.Comment("---- radio update tasks ----")
343 info.script.Print("Patching firmware images...")
344
345 if bootImages != {}:
346 InstallBootImages(info.script, bootImages)
347 if binImages != {}:
348 InstallBinImages(info.script, binImages)
349 if fwImages != {}:
350 InstallFwImages(info.script, fwImages)
Louis Popic6a3c3e2016-07-16 16:19:13 +0200351 if imgImages != {}:
352 InstallImgImages(info.script, imgImages)
Steve Kondik2cd36232016-07-14 14:53:51 -0700353 return
354
355
356def FullOTA_InstallEnd_MMC(info):
357 if OTA_VerifyEnd(info, info.input_version, info.input_zip):
358 OTA_InstallEnd(info)
359 return
360
361
362def FullOTA_InstallEnd_MTD(info):
363 print "warning radio-update: radio update for NAND devices not supported"
364 return
365
366
367def FullOTA_InstallEnd(info):
368 FullOTA_InstallEnd_MMC(info)
369 return
370
371def IncrementalOTA_InstallEnd_MMC(info):
372 OTA_InstallEnd(info)
373 return
374
375
376def IncrementalOTA_InstallEnd_MTD(info):
377 print "warning radio-update: radio update for NAND devices not supported"
378 return
379
380def IncrementalOTA_InstallEnd(info):
381 IncrementalOTA_InstallEnd_MMC(info)
382 return