lin
2025-03-22 34bf7c4dd3c00c587f836898977857f2fe9bac74
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
/*
 *  * Copyright 2000-2009
 *   * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
 *    *
 *     * SPDX-License-Identifier:    GPL-2.0+
 *     */
#include <config.h>
#include <common.h>
#include <sparse_format.h>
#include "sparse.h"
#include "../sprite_verify.h"
#include "sunxi_flash.h"
#include "../cartoon/sprite_cartoon.h"
 
#define SPARSE_FORMAT_TYPE_TOTAL_HEAD 0xff00
#define SPARSE_FORMAT_TYPE_CHUNK_HEAD 0xff01
#define SPARSE_FORMAT_TYPE_CHUNK_DATA 0xff02
#define SPARSE_FORMAT_TYPE_CHUNK_FILL_DATA 0xff03
 
static uint android_format_checksum;
static uint sparse_format_type;
static uint chunk_count;
static int last_rest_size;
static int chunk_length;
static uint flash_start;
static sparse_header_t globl_header;
static uint total_chunks;
/*
************************************************************************************************************
*
*                                             unsparse_probe
*
*    函数名称:
*
*    参数列表:
*
*    返回值  :
*
*    说明    :
*
*
************************************************************************************************************
*/
int unsparse_probe(char *source, uint length, uint android_format_flash_start)
{
   sparse_header_t *header = (sparse_header_t *)source;
 
   if (header->magic != SPARSE_HEADER_MAGIC) {
       printf("sparse: bad magic\n");
 
       return ANDROID_FORMAT_BAD;
   }
 
   if ((header->major_version != SPARSE_HEADER_MAJOR_VER) ||
       (header->file_hdr_sz != sizeof(sparse_header_t)) ||
       (header->chunk_hdr_sz != sizeof(chunk_header_t))) {
       printf("sparse: incompatible format\n");
 
       return ANDROID_FORMAT_BAD;
   }
   android_format_checksum = 0;
   last_rest_size        = 0;
   chunk_count        = 0;
   chunk_length        = 0;
   sparse_format_type      = SPARSE_FORMAT_TYPE_TOTAL_HEAD;
   flash_start        = android_format_flash_start;
   total_chunks        = header->total_chunks;
 
   return ANDROID_FORMAT_DETECT;
}
/*
************************************************************************************************************
*
*                                             DRAM_Write
*
*    函数名称:
*
*    参数列表:
*
*    返回值  :
*
*    说明    :
*
*
************************************************************************************************************
*/
int unsparse_direct_write(void *pbuf, uint length)
{
   int unenough_length;
   int this_rest_size;
   int tmp_down_size;
   char *tmp_buf, *tmp_dest_buf;
   chunk_header_t *chunk;
   //首先计算传进的数据的校验和
   android_format_checksum += add_sum(pbuf, length);
 
   this_rest_size = last_rest_size + length;
   tmp_buf    = (char *)pbuf - last_rest_size;
   last_rest_size = 0;
   while (this_rest_size > 0) {
       switch (sparse_format_type) {
       case SPARSE_FORMAT_TYPE_TOTAL_HEAD: {
           memcpy(&globl_header, tmp_buf, sizeof(sparse_header_t));
           this_rest_size -= sizeof(sparse_header_t);
           tmp_buf += sizeof(sparse_header_t);
 
           sparse_format_type = SPARSE_FORMAT_TYPE_CHUNK_HEAD;
 
           break;
       }
       case SPARSE_FORMAT_TYPE_CHUNK_HEAD: {
           if (this_rest_size < sizeof(chunk_header_t)) {
               printf("sparse: chunk head data is not enough\n");
               last_rest_size = this_rest_size;
               tmp_dest_buf   = (char *)pbuf - this_rest_size;
               memcpy(tmp_dest_buf, tmp_buf, this_rest_size);
               this_rest_size = 0;
 
               break;
           }
           chunk = (chunk_header_t *)tmp_buf;
           /* move to next chunk */
           tmp_buf += sizeof(
               chunk_header_t); //此时tmp_buf已经指向下一个chunk或者data起始地址
           this_rest_size -=
               sizeof(chunk_header_t); //剩余的数据长度
           chunk_length =
               chunk->chunk_sz *
               globl_header
                   .blk_sz; //当前数据块需要写入的数据长度
           printf("chunk %d(%d)\n", chunk_count++, total_chunks);
#ifdef CONFIG_SUNXI_SPRITE_CARTOON
           sprite_cartoon_upgrade(10 + (70 * chunk_count)/total_chunks);
#endif
           switch (chunk->chunk_type) {
           case CHUNK_TYPE_RAW:
 
               if (chunk->total_sz !=
                   (chunk_length + sizeof(chunk_header_t))) {
                   printf("sparse: bad chunk size for chunk %d, type Raw\n",
                          chunk_count);
 
                   return -1;
               }
               //这里不处理数据部分,转到下一个状态
               sparse_format_type =
                   SPARSE_FORMAT_TYPE_CHUNK_DATA;
 
               break;
 
           case CHUNK_TYPE_FILL:
               if (chunk->total_sz !=
                   sizeof(chunk_header_t) + sizeof(u32)) {
                   printf("spase : bad chunk size for chunk ,type FILL \n");
                   return -1;
               }
               sparse_format_type =
                   SPARSE_FORMAT_TYPE_CHUNK_FILL_DATA;
 
               break;
           case CHUNK_TYPE_DONT_CARE:
               if (chunk->total_sz != sizeof(chunk_header_t)) {
                   printf("sparse: bogus DONT CARE chunk\n");
 
                   return -1;
               }
               flash_start += (chunk_length >> 9);
               sparse_format_type =
                   SPARSE_FORMAT_TYPE_CHUNK_HEAD;
 
               break;
 
           default:
               printf("sparse: unknown chunk ID %x\n",
                      chunk->chunk_type);
 
               return -1;
           }
           break;
       }
       case SPARSE_FORMAT_TYPE_CHUNK_DATA: {
           //首先判断数据是否足够当前chunk所需,如果不足,则计算出还需要的数据长度
           unenough_length =
               (chunk_length >= this_rest_size) ?
                   (chunk_length - this_rest_size) :
                   0;
           if (!unenough_length) {
               //数据足够,直接写入
               if (!sunxi_sprite_write(flash_start,
                           chunk_length >> 9,
                           tmp_buf)) {
                   printf("sparse: flash write failed\n");
                   return -1;
               }
               if (chunk_length & 511) {
                   printf("data is not sector align 0\n");
 
                   return -1;
               }
               flash_start += (chunk_length >> 9);
               tmp_buf += chunk_length;
               this_rest_size -= chunk_length;
               chunk_length = 0;
 
               sparse_format_type =
                   SPARSE_FORMAT_TYPE_CHUNK_HEAD;
           } else { //存在缺失数据的情况
               if (this_rest_size < 8 * 1024) {
                   //先看已有数据是否不足8k
                   //当不足时,把这笔数据放到下一笔数据的前部,等待下一次处理
                   tmp_dest_buf =
                       (char *)pbuf - this_rest_size;
                   memcpy(tmp_dest_buf, tmp_buf,
                          this_rest_size);
                   last_rest_size = this_rest_size;
                   this_rest_size = 0;
 
                   break;
               }
               //当已有数据超过16k时
               //当缺失数据长度不足4k时,可能只缺几十个字节
               if (unenough_length < 4 * 1024) {
                   //采用拼接方法,先烧写部分已有数据,然后在下一次把未烧写的已有数据和缺失数据一起烧录
                   tmp_down_size = this_rest_size +
                           unenough_length -
                           4 * 1024;
               } else {
                   //这里处理缺失数据超过8k(包含)的情况,同时已有数据也超过16k
 
                   //直接烧录当前全部数据;
                   tmp_down_size = this_rest_size &
                           (~(512 - 1)); //扇区对齐
               }
               if (!sunxi_sprite_write(flash_start,
                           tmp_down_size >> 9,
                           tmp_buf)) {
                   printf("sparse: flash write failed\n");
                   return -1;
               }
               if (tmp_down_size & 511) {
                   printf("data is not sector align 1\n");
 
                   return -1;
               }
               tmp_buf += tmp_down_size;
               flash_start += (tmp_down_size >> 9);
               chunk_length -= tmp_down_size;
               this_rest_size -= tmp_down_size;
               tmp_dest_buf = (char *)pbuf - this_rest_size;
               memcpy(tmp_dest_buf, tmp_buf, this_rest_size);
               last_rest_size = this_rest_size;
               this_rest_size = 0;
 
               sparse_format_type =
                   SPARSE_FORMAT_TYPE_CHUNK_DATA;
           }
 
           break;
       }
       case SPARSE_FORMAT_TYPE_CHUNK_FILL_DATA: {
           u32 fillbuf[1024];
           u32 file_val = 0;
           u32 ii       = 0;
 
           if (this_rest_size >= 4) {
               this_rest_size -= sizeof(u32);
               file_val = *(int *)tmp_buf;
               if (chunk_length & 511) {
                   printf("fill data is not sector align 0\n");
                   return -1;
               }
               for (ii = 0; ii < sizeof(fillbuf)/sizeof(fillbuf[0]); ii++)
                   fillbuf[ii] = file_val;
               for (ii = 0; ii < (chunk_length >> 12); ii++) {
                   if (!sunxi_sprite_write(flash_start, 8,
                               fillbuf)) {
                       printf("sparse: fill data write failed\n");
 
                       return -1;
                   }
                   flash_start += 8;
               }
               tmp_buf += sizeof(u32);
               sparse_format_type =
                   SPARSE_FORMAT_TYPE_CHUNK_HEAD;
           } else {
               tmp_dest_buf = (char *)pbuf - this_rest_size;
               memcpy(tmp_dest_buf, tmp_buf, this_rest_size);
               last_rest_size = this_rest_size;
               this_rest_size = 0;
               sparse_format_type =
                   SPARSE_FORMAT_TYPE_CHUNK_FILL_DATA;
           }
 
           break;
       }
       default: {
           printf("sparse: unknown status\n");
 
           return -1;
       }
       }
   }
 
   return 0;
}
/*
************************************************************************************************************
*
*                                             unsparse_checksum
*
*    函数名称:
*
*    参数列表:
*
*    返回值  :
*
*    说明    :
*
*
************************************************************************************************************
*/
uint unsparse_checksum(void)
{
   return android_format_checksum;
}