1 /*
2 * Copyright (c) 2020 HiSilicon (Shanghai) Technologies CO., LIMITED.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 * Description: UPG lzma decode functions source file
15 */
16
17 #include <stddef.h>
18 #include <stdint.h>
19 #include "securec.h"
20 #include "chip_io.h"
21 #include "td_type.h"
22 #include "upg_alloc.h"
23 #include "upg_porting.h"
24 #include "upg_common.h"
25 #include "upg_debug.h"
26 #if (UPG_CFG_SUPPORT_RESOURCES_FILE == YES)
27 #include "dfx_file_operation.h"
28 #endif
29 #include "upg_encry.h"
30 #include "upg_lzmadec.h"
31
32 #define OTA_ENCRY_FLAG 0x3C7896E1
upg_lzma_alloc(const ISzAllocPtr unused,size_t size)33 STATIC void *upg_lzma_alloc(const ISzAllocPtr unused, size_t size)
34 {
35 unused(unused);
36 void *p;
37 p = upg_malloc((uint32_t)size);
38 if (p == NULL) {
39 upg_log_err("[UPG] upg_lzma_alloc failed!!! size = 0x%x\r\n", (uint32_t)size);
40 return NULL;
41 }
42 return p;
43 }
44
upg_lzma_free(const ISzAllocPtr unused,void * address)45 STATIC void upg_lzma_free(const ISzAllocPtr unused, void *address)
46 {
47 unused(unused);
48 if (address == NULL) {
49 return;
50 }
51 upg_free(address);
52 }
53
lzmadec_init(CLzmaDec * p)54 static inline void lzmadec_init(CLzmaDec *p)
55 {
56 return LzmaDec_Init(p);
57 }
58
lzmadec_decodetodic(CLzmaDec * p,SizeT dic_limit,const Byte * src,SizeT * srclen,ELzmaFinishMode finish_mode,ELzmaStatus * status)59 __attribute__((unused)) static inline int32_t lzmadec_decodetodic(CLzmaDec *p, SizeT dic_limit, const Byte *src,
60 SizeT *srclen, ELzmaFinishMode finish_mode, ELzmaStatus *status)
61 {
62 return LzmaDec_DecodeToDic(p, dic_limit, src, srclen, finish_mode, status);
63 }
64
lzmadec_freeprobs(CLzmaDec * p,ISzAllocPtr alloc)65 static inline void lzmadec_freeprobs(CLzmaDec *p, ISzAllocPtr alloc)
66 {
67 return LzmaDec_FreeProbs(p, alloc);
68 }
69
lzmadec_allocateprobs(CLzmaDec * p,const Byte * props,unsigned props_size,ISzAllocPtr alloc)70 static inline int32_t lzmadec_allocateprobs(CLzmaDec *p, const Byte *props, unsigned props_size, ISzAllocPtr alloc)
71 {
72 return LzmaDec_AllocateProbs(p, props, props_size, alloc);
73 }
74
lzmadec_decodetobuf(CLzmaDec * p,Byte * dest,SizeT * dest_len,const Byte * src,SizeT * src_len,ELzmaFinishMode finish_mode,ELzmaStatus * status)75 STATIC SRes lzmadec_decodetobuf(CLzmaDec *p, Byte *dest, SizeT *dest_len, const Byte *src, SizeT *src_len,
76 ELzmaFinishMode finish_mode, ELzmaStatus *status)
77 {
78 return LzmaDec_DecodeToBuf(p, dest, dest_len, src, src_len, finish_mode, status);
79 }
80
upg_lzma_init_buf(upg_lzma_decode2_data_t * val_data)81 uint32_t upg_lzma_init_buf(upg_lzma_decode2_data_t *val_data)
82 {
83 ISzAlloc alloc;
84 val_data->buf.in_size = 0;
85 val_data->buf.write_pos = 0;
86 val_data->buf.inbuf = upg_lzma_alloc(&alloc, IN_BUF_SIZE);
87 if (val_data->buf.inbuf == NULL) {
88 return ERRCODE_MALLOC;
89 }
90
91 val_data->buf.outbuf = upg_lzma_alloc(&alloc, OUT_BUF_SIZE);
92 if (val_data->buf.outbuf == NULL) {
93 upg_lzma_free(&alloc, val_data->buf.inbuf);
94 val_data->buf.inbuf = NULL;
95 return ERRCODE_MALLOC;
96 }
97 return ERRCODE_SUCC;
98 }
99
upg_lzma_init(CLzmaDec * p,upg_lzma_decode2_data_t * val_data,const Byte * props,uint32_t props_len)100 uint32_t upg_lzma_init(CLzmaDec *p, upg_lzma_decode2_data_t *val_data, const Byte *props, uint32_t props_len)
101 {
102 LzmaDec_Construct(p);
103
104 ISzAlloc alloc;
105 alloc.Alloc = upg_lzma_alloc;
106 alloc.Free = upg_lzma_free;
107
108 if (props_len < LZMA_PROPS_SIZE) {
109 return ERRCODE_UPG_INVALID_PARAMETER;
110 }
111
112 int32_t res = lzmadec_allocateprobs(p, props, LZMA_PROPS_SIZE, &alloc);
113 if (res != 0) {
114 return (uint32_t)res;
115 }
116
117 uint32_t unpack_size = 0;
118 for (uint32_t i = 0; i < props_len - LZMA_PROPS_SIZE; i++) {
119 unpack_size += (uint32_t)props[LZMA_PROPS_SIZE + i] << (i * 8); /* 8: 用于计算偏移位数 */
120 }
121 uint32_t dic_size = unpack_size;
122
123 if ((p->prop).dicSize <= unpack_size) {
124 dic_size = (p->prop).dicSize;
125 }
126
127 if (dic_size == 0) {
128 return ERRCODE_UPG_INVALID_PARAMETER;
129 }
130
131 p->dic = upg_lzma_alloc(&alloc, dic_size);
132 if (p->dic == NULL) {
133 return ERRCODE_MALLOC;
134 }
135
136 p->dicBufSize = dic_size;
137 val_data->decompress_len = unpack_size;
138 if (upg_lzma_init_buf(val_data) != ERRCODE_SUCC) {
139 upg_lzma_free(&alloc, p->dic);
140 p->dic = NULL;
141 return ERRCODE_MALLOC;
142 }
143
144 lzmadec_init(p);
145 return ERRCODE_SUCC;
146 }
147
upg_lzma_deinit(CLzmaDec * p,upg_lzma_decode2_data_t * val_data)148 void upg_lzma_deinit(CLzmaDec *p, upg_lzma_decode2_data_t *val_data)
149 {
150 ISzAlloc alloc;
151 alloc.Alloc = upg_lzma_alloc;
152 alloc.Free = upg_lzma_free;
153
154 upg_lzma_free(&alloc, p->dic);
155 p->dic = NULL;
156
157 lzmadec_freeprobs(p, &alloc);
158
159 upg_lzma_free(&alloc, val_data->buf.inbuf);
160 val_data->buf.inbuf = NULL;
161
162 upg_lzma_free(&alloc, val_data->buf.outbuf);
163 val_data->buf.outbuf = NULL;
164 }
165
upg_lzma_dec_check_ret(SRes res,uint32_t unpack_size,bool in_out_zero,ELzmaStatus status,SRes * ret)166 STATIC bool upg_lzma_dec_check_ret(SRes res, uint32_t unpack_size, bool in_out_zero, ELzmaStatus status, SRes *ret)
167 {
168 if ((res != SZ_OK) || (unpack_size == 0)) {
169 *ret = res;
170 return true;
171 }
172
173 if (in_out_zero) {
174 if (status != LZMA_STATUS_FINISHED_WITH_MARK) {
175 *ret = SZ_ERROR_DATA;
176 return true;
177 }
178 *ret = res;
179 return true;
180 }
181 return false;
182 }
183
184 /* 读镜像,并解密 */
upg_lzma_read_pkt_decry(upg_lzma_decode2_data_t * data,const upg_image_header_t * image)185 static uint32_t upg_lzma_read_pkt_decry(upg_lzma_decode2_data_t *data, const upg_image_header_t *image)
186 {
187 uint32_t in_size = (data->compress_len > IN_BUF_SIZE) ? IN_BUF_SIZE : data->compress_len;
188 UNUSED(image);
189 if (upg_read_fota_pkg_data(data->in_offset, data->buf.inbuf, &in_size) != ERRCODE_SUCC) {
190 return SZ_ERROR_DATA;
191 }
192 #ifdef CONFIG_MIDDLEWARE_SUPPORT_UPG_COMPRESS_ENCRY
193 if (upg_decry_fota_pkt(data->buf.inbuf, in_size, image) != ERRCODE_SUCC) {
194 return ERRCODE_FAIL;
195 }
196 #endif
197 data->buf.in_size = in_size; /* 本次待处理长度 */
198 data->in_offset += in_size; /* 读imag偏移地址 */
199 data->compress_len -= in_size; /* 待处理imag长度 */
200 return ERRCODE_SUCC;
201 }
202
upg_lzma_get_mode(SizeT * out_processed,uint32_t unpack_size)203 ELzmaFinishMode upg_lzma_get_mode(SizeT *out_processed, uint32_t unpack_size)
204 {
205 /* 最后一段解压后的长度不足4k, 解压需要切换finish模式 */
206 ELzmaFinishMode finish_mode = LZMA_FINISH_ANY;
207 if (unpack_size < OUT_BUF_SIZE) {
208 *out_processed = (SizeT)unpack_size;
209 finish_mode = LZMA_FINISH_END;
210 }
211 return finish_mode;
212 }
213
upg_lzma_write_image(upg_lzma_decode2_data_t * data,const upg_image_header_t * image,td_bool * first_pkt)214 uint32_t upg_lzma_write_image(upg_lzma_decode2_data_t *data, const upg_image_header_t *image, td_bool *first_pkt)
215 {
216 uint32_t ret = ERRCODE_SUCC;
217 UNUSED(first_pkt);
218 /* 直接写flash */
219 if (image->re_enc_flag != OTA_ENCRY_FLAG) {
220 #if defined(UPG_CFG_SUPPORT_ERASE_WHOLE_IMAGE) && defined(YES) && (UPG_CFG_SUPPORT_ERASE_WHOLE_IMAGE == YES)
221 ret = upg_write_new_image_data(data->out_offset, data->buf.outbuf, &data->buf.write_pos, data->image_id, false);
222 #else
223 ret = upg_write_new_image_data(data->out_offset, data->buf.outbuf, &data->buf.write_pos, data->image_id, true);
224 #endif
225 if (ret != ERRCODE_SUCC) {
226 return SZ_ERROR_DATA;
227 }
228 data->out_offset += data->buf.write_pos;
229 data->buf.write_pos = 0;
230 return ERRCODE_SUCC;
231 }
232 #ifdef CONFIG_MIDDLEWARE_SUPPORT_UPG_COMPRESS_ENCRY
233 /* 加密后写flash */
234 ret = upg_encry_and_write_pkt(data, image, first_pkt);
235 if (ret != ERRCODE_SUCC) {
236 upg_log_err("[UPG] upg_encry_fota_pkt fail ret = 0x%x \r\n", ret);
237 return ERRCODE_FAIL;
238 }
239 #endif
240 return ret;
241 }
242
upg_lzma_decode_to_midbuf(CLzmaDec * p,upg_lzma_decode2_data_t * data,const upg_image_header_t * image,td_bool * first_pkt)243 uint32_t upg_lzma_decode_to_midbuf(CLzmaDec *p, upg_lzma_decode2_data_t *data,
244 const upg_image_header_t *image, td_bool *first_pkt)
245 {
246 SRes res_ret;
247 upg_lzma_buf_t *buf = &data->buf;
248 size_t in_pos = 0; /* 解压进度 */
249 size_t in_size = buf->in_size; /* 待解压长度 */
250 ELzmaStatus status = LZMA_STATUS_NOT_SPECIFIED;
251 ELzmaFinishMode finish_mode = LZMA_FINISH_ANY;
252
253 while (in_pos < in_size) {
254 SizeT in_processed = in_size - in_pos; /* 本次待解压长度 */
255 SizeT out_processed = OUT_BUF_SIZE; /* 预计解压后长度 */
256 finish_mode = upg_lzma_get_mode(&out_processed, data->decompress_len);
257 SRes res = lzmadec_decodetobuf(p, buf->outbuf + buf->write_pos, &out_processed, buf->inbuf + in_pos, /* 解压 */
258 &in_processed, finish_mode, &status);
259 if (res != SZ_OK) {
260 upg_log_err("[UPG] lzmadec_decodetobuf fail ret = 0x%x. \r\n", res);
261 return res;
262 }
263
264 in_pos += in_processed;
265 data->decompress_len -= out_processed;
266 buf->write_pos += out_processed;
267 upg_calculate_and_notify_process(out_processed);
268 /* midbuf缓冲区剩余空间不足4k 或 若解压完成,则写入flash */
269 if ((OUT_BUF_SIZE - buf->write_pos) < IN_BUF_SIZE || data->decompress_len == 0 || in_pos == in_size) {
270 if (upg_lzma_write_image(data, image, first_pkt) != ERRCODE_SUCC) {
271 upg_log_err("[UPG] upg_lzma_write_image fail.\r\n");
272 return ERRCODE_FAIL;
273 }
274 }
275 if (upg_lzma_dec_check_ret(res, data->decompress_len, (in_processed == 0 && out_processed == 0),
276 status, &res_ret)) {
277 return (uint32_t)res_ret;
278 }
279 }
280 return ERRCODE_SUCC;
281 }
282
283 /* 压缩加密升级:解密->解压->加密 */
upg_lzma_decode(CLzmaDec * p,upg_lzma_decode2_data_t * data,const upg_image_header_t * image)284 uint32_t upg_lzma_decode(CLzmaDec *p, upg_lzma_decode2_data_t *data, const upg_image_header_t *image)
285 {
286 td_bool first_pkt = TD_TRUE;
287 uint32_t ret = ERRCODE_SUCC;
288
289 while (data->compress_len > 0) {
290 /* 读镜像 -> 解密 */
291 ret = upg_lzma_read_pkt_decry(data, image);
292 if (ret != ERRCODE_SUCC) {
293 upg_log_err("[UPG] upg_lzma_read_pkt_decry fail ret = 0x%x.\r\n", ret);
294 return ret;
295 }
296
297 /* 解压 -> 加密 -> 写flash */
298 ret = upg_lzma_decode_to_midbuf(p, data, image, &first_pkt);
299 if (ret != ERRCODE_SUCC) {
300 upg_log_err("[UPG] upg_lzma_decode_to_buf fail ret = 0x%x.\r\n", ret);
301 return ret;
302 }
303
304 upg_watchdog_kick(); /* 踢狗 */
305 }
306 return ret;
307 }
308
309 #if (UPG_CFG_SUPPORT_RESOURCES_FILE == YES)
upg_resource_file_decode(CLzmaDec * p,upg_lzma_decode2_data_t * data,upg_resource_node_t * file_info)310 errcode_t upg_resource_file_decode(CLzmaDec *p, upg_lzma_decode2_data_t *data, upg_resource_node_t *file_info)
311 {
312 errcode_t ret = ERRCODE_SUCC;
313 size_t in_size = 0; /* 待读出压缩数据的大小 */
314 size_t out_len = 0; /* 解压缩后数据的大小 */
315 uint32_t file_len = file_info->file_len; /* 文件的大小,即本次需要解压缩出来的原始数据长度 */
316 uint32_t in_offset = data->in_offset; /* 已解压数据的压缩包的偏移位置 */
317 uint32_t file_offset = 0; /* 本次解压出的数据长度, 用作写入的偏移位置 */
318 ELzmaStatus status = LZMA_STATUS_NOT_SPECIFIED;
319
320 if (file_info->offset != data->out_offset) {
321 return ERRCODE_UPG_INVALID_OFFSET;
322 }
323
324 int32_t write_fd = dfx_file_open_for_write((const char *)file_info->file_path);
325 if (write_fd < 0) {
326 return ERRCODE_UPG_FILE_OPEN_FAIL;
327 }
328
329 while (file_len > 0) {
330 in_size = (data->compress_len > IN_BUF_SIZE) ? IN_BUF_SIZE : data->compress_len;
331 ret = upg_read_fota_pkg_data(in_offset, data->buf.inbuf, (uint32_t *)(uintptr_t)&in_size);
332 if (ret != ERRCODE_SUCC) {
333 break;
334 }
335
336 out_len = (file_len > OUT_BUF_SIZE) ? OUT_BUF_SIZE : file_len;
337 if (lzmadec_decodetobuf(p, data->buf.outbuf, &out_len, data->buf.inbuf, &in_size,
338 LZMA_FINISH_ANY, &status) != SZ_OK) {
339 ret = ERRCODE_UPG_DECOMPRESS_FAIL;
340 break;
341 }
342
343 if (dfx_file_write_fd(write_fd, file_offset, data->buf.outbuf, out_len) != (int32_t)out_len) {
344 ret = ERRCODE_UPG_FILE_WRITE_FAIL;
345 break;
346 }
347
348 in_offset += in_size;
349 data->compress_len -= in_size;
350 file_offset += out_len;
351 file_len -= out_len;
352
353 upg_calculate_and_notify_process((uint32_t)out_len);
354
355 if (data->compress_len == 0 || (in_size == 0 && out_len == 0)) {
356 break;
357 }
358 }
359
360 data->in_offset = in_offset;
361 data->out_offset += file_offset;
362 if (in_size == 0 && out_len == 0 && status != LZMA_STATUS_FINISHED_WITH_MARK && file_info->file_len != 0) {
363 ret = ERRCODE_UPG_DECOMPRESS_FAIL;
364 }
365
366 dfx_file_fsync(write_fd);
367 dfx_file_close(write_fd);
368 return ret;
369 }
370 #else
upg_resource_file_decode(CLzmaDec * p,upg_lzma_decode2_data_t * data,upg_resource_node_t * file_info)371 errcode_t upg_resource_file_decode(CLzmaDec *p, upg_lzma_decode2_data_t *data, upg_resource_node_t *file_info)
372 {
373 unused(p);
374 unused(data);
375 unused(file_info);
376 return ERRCODE_SUCC;
377 }
378 #endif