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 KSEG0 0x80000000 31#define KSEG1 0xa0000000 32 33#define KSEG1ADDR(a) ((((unsigned)(a)) & 0x1fffffffU) | KSEG1) 34 35#undef LZMA_DEBUG 36 37#ifdef LZMA_DEBUG 38# define DBG(f, a...) printf(f, ## a) 39#else 40# define DBG(f, a...) do {} while (0) 41#endif 42 43/* beyond the image end, size not known in advance */ 44extern unsigned char workspace[]; 45 46 47extern void board_init(void); 48 49static CLzmaDecoderState lzma_state; 50static unsigned char *lzma_data; 51static unsigned long lzma_datasize; 52static unsigned long lzma_outsize; 53static unsigned long kernel_la; 54 55static void halt(void) 56{ 57 printf("\nSystem halted!\n"); 58 for(;;); 59} 60 61static __inline__ unsigned char lzma_get_byte(void) 62{ 63 unsigned char c; 64 65 lzma_datasize--; 66 c = *lzma_data++; 67 68 return c; 69} 70 71static int lzma_init_props(void) 72{ 73 unsigned char props[LZMA_PROPERTIES_SIZE]; 74 int res; 75 int i; 76 77 /* read lzma properties */ 78 for (i = 0; i < LZMA_PROPERTIES_SIZE; i++) 79 props[i] = lzma_get_byte(); 80 81 /* read the lower half of uncompressed size in the header */ 82 lzma_outsize = ((SizeT) lzma_get_byte()) + 83 ((SizeT) lzma_get_byte() << 8) + 84 ((SizeT) lzma_get_byte() << 16) + 85 ((SizeT) lzma_get_byte() << 24); 86 87 /* skip rest of the header (upper half of uncompressed size) */ 88 for (i = 0; i < 4; i++) 89 lzma_get_byte(); 90 91 res = LzmaDecodeProperties(&lzma_state.Properties, props, 92 LZMA_PROPERTIES_SIZE); 93 return res; 94} 95 96static int lzma_decompress(unsigned char *outStream) 97{ 98 SizeT ip, op; 99 int ret; 100 101 lzma_state.Probs = (CProb *) workspace; 102 103 ret = LzmaDecode(&lzma_state, lzma_data, lzma_datasize, &ip, outStream, 104 lzma_outsize, &op); 105 106 if (ret != LZMA_RESULT_OK) { 107 int i; 108 109 DBG("LzmaDecode error %d at %08x, osize:%d ip:%d op:%d\n", 110 ret, lzma_data + ip, lzma_outsize, ip, op); 111 112 for (i = 0; i < 16; i++) 113 DBG("%02x ", lzma_data[ip + i]); 114 115 DBG("\n"); 116 } 117 118 return ret; 119} 120 121static void lzma_init_data(void) 122{ 123 extern unsigned char _lzma_data_start[]; 124 extern unsigned char _lzma_data_end[]; 125 126 kernel_la = LOADADDR; 127 lzma_data = _lzma_data_start; 128 lzma_datasize = _lzma_data_end - _lzma_data_start; 129} 130 131void loader_main(unsigned long reg_a0, unsigned long reg_a1, 132 unsigned long reg_a2, unsigned long reg_a3) 133{ 134 void (*kernel_entry) (unsigned long, unsigned long, unsigned long, 135 unsigned long); 136 int res; 137 138 board_init(); 139 140 printf("\n\nOpenWrt kernel loader for BCM63XX\n"); 141 printf("Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>\n"); 142 printf("Copyright (C) 2014 Jonas Gorski <jogo@openwrt.org>\n"); 143 144 lzma_init_data(); 145 146 res = lzma_init_props(); 147 if (res != LZMA_RESULT_OK) { 148 printf("Incorrect LZMA stream properties!\n"); 149 halt(); 150 } 151 152 printf("Decompressing kernel... "); 153 154 res = lzma_decompress((unsigned char *) kernel_la); 155 if (res != LZMA_RESULT_OK) { 156 printf("failed, "); 157 switch (res) { 158 case LZMA_RESULT_DATA_ERROR: 159 printf("data error!\n"); 160 break; 161 default: 162 printf("unknown error %d!\n", res); 163 } 164 halt(); 165 } else { 166 printf("done!\n"); 167 } 168 169 flush_cache(kernel_la, lzma_outsize); 170 171 printf("Starting kernel at %08x...\n\n", kernel_la); 172 173 kernel_entry = (void *) kernel_la; 174 kernel_entry(reg_a0, reg_a1, reg_a2, reg_a3); 175} 176