Root/target/linux/ar71xx/image/lzma-loader/src/loader.c

1/*
2 * LZMA compressed kernel loader for Atheros AR7XXX/AR9XXX based boards
3 *
4 * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
5 *
6 * Some parts of this code was based on the OpenWrt specific lzma-loader
7 * for the BCM47xx and ADM5120 based boards:
8 * Copyright (C) 2004 Manuel Novoa III (mjn3@codepoet.org)
9 * Copyright (C) 2005 Mineharu Takahara <mtakahar@yahoo.com>
10 * Copyright (C) 2005 by Oleg I. Vdovikin <oleg@cs.msu.su>
11 *
12 * The image_header structure has been taken from the U-Boot project.
13 * (C) Copyright 2008 Semihalf
14 * (C) Copyright 2000-2005
15 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
16 *
17 * This program is free software; you can redistribute it and/or modify it
18 * under the terms of the GNU General Public License version 2 as published
19 * by the Free Software Foundation.
20 */
21
22#include <stddef.h>
23#include <stdint.h>
24
25#include "config.h"
26#include "cache.h"
27#include "printf.h"
28#include "LzmaDecode.h"
29
30#define AR71XX_FLASH_START 0x1f000000
31#define AR71XX_FLASH_END 0x1fe00000
32
33#define KSEG0 0x80000000
34#define KSEG1 0xa0000000
35
36#define KSEG1ADDR(a) ((((unsigned)(a)) & 0x1fffffffU) | KSEG1)
37
38#undef LZMA_DEBUG
39
40#ifdef LZMA_DEBUG
41# define DBG(f, a...) printf(f, ## a)
42#else
43# define DBG(f, a...) do {} while (0)
44#endif
45
46#define IH_MAGIC_OKLI 0x4f4b4c49 /* 'OKLI' */
47
48#define IH_NMLEN 32 /* Image Name Length */
49
50typedef struct image_header {
51    uint32_t ih_magic; /* Image Header Magic Number */
52    uint32_t ih_hcrc; /* Image Header CRC Checksum */
53    uint32_t ih_time; /* Image Creation Timestamp */
54    uint32_t ih_size; /* Image Data Size */
55    uint32_t ih_load; /* Data Load Address */
56    uint32_t ih_ep; /* Entry Point Address */
57    uint32_t ih_dcrc; /* Image Data CRC Checksum */
58    uint8_t ih_os; /* Operating System */
59    uint8_t ih_arch; /* CPU architecture */
60    uint8_t ih_type; /* Image Type */
61    uint8_t ih_comp; /* Compression Type */
62    uint8_t ih_name[IH_NMLEN]; /* Image Name */
63} image_header_t;
64
65/* beyond the image end, size not known in advance */
66extern unsigned char workspace[];
67extern void board_init(void);
68
69static CLzmaDecoderState lzma_state;
70static unsigned char *lzma_data;
71static unsigned long lzma_datasize;
72static unsigned long lzma_outsize;
73static unsigned long kernel_la;
74
75#ifdef CONFIG_KERNEL_CMDLINE
76#define kernel_argc 1
77static const char kernel_cmdline[] = CONFIG_KERNEL_CMDLINE;
78static const char *kernel_argv[] = {
79    kernel_cmdline,
80    NULL,
81};
82#endif /* CONFIG_KERNEL_CMDLINE */
83
84static void halt(void)
85{
86    printf("\nSystem halted!\n");
87    for(;;);
88}
89
90static __inline__ unsigned long get_be32(void *buf)
91{
92    unsigned char *p = buf;
93
94    return (((unsigned long) p[0] << 24) +
95            ((unsigned long) p[1] << 16) +
96            ((unsigned long) p[2] << 8) +
97            (unsigned long) p[3]);
98}
99
100static __inline__ unsigned char lzma_get_byte(void)
101{
102    unsigned char c;
103
104    lzma_datasize--;
105    c = *lzma_data++;
106
107    return c;
108}
109
110static int lzma_init_props(void)
111{
112    unsigned char props[LZMA_PROPERTIES_SIZE];
113    int res;
114    int i;
115
116    /* read lzma properties */
117    for (i = 0; i < LZMA_PROPERTIES_SIZE; i++)
118        props[i] = lzma_get_byte();
119
120    /* read the lower half of uncompressed size in the header */
121    lzma_outsize = ((SizeT) lzma_get_byte()) +
122               ((SizeT) lzma_get_byte() << 8) +
123               ((SizeT) lzma_get_byte() << 16) +
124               ((SizeT) lzma_get_byte() << 24);
125
126    /* skip rest of the header (upper half of uncompressed size) */
127    for (i = 0; i < 4; i++)
128        lzma_get_byte();
129
130    res = LzmaDecodeProperties(&lzma_state.Properties, props,
131                    LZMA_PROPERTIES_SIZE);
132    return res;
133}
134
135static int lzma_decompress(unsigned char *outStream)
136{
137    SizeT ip, op;
138    int ret;
139
140    lzma_state.Probs = (CProb *) workspace;
141
142    ret = LzmaDecode(&lzma_state, lzma_data, lzma_datasize, &ip, outStream,
143             lzma_outsize, &op);
144
145    if (ret != LZMA_RESULT_OK) {
146        int i;
147
148        DBG("LzmaDecode error %d at %08x, osize:%d ip:%d op:%d\n",
149            ret, lzma_data + ip, lzma_outsize, ip, op);
150
151        for (i = 0; i < 16; i++)
152            DBG("%02x ", lzma_data[ip + i]);
153
154        DBG("\n");
155    }
156
157    return ret;
158}
159
160#if (LZMA_WRAPPER)
161static void lzma_init_data(void)
162{
163    extern unsigned char _lzma_data_start[];
164    extern unsigned char _lzma_data_end[];
165
166    kernel_la = LOADADDR;
167    lzma_data = _lzma_data_start;
168    lzma_datasize = _lzma_data_end - _lzma_data_start;
169}
170#else
171static void lzma_init_data(void)
172{
173    struct image_header *hdr = NULL;
174    unsigned char *flash_base;
175    unsigned long flash_ofs;
176    unsigned long kernel_ofs;
177    unsigned long kernel_size;
178
179    flash_base = (unsigned char *) KSEG1ADDR(AR71XX_FLASH_START);
180
181    printf("Looking for OpenWrt image... ");
182
183    for (flash_ofs = CONFIG_FLASH_OFFS;
184         flash_ofs <= (CONFIG_FLASH_OFFS + CONFIG_FLASH_MAX);
185         flash_ofs += CONFIG_FLASH_STEP) {
186        unsigned long magic;
187        unsigned char *p;
188
189        p = flash_base + flash_ofs;
190        magic = get_be32(p);
191        if (magic == IH_MAGIC_OKLI) {
192            hdr = (struct image_header *) p;
193            break;
194        }
195    }
196
197    if (hdr == NULL) {
198        printf("not found!\n");
199        halt();
200    }
201
202    printf("found at 0x%08x\n", flash_base + flash_ofs);
203
204    kernel_ofs = sizeof(struct image_header);
205    kernel_size = get_be32(&hdr->ih_size);
206    kernel_la = get_be32(&hdr->ih_load);
207
208    lzma_data = flash_base + flash_ofs + kernel_ofs;
209    lzma_datasize = kernel_size;
210}
211#endif /* (LZMA_WRAPPER) */
212
213void loader_main(unsigned long reg_a0, unsigned long reg_a1,
214         unsigned long reg_a2, unsigned long reg_a3)
215{
216    void (*kernel_entry) (unsigned long, unsigned long, unsigned long,
217                  unsigned long);
218    int res;
219
220    board_init();
221
222    printf("\n\nOpenWrt kernel loader for AR7XXX/AR9XXX\n");
223    printf("Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>\n");
224
225    lzma_init_data();
226
227    res = lzma_init_props();
228    if (res != LZMA_RESULT_OK) {
229        printf("Incorrect LZMA stream properties!\n");
230        halt();
231    }
232
233    printf("Decompressing kernel... ");
234
235    res = lzma_decompress((unsigned char *) kernel_la);
236    if (res != LZMA_RESULT_OK) {
237        printf("failed, ");
238        switch (res) {
239        case LZMA_RESULT_DATA_ERROR:
240            printf("data error!\n");
241            break;
242        default:
243            printf("unknown error %d!\n", res);
244        }
245        halt();
246    } else {
247        printf("done!\n");
248    }
249
250    flush_cache(kernel_la, lzma_outsize);
251
252    printf("Starting kernel at %08x...\n\n", kernel_la);
253
254#ifdef CONFIG_KERNEL_CMDLINE
255    reg_a0 = kernel_argc;
256    reg_a1 = (unsigned long) kernel_argv;
257    reg_a2 = 0;
258    reg_a3 = 0;
259#endif
260
261    kernel_entry = (void *) kernel_la;
262    kernel_entry(reg_a0, reg_a1, reg_a2, reg_a3);
263}
264

Archive Download this file



interactive