1/* MN10300 Miscellaneous helper routines for kernel decompressor 2 * 3 * Copyright (C) 2007 Matsushita Electric Industrial Co., Ltd. 4 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. 5 * Modified by David Howells (dhowells@redhat.com) 6 * - Derived from arch/x86/boot/compressed/misc_32.c 7 * 8 * This program is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU General Public Licence 10 * as published by the Free Software Foundation; either version 11 * 2 of the Licence, or (at your option) any later version. 12 */ 13#include <linux/compiler.h> 14#include <asm/serial-regs.h> 15#include "misc.h" 16 17#ifndef CONFIG_GDBSTUB_ON_TTYSx 18/* display 'Uncompressing Linux... ' messages on ttyS0 or ttyS1 */ 19#define CYG_DEV_BASE 0xA6FB0000 20 21#define CYG_DEV_THR (*((volatile __u8*)(CYG_DEV_BASE + 0x00))) 22#define CYG_DEV_MCR (*((volatile __u8*)(CYG_DEV_BASE + 0x10))) 23#define SIO_MCR_DTR 0x01 24#define SIO_MCR_RTS 0x02 25#define CYG_DEV_LSR (*((volatile __u8*)(CYG_DEV_BASE + 0x14))) 26#define SIO_LSR_THRE 0x20 /* transmitter holding register empty */ 27#define SIO_LSR_TEMT 0x40 /* transmitter register empty */ 28#define CYG_DEV_MSR (*((volatile __u8*)(CYG_DEV_BASE + 0x18))) 29#define SIO_MSR_CTS 0x10 /* clear to send */ 30#define SIO_MSR_DSR 0x20 /* data set ready */ 31 32#define LSR_WAIT_FOR(STATE) \ 33 do { while (!(CYG_DEV_LSR & SIO_LSR_##STATE)) {} } while (0) 34#define FLOWCTL_QUERY(LINE) \ 35 ({ CYG_DEV_MSR & SIO_MSR_##LINE; }) 36#define FLOWCTL_WAIT_FOR(LINE) \ 37 do { while (!(CYG_DEV_MSR & SIO_MSR_##LINE)) {} } while (0) 38#define FLOWCTL_CLEAR(LINE) \ 39 do { CYG_DEV_MCR &= ~SIO_MCR_##LINE; } while (0) 40#define FLOWCTL_SET(LINE) \ 41 do { CYG_DEV_MCR |= SIO_MCR_##LINE; } while (0) 42#endif 43 44/* 45 * gzip declarations 46 */ 47 48#define OF(args) args 49#define STATIC static 50 51#undef memset 52#undef memcpy 53 54static inline void *memset(const void *s, int c, size_t n) 55{ 56 int i; 57 char *ss = (char *) s; 58 59 for (i = 0; i < n; i++) 60 ss[i] = c; 61 return (void *)s; 62} 63 64#define memzero(s, n) memset((s), 0, (n)) 65 66static inline void *memcpy(void *__dest, const void *__src, size_t __n) 67{ 68 int i; 69 const char *s = __src; 70 char *d = __dest; 71 72 for (i = 0; i < __n; i++) 73 d[i] = s[i]; 74 return __dest; 75} 76 77typedef unsigned char uch; 78typedef unsigned short ush; 79typedef unsigned long ulg; 80 81#define WSIZE 0x8000 /* Window size must be at least 32k, and a power of 82 * two */ 83 84static uch *inbuf; /* input buffer */ 85static uch window[WSIZE]; /* sliding window buffer */ 86 87static unsigned insize; /* valid bytes in inbuf */ 88static unsigned inptr; /* index of next byte to be processed in inbuf */ 89static unsigned outcnt; /* bytes in output buffer */ 90 91/* gzip flag byte */ 92#define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */ 93#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */ 94#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ 95#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ 96#define COMMENT 0x10 /* bit 4 set: file comment present */ 97#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */ 98#define RESERVED 0xC0 /* bit 6,7: reserved */ 99 100/* Diagnostic functions */ 101#ifdef DEBUG 102# define Assert(cond, msg) { if (!(cond)) error(msg); } 103# define Trace(x) fprintf x 104# define Tracev(x) { if (verbose) fprintf x ; } 105# define Tracevv(x) { if (verbose > 1) fprintf x ; } 106# define Tracec(c, x) { if (verbose && (c)) fprintf x ; } 107# define Tracecv(c, x) { if (verbose > 1 && (c)) fprintf x ; } 108#else 109# define Assert(cond, msg) 110# define Trace(x) 111# define Tracev(x) 112# define Tracevv(x) 113# define Tracec(c, x) 114# define Tracecv(c, x) 115#endif 116 117static int fill_inbuf(void); 118static void flush_window(void); 119static void error(const char *) __attribute__((noreturn)); 120static void kputs(const char *); 121 122static inline unsigned char get_byte(void) 123{ 124 unsigned char ch = inptr < insize ? inbuf[inptr++] : fill_inbuf(); 125 126 return ch; 127} 128 129/* 130 * This is set up by the setup-routine at boot-time 131 */ 132#define EXT_MEM_K (*(unsigned short *)0x90002) 133#ifndef STANDARD_MEMORY_BIOS_CALL 134#define ALT_MEM_K (*(unsigned long *) 0x901e0) 135#endif 136#define SCREEN_INFO (*(struct screen_info *)0x90000) 137 138static long bytes_out; 139static uch *output_data; 140static unsigned long output_ptr; 141 142 143static unsigned long free_mem_ptr = (unsigned long) &end; 144static unsigned long free_mem_end_ptr = (unsigned long) &end + 0x90000; 145 146#define INPLACE_MOVE_ROUTINE 0x1000 147#define LOW_BUFFER_START 0x2000 148#define LOW_BUFFER_END 0x90000 149#define LOW_BUFFER_SIZE (LOW_BUFFER_END - LOW_BUFFER_START) 150#define HEAP_SIZE 0x3000 151static int high_loaded; 152static uch *high_buffer_start /* = (uch *)(((ulg)&end) + HEAP_SIZE)*/; 153 154static char *vidmem = (char *)0xb8000; 155static int lines, cols; 156 157#define BOOTLOADER_INFLATE 158#include "../../../../lib/inflate.c" 159 160static inline void scroll(void) 161{ 162 int i; 163 164 memcpy(vidmem, vidmem + cols * 2, (lines - 1) * cols * 2); 165 for (i = (lines - 1) * cols * 2; i < lines * cols * 2; i += 2) 166 vidmem[i] = ' '; 167} 168 169static inline void kputchar(unsigned char ch) 170{ 171#ifdef CONFIG_MN10300_UNIT_ASB2305 172 while (SC0STR & SC01STR_TBF) 173 continue; 174 175 if (ch == 0x0a) { 176 SC0TXB = 0x0d; 177 while (SC0STR & SC01STR_TBF) 178 continue; 179 } 180 181 SC0TXB = ch; 182 183#else 184 while (SC1STR & SC01STR_TBF) 185 continue; 186 187 if (ch == 0x0a) { 188 SC1TXB = 0x0d; 189 while (SC1STR & SC01STR_TBF) 190 continue; 191 } 192 193 SC1TXB = ch; 194 195#endif 196} 197 198static void kputs(const char *s) 199{ 200#ifdef CONFIG_DEBUG_DECOMPRESS_KERNEL 201#ifndef CONFIG_GDBSTUB_ON_TTYSx 202 char ch; 203 204 FLOWCTL_SET(DTR); 205 206 while (*s) { 207 LSR_WAIT_FOR(THRE); 208 209 ch = *s++; 210 if (ch == 0x0a) { 211 CYG_DEV_THR = 0x0d; 212 LSR_WAIT_FOR(THRE); 213 } 214 CYG_DEV_THR = ch; 215 } 216 217 FLOWCTL_CLEAR(DTR); 218#else 219 220 for (; *s; s++) 221 kputchar(*s); 222 223#endif 224#endif /* CONFIG_DEBUG_DECOMPRESS_KERNEL */ 225} 226 227/* =========================================================================== 228 * Fill the input buffer. This is called only when the buffer is empty 229 * and at least one byte is really needed. 230 */ 231static int fill_inbuf() 232{ 233 if (insize != 0) 234 error("ran out of input data\n"); 235 236 inbuf = input_data; 237 insize = input_len; 238 inptr = 1; 239 return inbuf[0]; 240} 241 242/* =========================================================================== 243 * Write the output window window[0..outcnt-1] and update crc and bytes_out. 244 * (Used for the decompressed data only.) 245 */ 246static void flush_window_low(void) 247{ 248 ulg c = crc; /* temporary variable */ 249 unsigned n; 250 uch *in, *out, ch; 251 252 in = window; 253 out = &output_data[output_ptr]; 254 for (n = 0; n < outcnt; n++) { 255 ch = *out++ = *in++; 256 c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8); 257 } 258 crc = c; 259 bytes_out += (ulg)outcnt; 260 output_ptr += (ulg)outcnt; 261 outcnt = 0; 262} 263 264static void flush_window_high(void) 265{ 266 ulg c = crc; /* temporary variable */ 267 unsigned n; 268 uch *in, ch; 269 in = window; 270 for (n = 0; n < outcnt; n++) { 271 ch = *output_data++ = *in++; 272 if ((ulg) output_data == LOW_BUFFER_END) 273 output_data = high_buffer_start; 274 c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8); 275 } 276 crc = c; 277 bytes_out += (ulg)outcnt; 278 outcnt = 0; 279} 280 281static void flush_window(void) 282{ 283 if (high_loaded) 284 flush_window_high(); 285 else 286 flush_window_low(); 287} 288 289static void error(const char *x) 290{ 291 kputs("\n\n"); 292 kputs(x); 293 kputs("\n\n -- System halted"); 294 295 while (1) 296 /* Halt */; 297} 298 299#define STACK_SIZE (4096) 300 301long user_stack[STACK_SIZE]; 302 303struct { 304 long *a; 305 short b; 306} stack_start = { &user_stack[STACK_SIZE], 0 }; 307 308void setup_normal_output_buffer(void) 309{ 310#ifdef STANDARD_MEMORY_BIOS_CALL 311 if (EXT_MEM_K < 1024) 312 error("Less than 2MB of memory.\n"); 313#else 314 if ((ALT_MEM_K > EXT_MEM_K ? ALT_MEM_K : EXT_MEM_K) < 1024) 315 error("Less than 2MB of memory.\n"); 316#endif 317 output_data = (char *) 0x100000; /* Points to 1M */ 318} 319 320struct moveparams { 321 uch *low_buffer_start; 322 int lcount; 323 uch *high_buffer_start; 324 int hcount; 325}; 326 327void setup_output_buffer_if_we_run_high(struct moveparams *mv) 328{ 329 high_buffer_start = (uch *)(((ulg) &end) + HEAP_SIZE); 330#ifdef STANDARD_MEMORY_BIOS_CALL 331 if (EXT_MEM_K < (3 * 1024)) 332 error("Less than 4MB of memory.\n"); 333#else 334 if ((ALT_MEM_K > EXT_MEM_K ? ALT_MEM_K : EXT_MEM_K) < (3 * 1024)) 335 error("Less than 4MB of memory.\n"); 336#endif 337 mv->low_buffer_start = output_data = (char *) LOW_BUFFER_START; 338 high_loaded = 1; 339 free_mem_end_ptr = (long) high_buffer_start; 340 if (0x100000 + LOW_BUFFER_SIZE > (ulg) high_buffer_start) { 341 high_buffer_start = (uch *)(0x100000 + LOW_BUFFER_SIZE); 342 mv->hcount = 0; /* say: we need not to move high_buffer */ 343 } else { 344 mv->hcount = -1; 345 } 346 mv->high_buffer_start = high_buffer_start; 347} 348 349void close_output_buffer_if_we_run_high(struct moveparams *mv) 350{ 351 mv->lcount = bytes_out; 352 if (bytes_out > LOW_BUFFER_SIZE) { 353 mv->lcount = LOW_BUFFER_SIZE; 354 if (mv->hcount) 355 mv->hcount = bytes_out - LOW_BUFFER_SIZE; 356 } else { 357 mv->hcount = 0; 358 } 359} 360 361#undef DEBUGFLAG 362#ifdef DEBUGFLAG 363int debugflag; 364#endif 365 366int decompress_kernel(struct moveparams *mv) 367{ 368#ifdef DEBUGFLAG 369 while (!debugflag) 370 barrier(); 371#endif 372 373 output_data = (char *) CONFIG_KERNEL_TEXT_ADDRESS; 374 375 makecrc(); 376 kputs("Uncompressing Linux... "); 377 gunzip(); 378 kputs("Ok, booting the kernel.\n"); 379 return 0; 380} 381