| /* | |
| * Definitions and wrapper functions for kernel decompressor | |
| * | |
| * (C) 2017 Helge Deller <deller@gmx.de> | |
| */ | |
| #include <linux/uaccess.h> | |
| #include <asm/unaligned.h> | |
| #include <asm/page.h> | |
| #include "sizes.h" | |
| /* | |
| * gzip declarations | |
| */ | |
| #define STATIC static | |
| #undef memmove | |
| #define memmove memmove | |
| #define memzero(s, n) memset((s), 0, (n)) | |
| #define malloc malloc_gzip | |
| #define free free_gzip | |
| /* Symbols defined by linker scripts */ | |
| extern char input_data[]; | |
| extern int input_len; | |
| /* output_len is inserted by the linker possibly at an unaligned address */ | |
| extern __le32 output_len __aligned(1); | |
| extern char _text, _end; | |
| extern char _bss, _ebss; | |
| extern char _startcode_end; | |
| extern void startup_continue(void *entry, unsigned long cmdline, | |
| unsigned long rd_start, unsigned long rd_end) __noreturn; | |
| void error(char *m) __noreturn; | |
| static unsigned long free_mem_ptr; | |
| static unsigned long free_mem_end_ptr; | |
| #ifdef CONFIG_KERNEL_GZIP | |
| #include "../../../../lib/decompress_inflate.c" | |
| #endif | |
| #ifdef CONFIG_KERNEL_BZIP2 | |
| #include "../../../../lib/decompress_bunzip2.c" | |
| #endif | |
| #ifdef CONFIG_KERNEL_LZ4 | |
| #include "../../../../lib/decompress_unlz4.c" | |
| #endif | |
| #ifdef CONFIG_KERNEL_LZMA | |
| #include "../../../../lib/decompress_unlzma.c" | |
| #endif | |
| #ifdef CONFIG_KERNEL_LZO | |
| #include "../../../../lib/decompress_unlzo.c" | |
| #endif | |
| #ifdef CONFIG_KERNEL_XZ | |
| #include "../../../../lib/decompress_unxz.c" | |
| #endif | |
| void *memmove(void *dest, const void *src, size_t n) | |
| { | |
| const char *s = src; | |
| char *d = dest; | |
| if (d <= s) { | |
| while (n--) | |
| *d++ = *s++; | |
| } else { | |
| d += n; | |
| s += n; | |
| while (n--) | |
| *--d = *--s; | |
| } | |
| return dest; | |
| } | |
| void *memset(void *s, int c, size_t count) | |
| { | |
| char *xs = (char *)s; | |
| while (count--) | |
| *xs++ = c; | |
| return s; | |
| } | |
| void *memcpy(void *d, const void *s, size_t len) | |
| { | |
| char *dest = (char *)d; | |
| const char *source = (const char *)s; | |
| while (len--) | |
| *dest++ = *source++; | |
| return d; | |
| } | |
| size_t strlen(const char *s) | |
| { | |
| const char *sc; | |
| for (sc = s; *sc != '\0'; ++sc) | |
| ; | |
| return sc - s; | |
| } | |
| char *strchr(const char *s, int c) | |
| { | |
| while (*s) { | |
| if (*s == (char)c) | |
| return (char *)s; | |
| ++s; | |
| } | |
| return NULL; | |
| } | |
| int puts(const char *s) | |
| { | |
| const char *nuline = s; | |
| while ((nuline = strchr(s, '\n')) != NULL) { | |
| if (nuline != s) | |
| pdc_iodc_print(s, nuline - s); | |
| pdc_iodc_print("\r\n", 2); | |
| s = nuline + 1; | |
| } | |
| if (*s != '\0') | |
| pdc_iodc_print(s, strlen(s)); | |
| return 0; | |
| } | |
| static int putchar(int c) | |
| { | |
| char buf[2]; | |
| buf[0] = c; | |
| buf[1] = '\0'; | |
| puts(buf); | |
| return c; | |
| } | |
| void __noreturn error(char *x) | |
| { | |
| puts("\n\n"); | |
| puts(x); | |
| puts("\n\n -- System halted"); | |
| while (1) /* wait forever */ | |
| ; | |
| } | |
| static int print_hex(unsigned long num) | |
| { | |
| const char hex[] = "0123456789abcdef"; | |
| char str[40]; | |
| int i = sizeof(str)-1; | |
| str[i--] = '\0'; | |
| do { | |
| str[i--] = hex[num & 0x0f]; | |
| num >>= 4; | |
| } while (num); | |
| str[i--] = 'x'; | |
| str[i] = '0'; | |
| puts(&str[i]); | |
| return 0; | |
| } | |
| int printf(const char *fmt, ...) | |
| { | |
| va_list args; | |
| int i = 0; | |
| va_start(args, fmt); | |
| while (fmt[i]) { | |
| if (fmt[i] != '%') { | |
| put: | |
| putchar(fmt[i++]); | |
| continue; | |
| } | |
| if (fmt[++i] == '%') | |
| goto put; | |
| ++i; | |
| print_hex(va_arg(args, unsigned long)); | |
| } | |
| va_end(args); | |
| return 0; | |
| } | |
| /* helper functions for libgcc */ | |
| void abort(void) | |
| { | |
| error("aborted."); | |
| } | |
| #undef malloc | |
| void *malloc(size_t size) | |
| { | |
| return malloc_gzip(size); | |
| } | |
| #undef free | |
| void free(void *ptr) | |
| { | |
| return free_gzip(ptr); | |
| } | |
| static void flush_data_cache(char *start, unsigned long length) | |
| { | |
| char *end = start + length; | |
| do { | |
| asm volatile("fdc 0(%0)" : : "r" (start)); | |
| asm volatile("fic 0(%%sr0,%0)" : : "r" (start)); | |
| start += 16; | |
| } while (start < end); | |
| asm volatile("fdc 0(%0)" : : "r" (end)); | |
| asm ("sync"); | |
| } | |
| unsigned long decompress_kernel(unsigned int started_wide, | |
| unsigned int command_line, | |
| const unsigned int rd_start, | |
| const unsigned int rd_end) | |
| { | |
| char *output; | |
| unsigned long len, len_all; | |
| #ifdef CONFIG_64BIT | |
| parisc_narrow_firmware = 0; | |
| #endif | |
| set_firmware_width_unlocked(); | |
| putchar('U'); /* if you get this p and no more, string storage */ | |
| /* in $GLOBAL$ is wrong or %dp is wrong */ | |
| puts("ncompressing ...\n"); | |
| output = (char *) KERNEL_BINARY_TEXT_START; | |
| len_all = __pa(SZ_end) - __pa(SZparisc_kernel_start); | |
| if ((unsigned long) &_startcode_end > (unsigned long) output) | |
| error("Bootcode overlaps kernel code"); | |
| len = get_unaligned_le32(&output_len); | |
| if (len > len_all) | |
| error("Output len too big."); | |
| else | |
| memset(&output[len], 0, len_all - len); | |
| /* | |
| * Initialize free_mem_ptr and free_mem_end_ptr. | |
| */ | |
| free_mem_ptr = (unsigned long) &_ebss; | |
| free_mem_ptr += 2*1024*1024; /* leave 2 MB for stack */ | |
| /* Limit memory for bootoader to 1GB */ | |
| #define ARTIFICIAL_LIMIT (1*1024*1024*1024) | |
| free_mem_end_ptr = PAGE0->imm_max_mem; | |
| if (free_mem_end_ptr > ARTIFICIAL_LIMIT) | |
| free_mem_end_ptr = ARTIFICIAL_LIMIT; | |
| #ifdef CONFIG_BLK_DEV_INITRD | |
| /* if we have ramdisk this is at end of memory */ | |
| if (rd_start && rd_start < free_mem_end_ptr) | |
| free_mem_end_ptr = rd_start; | |
| #endif | |
| #ifdef DEBUG | |
| printf("startcode_end = %x\n", &_startcode_end); | |
| printf("commandline = %x\n", command_line); | |
| printf("rd_start = %x\n", rd_start); | |
| printf("rd_end = %x\n", rd_end); | |
| printf("free_ptr = %x\n", free_mem_ptr); | |
| printf("free_ptr_end = %x\n", free_mem_end_ptr); | |
| printf("input_data = %x\n", input_data); | |
| printf("input_len = %x\n", input_len); | |
| printf("output = %x\n", output); | |
| printf("output_len = %x\n", len); | |
| printf("output_max = %x\n", len_all); | |
| #endif | |
| __decompress(input_data, input_len, NULL, NULL, | |
| output, 0, NULL, error); | |
| flush_data_cache(output, len); | |
| printf("Booting kernel ...\n\n"); | |
| return (unsigned long) output; | |
| } |