mkbrncmdline.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * mkbrncmdline.c - partially based on OpenWrt's wndr3700.c
  4. *
  5. * Copyright (C) 2011 Tobias Diedrich <[email protected]>
  6. */
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <stddef.h>
  10. #include <unistd.h>
  11. #include <errno.h>
  12. #include <fcntl.h>
  13. #include <sys/mman.h>
  14. #include <string.h>
  15. #include <netinet/in.h>
  16. #include <inttypes.h>
  17. static void usage(const char *) __attribute__ (( __noreturn__ ));
  18. static void usage(const char *mess)
  19. {
  20. fprintf(stderr, "Error: %s\n", mess);
  21. fprintf(stderr, "Usage: mkbrncmdline -i input_file -o output_file [-a loadaddress] arg1 [argx ...]\n");
  22. fprintf(stderr, "\n");
  23. exit(1);
  24. }
  25. static char *input_file = NULL;
  26. static char *output_file = NULL;
  27. static unsigned loadaddr = 0x80002000;
  28. static void parseopts(int *argc, char ***argv)
  29. {
  30. char *endptr;
  31. int res;
  32. while ((res = getopt(*argc, *argv, "a:i:o:")) != -1) {
  33. switch (res) {
  34. default:
  35. usage("Unknown option");
  36. break;
  37. case 'a':
  38. loadaddr = strtoul(optarg, &endptr, 0);
  39. if (endptr == optarg || *endptr != 0)
  40. usage("loadaddress must be a decimal or hexadecimal 32-bit value");
  41. break;
  42. case 'i':
  43. input_file = optarg;
  44. break;
  45. case 'o':
  46. output_file = optarg;
  47. break;
  48. }
  49. }
  50. *argc -= optind;
  51. *argv += optind;
  52. }
  53. static void emitload(int outfd, int reg, unsigned value)
  54. {
  55. char buf[8] = {
  56. 0x3c, 0x04 + reg,
  57. value >> 24, value >> 16,
  58. 0x34, 0x84 + reg + (reg << 5),
  59. value >> 8, value,
  60. };
  61. if (write(outfd, buf, sizeof(buf)) != sizeof(buf)) {
  62. fprintf(stderr, "write: %s\n", strerror(errno));
  63. exit(1);
  64. }
  65. }
  66. int main(int argc, char **argv)
  67. {
  68. int outfd;
  69. int i;
  70. int fd;
  71. size_t len, skip, buf_len;
  72. unsigned cmdline_addr;
  73. unsigned s_ofs;
  74. char *buf;
  75. parseopts(&argc, &argv);
  76. if (argc < 1)
  77. usage("must specify at least one kernel cmdline argument");
  78. if (input_file == NULL || output_file == NULL)
  79. usage("must specify input and output file");
  80. if ((outfd = open(output_file, O_WRONLY|O_CREAT|O_TRUNC, 0644)) == -1)
  81. {
  82. fprintf(stderr, "Error opening '%s' for writing: %s\n", output_file, strerror(errno));
  83. exit(1);
  84. }
  85. // mmap input_file
  86. if ((fd = open(input_file, O_RDONLY)) < 0
  87. || (len = lseek(fd, 0, SEEK_END)) < 0
  88. || (input_file = mmap(0, len, PROT_READ, MAP_SHARED, fd, 0)) == (void *) (-1)
  89. || close(fd) < 0)
  90. {
  91. fprintf(stderr, "Error mapping file '%s': %s\n", input_file, strerror(errno));
  92. exit(1);
  93. }
  94. cmdline_addr = loadaddr + len;
  95. // Kernel args are passed in registers a0,a1,a2 and a3
  96. emitload(outfd, 0, 0); /* a0 = 0 */
  97. emitload(outfd, 1, 0); /* a1 = 0 */
  98. emitload(outfd, 2, cmdline_addr); /* a2 = &cmdline */
  99. emitload(outfd, 3, 0); /* a3 = 0 */
  100. skip = lseek(outfd, 0, SEEK_END);
  101. // write the kernel
  102. if (write(outfd, input_file + skip, len - skip) != len -skip) {
  103. fprintf(stderr, "write: %s\n", strerror(errno));
  104. exit(1);
  105. }
  106. // write cmdline structure
  107. buf_len = (argc + 1) * 4;
  108. for (i=0; i<argc; i++) {
  109. buf_len += strlen(argv[i]) + 1;
  110. }
  111. buf = malloc(buf_len + 16);
  112. if (!buf) {
  113. fprintf(stderr, "Could not allocate memory for cmdline buffer\n");
  114. exit(1);
  115. }
  116. memset(buf, 0, buf_len);
  117. s_ofs = 4 * (argc + 1);
  118. for (i=0; i<argc; i++) {
  119. unsigned s_ptr = cmdline_addr + s_ofs;
  120. buf[i * 4 + 0] = s_ptr >> 24;
  121. buf[i * 4 + 1] = s_ptr >> 16;
  122. buf[i * 4 + 2] = s_ptr >> 8;
  123. buf[i * 4 + 3] = s_ptr >> 0;
  124. memcpy(&buf[s_ofs], argv[i], strlen(argv[i]));
  125. s_ofs += strlen(argv[i]) + 1;
  126. }
  127. if (write(outfd, buf, buf_len) != buf_len) {
  128. fprintf(stderr, "write: %s\n", strerror(errno));
  129. exit(1);
  130. }
  131. munmap(input_file, len);
  132. close(outfd);
  133. free(buf);
  134. return 0;
  135. }