Path: blob/master/arch/mn10300/boot/compressed/misc.c
17479 views
/* MN10300 Miscellaneous helper routines for kernel decompressor1*2* Copyright (C) 2007 Matsushita Electric Industrial Co., Ltd.3* Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.4* Modified by David Howells ([email protected])5* - Derived from arch/x86/boot/compressed/misc_32.c6*7* This program is free software; you can redistribute it and/or8* modify it under the terms of the GNU General Public Licence9* as published by the Free Software Foundation; either version10* 2 of the Licence, or (at your option) any later version.11*/12#include <linux/compiler.h>13#include <asm/serial-regs.h>14#include "misc.h"1516#ifndef CONFIG_GDBSTUB_ON_TTYSx17/* display 'Uncompressing Linux... ' messages on ttyS0 or ttyS1 */18#if 1 /* ttyS0 */19#define CYG_DEV_BASE 0xA6FB000020#else /* ttyS1 */21#define CYG_DEV_BASE 0xA6FC000022#endif2324#define CYG_DEV_THR (*((volatile __u8*)(CYG_DEV_BASE + 0x00)))25#define CYG_DEV_MCR (*((volatile __u8*)(CYG_DEV_BASE + 0x10)))26#define SIO_MCR_DTR 0x0127#define SIO_MCR_RTS 0x0228#define CYG_DEV_LSR (*((volatile __u8*)(CYG_DEV_BASE + 0x14)))29#define SIO_LSR_THRE 0x20 /* transmitter holding register empty */30#define SIO_LSR_TEMT 0x40 /* transmitter register empty */31#define CYG_DEV_MSR (*((volatile __u8*)(CYG_DEV_BASE + 0x18)))32#define SIO_MSR_CTS 0x10 /* clear to send */33#define SIO_MSR_DSR 0x20 /* data set ready */3435#define LSR_WAIT_FOR(STATE) \36do { while (!(CYG_DEV_LSR & SIO_LSR_##STATE)) {} } while (0)37#define FLOWCTL_QUERY(LINE) \38({ CYG_DEV_MSR & SIO_MSR_##LINE; })39#define FLOWCTL_WAIT_FOR(LINE) \40do { while (!(CYG_DEV_MSR & SIO_MSR_##LINE)) {} } while (0)41#define FLOWCTL_CLEAR(LINE) \42do { CYG_DEV_MCR &= ~SIO_MCR_##LINE; } while (0)43#define FLOWCTL_SET(LINE) \44do { CYG_DEV_MCR |= SIO_MCR_##LINE; } while (0)45#endif4647/*48* gzip declarations49*/5051#define OF(args) args52#define STATIC static5354#undef memset55#undef memcpy5657static inline void *memset(const void *s, int c, size_t n)58{59int i;60char *ss = (char *) s;6162for (i = 0; i < n; i++)63ss[i] = c;64return (void *)s;65}6667#define memzero(s, n) memset((s), 0, (n))6869static inline void *memcpy(void *__dest, const void *__src, size_t __n)70{71int i;72const char *s = __src;73char *d = __dest;7475for (i = 0; i < __n; i++)76d[i] = s[i];77return __dest;78}7980typedef unsigned char uch;81typedef unsigned short ush;82typedef unsigned long ulg;8384#define WSIZE 0x8000 /* Window size must be at least 32k, and a power of85* two */8687static uch *inbuf; /* input buffer */88static uch window[WSIZE]; /* sliding window buffer */8990static unsigned insize; /* valid bytes in inbuf */91static unsigned inptr; /* index of next byte to be processed in inbuf */92static unsigned outcnt; /* bytes in output buffer */9394/* gzip flag byte */95#define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */96#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */97#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */98#define ORIG_NAME 0x08 /* bit 3 set: original file name present */99#define COMMENT 0x10 /* bit 4 set: file comment present */100#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */101#define RESERVED 0xC0 /* bit 6,7: reserved */102103/* Diagnostic functions */104#ifdef DEBUG105# define Assert(cond, msg) { if (!(cond)) error(msg); }106# define Trace(x) fprintf x107# define Tracev(x) { if (verbose) fprintf x ; }108# define Tracevv(x) { if (verbose > 1) fprintf x ; }109# define Tracec(c, x) { if (verbose && (c)) fprintf x ; }110# define Tracecv(c, x) { if (verbose > 1 && (c)) fprintf x ; }111#else112# define Assert(cond, msg)113# define Trace(x)114# define Tracev(x)115# define Tracevv(x)116# define Tracec(c, x)117# define Tracecv(c, x)118#endif119120static int fill_inbuf(void);121static void flush_window(void);122static void error(const char *) __attribute__((noreturn));123static void kputs(const char *);124125static inline unsigned char get_byte(void)126{127unsigned char ch = inptr < insize ? inbuf[inptr++] : fill_inbuf();128129#if 0130char hex[3];131hex[0] = ((ch & 0x0f) > 9) ?132((ch & 0x0f) + 'A' - 0xa) : ((ch & 0x0f) + '0');133hex[1] = ((ch >> 4) > 9) ?134((ch >> 4) + 'A' - 0xa) : ((ch >> 4) + '0');135hex[2] = 0;136kputs(hex);137#endif138return ch;139}140141/*142* This is set up by the setup-routine at boot-time143*/144#define EXT_MEM_K (*(unsigned short *)0x90002)145#ifndef STANDARD_MEMORY_BIOS_CALL146#define ALT_MEM_K (*(unsigned long *) 0x901e0)147#endif148#define SCREEN_INFO (*(struct screen_info *)0x90000)149150static long bytes_out;151static uch *output_data;152static unsigned long output_ptr;153154155static unsigned long free_mem_ptr = (unsigned long) &end;156static unsigned long free_mem_end_ptr = (unsigned long) &end + 0x90000;157158#define INPLACE_MOVE_ROUTINE 0x1000159#define LOW_BUFFER_START 0x2000160#define LOW_BUFFER_END 0x90000161#define LOW_BUFFER_SIZE (LOW_BUFFER_END - LOW_BUFFER_START)162#define HEAP_SIZE 0x3000163static int high_loaded;164static uch *high_buffer_start /* = (uch *)(((ulg)&end) + HEAP_SIZE)*/;165166static char *vidmem = (char *)0xb8000;167static int lines, cols;168169#define BOOTLOADER_INFLATE170#include "../../../../lib/inflate.c"171172static inline void scroll(void)173{174int i;175176memcpy(vidmem, vidmem + cols * 2, (lines - 1) * cols * 2);177for (i = (lines - 1) * cols * 2; i < lines * cols * 2; i += 2)178vidmem[i] = ' ';179}180181static inline void kputchar(unsigned char ch)182{183#ifdef CONFIG_MN10300_UNIT_ASB2305184while (SC0STR & SC01STR_TBF)185continue;186187if (ch == 0x0a) {188SC0TXB = 0x0d;189while (SC0STR & SC01STR_TBF)190continue;191}192193SC0TXB = ch;194195#else196while (SC1STR & SC01STR_TBF)197continue;198199if (ch == 0x0a) {200SC1TXB = 0x0d;201while (SC1STR & SC01STR_TBF)202continue;203}204205SC1TXB = ch;206207#endif208}209210static void kputs(const char *s)211{212#ifdef CONFIG_DEBUG_DECOMPRESS_KERNEL213#ifndef CONFIG_GDBSTUB_ON_TTYSx214char ch;215216FLOWCTL_SET(DTR);217218while (*s) {219LSR_WAIT_FOR(THRE);220221ch = *s++;222if (ch == 0x0a) {223CYG_DEV_THR = 0x0d;224LSR_WAIT_FOR(THRE);225}226CYG_DEV_THR = ch;227}228229FLOWCTL_CLEAR(DTR);230#else231232for (; *s; s++)233kputchar(*s);234235#endif236#endif /* CONFIG_DEBUG_DECOMPRESS_KERNEL */237}238239/* ===========================================================================240* Fill the input buffer. This is called only when the buffer is empty241* and at least one byte is really needed.242*/243static int fill_inbuf()244{245if (insize != 0)246error("ran out of input data\n");247248inbuf = input_data;249insize = input_len;250inptr = 1;251return inbuf[0];252}253254/* ===========================================================================255* Write the output window window[0..outcnt-1] and update crc and bytes_out.256* (Used for the decompressed data only.)257*/258static void flush_window_low(void)259{260ulg c = crc; /* temporary variable */261unsigned n;262uch *in, *out, ch;263264in = window;265out = &output_data[output_ptr];266for (n = 0; n < outcnt; n++) {267ch = *out++ = *in++;268c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);269}270crc = c;271bytes_out += (ulg)outcnt;272output_ptr += (ulg)outcnt;273outcnt = 0;274}275276static void flush_window_high(void)277{278ulg c = crc; /* temporary variable */279unsigned n;280uch *in, ch;281in = window;282for (n = 0; n < outcnt; n++) {283ch = *output_data++ = *in++;284if ((ulg) output_data == LOW_BUFFER_END)285output_data = high_buffer_start;286c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);287}288crc = c;289bytes_out += (ulg)outcnt;290outcnt = 0;291}292293static void flush_window(void)294{295if (high_loaded)296flush_window_high();297else298flush_window_low();299}300301static void error(const char *x)302{303kputs("\n\n");304kputs(x);305kputs("\n\n -- System halted");306307while (1)308/* Halt */;309}310311#define STACK_SIZE (4096)312313long user_stack[STACK_SIZE];314315struct {316long *a;317short b;318} stack_start = { &user_stack[STACK_SIZE], 0 };319320void setup_normal_output_buffer(void)321{322#ifdef STANDARD_MEMORY_BIOS_CALL323if (EXT_MEM_K < 1024)324error("Less than 2MB of memory.\n");325#else326if ((ALT_MEM_K > EXT_MEM_K ? ALT_MEM_K : EXT_MEM_K) < 1024)327error("Less than 2MB of memory.\n");328#endif329output_data = (char *) 0x100000; /* Points to 1M */330}331332struct moveparams {333uch *low_buffer_start;334int lcount;335uch *high_buffer_start;336int hcount;337};338339void setup_output_buffer_if_we_run_high(struct moveparams *mv)340{341high_buffer_start = (uch *)(((ulg) &end) + HEAP_SIZE);342#ifdef STANDARD_MEMORY_BIOS_CALL343if (EXT_MEM_K < (3 * 1024))344error("Less than 4MB of memory.\n");345#else346if ((ALT_MEM_K > EXT_MEM_K ? ALT_MEM_K : EXT_MEM_K) < (3 * 1024))347error("Less than 4MB of memory.\n");348#endif349mv->low_buffer_start = output_data = (char *) LOW_BUFFER_START;350high_loaded = 1;351free_mem_end_ptr = (long) high_buffer_start;352if (0x100000 + LOW_BUFFER_SIZE > (ulg) high_buffer_start) {353high_buffer_start = (uch *)(0x100000 + LOW_BUFFER_SIZE);354mv->hcount = 0; /* say: we need not to move high_buffer */355} else {356mv->hcount = -1;357}358mv->high_buffer_start = high_buffer_start;359}360361void close_output_buffer_if_we_run_high(struct moveparams *mv)362{363mv->lcount = bytes_out;364if (bytes_out > LOW_BUFFER_SIZE) {365mv->lcount = LOW_BUFFER_SIZE;366if (mv->hcount)367mv->hcount = bytes_out - LOW_BUFFER_SIZE;368} else {369mv->hcount = 0;370}371}372373#undef DEBUGFLAG374#ifdef DEBUGFLAG375int debugflag;376#endif377378int decompress_kernel(struct moveparams *mv)379{380#ifdef DEBUGFLAG381while (!debugflag)382barrier();383#endif384385output_data = (char *) CONFIG_KERNEL_TEXT_ADDRESS;386387makecrc();388kputs("Uncompressing Linux... ");389gunzip();390kputs("Ok, booting the kernel.\n");391return 0;392}393394395