1 /*
2  * Copyright (c) 2009, Google Inc.
3  * All rights reserved.
4  *
5  * Copyright (c) 2009-2014, The Linux Foundation. All rights reserved.
6  * Portions Copyright 2014 Broadcom Corporation.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions are met:
10  *     * Redistributions of source code must retain the above copyright
11  *       notice, this list of conditions and the following disclaimer.
12  *     * Redistributions in binary form must reproduce the above copyright
13  *       notice, this list of conditions and the following disclaimer in the
14  *       documentation and/or other materials provided with the distribution.
15  *     * Neither the name of The Linux Foundation nor
16  *       the names of its contributors may be used to endorse or promote
17  *       products derived from this software without specific prior written
18  *       permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23  * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
27  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
30  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  *
32  * NOTE:
33  *   Although it is very similar, this license text is not identical
34  *   to the "BSD-3-Clause", therefore, DO NOT MODIFY THIS LICENSE TEXT!
35  */
36 
37 #include <config.h>
38 #include <common.h>
39 #include <aboot.h>
40 #include <malloc.h>
41 #include <part.h>
42 #include <sparse_format.h>
43 
write_sparse_image(block_dev_desc_t * dev_desc,disk_partition_t * info,const char * part_name,void * data,unsigned sz)44 void write_sparse_image(block_dev_desc_t *dev_desc,
45 		disk_partition_t *info, const char *part_name,
46 		void *data, unsigned sz)
47 {
48 	lbaint_t blk;
49 	lbaint_t blkcnt;
50 	lbaint_t blks;
51 	uint32_t bytes_written = 0;
52 	unsigned int chunk;
53 	unsigned int chunk_data_sz;
54 	uint32_t *fill_buf = NULL;
55 	uint32_t fill_val;
56 	sparse_header_t *sparse_header;
57 	chunk_header_t *chunk_header;
58 	uint32_t total_blocks = 0;
59 	int i;
60 
61 	/* Read and skip over sparse image header */
62 	sparse_header = (sparse_header_t *) data;
63 
64 	data += sparse_header->file_hdr_sz;
65 	if (sparse_header->file_hdr_sz > sizeof(sparse_header_t))
66 	{
67 		/*
68 		 * Skip the remaining bytes in a header that is longer than
69 		 * we expected.
70 		 */
71 		data += (sparse_header->file_hdr_sz - sizeof(sparse_header_t));
72 	}
73 
74 	debug("=== Sparse Image Header ===\n");
75 	debug("magic: 0x%x\n", sparse_header->magic);
76 	debug("major_version: 0x%x\n", sparse_header->major_version);
77 	debug("minor_version: 0x%x\n", sparse_header->minor_version);
78 	debug("file_hdr_sz: %d\n", sparse_header->file_hdr_sz);
79 	debug("chunk_hdr_sz: %d\n", sparse_header->chunk_hdr_sz);
80 	debug("blk_sz: %d\n", sparse_header->blk_sz);
81 	debug("total_blks: %d\n", sparse_header->total_blks);
82 	debug("total_chunks: %d\n", sparse_header->total_chunks);
83 
84 	/* verify sparse_header->blk_sz is an exact multiple of info->blksz */
85 	if (sparse_header->blk_sz !=
86 	    (sparse_header->blk_sz & ~(info->blksz - 1))) {
87 		printf("%s: Sparse image block size issue [%u]\n",
88 		       __func__, sparse_header->blk_sz);
89 		fastboot_fail("sparse image block size issue");
90 		return;
91 	}
92 
93 	puts("Flashing Sparse Image\n");
94 
95 	/* Start processing chunks */
96 	blk = info->start;
97 	for (chunk=0; chunk<sparse_header->total_chunks; chunk++)
98 	{
99 		/* Read and skip over chunk header */
100 		chunk_header = (chunk_header_t *) data;
101 		data += sizeof(chunk_header_t);
102 
103 		if (chunk_header->chunk_type != CHUNK_TYPE_RAW) {
104 			debug("=== Chunk Header ===\n");
105 			debug("chunk_type: 0x%x\n", chunk_header->chunk_type);
106 			debug("chunk_data_sz: 0x%x\n", chunk_header->chunk_sz);
107 			debug("total_size: 0x%x\n", chunk_header->total_sz);
108 		}
109 
110 		if (sparse_header->chunk_hdr_sz > sizeof(chunk_header_t))
111 		{
112 			/*
113 			 * Skip the remaining bytes in a header that is longer
114 			 * than we expected.
115 			 */
116 			data += (sparse_header->chunk_hdr_sz -
117 				 sizeof(chunk_header_t));
118 		}
119 
120 		chunk_data_sz = sparse_header->blk_sz * chunk_header->chunk_sz;
121 		blkcnt = chunk_data_sz / info->blksz;
122 		switch (chunk_header->chunk_type)
123 		{
124 			case CHUNK_TYPE_RAW:
125 			if (chunk_header->total_sz !=
126 			    (sparse_header->chunk_hdr_sz + chunk_data_sz))
127 			{
128 				fastboot_fail(
129 					"Bogus chunk size for chunk type Raw");
130 				return;
131 			}
132 
133 			if (blk + blkcnt > info->start + info->size) {
134 				printf(
135 				    "%s: Request would exceed partition size!\n",
136 				    __func__);
137 				fastboot_fail(
138 				    "Request would exceed partition size!");
139 				return;
140 			}
141 
142 			blks = dev_desc->block_write(dev_desc->dev, blk, blkcnt,
143 						     data);
144 			if (blks != blkcnt) {
145 				printf("%s: Write failed " LBAFU "\n",
146 				       __func__, blks);
147 				fastboot_fail("flash write failure");
148 				return;
149 			}
150 			blk += blkcnt;
151 			bytes_written += blkcnt * info->blksz;
152 			total_blocks += chunk_header->chunk_sz;
153 			data += chunk_data_sz;
154 			break;
155 
156 			case CHUNK_TYPE_FILL:
157 			if (chunk_header->total_sz !=
158 			    (sparse_header->chunk_hdr_sz + sizeof(uint32_t)))
159 			{
160 				fastboot_fail(
161 					"Bogus chunk size for chunk type FILL");
162 				return;
163 			}
164 
165 			fill_buf = (uint32_t *)
166 				   memalign(ARCH_DMA_MINALIGN,
167 					    ROUNDUP(info->blksz,
168 						    ARCH_DMA_MINALIGN));
169 			if (!fill_buf)
170 			{
171 				fastboot_fail(
172 					"Malloc failed for: CHUNK_TYPE_FILL");
173 				return;
174 			}
175 
176 			fill_val = *(uint32_t *)data;
177 			data = (char *) data + sizeof(uint32_t);
178 
179 			for (i = 0; i < (info->blksz / sizeof(fill_val)); i++)
180 				fill_buf[i] = fill_val;
181 
182 			if (blk + blkcnt > info->start + info->size) {
183 				printf(
184 				    "%s: Request would exceed partition size!\n",
185 				    __func__);
186 				fastboot_fail(
187 				    "Request would exceed partition size!");
188 				return;
189 			}
190 
191 			for (i = 0; i < blkcnt; i++) {
192 				blks = dev_desc->block_write(dev_desc->dev,
193 							     blk, 1, fill_buf);
194 				if (blks != 1) {
195 					printf(
196 					    "%s: Write failed, block # " LBAFU "\n",
197 					    __func__, blkcnt);
198 					fastboot_fail("flash write failure");
199 					free(fill_buf);
200 					return;
201 				}
202 				blk++;
203 			}
204 			bytes_written += blkcnt * info->blksz;
205 			total_blocks += chunk_data_sz / sparse_header->blk_sz;
206 
207 			free(fill_buf);
208 			break;
209 
210 			case CHUNK_TYPE_DONT_CARE:
211 			blk += blkcnt;
212 			total_blocks += chunk_header->chunk_sz;
213 			break;
214 
215 			case CHUNK_TYPE_CRC32:
216 			if (chunk_header->total_sz !=
217 			    sparse_header->chunk_hdr_sz)
218 			{
219 				fastboot_fail(
220 					"Bogus chunk size for chunk type Dont Care");
221 				return;
222 			}
223 			total_blocks += chunk_header->chunk_sz;
224 			data += chunk_data_sz;
225 			break;
226 
227 			default:
228 			printf("%s: Unknown chunk type: %x\n", __func__,
229 			       chunk_header->chunk_type);
230 			fastboot_fail("Unknown chunk type");
231 			return;
232 		}
233 	}
234 
235 	debug("Wrote %d blocks, expected to write %d blocks\n",
236 	      total_blocks, sparse_header->total_blks);
237 	printf("........ wrote %u bytes to '%s'\n", bytes_written, part_name);
238 
239 	if (total_blocks != sparse_header->total_blks)
240 		fastboot_fail("sparse image write failure");
241 
242 	fastboot_okay("");
243 	return;
244 }
245