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