mtdsplit_jimage.c 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. /*
  2. * Copyright (C) 2018 Paweł Dembicki <[email protected]>
  3. *
  4. * Based on: mtdsplit_uimage.c
  5. * Copyright (C) 2013 Gabor Juhos <[email protected]>
  6. *
  7. * This program is free software; you can redistribute it and/or modify it
  8. * under the terms of the GNU General Public License version 2 as published
  9. * by the Free Software Foundation.
  10. *
  11. */
  12. #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  13. #include <linux/module.h>
  14. #include <linux/init.h>
  15. #include <linux/kernel.h>
  16. #include <linux/slab.h>
  17. #include <linux/vmalloc.h>
  18. #include <linux/mtd/mtd.h>
  19. #include <linux/mtd/partitions.h>
  20. #include <linux/version.h>
  21. #include <linux/byteorder/generic.h>
  22. #include "mtdsplit.h"
  23. #define MAX_HEADER_LEN ( STAG_SIZE + SCH2_SIZE )
  24. #define STAG_SIZE 16
  25. #define STAG_ID 0x04
  26. #define STAG_MAGIC 0x2B24
  27. #define SCH2_SIZE 40
  28. #define SCH2_MAGIC 0x2124
  29. #define SCH2_VER 0x02
  30. /*
  31. * Jboot image header,
  32. * all data in little endian.
  33. */
  34. struct jimage_header //stag + sch2 jboot joined headers
  35. {
  36. uint8_t stag_cmark; // in factory 0xFF , in sysupgrade must be the same as stag_id
  37. uint8_t stag_id; // 0x04
  38. uint16_t stag_magic; //magic 0x2B24
  39. uint32_t stag_time_stamp; // timestamp calculated in jboot way
  40. uint32_t stag_image_length; // lentgh of kernel + sch2 header
  41. uint16_t stag_image_checksum; // negated jboot_checksum of sch2 + kernel
  42. uint16_t stag_tag_checksum; // negated jboot_checksum of stag header data
  43. uint16_t sch2_magic; // magic 0x2124
  44. uint8_t sch2_cp_type; // 0x00 for flat, 0x01 for jz, 0x02 for gzip, 0x03 for lzma
  45. uint8_t sch2_version; // 0x02 for sch2
  46. uint32_t sch2_ram_addr; // ram entry address
  47. uint32_t sch2_image_len; // kernel image length
  48. uint32_t sch2_image_crc32; // kernel image crc
  49. uint32_t sch2_start_addr; // ram start address
  50. uint32_t sch2_rootfs_addr; // rootfs flash address
  51. uint32_t sch2_rootfs_len; // rootfls length
  52. uint32_t sch2_rootfs_crc32; // rootfs crc32
  53. uint32_t sch2_header_crc32; // sch2 header crc32, durring calculation this area is replaced by zero
  54. uint16_t sch2_header_length; // sch2 header length: 0x28
  55. uint16_t sch2_cmd_line_length; // cmd line length, known zeros
  56. };
  57. static int
  58. read_jimage_header(struct mtd_info *mtd, size_t offset, u_char *buf,
  59. size_t header_len)
  60. {
  61. size_t retlen;
  62. int ret;
  63. ret = mtd_read(mtd, offset, header_len, &retlen, buf);
  64. if (ret) {
  65. pr_debug("read error in \"%s\"\n", mtd->name);
  66. return ret;
  67. }
  68. if (retlen != header_len) {
  69. pr_debug("short read in \"%s\"\n", mtd->name);
  70. return -EIO;
  71. }
  72. return 0;
  73. }
  74. /**
  75. * __mtdsplit_parse_jimage - scan partition and create kernel + rootfs parts
  76. *
  77. * @find_header: function to call for a block of data that will return offset
  78. * of a valid jImage header if found
  79. */
  80. static int __mtdsplit_parse_jimage(struct mtd_info *master,
  81. const struct mtd_partition **pparts,
  82. struct mtd_part_parser_data *data,
  83. ssize_t (*find_header)(u_char *buf, size_t len))
  84. {
  85. struct mtd_partition *parts;
  86. u_char *buf;
  87. int nr_parts;
  88. size_t offset;
  89. size_t jimage_offset;
  90. size_t jimage_size = 0;
  91. size_t rootfs_offset;
  92. size_t rootfs_size = 0;
  93. int jimage_part, rf_part;
  94. int ret;
  95. enum mtdsplit_part_type type;
  96. nr_parts = 2;
  97. parts = kzalloc(nr_parts * sizeof(*parts), GFP_KERNEL);
  98. if (!parts)
  99. return -ENOMEM;
  100. buf = vmalloc(MAX_HEADER_LEN);
  101. if (!buf) {
  102. ret = -ENOMEM;
  103. goto err_free_parts;
  104. }
  105. /* find jImage on erase block boundaries */
  106. for (offset = 0; offset < master->size; offset += master->erasesize) {
  107. struct jimage_header *header;
  108. jimage_size = 0;
  109. ret = read_jimage_header(master, offset, buf, MAX_HEADER_LEN);
  110. if (ret)
  111. continue;
  112. ret = find_header(buf, MAX_HEADER_LEN);
  113. if (ret < 0) {
  114. pr_debug("no valid jImage found in \"%s\" at offset %llx\n",
  115. master->name, (unsigned long long) offset);
  116. continue;
  117. }
  118. header = (struct jimage_header *)(buf + ret);
  119. jimage_size = sizeof(*header) + header->sch2_image_len + ret;
  120. if ((offset + jimage_size) > master->size) {
  121. pr_debug("jImage exceeds MTD device \"%s\"\n",
  122. master->name);
  123. continue;
  124. }
  125. break;
  126. }
  127. if (jimage_size == 0) {
  128. pr_debug("no jImage found in \"%s\"\n", master->name);
  129. ret = -ENODEV;
  130. goto err_free_buf;
  131. }
  132. jimage_offset = offset;
  133. if (jimage_offset == 0) {
  134. jimage_part = 0;
  135. rf_part = 1;
  136. /* find the roots after the jImage */
  137. ret = mtd_find_rootfs_from(master, jimage_offset + jimage_size,
  138. master->size, &rootfs_offset, &type);
  139. if (ret) {
  140. pr_debug("no rootfs after jImage in \"%s\"\n",
  141. master->name);
  142. goto err_free_buf;
  143. }
  144. rootfs_size = master->size - rootfs_offset;
  145. jimage_size = rootfs_offset - jimage_offset;
  146. } else {
  147. rf_part = 0;
  148. jimage_part = 1;
  149. /* check rootfs presence at offset 0 */
  150. ret = mtd_check_rootfs_magic(master, 0, &type);
  151. if (ret) {
  152. pr_debug("no rootfs before jImage in \"%s\"\n",
  153. master->name);
  154. goto err_free_buf;
  155. }
  156. rootfs_offset = 0;
  157. rootfs_size = jimage_offset;
  158. }
  159. if (rootfs_size == 0) {
  160. pr_debug("no rootfs found in \"%s\"\n", master->name);
  161. ret = -ENODEV;
  162. goto err_free_buf;
  163. }
  164. parts[jimage_part].name = KERNEL_PART_NAME;
  165. parts[jimage_part].offset = jimage_offset;
  166. parts[jimage_part].size = jimage_size;
  167. if (type == MTDSPLIT_PART_TYPE_UBI)
  168. parts[rf_part].name = UBI_PART_NAME;
  169. else
  170. parts[rf_part].name = ROOTFS_PART_NAME;
  171. parts[rf_part].offset = rootfs_offset;
  172. parts[rf_part].size = rootfs_size;
  173. vfree(buf);
  174. *pparts = parts;
  175. return nr_parts;
  176. err_free_buf:
  177. vfree(buf);
  178. err_free_parts:
  179. kfree(parts);
  180. return ret;
  181. }
  182. static ssize_t jimage_verify_default(u_char *buf, size_t len)
  183. {
  184. struct jimage_header *header = (struct jimage_header *)buf;
  185. /* default sanity checks */
  186. if (header->stag_magic != STAG_MAGIC) {
  187. pr_debug("invalid jImage stag header magic: %04x\n",
  188. header->stag_magic);
  189. return -EINVAL;
  190. }
  191. if (header->sch2_magic != SCH2_MAGIC) {
  192. pr_debug("invalid jImage sch2 header magic: %04x\n",
  193. header->stag_magic);
  194. return -EINVAL;
  195. }
  196. if (header->stag_cmark != header->stag_id) {
  197. pr_debug("invalid jImage stag header cmark: %02x\n",
  198. header->stag_magic);
  199. return -EINVAL;
  200. }
  201. if (header->stag_id != STAG_ID) {
  202. pr_debug("invalid jImage stag header id: %02x\n",
  203. header->stag_magic);
  204. return -EINVAL;
  205. }
  206. if (header->sch2_version != SCH2_VER) {
  207. pr_debug("invalid jImage sch2 header version: %02x\n",
  208. header->stag_magic);
  209. return -EINVAL;
  210. }
  211. return 0;
  212. }
  213. static int
  214. mtdsplit_jimage_parse_generic(struct mtd_info *master,
  215. const struct mtd_partition **pparts,
  216. struct mtd_part_parser_data *data)
  217. {
  218. return __mtdsplit_parse_jimage(master, pparts, data,
  219. jimage_verify_default);
  220. }
  221. #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)
  222. static const struct of_device_id mtdsplit_jimage_of_match_table[] = {
  223. { .compatible = "amit,jimage" },
  224. {},
  225. };
  226. #endif
  227. static struct mtd_part_parser jimage_generic_parser = {
  228. .owner = THIS_MODULE,
  229. .name = "jimage-fw",
  230. #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)
  231. .of_match_table = mtdsplit_jimage_of_match_table,
  232. #endif
  233. .parse_fn = mtdsplit_jimage_parse_generic,
  234. .type = MTD_PARSER_TYPE_FIRMWARE,
  235. };
  236. /**************************************************
  237. * Init
  238. **************************************************/
  239. static int __init mtdsplit_jimage_init(void)
  240. {
  241. register_mtd_parser(&jimage_generic_parser);
  242. return 0;
  243. }
  244. module_init(mtdsplit_jimage_init);