xref: /openbmc/linux/arch/parisc/boot/compressed/misc.c (revision bf070bb0)
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