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 <asm/unaligned.h> 9 #include <asm/page.h> 10 #include "sizes.h" 11 12 /* 13 * gzip declarations 14 */ 15 #define STATIC static 16 17 #undef memmove 18 #define memmove memmove 19 #define memzero(s, n) memset((s), 0, (n)) 20 21 #define malloc malloc_gzip 22 #define free free_gzip 23 24 /* Symbols defined by linker scripts */ 25 extern char input_data[]; 26 extern int input_len; 27 /* output_len is inserted by the linker possibly at an unaligned address */ 28 extern __le32 output_len __aligned(1); 29 extern char _text, _end; 30 extern char _bss, _ebss; 31 extern char _startcode_end; 32 extern void startup_continue(void *entry, unsigned long cmdline, 33 unsigned long rd_start, unsigned long rd_end) __noreturn; 34 35 void error(char *m) __noreturn; 36 37 static unsigned long free_mem_ptr; 38 static unsigned long free_mem_end_ptr; 39 40 #ifdef CONFIG_KERNEL_GZIP 41 #include "../../../../lib/decompress_inflate.c" 42 #endif 43 44 #ifdef CONFIG_KERNEL_BZIP2 45 #include "../../../../lib/decompress_bunzip2.c" 46 #endif 47 48 #ifdef CONFIG_KERNEL_LZ4 49 #include "../../../../lib/decompress_unlz4.c" 50 #endif 51 52 #ifdef CONFIG_KERNEL_LZMA 53 #include "../../../../lib/decompress_unlzma.c" 54 #endif 55 56 #ifdef CONFIG_KERNEL_LZO 57 #include "../../../../lib/decompress_unlzo.c" 58 #endif 59 60 #ifdef CONFIG_KERNEL_XZ 61 #include "../../../../lib/decompress_unxz.c" 62 #endif 63 64 void *memmove(void *dest, const void *src, size_t n) 65 { 66 const char *s = src; 67 char *d = dest; 68 69 if (d <= s) { 70 while (n--) 71 *d++ = *s++; 72 } else { 73 d += n; 74 s += n; 75 while (n--) 76 *--d = *--s; 77 } 78 return dest; 79 } 80 81 void *memset(void *s, int c, size_t count) 82 { 83 char *xs = (char *)s; 84 85 while (count--) 86 *xs++ = c; 87 return s; 88 } 89 90 void *memcpy(void *d, const void *s, size_t len) 91 { 92 char *dest = (char *)d; 93 const char *source = (const char *)s; 94 95 while (len--) 96 *dest++ = *source++; 97 return d; 98 } 99 100 size_t strlen(const char *s) 101 { 102 const char *sc; 103 104 for (sc = s; *sc != '\0'; ++sc) 105 ; 106 return sc - s; 107 } 108 109 char *strchr(const char *s, int c) 110 { 111 while (*s) { 112 if (*s == (char)c) 113 return (char *)s; 114 ++s; 115 } 116 return NULL; 117 } 118 119 int puts(const char *s) 120 { 121 const char *nuline = s; 122 123 while ((nuline = strchr(s, '\n')) != NULL) { 124 if (nuline != s) 125 pdc_iodc_print(s, nuline - s); 126 pdc_iodc_print("\r\n", 2); 127 s = nuline + 1; 128 } 129 if (*s != '\0') 130 pdc_iodc_print(s, strlen(s)); 131 132 return 0; 133 } 134 135 static int putchar(int c) 136 { 137 char buf[2]; 138 139 buf[0] = c; 140 buf[1] = '\0'; 141 puts(buf); 142 return c; 143 } 144 145 void __noreturn error(char *x) 146 { 147 puts("\n\n"); 148 puts(x); 149 puts("\n\n -- System halted"); 150 while (1) /* wait forever */ 151 ; 152 } 153 154 static int print_hex(unsigned long num) 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 & 0x0f]; 163 num >>= 4; 164 } while (num); 165 166 str[i--] = 'x'; 167 str[i] = '0'; 168 puts(&str[i]); 169 170 return 0; 171 } 172 173 int printf(const char *fmt, ...) 174 { 175 va_list args; 176 int i = 0; 177 178 va_start(args, fmt); 179 180 while (fmt[i]) { 181 if (fmt[i] != '%') { 182 put: 183 putchar(fmt[i++]); 184 continue; 185 } 186 187 if (fmt[++i] == '%') 188 goto put; 189 ++i; 190 print_hex(va_arg(args, unsigned long)); 191 } 192 193 va_end(args); 194 return 0; 195 } 196 197 /* helper functions for libgcc */ 198 void abort(void) 199 { 200 error("aborted."); 201 } 202 203 #undef malloc 204 void *malloc(size_t size) 205 { 206 return malloc_gzip(size); 207 } 208 209 #undef free 210 void free(void *ptr) 211 { 212 return free_gzip(ptr); 213 } 214 215 216 static void flush_data_cache(char *start, unsigned long length) 217 { 218 char *end = start + length; 219 220 do { 221 asm volatile("fdc 0(%0)" : : "r" (start)); 222 asm volatile("fic 0(%%sr0,%0)" : : "r" (start)); 223 start += 16; 224 } while (start < end); 225 asm volatile("fdc 0(%0)" : : "r" (end)); 226 227 asm ("sync"); 228 } 229 230 unsigned long decompress_kernel(unsigned int started_wide, 231 unsigned int command_line, 232 const unsigned int rd_start, 233 const unsigned int rd_end) 234 { 235 char *output; 236 unsigned long len, len_all; 237 238 #ifdef CONFIG_64BIT 239 parisc_narrow_firmware = 0; 240 #endif 241 242 set_firmware_width_unlocked(); 243 244 putchar('U'); /* if you get this p and no more, string storage */ 245 /* in $GLOBAL$ is wrong or %dp is wrong */ 246 puts("ncompressing ...\n"); 247 248 output = (char *) KERNEL_BINARY_TEXT_START; 249 len_all = __pa(SZ_end) - __pa(SZparisc_kernel_start); 250 251 if ((unsigned long) &_startcode_end > (unsigned long) output) 252 error("Bootcode overlaps kernel code"); 253 254 len = get_unaligned_le32(&output_len); 255 if (len > len_all) 256 error("Output len too big."); 257 else 258 memset(&output[len], 0, len_all - len); 259 260 /* 261 * Initialize free_mem_ptr and free_mem_end_ptr. 262 */ 263 free_mem_ptr = (unsigned long) &_ebss; 264 free_mem_ptr += 2*1024*1024; /* leave 2 MB for stack */ 265 266 /* Limit memory for bootoader to 1GB */ 267 #define ARTIFICIAL_LIMIT (1*1024*1024*1024) 268 free_mem_end_ptr = PAGE0->imm_max_mem; 269 if (free_mem_end_ptr > ARTIFICIAL_LIMIT) 270 free_mem_end_ptr = ARTIFICIAL_LIMIT; 271 272 #ifdef CONFIG_BLK_DEV_INITRD 273 /* if we have ramdisk this is at end of memory */ 274 if (rd_start && rd_start < free_mem_end_ptr) 275 free_mem_end_ptr = rd_start; 276 #endif 277 278 #ifdef DEBUG 279 printf("startcode_end = %x\n", &_startcode_end); 280 printf("commandline = %x\n", command_line); 281 printf("rd_start = %x\n", rd_start); 282 printf("rd_end = %x\n", rd_end); 283 284 printf("free_ptr = %x\n", free_mem_ptr); 285 printf("free_ptr_end = %x\n", free_mem_end_ptr); 286 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", len); 291 printf("output_max = %x\n", len_all); 292 #endif 293 294 __decompress(input_data, input_len, NULL, NULL, 295 output, 0, NULL, error); 296 297 flush_data_cache(output, len); 298 299 printf("Booting kernel ...\n\n"); 300 301 return (unsigned long) output; 302 } 303