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