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