Merge tag 'char-misc-4.15-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/gregk...
[sfrench/cifs-2.6.git] / arch / parisc / boot / compressed / misc.c
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 }