linux/arch/mn10300/boot/compressed/misc.c
<<
>>
Prefs
   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#include "../../../../lib/inflate.c"
 171
 172static inline void scroll(void)
 173{
 174        int i;
 175
 176        memcpy(vidmem, vidmem + cols * 2, (lines - 1) * cols * 2);
 177        for (i = (lines - 1) * cols * 2; i < lines * cols * 2; i += 2)
 178                vidmem[i] = ' ';
 179}
 180
 181static inline void kputchar(unsigned char ch)
 182{
 183#ifdef CONFIG_MN10300_UNIT_ASB2305
 184        while (SC0STR & SC01STR_TBF)
 185                continue;
 186
 187        if (ch == 0x0a) {
 188                SC0TXB = 0x0d;
 189                while (SC0STR & SC01STR_TBF)
 190                        continue;
 191        }
 192
 193        SC0TXB = ch;
 194
 195#else
 196        while (SC1STR & SC01STR_TBF)
 197                continue;
 198
 199        if (ch == 0x0a) {
 200                SC1TXB = 0x0d;
 201                while (SC1STR & SC01STR_TBF)
 202                        continue;
 203        }
 204
 205        SC1TXB = ch;
 206
 207#endif
 208}
 209
 210static void kputs(const char *s)
 211{
 212#ifdef CONFIG_DEBUG_DECOMPRESS_KERNEL
 213#ifndef CONFIG_GDBSTUB_ON_TTYSx
 214        char ch;
 215
 216        FLOWCTL_SET(DTR);
 217
 218        while (*s) {
 219                LSR_WAIT_FOR(THRE);
 220
 221                ch = *s++;
 222                if (ch == 0x0a) {
 223                        CYG_DEV_THR = 0x0d;
 224                        LSR_WAIT_FOR(THRE);
 225                }
 226                CYG_DEV_THR = ch;
 227        }
 228
 229        FLOWCTL_CLEAR(DTR);
 230#else
 231
 232        for (; *s; s++)
 233                kputchar(*s);
 234
 235#endif
 236#endif /* CONFIG_DEBUG_DECOMPRESS_KERNEL */
 237}
 238
 239/* ===========================================================================
 240 * Fill the input buffer. This is called only when the buffer is empty
 241 * and at least one byte is really needed.
 242 */
 243static int fill_inbuf()
 244{
 245        if (insize != 0)
 246                error("ran out of input data\n");
 247
 248        inbuf = input_data;
 249        insize = input_len;
 250        inptr = 1;
 251        return inbuf[0];
 252}
 253
 254/* ===========================================================================
 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{
 260    ulg c = crc;         /* temporary variable */
 261    unsigned n;
 262    uch *in, *out, ch;
 263
 264    in = window;
 265    out = &output_data[output_ptr];
 266    for (n = 0; n < outcnt; n++) {
 267            ch = *out++ = *in++;
 268            c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
 269    }
 270    crc = c;
 271    bytes_out += (ulg)outcnt;
 272    output_ptr += (ulg)outcnt;
 273    outcnt = 0;
 274}
 275
 276static void flush_window_high(void)
 277{
 278    ulg c = crc;         /* temporary variable */
 279    unsigned n;
 280    uch *in,  ch;
 281    in = window;
 282    for (n = 0; n < outcnt; n++) {
 283        ch = *output_data++ = *in++;
 284        if ((ulg) output_data == LOW_BUFFER_END)
 285                output_data = high_buffer_start;
 286        c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
 287    }
 288    crc = c;
 289    bytes_out += (ulg)outcnt;
 290    outcnt = 0;
 291}
 292
 293static void flush_window(void)
 294{
 295        if (high_loaded)
 296                flush_window_high();
 297        else
 298                flush_window_low();
 299}
 300
 301static void error(const char *x)
 302{
 303        kputs("\n\n");
 304        kputs(x);
 305        kputs("\n\n -- System halted");
 306
 307        while (1)
 308                /* Halt */;
 309}
 310
 311#define STACK_SIZE (4096)
 312
 313long user_stack[STACK_SIZE];
 314
 315struct {
 316        long *a;
 317        short b;
 318} stack_start = { &user_stack[STACK_SIZE], 0 };
 319
 320void setup_normal_output_buffer(void)
 321{
 322#ifdef STANDARD_MEMORY_BIOS_CALL
 323        if (EXT_MEM_K < 1024)
 324                error("Less than 2MB of memory.\n");
 325#else
 326        if ((ALT_MEM_K > EXT_MEM_K ? ALT_MEM_K : EXT_MEM_K) < 1024)
 327                error("Less than 2MB of memory.\n");
 328#endif
 329        output_data = (char *) 0x100000; /* Points to 1M */
 330}
 331
 332struct moveparams {
 333        uch *low_buffer_start;
 334        int lcount;
 335        uch *high_buffer_start;
 336        int hcount;
 337};
 338
 339void setup_output_buffer_if_we_run_high(struct moveparams *mv)
 340{
 341        high_buffer_start = (uch *)(((ulg) &end) + HEAP_SIZE);
 342#ifdef STANDARD_MEMORY_BIOS_CALL
 343        if (EXT_MEM_K < (3 * 1024))
 344                error("Less than 4MB of memory.\n");
 345#else
 346        if ((ALT_MEM_K > EXT_MEM_K ? ALT_MEM_K : EXT_MEM_K) < (3 * 1024))
 347                error("Less than 4MB of memory.\n");
 348#endif
 349        mv->low_buffer_start = output_data = (char *) LOW_BUFFER_START;
 350        high_loaded = 1;
 351        free_mem_end_ptr = (long) high_buffer_start;
 352        if (0x100000 + LOW_BUFFER_SIZE > (ulg) high_buffer_start) {
 353                high_buffer_start = (uch *)(0x100000 + LOW_BUFFER_SIZE);
 354                mv->hcount = 0; /* say: we need not to move high_buffer */
 355        } else {
 356                mv->hcount = -1;
 357        }
 358        mv->high_buffer_start = high_buffer_start;
 359}
 360
 361void close_output_buffer_if_we_run_high(struct moveparams *mv)
 362{
 363        mv->lcount = bytes_out;
 364        if (bytes_out > LOW_BUFFER_SIZE) {
 365                mv->lcount = LOW_BUFFER_SIZE;
 366                if (mv->hcount)
 367                        mv->hcount = bytes_out - LOW_BUFFER_SIZE;
 368        } else {
 369                mv->hcount = 0;
 370        }
 371}
 372
 373#undef DEBUGFLAG
 374#ifdef DEBUGFLAG
 375int debugflag;
 376#endif
 377
 378int decompress_kernel(struct moveparams *mv)
 379{
 380#ifdef DEBUGFLAG
 381        while (!debugflag)
 382                barrier();
 383#endif
 384
 385        output_data = (char *) CONFIG_KERNEL_TEXT_ADDRESS;
 386
 387        makecrc();
 388        kputs("Uncompressing Linux... ");
 389        gunzip();
 390        kputs("Ok, booting the kernel.\n");
 391        return 0;
 392}
 393
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.