root/arch/parisc/boot/compressed/misc.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. startup_continue
  2. memset
  3. memcpy
  4. strlen
  5. strchr
  6. puts
  7. putchar
  8. error
  9. print_num
  10. printf
  11. abort
  12. malloc
  13. free
  14. flush_data_cache
  15. parse_elf
  16. decompress_kernel

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

/* [<][>][^][v][top][bottom][index][help] */