Commit e6ca1ad604419619e2e6ba16a6e43cf15ff07fb1
Committed by
Tom Rini
1 parent
1c39d856db
Exists in
v2017.01-smarct4x
and in
37 other branches
implement the Android sparse image format
update to provide usable implementation to U-Boot Signed-off-by: Steve Rae <srae@broadcom.com>
Showing 3 changed files with 111 additions and 53 deletions Side-by-side Diff
common/aboot.c
... | ... | @@ -3,6 +3,7 @@ |
3 | 3 | * All rights reserved. |
4 | 4 | * |
5 | 5 | * Copyright (c) 2009-2014, The Linux Foundation. All rights reserved. |
6 | + * Portions Copyright 2014 Broadcom Corporation. | |
6 | 7 | * |
7 | 8 | * Redistribution and use in source and binary forms, with or without |
8 | 9 | * modification, are permitted provided that the following conditions are met: |
9 | 10 | |
10 | 11 | |
11 | 12 | |
12 | 13 | |
13 | 14 | |
14 | 15 | |
... | ... | @@ -33,44 +34,32 @@ |
33 | 34 | * to the "BSD-3-Clause", therefore, DO NOT MODIFY THIS LICENSE TEXT! |
34 | 35 | */ |
35 | 36 | |
36 | -void cmd_flash_mmc_sparse_img(const char *arg, void *data, unsigned sz) | |
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 | + | |
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) | |
37 | 47 | { |
48 | + lbaint_t blk; | |
49 | + lbaint_t blkcnt; | |
50 | + lbaint_t blks; | |
51 | + uint32_t bytes_written = 0; | |
38 | 52 | unsigned int chunk; |
39 | 53 | unsigned int chunk_data_sz; |
40 | 54 | uint32_t *fill_buf = NULL; |
41 | 55 | uint32_t fill_val; |
42 | - uint32_t chunk_blk_cnt = 0; | |
43 | 56 | sparse_header_t *sparse_header; |
44 | 57 | chunk_header_t *chunk_header; |
45 | 58 | uint32_t total_blocks = 0; |
46 | - unsigned long long ptn = 0; | |
47 | - unsigned long long size = 0; | |
48 | - int index = INVALID_PTN; | |
49 | 59 | int i; |
50 | - uint8_t lun = 0; | |
51 | 60 | |
52 | - index = partition_get_index(arg); | |
53 | - ptn = partition_get_offset(index); | |
54 | - if(ptn == 0) { | |
55 | - fastboot_fail("partition table doesn't exist"); | |
56 | - return; | |
57 | - } | |
58 | - | |
59 | - size = partition_get_size(index); | |
60 | - if (ROUND_TO_PAGE(sz,511) > size) { | |
61 | - fastboot_fail("size too large"); | |
62 | - return; | |
63 | - } | |
64 | - | |
65 | - lun = partition_get_lun(index); | |
66 | - mmc_set_lun(lun); | |
67 | - | |
68 | 61 | /* Read and skip over sparse image header */ |
69 | 62 | sparse_header = (sparse_header_t *) data; |
70 | - if ((sparse_header->total_blks * sparse_header->blk_sz) > size) { | |
71 | - fastboot_fail("size too large"); | |
72 | - return; | |
73 | - } | |
74 | 63 | |
75 | 64 | data += sparse_header->file_hdr_sz; |
76 | 65 | if (sparse_header->file_hdr_sz > sizeof(sparse_header_t)) |
77 | 66 | |
78 | 67 | |
... | ... | @@ -92,17 +81,31 @@ |
92 | 81 | debug("total_blks: %d\n", sparse_header->total_blks); |
93 | 82 | debug("total_chunks: %d\n", sparse_header->total_chunks); |
94 | 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 | 95 | /* Start processing chunks */ |
96 | + blk = info->start; | |
96 | 97 | for (chunk=0; chunk<sparse_header->total_chunks; chunk++) |
97 | 98 | { |
98 | 99 | /* Read and skip over chunk header */ |
99 | 100 | chunk_header = (chunk_header_t *) data; |
100 | 101 | data += sizeof(chunk_header_t); |
101 | 102 | |
102 | - debug("=== Chunk Header ===\n"); | |
103 | - debug("chunk_type: 0x%x\n", chunk_header->chunk_type); | |
104 | - debug("chunk_data_sz: 0x%x\n", chunk_header->chunk_sz); | |
105 | - debug("total_size: 0x%x\n", chunk_header->total_sz); | |
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 | + } | |
106 | 109 | |
107 | 110 | if (sparse_header->chunk_hdr_sz > sizeof(chunk_header_t)) |
108 | 111 | { |
... | ... | @@ -115,6 +118,7 @@ |
115 | 118 | } |
116 | 119 | |
117 | 120 | chunk_data_sz = sparse_header->blk_sz * chunk_header->chunk_sz; |
121 | + blkcnt = chunk_data_sz / info->blksz; | |
118 | 122 | switch (chunk_header->chunk_type) |
119 | 123 | { |
120 | 124 | case CHUNK_TYPE_RAW: |
121 | 125 | |
... | ... | @@ -126,14 +130,25 @@ |
126 | 130 | return; |
127 | 131 | } |
128 | 132 | |
129 | - if (mmc_write(ptn + | |
130 | - ((uint64_t)total_blocks * | |
131 | - sparse_header->blk_sz), | |
132 | - chunk_data_sz, (unsigned int *)data)) | |
133 | - { | |
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); | |
134 | 147 | fastboot_fail("flash write failure"); |
135 | 148 | return; |
136 | 149 | } |
150 | + blk += blkcnt; | |
151 | + bytes_written += blkcnt * info->blksz; | |
137 | 152 | total_blocks += chunk_header->chunk_sz; |
138 | 153 | data += chunk_data_sz; |
139 | 154 | break; |
... | ... | @@ -148,9 +163,9 @@ |
148 | 163 | } |
149 | 164 | |
150 | 165 | fill_buf = (uint32_t *) |
151 | - memalign(CACHE_LINE, | |
152 | - ROUNDUP(sparse_header->blk_sz, | |
153 | - CACHE_LINE)); | |
166 | + memalign(ARCH_DMA_MINALIGN, | |
167 | + ROUNDUP(info->blksz, | |
168 | + ARCH_DMA_MINALIGN)); | |
154 | 169 | if (!fill_buf) |
155 | 170 | { |
156 | 171 | fastboot_fail( |
157 | 172 | |
158 | 173 | |
159 | 174 | |
160 | 175 | |
161 | 176 | |
... | ... | @@ -160,27 +175,34 @@ |
160 | 175 | |
161 | 176 | fill_val = *(uint32_t *)data; |
162 | 177 | data = (char *) data + sizeof(uint32_t); |
163 | - chunk_blk_cnt = chunk_data_sz / sparse_header->blk_sz; | |
164 | 178 | |
165 | - for (i = 0; i < (sparse_header->blk_sz / sizeof(fill_val)); i++) | |
166 | - { | |
179 | + for (i = 0; i < (info->blksz / sizeof(fill_val)); i++) | |
167 | 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; | |
168 | 189 | } |
169 | 190 | |
170 | - for (i = 0; i < chunk_blk_cnt; i++) | |
171 | - { | |
172 | - if (mmc_write(ptn + | |
173 | - ((uint64_t)total_blocks * | |
174 | - sparse_header->blk_sz), | |
175 | - sparse_header->blk_sz, fill_buf)) | |
176 | - { | |
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); | |
177 | 198 | fastboot_fail("flash write failure"); |
178 | 199 | free(fill_buf); |
179 | 200 | return; |
180 | 201 | } |
181 | - | |
182 | - total_blocks++; | |
202 | + blk++; | |
183 | 203 | } |
204 | + bytes_written += blkcnt * info->blksz; | |
205 | + total_blocks += chunk_data_sz / sparse_header->blk_sz; | |
184 | 206 | |
185 | 207 | free(fill_buf); |
186 | 208 | break; |
... | ... | @@ -189,7 +211,7 @@ |
189 | 211 | total_blocks += chunk_header->chunk_sz; |
190 | 212 | break; |
191 | 213 | |
192 | - case CHUNK_TYPE_CRC: | |
214 | + case CHUNK_TYPE_CRC32: | |
193 | 215 | if (chunk_header->total_sz != |
194 | 216 | sparse_header->chunk_hdr_sz) |
195 | 217 | { |
... | ... | @@ -202,8 +224,8 @@ |
202 | 224 | break; |
203 | 225 | |
204 | 226 | default: |
205 | - debug("Unkown chunk type: %x\n", | |
206 | - chunk_header->chunk_type); | |
227 | + printf("%s: Unknown chunk type: %x\n", __func__, | |
228 | + chunk_header->chunk_type); | |
207 | 229 | fastboot_fail("Unknown chunk type"); |
208 | 230 | return; |
209 | 231 | } |
... | ... | @@ -211,6 +233,7 @@ |
211 | 233 | |
212 | 234 | debug("Wrote %d blocks, expected to write %d blocks\n", |
213 | 235 | total_blocks, sparse_header->total_blks); |
236 | + printf("........ wrote %u bytes to '%s'\n", bytes_written, part_name); | |
214 | 237 | |
215 | 238 | if (total_blocks != sparse_header->total_blks) |
216 | 239 | fastboot_fail("sparse image write failure"); |
include/aboot.h
1 | +/* | |
2 | + * Copyright 2014 Broadcom Corporation. | |
3 | + * | |
4 | + * SPDX-License-Identifier: GPL-2.0+ | |
5 | + */ | |
6 | + | |
7 | +#include <part.h> | |
8 | +#include <sparse_format.h> | |
9 | + | |
10 | +#define ROUNDUP(x, y) (((x) + ((y) - 1)) & ~((y) - 1)) | |
11 | + | |
12 | +void fastboot_fail(const char *s); | |
13 | +void fastboot_okay(const char *s); | |
14 | + | |
15 | +static inline int is_sparse_image(void *buf) | |
16 | +{ | |
17 | + sparse_header_t *s_header = (sparse_header_t *)buf; | |
18 | + | |
19 | + if ((le32_to_cpu(s_header->magic) == SPARSE_HEADER_MAGIC) && | |
20 | + (le16_to_cpu(s_header->major_version) == 1)) | |
21 | + return 1; | |
22 | + | |
23 | + return 0; | |
24 | +} | |
25 | + | |
26 | +void write_sparse_image(block_dev_desc_t *dev_desc, | |
27 | + disk_partition_t *info, const char *part_name, | |
28 | + void *data, unsigned sz); |
include/sparse_defs.h