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