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
26static 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
36static 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 */
64unsigned 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 */
124unsigned 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 */
171unsigned 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