├── Makefile ├── README.md ├── dtbSplit.cpp └── dtbTool.c /Makefile: -------------------------------------------------------------------------------- 1 | all: dtbTool dtbSplit 2 | 3 | dtbTool: dtbTool.c 4 | $(CC) -o dtbTool dtbTool.c 5 | 6 | dtbSplit: dtbSplit.cpp 7 | $(CXX) -o dtbSplit -std=c++11 dtbSplit.cpp 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | AML DTB Tools 2 | ==== 3 | 4 | Comprises of a splitter and builder of AmLogic's multi-dtb formats. 5 | 6 | The format is deduced from the [AmLogic u-boot code](https://github.com/codesnake/uboot-amlogic/blob/master/common/aml_dt.c) 7 | 8 | The dtbTool is based on dtbTool source from the CyanogenMod project. 9 | -------------------------------------------------------------------------------- /dtbSplit.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Wilhansen Li. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are 6 | * met: 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following 11 | disclaimer in the documentation and/or other materials provided 12 | with the distribution. 13 | * Neither the name of Wilhansen Li nor the names of its 14 | contributors may be used to endorse or promote products derived 15 | from this software without specific prior written permission. 16 | * 17 | * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED 18 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 19 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT 20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 21 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 24 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 25 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 26 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 27 | * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | #include 39 | 40 | using namespace std; 41 | 42 | #define AML_DT_HEADER 0x5f4c4d41 43 | #define DT_HEADER_MAGIC 0xedfe0dd0 44 | #define AML_DT_ID_VARI_TOTAL 3 45 | 46 | #pragma pack(push, 1) 47 | struct DTHeader { 48 | uint32_t magic; /* magic word of OF_DT_HEADER */ 49 | uint32_t totalsize; /* total size of DT block */ 50 | }; 51 | struct Header { 52 | uint32_t magic; 53 | uint32_t version; 54 | uint32_t entry_count; 55 | }; 56 | 57 | template 58 | struct HeaderEntry { 59 | char soc[ID_SIZE]; 60 | char plat[ID_SIZE]; 61 | char vari[ID_SIZE]; 62 | uint32_t offset; 63 | char padding[4]; 64 | }; 65 | #pragma pack(pop) 66 | 67 | typedef HeaderEntry<4> HeaderEntryV1; 68 | typedef HeaderEntry<16> HeaderEntryV2; 69 | 70 | void trimSpace(char *b, const int len) { 71 | int len2 = len; 72 | while (len2 > 0 && isspace(b[len2 - 1])) { 73 | len2--; 74 | } 75 | if (len2 < len && len2 > 0) { 76 | b[len2] = 0; 77 | b[len - 1] = 0; 78 | } 79 | } 80 | uint32_t swap_bytes_u32(uint32_t b) { 81 | return ((b & 0xFF000000) >> 24) | 82 | ((b & 0x00FF0000) >> 8) | 83 | ((b & 0x0000FF00) << 8) | 84 | (b << 24); 85 | } 86 | template 87 | void dumpData(const uint32_t entries, const string &dest, ifstream &dtb) { 88 | typedef HeaderEntry HeaderType; 89 | 90 | vector headers; 91 | for ( uint32_t i = 0; i < entries; ++i ) { 92 | HeaderType h; 93 | dtb.read((char*)&h, sizeof(h)); 94 | 95 | headers.push_back(h); 96 | } 97 | for ( uint32_t i = 0; i < headers.size(); ++i ) { 98 | auto &h = headers[i]; 99 | ostringstream id; 100 | 101 | auto u32soc = reinterpret_cast(h.soc); 102 | auto u32plat = reinterpret_cast(h.plat); 103 | auto u32vari = reinterpret_cast(h.vari); 104 | for ( uint32_t j = 0; j < ID_SIZE/sizeof(uint32_t); ++j ) { 105 | *(u32soc + j) = swap_bytes_u32(*(u32soc + j)); 106 | *(u32plat + j) = swap_bytes_u32(*(u32plat + j)); 107 | *(u32vari + j) = swap_bytes_u32(*(u32vari + j)); 108 | } 109 | trimSpace(h.soc, ID_SIZE); 110 | trimSpace(h.plat, ID_SIZE); 111 | trimSpace(h.vari, ID_SIZE); 112 | 113 | if ( h.soc[ID_SIZE-1] == 0 ) { 114 | id << h.soc; 115 | } else { 116 | id.write(h.soc, sizeof(h.soc)); 117 | } 118 | id << '-'; 119 | if ( h.plat[ID_SIZE-1] == 0 ) { 120 | id << h.plat; 121 | } else { 122 | id.write(h.plat, sizeof(h.plat)); 123 | } 124 | id << '-'; 125 | if ( h.vari[ID_SIZE-1] == 0 ) { 126 | id << h.vari; 127 | } else { 128 | id.write(h.vari, sizeof(h.vari)); 129 | } 130 | cout << "Found header: " << id.str() << '\n'; 131 | 132 | dtb.seekg(h.offset); 133 | DTHeader dtheader; 134 | dtb.read((char*)&dtheader, sizeof(dtheader)); 135 | if ( dtheader.magic != DT_HEADER_MAGIC ) { 136 | cout.setf(ios::hex); 137 | cout << "\tDTB Header mismatch. Found: " << dtheader.magic; 138 | continue; 139 | } 140 | dtheader.totalsize = ntohl(dtheader.totalsize); 141 | cout.setf(ios::dec); 142 | cout << "\t offset: " << h.offset << " size: " << dtheader.totalsize << '\n'; 143 | dtb.seekg(h.offset); 144 | vector data(dtheader.totalsize); 145 | dtb.read(data.data(), data.size()); 146 | ofstream output(dest + id.str() + ".dtb", ios::binary); 147 | output.write(data.data(), data.size()); 148 | } 149 | } 150 | 151 | int main(int argc, char **argv) { 152 | if ( argc < 3 ) { 153 | cerr << "Usage: " << argv[0] << " boot.img out_prefix\n"; 154 | return 1; 155 | } 156 | 157 | ifstream dtb(argv[1], ios::binary); 158 | if ( !dtb ) { 159 | cerr << "Unable to open dtb file: " << argv[2] << endl; 160 | return 1; 161 | } 162 | string dest; 163 | if ( argc > 2 ) { 164 | dest = argv[2]; 165 | } 166 | Header header; 167 | dtb.read((char*)&header, sizeof(header)); 168 | 169 | if ( header.magic != AML_DT_HEADER ) { 170 | cerr << "Invalid AML DTB header." << endl; 171 | return 1; 172 | } 173 | cout << "DTB Version: " << header.version << " entries: " << header.entry_count << endl; 174 | 175 | if(header.version == 1) { 176 | dumpData<4>(header.entry_count, dest, dtb); 177 | } else if(header.version == 2) { 178 | dumpData<16>(header.entry_count, dest, dtb); 179 | } else { 180 | cerr << "Unrecognized DTB version" << endl; 181 | return 1; 182 | } 183 | 184 | return 0; 185 | } -------------------------------------------------------------------------------- /dtbTool.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012, Code Aurora Forum. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are 6 | * met: 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following 11 | disclaimer in the documentation and/or other materials provided 12 | with the distribution. 13 | * Neither the name of Code Aurora Forum, Inc. nor the names of its 14 | contributors may be used to endorse or promote products derived 15 | from this software without specific prior written permission. 16 | * 17 | * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED 18 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 19 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT 20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 21 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 24 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 25 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 26 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 27 | * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #define _GNU_SOURCE 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | 43 | #define AML_DT_MAGIC "AML_" /* Master DTB magic */ 44 | #define AML_DT_VERSION 2 /* AML version */ 45 | 46 | #define DT_ID_TAG "amlogic-dt-id" 47 | 48 | #define PAGE_SIZE_DEF 2048 49 | #define PAGE_SIZE_MAX (1024*1024) 50 | 51 | #define log_err(x...) printf(x) 52 | #define log_info(x...) printf(x) 53 | #define log_dbg(x...) { if (verbose) printf(x); } 54 | 55 | #define COPY_BLK 1024 /* File copy block size */ 56 | 57 | #define RC_SUCCESS 0 58 | #define RC_ERROR -1 59 | 60 | #define INFO_ENTRY_SIZE 16 61 | #define INFO_ENTRY_SIZE_S "16" 62 | #define TABLE_ENTRY_HEADER_SIZE (INFO_ENTRY_SIZE * 3 + sizeof(uint32_t) * 2) 63 | 64 | struct chipInfo_t { 65 | uint8_t chipset[INFO_ENTRY_SIZE]; 66 | uint8_t platform[INFO_ENTRY_SIZE]; 67 | uint8_t revNum[INFO_ENTRY_SIZE]; 68 | uint32_t dtb_size; 69 | char *dtb_file; 70 | struct chipInfo_t *prev; 71 | struct chipInfo_t *next; 72 | }; 73 | 74 | struct chipInfo_t *chip_list; 75 | 76 | char *input_dir; 77 | char *output_file; 78 | char *dtc_path; 79 | int verbose; 80 | int page_size = PAGE_SIZE_DEF; 81 | 82 | int entry_cmp(uint8_t *a, uint8_t *b) 83 | { 84 | return memcmp(a, b, INFO_ENTRY_SIZE); 85 | } 86 | 87 | uint32_t swap_bytes_u32(uint32_t b) 88 | { 89 | return ((b & 0xFF000000) >> 24) | 90 | ((b & 0x00FF0000) >> 8) | 91 | ((b & 0x0000FF00) << 8) | 92 | (b << 24); 93 | } 94 | void padSpaces(uint8_t *s, int sz) 95 | { 96 | --sz; 97 | while ( sz >= 0 && s[sz] == 0 ) 98 | { 99 | s[sz] = 0x20; 100 | --sz; 101 | } 102 | } 103 | 104 | void print_help() 105 | { 106 | log_info("dtbTool [options] -o \n"); 107 | log_info(" options:\n"); 108 | log_info(" --output-file/-o output file\n"); 109 | log_info(" --dtc-path/-p path to dtc\n"); 110 | log_info(" --page-size/-s page size in bytes\n"); 111 | log_info(" --verbose/-v verbose\n"); 112 | log_info(" --help/-h this help screen\n"); 113 | } 114 | 115 | int parse_commandline(int argc, char *const argv[]) 116 | { 117 | int c; 118 | 119 | struct option long_options[] = { 120 | {"output-file", 1, 0, 'o'}, 121 | {"dtc-path", 1, 0, 'p'}, 122 | {"page-size", 1, 0, 's'}, 123 | {"verbose", 0, 0, 'v'}, 124 | {"help", 0, 0, 'h'}, 125 | {0, 0, 0, 0} 126 | }; 127 | 128 | while ((c = getopt_long(argc, argv, "-o:p:s:vh", long_options, NULL)) 129 | != -1) { 130 | switch (c) { 131 | case 1: 132 | if (!input_dir) { 133 | input_dir = optarg; 134 | { 135 | int len = strlen(input_dir); 136 | if ( len > 1 && input_dir[len - 1] != '/' ) { 137 | input_dir = malloc(len + 2); 138 | strcpy(input_dir, optarg); 139 | input_dir[len] = '/'; 140 | input_dir[len + 1] = 0; 141 | } 142 | } 143 | } 144 | break; 145 | case 'o': 146 | output_file = optarg; 147 | break; 148 | case 'p': 149 | dtc_path = optarg; 150 | break; 151 | case 's': 152 | page_size = atoi(optarg); 153 | if ((page_size <= 0) || (page_size > (PAGE_SIZE_MAX))) { 154 | log_err("Invalid page size (> 0 and <=1MB\n"); 155 | return RC_ERROR; 156 | } 157 | break; 158 | case 'v': 159 | verbose = 1; 160 | break; 161 | case 'h': 162 | default: 163 | return RC_ERROR; 164 | } 165 | } 166 | 167 | if (!output_file) { 168 | log_err("Output file must be specified\n"); 169 | return RC_ERROR; 170 | } 171 | 172 | if (!input_dir) 173 | input_dir = "./"; 174 | 175 | if (!dtc_path) 176 | dtc_path = ""; 177 | 178 | return RC_SUCCESS; 179 | } 180 | 181 | /* Unique entry sorted list add (by chipset->platform->rev) */ 182 | int chip_add(struct chipInfo_t *c) 183 | { 184 | struct chipInfo_t *x = chip_list; 185 | 186 | if (!chip_list) { 187 | chip_list = c; 188 | c->next = NULL; 189 | c->prev = NULL; 190 | return RC_SUCCESS; 191 | } 192 | 193 | while (1) { 194 | if (entry_cmp(c->chipset, x->chipset) < 0 || 195 | (entry_cmp(c->chipset, x->chipset) == 0 && 196 | (entry_cmp(c->platform, x->platform) < 0 || 197 | (entry_cmp(c->platform, x->platform) == 0 && 198 | entry_cmp(c->revNum, x->revNum) < 0)))) { 199 | if (!x->prev) { 200 | c->next = chip_list; 201 | c->prev = NULL; 202 | chip_list = c; 203 | break; 204 | } else { 205 | c->next = x; 206 | c->prev = x->prev; 207 | x->prev->next = c; 208 | x->prev = c; 209 | break; 210 | } 211 | } 212 | if (entry_cmp(c->chipset, x->chipset) == 0 && 213 | entry_cmp(c->platform, x->platform) == 0 && 214 | entry_cmp(c->revNum, x->revNum) == 0) { 215 | return RC_ERROR; /* duplicate */ 216 | } 217 | if (!x->next) { 218 | c->prev = x; 219 | c->next = NULL; 220 | x->next = c; 221 | break; 222 | } 223 | x = x->next; 224 | } 225 | return RC_SUCCESS; 226 | } 227 | 228 | void chip_deleteall() 229 | { 230 | struct chipInfo_t *c = chip_list, *t; 231 | 232 | while (c) { 233 | t = c; 234 | c = c->next; 235 | free(t->dtb_file); 236 | free(t); 237 | } 238 | } 239 | 240 | /* Extract 'qcom,msm-id' parameter triplet from DTB 241 | qcom,msm-id = ; 242 | */ 243 | struct chipInfo_t *getChipInfo(const char *filename) 244 | { 245 | const char str1[] = "dtc -I dtb -O dts \""; 246 | const char str2[] = "\" 2>&1"; 247 | char *buf, *pos; 248 | char *line = NULL; 249 | size_t line_size; 250 | FILE *pfile; 251 | int llen; 252 | struct chipInfo_t *chip = NULL; 253 | int rc = 0; 254 | uint8_t data[3][INFO_ENTRY_SIZE + 1] = { {0} }; 255 | 256 | line_size = 1024; 257 | line = (char *)malloc(line_size); 258 | if (!line) { 259 | log_err("Out of memory\n"); 260 | return NULL; 261 | } 262 | 263 | llen = sizeof(char) * (strlen(dtc_path) + 264 | strlen(str1) + 265 | strlen(str2) + 266 | strlen(filename) + 1); 267 | buf = (char *)malloc(llen); 268 | if (!buf) { 269 | log_err("Out of memory\n"); 270 | free(line); 271 | return NULL; 272 | } 273 | 274 | strncpy(buf, dtc_path, llen); 275 | strncat(buf, str1, llen); 276 | strncat(buf, filename, llen); 277 | strncat(buf, str2, llen); 278 | 279 | pfile = popen(buf, "r"); 280 | free(buf); 281 | 282 | if (pfile == NULL) { 283 | log_err("... skip, fail to decompile dtb\n"); 284 | } else { 285 | /* Find "dtb file entry" */ 286 | while ((llen = getline(&line, &line_size, pfile)) != -1) { 287 | if ((pos = strstr(line, DT_ID_TAG)) != NULL) { 288 | pos += strlen(DT_ID_TAG); 289 | 290 | for (; *pos; pos++) { 291 | if (*pos == '"') { 292 | /* Start convertion of triplet */ 293 | pos++; 294 | rc = sscanf(pos, "%" INFO_ENTRY_SIZE_S "[^_]_%" INFO_ENTRY_SIZE_S "[^_]_%" INFO_ENTRY_SIZE_S "[^_\"]\"", 295 | data[0], data[1], data[2]); 296 | if (rc == 3) { 297 | chip = (struct chipInfo_t *) 298 | malloc(sizeof(struct chipInfo_t)); 299 | if (!chip) { 300 | log_err("Out of memory\n"); 301 | break; 302 | } 303 | memcpy(chip->chipset, data[0], INFO_ENTRY_SIZE); 304 | memcpy(chip->platform, data[1], INFO_ENTRY_SIZE); 305 | memcpy(chip->revNum, data[2], INFO_ENTRY_SIZE); 306 | chip->dtb_size = 0; 307 | chip->dtb_file = NULL; 308 | 309 | free(line); 310 | pclose(pfile); 311 | return chip; 312 | } else { 313 | break; 314 | } 315 | } 316 | } 317 | log_err("... skip, incorrect '%s' format\n", DT_ID_TAG); 318 | break; 319 | } 320 | } 321 | if (line) 322 | free(line); 323 | pclose(pfile); 324 | } 325 | 326 | return NULL; 327 | } 328 | 329 | int main(int argc, char **argv) 330 | { 331 | char buf[COPY_BLK]; 332 | struct chipInfo_t *chip; 333 | struct dirent *dp; 334 | FILE *pInputFile; 335 | char *filename; 336 | int padding; 337 | uint8_t *filler = NULL; 338 | int numBytesRead = 0; 339 | int totBytesRead = 0; 340 | int out_fd; 341 | int flen; 342 | int rc = RC_SUCCESS; 343 | int dtb_count = 0, dtb_offset = 0; 344 | size_t wrote = 0, expected = 0; 345 | struct stat st; 346 | uint32_t version = AML_DT_VERSION; 347 | 348 | log_info("DTB combiner:\n"); 349 | 350 | if (parse_commandline(argc, argv) != RC_SUCCESS) { 351 | print_help(); 352 | return RC_ERROR; 353 | } 354 | 355 | log_info(" Input directory: '%s'\n", input_dir); 356 | log_info(" Output file: '%s'\n", output_file); 357 | 358 | DIR *dir = opendir(input_dir); 359 | if (!dir) { 360 | log_err("Failed to open input directory '%s'\n", input_dir); 361 | return RC_ERROR; 362 | } 363 | 364 | filler = (uint8_t *)malloc(page_size); 365 | if (!filler) { 366 | log_err("Out of memory\n"); 367 | closedir(dir); 368 | return RC_ERROR; 369 | } 370 | memset(filler, 0, page_size); 371 | 372 | /* Open the .dtb files in the specified path, decompile and 373 | extract "amlogic-dt-id" parameter 374 | */ 375 | while ((dp = readdir(dir)) != NULL) { 376 | if ((dp->d_type == DT_REG)) { 377 | flen = strlen(dp->d_name); 378 | if ((flen > 4) && 379 | (strncmp(&dp->d_name[flen-4], ".dtb", 4) == 0)) { 380 | log_info("Found file: %s ... ", dp->d_name); 381 | 382 | flen = strlen(input_dir) + strlen(dp->d_name) + 1; 383 | filename = (char *)malloc(flen); 384 | if (!filename) { 385 | log_err("Out of memory\n"); 386 | rc = RC_ERROR; 387 | break; 388 | } 389 | strncpy(filename, input_dir, flen); 390 | strncat(filename, dp->d_name, flen); 391 | 392 | chip = getChipInfo(filename); 393 | if (!chip) { 394 | log_err("skip, failed to scan for '%s' tag\n", 395 | DT_ID_TAG); 396 | free(filename); 397 | continue; 398 | } 399 | 400 | if ((stat(filename, &st) != 0) || 401 | (st.st_size == 0)) { 402 | log_err("skip, failed to get DTB size\n"); 403 | free(filename); 404 | continue; 405 | } 406 | 407 | log_info("chipset: %" INFO_ENTRY_SIZE_S "s, " 408 | "platform: %" INFO_ENTRY_SIZE_S "s, " 409 | "rev: %" INFO_ENTRY_SIZE_S "s\n", 410 | chip->chipset, chip->platform, chip->revNum); 411 | 412 | rc = chip_add(chip); 413 | if (rc != RC_SUCCESS) { 414 | log_err("... duplicate info, skipped\n"); 415 | free(filename); 416 | continue; 417 | } 418 | 419 | dtb_count++; 420 | 421 | chip->dtb_size = st.st_size + 422 | (page_size - (st.st_size % page_size)); 423 | chip->dtb_file = filename; 424 | } 425 | } 426 | } 427 | closedir(dir); 428 | log_info("=> Found %d unique DTB(s)\n", dtb_count); 429 | 430 | if (!dtb_count) 431 | goto cleanup; 432 | 433 | 434 | /* Generate the master DTB file: 435 | 436 | Simplify write error handling by just checking for actual vs 437 | expected bytes written at the end. 438 | */ 439 | 440 | log_info("\nGenerating master DTB... "); 441 | 442 | out_fd = open(output_file, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR); 443 | if (!out_fd < 0) { 444 | log_err("Cannot create '%s'\n", output_file); 445 | rc = RC_ERROR; 446 | goto cleanup; 447 | } 448 | 449 | /* Write header info */ 450 | wrote += write(out_fd, AML_DT_MAGIC, sizeof(uint8_t) * 4); /* magic */ 451 | wrote += write(out_fd, &version, sizeof(uint32_t)); /* version */ 452 | wrote += write(out_fd, (uint32_t *)&dtb_count, sizeof(uint32_t)); 453 | /* #DTB */ 454 | 455 | /* Calculate offset of first DTB block */ 456 | dtb_offset = 12 + /* header */ 457 | (TABLE_ENTRY_HEADER_SIZE * dtb_count) + /* DTB table entries */ 458 | 4; /* end of table indicator */ 459 | /* Round up to page size */ 460 | padding = page_size - (dtb_offset % page_size); 461 | dtb_offset += padding; 462 | expected = dtb_offset; 463 | 464 | /* Write index table: 465 | chipset 466 | platform 467 | soc rev 468 | dtb offset 469 | dtb size 470 | */ 471 | for (chip = chip_list; chip; chip = chip->next) { 472 | /* for some reason, the id entries are padded with spaces (0x20) 473 | and are flipped. */ 474 | { 475 | int i; 476 | uint32_t *u32chipset = (uint32_t*)chip->chipset, 477 | *u32platform = (uint32_t*)chip->platform, 478 | *u32revNum = (uint32_t*)chip->revNum; 479 | 480 | padSpaces(chip->chipset, INFO_ENTRY_SIZE); 481 | padSpaces(chip->platform, INFO_ENTRY_SIZE); 482 | padSpaces(chip->revNum, INFO_ENTRY_SIZE); 483 | for ( i = 0; i < INFO_ENTRY_SIZE/sizeof(uint32_t); ++i ) { 484 | *(u32chipset + i) = swap_bytes_u32(*(u32chipset + i)); 485 | *(u32platform + i) = swap_bytes_u32(*(u32platform + i)); 486 | *(u32revNum + i) = swap_bytes_u32(*(u32revNum + i)); 487 | } 488 | } 489 | wrote += write(out_fd, chip->chipset, INFO_ENTRY_SIZE); 490 | wrote += write(out_fd, chip->platform, INFO_ENTRY_SIZE); 491 | wrote += write(out_fd, chip->revNum, INFO_ENTRY_SIZE); 492 | wrote += write(out_fd, &expected, sizeof(uint32_t)); 493 | wrote += write(out_fd, &chip->dtb_size, sizeof(uint32_t)); 494 | expected += chip->dtb_size; 495 | } 496 | 497 | rc = RC_SUCCESS; 498 | wrote += write(out_fd, &rc, sizeof(uint32_t)); /* end of table indicator */ 499 | if (padding > 0) 500 | wrote += write(out_fd, filler, padding); 501 | 502 | /* Write DTB's */ 503 | for (chip = chip_list; chip; chip = chip->next) { 504 | log_dbg("\n (writing '%s' - %u bytes) ", chip->dtb_file, chip->dtb_size); 505 | pInputFile = fopen(chip->dtb_file, "r"); 506 | if (pInputFile != NULL) { 507 | totBytesRead = 0; 508 | while ((numBytesRead = fread(buf, 1, COPY_BLK, pInputFile)) > 0) { 509 | wrote += write(out_fd, buf, numBytesRead); 510 | totBytesRead += numBytesRead; 511 | } 512 | fclose(pInputFile); 513 | padding = page_size - (totBytesRead % page_size); 514 | if ((uint32_t)(totBytesRead + padding) != chip->dtb_size) { 515 | log_err("DTB size mismatch, please re-run: expected %d vs actual %d (%s)\n", 516 | chip->dtb_size, totBytesRead + padding, 517 | chip->dtb_file); 518 | rc = RC_ERROR; 519 | break; 520 | } 521 | if (padding > 0) 522 | wrote += write(out_fd, filler, padding); 523 | } else { 524 | log_err("failed to open DTB '%s'\n", chip->dtb_file); 525 | rc = RC_ERROR; 526 | break; 527 | } 528 | } 529 | close(out_fd); 530 | 531 | if (expected != wrote) { 532 | log_err("error writing output file, please rerun: size mismatch %d vs %d\n", 533 | expected, wrote); 534 | rc = RC_ERROR; 535 | } else 536 | log_dbg("Total wrote %u bytes\n", wrote); 537 | 538 | if (rc != RC_SUCCESS) 539 | unlink(output_file); 540 | else 541 | log_info("completed\n"); 542 | 543 | cleanup: 544 | free(filler); 545 | chip_deleteall(); 546 | return rc; 547 | } --------------------------------------------------------------------------------