avr32: use dlmalloc for DMA buffers
[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  * 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
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 }