1 /* 2 * (C) Copyright 2022 Rockchip Electronics Co., Ltd 3 * 4 * SPDX-License-Identifier: GPL-2.0+ 5 */ 6 7 #include <common.h> 8 #include <blk.h> 9 #include <memalign.h> 10 #include <image-sparse.h> 11 #include <u-boot/sha256.h> 12 13 /******************************************************************************/ 14 #define PER_BLK_WRITE_SIZE SZ_8M /* Avoid -ENOMEM, eg: bounce buffer */ 15 #define DEBUG_SPARSE 16 17 /******************************************************************************/ 18 static void print_header_info(sparse_header_t *header) 19 { 20 #ifdef DEBUG_SPARSE 21 printf(" ==== sparse header ===\n"); 22 printf(" magic: 0x%x\n", header->magic); 23 printf(" major_version: 0x%x\n", header->major_version); 24 printf(" minor_version: 0x%x\n", header->minor_version); 25 printf(" file_hdr_sz: %d\n", header->file_hdr_sz); 26 printf(" chunk_hdr_sz: %d\n", header->chunk_hdr_sz); 27 printf(" blk_sz: %d\n", header->blk_sz); 28 printf(" total_blks: %d\n", header->total_blks); 29 printf(" total_chunks: %d\n", header->total_chunks); 30 printf(" image_checksum: %d\n\n", header->image_checksum); 31 #endif 32 } 33 34 static void print_chunk_info(chunk_header_t *chunk, u32 id, 35 const u8 *ptr, sparse_header_t *header) 36 { 37 #ifdef DEBUG_SPARSE 38 const char *type; 39 40 if (chunk->chunk_type == CHUNK_TYPE_RAW) 41 type = "RAW"; 42 else if (chunk->chunk_type == CHUNK_TYPE_DONT_CARE) 43 type = "DONT CARE"; 44 else if (chunk->chunk_type == CHUNK_TYPE_FILL) 45 type = "FILL"; 46 else if (chunk->chunk_type == CHUNK_TYPE_CRC32) 47 type = "CRC32"; 48 else 49 type = "UNK"; 50 51 printf(" === [chunk.%d]\n", id + 1); 52 printf(" chunk_type: %s\n", type); 53 printf(" chunk_sz: %d\n", chunk->chunk_sz); 54 printf(" total_sz: %d\n", chunk->total_sz); 55 printf(" offset: %ld\n", (ulong)ptr - (ulong)header); 56 printf(" buf: 0x%08lx\n", (ulong)ptr); 57 #endif 58 } 59 60 static int flash_write_data(struct blk_desc *desc, const u8 *data, 61 ulong offset, ulong blocks) 62 { const u8 *buf = data; 63 u32 step = BLOCK_CNT(PER_BLK_WRITE_SIZE, desc); 64 long left = blocks; /* signed long ! */ 65 ulong lba = offset; 66 ulong blks; 67 68 #ifdef DEBUG_SPARSE 69 printf(" lba: 0x%08lx - 0x%08lx\n", lba, lba + blocks); 70 #ifdef CONFIG_SHA256 71 u8 hash[32]; 72 int i; 73 74 sha256_csum(data, blocks * desc->blksz, hash); 75 printf(" sha256sum: "); 76 for (i = 0; i < ARRAY_SIZE(hash); i++) 77 printf("%02x", hash[i]); 78 printf("\n"); 79 #endif 80 #endif 81 while (left > 0) { 82 if (left < step) 83 blks = left; 84 else 85 blks = step; 86 87 if (blks != blk_dwrite(desc, lba, blks, buf)) { 88 printf("Raw data: LBA 0x%lx written error.\n", lba); 89 return -EIO; 90 } 91 buf += blks * desc->blksz; 92 lba += blks; 93 left -= step; 94 } 95 96 return 0; 97 } 98 99 static int flash_fill_data(struct blk_desc *desc, ulong offset, ulong blocks, 100 u32 fill_val) 101 { 102 u32 step = BLOCK_CNT(PER_BLK_WRITE_SIZE, desc); 103 long left = blocks; /* signed long ! */ 104 ulong lba = offset; 105 ulong blks; 106 char *buf; 107 108 buf = malloc(PER_BLK_WRITE_SIZE); 109 if (!buf) { 110 printf("No memory\n"); 111 return -ENOMEM; 112 } 113 #ifdef DEBUG_SPARSE 114 printf(" lba: 0x%08lx - 0x%08lx\n", lba, lba + blocks); 115 printf(" fill: 0x%08x\n", fill_val); 116 #endif 117 memset((char *)buf, fill_val, PER_BLK_WRITE_SIZE); 118 while (left > 0) { 119 if (left < step) 120 blks = left; 121 else 122 blks = step; 123 124 if (blks != blk_dwrite(desc, lba, blks, buf)) { 125 printf("Fill data: LBA 0x%lx write error.\n", lba); 126 free(buf); 127 return -EIO; 128 } 129 lba += blks; 130 left -= step; 131 } 132 free(buf); 133 134 return 0; 135 } 136 137 /******************************************************************************/ 138 int ext4_unsparse(struct blk_desc *desc, const u8 *buf, ulong start) 139 { 140 sparse_header_t *header = (sparse_header_t *)buf; 141 chunk_header_t *chunk = NULL; 142 ulong blk = start; 143 ulong chunk_len; 144 u64 img_size; 145 u32 i, fill; 146 147 putc('\n'); 148 149 if (!is_sparse_image(header)) { 150 printf("Invalid sparse format.\n"); 151 return -EINVAL; 152 } 153 154 print_header_info(header); 155 156 /* check fs img's real size is larger than partition size */ 157 img_size = (u64)(header->total_blks * header->blk_sz); 158 159 /* erase area: ensure DONT-CARE is 0 and FILL(0x0) is 0 */ 160 if (blk_derase(desc, start, BLOCK_CNT(img_size, desc)) != 161 BLOCK_CNT(img_size, desc)) 162 return -EIO; 163 164 printf("Erase 0x%08lx - 0x%08lx blocks OK.\n\n", 165 start, start + (ulong)BLOCK_CNT(img_size, desc)); 166 167 /* skip the sparse header,to visit first chunk */ 168 buf += header->file_hdr_sz; 169 170 /* to visit each chunk */ 171 for (i = 0; i < header->total_chunks; i++) { 172 /* here the chunk_header */ 173 chunk = (chunk_header_t *)buf; 174 175 /* go to next chunk's data */ 176 buf += header->chunk_hdr_sz; 177 178 switch (chunk->chunk_type) { 179 case CHUNK_TYPE_RAW: 180 print_chunk_info(chunk, i, buf, header); 181 182 /* to calculate the length of each chunk */ 183 chunk_len = chunk->chunk_sz * header->blk_sz; 184 185 /* verify every chunk to asure it is valid */ 186 if (chunk->total_sz 187 != (chunk_len + header->chunk_hdr_sz)) { 188 printf("No.%d chunk size error.\n", i + 1); 189 return -EINVAL; 190 } 191 192 if (flash_write_data(desc, buf, 193 blk, BLOCK_CNT(chunk_len, desc))) 194 return -EIO; 195 196 buf += chunk_len; 197 blk += BLOCK_CNT(chunk_len, desc); 198 break; 199 case CHUNK_TYPE_DONT_CARE: 200 print_chunk_info(chunk, i, buf, header); 201 202 if (chunk->total_sz != header->chunk_hdr_sz) { 203 printf("No.%d chunk size error.\n", i + 1); 204 return -EINVAL; 205 } 206 207 chunk_len = chunk->chunk_sz * header->blk_sz; 208 blk += BLOCK_CNT(chunk_len, desc); 209 break; 210 case CHUNK_TYPE_FILL: 211 print_chunk_info(chunk, i, buf, header); 212 213 /* verify every chunk to asure it is valid */ 214 if (chunk->total_sz - header->chunk_hdr_sz != 4) { 215 printf("No.%d chunk size error.\n", i); 216 return -EINVAL; 217 } 218 219 /* to calculate the length of each chunk */ 220 chunk_len = chunk->chunk_sz * header->blk_sz; 221 222 /* ignore fill value "0", as we have erased yet */ 223 fill = *(u32 *)buf; 224 if (fill != 0) { 225 if (flash_fill_data(desc, blk, 226 BLOCK_CNT(chunk_len, desc), fill)) 227 return -EIO; 228 } 229 buf += 4; 230 blk += BLOCK_CNT(chunk_len, desc); 231 break; 232 case CHUNK_TYPE_CRC32: 233 print_chunk_info(chunk, i, buf, header); 234 printf("No.%d chunk type CRC32, Cannot handle!\n", i + 1); 235 return -ENOTSUPP; 236 default: 237 printf("sparse: unknown chunk type %04x.\n", chunk->chunk_type); 238 return -ENOTSUPP; 239 } 240 } 241 242 printf("\nUnsparsed is %lld MiB and 0x%08lx - 0x%08lx blocks written OK.\n", 243 img_size >> 20, start, blk); 244 245 return 0; 246 } 247 248