bmips: add new target
[openwrt/openwrt.git] / target / linux / bmips / image / lzma-loader / src / loader.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * LZMA compressed kernel loader for Atheros AR7XXX/AR9XXX based boards
4 *
5 * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
6 *
7 * Some parts of this code was based on the OpenWrt specific lzma-loader
8 * for the BCM47xx and ADM5120 based boards:
9 * Copyright (C) 2004 Manuel Novoa III (mjn3@codepoet.org)
10 * Copyright (C) 2005 Mineharu Takahara <mtakahar@yahoo.com>
11 * Copyright (C) 2005 by Oleg I. Vdovikin <oleg@cs.msu.su>
12 *
13 * The image_header structure has been taken from the U-Boot project.
14 * (C) Copyright 2008 Semihalf
15 * (C) Copyright 2000-2005
16 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
17 */
18
19 #include <stddef.h>
20 #include <stdint.h>
21
22 #include "config.h"
23 #include "cache.h"
24 #include "printf.h"
25 #include "LzmaDecode.h"
26
27 #define KSEG0 0x80000000
28 #define KSEG1 0xa0000000
29
30 #define KSEG1ADDR(a) ((((unsigned)(a)) & 0x1fffffffU) | KSEG1)
31
32 #undef LZMA_DEBUG
33
34 #ifdef LZMA_DEBUG
35 # define DBG(f, a...) printf(f, ## a)
36 #else
37 # define DBG(f, a...) do {} while (0)
38 #endif
39
40 /* beyond the image end, size not known in advance */
41 extern unsigned char workspace[];
42
43
44 static CLzmaDecoderState lzma_state;
45 static unsigned char *lzma_data;
46 static unsigned long lzma_datasize;
47 static unsigned long lzma_outsize;
48 static unsigned long kernel_la;
49
50 static void halt(void)
51 {
52 printf("\nSystem halted!\n");
53 for(;;);
54 }
55
56 static __inline__ unsigned char lzma_get_byte(void)
57 {
58 unsigned char c;
59
60 lzma_datasize--;
61 c = *lzma_data++;
62
63 return c;
64 }
65
66 static int lzma_init_props(void)
67 {
68 unsigned char props[LZMA_PROPERTIES_SIZE];
69 int res;
70 int i;
71
72 /* read lzma properties */
73 for (i = 0; i < LZMA_PROPERTIES_SIZE; i++)
74 props[i] = lzma_get_byte();
75
76 /* read the lower half of uncompressed size in the header */
77 lzma_outsize = ((SizeT) lzma_get_byte()) +
78 ((SizeT) lzma_get_byte() << 8) +
79 ((SizeT) lzma_get_byte() << 16) +
80 ((SizeT) lzma_get_byte() << 24);
81
82 /* skip rest of the header (upper half of uncompressed size) */
83 for (i = 0; i < 4; i++)
84 lzma_get_byte();
85
86 res = LzmaDecodeProperties(&lzma_state.Properties, props,
87 LZMA_PROPERTIES_SIZE);
88 return res;
89 }
90
91 static int lzma_decompress(unsigned char *outStream)
92 {
93 SizeT ip, op;
94 int ret;
95
96 lzma_state.Probs = (CProb *) workspace;
97
98 ret = LzmaDecode(&lzma_state, lzma_data, lzma_datasize, &ip, outStream,
99 lzma_outsize, &op);
100
101 if (ret != LZMA_RESULT_OK) {
102 int i;
103
104 DBG("LzmaDecode error %d at %08x, osize:%d ip:%d op:%d\n",
105 ret, lzma_data + ip, lzma_outsize, ip, op);
106
107 for (i = 0; i < 16; i++)
108 DBG("%02x ", lzma_data[ip + i]);
109
110 DBG("\n");
111 }
112
113 return ret;
114 }
115
116 static void lzma_init_data(void)
117 {
118 extern unsigned char _lzma_data_start[];
119 extern unsigned char _lzma_data_end[];
120
121 kernel_la = LOADADDR;
122 lzma_data = _lzma_data_start;
123 lzma_datasize = _lzma_data_end - _lzma_data_start;
124 }
125
126 void loader_main(unsigned long reg_a0, unsigned long reg_a1,
127 unsigned long reg_a2, unsigned long reg_a3)
128 {
129 void (*kernel_entry) (unsigned long, unsigned long, unsigned long,
130 unsigned long);
131 int res;
132
133 printf("\n\nOpenWrt kernel loader for BMIPS\n");
134 printf("Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>\n");
135 printf("Copyright (C) 2014 Jonas Gorski <jogo@openwrt.org>\n");
136 printf("Copyright (C) 2020 Alvaro Fernandez Rojas <noltari@gmail.com>\n");
137
138 lzma_init_data();
139
140 res = lzma_init_props();
141 if (res != LZMA_RESULT_OK) {
142 printf("Incorrect LZMA stream properties!\n");
143 halt();
144 }
145
146 printf("Decompressing kernel... ");
147
148 res = lzma_decompress((unsigned char *) kernel_la);
149 if (res != LZMA_RESULT_OK) {
150 printf("failed, ");
151 switch (res) {
152 case LZMA_RESULT_DATA_ERROR:
153 printf("data error!\n");
154 break;
155 default:
156 printf("unknown error %d!\n", res);
157 }
158 halt();
159 } else {
160 printf("done!\n");
161 }
162
163 flush_cache(kernel_la, lzma_outsize);
164
165 printf("Starting kernel at %08x...\n\n", kernel_la);
166
167 kernel_entry = (void *) kernel_la;
168 kernel_entry(reg_a0, reg_a1, reg_a2, reg_a3);
169 }