dtbimg.c 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. /* tools/mkbootimg/dtbimg.c
  2. **
  3. ** Copyright 2007, The Android Open Source Project
  4. ** Copyright 2013, Sony Mobile Communications
  5. **
  6. ** Licensed under the Apache License, Version 2.0 (the "License");
  7. ** you may not use this file except in compliance with the License.
  8. ** You may obtain a copy of the License at
  9. **
  10. ** http://www.apache.org/licenses/LICENSE-2.0
  11. **
  12. ** Unless required by applicable law or agreed to in writing, software
  13. ** distributed under the License is distributed on an "AS IS" BASIS,
  14. ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. ** See the License for the specific language governing permissions and
  16. ** limitations under the License.
  17. **
  18. ** December 2016, Christopher N. Hesse
  19. ** Separate dt creation from mkbootimg program.
  20. */
  21. #include <stdio.h>
  22. #include <stdlib.h>
  23. #include <string.h>
  24. #include <unistd.h>
  25. #include <fcntl.h>
  26. #include <errno.h>
  27. #include <limits.h>
  28. #include <sys/types.h>
  29. #include <arpa/inet.h>
  30. #include <assert.h>
  31. #include <dirent.h>
  32. #include <err.h>
  33. #include <stdint.h>
  34. /* must be provided by the device tree */
  35. #include <samsung_dtbh.h>
  36. #include "libfdt.h"
  37. struct dt_blob;
  38. struct dt_entry {
  39. uint32_t chip;
  40. uint32_t platform;
  41. uint32_t subtype;
  42. uint32_t hw_rev;
  43. uint32_t hw_rev_end;
  44. uint32_t offset;
  45. uint32_t size; /* including padding */
  46. uint32_t space;
  47. struct dt_blob *blob;
  48. };
  49. /*
  50. * Comparator for sorting dt_entries
  51. */
  52. static int dt_entry_cmp(const void *ap, const void *bp)
  53. {
  54. struct dt_entry *a = (struct dt_entry*)ap;
  55. struct dt_entry *b = (struct dt_entry*)bp;
  56. if (a->chip != b->chip)
  57. return a->chip - b->chip;
  58. return a->hw_rev - b->hw_rev;
  59. }
  60. /*
  61. * In memory representation of a dtb blob
  62. */
  63. struct dt_blob {
  64. uint32_t size;
  65. uint32_t offset;
  66. void *payload;
  67. struct dt_blob *next;
  68. };
  69. static void *load_file(const char *fn, unsigned *_sz)
  70. {
  71. char *data;
  72. int sz;
  73. int fd;
  74. data = 0;
  75. fd = open(fn, O_RDONLY);
  76. if(fd < 0) return 0;
  77. sz = lseek(fd, 0, SEEK_END);
  78. if(sz < 0) goto oops;
  79. if(lseek(fd, 0, SEEK_SET) != 0) goto oops;
  80. data = (char*) malloc(sz);
  81. if(data == 0) goto oops;
  82. if(read(fd, data, sz) != sz) goto oops;
  83. close(fd);
  84. if(_sz) *_sz = sz;
  85. return data;
  86. oops:
  87. close(fd);
  88. if(data != 0) free(data);
  89. return 0;
  90. }
  91. void *load_dtbh_block(const char *dtb_path, unsigned pagesize, unsigned *_sz)
  92. {
  93. const unsigned pagemask = pagesize - 1;
  94. struct dt_entry *new_entries;
  95. struct dt_entry *entries = NULL;
  96. struct dt_entry *entry;
  97. struct dt_blob *blob;
  98. struct dt_blob *blob_list = NULL;
  99. struct dt_blob *last_blob = NULL;
  100. struct dirent *de;
  101. unsigned new_count;
  102. unsigned entry_count = 0;
  103. unsigned offset;
  104. unsigned dtb_sz;
  105. unsigned hdr_sz = DT_HEADER_PHYS_SIZE;
  106. uint32_t version = DTBH_VERSION;
  107. unsigned blob_sz = 0;
  108. char fname[PATH_MAX];
  109. const unsigned *prop_chip;
  110. const unsigned *prop_platform;
  111. const unsigned *prop_subtype;
  112. const unsigned *prop_hw_rev;
  113. const unsigned *prop_hw_rev_end;
  114. int namlen;
  115. int len;
  116. void *dtb;
  117. char *dtbh;
  118. DIR *dir;
  119. unsigned c;
  120. dir = opendir(dtb_path);
  121. if (dir == NULL)
  122. err(1, "failed to open '%s'", dtb_path);
  123. while ((de = readdir(dir)) != NULL) {
  124. namlen = strlen(de->d_name);
  125. if (namlen < 4 || strcmp(&de->d_name[namlen - 4], ".dtb"))
  126. continue;
  127. snprintf(fname, sizeof(fname), "%s/%s", dtb_path, de->d_name);
  128. dtb = load_file(fname, &dtb_sz);
  129. if (dtb == NULL)
  130. err(1, "failed to read dtb '%s'", fname);
  131. if (fdt_check_header(dtb) != 0) {
  132. warnx("'%s' is not a valid dtb, skipping", fname);
  133. free(dtb);
  134. continue;
  135. }
  136. offset = fdt_path_offset(dtb, "/");
  137. prop_chip = fdt_getprop(dtb, offset, "model_info-chip", &len);
  138. if (len % (sizeof(uint32_t)) != 0) {
  139. warnx("model_info-chip of %s is of invalid size, skipping", fname);
  140. free(dtb);
  141. continue;
  142. }
  143. prop_platform = fdt_getprop(dtb, offset, "model_info-platform", &len);
  144. if (strcmp((char *)&prop_platform[0], DTBH_PLATFORM)) {
  145. warnx("model_info-platform of %s is invalid, skipping (expected %s but got %s)",
  146. fname, DTBH_PLATFORM, (char *)&prop_platform[0]);
  147. free(dtb);
  148. continue;
  149. }
  150. prop_subtype = fdt_getprop(dtb, offset, "model_info-subtype", &len);
  151. if (strcmp((char *)&prop_subtype[0], DTBH_SUBTYPE)) {
  152. warnx("model_info-subtype of %s is invalid, skipping (expected %s but got %s)",
  153. fname, DTBH_SUBTYPE, (char *)&prop_subtype[0]);
  154. free(dtb);
  155. continue;
  156. }
  157. prop_hw_rev = fdt_getprop(dtb, offset, "model_info-hw_rev", &len);
  158. if (len % (sizeof(uint32_t)) != 0) {
  159. warnx("model_info-hw_rev of %s is of invalid size, skipping", fname);
  160. free(dtb);
  161. continue;
  162. }
  163. prop_hw_rev_end = fdt_getprop(dtb, offset, "model_info-hw_rev_end", &len);
  164. if (len % (sizeof(uint32_t)) != 0) {
  165. warnx("model_info-hw_rev_end of %s is of invalid size, skipping", fname);
  166. free(dtb);
  167. continue;
  168. }
  169. blob = calloc(1, sizeof(struct dt_blob));
  170. if (blob == NULL)
  171. err(1, "failed to allocate memory");
  172. blob->payload = dtb;
  173. blob->size = dtb_sz;
  174. if (blob_list == NULL) {
  175. blob_list = blob;
  176. last_blob = blob;
  177. } else {
  178. last_blob->next = blob;
  179. last_blob = blob;
  180. }
  181. blob_sz += (blob->size + pagemask) & ~pagemask;
  182. new_count = entry_count + 1;
  183. new_entries = realloc(entries, new_count * sizeof(struct dt_entry));
  184. if (new_entries == NULL)
  185. err(1, "failed to allocate memory");
  186. entries = new_entries;
  187. entry = &entries[entry_count];
  188. memset(entry, 0, sizeof(*entry));
  189. entry->chip = ntohl(prop_chip[0]);
  190. entry->platform = DTBH_PLATFORM_CODE;
  191. entry->subtype = DTBH_SUBTYPE_CODE;
  192. entry->hw_rev = ntohl(prop_hw_rev[0]);
  193. entry->hw_rev_end = ntohl(prop_hw_rev_end[0]);
  194. entry->space = 0x20; /* space delimiter */
  195. entry->blob = blob;
  196. entry_count++;
  197. hdr_sz += entry_count * DT_ENTRY_PHYS_SIZE;
  198. }
  199. closedir(dir);
  200. if (entry_count == 0) {
  201. warnx("unable to locate any dtbs in the given path");
  202. return NULL;
  203. }
  204. hdr_sz += sizeof(uint32_t); /* eot marker */
  205. hdr_sz = (hdr_sz + pagemask) & ~pagemask;
  206. qsort(entries, entry_count, sizeof(struct dt_entry), dt_entry_cmp);
  207. /* The size of the dt header is now known, calculate the blob offsets... */
  208. offset = hdr_sz;
  209. for (blob = blob_list; blob; blob = blob->next) {
  210. blob->offset = offset;
  211. offset += (blob->size + pagemask) & ~pagemask;
  212. }
  213. /* ...and update the entries */
  214. for (c = 0; c < entry_count; c++) {
  215. entry = &entries[c];
  216. entry->offset = entry->blob->offset;
  217. entry->size = (entry->blob->size + pagemask) & ~pagemask;
  218. }
  219. /*
  220. * All parts are now gathered, so build the dt block
  221. */
  222. dtbh = calloc(hdr_sz + blob_sz, 1);
  223. if (dtbh == NULL)
  224. err(1, "failed to allocate memory");
  225. offset = 0;
  226. memcpy(dtbh, DTBH_MAGIC, sizeof(uint32_t));
  227. memcpy(dtbh + sizeof(uint32_t), &version, sizeof(uint32_t));
  228. memcpy(dtbh + (sizeof(uint32_t) * 2), &entry_count, sizeof(uint32_t));
  229. offset += DT_HEADER_PHYS_SIZE;
  230. /* add dtbh entries */
  231. for (c = 0; c < entry_count; c++) {
  232. entry = &entries[c];
  233. memcpy(dtbh + offset, entry, DT_ENTRY_PHYS_SIZE);
  234. offset += DT_ENTRY_PHYS_SIZE;
  235. }
  236. /* add padding after dt header */
  237. offset += pagesize - (offset & pagemask);
  238. for (blob = blob_list; blob; blob = blob->next) {
  239. memcpy(dtbh + offset, blob->payload, blob->size);
  240. offset += (blob->size + pagemask) & ~pagemask;
  241. }
  242. *_sz = hdr_sz + blob_sz;
  243. return dtbh;
  244. }