diff options
Diffstat (limited to 'arch/ppc/boot/openfirmware')
-rw-r--r-- | arch/ppc/boot/openfirmware/Makefile | 188 | ||||
-rw-r--r-- | arch/ppc/boot/openfirmware/chrpmain.c | 101 | ||||
-rw-r--r-- | arch/ppc/boot/openfirmware/coffmain.c | 101 | ||||
-rw-r--r-- | arch/ppc/boot/openfirmware/common.c | 162 | ||||
-rw-r--r-- | arch/ppc/boot/openfirmware/dummy.c | 4 | ||||
-rw-r--r-- | arch/ppc/boot/openfirmware/misc.S | 67 | ||||
-rw-r--r-- | arch/ppc/boot/openfirmware/newworldmain.c | 94 | ||||
-rw-r--r-- | arch/ppc/boot/openfirmware/start.c | 172 |
8 files changed, 889 insertions, 0 deletions
diff --git a/arch/ppc/boot/openfirmware/Makefile b/arch/ppc/boot/openfirmware/Makefile new file mode 100644 index 000000000000..4eacbd8c772a --- /dev/null +++ b/arch/ppc/boot/openfirmware/Makefile @@ -0,0 +1,188 @@ +# Makefile for making bootable images on various OpenFirmware machines. +# +# Paul Mackerras January 1997 +# XCOFF bootable images for PowerMacs +# Geert Uytterhoeven September 1997 +# ELF bootable iamges for CHRP machines. +# Tom Rini January 2001 +# Cleaned up, moved into arch/ppc/boot/pmac +# Tom Rini July/August 2002 +# Merged 'chrp' and 'pmac' into 'openfirmware', and cleaned up the +# rules. + +zImage.initrd znetboot.initrd: del-ramdisk-sec := -R .ramdisk +zImage.initrd znetboot.initrd: initrd := .initrd + + +boot := arch/ppc/boot +common := $(boot)/common +utils := $(boot)/utils +bootlib := $(boot)/lib +of1275 := $(boot)/of1275 +images := $(boot)/images + +OBJCOPY_ARGS := -O aixcoff-rs6000 -R .stab -R .stabstr -R .comment +COFF_LD_ARGS := -T $(srctree)/$(boot)/ld.script -e _start -Ttext 0x00500000 \ + -Bstatic +CHRP_LD_ARGS := -T $(srctree)/$(boot)/ld.script -e _start -Ttext 0x00800000 +NEWWORLD_LD_ARGS:= -T $(srctree)/$(boot)/ld.script -e _start -Ttext 0x01000000 + +COMMONOBJS := start.o misc.o common.o +COFFOBJS := coffcrt0.o $(COMMONOBJS) coffmain.o +CHRPOBJS := crt0.o $(COMMONOBJS) chrpmain.o +NEWWORLDOBJS := crt0.o $(COMMONOBJS) newworldmain.o + +targets := $(COFFOBJS) $(CHRPOBJS) $(NEWWORLDOBJS) dummy.o +COFFOBJS := $(addprefix $(obj)/, $(COFFOBJS)) +CHRPOBJS := $(addprefix $(obj)/, $(CHRPOBJS)) +NEWWORLDOBJS := $(addprefix $(obj)/, $(NEWWORLDOBJS)) + +LIBS := lib/lib.a $(bootlib)/lib.a $(of1275)/lib.a $(common)/lib.a + +HACKCOFF := $(utils)/hack-coff + +ifdef CONFIG_SMP +END := .smp +endif +ifdef CONFIG_PPC64BRIDGE +END += .64 +endif + + +$(images)/ramdisk.image.gz: + @echo ' MISSING $@' + @echo ' RAM disk image must be provided separately' + @/bin/false + +objcpxmon-$(CONFIG_XMON) := --add-section=.sysmap=System.map \ + --set-section-flags=.sysmap=contents,alloc,load,readonly,data +quiet_cmd_genimage = GEN $@ + cmd_genimage = $(OBJCOPY) -R .comment \ + --add-section=.image=$(images)/vmlinux.gz \ + --set-section-flags=.image=contents,alloc,load,readonly,data \ + $(objcpxmon-y) $< $@ + +targets += image.o +$(obj)/image.o: $(obj)/dummy.o $(images)/vmlinux.gz FORCE + $(call if_changed,genimage) + +# Place the ramdisk in the initrd image. +quiet_cmd_genimage-initrd = GEN $@ + cmd_genimage-initrd = $(OBJCOPY) $< $@ \ + --add-section=.ramdisk=$(images)/ramdisk.image.gz \ + --set-section-flags=.ramdisk=contents,alloc,load,readonly,data +targets += image.initrd.o +$(obj)/image.initrd.o: $(obj)/image.o $(images)/ramdisk.image.gz FORCE + $(call if_changed,genimage-initrd) + +# Create the note section for New-World PowerMacs. +quiet_cmd_mknote = MKNOTE $@ + cmd_mknote = $(utils)/mknote > $@ +targets += note +$(obj)/note: $(utils)/mknote FORCE + $(call if_changed,mknote) + + +$(obj)/coffcrt0.o: EXTRA_AFLAGS := -traditional -DXCOFF +$(obj)/crt0.o: EXTRA_AFLAGS := -traditional +targets += coffcrt0.o crt0.o +$(obj)/coffcrt0.o $(obj)/crt0.o: $(common)/crt0.S FORCE + $(call if_changed_dep,as_o_S) + +quiet_cmd_gencoffb = COFF $@ + cmd_gencoffb = $(LD) -o $@ $(COFF_LD_ARGS) $(COFFOBJS) $< $(LIBS) && \ + $(OBJCOPY) $@ $@ -R .comment $(del-ramdisk-sec) +targets += coffboot +$(obj)/coffboot: $(obj)/image.o $(COFFOBJS) $(LIBS) $(srctree)/$(boot)/ld.script FORCE + $(call if_changed,gencoffb) +targets += coffboot.initrd +$(obj)/coffboot.initrd: $(obj)/image.initrd.o $(COFFOBJS) $(LIBS) \ + $(srctree)/$(boot)/ld.script FORCE + $(call if_changed,gencoffb) + + +quiet_cmd_gen-coff = COFF $@ + cmd_gen-coff = $(OBJCOPY) $(OBJCOPY_ARGS) $< $@ && \ + $(HACKCOFF) $@ && \ + ln -sf $(notdir $@) $(images)/zImage$(initrd).pmac + +$(images)/vmlinux.coff: $(obj)/coffboot + $(call cmd,gen-coff) + +$(images)/vmlinux.initrd.coff: $(obj)/coffboot.initrd + $(call cmd,gen-coff) + +quiet_cmd_gen-elf-pmac = ELF $@ + cmd_gen-elf-pmac = $(LD) $(NEWWORLD_LD_ARGS) -o $@ \ + $(NEWWORLDOBJS) $(LIBS) $< && \ + $(OBJCOPY) $@ $@ --add-section=.note=$(obj)/note \ + -R .comment $(del-ramdisk-sec) + +$(images)/vmlinux.elf-pmac: $(obj)/image.o $(NEWWORLDOBJS) $(LIBS) \ + $(obj)/note $(srctree)/$(boot)/ld.script + $(call cmd,gen-elf-pmac) +$(images)/vmlinux.initrd.elf-pmac: $(obj)/image.initrd.o $(NEWWORLDOBJS) \ + $(LIBS) $(obj)/note \ + $(srctree)/$(boot)/ld.script + $(call cmd,gen-elf-pmac) + +quiet_cmd_gen-chrp = CHRP $@ + cmd_gen-chrp = $(LD) $(CHRP_LD_ARGS) -o $@ $(CHRPOBJS) $< $(LIBS) && \ + $(OBJCOPY) $@ $@ -R .comment $(del-ramdisk-sec) + +$(images)/zImage.chrp: $(obj)/image.o $(CHRPOBJS) $(LIBS) \ + $(srctree)/$(boot)/ld.script + $(call cmd,gen-chrp) +$(images)/zImage.initrd.chrp: $(obj)/image.initrd.o $(CHRPOBJS) $(LIBS) \ + $(srctree)/$(boot)/ld.script + $(call cmd,gen-chrp) + +quiet_cmd_addnote = ADDNOTE $@ + cmd_addnote = cat $< > $@ && $(utils)/addnote $@ +$(images)/zImage.chrp-rs6k $(images)/zImage.initrd.chrp-rs6k: \ + %-rs6k: % + $(call cmd,addnote) + +quiet_cmd_gen-miboot = GEN $@ + cmd_gen-miboot = $(OBJCOPY) $(OBJCOPY_ARGS) \ + --add-section=$1=$(word 2, $^) $< $@ +$(images)/miboot.image: $(obj)/dummy.o $(images)/vmlinux.gz + $(call cmd,gen-miboot,image) + +$(images)/miboot.initrd.image: $(images)/miboot.image $(images)/ramdisk.image.gz + $(call cmd,gen-miboot,initrd) + +# The targets used on the make command-line + +.PHONY: zImage zImage.initrd +zImage: $(images)/vmlinux.coff \ + $(images)/vmlinux.elf-pmac \ + $(images)/zImage.chrp \ + $(images)/zImage.chrp-rs6k \ + $(images)/miboot.image + @echo ' kernel: $@ is ready ($<)' +zImage.initrd: $(images)/vmlinux.initrd.coff \ + $(images)/vmlinux.initrd.elf-pmac \ + $(images)/zImage.initrd.chrp \ + $(images)/zImage.initrd.chrp-rs6k \ + $(images)/miboot.initrd.image + @echo ' kernel: $@ is ready ($<)' + +TFTPIMAGE := /tftpboot/zImage + +.PHONY: znetboot znetboot.initrd +znetboot: $(images)/vmlinux.coff \ + $(images)/vmlinux.elf-pmac \ + $(images)/zImage.chrp + cp $(images)/vmlinux.coff $(TFTPIMAGE).pmac$(END) + cp $(images)/vmlinux.elf-pmac $(TFTPIMAGE).pmac$(END).elf + cp $(images)/zImage.chrp $(TFTPIMAGE).chrp$(END) + @echo ' kernel: $@ is ready ($<)' +znetboot.initrd:$(images)/vmlinux.initrd.coff \ + $(images)/vmlinux.initrd.elf-pmac \ + $(images)/zImage.initrd.chrp + cp $(images)/vmlinux.initrd.coff $(TFTPIMAGE).pmac$(END) + cp $(images)/vmlinux.initrd.elf-pmac $(TFTPIMAGE).pmac$(END).elf + cp $(images)/zImage.initrd.chrp $(TFTPIMAGE).chrp$(END) + @echo ' kernel: $@ is ready ($<)' + diff --git a/arch/ppc/boot/openfirmware/chrpmain.c b/arch/ppc/boot/openfirmware/chrpmain.c new file mode 100644 index 000000000000..6fb4f738728c --- /dev/null +++ b/arch/ppc/boot/openfirmware/chrpmain.c @@ -0,0 +1,101 @@ +/* + * Copyright (C) Paul Mackerras 1997. + * + * 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 <linux/string.h> +#include "nonstdio.h" +#include "of1275.h" +#include <asm/processor.h> +#include <asm/page.h> + +/* Passed from the linker */ +extern char __image_begin, __image_end; +extern char __ramdisk_begin, __ramdisk_end; +extern char _start, _end; + +extern unsigned int heap_max; +extern void flush_cache(void *, unsigned long); +extern void gunzip(void *, int, unsigned char *, int *); +extern void make_bi_recs(unsigned long addr, char *name, unsigned int mach, + unsigned int progend); + +char *avail_ram; +char *begin_avail, *end_avail; +char *avail_high; + +#define RAM_START 0x00000000 +#define RAM_END (64<<20) + +#define BOOT_START ((unsigned long)_start) +#define BOOT_END ((unsigned long)(_end + 0xFFF) & ~0xFFF) + +#define RAM_FREE ((unsigned long)(_end+0x1000)&~0xFFF) +#define PROG_START 0x00010000 +#define PROG_SIZE 0x007f0000 /* 8MB */ + +#define SCRATCH_SIZE (128 << 10) + +static char scratch[SCRATCH_SIZE]; /* 1MB of scratch space for gunzip */ + +typedef void (*kernel_start_t)(int, int, void *, unsigned int, unsigned int); + +void +boot(int a1, int a2, void *prom) +{ + unsigned sa, len; + void *dst; + unsigned char *im; + unsigned int initrd_size, initrd_start; + + printf("chrpboot starting: loaded at 0x%p\n\r", &_start); + + initrd_size = &__ramdisk_end - &__ramdisk_begin; + if (initrd_size) { + initrd_start = (RAM_END - initrd_size) & ~0xFFF; + a1 = initrd_start; + a2 = initrd_size; + claim(initrd_start, RAM_END - initrd_start, 0); + printf("initial ramdisk moving 0x%x <- 0x%p (%x bytes)\n\r", + initrd_start, &__ramdisk_begin, initrd_size); + memcpy((char *)initrd_start, &__ramdisk_begin, initrd_size); + } else { + initrd_start = 0; + initrd_size = 0; + a2 = 0xdeadbeef; + } + + im = &__image_begin; + len = &__image_end - &__image_begin; + /* claim 4MB starting at PROG_START */ + claim(PROG_START, PROG_SIZE - PROG_START, 0); + dst = (void *) PROG_START; + if (im[0] == 0x1f && im[1] == 0x8b) { + avail_ram = scratch; + begin_avail = avail_high = avail_ram; + end_avail = scratch + sizeof(scratch); + printf("gunzipping (0x%p <- 0x%p:0x%p)...", dst, im, im+len); + gunzip(dst, 0x400000, im, &len); + printf("done %u bytes\n\r", len); + printf("%u bytes of heap consumed, max in use %u\n\r", + avail_high - begin_avail, heap_max); + } else { + memmove(dst, im, len); + } + + flush_cache(dst, len); + make_bi_recs(((unsigned long) dst + len), "chrpboot", _MACH_chrp, + (PROG_START + PROG_SIZE)); + + sa = PROG_START; + printf("start address = 0x%x\n\r", sa); + + (*(kernel_start_t)sa)(a1, a2, prom, initrd_start, initrd_size); + + printf("returned?\n\r"); + + pause(); +} diff --git a/arch/ppc/boot/openfirmware/coffmain.c b/arch/ppc/boot/openfirmware/coffmain.c new file mode 100644 index 000000000000..04ba9d57e110 --- /dev/null +++ b/arch/ppc/boot/openfirmware/coffmain.c @@ -0,0 +1,101 @@ +/* + * Copyright (C) Paul Mackerras 1997. + * + * 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 <linux/string.h> +#include <asm/processor.h> +#include <asm/page.h> + +#include "nonstdio.h" +#include "of1275.h" + +/* Passed from the linker */ +extern char __image_begin, __image_end; +extern char __ramdisk_begin[], __ramdisk_end; +extern char _start, _end; + +extern char image_data[], initrd_data[]; +extern int initrd_len, image_len; +extern unsigned int heap_max; +extern void flush_cache(void *start, unsigned int len); +extern void gunzip(void *, int, unsigned char *, int *); +extern void make_bi_recs(unsigned long addr, char *name, unsigned int mach, + unsigned int progend); +extern void setup_bats(unsigned long start); + +char *avail_ram; +char *begin_avail, *end_avail; +char *avail_high; + +#define SCRATCH_SIZE (128 << 10) + +static char heap[SCRATCH_SIZE]; + +static unsigned long ram_start = 0; +static unsigned long ram_end = 0x1000000; + +static unsigned long prog_start = 0x900000; +static unsigned long prog_size = 0x700000; + +typedef void (*kernel_start_t)(int, int, void *); + +void boot(int a1, int a2, void *prom) +{ + unsigned sa, len; + void *dst; + unsigned char *im; + unsigned initrd_start, initrd_size; + + printf("coffboot starting: loaded at 0x%p\n", &_start); + setup_bats(ram_start); + + initrd_size = (char *)(&__ramdisk_end) - (char *)(&__ramdisk_begin); + if (initrd_size) { + initrd_start = (ram_end - initrd_size) & ~0xFFF; + a1 = initrd_start; + a2 = initrd_size; + claim(initrd_start, ram_end - initrd_start, 0); + printf("initial ramdisk moving 0x%x <- 0x%p (%x bytes)\n\r", + initrd_start, (char *)(&__ramdisk_begin), initrd_size); + memcpy((char *)initrd_start, (char *)(&__ramdisk_begin), initrd_size); + prog_size = initrd_start - prog_start; + } else + a2 = 0xdeadbeef; + + im = (char *)(&__image_begin); + len = (char *)(&__image_end) - (char *)(&__image_begin); + /* claim 4MB starting at PROG_START */ + claim(prog_start, prog_size, 0); + map(prog_start, prog_start, prog_size); + dst = (void *) prog_start; + if (im[0] == 0x1f && im[1] == 0x8b) { + /* set up scratch space */ + begin_avail = avail_high = avail_ram = heap; + end_avail = heap + sizeof(heap); + printf("heap at 0x%p\n", avail_ram); + printf("gunzipping (0x%p <- 0x%p:0x%p)...", dst, im, im+len); + gunzip(dst, prog_size, im, &len); + printf("done %u bytes\n", len); + printf("%u bytes of heap consumed, max in use %u\n", + avail_high - begin_avail, heap_max); + } else { + memmove(dst, im, len); + } + + flush_cache(dst, len); + make_bi_recs(((unsigned long) dst + len), "coffboot", _MACH_Pmac, + (prog_start + prog_size)); + + sa = (unsigned long)prog_start; + printf("start address = 0x%x\n", sa); + + (*(kernel_start_t)sa)(a1, a2, prom); + + printf("returned?\n"); + + pause(); +} diff --git a/arch/ppc/boot/openfirmware/common.c b/arch/ppc/boot/openfirmware/common.c new file mode 100644 index 000000000000..9e6952781f1f --- /dev/null +++ b/arch/ppc/boot/openfirmware/common.c @@ -0,0 +1,162 @@ +/* + * Copyright (C) Paul Mackerras 1997. + * + * 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 "of1275.h" +#include <linux/string.h> +#include <linux/zlib.h> +#include <asm/bootinfo.h> +#include <asm/page.h> + +/* Information from the linker */ +extern char __sysmap_begin, __sysmap_end; + +extern int strcmp(const char *s1, const char *s2); +extern char *avail_ram, *avail_high; +extern char *end_avail; + +unsigned int heap_use, heap_max; + +struct memchunk { + unsigned int size; + struct memchunk *next; +}; + +static struct memchunk *freechunks; + +static void *zalloc(unsigned size) +{ + void *p; + struct memchunk **mpp, *mp; + + size = (size + 7) & -8; + heap_use += size; + if (heap_use > heap_max) + heap_max = heap_use; + for (mpp = &freechunks; (mp = *mpp) != 0; mpp = &mp->next) { + if (mp->size == size) { + *mpp = mp->next; + return mp; + } + } + p = avail_ram; + avail_ram += size; + if (avail_ram > avail_high) + avail_high = avail_ram; + if (avail_ram > end_avail) { + printf("oops... out of memory\n\r"); + pause(); + } + return p; +} + +#define HEAD_CRC 2 +#define EXTRA_FIELD 4 +#define ORIG_NAME 8 +#define COMMENT 0x10 +#define RESERVED 0xe0 + +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] != Z_DEFLATED || (flags & RESERVED) != 0) { + printf("bad gzipped data\n\r"); + 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\r"); + exit(); + } + + /* Initialize ourself. */ + s.workspace = zalloc(zlib_inflate_workspacesize()); + r = zlib_inflateInit2(&s, -MAX_WBITS); + if (r != Z_OK) { + printf("zlib_inflateInit2 returned %d\n\r", r); + exit(); + } + s.next_in = src + i; + s.avail_in = *lenp - i; + s.next_out = dst; + s.avail_out = dstlen; + r = zlib_inflate(&s, Z_FINISH); + if (r != Z_OK && r != Z_STREAM_END) { + printf("inflate returned %d msg: %s\n\r", r, s.msg); + exit(); + } + *lenp = s.next_out - (unsigned char *) dst; + zlib_inflateEnd(&s); +} + +/* Make a bi_rec in OF. We need to be passed a name for BI_BOOTLOADER_ID, + * a machine type for BI_MACHTYPE, and the location where the end of the + * bootloader is (PROG_START + PROG_SIZE) + */ +void make_bi_recs(unsigned long addr, char *name, unsigned int mach, + unsigned long progend) +{ + unsigned long sysmap_size; + struct bi_record *rec; + + /* Figure out the size of a possible System.map we're going to + * pass along. + * */ + sysmap_size = (unsigned long)(&__sysmap_end) - + (unsigned long)(&__sysmap_begin); + + /* leave a 1MB gap then align to the next 1MB boundary */ + addr = _ALIGN(addr+ (1<<20) - 1, (1<<20)); + /* oldworld machine seem very unhappy about this. -- Tom */ + if (addr >= progend) + claim(addr, 0x1000, 0); + + rec = (struct bi_record *)addr; + rec->tag = BI_FIRST; + rec->size = sizeof(struct bi_record); + rec = (struct bi_record *)((unsigned long)rec + rec->size); + + rec->tag = BI_BOOTLOADER_ID; + sprintf( (char *)rec->data, name); + rec->size = sizeof(struct bi_record) + strlen(name) + 1; + rec = (struct bi_record *)((unsigned long)rec + rec->size); + + rec->tag = BI_MACHTYPE; + rec->data[0] = mach; + rec->data[1] = 1; + rec->size = sizeof(struct bi_record) + 2 * sizeof(unsigned long); + rec = (struct bi_record *)((unsigned long)rec + rec->size); + + if (sysmap_size) { + rec->tag = BI_SYSMAP; + rec->data[0] = (unsigned long)(&__sysmap_begin); + rec->data[1] = sysmap_size; + rec->size = sizeof(struct bi_record) + 2 * + sizeof(unsigned long); + rec = (struct bi_record *)((unsigned long)rec + rec->size); + } + + rec->tag = BI_LAST; + rec->size = sizeof(struct bi_record); + rec = (struct bi_record *)((unsigned long)rec + rec->size); +} diff --git a/arch/ppc/boot/openfirmware/dummy.c b/arch/ppc/boot/openfirmware/dummy.c new file mode 100644 index 000000000000..31dbf45bf99c --- /dev/null +++ b/arch/ppc/boot/openfirmware/dummy.c @@ -0,0 +1,4 @@ +int main(void) +{ + return 0; +} diff --git a/arch/ppc/boot/openfirmware/misc.S b/arch/ppc/boot/openfirmware/misc.S new file mode 100644 index 000000000000..ab9e897cadd0 --- /dev/null +++ b/arch/ppc/boot/openfirmware/misc.S @@ -0,0 +1,67 @@ +/* + * Copyright (C) Paul Mackerras 1997. + * + * 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. + */ + .text + +/* + * Use the BAT2 & 3 registers to map the 1st 16MB of RAM to + * the address given as the 1st argument. + */ + .globl setup_bats +setup_bats: + mfpvr 5 + rlwinm 5,5,16,16,31 /* r3 = 1 for 601, 4 for 604 */ + cmpwi 0,5,1 + li 0,0 + bne 4f + mtibatl 3,0 /* invalidate BAT first */ + ori 3,3,4 /* set up BAT registers for 601 */ + li 4,0x7f + mtibatu 2,3 + mtibatl 2,4 + oris 3,3,0x80 + oris 4,4,0x80 + mtibatu 3,3 + mtibatl 3,4 + b 5f +4: mtdbatu 3,0 /* invalidate BATs first */ + mtibatu 3,0 + ori 3,3,0xff /* set up BAT registers for 604 */ + li 4,2 + mtdbatl 2,4 + mtdbatu 2,3 + mtibatl 2,4 + mtibatu 2,3 + oris 3,3,0x80 + oris 4,4,0x80 + mtdbatl 3,4 + mtdbatu 3,3 + mtibatl 3,4 + mtibatu 3,3 +5: sync + isync + blr + +/* + * Flush the dcache and invalidate the icache for a range of addresses. + * + * flush_cache(addr, len) + */ + .global flush_cache +flush_cache: + addi 4,4,0x1f /* len = (len + 0x1f) / 0x20 */ + rlwinm. 4,4,27,5,31 + mtctr 4 + beqlr +1: dcbf 0,3 + icbi 0,3 + addi 3,3,0x20 + bdnz 1b + sync + isync + blr diff --git a/arch/ppc/boot/openfirmware/newworldmain.c b/arch/ppc/boot/openfirmware/newworldmain.c new file mode 100644 index 000000000000..fa8a8f9313f9 --- /dev/null +++ b/arch/ppc/boot/openfirmware/newworldmain.c @@ -0,0 +1,94 @@ +/* + * Copyright (C) Paul Mackerras 1997. + * + * 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 <linux/string.h> +#include "nonstdio.h" +#include "of1275.h" +#include <asm/processor.h> +#include <asm/page.h> + +/* Passed from the linker */ +extern char __image_begin, __image_end; +extern char __ramdisk_begin[], __ramdisk_end; +extern char _start, _end; + +extern unsigned int heap_max; +extern void flush_cache(void *start, unsigned int len); +extern void gunzip(void *, int, unsigned char *, int *); +extern void make_bi_recs(unsigned long addr, char *name, unsigned int mach, + unsigned int progend); + +char *avail_ram; +char *begin_avail, *end_avail; +char *avail_high; + + +#define RAM_END (16 << 20) + +#define PROG_START 0x00010000 +#define PROG_SIZE 0x007f0000 + +#define SCRATCH_SIZE (128 << 10) + +typedef void (*kernel_start_t)(int, int, void *); + +void boot(int a1, int a2, void *prom) +{ + unsigned sa, len; + void *dst; + unsigned char *im; + unsigned initrd_start, initrd_size; + + printf("chrpboot starting: loaded at 0x%p\n", &_start); + + initrd_size = (char *)(&__ramdisk_end) - (char *)(&__ramdisk_begin); + if (initrd_size) { + initrd_start = (RAM_END - initrd_size) & ~0xFFF; + a1 = initrd_start; + a2 = initrd_size; + claim(initrd_start, RAM_END - initrd_start, 0); + printf("initial ramdisk moving 0x%x <- 0x%p (%x bytes)\n\r", + initrd_start, (char *)(&__ramdisk_begin), initrd_size); + memcpy((char *)initrd_start, (char *)(&__ramdisk_begin), initrd_size); + } else + a2 = 0xdeadbeef; + + im = (char *)(&__image_begin); + len = (char *)(&__image_end) - (char *)(&__image_begin); + /* claim 3MB starting at PROG_START */ + claim(PROG_START, PROG_SIZE, 0); + dst = (void *) PROG_START; + if (im[0] == 0x1f && im[1] == 0x8b) { + /* claim some memory for scratch space */ + avail_ram = (char *) claim(0, SCRATCH_SIZE, 0x10); + begin_avail = avail_high = avail_ram; + end_avail = avail_ram + SCRATCH_SIZE; + printf("heap at 0x%p\n", avail_ram); + printf("gunzipping (0x%p <- 0x%p:0x%p)...", dst, im, im+len); + gunzip(dst, PROG_SIZE, im, &len); + printf("done %u bytes\n", len); + printf("%u bytes of heap consumed, max in use %u\n", + avail_high - begin_avail, heap_max); + release(begin_avail, SCRATCH_SIZE); + } else { + memmove(dst, im, len); + } + + flush_cache(dst, len); + make_bi_recs(((unsigned long) dst + len), "chrpboot", _MACH_Pmac, + (PROG_START + PROG_SIZE)); + + sa = (unsigned long)PROG_START; + printf("start address = 0x%x\n", sa); + + (*(kernel_start_t)sa)(a1, a2, prom); + + printf("returned?\n"); + + pause(); +} diff --git a/arch/ppc/boot/openfirmware/start.c b/arch/ppc/boot/openfirmware/start.c new file mode 100644 index 000000000000..1617a26956bf --- /dev/null +++ b/arch/ppc/boot/openfirmware/start.c @@ -0,0 +1,172 @@ +/* + * Copyright (C) Paul Mackerras 1997. + * + * 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 <stdarg.h> +#include "of1275.h" + +extern int strlen(const char *s); +extern void boot(int a1, int a2, void *prom); + +phandle stdin; +phandle stdout; +phandle stderr; + +void printk(char *fmt, ...); + +void +start(int a1, int a2, void *promptr) +{ + ofinit(promptr); + if (ofstdio(&stdin, &stdout, &stderr)) + exit(); + + boot(a1, a2, promptr); + for (;;) + exit(); +} + +int writestring(void *f, char *ptr, int nb) +{ + int w = 0, i; + char *ret = "\r"; + + for (i = 0; i < nb; ++i) { + if (ptr[i] == '\n') { + if (i > w) { + write(f, ptr + w, i - w); + w = i; + } + write(f, ret, 1); + } + } + if (w < nb) + write(f, ptr + w, nb - w); + return nb; +} + +int +putc(int c, void *f) +{ + char ch = c; + + return writestring(f, &ch, 1) == 1? c: -1; +} + +int +putchar(int c) +{ + return putc(c, stdout); +} + +int +fputs(char *str, void *f) +{ + int n = strlen(str); + + return writestring(f, str, n) == n? 0: -1; +} + +int +readchar(void) +{ + char ch; + + for (;;) { + switch (read(stdin, &ch, 1)) { + case 1: + return ch; + case -1: + printk("read(stdin) returned -1\n"); + return -1; + } + } +} + +static char line[256]; +static char *lineptr; +static int lineleft; + +int +getchar(void) +{ + int c; + + if (lineleft == 0) { + lineptr = line; + for (;;) { + c = readchar(); + if (c == -1 || c == 4) + break; + if (c == '\r' || c == '\n') { + *lineptr++ = '\n'; + putchar('\n'); + break; + } + switch (c) { + case 0177: + case '\b': + if (lineptr > line) { + putchar('\b'); + putchar(' '); + putchar('\b'); + --lineptr; + } + break; + case 'U' & 0x1F: + while (lineptr > line) { + putchar('\b'); + putchar(' '); + putchar('\b'); + --lineptr; + } + break; + default: + if (lineptr >= &line[sizeof(line) - 1]) + putchar('\a'); + else { + putchar(c); + *lineptr++ = c; + } + } + } + lineleft = lineptr - line; + lineptr = line; + } + if (lineleft == 0) + return -1; + --lineleft; + return *lineptr++; +} + +extern int vsprintf(char *buf, const char *fmt, va_list args); +static char sprint_buf[1024]; + +void +printk(char *fmt, ...) +{ + va_list args; + int n; + + va_start(args, fmt); + n = vsprintf(sprint_buf, fmt, args); + va_end(args); + writestring(stdout, sprint_buf, n); +} + +int +printf(char *fmt, ...) +{ + va_list args; + int n; + + va_start(args, fmt); + n = vsprintf(sprint_buf, fmt, args); + va_end(args); + writestring(stdout, sprint_buf, n); + return n; +} |