• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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