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