misc.c 3.8 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
static void putstr(const char *ptr);
33
extern void error(char *x);
34

35
#include <mach/uncompress.h>
L
Linus Torvalds 已提交
36

37
#ifdef CONFIG_DEBUG_ICEDCC
38

39
#if defined(CONFIG_CPU_V6) || defined(CONFIG_CPU_V6K)
40 41 42 43 44 45 46 47 48 49 50 51 52 53

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));
}
54 55 56 57 58 59 60 61 62 63 64 65

#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));
}

66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
#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));
}
81 82 83

#else

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

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

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

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

98 99
#endif

100 101
#define putc(ch)	icedcc_putc(ch)
#endif
L
Linus Torvalds 已提交
102

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

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

	flush();
L
Linus Torvalds 已提交
114 115 116
}


117
void *memcpy(void *__dest, __const void *__src, size_t __n)
L
Linus Torvalds 已提交
118 119 120 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
{
	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[];

157 158
unsigned char *output_data;
unsigned long output_ptr;
L
Linus Torvalds 已提交
159

160 161
unsigned long free_mem_ptr;
unsigned long free_mem_end_ptr;
L
Linus Torvalds 已提交
162

163 164 165 166
#ifndef arch_error
#define arch_error(x)
#endif

167
void error(char *x)
L
Linus Torvalds 已提交
168
{
169 170
	arch_error(x);

L
Linus Torvalds 已提交
171 172 173 174 175 176 177
	putstr("\n\n");
	putstr(x);
	putstr("\n\n -- System halted");

	while(1);	/* Halt */
}

178 179 180 181 182
asmlinkage void __div0(void)
{
	error("Attempting division by 0!");
}

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

L
Linus Torvalds 已提交
185

186 187 188 189
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 已提交
190
{
191 192 193
	unsigned char *tmp;

	output_data		= (unsigned char *)output_start;
L
Linus Torvalds 已提交
194
	free_mem_ptr		= free_mem_ptr_p;
195
	free_mem_end_ptr	= free_mem_ptr_end_p;
L
Linus Torvalds 已提交
196 197 198 199
	__machine_arch_type	= arch_id;

	arch_decomp_setup();

200 201 202
	tmp = (unsigned char *) (((unsigned long)input_data_end) - 4);
	output_ptr = get_unaligned_le32(tmp);

L
Linus Torvalds 已提交
203
	putstr("Uncompressing Linux...");
204 205
	do_decompress(input_data, input_data_end - input_data,
			output_data, error);
L
Linus Torvalds 已提交
206 207 208
	putstr(" done, booting the kernel.\n");
	return output_ptr;
}