diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-02-04 07:40:19 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-02-04 07:40:19 +0000 |
commit | 33263fc5f9ac8e8cb2b22d06af3ce5ac1dd815e4 (patch) | |
tree | 2d1b86a40bef0958a68cf1a2eafbeb0667a70543 /arch/ppc/treeboot/main.c | |
parent | 216f5f51aa02f8b113aa620ebc14a9631a217a00 (diff) |
Merge with Linux 2.3.32.
Diffstat (limited to 'arch/ppc/treeboot/main.c')
-rw-r--r-- | arch/ppc/treeboot/main.c | 209 |
1 files changed, 209 insertions, 0 deletions
diff --git a/arch/ppc/treeboot/main.c b/arch/ppc/treeboot/main.c new file mode 100644 index 000000000..1b5ef3805 --- /dev/null +++ b/arch/ppc/treeboot/main.c @@ -0,0 +1,209 @@ +/* + * Copyright (c) 1997 Paul Mackerras <paulus@cs.anu.edu.au> + * Initial Power Macintosh COFF version. + * Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu> + * Modifications for an ELF-based IBM evaluation board version. + * + * Module name: main.c + * + * Description: + * This module does most of the real work for the boot loader. It + * checks the variables holding the absolute start address and size + * of the Linux kernel "image" and initial RAM disk "initrd" sections + * and if they are present, moves them to their "proper" locations. + * + * For the Linux kernel, "proper" is physical address 0x00000000. + * For the RAM disk, "proper" is the image's size below the top + * of physical memory. The Linux kernel may be in either raw + * binary form or compressed with GNU zip (aka gzip). + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include "nonstdio.h" +#include "zlib.h" +#include "irSect.h" + + +/* Preprocessor Defines */ + +#define RAM_SIZE (4 * 1024 * 1024) + +#define RAM_PBASE 0x00000000 +#define RAM_PEND (RAM_PBASE + RAM_SIZE) + +#define RAM_VBASE 0xC0000000 +#define RAM_VEND (RAM_VBASE + RAM_SIZE) + +#define RAM_START RAM_PBASE +#define RAM_END RAM_PEND +#define RAM_FREE (imageSect_start + imageSect_size + initrdSect_size) + +#define PROG_START RAM_START + + +/* Function Macros */ + +#define ALIGN_UP(x, align) (((x) + ((align) - 1)) & ~((align) - 1)) + + +/* Global Variables */ + +/* Needed by zalloc and zfree for allocating memory */ + +char *avail_ram; /* Indicates start of RAM available for heap */ +char *end_avail; /* Indicates end of RAM available for heap */ + + +/* Function Prototypes */ + +void *zalloc(void *x, unsigned items, unsigned size); +void zfree(void *x, void *addr, unsigned nb); + +void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp); + +void printf () {} +void pause () {} +void exit () {} + + +void start(void) +{ + void *options; + int ns, oh, i; + unsigned sa, len; + void *dst; + unsigned char *im; + unsigned initrd_start, initrd_size; + + /* setup_bats(RAM_START); */ + + /* Init RAM disk (initrd) section */ + + if (initrdSect_start != 0 && (initrd_size = initrdSect_size) != 0) { + initrd_start = (RAM_END - initrd_size) & ~0xFFF; + + printf("Initial RAM disk at 0x%08x (%u bytes)\n", + initrd_start, initrd_size); + + memcpy((char *)initrd_start, + (char *)(initrdSect_start), + initrdSect_size); + + end_avail = (char *)initrd_start; + } else { + end_avail = (char *)RAM_END; + } + + /* Linux kernel image section */ + + im = (unsigned char *)(imageSect_start); + len = imageSect_size; + dst = (void *)PROG_START; + + /* Check for the gzip archive magic numbers */ + + if (im[0] == 0x1f && im[1] == 0x8b) { + + /* The gunzip routine needs everything nice and aligned */ + + void *cp = (void *)ALIGN_UP(RAM_FREE, 8); + avail_ram = (void *)(cp + ALIGN_UP(len, 8)); + memcpy(cp, im, len); + + /* I'm not sure what the 0x200000 parameter is for, but it works. */ + + gunzip(dst, 0x200000, cp, &len); + } else { + memmove(dst, im, len); + } + + /* flush_cache(dst, len); */ + + sa = (unsigned long)dst; + + (*(void (*)())sa)(); + + pause(); +} + +void *zalloc(void *x, unsigned items, unsigned size) +{ + void *p = avail_ram; + + size *= items; + size = ALIGN_UP(size, 8); + avail_ram += size; + if (avail_ram > end_avail) { + printf("oops... out of memory\n"); + pause(); + } + return p; +} + +void zfree(void *x, void *addr, unsigned nb) +{ + +} + +#define HEAD_CRC 2 +#define EXTRA_FIELD 4 +#define ORIG_NAME 8 +#define COMMENT 0x10 +#define RESERVED 0xe0 + +#define DEFLATED 8 + +void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp) +{ + z_stream s; + int r, i, flags; + + /* skip header */ + i = 10; + flags = src[3]; + if (src[2] != DEFLATED || (flags & RESERVED) != 0) { + printf("bad gzipped data\n"); + exit(); + } + if ((flags & EXTRA_FIELD) != 0) + i = 12 + src[10] + (src[11] << 8); + if ((flags & ORIG_NAME) != 0) + while (src[i++] != 0) + ; + if ((flags & COMMENT) != 0) + while (src[i++] != 0) + ; + if ((flags & HEAD_CRC) != 0) + i += 2; + if (i >= *lenp) { + printf("gunzip: ran out of data in header\n"); + exit(); + } + printf("done 1\n"); + s.zalloc = zalloc; + s.zfree = zfree; + r = inflateInit2(&s, -MAX_WBITS); + if (r != Z_OK) { + printf("inflateInit2 returned %d\n", r); + exit(); + } + s.next_in = src + i; + s.avail_in = *lenp - i; + s.next_out = dst; + s.avail_out = dstlen; + printf("doing inflate\n"); + r = inflate(&s, Z_FINISH); + printf("done inflate\n"); + if (r != Z_OK && r != Z_STREAM_END) { + printf("inflate returned %d\n", r); + exit(); + } + *lenp = s.next_out - (unsigned char *) dst; + printf("doing end\n"); + inflateEnd(&s); +} |