misc.c 4.0 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
/*
 * misc.c
 * 
 * This is a collection of several routines from gzip-1.0.3 
 * adapted for Linux.
 *
 * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994
 *
 * Modified for ARM Linux by Russell King
 *
 * Nicolas Pitre <nico@visuaide.com>  1999/04/14 :
 *  For this code to run directly from Flash, all constant variables must
 *  be marked with 'const' and all other variables initialized at run-time 
 *  only.  This way all non constant variables will end up in the bss segment,
 *  which should point to addresses in RAM and cleared to 0 on start.
 *  This allows for a much quicker boot time.
 */

unsigned int __machine_arch_type;

21 22
#define _LINUX_STRING_H_

23 24 25
#include <linux/compiler.h>	/* for inline */
#include <linux/types.h>	/* for size_t */
#include <linux/stddef.h>	/* for NULL */
26
#include <linux/linkage.h>
27
#include <asm/string.h>
28 29

#include <asm/unaligned.h>
L
Linus Torvalds 已提交
30 31 32

#ifdef STANDALONE_DEBUG
#define putstr printf
33
#else
L
Linus Torvalds 已提交
34

35 36
static void putstr(const char *ptr);

37
#include <mach/uncompress.h>
L
Linus Torvalds 已提交
38

39
#ifdef CONFIG_DEBUG_ICEDCC
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55

#ifdef CONFIG_CPU_V6

static void icedcc_putc(int ch)
{
	int status, i = 0x4000000;

	do {
		if (--i < 0)
			return;

		asm volatile ("mrc p14, 0, %0, c0, c1, 0" : "=r" (status));
	} while (status & (1 << 29));

	asm("mcr p14, 0, %0, c0, c5, 0" : : "r" (ch));
}
56 57 58 59 60 61 62 63 64 65 66 67

#elif defined(CONFIG_CPU_V7)

static void icedcc_putc(int ch)
{
	asm(
	"wait:	mrc	p14, 0, pc, c0, c1, 0			\n\
		bcs	wait					\n\
		mcr     p14, 0, %0, c0, c5, 0			"
	: : "r" (ch));
}

68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
#elif defined(CONFIG_CPU_XSCALE)

static void icedcc_putc(int ch)
{
	int status, i = 0x4000000;

	do {
		if (--i < 0)
			return;

		asm volatile ("mrc p14, 0, %0, c14, c0, 0" : "=r" (status));
	} while (status & (1 << 28));

	asm("mcr p14, 0, %0, c8, c0, 0" : : "r" (ch));
}
83 84 85

#else

86 87 88 89 90 91 92 93
static void icedcc_putc(int ch)
{
	int status, i = 0x4000000;

	do {
		if (--i < 0)
			return;

94
		asm volatile ("mrc p14, 0, %0, c0, c0, 0" : "=r" (status));
95 96
	} while (status & 2);

97
	asm("mcr p14, 0, %0, c1, c0, 0" : : "r" (ch));
98 99
}

100 101
#endif

102 103
#define putc(ch)	icedcc_putc(ch)
#endif
L
Linus Torvalds 已提交
104

105
static void putstr(const char *ptr)
L
Linus Torvalds 已提交
106
{
107 108 109 110 111 112
	char c;

	while ((c = *ptr++) != '\0') {
		if (c == '\n')
			putc('\r');
		putc(c);
L
Linus Torvalds 已提交
113
	}
114 115

	flush();
L
Linus Torvalds 已提交
116 117 118 119
}

#endif

120
void *memcpy(void *__dest, __const void *__src, size_t __n)
L
Linus Torvalds 已提交
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
{
	int i = 0;
	unsigned char *d = (unsigned char *)__dest, *s = (unsigned char *)__src;

	for (i = __n >> 3; i > 0; i--) {
		*d++ = *s++;
		*d++ = *s++;
		*d++ = *s++;
		*d++ = *s++;
		*d++ = *s++;
		*d++ = *s++;
		*d++ = *s++;
		*d++ = *s++;
	}

	if (__n & 1 << 2) {
		*d++ = *s++;
		*d++ = *s++;
		*d++ = *s++;
		*d++ = *s++;
	}

	if (__n & 1 << 1) {
		*d++ = *s++;
		*d++ = *s++;
	}

	if (__n & 1)
		*d++ = *s++;

	return __dest;
}

/*
 * gzip delarations
 */
extern char input_data[];
extern char input_data_end[];

160 161
unsigned char *output_data;
unsigned long output_ptr;
L
Linus Torvalds 已提交
162

163 164
unsigned long free_mem_ptr;
unsigned long free_mem_end_ptr;
L
Linus Torvalds 已提交
165

166 167 168 169
#ifndef arch_error
#define arch_error(x)
#endif

170
void error(char *x)
L
Linus Torvalds 已提交
171
{
172 173
	arch_error(x);

L
Linus Torvalds 已提交
174 175 176 177 178 179 180
	putstr("\n\n");
	putstr(x);
	putstr("\n\n -- System halted");

	while(1);	/* Halt */
}

181 182 183 184 185
asmlinkage void __div0(void)
{
	error("Attempting division by 0!");
}

186 187
extern void do_decompress(u8 *input, int len, u8 *output, void (*error)(char *x));

L
Linus Torvalds 已提交
188 189
#ifndef STANDALONE_DEBUG

190 191 192 193
unsigned long
decompress_kernel(unsigned long output_start, unsigned long free_mem_ptr_p,
		unsigned long free_mem_ptr_end_p,
		int arch_id)
L
Linus Torvalds 已提交
194
{
195 196 197
	unsigned char *tmp;

	output_data		= (unsigned char *)output_start;
L
Linus Torvalds 已提交
198
	free_mem_ptr		= free_mem_ptr_p;
199
	free_mem_end_ptr	= free_mem_ptr_end_p;
L
Linus Torvalds 已提交
200 201 202 203
	__machine_arch_type	= arch_id;

	arch_decomp_setup();

204 205 206
	tmp = (unsigned char *) (((unsigned long)input_data_end) - 4);
	output_ptr = get_unaligned_le32(tmp);

L
Linus Torvalds 已提交
207
	putstr("Uncompressing Linux...");
208 209
	do_decompress(input_data, input_data_end - input_data,
			output_data, error);
L
Linus Torvalds 已提交
210 211 212 213 214 215 216 217 218 219 220 221
	putstr(" done, booting the kernel.\n");
	return output_ptr;
}
#else

char output_buffer[1500*1024];

int main()
{
	output_data = output_buffer;

	putstr("Uncompressing Linux...");
222 223
	decompress(input_data, input_data_end - input_data,
			NULL, NULL, output_data, NULL, error);
L
Linus Torvalds 已提交
224 225 226 227
	putstr("done.\n");
	return 0;
}
#endif