Commit cc0f08cd347ea9741375a70c490c6bee684f7bac
Committed by
Tom Rini
1 parent
64ece84854
Exists in
v2017.01-smarct4x
and in
25 other branches
fastboot: sparse: resync common/image-sparse.c (part 1)
This file originally came from upstream code. While retaining the storage abstraction feature, this is the first set of the changes required to resync with the cmd_flash_mmc_sparse_img() in the file aboot.c from https://us.codeaurora.org/cgit/quic/la/kernel/lk/plain/app/aboot/aboot.c?h=LE.BR.1.2.1 Signed-off-by: Steve Rae <srae@broadcom.com>
Showing 4 changed files with 210 additions and 352 deletions Side-by-side Diff
common/fb_mmc.c
... | ... | @@ -7,12 +7,10 @@ |
7 | 7 | #include <config.h> |
8 | 8 | #include <common.h> |
9 | 9 | #include <blk.h> |
10 | -#include <errno.h> | |
11 | 10 | #include <fastboot.h> |
12 | 11 | #include <fb_mmc.h> |
13 | 12 | #include <image-sparse.h> |
14 | 13 | #include <part.h> |
15 | -#include <sparse_format.h> | |
16 | 14 | #include <mmc.h> |
17 | 15 | #include <div64.h> |
18 | 16 | |
19 | 17 | |
20 | 18 | |
21 | 19 | |
... | ... | @@ -48,22 +46,13 @@ |
48 | 46 | return ret; |
49 | 47 | } |
50 | 48 | |
51 | - | |
52 | -static int fb_mmc_sparse_write(struct sparse_storage *storage, | |
53 | - void *priv, | |
54 | - unsigned int offset, | |
55 | - unsigned int size, | |
56 | - char *data) | |
49 | +static lbaint_t fb_mmc_sparse_write(struct sparse_storage *info, | |
50 | + lbaint_t blk, lbaint_t blkcnt, const void *buffer) | |
57 | 51 | { |
58 | - struct fb_mmc_sparse *sparse = priv; | |
52 | + struct fb_mmc_sparse *sparse = info->priv; | |
59 | 53 | struct blk_desc *dev_desc = sparse->dev_desc; |
60 | - int ret; | |
61 | 54 | |
62 | - ret = blk_dwrite(dev_desc, offset, size, data); | |
63 | - if (!ret) | |
64 | - return -EIO; | |
65 | - | |
66 | - return ret; | |
55 | + return blk_dwrite(dev_desc, blk, blkcnt, buffer); | |
67 | 56 | } |
68 | 57 | |
69 | 58 | static void write_raw_image(struct blk_desc *dev_desc, disk_partition_t *info, |
70 | 59 | |
71 | 60 | |
72 | 61 | |
73 | 62 | |
74 | 63 | |
... | ... | @@ -139,26 +128,25 @@ |
139 | 128 | |
140 | 129 | if (is_sparse_image(download_buffer)) { |
141 | 130 | struct fb_mmc_sparse sparse_priv; |
142 | - sparse_storage_t sparse; | |
131 | + struct sparse_storage sparse; | |
143 | 132 | |
144 | 133 | sparse_priv.dev_desc = dev_desc; |
145 | 134 | |
146 | - sparse.block_sz = info.blksz; | |
135 | + sparse.blksz = info.blksz; | |
147 | 136 | sparse.start = info.start; |
148 | 137 | sparse.size = info.size; |
149 | - sparse.name = cmd; | |
150 | 138 | sparse.write = fb_mmc_sparse_write; |
151 | 139 | |
152 | 140 | printf("Flashing sparse image at offset " LBAFU "\n", |
153 | - info.start); | |
141 | + sparse.start); | |
154 | 142 | |
155 | - store_sparse_image(&sparse, &sparse_priv, download_buffer); | |
143 | + sparse.priv = &sparse_priv; | |
144 | + write_sparse_image(&sparse, cmd, download_buffer, | |
145 | + download_bytes, response_str); | |
156 | 146 | } else { |
157 | 147 | write_raw_image(dev_desc, &info, cmd, download_buffer, |
158 | 148 | download_bytes); |
159 | 149 | } |
160 | - | |
161 | - fastboot_okay(response_str, ""); | |
162 | 150 | } |
163 | 151 | |
164 | 152 | void fb_mmc_erase(const char *cmd, char *response) |
common/fb_nand.c
... | ... | @@ -10,7 +10,6 @@ |
10 | 10 | |
11 | 11 | #include <fastboot.h> |
12 | 12 | #include <image-sparse.h> |
13 | -#include <sparse_format.h> | |
14 | 13 | |
15 | 14 | #include <linux/mtd/mtd.h> |
16 | 15 | #include <jffs2/jffs2.h> |
... | ... | @@ -19,7 +18,7 @@ |
19 | 18 | static char *response_str; |
20 | 19 | |
21 | 20 | struct fb_nand_sparse { |
22 | - struct mtd_info *nand; | |
21 | + struct mtd_info *mtd; | |
23 | 22 | struct part_info *part; |
24 | 23 | }; |
25 | 24 | |
26 | 25 | |
27 | 26 | |
28 | 27 | |
29 | 28 | |
... | ... | @@ -105,30 +104,32 @@ |
105 | 104 | buffer, flags); |
106 | 105 | } |
107 | 106 | |
108 | -static int fb_nand_sparse_write(struct sparse_storage *storage, | |
109 | - void *priv, | |
110 | - unsigned int offset, | |
111 | - unsigned int size, | |
112 | - char *data) | |
107 | +static lbaint_t fb_nand_sparse_write(struct sparse_storage *info, | |
108 | + lbaint_t blk, lbaint_t blkcnt, const void *buffer) | |
113 | 109 | { |
114 | - struct fb_nand_sparse *sparse = priv; | |
110 | + struct fb_nand_sparse *sparse = info->priv; | |
115 | 111 | size_t written; |
116 | 112 | int ret; |
117 | 113 | |
118 | - ret = _fb_nand_write(sparse->nand, sparse->part, data, | |
119 | - offset * storage->block_sz, | |
120 | - size * storage->block_sz, &written); | |
114 | + ret = _fb_nand_write(sparse->mtd, sparse->part, (void *)buffer, | |
115 | + blk * info->blksz, | |
116 | + blkcnt * info->blksz, &written); | |
121 | 117 | if (ret < 0) { |
122 | 118 | printf("Failed to write sparse chunk\n"); |
123 | 119 | return ret; |
124 | 120 | } |
125 | 121 | |
126 | - return written / storage->block_sz; | |
122 | +/* TODO - verify that the value "written" includes the "bad-blocks" ... */ | |
123 | + | |
124 | + /* | |
125 | + * the return value must be 'blkcnt' ("good-blocks") plus the | |
126 | + * number of "bad-blocks" encountered within this space... | |
127 | + */ | |
128 | + return written / info->blksz; | |
127 | 129 | } |
128 | 130 | |
129 | -void fb_nand_flash_write(const char *partname, | |
130 | - void *download_buffer, unsigned int download_bytes, | |
131 | - char *response) | |
131 | +void fb_nand_flash_write(const char *cmd, void *download_buffer, | |
132 | + unsigned int download_bytes, char *response) | |
132 | 133 | { |
133 | 134 | struct part_info *part; |
134 | 135 | struct mtd_info *mtd = NULL; |
... | ... | @@ -137,7 +138,7 @@ |
137 | 138 | /* initialize the response buffer */ |
138 | 139 | response_str = response; |
139 | 140 | |
140 | - ret = fb_nand_lookup(partname, response, &mtd, &part); | |
141 | + ret = fb_nand_lookup(cmd, response, &mtd, &part); | |
141 | 142 | if (ret) { |
142 | 143 | error("invalid NAND device"); |
143 | 144 | fastboot_fail(response_str, "invalid NAND device"); |
144 | 145 | |
145 | 146 | |
146 | 147 | |
... | ... | @@ -150,19 +151,22 @@ |
150 | 151 | |
151 | 152 | if (is_sparse_image(download_buffer)) { |
152 | 153 | struct fb_nand_sparse sparse_priv; |
153 | - sparse_storage_t sparse; | |
154 | + struct sparse_storage sparse; | |
154 | 155 | |
155 | - sparse_priv.nand = mtd; | |
156 | + sparse_priv.mtd = mtd; | |
156 | 157 | sparse_priv.part = part; |
157 | 158 | |
158 | - sparse.block_sz = mtd->writesize; | |
159 | - sparse.start = part->offset / sparse.block_sz; | |
160 | - sparse.size = part->size / sparse.block_sz; | |
161 | - sparse.name = part->name; | |
159 | + sparse.blksz = mtd->writesize; | |
160 | + sparse.start = part->offset / sparse.blksz; | |
161 | + sparse.size = part->size / sparse.blksz; | |
162 | 162 | sparse.write = fb_nand_sparse_write; |
163 | 163 | |
164 | - ret = store_sparse_image(&sparse, &sparse_priv, | |
165 | - download_buffer); | |
164 | + printf("Flashing sparse image at offset " LBAFU "\n", | |
165 | + sparse.start); | |
166 | + | |
167 | + sparse.priv = &sparse_priv; | |
168 | + write_sparse_image(&sparse, cmd, download_buffer, | |
169 | + download_bytes, response_str); | |
166 | 170 | } else { |
167 | 171 | printf("Flashing raw image at offset 0x%llx\n", |
168 | 172 | part->offset); |
... | ... | @@ -182,7 +186,7 @@ |
182 | 186 | fastboot_okay(response_str, ""); |
183 | 187 | } |
184 | 188 | |
185 | -void fb_nand_erase(const char *partname, char *response) | |
189 | +void fb_nand_erase(const char *cmd, char *response) | |
186 | 190 | { |
187 | 191 | struct part_info *part; |
188 | 192 | struct mtd_info *mtd = NULL; |
... | ... | @@ -191,7 +195,7 @@ |
191 | 195 | /* initialize the response buffer */ |
192 | 196 | response_str = response; |
193 | 197 | |
194 | - ret = fb_nand_lookup(partname, response, &mtd, &part); | |
198 | + ret = fb_nand_lookup(cmd, response, &mtd, &part); | |
195 | 199 | if (ret) { |
196 | 200 | error("invalid NAND device"); |
197 | 201 | fastboot_fail(response_str, "invalid NAND device"); |
common/image-sparse.c
... | ... | @@ -36,55 +36,45 @@ |
36 | 36 | |
37 | 37 | #include <config.h> |
38 | 38 | #include <common.h> |
39 | -#include <div64.h> | |
40 | -#include <errno.h> | |
41 | 39 | #include <image-sparse.h> |
40 | +#include <div64.h> | |
42 | 41 | #include <malloc.h> |
43 | 42 | #include <part.h> |
44 | 43 | #include <sparse_format.h> |
44 | +#include <fastboot.h> | |
45 | 45 | |
46 | 46 | #include <linux/math64.h> |
47 | 47 | |
48 | -typedef struct sparse_buffer { | |
49 | - void *data; | |
50 | - u32 length; | |
51 | - u32 repeat; | |
52 | - u16 type; | |
53 | -} sparse_buffer_t; | |
54 | - | |
55 | -static unsigned int sparse_get_chunk_data_size(sparse_header_t *sparse, | |
56 | - chunk_header_t *chunk) | |
48 | +void write_sparse_image( | |
49 | + struct sparse_storage *info, const char *part_name, | |
50 | + void *data, unsigned sz, char *response_str) | |
57 | 51 | { |
58 | - return chunk->total_sz - sparse->chunk_hdr_sz; | |
59 | -} | |
52 | + lbaint_t blk; | |
53 | + lbaint_t blkcnt; | |
54 | + lbaint_t blks; | |
55 | + uint32_t bytes_written = 0; | |
56 | + unsigned int chunk; | |
57 | + unsigned int offset; | |
58 | + unsigned int chunk_data_sz; | |
59 | + uint32_t *fill_buf = NULL; | |
60 | + uint32_t fill_val; | |
61 | + sparse_header_t *sparse_header; | |
62 | + chunk_header_t *chunk_header; | |
63 | + uint32_t total_blocks = 0; | |
64 | + int i; | |
60 | 65 | |
61 | -static unsigned int sparse_block_size_to_storage(unsigned int size, | |
62 | - sparse_storage_t *storage, | |
63 | - sparse_header_t *sparse) | |
64 | -{ | |
65 | - return (unsigned int)lldiv((uint64_t)size * sparse->blk_sz, | |
66 | - storage->block_sz); | |
67 | -} | |
66 | + /* Read and skip over sparse image header */ | |
67 | + sparse_header = (sparse_header_t *)data; | |
68 | 68 | |
69 | -static bool sparse_chunk_has_buffer(chunk_header_t *chunk) | |
70 | -{ | |
71 | - switch (chunk->chunk_type) { | |
72 | - case CHUNK_TYPE_RAW: | |
73 | - case CHUNK_TYPE_FILL: | |
74 | - return true; | |
75 | - | |
76 | - default: | |
77 | - return false; | |
69 | + data += sparse_header->file_hdr_sz; | |
70 | + if (sparse_header->file_hdr_sz > sizeof(sparse_header_t)) { | |
71 | + /* | |
72 | + * Skip the remaining bytes in a header that is longer than | |
73 | + * we expected. | |
74 | + */ | |
75 | + data += (sparse_header->file_hdr_sz - sizeof(sparse_header_t)); | |
78 | 76 | } |
79 | -} | |
80 | 77 | |
81 | -static sparse_header_t *sparse_parse_header(void **data) | |
82 | -{ | |
83 | - /* Read and skip over sparse image header */ | |
84 | - sparse_header_t *sparse_header = (sparse_header_t *) *data; | |
85 | - | |
86 | - *data += sparse_header->file_hdr_sz; | |
87 | - | |
88 | 78 | debug("=== Sparse Image Header ===\n"); |
89 | 79 | debug("magic: 0x%x\n", sparse_header->magic); |
90 | 80 | debug("major_version: 0x%x\n", sparse_header->major_version); |
91 | 81 | |
92 | 82 | |
93 | 83 | |
94 | 84 | |
95 | 85 | |
96 | 86 | |
97 | 87 | |
98 | 88 | |
99 | 89 | |
100 | 90 | |
101 | 91 | |
102 | 92 | |
103 | 93 | |
104 | 94 | |
105 | 95 | |
106 | 96 | |
107 | 97 | |
108 | 98 | |
... | ... | @@ -95,290 +85,165 @@ |
95 | 85 | debug("total_blks: %d\n", sparse_header->total_blks); |
96 | 86 | debug("total_chunks: %d\n", sparse_header->total_chunks); |
97 | 87 | |
98 | - return sparse_header; | |
99 | -} | |
100 | - | |
101 | -static int sparse_parse_fill_chunk(sparse_header_t *sparse, | |
102 | - chunk_header_t *chunk) | |
103 | -{ | |
104 | - unsigned int chunk_data_sz = sparse_get_chunk_data_size(sparse, chunk); | |
105 | - | |
106 | - if (chunk_data_sz != sizeof(uint32_t)) | |
107 | - return -EINVAL; | |
108 | - | |
109 | - return 0; | |
110 | -} | |
111 | - | |
112 | -static int sparse_parse_raw_chunk(sparse_header_t *sparse, | |
113 | - chunk_header_t *chunk) | |
114 | -{ | |
115 | - unsigned int chunk_data_sz = sparse_get_chunk_data_size(sparse, chunk); | |
116 | - | |
117 | - /* Check if the data size is a multiple of the main block size */ | |
118 | - if (chunk_data_sz % sparse->blk_sz) | |
119 | - return -EINVAL; | |
120 | - | |
121 | - /* Check that the chunk size is consistent */ | |
122 | - if ((chunk_data_sz / sparse->blk_sz) != chunk->chunk_sz) | |
123 | - return -EINVAL; | |
124 | - | |
125 | - return 0; | |
126 | -} | |
127 | - | |
128 | -static chunk_header_t *sparse_parse_chunk(sparse_header_t *sparse, | |
129 | - void **image) | |
130 | -{ | |
131 | - chunk_header_t *chunk = (chunk_header_t *) *image; | |
132 | - int ret; | |
133 | - | |
134 | - debug("=== Chunk Header ===\n"); | |
135 | - debug("chunk_type: 0x%x\n", chunk->chunk_type); | |
136 | - debug("chunk_data_sz: 0x%x\n", chunk->chunk_sz); | |
137 | - debug("total_size: 0x%x\n", chunk->total_sz); | |
138 | - | |
139 | - switch (chunk->chunk_type) { | |
140 | - case CHUNK_TYPE_RAW: | |
141 | - ret = sparse_parse_raw_chunk(sparse, chunk); | |
142 | - if (ret) | |
143 | - return NULL; | |
144 | - break; | |
145 | - | |
146 | - case CHUNK_TYPE_FILL: | |
147 | - ret = sparse_parse_fill_chunk(sparse, chunk); | |
148 | - if (ret) | |
149 | - return NULL; | |
150 | - break; | |
151 | - | |
152 | - case CHUNK_TYPE_DONT_CARE: | |
153 | - case CHUNK_TYPE_CRC32: | |
154 | - debug("Ignoring chunk\n"); | |
155 | - break; | |
156 | - | |
157 | - default: | |
158 | - printf("%s: Unknown chunk type: %x\n", __func__, | |
159 | - chunk->chunk_type); | |
160 | - return NULL; | |
161 | - } | |
162 | - | |
163 | - *image += sparse->chunk_hdr_sz; | |
164 | - | |
165 | - return chunk; | |
166 | -} | |
167 | - | |
168 | -static int sparse_get_fill_buffer(sparse_header_t *sparse, | |
169 | - chunk_header_t *chunk, | |
170 | - sparse_buffer_t *buffer, | |
171 | - unsigned int blk_sz, | |
172 | - void *data) | |
173 | -{ | |
174 | - int i; | |
175 | - | |
176 | - buffer->type = CHUNK_TYPE_FILL; | |
177 | - | |
178 | 88 | /* |
179 | - * We create a buffer of one block, and ask it to be | |
180 | - * repeated as many times as needed. | |
181 | - */ | |
182 | - buffer->length = blk_sz; | |
183 | - buffer->repeat = (chunk->chunk_sz * sparse->blk_sz) / blk_sz; | |
184 | - | |
185 | - buffer->data = memalign(ARCH_DMA_MINALIGN, | |
186 | - ROUNDUP(blk_sz, | |
187 | - ARCH_DMA_MINALIGN)); | |
188 | - if (!buffer->data) | |
189 | - return -ENOMEM; | |
190 | - | |
191 | - for (i = 0; i < (buffer->length / sizeof(uint32_t)); i++) | |
192 | - ((uint32_t *)buffer->data)[i] = *(uint32_t *)(data); | |
193 | - | |
194 | - return 0; | |
195 | -} | |
196 | - | |
197 | -static int sparse_get_raw_buffer(sparse_header_t *sparse, | |
198 | - chunk_header_t *chunk, | |
199 | - sparse_buffer_t *buffer, | |
200 | - unsigned int blk_sz, | |
201 | - void *data) | |
202 | -{ | |
203 | - unsigned int chunk_data_sz = sparse_get_chunk_data_size(sparse, chunk); | |
204 | - | |
205 | - buffer->type = CHUNK_TYPE_RAW; | |
206 | - buffer->length = chunk_data_sz; | |
207 | - buffer->data = data; | |
208 | - buffer->repeat = 1; | |
209 | - | |
210 | - return 0; | |
211 | -} | |
212 | - | |
213 | -static sparse_buffer_t *sparse_get_data_buffer(sparse_header_t *sparse, | |
214 | - chunk_header_t *chunk, | |
215 | - unsigned int blk_sz, | |
216 | - void **image) | |
217 | -{ | |
218 | - unsigned int chunk_data_sz = sparse_get_chunk_data_size(sparse, chunk); | |
219 | - sparse_buffer_t *buffer; | |
220 | - void *data = *image; | |
221 | - int ret; | |
222 | - | |
223 | - *image += chunk_data_sz; | |
224 | - | |
225 | - if (!sparse_chunk_has_buffer(chunk)) | |
226 | - return NULL; | |
227 | - | |
228 | - buffer = calloc(sizeof(sparse_buffer_t), 1); | |
229 | - if (!buffer) | |
230 | - return NULL; | |
231 | - | |
232 | - switch (chunk->chunk_type) { | |
233 | - case CHUNK_TYPE_RAW: | |
234 | - ret = sparse_get_raw_buffer(sparse, chunk, buffer, blk_sz, | |
235 | - data); | |
236 | - if (ret) | |
237 | - return NULL; | |
238 | - break; | |
239 | - | |
240 | - case CHUNK_TYPE_FILL: | |
241 | - ret = sparse_get_fill_buffer(sparse, chunk, buffer, blk_sz, | |
242 | - data); | |
243 | - if (ret) | |
244 | - return NULL; | |
245 | - break; | |
246 | - | |
247 | - default: | |
248 | - return NULL; | |
249 | - } | |
250 | - | |
251 | - debug("=== Buffer ===\n"); | |
252 | - debug("length: 0x%x\n", buffer->length); | |
253 | - debug("repeat: 0x%x\n", buffer->repeat); | |
254 | - debug("type: 0x%x\n", buffer->type); | |
255 | - debug("data: 0x%p\n", buffer->data); | |
256 | - | |
257 | - return buffer; | |
258 | -} | |
259 | - | |
260 | -static void sparse_put_data_buffer(sparse_buffer_t *buffer) | |
261 | -{ | |
262 | - if (buffer->type == CHUNK_TYPE_FILL) | |
263 | - free(buffer->data); | |
264 | - | |
265 | - free(buffer); | |
266 | -} | |
267 | - | |
268 | -int store_sparse_image(sparse_storage_t *storage, | |
269 | - void *storage_priv, void *data) | |
270 | -{ | |
271 | - unsigned int chunk, offset; | |
272 | - sparse_header_t *sparse_header; | |
273 | - chunk_header_t *chunk_header; | |
274 | - sparse_buffer_t *buffer; | |
275 | - uint32_t start; | |
276 | - uint32_t total_blocks = 0; | |
277 | - int i; | |
278 | - | |
279 | - debug("=== Storage ===\n"); | |
280 | - debug("name: %s\n", storage->name); | |
281 | - debug("block_size: 0x%x\n", storage->block_sz); | |
282 | - debug("start: 0x%x\n", storage->start); | |
283 | - debug("size: 0x%x\n", storage->size); | |
284 | - debug("write: 0x%p\n", storage->write); | |
285 | - debug("priv: 0x%p\n", storage_priv); | |
286 | - | |
287 | - sparse_header = sparse_parse_header(&data); | |
288 | - if (!sparse_header) { | |
289 | - printf("sparse header issue\n"); | |
290 | - return -EINVAL; | |
291 | - } | |
292 | - | |
293 | - /* | |
294 | 89 | * Verify that the sparse block size is a multiple of our |
295 | 90 | * storage backend block size |
296 | 91 | */ |
297 | - div_u64_rem(sparse_header->blk_sz, storage->block_sz, &offset); | |
92 | + div_u64_rem(sparse_header->blk_sz, info->blksz, &offset); | |
298 | 93 | if (offset) { |
299 | 94 | printf("%s: Sparse image block size issue [%u]\n", |
300 | 95 | __func__, sparse_header->blk_sz); |
301 | - return -EINVAL; | |
96 | + fastboot_fail(response_str, "sparse image block size issue"); | |
97 | + return; | |
302 | 98 | } |
303 | 99 | |
304 | 100 | puts("Flashing Sparse Image\n"); |
305 | 101 | |
306 | 102 | /* Start processing chunks */ |
307 | - start = storage->start; | |
103 | + blk = info->start; | |
308 | 104 | for (chunk = 0; chunk < sparse_header->total_chunks; chunk++) { |
309 | - uint32_t blkcnt; | |
105 | + /* Read and skip over chunk header */ | |
106 | + chunk_header = (chunk_header_t *)data; | |
107 | + data += sizeof(chunk_header_t); | |
310 | 108 | |
311 | - chunk_header = sparse_parse_chunk(sparse_header, &data); | |
312 | - if (!chunk_header) { | |
313 | - printf("Unknown chunk type"); | |
314 | - return -EINVAL; | |
109 | + if (chunk_header->chunk_type != CHUNK_TYPE_RAW) { | |
110 | + debug("=== Chunk Header ===\n"); | |
111 | + debug("chunk_type: 0x%x\n", chunk_header->chunk_type); | |
112 | + debug("chunk_data_sz: 0x%x\n", chunk_header->chunk_sz); | |
113 | + debug("total_size: 0x%x\n", chunk_header->total_sz); | |
315 | 114 | } |
316 | 115 | |
317 | - /* | |
318 | - * If we have a DONT_CARE type, just skip the blocks | |
319 | - * and go on parsing the rest of the chunks | |
320 | - */ | |
321 | - if (chunk_header->chunk_type == CHUNK_TYPE_DONT_CARE) { | |
322 | - blkcnt = sparse_block_size_to_storage(chunk_header->chunk_sz, | |
323 | - storage, | |
324 | - sparse_header); | |
325 | -#ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV | |
326 | - total_blocks += blkcnt; | |
327 | -#endif | |
328 | - continue; | |
116 | + if (sparse_header->chunk_hdr_sz > sizeof(chunk_header_t)) { | |
117 | + /* | |
118 | + * Skip the remaining bytes in a header that is longer | |
119 | + * than we expected. | |
120 | + */ | |
121 | + data += (sparse_header->chunk_hdr_sz - | |
122 | + sizeof(chunk_header_t)); | |
329 | 123 | } |
330 | 124 | |
331 | - /* Retrieve the buffer we're going to write */ | |
332 | - buffer = sparse_get_data_buffer(sparse_header, chunk_header, | |
333 | - storage->block_sz, &data); | |
334 | - if (!buffer) | |
335 | - continue; | |
125 | + chunk_data_sz = sparse_header->blk_sz * chunk_header->chunk_sz; | |
126 | + blkcnt = chunk_data_sz / info->blksz; | |
127 | + switch (chunk_header->chunk_type) { | |
128 | + case CHUNK_TYPE_RAW: | |
129 | + if (chunk_header->total_sz != | |
130 | + (sparse_header->chunk_hdr_sz + chunk_data_sz)) { | |
131 | + fastboot_fail(response_str, | |
132 | + "Bogus chunk size for chunk type Raw"); | |
133 | + return; | |
134 | + } | |
336 | 135 | |
337 | - blkcnt = (buffer->length / storage->block_sz) * buffer->repeat; | |
136 | + if (blk + blkcnt > info->start + info->size) { | |
137 | + printf( | |
138 | + "%s: Request would exceed partition size!\n", | |
139 | + __func__); | |
140 | + fastboot_fail(response_str, | |
141 | + "Request would exceed partition size!"); | |
142 | + return; | |
143 | + } | |
338 | 144 | |
339 | - if ((start + total_blocks + blkcnt) > | |
340 | - (storage->start + storage->size)) { | |
341 | - printf("%s: Request would exceed partition size!\n", | |
342 | - __func__); | |
343 | - return -EINVAL; | |
344 | - } | |
145 | + blks = info->write(info, blk, blkcnt, data); | |
146 | + /* blks might be > blkcnt (eg. NAND bad-blocks) */ | |
147 | + if (blks < blkcnt) { | |
148 | + printf("%s: %s" LBAFU " [" LBAFU "]\n", | |
149 | + __func__, "Write failed, block #", | |
150 | + blk, blks); | |
151 | + fastboot_fail(response_str, | |
152 | + "flash write failure"); | |
153 | + return; | |
154 | + } | |
155 | + blk += blks; | |
156 | + bytes_written += blkcnt * info->blksz; | |
157 | + total_blocks += chunk_header->chunk_sz; | |
158 | + data += chunk_data_sz; | |
159 | + break; | |
345 | 160 | |
346 | - for (i = 0; i < buffer->repeat; i++) { | |
347 | - unsigned long buffer_blk_cnt; | |
348 | - int ret; | |
161 | + case CHUNK_TYPE_FILL: | |
162 | + if (chunk_header->total_sz != | |
163 | + (sparse_header->chunk_hdr_sz + sizeof(uint32_t))) { | |
164 | + fastboot_fail(response_str, | |
165 | + "Bogus chunk size for chunk type FILL"); | |
166 | + return; | |
167 | + } | |
349 | 168 | |
350 | - buffer_blk_cnt = buffer->length / storage->block_sz; | |
169 | + fill_buf = (uint32_t *) | |
170 | + memalign(ARCH_DMA_MINALIGN, | |
171 | + ROUNDUP(info->blksz, | |
172 | + ARCH_DMA_MINALIGN)); | |
173 | + if (!fill_buf) { | |
174 | + fastboot_fail(response_str, | |
175 | + "Malloc failed for: CHUNK_TYPE_FILL"); | |
176 | + return; | |
177 | + } | |
351 | 178 | |
352 | - ret = storage->write(storage, storage_priv, | |
353 | - start + total_blocks, | |
354 | - buffer_blk_cnt, | |
355 | - buffer->data); | |
356 | - if (ret < 0) { | |
357 | - printf("%s: Write %d failed %d\n", | |
358 | - __func__, i, ret); | |
359 | - return ret; | |
179 | + fill_val = *(uint32_t *)data; | |
180 | + data = (char *)data + sizeof(uint32_t); | |
181 | + | |
182 | + for (i = 0; i < (info->blksz / sizeof(fill_val)); i++) | |
183 | + fill_buf[i] = fill_val; | |
184 | + | |
185 | + if (blk + blkcnt > info->start + info->size) { | |
186 | + printf( | |
187 | + "%s: Request would exceed partition size!\n", | |
188 | + __func__); | |
189 | + fastboot_fail(response_str, | |
190 | + "Request would exceed partition size!"); | |
191 | + return; | |
360 | 192 | } |
361 | 193 | |
362 | - total_blocks += ret; | |
363 | - } | |
194 | + for (i = 0; i < blkcnt; i++) { | |
195 | + blks = info->write(info, blk, 1, fill_buf); | |
196 | + /* blks might be > 1 (eg. NAND bad-blocks) */ | |
197 | + if (blks < 1) { | |
198 | + printf("%s: %s, block # " LBAFU "\n", | |
199 | + __func__, "Write failed", blk); | |
200 | + fastboot_fail(response_str, | |
201 | + "flash write failure"); | |
202 | + free(fill_buf); | |
203 | + return; | |
204 | + } | |
205 | + blk += blks; | |
206 | + } | |
207 | + bytes_written += blkcnt * info->blksz; | |
208 | + total_blocks += chunk_data_sz / sparse_header->blk_sz; | |
209 | + free(fill_buf); | |
210 | + break; | |
364 | 211 | |
365 | - sparse_put_data_buffer(buffer); | |
212 | + case CHUNK_TYPE_DONT_CARE: | |
213 | +#ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV | |
214 | + blk += blkcnt; | |
215 | + total_blocks += chunk_header->chunk_sz; | |
216 | +#endif | |
217 | + break; | |
218 | + | |
219 | + case CHUNK_TYPE_CRC32: | |
220 | + if (chunk_header->total_sz != | |
221 | + sparse_header->chunk_hdr_sz) { | |
222 | + fastboot_fail(response_str, | |
223 | + "Bogus chunk size for chunk type Dont Care"); | |
224 | + return; | |
225 | + } | |
226 | + total_blocks += chunk_header->chunk_sz; | |
227 | + data += chunk_data_sz; | |
228 | + break; | |
229 | + | |
230 | + default: | |
231 | + printf("%s: Unknown chunk type: %x\n", __func__, | |
232 | + chunk_header->chunk_type); | |
233 | + fastboot_fail(response_str, "Unknown chunk type"); | |
234 | + return; | |
235 | + } | |
366 | 236 | } |
367 | 237 | |
368 | 238 | debug("Wrote %d blocks, expected to write %d blocks\n", |
369 | - total_blocks, | |
370 | - sparse_block_size_to_storage(sparse_header->total_blks, | |
371 | - storage, sparse_header)); | |
372 | - printf("........ wrote %d blocks to '%s'\n", total_blocks, | |
373 | - storage->name); | |
239 | + total_blocks, sparse_header->total_blks); | |
240 | + printf("........ wrote %u bytes to '%s'\n", bytes_written, part_name); | |
374 | 241 | |
375 | - if (total_blocks != | |
376 | - sparse_block_size_to_storage(sparse_header->total_blks, | |
377 | - storage, sparse_header)) { | |
378 | - printf("sparse image write failure\n"); | |
379 | - return -EIO; | |
380 | - } | |
242 | + if (total_blocks != sparse_header->total_blks) | |
243 | + fastboot_fail(response_str, "sparse image write failure"); | |
244 | + else | |
245 | + fastboot_okay(response_str, ""); | |
381 | 246 | |
382 | - return 0; | |
247 | + return; | |
383 | 248 | } |
include/image-sparse.h
... | ... | @@ -9,16 +9,17 @@ |
9 | 9 | |
10 | 10 | #define ROUNDUP(x, y) (((x) + ((y) - 1)) & ~((y) - 1)) |
11 | 11 | |
12 | -typedef struct sparse_storage { | |
13 | - unsigned int block_sz; | |
14 | - unsigned int start; | |
15 | - unsigned int size; | |
16 | - const char *name; | |
12 | +struct sparse_storage { | |
13 | + lbaint_t blksz; | |
14 | + lbaint_t start; | |
15 | + lbaint_t size; | |
16 | + void *priv; | |
17 | 17 | |
18 | - int (*write)(struct sparse_storage *storage, void *priv, | |
19 | - unsigned int offset, unsigned int size, | |
20 | - char *data); | |
21 | -} sparse_storage_t; | |
18 | + lbaint_t (*write)(struct sparse_storage *info, | |
19 | + lbaint_t blk, | |
20 | + lbaint_t blkcnt, | |
21 | + const void *buffer); | |
22 | +}; | |
22 | 23 | |
23 | 24 | static inline int is_sparse_image(void *buf) |
24 | 25 | { |
... | ... | @@ -31,6 +32,6 @@ |
31 | 32 | return 0; |
32 | 33 | } |
33 | 34 | |
34 | -int store_sparse_image(sparse_storage_t *storage, void *storage_priv, | |
35 | - void *data); | |
35 | +void write_sparse_image(struct sparse_storage *info, const char *part_name, | |
36 | + void *data, unsigned sz, char *response_str); |