Input: wm97xx: add new AC97 bus support
[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 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 }