vrl4.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. /*
  2. * vrl4 format generator
  3. *
  4. * Copyright (C) 2010 Simon Horman
  5. *
  6. * This file is subject to the terms and conditions of the GNU General Public
  7. * License. See the file "COPYING" in the main directory of this archive
  8. * for more details.
  9. */
  10. /*
  11. * usage: vrl4 < zImage > out
  12. * dd if=out of=/dev/sdx bs=512 seek=1 # Write the image to sector 1
  13. *
  14. * Reads a zImage from stdin and writes a vrl4 image to stdout.
  15. * In practice this means writing a padded vrl4 header to stdout followed
  16. * by the zImage.
  17. *
  18. * The padding places the zImage at ALIGN bytes into the output.
  19. * The vrl4 uses ALIGN + START_BASE as the start_address.
  20. * This is where the mask ROM will jump to after verifying the header.
  21. *
  22. * The header sets copy_size to min(sizeof(zImage), MAX_BOOT_PROG_LEN) + ALIGN.
  23. * That is, the mask ROM will load the padded header (ALIGN bytes)
  24. * And then MAX_BOOT_PROG_LEN bytes of the image, or the entire image,
  25. * whichever is smaller.
  26. *
  27. * The zImage is not modified in any way.
  28. */
  29. #define _BSD_SOURCE
  30. #include <endian.h>
  31. #include <unistd.h>
  32. #include <stdint.h>
  33. #include <stdio.h>
  34. #include <errno.h>
  35. #include <tools/endian.h>
  36. struct hdr {
  37. uint32_t magic1;
  38. uint32_t reserved1;
  39. uint32_t magic2;
  40. uint32_t reserved2;
  41. uint16_t copy_size;
  42. uint16_t boot_options;
  43. uint32_t reserved3;
  44. uint32_t start_address;
  45. uint32_t reserved4;
  46. uint32_t reserved5;
  47. char reserved6[308];
  48. };
  49. #define DECLARE_HDR(h) \
  50. struct hdr (h) = { \
  51. .magic1 = htole32(0xea000000), \
  52. .reserved1 = htole32(0x56), \
  53. .magic2 = htole32(0xe59ff008), \
  54. .reserved3 = htole16(0x1) }
  55. /* Align to 512 bytes, the MMCIF sector size */
  56. #define ALIGN_BITS 9
  57. #define ALIGN (1 << ALIGN_BITS)
  58. #define START_BASE 0xe55b0000
  59. /*
  60. * With an alignment of 512 the header uses the first sector.
  61. * There is a 128 sector (64kbyte) limit on the data loaded by the mask ROM.
  62. * So there are 127 sectors left for the boot programme. But in practice
  63. * Only a small portion of a zImage is needed, 16 sectors should be more
  64. * than enough.
  65. *
  66. * Note that this sets how much of the zImage is copied by the mask ROM.
  67. * The entire zImage is present after the header and is loaded
  68. * by the code in the boot program (which is the first portion of the zImage).
  69. */
  70. #define MAX_BOOT_PROG_LEN (16 * 512)
  71. #define ROUND_UP(x) ((x + ALIGN - 1) & ~(ALIGN - 1))
  72. static ssize_t do_read(int fd, void *buf, size_t count)
  73. {
  74. size_t offset = 0;
  75. ssize_t l;
  76. while (offset < count) {
  77. l = read(fd, buf + offset, count - offset);
  78. if (!l)
  79. break;
  80. if (l < 0) {
  81. if (errno == EAGAIN || errno == EWOULDBLOCK)
  82. continue;
  83. perror("read");
  84. return -1;
  85. }
  86. offset += l;
  87. }
  88. return offset;
  89. }
  90. static ssize_t do_write(int fd, const void *buf, size_t count)
  91. {
  92. size_t offset = 0;
  93. ssize_t l;
  94. while (offset < count) {
  95. l = write(fd, buf + offset, count - offset);
  96. if (l < 0) {
  97. if (errno == EAGAIN || errno == EWOULDBLOCK)
  98. continue;
  99. perror("write");
  100. return -1;
  101. }
  102. offset += l;
  103. }
  104. return offset;
  105. }
  106. static ssize_t write_zero(int fd, size_t len)
  107. {
  108. size_t i = len;
  109. while (i--) {
  110. const char x = 0;
  111. if (do_write(fd, &x, 1) < 0)
  112. return -1;
  113. }
  114. return len;
  115. }
  116. int main(void)
  117. {
  118. DECLARE_HDR(hdr);
  119. char boot_program[MAX_BOOT_PROG_LEN];
  120. size_t aligned_hdr_len, alligned_prog_len;
  121. ssize_t prog_len;
  122. prog_len = do_read(0, boot_program, sizeof(boot_program));
  123. if (prog_len <= 0)
  124. return -1;
  125. aligned_hdr_len = ROUND_UP(sizeof(hdr));
  126. hdr.start_address = htole32(START_BASE + aligned_hdr_len);
  127. alligned_prog_len = ROUND_UP(prog_len);
  128. hdr.copy_size = htole16(aligned_hdr_len + alligned_prog_len);
  129. if (do_write(1, &hdr, sizeof(hdr)) < 0)
  130. return -1;
  131. if (write_zero(1, aligned_hdr_len - sizeof(hdr)) < 0)
  132. return -1;
  133. if (do_write(1, boot_program, prog_len) < 0)
  134. return 1;
  135. /* Write out the rest of the kernel */
  136. while (1) {
  137. prog_len = do_read(0, boot_program, sizeof(boot_program));
  138. if (prog_len < 0)
  139. return 1;
  140. if (prog_len == 0)
  141. break;
  142. if (do_write(1, boot_program, prog_len) < 0)
  143. return 1;
  144. }
  145. return 0;
  146. }