cleanup code which handles the Android sparse image format
[oweals/u-boot.git] / common / aboot.c
1 /*
2  * Copyright (c) 2009, Google Inc.
3  * All rights reserved.
4  *
5  * Copyright (c) 2009-2014, The Linux Foundation. All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are met:
9  *     * Redistributions of source code must retain the above copyright
10  *       notice, this list of conditions and the following disclaimer.
11  *     * Redistributions in binary form must reproduce the above copyright
12  *       notice, this list of conditions and the following disclaimer in the
13  *       documentation and/or other materials provided with the distribution.
14  *     * Neither the name of The Linux Foundation nor
15  *       the names of its contributors may be used to endorse or promote
16  *       products derived from this software without specific prior written
17  *       permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22  * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  *
31  * NOTE:
32  *   Although it is very similar, this license text is not identical
33  *   to the "BSD-3-Clause", therefore, DO NOT MODIFY THIS LICENSE TEXT!
34  */
35
36 void cmd_flash_mmc_sparse_img(const char *arg, void *data, unsigned sz)
37 {
38         unsigned int chunk;
39         unsigned int chunk_data_sz;
40         uint32_t *fill_buf = NULL;
41         uint32_t fill_val;
42         uint32_t chunk_blk_cnt = 0;
43         sparse_header_t *sparse_header;
44         chunk_header_t *chunk_header;
45         uint32_t total_blocks = 0;
46         unsigned long long ptn = 0;
47         unsigned long long size = 0;
48         int index = INVALID_PTN;
49         int i;
50         uint8_t lun = 0;
51
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         /* Read and skip over sparse image header */
69         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
75         data += sparse_header->file_hdr_sz;
76         if (sparse_header->file_hdr_sz > sizeof(sparse_header_t))
77         {
78                 /*
79                  * Skip the remaining bytes in a header that is longer than
80                  * we expected.
81                  */
82                 data += (sparse_header->file_hdr_sz - sizeof(sparse_header_t));
83         }
84
85         debug("=== Sparse Image Header ===\n");
86         debug("magic: 0x%x\n", sparse_header->magic);
87         debug("major_version: 0x%x\n", sparse_header->major_version);
88         debug("minor_version: 0x%x\n", sparse_header->minor_version);
89         debug("file_hdr_sz: %d\n", sparse_header->file_hdr_sz);
90         debug("chunk_hdr_sz: %d\n", sparse_header->chunk_hdr_sz);
91         debug("blk_sz: %d\n", sparse_header->blk_sz);
92         debug("total_blks: %d\n", sparse_header->total_blks);
93         debug("total_chunks: %d\n", sparse_header->total_chunks);
94
95         /* Start processing chunks */
96         for (chunk=0; chunk<sparse_header->total_chunks; chunk++)
97         {
98                 /* Read and skip over chunk header */
99                 chunk_header = (chunk_header_t *) data;
100                 data += sizeof(chunk_header_t);
101
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);
106
107                 if (sparse_header->chunk_hdr_sz > sizeof(chunk_header_t))
108                 {
109                         /*
110                          * Skip the remaining bytes in a header that is longer
111                          * than we expected.
112                          */
113                         data += (sparse_header->chunk_hdr_sz -
114                                  sizeof(chunk_header_t));
115                 }
116
117                 chunk_data_sz = sparse_header->blk_sz * chunk_header->chunk_sz;
118                 switch (chunk_header->chunk_type)
119                 {
120                         case CHUNK_TYPE_RAW:
121                         if (chunk_header->total_sz !=
122                             (sparse_header->chunk_hdr_sz + chunk_data_sz))
123                         {
124                                 fastboot_fail(
125                                         "Bogus chunk size for chunk type Raw");
126                                 return;
127                         }
128
129                         if (mmc_write(ptn +
130                                       ((uint64_t)total_blocks *
131                                                  sparse_header->blk_sz),
132                                       chunk_data_sz, (unsigned int *)data))
133                         {
134                                 fastboot_fail("flash write failure");
135                                 return;
136                         }
137                         total_blocks += chunk_header->chunk_sz;
138                         data += chunk_data_sz;
139                         break;
140
141                         case CHUNK_TYPE_FILL:
142                         if (chunk_header->total_sz !=
143                             (sparse_header->chunk_hdr_sz + sizeof(uint32_t)))
144                         {
145                                 fastboot_fail(
146                                         "Bogus chunk size for chunk type FILL");
147                                 return;
148                         }
149
150                         fill_buf = (uint32_t *)
151                                    memalign(CACHE_LINE,
152                                             ROUNDUP(sparse_header->blk_sz,
153                                                     CACHE_LINE));
154                         if (!fill_buf)
155                         {
156                                 fastboot_fail(
157                                         "Malloc failed for: CHUNK_TYPE_FILL");
158                                 return;
159                         }
160
161                         fill_val = *(uint32_t *)data;
162                         data = (char *) data + sizeof(uint32_t);
163                         chunk_blk_cnt = chunk_data_sz / sparse_header->blk_sz;
164
165                         for (i = 0; i < (sparse_header->blk_sz / sizeof(fill_val)); i++)
166                         {
167                                 fill_buf[i] = fill_val;
168                         }
169
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                                 {
177                                         fastboot_fail("flash write failure");
178                                         free(fill_buf);
179                                         return;
180                                 }
181
182                                 total_blocks++;
183                         }
184
185                         free(fill_buf);
186                         break;
187
188                         case CHUNK_TYPE_DONT_CARE:
189                         total_blocks += chunk_header->chunk_sz;
190                         break;
191
192                         case CHUNK_TYPE_CRC:
193                         if (chunk_header->total_sz !=
194                             sparse_header->chunk_hdr_sz)
195                         {
196                                 fastboot_fail(
197                                         "Bogus chunk size for chunk type Dont Care");
198                                 return;
199                         }
200                         total_blocks += chunk_header->chunk_sz;
201                         data += chunk_data_sz;
202                         break;
203
204                         default:
205                         debug("Unkown chunk type: %x\n",
206                               chunk_header->chunk_type);
207                         fastboot_fail("Unknown chunk type");
208                         return;
209                 }
210         }
211
212         debug("Wrote %d blocks, expected to write %d blocks\n",
213               total_blocks, sparse_header->total_blks);
214
215         if (total_blocks != sparse_header->total_blks)
216                 fastboot_fail("sparse image write failure");
217
218         fastboot_okay("");
219         return;
220 }