blob: 4e02144c2dade8fdcba5572f29ff97a78efd3e08 [file] [log] [blame]
Shashank Mittal874d47a2011-12-02 21:36:26 -08001# Copyright (C) 2009 The Android Open Source Project
Stanimir Varbanova220ab42013-07-17 15:37:00 +03002# Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
Shashank Mittal874d47a2011-12-02 21:36:26 -08003#
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
Pavel Nedevca5eaa42013-08-20 17:53:18 +030022
23bootImages = {}
24binImages = {}
25fwImages = {}
26
27
28# Parse filesmap file containing firmware residing places
Stanimir Varbanova220ab42013-07-17 15:37:00 +030029def LoadFilesMap(zip, name="RADIO/filesmap"):
Shashank Mittaleb866e22011-12-09 00:20:36 -080030 try:
Stanimir Varbanova220ab42013-07-17 15:37:00 +030031 data = zip.read(name)
Shashank Mittaleb866e22011-12-09 00:20:36 -080032 except KeyError:
Stanimir Varbanova220ab42013-07-17 15:37:00 +030033 print "Warning: could not find %s in %s." % (name, zip)
Shashank Mittaleb866e22011-12-09 00:20:36 -080034 data = ""
35 d = {}
36 for line in data.split("\n"):
37 line = line.strip()
Stanimir Varbanova220ab42013-07-17 15:37:00 +030038 if not line or line.startswith("#"):
39 continue
Shashank Mittaleb866e22011-12-09 00:20:36 -080040 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
Pavel Nedevca5eaa42013-08-20 17:53:18 +030046
47# Read firmware images from target files zip
Shashank Mittal874d47a2011-12-02 21:36:26 -080048def GetRadioFiles(z):
49 out = {}
50 for info in z.infolist():
Pavel Nedevca5eaa42013-08-20 17:53:18 +030051 f = info.filename
52 if f.startswith("RADIO/") and (f.__len__() > len("RADIO/")):
53 fn = f[6:]
Stanimir Varbanova220ab42013-07-17 15:37:00 +030054 if fn.startswith("filesmap"):
55 continue
Pavel Nedevca5eaa42013-08-20 17:53:18 +030056 data = z.read(f)
57 out[fn] = common.File(f, data)
Shashank Mittal874d47a2011-12-02 21:36:26 -080058 return out
59
Pavel Nedev7cf11da2013-08-13 13:43:21 +030060
Pavel Nedevca5eaa42013-08-20 17:53:18 +030061# 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 = {}
87
88 for f in files:
89 extIdx = -1
90 dotSeparated = f.split(".")
91 while True:
92 if dotSeparated[extIdx] != 'p' and dotSeparated[extIdx] != 'enc':
93 break
94 extIdx -= 1
95
96 if dotSeparated[extIdx] == 'mbn':
97 boot[f] = files[f]
98 elif dotSeparated[extIdx] == 'bin':
99 bin[f] = files[f]
100 else:
101 fw[f] = files[f]
102 return boot, bin, fw
103
104
105# Prepare radio-update files and verify them
106def OTA_VerifyEnd(info, api_version, target_zip, source_zip=None):
107 if api_version < 3:
108 print "warning radio-update: no support for api_version less than 3"
109 return False
110
111 print "Loading radio filesmap..."
112 filesmap = LoadFilesMap(target_zip)
113 if filesmap == {}:
114 print "warning radio-update: no or invalid filesmap file found"
115 return False
116
117 print "Loading radio target..."
118 tgt_files = GetRadioFiles(target_zip)
119 if tgt_files == {}:
120 print "warning radio-update: no radio images in input target_files"
121 return False
122
123 src_files = None
124 if source_zip is not None:
125 print "Loading radio source..."
126 src_files = GetRadioFiles(source_zip)
127
128 update_list = {}
129 largest_source_size = 0
130
131 print "Preparing radio-update files..."
132 for fn in tgt_files:
133 dest, destBak = GetFileDestination(fn, filesmap)
134 if dest is None:
135 continue
136
137 tf = tgt_files[fn]
138 sf = None
139 if src_files is not None:
140 sf = src_files.get(fn, None)
141
Pavel Nedev65bad502013-09-10 17:38:35 +0300142 full = sf is None or fn.endswith('.enc')
Pavel Nedevca5eaa42013-08-20 17:53:18 +0300143 if not full:
Pavel Nedev65bad502013-09-10 17:38:35 +0300144 # no difference - skip this file
145 if tf.sha1 == sf.sha1:
146 continue
Pavel Nedevca5eaa42013-08-20 17:53:18 +0300147 d = common.Difference(tf, sf)
148 _, _, d = d.ComputePatch()
Pavel Nedev65bad502013-09-10 17:38:35 +0300149 # no difference - skip this file
150 if d is None:
151 continue
Pavel Nedevca5eaa42013-08-20 17:53:18 +0300152 # if patch is almost as big as the file - don't bother patching
Pavel Nedev65bad502013-09-10 17:38:35 +0300153 full = len(d) > tf.size * common.OPTIONS.patch_threshold
Pavel Nedevca5eaa42013-08-20 17:53:18 +0300154 if not full:
155 f = "patch/firmware-update/" + fn + ".p"
156 common.ZipWriteStr(info.output_zip, f, d)
157 update_list[f] = (dest, destBak, tf, sf)
158 largest_source_size = max(largest_source_size, sf.size)
159 if full:
160 f = "firmware-update/" + fn
161 common.ZipWriteStr(info.output_zip, f, tf.data)
162 update_list[f] = (dest, destBak, None, None)
163
164 global bootImages
165 global binImages
166 global fwImages
167 bootImages, binImages, fwImages = SplitFwTypes(update_list)
168
169 # If there are incremental patches verify them
170 if largest_source_size != 0:
171 info.script.Comment("---- radio update verification ----")
172 info.script.Print("Verifying radio-update...")
173
174 for f in bootImages:
175 dest, destBak, tf, sf = bootImages[f]
176 # Not incremental
177 if sf is None:
178 continue
179 info.script.PatchCheck("EMMC:%s:%d:%s:%d:%s" %
180 (dest, sf.size, sf.sha1, tf.size, tf.sha1))
181 if destBak is not None:
182 info.script.PatchCheck("EMMC:%s:%d:%s:%d:%s" %
183 (destBak, sf.size, sf.sha1, tf.size, tf.sha1))
184 for f in binImages:
185 dest, destBak, tf, sf = binImages[f]
186 # Not incremental
187 if sf is None:
188 continue
189 info.script.PatchCheck("EMMC:%s:%d:%s:%d:%s" %
190 (dest, sf.size, sf.sha1, tf.size, tf.sha1))
191
192 last_mounted = ""
193 for f in fwImages:
194 dest, destBak, tf, sf = fwImages[f]
195 # Not incremental
196 if sf is None:
197 continue
198 # Get the filename without the path and the patch (.p) extention
199 f = f.split("/")[-1][:-2]
200 # Parse filesmap destination paths for "/dev/" pattern in the beginng.
201 # This would mean that the file must be written to block device -
202 # fs mount needed
203 if dest.startswith("/dev/"):
204 if last_mounted != dest:
205 info.script.AppendExtra('unmount("/firmware");')
206 info.script.AppendExtra('mount("vfat", "EMMC", "%s", "/firmware");' %
207 (dest))
208 last_mounted = dest
209 dest = "/firmware/image/" + f
210 else:
211 dest = dest + "/" + f
212 info.script.PatchCheck(dest, tf.sha1, sf.sha1)
213
214 info.script.CacheFreeSpaceCheck(largest_source_size)
215 return True
216
Pavel Nedev7cf11da2013-08-13 13:43:21 +0300217
Shashank Mittal874d47a2011-12-02 21:36:26 -0800218def FullOTA_Assertions(info):
Shashank Mittaleb866e22011-12-09 00:20:36 -0800219 #TODO: Implement device specific asserstions.
Shashank Mittal874d47a2011-12-02 21:36:26 -0800220 return
221
Pavel Nedevca5eaa42013-08-20 17:53:18 +0300222
Shashank Mittaleb866e22011-12-09 00:20:36 -0800223def IncrementalOTA_Assertions(info):
224 #TODO: Implement device specific asserstions.
225 return
226
Pavel Nedev7cf11da2013-08-13 13:43:21 +0300227
Pavel Nedevca5eaa42013-08-20 17:53:18 +0300228def IncrementalOTA_VerifyEnd(info):
Ameya Thakurab03e5d2014-07-01 12:05:45 -0700229 OTA_VerifyEnd(info, info.target_version, info.target_zip, info.source_zip)
230 return
Shashank Mittaleb866e22011-12-09 00:20:36 -0800231
Pavel Nedevca5eaa42013-08-20 17:53:18 +0300232
233# This function handles only non-HLOS whole partition images
234def InstallRawImage(script, f, dest, tf, sf):
235 if f.endswith('.p'):
236 script.ApplyPatch("EMMC:%s:%d:%s:%d:%s" %
237 (dest, sf.size, sf.sha1, tf.size, tf.sha1),
238 "-", tf.size, tf.sha1, sf.sha1, f)
239 elif f.endswith('.enc'):
240 # Get the filename without the path
241 fn = f.split("/")[-1]
242 script.AppendExtra('package_extract_file("%s", "/tmp/%s");' % (f, fn))
243 script.AppendExtra('msm.decrypt("/tmp/%s", "%s");' % (fn, dest))
244 else:
245 script.AppendExtra('package_extract_file("%s", "%s");' % (f, dest))
246 return
247
248
Stanimir Varbanova220ab42013-07-17 15:37:00 +0300249# This function handles only non-HLOS boot images - files list must contain
250# only such images (aboot, tz, etc)
Pavel Nedevca5eaa42013-08-20 17:53:18 +0300251def InstallBootImages(script, files):
252 bakExists = False
Pavel Nedev7cf11da2013-08-13 13:43:21 +0300253 # update main partitions
Pavel Nedevca5eaa42013-08-20 17:53:18 +0300254 script.AppendExtra('ifelse(msm.boot_update("main"), (')
255 for f in files:
256 dest, destBak, tf, sf = files[f]
257 if destBak is not None:
258 bakExists = True
259 InstallRawImage(script, f, dest, tf, sf)
260 script.AppendExtra('), "");')
Stanimir Varbanova220ab42013-07-17 15:37:00 +0300261
Pavel Nedevca5eaa42013-08-20 17:53:18 +0300262 # update backup partitions
263 if bakExists:
264 script.AppendExtra('ifelse(msm.boot_update("backup"), (')
265 for f in files:
266 dest, destBak, tf, sf = files[f]
267 if destBak is not None:
268 InstallRawImage(script, f, destBak, tf, sf)
269 script.AppendExtra('), "");')
270 # just finalize primary update stage
Pavel Nedev7cf11da2013-08-13 13:43:21 +0300271 else:
Pavel Nedevca5eaa42013-08-20 17:53:18 +0300272 script.AppendExtra('msm.boot_update("backup");')
Stanimir Varbanova220ab42013-07-17 15:37:00 +0300273
Pavel Nedev7cf11da2013-08-13 13:43:21 +0300274 # finalize partitions update
Pavel Nedevca5eaa42013-08-20 17:53:18 +0300275 script.AppendExtra('msm.boot_update("finalize");')
Stanimir Varbanova220ab42013-07-17 15:37:00 +0300276 return
277
Pavel Nedevca5eaa42013-08-20 17:53:18 +0300278
279# This function handles only non-HLOS bin images
280def InstallBinImages(script, files):
281 for f in files:
282 dest, _, tf, sf = files[f]
283 InstallRawImage(script, f, dest, tf, sf)
284 return
285
286
287# This function handles only non-HLOS firmware files that are not whole
288# partition images (modem, dsp, etc)
289def InstallFwImages(script, files):
Stanimir Varbanova220ab42013-07-17 15:37:00 +0300290 last_mounted = ""
291
292 for f in files:
Pavel Nedevca5eaa42013-08-20 17:53:18 +0300293 dest, _, tf, sf = files[f]
294 # Get the filename without the path
295 fn = f.split("/")[-1]
296 # Parse filesmap destination paths for "/dev/" pattern in the beginng.
Stanimir Varbanova220ab42013-07-17 15:37:00 +0300297 # This would mean that the file must be written to block device -
Pavel Nedev7cf11da2013-08-13 13:43:21 +0300298 # fs mount needed
Pavel Nedevca5eaa42013-08-20 17:53:18 +0300299 if dest.startswith("/dev/"):
300 if last_mounted != dest:
301 script.AppendExtra('unmount("/firmware");')
302 script.AppendExtra('mount("vfat", "EMMC", "%s", "/firmware");' %
303 (dest))
304 last_mounted = dest
Stanimir Varbanova220ab42013-07-17 15:37:00 +0300305 dest = "/firmware/image/" + fn
306 else:
Pavel Nedevca5eaa42013-08-20 17:53:18 +0300307 dest = dest + "/" + fn
Stanimir Varbanova220ab42013-07-17 15:37:00 +0300308
Pavel Nedevca5eaa42013-08-20 17:53:18 +0300309 if f.endswith('.p'):
310 script.ApplyPatch(dest[:-2], "-", tf.size, tf.sha1, sf.sha1, f)
311 elif f.endswith('.enc'):
312 script.AppendExtra('package_extract_file("%s", "/tmp/%s");' % (f, fn))
313 script.AppendExtra('msm.decrypt("/tmp/%s", "%s");' % (fn, dest[:-4]))
Stanimir Varbanova220ab42013-07-17 15:37:00 +0300314 else:
Pavel Nedevca5eaa42013-08-20 17:53:18 +0300315 script.AppendExtra('package_extract_file("%s", "%s");' % (f, dest))
Stanimir Varbanova220ab42013-07-17 15:37:00 +0300316
317 if last_mounted != "":
Pavel Nedevca5eaa42013-08-20 17:53:18 +0300318 script.AppendExtra('unmount("/firmware");')
Stanimir Varbanova220ab42013-07-17 15:37:00 +0300319 return
320
Stanimir Varbanova220ab42013-07-17 15:37:00 +0300321
Pavel Nedevca5eaa42013-08-20 17:53:18 +0300322def OTA_InstallEnd(info):
323 print "Applying radio-update script modifications..."
324 info.script.Comment("---- radio update tasks ----")
325 info.script.Print("Patching firmware images...")
Stanimir Varbanova220ab42013-07-17 15:37:00 +0300326
Pavel Nedevca5eaa42013-08-20 17:53:18 +0300327 if bootImages != {}:
328 InstallBootImages(info.script, bootImages)
329 if binImages != {}:
330 InstallBinImages(info.script, binImages)
331 if fwImages != {}:
332 InstallFwImages(info.script, fwImages)
Pavel Nedev7cf11da2013-08-13 13:43:21 +0300333 return
334
Pavel Nedevca5eaa42013-08-20 17:53:18 +0300335
Pavel Nedev7cf11da2013-08-13 13:43:21 +0300336def FullOTA_InstallEnd_MMC(info):
Pavel Nedevca5eaa42013-08-20 17:53:18 +0300337 if OTA_VerifyEnd(info, info.input_version, info.input_zip):
338 OTA_InstallEnd(info)
Stanimir Varbanova220ab42013-07-17 15:37:00 +0300339 return
340
Pavel Nedevca5eaa42013-08-20 17:53:18 +0300341
Stanimir Varbanova220ab42013-07-17 15:37:00 +0300342def FullOTA_InstallEnd_MTD(info):
343 print "warning radio-update: radio update for NAND devices not supported"
Shashank Mittaleb866e22011-12-09 00:20:36 -0800344 return
345
Pavel Nedevca5eaa42013-08-20 17:53:18 +0300346
Shashank Mittaleb866e22011-12-09 00:20:36 -0800347def FullOTA_InstallEnd(info):
Ameya Thakurab03e5d2014-07-01 12:05:45 -0700348 FullOTA_InstallEnd_MMC(info)
Stanimir Varbanov4cb7edf2013-05-20 16:47:21 +0300349 return
350
Stanimir Varbanova220ab42013-07-17 15:37:00 +0300351def IncrementalOTA_InstallEnd_MMC(info):
Pavel Nedevca5eaa42013-08-20 17:53:18 +0300352 OTA_InstallEnd(info)
Stanimir Varbanova220ab42013-07-17 15:37:00 +0300353 return
Stanimir Varbanov4cb7edf2013-05-20 16:47:21 +0300354
Pavel Nedevca5eaa42013-08-20 17:53:18 +0300355
Stanimir Varbanova220ab42013-07-17 15:37:00 +0300356def IncrementalOTA_InstallEnd_MTD(info):
357 print "warning radio-update: radio update for NAND devices not supported"
358 return
359
360def IncrementalOTA_InstallEnd(info):
Ameya Thakurab03e5d2014-07-01 12:05:45 -0700361 IncrementalOTA_InstallEnd_MMC(info)
Shashank Mittaleb866e22011-12-09 00:20:36 -0800362 return