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. struct hdr {
  36. uint32_t magic1;
  37. uint32_t reserved1;
  38. uint32_t magic2;
  39. uint32_t reserved2;
  40. uint16_t copy_size;
  41. uint16_t boot_options;
  42. uint32_t reserved3;
  43. uint32_t start_address;
  44. uint32_t reserved4;
  45. uint32_t reserved5;
  46. char reserved6[308];
  47. };
  48. #define DECLARE_HDR(h) \
  49. struct hdr (h) = { \
  50. .magic1 = htole32(0xea000000), \
  51. .reserved1 = htole32(0x56), \
  52. .magic2 = htole32(0xe59ff008), \
  53. .reserved3 = htole16(0x1) }
  54. /* Align to 512 bytes, the MMCIF sector size */
  55. #define ALIGN_BITS 9
  56. #define ALIGN (1 << ALIGN_BITS)
  57. #define START_BASE 0xe55b0000
  58. /*
  59. * With an alignment of 512 the header uses the first sector.
  60. * There is a 128 sector (64kbyte) limit on the data loaded by the mask ROM.
  61. * So there are 127 sectors left for the boot programme. But in practice
  62. * Only a small portion of a zImage is needed, 16 sectors should be more
  63. * than enough.
  64. *
  65. * Note that this sets how much of the zImage is copied by the mask ROM.
  66. * The entire zImage is present after the header and is loaded
  67. * by the code in the boot program (which is the first portion of the zImage).
  68. */
  69. #define MAX_BOOT_PROG_LEN (16 * 512)
  70. #define ROUND_UP(x) ((x + ALIGN - 1) & ~(ALIGN - 1))
  71. ssize_t do_read(int fd, void *buf, size_t count)
  72. {
  73. size_t offset = 0;
  74. ssize_t l;
  75. while (offset < count) {
  76. l = read(fd, buf + offset, count - offset);
  77. if (!l)
  78. break;
  79. if (l < 0) {
  80. if (errno == EAGAIN || errno == EWOULDBLOCK)
  81. continue;
  82. perror("read");
  83. return -1;
  84. }
  85. offset += l;
  86. }
  87. return offset;
  88. }
  89. ssize_t do_write(int fd, const void *buf, size_t count)
  90. {
  91. size_t offset = 0;
  92. ssize_t l;
  93. while (offset < count) {
  94. l = write(fd, buf + offset, count - offset);
  95. if (l < 0) {
  96. if (errno == EAGAIN || errno == EWOULDBLOCK)
  97. continue;
  98. perror("write");
  99. return -1;
  100. }
  101. offset += l;
  102. }
  103. return offset;
  104. }
  105. ssize_t write_zero(int fd, size_t len)
  106. {
  107. size_t i = len;
  108. while (i--) {
  109. const char x = 0;
  110. if (do_write(fd, &x, 1) < 0)
  111. return -1;
  112. }
  113. return len;
  114. }
  115. int main(void)
  116. {
  117. DECLARE_HDR(hdr);
  118. char boot_program[MAX_BOOT_PROG_LEN];
  119. size_t aligned_hdr_len, alligned_prog_len;
  120. ssize_t prog_len;
  121. prog_len = do_read(0, boot_program, sizeof(boot_program));
  122. if (prog_len <= 0)
  123. return -1;
  124. aligned_hdr_len = ROUND_UP(sizeof(hdr));
  125. hdr.start_address = htole32(START_BASE + aligned_hdr_len);
  126. alligned_prog_len = ROUND_UP(prog_len);
  127. hdr.copy_size = htole16(aligned_hdr_len + alligned_prog_len);
  128. if (do_write(1, &hdr, sizeof(hdr)) < 0)
  129. return -1;
  130. if (write_zero(1, aligned_hdr_len - sizeof(hdr)) < 0)
  131. return -1;
  132. if (do_write(1, boot_program, prog_len) < 0)
  133. return 1;
  134. /* Write out the rest of the kernel */
  135. while (1) {
  136. prog_len = do_read(0, boot_program, sizeof(boot_program));
  137. if (prog_len < 0)
  138. return 1;
  139. if (prog_len == 0)
  140. break;
  141. if (do_write(1, boot_program, prog_len) < 0)
  142. return 1;
  143. }
  144. return 0;
  145. }