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