xref: /openbmc/linux/arch/arm/boot/compressed/misc.c (revision 200b7a8dc09504bc0aedac567a307a6e533f39e5)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * misc.c
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  * This is a collection of several routines from gzip-1.0.3
51da177e4SLinus Torvalds  * adapted for Linux.
61da177e4SLinus Torvalds  *
71da177e4SLinus Torvalds  * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994
81da177e4SLinus Torvalds  *
91da177e4SLinus Torvalds  * Modified for ARM Linux by Russell King
101da177e4SLinus Torvalds  *
111da177e4SLinus Torvalds  * Nicolas Pitre <nico@visuaide.com>  1999/04/14 :
121da177e4SLinus Torvalds  *  For this code to run directly from Flash, all constant variables must
131da177e4SLinus Torvalds  *  be marked with 'const' and all other variables initialized at run-time
141da177e4SLinus Torvalds  *  only.  This way all non constant variables will end up in the bss segment,
151da177e4SLinus Torvalds  *  which should point to addresses in RAM and cleared to 0 on start.
161da177e4SLinus Torvalds  *  This allows for a much quicker boot time.
171da177e4SLinus Torvalds  */
181da177e4SLinus Torvalds 
191da177e4SLinus Torvalds unsigned int __machine_arch_type;
201da177e4SLinus Torvalds 
21e7db7b42SAlbin Tonnerre #define _LINUX_STRING_H_
22e7db7b42SAlbin Tonnerre 
23aa0d3bb7SRusty Russell #include <linux/compiler.h>	/* for inline */
24aa0d3bb7SRusty Russell #include <linux/types.h>	/* for size_t */
25aa0d3bb7SRusty Russell #include <linux/stddef.h>	/* for NULL */
26aa0d3bb7SRusty Russell #include <asm/string.h>
27e7db7b42SAlbin Tonnerre #include <linux/linkage.h>
28e7db7b42SAlbin Tonnerre 
29e7db7b42SAlbin Tonnerre #include <asm/unaligned.h>
301da177e4SLinus Torvalds 
311da177e4SLinus Torvalds #ifdef STANDALONE_DEBUG
321da177e4SLinus Torvalds #define putstr printf
33a081568dSRussell King #else
34a081568dSRussell King 
35a081568dSRussell King static void putstr(const char *ptr);
36a081568dSRussell King 
37a09e64fbSRussell King #include <mach/uncompress.h>
381da177e4SLinus Torvalds 
391da177e4SLinus Torvalds #ifdef CONFIG_DEBUG_ICEDCC
407d95ded9STony Lindgren 
417d95ded9STony Lindgren #ifdef CONFIG_CPU_V6
427d95ded9STony Lindgren 
437d95ded9STony Lindgren static void icedcc_putc(int ch)
447d95ded9STony Lindgren {
457d95ded9STony Lindgren 	int status, i = 0x4000000;
467d95ded9STony Lindgren 
477d95ded9STony Lindgren 	do {
487d95ded9STony Lindgren 		if (--i < 0)
497d95ded9STony Lindgren 			return;
507d95ded9STony Lindgren 
517d95ded9STony Lindgren 		asm volatile ("mrc p14, 0, %0, c0, c1, 0" : "=r" (status));
527d95ded9STony Lindgren 	} while (status & (1 << 29));
537d95ded9STony Lindgren 
547d95ded9STony Lindgren 	asm("mcr p14, 0, %0, c0, c5, 0" : : "r" (ch));
557d95ded9STony Lindgren }
56*200b7a8dSTony Lindgren 
57*200b7a8dSTony Lindgren #elif defined(CONFIG_CPU_V7)
58*200b7a8dSTony Lindgren 
59*200b7a8dSTony Lindgren static void icedcc_putc(int ch)
60*200b7a8dSTony Lindgren {
61*200b7a8dSTony Lindgren 	asm(
62*200b7a8dSTony Lindgren 	"wait:	mrc	p14, 0, pc, c0, c1, 0			\n\
63*200b7a8dSTony Lindgren 		bcs	wait					\n\
64*200b7a8dSTony Lindgren 		mcr     p14, 0, %0, c0, c5, 0			"
65*200b7a8dSTony Lindgren 	: : "r" (ch));
66*200b7a8dSTony Lindgren }
67*200b7a8dSTony Lindgren 
68c633c3cfSJean-Christop PLAGNIOL-VILLARD #elif defined(CONFIG_CPU_XSCALE)
69c633c3cfSJean-Christop PLAGNIOL-VILLARD 
70c633c3cfSJean-Christop PLAGNIOL-VILLARD static void icedcc_putc(int ch)
71c633c3cfSJean-Christop PLAGNIOL-VILLARD {
72c633c3cfSJean-Christop PLAGNIOL-VILLARD 	int status, i = 0x4000000;
73c633c3cfSJean-Christop PLAGNIOL-VILLARD 
74c633c3cfSJean-Christop PLAGNIOL-VILLARD 	do {
75c633c3cfSJean-Christop PLAGNIOL-VILLARD 		if (--i < 0)
76c633c3cfSJean-Christop PLAGNIOL-VILLARD 			return;
77c633c3cfSJean-Christop PLAGNIOL-VILLARD 
78c633c3cfSJean-Christop PLAGNIOL-VILLARD 		asm volatile ("mrc p14, 0, %0, c14, c0, 0" : "=r" (status));
79c633c3cfSJean-Christop PLAGNIOL-VILLARD 	} while (status & (1 << 28));
80c633c3cfSJean-Christop PLAGNIOL-VILLARD 
81c633c3cfSJean-Christop PLAGNIOL-VILLARD 	asm("mcr p14, 0, %0, c8, c0, 0" : : "r" (ch));
82c633c3cfSJean-Christop PLAGNIOL-VILLARD }
837d95ded9STony Lindgren 
847d95ded9STony Lindgren #else
857d95ded9STony Lindgren 
86de4533a0SRussell King static void icedcc_putc(int ch)
87de4533a0SRussell King {
88de4533a0SRussell King 	int status, i = 0x4000000;
89de4533a0SRussell King 
90de4533a0SRussell King 	do {
91de4533a0SRussell King 		if (--i < 0)
92de4533a0SRussell King 			return;
93de4533a0SRussell King 
94b2556da5SUwe Zeisberger 		asm volatile ("mrc p14, 0, %0, c0, c0, 0" : "=r" (status));
95de4533a0SRussell King 	} while (status & 2);
96de4533a0SRussell King 
97b2556da5SUwe Zeisberger 	asm("mcr p14, 0, %0, c1, c0, 0" : : "r" (ch));
98de4533a0SRussell King }
99de4533a0SRussell King 
1007d95ded9STony Lindgren #endif
1017d95ded9STony Lindgren 
102a081568dSRussell King #define putc(ch)	icedcc_putc(ch)
103a081568dSRussell King #endif
1041da177e4SLinus Torvalds 
105a081568dSRussell King static void putstr(const char *ptr)
1061da177e4SLinus Torvalds {
107a081568dSRussell King 	char c;
108a081568dSRussell King 
109a081568dSRussell King 	while ((c = *ptr++) != '\0') {
110a081568dSRussell King 		if (c == '\n')
111a081568dSRussell King 			putc('\r');
112a081568dSRussell King 		putc(c);
1131da177e4SLinus Torvalds 	}
114a081568dSRussell King 
115a081568dSRussell King 	flush();
1161da177e4SLinus Torvalds }
1171da177e4SLinus Torvalds 
1181da177e4SLinus Torvalds #endif
1191da177e4SLinus Torvalds 
1201da177e4SLinus Torvalds #define __ptr_t void *
1211da177e4SLinus Torvalds 
12259f0cb0fSRussell King #define memzero(s,n) __memzero(s,n)
12359f0cb0fSRussell King 
1241da177e4SLinus Torvalds /*
1251da177e4SLinus Torvalds  * Optimised C version of memzero for the ARM.
1261da177e4SLinus Torvalds  */
1271da177e4SLinus Torvalds void __memzero (__ptr_t s, size_t n)
1281da177e4SLinus Torvalds {
1291da177e4SLinus Torvalds 	union { void *vp; unsigned long *ulp; unsigned char *ucp; } u;
1301da177e4SLinus Torvalds 	int i;
1311da177e4SLinus Torvalds 
1321da177e4SLinus Torvalds 	u.vp = s;
1331da177e4SLinus Torvalds 
1341da177e4SLinus Torvalds 	for (i = n >> 5; i > 0; i--) {
1351da177e4SLinus Torvalds 		*u.ulp++ = 0;
1361da177e4SLinus Torvalds 		*u.ulp++ = 0;
1371da177e4SLinus Torvalds 		*u.ulp++ = 0;
1381da177e4SLinus Torvalds 		*u.ulp++ = 0;
1391da177e4SLinus Torvalds 		*u.ulp++ = 0;
1401da177e4SLinus Torvalds 		*u.ulp++ = 0;
1411da177e4SLinus Torvalds 		*u.ulp++ = 0;
1421da177e4SLinus Torvalds 		*u.ulp++ = 0;
1431da177e4SLinus Torvalds 	}
1441da177e4SLinus Torvalds 
1451da177e4SLinus Torvalds 	if (n & 1 << 4) {
1461da177e4SLinus Torvalds 		*u.ulp++ = 0;
1471da177e4SLinus Torvalds 		*u.ulp++ = 0;
1481da177e4SLinus Torvalds 		*u.ulp++ = 0;
1491da177e4SLinus Torvalds 		*u.ulp++ = 0;
1501da177e4SLinus Torvalds 	}
1511da177e4SLinus Torvalds 
1521da177e4SLinus Torvalds 	if (n & 1 << 3) {
1531da177e4SLinus Torvalds 		*u.ulp++ = 0;
1541da177e4SLinus Torvalds 		*u.ulp++ = 0;
1551da177e4SLinus Torvalds 	}
1561da177e4SLinus Torvalds 
1571da177e4SLinus Torvalds 	if (n & 1 << 2)
1581da177e4SLinus Torvalds 		*u.ulp++ = 0;
1591da177e4SLinus Torvalds 
1601da177e4SLinus Torvalds 	if (n & 1 << 1) {
1611da177e4SLinus Torvalds 		*u.ucp++ = 0;
1621da177e4SLinus Torvalds 		*u.ucp++ = 0;
1631da177e4SLinus Torvalds 	}
1641da177e4SLinus Torvalds 
1651da177e4SLinus Torvalds 	if (n & 1)
1661da177e4SLinus Torvalds 		*u.ucp++ = 0;
1671da177e4SLinus Torvalds }
1681da177e4SLinus Torvalds 
1691da177e4SLinus Torvalds static inline __ptr_t memcpy(__ptr_t __dest, __const __ptr_t __src,
1701da177e4SLinus Torvalds 			    size_t __n)
1711da177e4SLinus Torvalds {
1721da177e4SLinus Torvalds 	int i = 0;
1731da177e4SLinus Torvalds 	unsigned char *d = (unsigned char *)__dest, *s = (unsigned char *)__src;
1741da177e4SLinus Torvalds 
1751da177e4SLinus Torvalds 	for (i = __n >> 3; i > 0; i--) {
1761da177e4SLinus Torvalds 		*d++ = *s++;
1771da177e4SLinus Torvalds 		*d++ = *s++;
1781da177e4SLinus Torvalds 		*d++ = *s++;
1791da177e4SLinus Torvalds 		*d++ = *s++;
1801da177e4SLinus Torvalds 		*d++ = *s++;
1811da177e4SLinus Torvalds 		*d++ = *s++;
1821da177e4SLinus Torvalds 		*d++ = *s++;
1831da177e4SLinus Torvalds 		*d++ = *s++;
1841da177e4SLinus Torvalds 	}
1851da177e4SLinus Torvalds 
1861da177e4SLinus Torvalds 	if (__n & 1 << 2) {
1871da177e4SLinus Torvalds 		*d++ = *s++;
1881da177e4SLinus Torvalds 		*d++ = *s++;
1891da177e4SLinus Torvalds 		*d++ = *s++;
1901da177e4SLinus Torvalds 		*d++ = *s++;
1911da177e4SLinus Torvalds 	}
1921da177e4SLinus Torvalds 
1931da177e4SLinus Torvalds 	if (__n & 1 << 1) {
1941da177e4SLinus Torvalds 		*d++ = *s++;
1951da177e4SLinus Torvalds 		*d++ = *s++;
1961da177e4SLinus Torvalds 	}
1971da177e4SLinus Torvalds 
1981da177e4SLinus Torvalds 	if (__n & 1)
1991da177e4SLinus Torvalds 		*d++ = *s++;
2001da177e4SLinus Torvalds 
2011da177e4SLinus Torvalds 	return __dest;
2021da177e4SLinus Torvalds }
2031da177e4SLinus Torvalds 
2041da177e4SLinus Torvalds /*
2051da177e4SLinus Torvalds  * gzip delarations
2061da177e4SLinus Torvalds  */
2071da177e4SLinus Torvalds #define STATIC static
2081da177e4SLinus Torvalds 
2091da177e4SLinus Torvalds /* Diagnostic functions */
2101da177e4SLinus Torvalds #ifdef DEBUG
2111da177e4SLinus Torvalds #  define Assert(cond,msg) {if(!(cond)) error(msg);}
2121da177e4SLinus Torvalds #  define Trace(x) fprintf x
2131da177e4SLinus Torvalds #  define Tracev(x) {if (verbose) fprintf x ;}
2141da177e4SLinus Torvalds #  define Tracevv(x) {if (verbose>1) fprintf x ;}
2151da177e4SLinus Torvalds #  define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
2161da177e4SLinus Torvalds #  define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
2171da177e4SLinus Torvalds #else
2181da177e4SLinus Torvalds #  define Assert(cond,msg)
2191da177e4SLinus Torvalds #  define Trace(x)
2201da177e4SLinus Torvalds #  define Tracev(x)
2211da177e4SLinus Torvalds #  define Tracevv(x)
2221da177e4SLinus Torvalds #  define Tracec(c,x)
2231da177e4SLinus Torvalds #  define Tracecv(c,x)
2241da177e4SLinus Torvalds #endif
2251da177e4SLinus Torvalds 
2261da177e4SLinus Torvalds static void error(char *m);
2271da177e4SLinus Torvalds 
2281da177e4SLinus Torvalds extern char input_data[];
2291da177e4SLinus Torvalds extern char input_data_end[];
2301da177e4SLinus Torvalds 
231e7db7b42SAlbin Tonnerre static unsigned char *output_data;
232e7db7b42SAlbin Tonnerre static unsigned long output_ptr;
2331da177e4SLinus Torvalds 
2341da177e4SLinus Torvalds static void error(char *m);
2351da177e4SLinus Torvalds 
2361da177e4SLinus Torvalds static void putstr(const char *);
2371da177e4SLinus Torvalds 
238e7db7b42SAlbin Tonnerre static unsigned long free_mem_ptr;
239e7db7b42SAlbin Tonnerre static unsigned long free_mem_end_ptr;
2401da177e4SLinus Torvalds 
2412d6ffccaSThomas Petazzoni #ifdef STANDALONE_DEBUG
2422d6ffccaSThomas Petazzoni #define NO_INFLATE_MALLOC
2432d6ffccaSThomas Petazzoni #endif
2442d6ffccaSThomas Petazzoni 
2452d6ffccaSThomas Petazzoni #define ARCH_HAS_DECOMP_WDOG
2461da177e4SLinus Torvalds 
247e7db7b42SAlbin Tonnerre #ifdef CONFIG_KERNEL_GZIP
248e7db7b42SAlbin Tonnerre #include "../../../../lib/decompress_inflate.c"
249e7db7b42SAlbin Tonnerre #endif
2501da177e4SLinus Torvalds 
251e7db7b42SAlbin Tonnerre #ifdef CONFIG_KERNEL_LZO
252e7db7b42SAlbin Tonnerre #include "../../../../lib/decompress_unlzo.c"
253e7db7b42SAlbin Tonnerre #endif
2541da177e4SLinus Torvalds 
255f8c905d3SBen Dooks #ifndef arch_error
256f8c905d3SBen Dooks #define arch_error(x)
257f8c905d3SBen Dooks #endif
258f8c905d3SBen Dooks 
2591da177e4SLinus Torvalds static void error(char *x)
2601da177e4SLinus Torvalds {
261f8c905d3SBen Dooks 	arch_error(x);
262f8c905d3SBen Dooks 
2631da177e4SLinus Torvalds 	putstr("\n\n");
2641da177e4SLinus Torvalds 	putstr(x);
2651da177e4SLinus Torvalds 	putstr("\n\n -- System halted");
2661da177e4SLinus Torvalds 
2671da177e4SLinus Torvalds 	while(1);	/* Halt */
2681da177e4SLinus Torvalds }
2691da177e4SLinus Torvalds 
270e7db7b42SAlbin Tonnerre asmlinkage void __div0(void)
271e7db7b42SAlbin Tonnerre {
272e7db7b42SAlbin Tonnerre 	error("Attempting division by 0!");
273e7db7b42SAlbin Tonnerre }
274e7db7b42SAlbin Tonnerre 
2751da177e4SLinus Torvalds #ifndef STANDALONE_DEBUG
2761da177e4SLinus Torvalds 
277e7db7b42SAlbin Tonnerre unsigned long
278e7db7b42SAlbin Tonnerre decompress_kernel(unsigned long output_start, unsigned long free_mem_ptr_p,
279e7db7b42SAlbin Tonnerre 		unsigned long free_mem_ptr_end_p,
2801da177e4SLinus Torvalds 		int arch_id)
2811da177e4SLinus Torvalds {
282e7db7b42SAlbin Tonnerre 	unsigned char *tmp;
283e7db7b42SAlbin Tonnerre 
284e7db7b42SAlbin Tonnerre 	output_data		= (unsigned char *)output_start;
2851da177e4SLinus Torvalds 	free_mem_ptr		= free_mem_ptr_p;
2862d6ffccaSThomas Petazzoni 	free_mem_end_ptr	= free_mem_ptr_end_p;
2871da177e4SLinus Torvalds 	__machine_arch_type	= arch_id;
2881da177e4SLinus Torvalds 
2891da177e4SLinus Torvalds 	arch_decomp_setup();
2901da177e4SLinus Torvalds 
291e7db7b42SAlbin Tonnerre 	tmp = (unsigned char *) (((unsigned long)input_data_end) - 4);
292e7db7b42SAlbin Tonnerre 	output_ptr = get_unaligned_le32(tmp);
293e7db7b42SAlbin Tonnerre 
2941da177e4SLinus Torvalds 	putstr("Uncompressing Linux...");
295e7db7b42SAlbin Tonnerre 	decompress(input_data, input_data_end - input_data,
296e7db7b42SAlbin Tonnerre 			NULL, NULL, output_data, NULL, error);
2971da177e4SLinus Torvalds 	putstr(" done, booting the kernel.\n");
2981da177e4SLinus Torvalds 	return output_ptr;
2991da177e4SLinus Torvalds }
3001da177e4SLinus Torvalds #else
3011da177e4SLinus Torvalds 
3021da177e4SLinus Torvalds char output_buffer[1500*1024];
3031da177e4SLinus Torvalds 
3041da177e4SLinus Torvalds int main()
3051da177e4SLinus Torvalds {
3061da177e4SLinus Torvalds 	output_data = output_buffer;
3071da177e4SLinus Torvalds 
3081da177e4SLinus Torvalds 	putstr("Uncompressing Linux...");
309e7db7b42SAlbin Tonnerre 	decompress(input_data, input_data_end - input_data,
310e7db7b42SAlbin Tonnerre 			NULL, NULL, output_data, NULL, error);
3111da177e4SLinus Torvalds 	putstr("done.\n");
3121da177e4SLinus Torvalds 	return 0;
3131da177e4SLinus Torvalds }
3141da177e4SLinus Torvalds #endif
315