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