misc.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  1. /*
  2. * Definitions and wrapper functions for kernel decompressor
  3. *
  4. * (C) 2017 Helge Deller <[email protected]>
  5. */
  6. #include <linux/uaccess.h>
  7. #include <linux/elf.h>
  8. #include <asm/unaligned.h>
  9. #include <asm/page.h>
  10. #include "sizes.h"
  11. /*
  12. * gzip declarations
  13. */
  14. #define STATIC static
  15. #undef memmove
  16. #define memmove memmove
  17. #define memzero(s, n) memset((s), 0, (n))
  18. #define malloc malloc_gzip
  19. #define free free_gzip
  20. /* Symbols defined by linker scripts */
  21. extern char input_data[];
  22. extern int input_len;
  23. /* output_len is inserted by the linker possibly at an unaligned address */
  24. extern char output_len;
  25. extern char _text, _end;
  26. extern char _bss, _ebss;
  27. extern char _startcode_end;
  28. extern void startup_continue(void *entry, unsigned long cmdline,
  29. unsigned long rd_start, unsigned long rd_end) __noreturn;
  30. void error(char *m) __noreturn;
  31. static unsigned long free_mem_ptr;
  32. static unsigned long free_mem_end_ptr;
  33. #ifdef CONFIG_KERNEL_GZIP
  34. #include "../../../../lib/decompress_inflate.c"
  35. #endif
  36. #ifdef CONFIG_KERNEL_BZIP2
  37. #include "../../../../lib/decompress_bunzip2.c"
  38. #endif
  39. #ifdef CONFIG_KERNEL_LZ4
  40. #include "../../../../lib/decompress_unlz4.c"
  41. #endif
  42. #ifdef CONFIG_KERNEL_LZMA
  43. #include "../../../../lib/decompress_unlzma.c"
  44. #endif
  45. #ifdef CONFIG_KERNEL_LZO
  46. #include "../../../../lib/decompress_unlzo.c"
  47. #endif
  48. #ifdef CONFIG_KERNEL_XZ
  49. #include "../../../../lib/decompress_unxz.c"
  50. #endif
  51. void *memmove(void *dest, const void *src, size_t n)
  52. {
  53. const char *s = src;
  54. char *d = dest;
  55. if (d <= s) {
  56. while (n--)
  57. *d++ = *s++;
  58. } else {
  59. d += n;
  60. s += n;
  61. while (n--)
  62. *--d = *--s;
  63. }
  64. return dest;
  65. }
  66. void *memset(void *s, int c, size_t count)
  67. {
  68. char *xs = (char *)s;
  69. while (count--)
  70. *xs++ = c;
  71. return s;
  72. }
  73. void *memcpy(void *d, const void *s, size_t len)
  74. {
  75. char *dest = (char *)d;
  76. const char *source = (const char *)s;
  77. while (len--)
  78. *dest++ = *source++;
  79. return d;
  80. }
  81. size_t strlen(const char *s)
  82. {
  83. const char *sc;
  84. for (sc = s; *sc != '\0'; ++sc)
  85. ;
  86. return sc - s;
  87. }
  88. char *strchr(const char *s, int c)
  89. {
  90. while (*s) {
  91. if (*s == (char)c)
  92. return (char *)s;
  93. ++s;
  94. }
  95. return NULL;
  96. }
  97. int puts(const char *s)
  98. {
  99. const char *nuline = s;
  100. while ((nuline = strchr(s, '\n')) != NULL) {
  101. if (nuline != s)
  102. pdc_iodc_print(s, nuline - s);
  103. pdc_iodc_print("\r\n", 2);
  104. s = nuline + 1;
  105. }
  106. if (*s != '\0')
  107. pdc_iodc_print(s, strlen(s));
  108. return 0;
  109. }
  110. static int putchar(int c)
  111. {
  112. char buf[2];
  113. buf[0] = c;
  114. buf[1] = '\0';
  115. puts(buf);
  116. return c;
  117. }
  118. void __noreturn error(char *x)
  119. {
  120. if (x) puts(x);
  121. puts("\n -- System halted\n");
  122. while (1) /* wait forever */
  123. ;
  124. }
  125. static int print_num(unsigned long num, int base)
  126. {
  127. const char hex[] = "0123456789abcdef";
  128. char str[40];
  129. int i = sizeof(str)-1;
  130. str[i--] = '\0';
  131. do {
  132. str[i--] = hex[num % base];
  133. num = num / base;
  134. } while (num);
  135. if (base == 16) {
  136. str[i--] = 'x';
  137. str[i] = '0';
  138. } else i++;
  139. puts(&str[i]);
  140. return 0;
  141. }
  142. int printf(const char *fmt, ...)
  143. {
  144. va_list args;
  145. int i = 0;
  146. va_start(args, fmt);
  147. while (fmt[i]) {
  148. if (fmt[i] != '%') {
  149. put:
  150. putchar(fmt[i++]);
  151. continue;
  152. }
  153. if (fmt[++i] == '%')
  154. goto put;
  155. print_num(va_arg(args, unsigned long),
  156. fmt[i] == 'x' ? 16:10);
  157. ++i;
  158. }
  159. va_end(args);
  160. return 0;
  161. }
  162. /* helper functions for libgcc */
  163. void abort(void)
  164. {
  165. error("aborted.");
  166. }
  167. #undef malloc
  168. void *malloc(size_t size)
  169. {
  170. return malloc_gzip(size);
  171. }
  172. #undef free
  173. void free(void *ptr)
  174. {
  175. return free_gzip(ptr);
  176. }
  177. static void flush_data_cache(char *start, unsigned long length)
  178. {
  179. char *end = start + length;
  180. do {
  181. asm volatile("fdc 0(%0)" : : "r" (start));
  182. asm volatile("fic 0(%%sr0,%0)" : : "r" (start));
  183. start += 16;
  184. } while (start < end);
  185. asm volatile("fdc 0(%0)" : : "r" (end));
  186. asm ("sync");
  187. }
  188. static void parse_elf(void *output)
  189. {
  190. #ifdef CONFIG_64BIT
  191. Elf64_Ehdr ehdr;
  192. Elf64_Phdr *phdrs, *phdr;
  193. #else
  194. Elf32_Ehdr ehdr;
  195. Elf32_Phdr *phdrs, *phdr;
  196. #endif
  197. void *dest;
  198. int i;
  199. memcpy(&ehdr, output, sizeof(ehdr));
  200. if (ehdr.e_ident[EI_MAG0] != ELFMAG0 ||
  201. ehdr.e_ident[EI_MAG1] != ELFMAG1 ||
  202. ehdr.e_ident[EI_MAG2] != ELFMAG2 ||
  203. ehdr.e_ident[EI_MAG3] != ELFMAG3) {
  204. error("Kernel is not a valid ELF file");
  205. return;
  206. }
  207. #ifdef DEBUG
  208. printf("Parsing ELF... ");
  209. #endif
  210. phdrs = malloc(sizeof(*phdrs) * ehdr.e_phnum);
  211. if (!phdrs)
  212. error("Failed to allocate space for phdrs");
  213. memcpy(phdrs, output + ehdr.e_phoff, sizeof(*phdrs) * ehdr.e_phnum);
  214. for (i = 0; i < ehdr.e_phnum; i++) {
  215. phdr = &phdrs[i];
  216. switch (phdr->p_type) {
  217. case PT_LOAD:
  218. dest = (void *)((unsigned long) phdr->p_paddr &
  219. (__PAGE_OFFSET_DEFAULT-1));
  220. memmove(dest, output + phdr->p_offset, phdr->p_filesz);
  221. break;
  222. default:
  223. break;
  224. }
  225. }
  226. free(phdrs);
  227. }
  228. unsigned long decompress_kernel(unsigned int started_wide,
  229. unsigned int command_line,
  230. const unsigned int rd_start,
  231. const unsigned int rd_end)
  232. {
  233. char *output;
  234. unsigned long vmlinux_addr, vmlinux_len;
  235. unsigned long kernel_addr, kernel_len;
  236. #ifdef CONFIG_64BIT
  237. parisc_narrow_firmware = 0;
  238. #endif
  239. set_firmware_width_unlocked();
  240. putchar('D'); /* if you get this D and no more, string storage */
  241. /* in $GLOBAL$ is wrong or %dp is wrong */
  242. puts("ecompressing Linux... ");
  243. /* where the final bits are stored */
  244. kernel_addr = KERNEL_BINARY_TEXT_START;
  245. kernel_len = __pa(SZ_end) - __pa(SZparisc_kernel_start);
  246. if ((unsigned long) &_startcode_end > kernel_addr)
  247. error("Bootcode overlaps kernel code");
  248. /*
  249. * Calculate addr to where the vmlinux ELF file shall be decompressed.
  250. * Assembly code in head.S positioned the stack directly behind bss, so
  251. * leave 2 MB for the stack.
  252. */
  253. vmlinux_addr = (unsigned long) &_ebss + 2*1024*1024;
  254. vmlinux_len = get_unaligned_le32(&output_len);
  255. output = (char *) vmlinux_addr;
  256. /*
  257. * Initialize free_mem_ptr and free_mem_end_ptr.
  258. */
  259. free_mem_ptr = vmlinux_addr + vmlinux_len;
  260. /* Limit memory for bootoader to 1GB */
  261. #define ARTIFICIAL_LIMIT (1*1024*1024*1024)
  262. free_mem_end_ptr = PAGE0->imm_max_mem;
  263. if (free_mem_end_ptr > ARTIFICIAL_LIMIT)
  264. free_mem_end_ptr = ARTIFICIAL_LIMIT;
  265. #ifdef CONFIG_BLK_DEV_INITRD
  266. /* if we have ramdisk this is at end of memory */
  267. if (rd_start && rd_start < free_mem_end_ptr)
  268. free_mem_end_ptr = rd_start;
  269. #endif
  270. if (free_mem_ptr >= free_mem_end_ptr) {
  271. int free_ram;
  272. free_ram = (free_mem_ptr >> 20) + 1;
  273. if (free_ram < 32)
  274. free_ram = 32;
  275. printf("\nKernel requires at least %d MB RAM.\n",
  276. free_ram);
  277. error(NULL);
  278. }
  279. #ifdef DEBUG
  280. printf("\n");
  281. printf("startcode_end = %x\n", &_startcode_end);
  282. printf("commandline = %x\n", command_line);
  283. printf("rd_start = %x\n", rd_start);
  284. printf("rd_end = %x\n", rd_end);
  285. printf("free_ptr = %x\n", free_mem_ptr);
  286. printf("free_ptr_end = %x\n", free_mem_end_ptr);
  287. printf("input_data = %x\n", input_data);
  288. printf("input_len = %x\n", input_len);
  289. printf("output = %x\n", output);
  290. printf("output_len = %x\n", vmlinux_len);
  291. printf("kernel_addr = %x\n", kernel_addr);
  292. printf("kernel_len = %x\n", kernel_len);
  293. #endif
  294. __decompress(input_data, input_len, NULL, NULL,
  295. output, 0, NULL, error);
  296. parse_elf(output);
  297. output = (char *) kernel_addr;
  298. flush_data_cache(output, kernel_len);
  299. printf("done.\nBooting the kernel.\n");
  300. return (unsigned long) output;
  301. }