summaryrefslogtreecommitdiff
path: root/openwrt/target/linux/image/ar7/src/loader.c
blob: 22b909d7e9936c94e8405f0a334a9e56bf92cb3a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
/* inflate.c -- Not copyrighted 1992 by Mark Adler
   version c10p1, 10 January 1993 */

/*
 * Adapted for booting Linux by Hannu Savolainen 1993
 * based on gzip-1.0.3
 *
 * Nicolas Pitre <nico@visuaide.com>, 1999/04/14 :
 *   Little mods for all variable to reside either into rodata or bss segments
 *   by marking constant variables with 'const' and initializing all the others
 *   at run-time only.  This allows for the kernel uncompressor to run
 *   directly from Flash or ROM memory on embeded systems.
 */

#include <linux/config.h>
#include "gzip.h"
#include "LzmaDecode.h"

/* Function prototypes */
unsigned char get_byte(void);
int tikernelunzip(int,char *[], char *[]);
static int tidecompress(uch *, uch *);

void kernel_entry(int, char *[], char *[]);
void (*ke)(int, char *[], char *[]); /* Gen reference to kernel function */
void (*prnt)(unsigned int, char *);		/* Gen reference to Yamon print function */
void printf(char *ptr);			/* Generate our own printf */

int tikernelunzip(int argc, char *argv[], char *arge[])
{
	extern unsigned int _ftext;
	extern uch kernelimage[];
	uch *in, *out;
	int status;

	printf("Launching kernel decompressor.\n");

	out = (unsigned char *) LOADADDR;
	in = &(kernelimage[0]);

	status = tidecompress(in, out);

	if (status == 0) {
		printf("Kernel decompressor was successful ... launching kernel.\n");

		ke = ( void(*)(int, char *[],char*[]))kernel_entry;
		(*ke)(argc,argv,arge);

		return (0);
	} else {
		printf("Error in decompression.\n");
		return(1);
	}
}

#if 0
char hex[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
void print_i(int i)
{
	int j;
	char buf[11];

	buf[0] = '0';
	buf[1] = 'x';
	buf[10] = 0;
	
	for (j = 0; j < 8; j++)
	{
		buf[2 + 7 - j] = hex[i & 0xf];
		i = i >> 4;
	}

	printf(buf);
}
#endif

int tidecompress(uch *indata, uch *outdata)
{
	extern unsigned int workspace;
	extern unsigned char kernelimage[], kernelimage_end[];
	unsigned int i;  /* temp value */
	unsigned int lc; /* literal context bits */
	unsigned int lp; /* literal pos state bits */
	unsigned int pb; /* pos state bits */
	unsigned int osize; /* uncompressed size */
	unsigned int wsize; /* window size */
	unsigned int insize = kernelimage_end - kernelimage;
	int status;
	
	output_ptr = 0;
	output_data = outdata;
	input_data = indata;

	/* lzma args */
	i = get_byte();
	lc = i % 9, i = i / 9;
	lp = i % 5, pb = i / 5;

	/* skip rest of the LZMA coder property */
	for (i = 0; i < 4; i++)
		get_byte();
	
	/* read the lower half of uncompressed size in the header */
	osize = ((unsigned int)get_byte()) +
		((unsigned int)get_byte() << 8) +
		((unsigned int)get_byte() << 16) +
		((unsigned int)get_byte() << 24);

	/* skip rest of the header (upper half of uncompressed size) */
	for (i = 0; i < 4; i++)
		get_byte();
	
	i = 0;
	wsize = (LZMA_BASE_SIZE + (LZMA_LIT_SIZE << (lc + lp))) * sizeof(CProb);

	if ((status = LzmaDecode((unsigned char *) &workspace, wsize, lc, lp, pb,
		indata + 13, insize - 13, (unsigned char *) output_data, osize, &i)) == LZMA_RESULT_OK)
			return 0;

	return status;
}


void printf(char *ptr)
{
	unsigned int *tempptr = (unsigned int  *)0x90000534;
	prnt = ( void (*)(unsigned int, char *)) *tempptr;
	(*prnt)(0,ptr);
}

unsigned char get_byte()
{
	unsigned char c;
	
	c = *input_data;
	input_data++;

	return c;
}