libubigen.c 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. /*
  2. * Copyright (c) International Business Machines Corp., 2006
  3. * Copyright (C) 2008 Nokia Corporation
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
  13. * the GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program; if not, write to the Free Software
  17. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18. */
  19. /*
  20. * Generating UBI images.
  21. *
  22. * Authors: Oliver Lohmann
  23. * Artem Bityutskiy
  24. */
  25. #define PROGRAM_NAME "libubigen"
  26. #include <stdlib.h>
  27. #include <stdint.h>
  28. #include <unistd.h>
  29. #include <string.h>
  30. #include <mtd/ubi-media.h>
  31. #include <mtd_swab.h>
  32. #include <libubigen.h>
  33. #include <crc32.h>
  34. #include "common.h"
  35. void ubigen_info_init(struct ubigen_info *ui, int peb_size, int min_io_size,
  36. int subpage_size, int vid_hdr_offs, int ubi_ver,
  37. uint32_t image_seq)
  38. {
  39. if (!vid_hdr_offs) {
  40. vid_hdr_offs = UBI_EC_HDR_SIZE + subpage_size - 1;
  41. vid_hdr_offs /= subpage_size;
  42. vid_hdr_offs *= subpage_size;
  43. }
  44. ui->peb_size = peb_size;
  45. ui->min_io_size = min_io_size;
  46. ui->vid_hdr_offs = vid_hdr_offs;
  47. ui->data_offs = vid_hdr_offs + UBI_VID_HDR_SIZE + min_io_size - 1;
  48. ui->data_offs /= min_io_size;
  49. ui->data_offs *= min_io_size;
  50. ui->leb_size = peb_size - ui->data_offs;
  51. ui->ubi_ver = ubi_ver;
  52. ui->image_seq = image_seq;
  53. ui->max_volumes = ui->leb_size / UBI_VTBL_RECORD_SIZE;
  54. if (ui->max_volumes > UBI_MAX_VOLUMES)
  55. ui->max_volumes = UBI_MAX_VOLUMES;
  56. ui->vtbl_size = ui->max_volumes * UBI_VTBL_RECORD_SIZE;
  57. }
  58. struct ubi_vtbl_record *ubigen_create_empty_vtbl(const struct ubigen_info *ui)
  59. {
  60. struct ubi_vtbl_record *vtbl;
  61. int i;
  62. vtbl = calloc(1, ui->vtbl_size);
  63. if (!vtbl) {
  64. sys_errmsg("cannot allocate %d bytes of memory", ui->vtbl_size);
  65. return NULL;
  66. }
  67. for (i = 0; i < ui->max_volumes; i++) {
  68. uint32_t crc = mtd_crc32(UBI_CRC32_INIT, &vtbl[i],
  69. UBI_VTBL_RECORD_SIZE_CRC);
  70. vtbl[i].crc = cpu_to_be32(crc);
  71. }
  72. return vtbl;
  73. }
  74. int ubigen_add_volume(const struct ubigen_info *ui,
  75. const struct ubigen_vol_info *vi,
  76. struct ubi_vtbl_record *vtbl)
  77. {
  78. struct ubi_vtbl_record *vtbl_rec = &vtbl[vi->id];
  79. uint32_t tmp;
  80. if (vi->id >= ui->max_volumes) {
  81. errmsg("too high volume id %d, max. volumes is %d",
  82. vi->id, ui->max_volumes);
  83. errno = EINVAL;
  84. return -1;
  85. }
  86. if (vi->alignment >= ui->leb_size) {
  87. errmsg("too large alignment %d, max is %d (LEB size)",
  88. vi->alignment, ui->leb_size);
  89. errno = EINVAL;
  90. return -1;
  91. }
  92. memset(vtbl_rec, 0, sizeof(struct ubi_vtbl_record));
  93. tmp = (vi->bytes + ui->leb_size - 1) / ui->leb_size;
  94. vtbl_rec->reserved_pebs = cpu_to_be32(tmp);
  95. vtbl_rec->alignment = cpu_to_be32(vi->alignment);
  96. vtbl_rec->vol_type = vi->type;
  97. tmp = ui->leb_size % vi->alignment;
  98. vtbl_rec->data_pad = cpu_to_be32(tmp);
  99. vtbl_rec->flags = vi->flags;
  100. memcpy(vtbl_rec->name, vi->name, vi->name_len);
  101. vtbl_rec->name[vi->name_len] = '\0';
  102. vtbl_rec->name_len = cpu_to_be16(vi->name_len);
  103. tmp = mtd_crc32(UBI_CRC32_INIT, vtbl_rec, UBI_VTBL_RECORD_SIZE_CRC);
  104. vtbl_rec->crc = cpu_to_be32(tmp);
  105. return 0;
  106. }
  107. void ubigen_init_ec_hdr(const struct ubigen_info *ui,
  108. struct ubi_ec_hdr *hdr, long long ec)
  109. {
  110. uint32_t crc;
  111. memset(hdr, 0, sizeof(struct ubi_ec_hdr));
  112. hdr->magic = cpu_to_be32(UBI_EC_HDR_MAGIC);
  113. hdr->version = ui->ubi_ver;
  114. hdr->ec = cpu_to_be64(ec);
  115. hdr->vid_hdr_offset = cpu_to_be32(ui->vid_hdr_offs);
  116. hdr->data_offset = cpu_to_be32(ui->data_offs);
  117. hdr->image_seq = cpu_to_be32(ui->image_seq);
  118. crc = mtd_crc32(UBI_CRC32_INIT, hdr, UBI_EC_HDR_SIZE_CRC);
  119. hdr->hdr_crc = cpu_to_be32(crc);
  120. }
  121. void ubigen_init_vid_hdr(const struct ubigen_info *ui,
  122. const struct ubigen_vol_info *vi,
  123. struct ubi_vid_hdr *hdr, int lnum,
  124. const void *data, int data_size)
  125. {
  126. uint32_t crc;
  127. memset(hdr, 0, sizeof(struct ubi_vid_hdr));
  128. hdr->magic = cpu_to_be32(UBI_VID_HDR_MAGIC);
  129. hdr->version = ui->ubi_ver;
  130. hdr->vol_type = vi->type;
  131. hdr->vol_id = cpu_to_be32(vi->id);
  132. hdr->lnum = cpu_to_be32(lnum);
  133. hdr->data_pad = cpu_to_be32(vi->data_pad);
  134. hdr->compat = vi->compat;
  135. if (vi->type == UBI_VID_STATIC) {
  136. hdr->data_size = cpu_to_be32(data_size);
  137. hdr->used_ebs = cpu_to_be32(vi->used_ebs);
  138. crc = mtd_crc32(UBI_CRC32_INIT, data, data_size);
  139. hdr->data_crc = cpu_to_be32(crc);
  140. }
  141. crc = mtd_crc32(UBI_CRC32_INIT, hdr, UBI_VID_HDR_SIZE_CRC);
  142. hdr->hdr_crc = cpu_to_be32(crc);
  143. }
  144. int ubigen_write_volume(const struct ubigen_info *ui,
  145. const struct ubigen_vol_info *vi, long long ec,
  146. long long bytes, int in, int out)
  147. {
  148. int len = vi->usable_leb_size, rd, lnum = 0;
  149. char *inbuf, *outbuf;
  150. if (vi->id >= ui->max_volumes) {
  151. errmsg("too high volume id %d, max. volumes is %d",
  152. vi->id, ui->max_volumes);
  153. errno = EINVAL;
  154. return -1;
  155. }
  156. if (vi->alignment >= ui->leb_size) {
  157. errmsg("too large alignment %d, max is %d (LEB size)",
  158. vi->alignment, ui->leb_size);
  159. errno = EINVAL;
  160. return -1;
  161. }
  162. inbuf = malloc(ui->leb_size);
  163. if (!inbuf)
  164. return sys_errmsg("cannot allocate %d bytes of memory",
  165. ui->leb_size);
  166. outbuf = malloc(ui->peb_size);
  167. if (!outbuf) {
  168. sys_errmsg("cannot allocate %d bytes of memory", ui->peb_size);
  169. goto out_free;
  170. }
  171. memset(outbuf, 0xFF, ui->data_offs);
  172. ubigen_init_ec_hdr(ui, (struct ubi_ec_hdr *)outbuf, ec);
  173. while (bytes) {
  174. int l;
  175. struct ubi_vid_hdr *vid_hdr;
  176. if (bytes < len)
  177. len = bytes;
  178. bytes -= len;
  179. l = len;
  180. do {
  181. rd = read(in, inbuf + len - l, l);
  182. if (rd != l) {
  183. sys_errmsg("cannot read %d bytes from the input file", l);
  184. goto out_free1;
  185. }
  186. l -= rd;
  187. } while (l);
  188. vid_hdr = (struct ubi_vid_hdr *)(&outbuf[ui->vid_hdr_offs]);
  189. ubigen_init_vid_hdr(ui, vi, vid_hdr, lnum, inbuf, len);
  190. memcpy(outbuf + ui->data_offs, inbuf, len);
  191. memset(outbuf + ui->data_offs + len, 0xFF,
  192. ui->peb_size - ui->data_offs - len);
  193. if (write(out, outbuf, ui->peb_size) != ui->peb_size) {
  194. sys_errmsg("cannot write %d bytes to the output file", ui->peb_size);
  195. goto out_free1;
  196. }
  197. lnum += 1;
  198. }
  199. free(outbuf);
  200. free(inbuf);
  201. return 0;
  202. out_free1:
  203. free(outbuf);
  204. out_free:
  205. free(inbuf);
  206. return -1;
  207. }
  208. int ubigen_write_layout_vol(const struct ubigen_info *ui, int peb1, int peb2,
  209. long long ec1, long long ec2,
  210. struct ubi_vtbl_record *vtbl, int fd)
  211. {
  212. int ret;
  213. struct ubigen_vol_info vi;
  214. char *outbuf;
  215. struct ubi_vid_hdr *vid_hdr;
  216. off_t seek;
  217. vi.bytes = ui->leb_size * UBI_LAYOUT_VOLUME_EBS;
  218. vi.id = UBI_LAYOUT_VOLUME_ID;
  219. vi.alignment = UBI_LAYOUT_VOLUME_ALIGN;
  220. vi.data_pad = ui->leb_size % UBI_LAYOUT_VOLUME_ALIGN;
  221. vi.usable_leb_size = ui->leb_size - vi.data_pad;
  222. vi.data_pad = ui->leb_size - vi.usable_leb_size;
  223. vi.type = UBI_LAYOUT_VOLUME_TYPE;
  224. vi.name = UBI_LAYOUT_VOLUME_NAME;
  225. vi.name_len = strlen(UBI_LAYOUT_VOLUME_NAME);
  226. vi.compat = UBI_LAYOUT_VOLUME_COMPAT;
  227. outbuf = malloc(ui->peb_size);
  228. if (!outbuf)
  229. return sys_errmsg("failed to allocate %d bytes",
  230. ui->peb_size);
  231. memset(outbuf, 0xFF, ui->data_offs);
  232. vid_hdr = (struct ubi_vid_hdr *)(&outbuf[ui->vid_hdr_offs]);
  233. memcpy(outbuf + ui->data_offs, vtbl, ui->vtbl_size);
  234. memset(outbuf + ui->data_offs + ui->vtbl_size, 0xFF,
  235. ui->peb_size - ui->data_offs - ui->vtbl_size);
  236. seek = (off_t) peb1 * ui->peb_size;
  237. if (lseek(fd, seek, SEEK_SET) != seek) {
  238. sys_errmsg("cannot seek output file");
  239. goto out_free;
  240. }
  241. ubigen_init_ec_hdr(ui, (struct ubi_ec_hdr *)outbuf, ec1);
  242. ubigen_init_vid_hdr(ui, &vi, vid_hdr, 0, NULL, 0);
  243. ret = write(fd, outbuf, ui->peb_size);
  244. if (ret != ui->peb_size) {
  245. sys_errmsg("cannot write %d bytes", ui->peb_size);
  246. goto out_free;
  247. }
  248. seek = (off_t) peb2 * ui->peb_size;
  249. if (lseek(fd, seek, SEEK_SET) != seek) {
  250. sys_errmsg("cannot seek output file");
  251. goto out_free;
  252. }
  253. ubigen_init_ec_hdr(ui, (struct ubi_ec_hdr *)outbuf, ec2);
  254. ubigen_init_vid_hdr(ui, &vi, vid_hdr, 1, NULL, 0);
  255. ret = write(fd, outbuf, ui->peb_size);
  256. if (ret != ui->peb_size) {
  257. sys_errmsg("cannot write %d bytes", ui->peb_size);
  258. goto out_free;
  259. }
  260. free(outbuf);
  261. return 0;
  262. out_free:
  263. free(outbuf);
  264. return -1;
  265. }