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#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