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 */
15
16 #include <lzmaram.h>
17 #include <hi_boot_err.h>
18 #include <hi_boot_rom.h>
19
20 #define LZMA_DIC_MIN (1 << 12)
21 #define LZMA_BASE_SIZE 1846
22 #define LZMA_LIT_SIZE 768
23 #define IN_BUF_SIZE 0x1000
24 #define OUT_BUF_SIZE 0x1000
25
lzma_alloc(hi_pbyte unused,size_t size)26 static hi_pbyte lzma_alloc(hi_pbyte unused, size_t size)
27 {
28 hi_unref_param(unused);
29 hi_pbyte addr = (hi_pbyte)boot_malloc(size);
30 if (!addr) {
31 boot_msg1("\n LZMA_Alloc fail= ", size);
32 }
33 return addr;
34 }
35
lzma_free(hi_pbyte unused,hi_pbyte address)36 static void lzma_free(hi_pbyte unused, hi_pbyte address)
37 {
38 hi_unref_param(unused);
39 if (address == HI_NULL) {
40 return;
41 }
42
43 boot_free(address);
44 }
45
46 /**
47 * @ingroup LZMA
48 * @brief : get file size and dictionary size before LZMA compressed
49 *
50 * @par :description:
51 * get file size and dictionary size before LZMA compressed
52 *
53 * @attention: nothing
54 * @param lzma_head [IN] type #hi_u8*-LZMA head
55 * @param pulDecompressedDataLen [OUT] type #unsigned int*, size before compressed
56 * @param dic_size [OUT] type #unsigned int* , dictionary size
57 *
58 * @retval #HI_ERR_SUCCESS success
59 * @retval # other value: fail, see hi_errno.h for details
60 * @par dependency:
61 *
62 * @see : nothing
63 */
hi_lzma_get_uncompress_len(const hi_u8 lzma_head[13],hi_u32 head_size,unsigned int * pul_decompressed_data_len,unsigned int * dic_size)64 unsigned int hi_lzma_get_uncompress_len(const hi_u8 lzma_head[13], hi_u32 head_size, /* head 13B */
65 unsigned int *pul_decompressed_data_len, unsigned int *dic_size)
66 {
67 unsigned int uncompressed_len;
68 unsigned int uncompressed_len_high;
69
70 if ((lzma_head == HI_NULL)
71 || (pul_decompressed_data_len == HI_NULL)
72 || head_size > 13) { /* head 13B */
73 boot_msg1("[lzma get uncompress len]head size", head_size);
74 return HI_ERR_LZMA_PARAM;
75 }
76
77 uncompressed_len = (unsigned int)lzma_head[5] | /* index 5, low 8bits */
78 ((unsigned int)lzma_head[6] << 8) | /* index 6, bits 8-15 */
79 ((unsigned int)lzma_head[7] << 16) | /* index 7, bits 16-23 */
80 ((unsigned int)lzma_head[8] << 24); /* index 8, bits 24-32 */
81 uncompressed_len_high = (unsigned int)lzma_head[9] | /* index 9, low 8bits */
82 ((unsigned int)lzma_head[10] << 8) | /* index 10, bits 8-15 */
83 ((unsigned int)lzma_head[11] << 16) | /* index 11, bits 16-23 */
84 ((unsigned int)lzma_head[12] << 24); /* index 12, bits 24-32 */
85
86 if ((uncompressed_len_high != 0)) {
87 /* uncompressed file is too long, output buffer is not enough */
88 boot_msg1("[lzma get uncompress len]high", uncompressed_len_high);
89 return HI_ERR_LZMA_LEN;
90 }
91
92 *dic_size = (unsigned int)lzma_head[1] | /* index 1, low 8bits */
93 ((unsigned int)lzma_head[2] << 8) | /* index 2, bits 8-15 */
94 ((unsigned int)lzma_head[3] << 16) | /* index 3, bits 16-23 */
95 ((unsigned int)lzma_head[4] << 24); /* index 4, bits 24-32 */
96
97 if (*dic_size < LZMA_DIC_MIN) {
98 *dic_size = LZMA_DIC_MIN;
99 }
100
101 *pul_decompressed_data_len = uncompressed_len;
102 return HI_ERR_SUCCESS;
103 }
104
105 /**
106 * @ingroup LZMA
107 * @brief : LZMA decompress for sections
108 *
109 * @par description:
110 * LZMA decompress for sections
111 *
112 * @attention : nothing
113 * @param lzma_head [IN] type #hi_u8*-LZMA head
114 * @param compress_len [IN] type #unsigned int, size after compressed
115 * @param in_func [IN] type #LZMA_STREAM_FCT, get content of compressed
116 * @param out_func [IN] type #LZMA_STREAM_FCT, save the content after compressed
117 *
118 * @retval #HI_ERR_SUCCESS success
119 * @retval # other value: fail, see hi_errno.h for details
120 * @par dependency:
121 *
122 * @see : nothing
123 */
hi_lzma_decompress(const hi_u8 lzma_head[13],hi_u32 head_size,unsigned int compress_len,lzma_stream_fct in_func,lzma_stream_fct out_func)124 unsigned int hi_lzma_decompress(const hi_u8 lzma_head[13], hi_u32 head_size, /* head 13B */
125 unsigned int compress_len, lzma_stream_fct in_func, lzma_stream_fct out_func)
126 {
127 unsigned int ret;
128 unsigned int lzma_stat = 0;
129 unsigned int uncompress_len = 0;
130 unsigned int dic_size = 0;
131 i_sz_alloc alloc = { 0 };
132 lzma_stream in_stream;
133 lzma_stream out_stream;
134 in_stream.func = in_func;
135 in_stream.offset = 13; /* offset 13 */
136 out_stream.func = out_func;
137 out_stream.offset = 0;
138
139 alloc.alloc = lzma_alloc;
140 alloc.free = lzma_free;
141
142 ret = hi_lzma_get_uncompress_len(lzma_head, head_size, &uncompress_len, &dic_size);
143 if (ret != HI_ERR_SUCCESS) {
144 boot_msg1("[hi lzma decompress]get uncompress len:", ret);
145 }
146 ret = LzmaDecode2(lzma_head, 5, &lzma_stat, &alloc, &in_stream, /* size 5 */
147 &out_stream, compress_len - 13, uncompress_len); /* length subtract 13 */
148 if (ret != 0) {
149 boot_msg1("[hi lzma decompress]decode ret:", ret);
150 }
151
152 return (ret ? (HI_ERR_LZMA_DECODE + ret) : HI_ERR_SUCCESS);
153 }
154
155 /**
156 * @ingroup LZMA
157 * @brief LZMA RAM usage detect
158 *
159 * @par description:
160 * LZMA RAM usage detect, detect for whether the current RAM is enough for LZMA uncompress
161 *
162 * @attention : nothing
163 * @param lzma_head [IN] type #hi_u8*, LZMA head
164 *
165 * @retval #HI_ERR_SUCCESS success
166 * @retval # other value: fail, see hi_errno.h for details
167 * @par dependency:
168 *
169 * @see : nothing
170 */
hi_lzma_mem_detect(const hi_u8 lzma_head[13],hi_u32 head_size)171 unsigned int hi_lzma_mem_detect(const hi_u8 lzma_head[13], hi_u32 head_size) /* head 13B */
172 {
173 unsigned int ret;
174 unsigned int compress_len = 0;
175 unsigned int dic_size = 0;
176 unsigned char d;
177 unsigned int lc, lp;
178 unsigned int malloc_size[5] = { /* size 5*4 */
179 0,
180 };
181 unsigned char *addr[5] = { /* addr 5B */
182 HI_NULL,
183 };
184 unsigned int array_size = sizeof(addr) / sizeof(addr[0]);
185 unsigned int i;
186
187 ret = hi_lzma_get_uncompress_len(lzma_head, head_size, &compress_len, &dic_size);
188 if (ret != HI_ERR_SUCCESS) {
189 return ret;
190 }
191 d = lzma_head[0];
192 if (d >= (9 * 5 * 5)) { /* less than 9*5*5 */
193 boot_msg1("[hi_lzma_mem_detect]d", d);
194 return HI_ERR_FAILURE;
195 }
196
197 lc = d % 9; /* remain of devide 9 */
198 d /= 9; /* counts of 9 */
199 lp = d % 5; /* remain of devide 5 */
200
201 malloc_size[0] = (((unsigned int)LZMA_BASE_SIZE + (LZMA_LIT_SIZE << (lc + lp))) * 2); /* shifts (lc+lp)*2 */
202 malloc_size[1] = IN_BUF_SIZE; /* index 1 */
203 malloc_size[2] = OUT_BUF_SIZE; /* index 2 */
204 malloc_size[3] = dic_size; /* index 3 */
205 malloc_size[4] = 0x400; /* for security ,index 4:0x400 */
206 boot_msg2("[hi_lzma_mem_detect]malloc_size[0-3]", malloc_size[0], dic_size);
207
208 for (i = 0; i < array_size; i++) {
209 addr[i] = boot_malloc(malloc_size[i]);
210
211 if (addr[i] == HI_NULL) {
212 ret = HI_ERR_FAILURE;
213 break;
214 }
215 }
216
217 for (i = 0; i < array_size; i++) {
218 if (addr[array_size - i - 1] != HI_NULL) {
219 boot_free(addr[array_size - i - 1]);
220 }
221 }
222
223 return ret;
224 }
225