summaryrefslogtreecommitdiffstats
path: root/target/linux/brcm47xx/patches-2.6.23/500-lzma_initramfs.patch
blob: a2e4c2b85c40af805f957ab07aa4b6fa2695aaa7 (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
--- a/scripts/gen_initramfs_list.sh
+++ b/scripts/gen_initramfs_list.sh
@@ -287,7 +287,7 @@
 	if [ "${is_cpio_compressed}" = "compressed" ]; then
 		cat ${cpio_tfile} > ${output_file}
 	else
-		cat ${cpio_tfile} | gzip -f -9 - > ${output_file}
+		lzma e -lc1 -lp2 -pb2 ${cpio_tfile} ${output_file}
 	fi
 	[ -z ${cpio_file} ] && rm ${cpio_tfile}
 fi
--- a/init/initramfs.c
+++ b/init/initramfs.c
@@ -441,6 +441,69 @@
 	outcnt = 0;
 }
 
+#include <linux/LzmaDecode.h>
+static int __init lzma_unzip(void)
+{
+	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 char *workspace;
+	unsigned char* outputbuffer;
+	unsigned int outsizeProcessed = 0;
+	int workspace_size;
+	int res;
+
+	// lzma args
+	i = get_byte();
+	lc = i % 9, i = i / 9;
+	lp = i % 5, pb = i / 5;
+
+	// skip dictionary size
+	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();
+
+	workspace_size = ((LZMA_BASE_SIZE + (LZMA_LIT_SIZE << (lc + lp))) * sizeof(CProb)) + 100;
+	printk( KERN_NOTICE "initramfs: LZMA lc=%d,lp=%d,pb=%d,origSize=%d\n",
+	lc,lp,pb,osize);
+	outputbuffer = kmalloc(osize, GFP_KERNEL);
+	if (outputbuffer == 0) {
+		printk(KERN_ERR "initramfs: Couldn't allocate lzma output buffer\n");
+		return -1;
+	}
+
+	workspace = kmalloc(workspace_size, GFP_KERNEL);
+	if (workspace == NULL) {
+		printk(KERN_ERR "initramfs: Couldn't allocate lzma workspace\n");
+		return -1;
+	}
+
+	res = LzmaDecode(workspace, workspace_size, lc, lp, pb, inbuf + inptr, insize - inptr, outputbuffer, osize, &outsizeProcessed);
+	if( res != 0 ) {
+		panic( KERN_ERR "initramfs: Lzma decode failure\n");
+		return -1;
+	}
+
+	flush_buffer(outputbuffer, outsizeProcessed);
+	inptr = insize;
+
+	kfree(outputbuffer);
+	kfree(workspace);
+	state = Reset;
+	return 0;
+}
+
 static char * __init unpack_to_rootfs(char *buf, unsigned len, int check_only)
 {
 	int written;
@@ -475,12 +538,28 @@
 		inptr = 0;
 		outcnt = 0;		/* bytes in output buffer */
 		bytes_out = 0;
-		crc = (ulg)0xffffffffL; /* shift register contents */
-		makecrc();
-		gunzip();
-		if (state != Reset)
+		if( inbuf[0] == 037 && ((inbuf[1] == 0213) || (inbuf[1] == 0236)))
+		{
+		   printk( KERN_NOTICE "detected gzip initramfs\n");
+		   crc = (ulg)0xffffffffL; /* shift register contents */
+		   makecrc();
+		   gunzip();
+		   if (state != Reset)
 			error("junk in gzipped archive");
-		this_header = saved_offset + inptr;
+		}
+		else if(!memcmp(inbuf+1, "\x00\x00\x80\x00", 4)) /* FIXME: hardcoded dictionary size */
+		{
+		   printk( KERN_NOTICE "detected lzma initramfs\n");
+		   lzma_unzip();
+		}
+		else
+		{
+		   // skip forward ?
+		   crc = (ulg)0xffffffffL; /* shift register contents */
+		   makecrc();
+		   gunzip();
+		}
+	        this_header = saved_offset + inptr;
 		buf += inptr;
 		len -= inptr;
 	}