1 /*-
2 * Copyright 2003-2005 Colin Percival
3 * All rights reserved
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted providing that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
18 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
22 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
23 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 * POSSIBILITY OF SUCH DAMAGE.
25 */
26 #include "nbpatch.h"
27 #include "libc.h"
28 #include "updater.h"
29
30 #define HEADER_SIZE 48
31
offtin(unsigned char * buf)32 long offtin(unsigned char *buf) {
33 long y;
34
35 y = buf[7] & 0x7F;
36 y <<= 8; y += buf[6];
37 y <<= 8; y += buf[5];
38 y <<= 8; y += buf[4];
39 y <<= 8; y += buf[3];
40 y <<= 8; y += buf[2];
41 y <<= 8; y += buf[1];
42 y <<= 8; y += buf[0];
43 if (buf[7] & 0x80)
44 y = -y;
45 return y;
46 }
47
xz_read(xzReadHandler * handler,struct xz_buf * b,struct xz_dec * s,unsigned long patch,unsigned char * buf,int len)48 long xz_read(xzReadHandler *handler, struct xz_buf *b,struct xz_dec *s, unsigned long patch, unsigned char *buf, int len)
49 {
50 long ret = 0;
51 if (handler == NULL || b == NULL || s == NULL || patch == 0 || buf == NULL || len <= 0) {
52 return 0;
53 };
54
55 b->out = buf;
56 b->out_pos = 0;
57 b->out_size = len;
58 while(true) {
59 if (b->in_pos == b->in_size && handler->avail_size > 0) {
60 size_t readsize = IN_BUF_MAX > handler->avail_size ? handler->avail_size:IN_BUF_MAX;
61 b->in_size = ota_patch_read(patch, handler->in_buf, handler->read_pos, readsize);
62 handler->avail_size -= readsize;
63 handler->read_pos += readsize;
64 b->in_pos = 0;
65 b->in = handler->in_buf;
66 }
67
68 ret = xz_dec_run(s, b);
69 if (ret != XZ_OK && ret != XZ_STREAM_END) {
70 OTA_LOG_I("xz dec err:%ld \n", ret);
71 return 0;
72 }
73 if (handler->avail_size <= 0 && b->in_pos == b->in_size
74 && b->out_pos < len) {
75 return b->out_pos;
76 }
77
78 if (b->out_pos == len) {
79 return len;
80 }
81 }
82 return ret;
83 }
84
ota_nbpatch(const unsigned long old_addr,long old_size,unsigned long patch,long * seek_pos,int num)85 static long ota_nbpatch(const unsigned long old_addr, long old_size, unsigned long patch, long *seek_pos, int num)
86 {
87 int ret = 0;
88 long new_size = 0;
89 long ctrl_len = 0;
90 long diff_len = 0;
91 long extra_len = 0;
92 unsigned char header[HEADER_SIZE], buf[8];
93 unsigned char *old_buf = NULL;
94 unsigned char *new_buf = NULL;
95 long old_pos = 0;
96 long new_pos = 0;
97 long ctrl[3] = {0};
98 long read_len = 0;
99 long i = 0;
100 CRC16_CTX crc_ctx;
101 unsigned short patch_crc = 0;
102 unsigned short crc = 0, cal_crc = 0;
103 struct xz_dec *ctrl_dec = NULL, *diff_dec = NULL, *extra_dec = NULL;
104 struct xz_buf cb = {0}, db = {0}, eb = {0};
105
106 if(!old_addr || !patch || !seek_pos ) {
107 ret = OTA_NB_INVALID_PARAM;
108 goto EXIT;
109 }
110 long patch_pos = *seek_pos;
111 old_buf = malloc(SECTOR_SIZE);
112 if (old_buf == NULL){
113 ret = OTA_NB_MEMORY_FAIL;
114 goto EXIT;
115 }
116 /*
117 File format:
118 0 8 "BSDIFF40"
119 8 8 X
120 16 8 Y
121 24 8 sizeof(newfile)
122 32 X bzip2(control block)
123 32+X bzip2(diff block)
124 32+X+Y bzip2(extra block)
125 with control block a set of triples (x,y,z) meaning "add x bytes
126 from oldfile to x bytes from the diff block; copy y bytes from the
127 extra block; seek forwards in oldfile by z bytes".
128 */
129 ret = ota_patch_read(patch, header, patch_pos, HEADER_SIZE);
130 if(ret < 0) {
131 ret = OTA_NB_HEADER_FAIL;
132 goto EXIT;
133 }
134
135 /* Check for appropriate magic */
136 if (memcmp(header, "BSDIFF40", 8) != 0) {
137 ret = OTA_NB_HEADER_FAIL;
138 goto EXIT;
139 }
140 /* Read lengths from header */
141 ctrl_len = offtin(header + 8);
142 diff_len = offtin(header + 16);
143 extra_len = offtin(header + 24);
144 new_size = offtin(header + 32);
145 crc = offtin(header + 40);
146 if ((ctrl_len < 0) || (diff_len < 0) || (new_size < 0)) {
147 ret = OTA_NB_HEADER_FAIL;
148 goto EXIT;
149 }
150
151 OTA_LOG_I("nbpatch %d header clen:%ld dlen:%ld elen:%ld crc:0x%02x... \n", num, ctrl_len, diff_len, extra_len, crc);
152 new_buf = malloc(new_size);
153 if (new_buf == NULL) {
154 ret = OTA_NB_MEMORY_FAIL;
155 goto EXIT;
156 }
157 crc16_init(&crc_ctx);
158 xz_crc32_init();
159 ctrl_dec = xz_dec_init(XZ_DYNALLOC, DIFF_DICT_SIZE);
160 if (ctrl_dec == NULL) {
161 ret = OTA_NB_MEMORY_FAIL;
162 goto EXIT;
163 }
164 diff_dec = xz_dec_init(XZ_DYNALLOC, DIFF_DICT_SIZE);
165 if (diff_dec == NULL) {
166 ret = OTA_NB_MEMORY_FAIL;
167 goto EXIT;
168 }
169 extra_dec = xz_dec_init(XZ_DYNALLOC, DIFF_DICT_SIZE);
170 if (extra_dec == NULL) {
171 ret = OTA_NB_MEMORY_FAIL;
172 goto EXIT;
173 }
174
175 xzReadHandler cbhandler;
176 memset(&cbhandler, 0, sizeof(xzReadHandler));
177 cbhandler.avail_size = ctrl_len;
178 cbhandler.read_pos = patch_pos + HEADER_SIZE;
179 xzReadHandler diffhandler;
180 memset(&diffhandler, 0, sizeof(xzReadHandler));
181 diffhandler.avail_size = diff_len;
182 diffhandler.read_pos = patch_pos + HEADER_SIZE + ctrl_len;
183 xzReadHandler extrahandler;
184 memset(&extrahandler, 0, sizeof(xzReadHandler));
185 extrahandler.avail_size = extra_len;
186 extrahandler.read_pos = patch_pos + HEADER_SIZE + ctrl_len + diff_len;
187
188 while (new_pos < new_size) {
189 /* Read control data */
190 for (i = 0; i <= 2; i++) {
191 read_len = xz_read(&cbhandler, &cb, ctrl_dec, patch, buf, 8);
192 if (read_len < 8) {
193 ret = OTA_NB_READ_CTRL_FAIL;
194 goto EXIT;
195 }
196 ctrl[i] = offtin(buf);
197 /* OTA_LOG_I("ctrlp[i] %ld", ctrl[i]); */
198 };
199
200 /* Sanity-check */
201 if (new_pos + ctrl[0] > new_size){
202 ret = OTA_NB_READ_DIFF_FAIL;
203 goto EXIT;
204 }
205 /* Read diff string */
206 read_len = xz_read(&diffhandler, &db, diff_dec, patch, new_buf + new_pos, ctrl[0]);
207 if ((read_len < ctrl[0])){
208 ret = OTA_NB_READ_DIFF_FAIL;
209 goto EXIT;
210 }
211 if(old_pos > old_size || old_pos + ctrl[0] > old_size) {
212 ret = OTA_NB_READ_OLD_FAIL;
213 goto EXIT;
214 }
215 long cp_size = ctrl[0];
216 long base_pos = 0;
217 int idx = 0;
218 long i;
219 for (i = 0; i < ctrl[0]; i++) {
220 if (!(i % SECTOR_SIZE)) {
221 base_pos = (idx++) * SECTOR_SIZE;
222 long osize = cp_size > SECTOR_SIZE ? SECTOR_SIZE : cp_size;
223 memset(old_buf, 0, osize);
224 ret = ota_patch_read(old_addr, old_buf, old_pos + base_pos, osize);
225 if(ret < 0) {
226 ret = OTA_NB_READ_OLD_FAIL;
227 goto EXIT;
228 }
229 cp_size -= osize;
230 /* OTA_LOG_I("start cp:%ld bp:%ld",cp_size, base_pos); */
231 }
232 if (i >= base_pos) {
233 new_buf[new_pos + i] += old_buf[i - base_pos];
234 }
235 }
236 crc16_update(&crc_ctx, new_buf + new_pos, ctrl[0]);
237 /* Adjust pointers */
238 new_pos += ctrl[0];
239 old_pos += ctrl[0];
240 /* Sanity-check */
241 if (new_pos + ctrl[1] > new_size) {
242 ret = OTA_NB_READ_EXTRA_FAIL;
243 goto EXIT;
244 }
245 /* Read extra string */
246 read_len = xz_read(&extrahandler, &eb, extra_dec, patch, new_buf + new_pos, ctrl[1]);
247 if (read_len < ctrl[1]) {
248 ret = OTA_NB_READ_EXTRA_FAIL;
249 goto EXIT;
250 }
251 crc16_update(&crc_ctx, new_buf + new_pos, ctrl[1]);
252 /* Adjust pointers */
253 new_pos += ctrl[1];
254 old_pos += ctrl[2];
255 };
256 crc16_final(&crc_ctx, &patch_crc);
257 cal_crc = crc16_computer(new_buf, new_size);
258 if(cal_crc != crc) {
259 OTA_LOG_I("cal %02x != crc %02x", cal_crc, crc);
260 ret = OTA_NB_CRC_COMP_FAIL;
261 goto EXIT;
262 }
263 ret = ota_patch_new_data(new_buf, new_size);
264 if(ret < 0) {
265 ret = OTA_NB_WRITE_DATA_FAIL;
266 goto EXIT;
267 }
268 patch_pos += HEADER_SIZE;
269 patch_pos += ctrl_len;
270 patch_pos += diff_len;
271 patch_pos += extra_len;
272 *seek_pos = patch_pos;
273
274 EXIT:
275 OTA_LOG_I("nbpatch %d end cal_crc:0x%02x patch_crc:0x%02x ret:%d\n", num, cal_crc, patch_crc, ret);
276 if(ctrl_dec){
277 xz_dec_end(ctrl_dec);
278 ctrl_dec = NULL;
279 }
280 if(diff_dec) {
281 xz_dec_end(diff_dec);
282 diff_dec = NULL;
283 }
284 if(extra_dec){
285 xz_dec_end(extra_dec);
286 extra_dec = NULL;
287 }
288 if(old_buf){
289 free(old_buf);
290 old_buf = NULL;
291 }
292 if(new_buf){
293 free(new_buf);
294 new_buf = NULL;
295 }
296 return (ret < 0) ? ret: new_size;
297 }
298
ota_nbpatch_main(void)299 int ota_nbpatch_main(void) {
300 int ret = -1;
301 unsigned long old_addr = 0;
302 unsigned long patch_addr = 0;
303 int patch_num = 0;
304 long patch_off = 0;
305 long patch_size = 0;
306 long old_size = 0;
307 long new_off = 0;
308 long new_size = 0;
309 ota_boot_param_t ota_param = {0};
310
311 memset(&ota_param, 0, sizeof(ota_boot_param_t));
312 ret = ota_patch_read_param(&ota_param);
313 if(ret < 0){
314 OTA_LOG_I("r param err.\n");
315 return OTA_NB_INVALID_PARAM;
316 }
317 old_addr = ota_param.dst_adr;
318 patch_addr = ota_param.src_adr;
319 patch_off = ota_param.patch_off;
320 patch_size = ota_param.len;
321 old_size = ota_param.old_size;
322 new_off = ota_param.new_off;
323 new_size = ota_param.new_size;
324 if (!old_addr || !patch_addr || old_size <= 0 || patch_size <= 0 || (ota_param.upg_flag != OTA_UPGRADE_DIFF)) {
325 OTA_LOG_I("param check err.\n");
326 return OTA_NB_INVALID_PARAM;
327 }
328
329 OTA_LOG_I("oaddr:0x%lx paddr:0x%lx num:%d noff:%lx nsize:%lx poff:%lx psize:%ld status:%d \n", old_addr, patch_addr, patch_num, new_off, new_size, patch_off, patch_size, ota_param.patch_status);
330 while (patch_off < patch_size) {
331 if(!ota_param.patch_status) {
332 new_size = ota_nbpatch(old_addr, old_size, patch_addr, &patch_off, patch_num);
333 ota_param.patch_num = ++patch_num;
334 ota_param.patch_off = patch_off;
335 ota_param.new_off = new_off;
336 ota_param.new_size = new_size;
337 ota_param.patch_status = 1;
338 if (new_size < 0) {
339 ret = new_size;
340 goto EXIT;
341 }
342 ota_patch_write_param(&ota_param);
343 }
344 ret = ota_load_new_data(new_off, new_size);
345 if(ret < 0) {
346 ret = OTA_NB_WRITE_DATA_FAIL;
347 OTA_LOG_I("err new off:%ld \n", new_size);
348 goto EXIT;
349 }
350 new_off += new_size;
351 ota_param.patch_status = 0;
352 ota_param.new_off = new_off;
353 ota_patch_write_param(&ota_param);
354 }
355 EXIT:
356 if(patch_off > patch_size) {
357 ota_param.patch_num = 0;
358 ota_param.patch_off = 0;
359 ota_param.patch_status = 0;
360 ota_param.new_off = 0;
361 ota_param.new_size = 0;
362 ota_param.upg_flag = 0;
363 }
364 ota_patch_write_param(&ota_param);
365 OTA_LOG_I("nbpatch complete ret: %d new off:%lx size:0x%lx patch_off:0x%lx \n",ret, new_off, new_size, patch_off);
366 return (ret < 0) ? ret: new_off;
367 }
368