1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * (C) Copyright 2022 Rockchip Electronics Co., Ltd
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * SPDX-License-Identifier: GPL-2.0+
5*4882a593Smuzhiyun */
6*4882a593Smuzhiyun
7*4882a593Smuzhiyun #include <common.h>
8*4882a593Smuzhiyun #include <blk.h>
9*4882a593Smuzhiyun #include <memalign.h>
10*4882a593Smuzhiyun #include <image-sparse.h>
11*4882a593Smuzhiyun #include <u-boot/sha256.h>
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun /******************************************************************************/
14*4882a593Smuzhiyun #define PER_BLK_WRITE_SIZE SZ_8M /* Avoid -ENOMEM, eg: bounce buffer */
15*4882a593Smuzhiyun #define DEBUG_SPARSE
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun /******************************************************************************/
print_header_info(sparse_header_t * header)18*4882a593Smuzhiyun static void print_header_info(sparse_header_t *header)
19*4882a593Smuzhiyun {
20*4882a593Smuzhiyun #ifdef DEBUG_SPARSE
21*4882a593Smuzhiyun printf(" ==== sparse header ===\n");
22*4882a593Smuzhiyun printf(" magic: 0x%x\n", header->magic);
23*4882a593Smuzhiyun printf(" major_version: 0x%x\n", header->major_version);
24*4882a593Smuzhiyun printf(" minor_version: 0x%x\n", header->minor_version);
25*4882a593Smuzhiyun printf(" file_hdr_sz: %d\n", header->file_hdr_sz);
26*4882a593Smuzhiyun printf(" chunk_hdr_sz: %d\n", header->chunk_hdr_sz);
27*4882a593Smuzhiyun printf(" blk_sz: %d\n", header->blk_sz);
28*4882a593Smuzhiyun printf(" total_blks: %d\n", header->total_blks);
29*4882a593Smuzhiyun printf(" total_chunks: %d\n", header->total_chunks);
30*4882a593Smuzhiyun printf(" image_checksum: %d\n\n", header->image_checksum);
31*4882a593Smuzhiyun #endif
32*4882a593Smuzhiyun }
33*4882a593Smuzhiyun
print_chunk_info(chunk_header_t * chunk,u32 id,const u8 * ptr,sparse_header_t * header)34*4882a593Smuzhiyun static void print_chunk_info(chunk_header_t *chunk, u32 id,
35*4882a593Smuzhiyun const u8 *ptr, sparse_header_t *header)
36*4882a593Smuzhiyun {
37*4882a593Smuzhiyun #ifdef DEBUG_SPARSE
38*4882a593Smuzhiyun const char *type;
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun if (chunk->chunk_type == CHUNK_TYPE_RAW)
41*4882a593Smuzhiyun type = "RAW";
42*4882a593Smuzhiyun else if (chunk->chunk_type == CHUNK_TYPE_DONT_CARE)
43*4882a593Smuzhiyun type = "DONT CARE";
44*4882a593Smuzhiyun else if (chunk->chunk_type == CHUNK_TYPE_FILL)
45*4882a593Smuzhiyun type = "FILL";
46*4882a593Smuzhiyun else if (chunk->chunk_type == CHUNK_TYPE_CRC32)
47*4882a593Smuzhiyun type = "CRC32";
48*4882a593Smuzhiyun else
49*4882a593Smuzhiyun type = "UNK";
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun printf(" === [chunk.%d]\n", id + 1);
52*4882a593Smuzhiyun printf(" chunk_type: %s\n", type);
53*4882a593Smuzhiyun printf(" chunk_sz: %d\n", chunk->chunk_sz);
54*4882a593Smuzhiyun printf(" total_sz: %d\n", chunk->total_sz);
55*4882a593Smuzhiyun printf(" offset: %ld\n", (ulong)ptr - (ulong)header);
56*4882a593Smuzhiyun printf(" buf: 0x%08lx\n", (ulong)ptr);
57*4882a593Smuzhiyun #endif
58*4882a593Smuzhiyun }
59*4882a593Smuzhiyun
flash_write_data(struct blk_desc * desc,const u8 * data,ulong offset,ulong blocks)60*4882a593Smuzhiyun static int flash_write_data(struct blk_desc *desc, const u8 *data,
61*4882a593Smuzhiyun ulong offset, ulong blocks)
62*4882a593Smuzhiyun { const u8 *buf = data;
63*4882a593Smuzhiyun u32 step = BLOCK_CNT(PER_BLK_WRITE_SIZE, desc);
64*4882a593Smuzhiyun long left = blocks; /* signed long ! */
65*4882a593Smuzhiyun ulong lba = offset;
66*4882a593Smuzhiyun ulong blks;
67*4882a593Smuzhiyun
68*4882a593Smuzhiyun #ifdef DEBUG_SPARSE
69*4882a593Smuzhiyun printf(" lba: 0x%08lx - 0x%08lx\n", lba, lba + blocks);
70*4882a593Smuzhiyun #ifdef CONFIG_SHA256
71*4882a593Smuzhiyun u8 hash[32];
72*4882a593Smuzhiyun int i;
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun sha256_csum(data, blocks * desc->blksz, hash);
75*4882a593Smuzhiyun printf(" sha256sum: ");
76*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(hash); i++)
77*4882a593Smuzhiyun printf("%02x", hash[i]);
78*4882a593Smuzhiyun printf("\n");
79*4882a593Smuzhiyun #endif
80*4882a593Smuzhiyun #endif
81*4882a593Smuzhiyun while (left > 0) {
82*4882a593Smuzhiyun if (left < step)
83*4882a593Smuzhiyun blks = left;
84*4882a593Smuzhiyun else
85*4882a593Smuzhiyun blks = step;
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun if (blks != blk_dwrite(desc, lba, blks, buf)) {
88*4882a593Smuzhiyun printf("Raw data: LBA 0x%lx written error.\n", lba);
89*4882a593Smuzhiyun return -EIO;
90*4882a593Smuzhiyun }
91*4882a593Smuzhiyun buf += blks * desc->blksz;
92*4882a593Smuzhiyun lba += blks;
93*4882a593Smuzhiyun left -= step;
94*4882a593Smuzhiyun }
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun return 0;
97*4882a593Smuzhiyun }
98*4882a593Smuzhiyun
flash_fill_data(struct blk_desc * desc,ulong offset,ulong blocks,u32 fill_val)99*4882a593Smuzhiyun static int flash_fill_data(struct blk_desc *desc, ulong offset, ulong blocks,
100*4882a593Smuzhiyun u32 fill_val)
101*4882a593Smuzhiyun {
102*4882a593Smuzhiyun u32 step = BLOCK_CNT(PER_BLK_WRITE_SIZE, desc);
103*4882a593Smuzhiyun long left = blocks; /* signed long ! */
104*4882a593Smuzhiyun ulong lba = offset;
105*4882a593Smuzhiyun ulong blks;
106*4882a593Smuzhiyun char *buf;
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun buf = malloc(PER_BLK_WRITE_SIZE);
109*4882a593Smuzhiyun if (!buf) {
110*4882a593Smuzhiyun printf("No memory\n");
111*4882a593Smuzhiyun return -ENOMEM;
112*4882a593Smuzhiyun }
113*4882a593Smuzhiyun #ifdef DEBUG_SPARSE
114*4882a593Smuzhiyun printf(" lba: 0x%08lx - 0x%08lx\n", lba, lba + blocks);
115*4882a593Smuzhiyun printf(" fill: 0x%08x\n", fill_val);
116*4882a593Smuzhiyun #endif
117*4882a593Smuzhiyun memset((char *)buf, fill_val, PER_BLK_WRITE_SIZE);
118*4882a593Smuzhiyun while (left > 0) {
119*4882a593Smuzhiyun if (left < step)
120*4882a593Smuzhiyun blks = left;
121*4882a593Smuzhiyun else
122*4882a593Smuzhiyun blks = step;
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun if (blks != blk_dwrite(desc, lba, blks, buf)) {
125*4882a593Smuzhiyun printf("Fill data: LBA 0x%lx write error.\n", lba);
126*4882a593Smuzhiyun free(buf);
127*4882a593Smuzhiyun return -EIO;
128*4882a593Smuzhiyun }
129*4882a593Smuzhiyun lba += blks;
130*4882a593Smuzhiyun left -= step;
131*4882a593Smuzhiyun }
132*4882a593Smuzhiyun free(buf);
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun return 0;
135*4882a593Smuzhiyun }
136*4882a593Smuzhiyun
137*4882a593Smuzhiyun /******************************************************************************/
ext4_unsparse(struct blk_desc * desc,const u8 * buf,ulong start)138*4882a593Smuzhiyun int ext4_unsparse(struct blk_desc *desc, const u8 *buf, ulong start)
139*4882a593Smuzhiyun {
140*4882a593Smuzhiyun sparse_header_t *header = (sparse_header_t *)buf;
141*4882a593Smuzhiyun chunk_header_t *chunk = NULL;
142*4882a593Smuzhiyun ulong blk = start;
143*4882a593Smuzhiyun ulong chunk_len;
144*4882a593Smuzhiyun u64 img_size;
145*4882a593Smuzhiyun u32 i, fill;
146*4882a593Smuzhiyun
147*4882a593Smuzhiyun putc('\n');
148*4882a593Smuzhiyun
149*4882a593Smuzhiyun if (!is_sparse_image(header)) {
150*4882a593Smuzhiyun printf("Invalid sparse format.\n");
151*4882a593Smuzhiyun return -EINVAL;
152*4882a593Smuzhiyun }
153*4882a593Smuzhiyun
154*4882a593Smuzhiyun print_header_info(header);
155*4882a593Smuzhiyun
156*4882a593Smuzhiyun /* check fs img's real size is larger than partition size */
157*4882a593Smuzhiyun img_size = (u64)(header->total_blks * header->blk_sz);
158*4882a593Smuzhiyun
159*4882a593Smuzhiyun /* erase area: ensure DONT-CARE is 0 and FILL(0x0) is 0 */
160*4882a593Smuzhiyun if (blk_derase(desc, start, BLOCK_CNT(img_size, desc)) !=
161*4882a593Smuzhiyun BLOCK_CNT(img_size, desc))
162*4882a593Smuzhiyun return -EIO;
163*4882a593Smuzhiyun
164*4882a593Smuzhiyun printf("Erase 0x%08lx - 0x%08lx blocks OK.\n\n",
165*4882a593Smuzhiyun start, start + (ulong)BLOCK_CNT(img_size, desc));
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun /* skip the sparse header,to visit first chunk */
168*4882a593Smuzhiyun buf += header->file_hdr_sz;
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun /* to visit each chunk */
171*4882a593Smuzhiyun for (i = 0; i < header->total_chunks; i++) {
172*4882a593Smuzhiyun /* here the chunk_header */
173*4882a593Smuzhiyun chunk = (chunk_header_t *)buf;
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun /* go to next chunk's data */
176*4882a593Smuzhiyun buf += header->chunk_hdr_sz;
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun switch (chunk->chunk_type) {
179*4882a593Smuzhiyun case CHUNK_TYPE_RAW:
180*4882a593Smuzhiyun print_chunk_info(chunk, i, buf, header);
181*4882a593Smuzhiyun
182*4882a593Smuzhiyun /* to calculate the length of each chunk */
183*4882a593Smuzhiyun chunk_len = chunk->chunk_sz * header->blk_sz;
184*4882a593Smuzhiyun
185*4882a593Smuzhiyun /* verify every chunk to asure it is valid */
186*4882a593Smuzhiyun if (chunk->total_sz
187*4882a593Smuzhiyun != (chunk_len + header->chunk_hdr_sz)) {
188*4882a593Smuzhiyun printf("No.%d chunk size error.\n", i + 1);
189*4882a593Smuzhiyun return -EINVAL;
190*4882a593Smuzhiyun }
191*4882a593Smuzhiyun
192*4882a593Smuzhiyun if (flash_write_data(desc, buf,
193*4882a593Smuzhiyun blk, BLOCK_CNT(chunk_len, desc)))
194*4882a593Smuzhiyun return -EIO;
195*4882a593Smuzhiyun
196*4882a593Smuzhiyun buf += chunk_len;
197*4882a593Smuzhiyun blk += BLOCK_CNT(chunk_len, desc);
198*4882a593Smuzhiyun break;
199*4882a593Smuzhiyun case CHUNK_TYPE_DONT_CARE:
200*4882a593Smuzhiyun print_chunk_info(chunk, i, buf, header);
201*4882a593Smuzhiyun
202*4882a593Smuzhiyun if (chunk->total_sz != header->chunk_hdr_sz) {
203*4882a593Smuzhiyun printf("No.%d chunk size error.\n", i + 1);
204*4882a593Smuzhiyun return -EINVAL;
205*4882a593Smuzhiyun }
206*4882a593Smuzhiyun
207*4882a593Smuzhiyun chunk_len = chunk->chunk_sz * header->blk_sz;
208*4882a593Smuzhiyun blk += BLOCK_CNT(chunk_len, desc);
209*4882a593Smuzhiyun break;
210*4882a593Smuzhiyun case CHUNK_TYPE_FILL:
211*4882a593Smuzhiyun print_chunk_info(chunk, i, buf, header);
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun /* verify every chunk to asure it is valid */
214*4882a593Smuzhiyun if (chunk->total_sz - header->chunk_hdr_sz != 4) {
215*4882a593Smuzhiyun printf("No.%d chunk size error.\n", i);
216*4882a593Smuzhiyun return -EINVAL;
217*4882a593Smuzhiyun }
218*4882a593Smuzhiyun
219*4882a593Smuzhiyun /* to calculate the length of each chunk */
220*4882a593Smuzhiyun chunk_len = chunk->chunk_sz * header->blk_sz;
221*4882a593Smuzhiyun
222*4882a593Smuzhiyun /* ignore fill value "0", as we have erased yet */
223*4882a593Smuzhiyun fill = *(u32 *)buf;
224*4882a593Smuzhiyun if (fill != 0) {
225*4882a593Smuzhiyun if (flash_fill_data(desc, blk,
226*4882a593Smuzhiyun BLOCK_CNT(chunk_len, desc), fill))
227*4882a593Smuzhiyun return -EIO;
228*4882a593Smuzhiyun }
229*4882a593Smuzhiyun buf += 4;
230*4882a593Smuzhiyun blk += BLOCK_CNT(chunk_len, desc);
231*4882a593Smuzhiyun break;
232*4882a593Smuzhiyun case CHUNK_TYPE_CRC32:
233*4882a593Smuzhiyun print_chunk_info(chunk, i, buf, header);
234*4882a593Smuzhiyun printf("No.%d chunk type CRC32, Cannot handle!\n", i + 1);
235*4882a593Smuzhiyun return -ENOTSUPP;
236*4882a593Smuzhiyun default:
237*4882a593Smuzhiyun printf("sparse: unknown chunk type %04x.\n", chunk->chunk_type);
238*4882a593Smuzhiyun return -ENOTSUPP;
239*4882a593Smuzhiyun }
240*4882a593Smuzhiyun }
241*4882a593Smuzhiyun
242*4882a593Smuzhiyun printf("\nUnsparsed is %lld MiB and 0x%08lx - 0x%08lx blocks written OK.\n",
243*4882a593Smuzhiyun img_size >> 20, start, blk);
244*4882a593Smuzhiyun
245*4882a593Smuzhiyun return 0;
246*4882a593Smuzhiyun }
247*4882a593Smuzhiyun
248