diff --git a/arch/ppc64/boot/Makefile b/arch/ppc64/boot/Makefile index ac1f5a109a8a3ee57e5ce00f2b571065dbf931b7..8024fa77ca78b7c2a4eb7ef85e8796ea6fa14f17 100644 --- a/arch/ppc64/boot/Makefile +++ b/arch/ppc64/boot/Makefile @@ -24,35 +24,45 @@ CROSS32_COMPILE = #CROSS32_COMPILE = /usr/local/ppc/bin/powerpc-linux- BOOTCC := $(CROSS32_COMPILE)gcc -BOOTCFLAGS := $(HOSTCFLAGS) -Iinclude -BOOTLD := $(CROSS32_COMPILE)ld +HOSTCC := gcc +BOOTCFLAGS := $(HOSTCFLAGS) -Iinclude -fno-builtin BOOTAS := $(CROSS32_COMPILE)as -BOOTAFLAGS := -D__ASSEMBLY__ $(HOSTCFLAGS) - -CFLAGS := $(CPPFLAGS) -O -fno-builtin -DSTDC_HEADERS -LD_ARGS := -Ttext 0x00400000 -e _start -OBJCOPYFLAGS := -S -O binary +BOOTAFLAGS := -D__ASSEMBLY__ $(BOOTCFLAGS) -traditional +BOOTLD := $(CROSS32_COMPILE)ld +BOOTLFLAGS := -Ttext 0x00400000 -e _start -T $(obj)/zImage.lds +BOOTOBJCOPY := $(CROSS32_COMPILE)objcopy +OBJCOPYFLAGS := contents,alloc,load,readonly,data -obj-boot := start.o main.o zlib.o imagesize.o no_initrd.o -OBJS := crt0.o start.o main.o zlib.o imagesize.o image.o -obj-boot := $(addprefix $(obj)/,$(obj-boot)) -OBJS := $(addprefix $(obj)/,$(OBJS)) -targets += $(obj-boot) $(addprefix $(obj)/,image.c image.o) +src-boot := crt0.S string.S prom.c main.c zlib.c imagesize.c +src-boot := $(addprefix $(obj)/, $(src-boot)) +obj-boot := $(addsuffix .o, $(basename $(src-boot))) quiet_cmd_bootcc = BOOTCC $@ cmd_bootcc = $(BOOTCC) -Wp,-MD,$(depfile) $(BOOTCFLAGS) -c -o $@ $< -$(obj-boot): %.o: %.c FORCE - $(call if_changed_dep,bootcc) quiet_cmd_bootas = BOOTAS $@ - cmd_bootas = $(BOOTCC) -Wp,-MD,$(depfile) $(BOOTAFLAGS) -traditional \ - -c -o $@ $< -$(obj)/crt0.o: %.o: %.S FORCE + cmd_bootas = $(BOOTCC) -Wp,-MD,$(depfile) $(BOOTAFLAGS) -c -o $@ $< + +$(patsubst %.c,%.o, $(filter %.c, $(src-boot))): %.o: %.c + $(call if_changed_dep,bootcc) +$(patsubst %.S,%.o, $(filter %.S, $(src-boot))): %.o: %.S $(call if_changed_dep,bootas) -host-progs := piggyback addnote addSystemMap addRamDisk -HOSTCFLAGS_piggyback.o := -DKERNELBASE=$(KERNELBASE) -EXTRA_TARGETS += zImage zImage.initrd vmlinux.bin vmlinux.gz \ +#----------------------------------------------------------- +# ELF sections within the zImage bootloader/wrapper +#----------------------------------------------------------- +required := vmlinux .config System.map +initrd := initrd + +obj-sec = $(foreach section, $(1), $(patsubst %,$(obj)/kernel-%.o, $(section))) +src-sec = $(foreach section, $(1), $(patsubst %,$(obj)/kernel-%.c, $(section))) +gz-sec = $(foreach section, $(1), $(patsubst %,$(obj)/kernel-%.gz, $(section))) + +host-progs := piggy addnote addSystemMap addRamDisk +EXTRA_TARGETS += zImage zImage.initrd imagesize.c \ + $(patsubst $(obj)/%,%, $(call obj-sec, $(required) $(initrd))) \ + $(patsubst $(obj)/%,%, $(call src-sec, $(required) $(initrd))) \ + $(patsubst $(obj)/%,%, $(call gz-sec, $(required) $(initrd))) \ vmlinux.sm vmlinux.initrd vmlinux.sminitrd \ sysmap.o initrd.o @@ -69,42 +79,48 @@ $(obj)/vmlinux.initrd: vmlinux $(obj)/addRamDisk $(obj)/ramdisk.image.gz System. $(obj)/vmlinux.sminitrd: $(obj)/vmlinux.sm $(obj)/addRamDisk $(obj)/ramdisk.image.gz FORCE $(call if_changed,ramdisk) +$(obj)/sysmap.o: System.map $(obj)/piggyback + $(call if_changed,piggy) + +addsection = $(BOOTOBJCOPY) $(1) \ + --add-section=.kernel:$(strip $(patsubst $(obj)/kernel-%.o,%, $(1)))=$(patsubst %.o,%.gz, $(1)) \ + --set-section-flags=.kernel:$(strip $(patsubst $(obj)/kernel-%.o,%, $(1)))=$(OBJCOPYFLAGS) + +quiet_cmd_addnote = ADDNOTE $@ + cmd_addnote = $(BOOTLD) $(BOOTLFLAGS) -o $@ $(obj-boot) && $(obj)/addnote $@ quiet_cmd_piggy = PIGGY $@ cmd_piggy = $(obj)/piggyback $(@:.o=) < $< | $(BOOTAS) -o $@ -$(obj)/image.o: $(obj)/vmlinux.gz $(obj)/piggyback FORCE - $(call if_changed,piggy) +$(call gz-sec, $(required)): $(obj)/kernel-%.gz: % + $(call if_changed,gzip) -$(obj)/sysmap.o: System.map $(obj)/piggyback FORCE - $(call if_changed,piggy) +$(obj)/kernel-initrd.gz: $(obj)/ramdisk.image.gz + cp -f $(obj)/ramdisk.image.gz $@ -$(obj)/initrd.o: $(obj)/ramdisk.image.gz $(obj)/piggyback FORCE - $(call if_changed,piggy) +$(call src-sec, $(required) $(initrd)): $(obj)/kernel-%.c: $(obj)/kernel-%.gz + touch $@ -quiet_cmd_addnote = ADDNOTE $@ - cmd_addnote = $(BOOTLD) $(LD_ARGS) -T $(obj)/zImage.lds -o $@ $(OBJS) $<\ - && $(obj)/addnote $@ +$(call obj-sec, $(required) $(initrd)): $(obj)/kernel-%.o: $(obj)/kernel-%.c + $(call if_changed_dep,bootcc) + $(call addsection, $@) -$(obj)/zImage: $(obj)/no_initrd.o $(OBJS) $(obj)/addnote FORCE +$(obj)/zImage: obj-boot += $(call obj-sec, $(required)) +$(obj)/zImage: $(call obj-sec, $(required)) $(obj-boot) $(obj)/addnote FORCE $(call if_changed,addnote) -$(obj)/zImage.initrd: $(obj)/initrd.o $(OBJS) $(obj)/addnote FORCE +$(obj)/zImage.initrd: obj-boot += $(call obj-sec, $(required) $(initrd)) +$(obj)/zImage.initrd: $(call obj-sec, $(required) $(initrd)) $(obj-boot) $(obj)/addnote FORCE $(call if_changed,addnote) -$(obj)/vmlinux.bin: vmlinux FORCE - $(call if_changed,objcopy) - -$(obj)/vmlinux.gz: $(obj)/vmlinux.bin FORCE - $(call if_changed,gzip) - $(obj)/imagesize.c: vmlinux @echo Generating $@ ls -l vmlinux | \ awk '{printf "/* generated -- do not edit! */\n" \ - "int uncompressed_size = %d;\n", $$5}' > $(obj)/imagesize.c + "unsigned long vmlinux_filesize = %d;\n", $$5}' > $(obj)/imagesize.c $(CROSS_COMPILE)nm -n vmlinux | tail -1 | \ - awk '{printf "long vmlinux_end = 0x%s;\n", substr($$1,8)}' \ + awk '{printf "unsigned long vmlinux_memsize = 0x%s;\n", substr($$1,8)}' \ >> $(obj)/imagesize.c -clean-files := $(targets) + +clean-files := $(patsubst $(obj)/%,%, $(obj-boot)) diff --git a/arch/ppc64/boot/README b/arch/ppc64/boot/README new file mode 100644 index 0000000000000000000000000000000000000000..3e11058760e4b7b08a893b4a48a87969ebed29e8 --- /dev/null +++ b/arch/ppc64/boot/README @@ -0,0 +1,11 @@ + +To extract the kernel vmlinux, System.map, .config or initrd from the zImage binary: + +objcopy -j .kernel:vmlinux -O binary zImage vmlinux.gz +objcopy -j .kernel:System.map -O binary zImage System.map.gz +objcopy -j .kernel:.config -O binary zImage config.gz +objcopy -j .kernel:initrd -O binary zImage.initrd initrd.gz + + + Peter + diff --git a/arch/ppc64/boot/addRamDisk.c b/arch/ppc64/boot/addRamDisk.c index 1309861241e9cb82f0b9d7654274eba9177105b1..f940d0f99177d86d3ad1f0c859d7e10782774827 100644 --- a/arch/ppc64/boot/addRamDisk.c +++ b/arch/ppc64/boot/addRamDisk.c @@ -25,7 +25,7 @@ void put4k(FILE *file, char *buf ) void death(const char *msg, FILE *fdesc, const char *fname) { - printf(msg); + fprintf(stderr, msg); fclose(fdesc); unlink(fname); exit(1); @@ -66,47 +66,47 @@ int main(int argc, char **argv) if (argc < 2) { - printf("Name of RAM disk file missing.\n"); + fprintf(stderr, "Name of RAM disk file missing.\n"); exit(1); } if (argc < 3) { - printf("Name of System Map input file is missing.\n"); + fprintf(stderr, "Name of System Map input file is missing.\n"); exit(1); } if (argc < 4) { - printf("Name of vmlinux file missing.\n"); + fprintf(stderr, "Name of vmlinux file missing.\n"); exit(1); } if (argc < 5) { - printf("Name of vmlinux output file missing.\n"); + fprintf(stderr, "Name of vmlinux output file missing.\n"); exit(1); } ramDisk = fopen(argv[1], "r"); if ( ! ramDisk ) { - printf("RAM disk file \"%s\" failed to open.\n", argv[1]); + fprintf(stderr, "RAM disk file \"%s\" failed to open.\n", argv[1]); exit(1); } sysmap = fopen(argv[2], "r"); if ( ! sysmap ) { - printf("System Map file \"%s\" failed to open.\n", argv[2]); + fprintf(stderr, "System Map file \"%s\" failed to open.\n", argv[2]); exit(1); } inputVmlinux = fopen(argv[3], "r"); if ( ! inputVmlinux ) { - printf("vmlinux file \"%s\" failed to open.\n", argv[3]); + fprintf(stderr, "vmlinux file \"%s\" failed to open.\n", argv[3]); exit(1); } outputVmlinux = fopen(argv[4], "w+"); if ( ! outputVmlinux ) { - printf("output vmlinux file \"%s\" failed to open.\n", argv[4]); + fprintf(stderr, "output vmlinux file \"%s\" failed to open.\n", argv[4]); exit(1); } @@ -118,7 +118,7 @@ int main(int argc, char **argv) fseek(inputVmlinux, 0, SEEK_SET); printf("kernel file size = %d\n", kernelLen); if ( kernelLen == 0 ) { - printf("You must have a linux kernel specified as argv[3]\n"); + fprintf(stderr, "You must have a linux kernel specified as argv[3]\n"); exit(1); } @@ -154,15 +154,14 @@ int main(int argc, char **argv) /* Process the Sysmap file to determine where _end is */ sysmapPages = sysmapLen / 4096; - for (i=0; i<sysmapPages; ++i) { - get4k(sysmap, inbuf); - } + /* read the whole file line by line, expect that it doesnt fail */ + while ( fgets(inbuf, 4096, sysmap) ) ; /* search for _end in the last page of the system map */ ptr_end = strstr(inbuf, " _end"); if (!ptr_end) { - printf("Unable to find _end in the sysmap file \n"); - printf("inbuf: \n"); - printf("%s \n", inbuf); + fprintf(stderr, "Unable to find _end in the sysmap file \n"); + fprintf(stderr, "inbuf: \n"); + fprintf(stderr, "%s \n", inbuf); exit(1); } printf("Found _end in the last page of the sysmap - backing up 10 characters it looks like %s", ptr_end-10); diff --git a/arch/ppc64/boot/addSystemMap.c b/arch/ppc64/boot/addSystemMap.c index 394028458ad74e11c74da89ca26837252035e199..03b9187d0c0095b7afaf2664fe6d541064b619cb 100644 --- a/arch/ppc64/boot/addSystemMap.c +++ b/arch/ppc64/boot/addSystemMap.c @@ -64,38 +64,38 @@ int main(int argc, char **argv) long padPages = 0; if ( argc < 2 ) { - printf("Name of System Map file missing.\n"); + fprintf(stderr, "Name of System Map file missing.\n"); exit(1); } if ( argc < 3 ) { - printf("Name of vmlinux file missing.\n"); + fprintf(stderr, "Name of vmlinux file missing.\n"); exit(1); } if ( argc < 4 ) { - printf("Name of vmlinux output file missing.\n"); + fprintf(stderr, "Name of vmlinux output file missing.\n"); exit(1); } sysmap = fopen(argv[1], "r"); if ( ! sysmap ) { - printf("System Map file \"%s\" failed to open.\n", argv[1]); + fprintf(stderr, "System Map file \"%s\" failed to open.\n", argv[1]); exit(1); } inputVmlinux = fopen(argv[2], "r"); if ( ! inputVmlinux ) { - printf("vmlinux file \"%s\" failed to open.\n", argv[2]); + fprintf(stderr, "vmlinux file \"%s\" failed to open.\n", argv[2]); exit(1); } outputVmlinux = fopen(argv[3], "w"); if ( ! outputVmlinux ) { - printf("output vmlinux file \"%s\" failed to open.\n", argv[3]); + fprintf(stderr, "output vmlinux file \"%s\" failed to open.\n", argv[3]); exit(1); } @@ -107,7 +107,7 @@ int main(int argc, char **argv) printf("kernel file size = %ld\n", kernelLen); if ( kernelLen == 0 ) { - printf("You must have a linux kernel specified as argv[2]\n"); + fprintf(stderr, "You must have a linux kernel specified as argv[2]\n"); exit(1); } @@ -146,17 +146,15 @@ int main(int argc, char **argv) /* Process the Sysmap file to determine the true end of the kernel */ sysmapPages = sysmapLen / 4096; printf("System map pages to copy = %ld\n", sysmapPages); - for (i=0; i<sysmapPages; ++i) - { - get4k(sysmap, inbuf); - } + /* read the whole file line by line, expect that it doesnt fail */ + while ( fgets(inbuf, 4096, sysmap) ) ; /* search for _end in the last page of the system map */ ptr_end = strstr(inbuf, " _end"); if (!ptr_end) { - printf("Unable to find _end in the sysmap file \n"); - printf("inbuf: \n"); - printf("%s \n", inbuf); + fprintf(stderr, "Unable to find _end in the sysmap file \n"); + fprintf(stderr, "inbuf: \n"); + fprintf(stderr, "%s \n", inbuf); exit(1); } printf("Found _end in the last page of the sysmap - backing up 10 characters it looks like %s", ptr_end-10); diff --git a/arch/ppc64/boot/crt0.S b/arch/ppc64/boot/crt0.S index 00a76ab75708e5f9b63c95fa69044cd34881f06d..04d3e74cd72f7d53fd9fbbfe7378a6b2f5e62e2f 100644 --- a/arch/ppc64/boot/crt0.S +++ b/arch/ppc64/boot/crt0.S @@ -8,258 +8,41 @@ * * NOTE: this code runs in 32 bit mode and is packaged as ELF32. */ + +#include <asm/ppc_asm.h> + .text .globl _start _start: - lis 9,_start@h - lis 8,_etext@ha - addi 8,8,_etext@l -1: dcbf 0,9 - icbi 0,9 - addi 9,9,0x20 - cmplwi 0,9,8 + lis r9,_start@h + lis r8,_etext@ha + addi r8,r8,_etext@l +1: dcbf r0,r9 + icbi r0,r9 + addi r9,r9,0x20 + cmplwi 0,r9,8 blt 1b sync isync ## Clear out the BSS as per ANSI C requirements - lis 7,_end@ha - addi 7,7,_end@l # r7 = &_end - lis 8,__bss_start@ha # - addi 8,8,__bss_start@l # r8 = &_bss_start + lis r7,_end@ha + addi r7,r7,_end@l # r7 = &_end + lis r8,__bss_start@ha # + addi r8,r8,__bss_start@l # r8 = &_bss_start ## Determine how large an area, in number of words, to clear - subf 7,8,7 # r7 = &_end - &_bss_start + 1 - addi 7,7,3 # r7 += 3 - srwi. 7,7,2 # r7 = size in words. - beq 3f # If the size is zero, do not bother - addi 8,8,-4 # r8 -= 4 - mtctr 7 # SPRN_CTR = number of words to clear - li 0,0 # r0 = 0 -2: stwu 0,4(8) # Clear out a word - bdnz 2b # If we are not done yet, keep clearing + subf r7,r8,r7 # r7 = &_end - &_bss_start + 1 + addi r7,r7,3 # r7 += 3 + srwi. r7,r7,2 # r7 = size in words. + beq 3f # If the size is zero, don't bother + addi r8,r8,-4 # r8 -= 4 + mtctr r7 # SPRN_CTR = number of words to clear + li r0,0 # r0 = 0 +2: stwu r0,4(r8) # Clear out a word + bdnz 2b # Keep clearing until done 3: - - b start - - -/* - * 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 - - -#define r0 0 -#define r3 3 -#define r4 4 -#define r5 5 -#define r6 6 -#define r7 7 -#define r8 8 - - .globl strcpy -strcpy: - addi r5,r3,-1 - addi r4,r4,-1 -1: lbzu r0,1(r4) - cmpwi 0,r0,0 - stbu r0,1(r5) - bne 1b - blr - - .globl strncpy -strncpy: - cmpwi 0,r5,0 - beqlr - mtctr r5 - addi r6,r3,-1 - addi r4,r4,-1 -1: lbzu r0,1(r4) - cmpwi 0,r0,0 - stbu r0,1(r6) - bdnzf 2,1b /* dec ctr, branch if ctr != 0 && !cr0.eq */ - blr - - .globl strcat -strcat: - addi r5,r3,-1 - addi r4,r4,-1 -1: lbzu r0,1(r5) - cmpwi 0,r0,0 - bne 1b - addi r5,r5,-1 -1: lbzu r0,1(r4) - cmpwi 0,r0,0 - stbu r0,1(r5) - bne 1b - blr - - .globl strcmp -strcmp: - addi r5,r3,-1 - addi r4,r4,-1 -1: lbzu r3,1(r5) - cmpwi 1,r3,0 - lbzu r0,1(r4) - subf. r3,r0,r3 - beqlr 1 - beq 1b - blr - - .globl strlen -strlen: - addi r4,r3,-1 -1: lbzu r0,1(r4) - cmpwi 0,r0,0 - bne 1b - subf r3,r3,r4 - blr - - .globl memset -memset: - rlwimi r4,r4,8,16,23 - rlwimi r4,r4,16,0,15 - addi r6,r3,-4 - cmplwi 0,r5,4 - blt 7f - stwu r4,4(r6) - beqlr - andi. r0,r6,3 - add r5,r0,r5 - subf r6,r0,r6 - rlwinm r0,r5,32-2,2,31 - mtctr r0 - bdz 6f -1: stwu r4,4(r6) - bdnz 1b -6: andi. r5,r5,3 -7: cmpwi 0,r5,0 - beqlr - mtctr r5 - addi r6,r6,3 -8: stbu r4,1(r6) - bdnz 8b - blr - - .globl bcopy -bcopy: - mr r6,r3 - mr r3,r4 - mr r4,r6 - b memcpy - - .globl memmove -memmove: - cmplw 0,r3,r4 - bgt backwards_memcpy - /* fall through */ - - .globl memcpy -memcpy: - rlwinm. r7,r5,32-3,3,31 /* r0 = r5 >> 3 */ - addi r6,r3,-4 - addi r4,r4,-4 - beq 2f /* if less than 8 bytes to do */ - andi. r0,r6,3 /* get dest word aligned */ - mtctr r7 - bne 5f -1: lwz r7,4(r4) - lwzu r8,8(r4) - stw r7,4(r6) - stwu r8,8(r6) - bdnz 1b - andi. r5,r5,7 -2: cmplwi 0,r5,4 - blt 3f - lwzu r0,4(r4) - addi r5,r5,-4 - stwu r0,4(r6) -3: cmpwi 0,r5,0 - beqlr - mtctr r5 - addi r4,r4,3 - addi r6,r6,3 -4: lbzu r0,1(r4) - stbu r0,1(r6) - bdnz 4b - blr -5: subfic r0,r0,4 - mtctr r0 -6: lbz r7,4(r4) - addi r4,r4,1 - stb r7,4(r6) - addi r6,r6,1 - bdnz 6b - subf r5,r0,r5 - rlwinm. r7,r5,32-3,3,31 - beq 2b - mtctr r7 - b 1b - - .globl backwards_memcpy -backwards_memcpy: - rlwinm. r7,r5,32-3,3,31 /* r0 = r5 >> 3 */ - add r6,r3,r5 - add r4,r4,r5 - beq 2f - andi. r0,r6,3 - mtctr r7 - bne 5f -1: lwz r7,-4(r4) - lwzu r8,-8(r4) - stw r7,-4(r6) - stwu r8,-8(r6) - bdnz 1b - andi. r5,r5,7 -2: cmplwi 0,r5,4 - blt 3f - lwzu r0,-4(r4) - subi r5,r5,4 - stwu r0,-4(r6) -3: cmpwi 0,r5,0 - beqlr - mtctr r5 -4: lbzu r0,-1(r4) - stbu r0,-1(r6) - bdnz 4b - blr -5: mtctr r0 -6: lbzu r7,-1(r4) - stbu r7,-1(r6) - bdnz 6b - subf r5,r0,r5 - rlwinm. r7,r5,32-3,3,31 - beq 2b - mtctr r7 - b 1b - - .globl memcmp -memcmp: - cmpwi 0,r5,0 - blelr - mtctr r5 - addi r6,r3,-1 - addi r4,r4,-1 -1: lbzu r3,1(r6) - lbzu r0,1(r4) - subf. r3,r0,r3 - bdnzt 2,1b - blr diff --git a/arch/ppc64/boot/main.c b/arch/ppc64/boot/main.c index 8d14d7172480b2a9be0907825695d447e79be5cd..11a6b84934788a162e9402af74b040e6801c789d 100644 --- a/arch/ppc64/boot/main.c +++ b/arch/ppc64/boot/main.c @@ -1,7 +1,7 @@ /* * Copyright (C) Paul Mackerras 1997. * - * Updates for PPC64 by Todd Inglett & Dave Engebretsen. + * Updates for PPC64 by Todd Inglett, Dave Engebretsen & Peter Bergner. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -9,31 +9,31 @@ * 2 of the License, or (at your option) any later version. */ #define __KERNEL__ +#include "ppc32-types.h" #include "zlib.h" +#include <linux/elf.h> #include <asm/processor.h> #include <asm/page.h> #include <asm/bootinfo.h> -#undef DEBUG - void memmove(void *dst, void *im, int len); extern void *finddevice(const char *); extern int getprop(void *, const char *, void *, int); +extern void printk(char *fmt, ...); extern void printf(const char *fmt, ...); extern int sprintf(char *buf, const char *fmt, ...); void gunzip(void *, int, unsigned char *, int *); void *claim(unsigned int, unsigned int, unsigned int); -void flush_cache(void *, int); +void flush_cache(void *, unsigned long); void pause(void); +extern void exit(void); + static struct bi_record *make_bi_recs(unsigned long); #define RAM_START 0x00000000 #define RAM_END (64<<20) -#define BOOT_START ((unsigned long)_start) -#define BOOT_END ((unsigned long)_end) - /* Value picked to match that used by yaboot */ #define PROG_START 0x01400000 @@ -42,18 +42,26 @@ char *begin_avail, *end_avail; char *avail_high; unsigned int heap_use; unsigned int heap_max; -unsigned long initrd_start = 0; -unsigned long initrd_size = 0; extern char _end[]; -extern char image_data[]; -extern int image_len; -extern char initrd_data[]; -extern int initrd_len; -extern char sysmap_data[]; -extern int sysmap_len; -extern int uncompressed_size; -extern long vmlinux_end; +extern char _vmlinux_start[]; +extern char _vmlinux_end[]; +extern char _sysmap_start[]; +extern char _sysmap_end[]; +extern char _initrd_start[]; +extern char _initrd_end[]; +extern unsigned long vmlinux_filesize; +extern unsigned long vmlinux_memsize; + +struct addr_range { + unsigned long addr; + unsigned long size; + unsigned long memsize; +}; +struct addr_range vmlinux = {0, 0, 0}; +struct addr_range vmlinuz = {0, 0, 0}; +struct addr_range sysmap = {0, 0, 0}; +struct addr_range initrd = {0, 0, 0}; static char scratch[128<<10]; /* 128kB of scratch space for gunzip */ @@ -62,67 +70,126 @@ typedef void (*kernel_entry_t)( unsigned long, void *, struct bi_record *); + +int (*prom)(void *); + +void *chosen_handle; +void *stdin; +void *stdout; +void *stderr; + + void -chrpboot(unsigned long a1, unsigned long a2, void *prom) +start(unsigned long a1, unsigned long a2, void *promptr) { - unsigned len; - void *dst = (void *)-1; - unsigned long claim_addr; - unsigned char *im; + unsigned long i, claim_addr, claim_size; extern char _start; struct bi_record *bi_recs; kernel_entry_t kernel_entry; - - printf("chrpboot starting: loaded at 0x%x\n\r", (unsigned)&_start); + Elf64_Ehdr *elf64; + Elf64_Phdr *elf64ph; - if (initrd_len) { - initrd_size = initrd_len; - initrd_start = (RAM_END - initrd_size) & ~0xFFF; + prom = (int (*)(void *)) promptr; + chosen_handle = finddevice("/chosen"); + if (chosen_handle == (void *) -1) + exit(); + if (getprop(chosen_handle, "stdout", &stdout, sizeof(stdout)) != 4) + exit(); + stderr = stdout; + if (getprop(chosen_handle, "stdin", &stdin, sizeof(stdin)) != 4) + exit(); + + printf("zImage starting: loaded at 0x%x\n\r", (unsigned)&_start); + +#if 0 + sysmap.size = (unsigned long)(_sysmap_end - _sysmap_start); + sysmap.memsize = sysmap.size; + if ( sysmap.size > 0 ) { + sysmap.addr = (RAM_END - sysmap.size) & ~0xFFF; + claim(sysmap.addr, RAM_END - sysmap.addr, 0); + printf("initial ramdisk moving 0x%lx <- 0x%lx (%lx bytes)\n\r", + sysmap.addr, (unsigned long)_sysmap_start, sysmap.size); + memcpy((void *)sysmap.addr, (void *)_sysmap_start, sysmap.size); + } +#endif + + initrd.size = (unsigned long)(_initrd_end - _initrd_start); + initrd.memsize = initrd.size; + if ( initrd.size > 0 ) { + initrd.addr = (RAM_END - initrd.size) & ~0xFFF; a1 = a2 = 0; - claim(initrd_start, RAM_END - initrd_start, 0); + claim(initrd.addr, RAM_END - initrd.addr, 0); printf("initial ramdisk moving 0x%lx <- 0x%lx (%lx bytes)\n\r", - initrd_start, (unsigned long)initrd_data, initrd_size); - memcpy((void *)initrd_start, (void *)initrd_data, initrd_size); + initrd.addr, (unsigned long)_initrd_start, initrd.size); + memcpy((void *)initrd.addr, (void *)_initrd_start, initrd.size); } - im = image_data; - len = image_len; - uncompressed_size = PAGE_ALIGN(uncompressed_size); + vmlinuz.addr = (unsigned long)_vmlinux_start; + vmlinuz.size = (unsigned long)(_vmlinux_end - _vmlinux_start); + vmlinux.addr = (unsigned long)(void *)-1; + vmlinux.size = PAGE_ALIGN(vmlinux_filesize); + vmlinux.memsize = vmlinux_memsize; + claim_size = vmlinux.memsize /* PPPBBB: + fudge for bi_recs */; for(claim_addr = PROG_START; claim_addr <= PROG_START * 8; claim_addr += 0x100000) { -#ifdef DEBUG printf(" trying: 0x%08lx\n\r", claim_addr); -#endif - dst = claim(claim_addr, uncompressed_size, 0); - if (dst != (void *)-1) break; + vmlinux.addr = (unsigned long)claim(claim_addr, claim_size, 0); + if ((void *)vmlinux.addr != (void *)-1) break; } - if (dst == (void *)-1) { + if ((void *)vmlinux.addr == (void *)-1) { printf("claim error, can't allocate kernel memory\n\r"); - return; + exit(); } - if (im[0] == 0x1f && im[1] == 0x8b) { + /* PPPBBB: should kernel always be gziped? */ + if (*(unsigned short *)vmlinuz.addr == 0x1f8b) { avail_ram = scratch; begin_avail = avail_high = avail_ram; end_avail = scratch + sizeof(scratch); - printf("gunzipping (0x%x <- 0x%x:0x%0x)...", - (unsigned)dst, (unsigned)im, (unsigned)im+len); - gunzip(dst, uncompressed_size, im, &len); - printf("done %u bytes\n\r", len); + printf("gunzipping (0x%lx <- 0x%lx:0x%0lx)...", + vmlinux.addr, vmlinuz.addr, vmlinuz.addr+vmlinuz.size); + gunzip((void *)vmlinux.addr, vmlinux.size, + (unsigned char *)vmlinuz.addr, (int *)&vmlinuz.size); + printf("done %lu bytes\n\r", vmlinuz.size); printf("%u bytes of heap consumed, max in use %u\n\r", (unsigned)(avail_high - begin_avail), heap_max); } else { - memmove(dst, im, len); + memmove((void *)vmlinux.addr,(void *)vmlinuz.addr,vmlinuz.size); + } + + /* Skip over the ELF header */ + elf64 = (Elf64_Ehdr *)vmlinux.addr; + if ( elf64->e_ident[EI_MAG0] != ELFMAG0 || + elf64->e_ident[EI_MAG1] != ELFMAG1 || + elf64->e_ident[EI_MAG2] != ELFMAG2 || + elf64->e_ident[EI_MAG3] != ELFMAG3 || + elf64->e_ident[EI_CLASS] != ELFCLASS64 || + elf64->e_ident[EI_DATA] != ELFDATA2MSB || + elf64->e_type != ET_EXEC || + elf64->e_machine != EM_PPC64 ) + { + printf("Error: not a valid PPC64 ELF file!\n\r"); + exit(); + } + + elf64ph = (Elf64_Phdr *)((unsigned long)elf64 + + (unsigned long)elf64->e_phoff); + for(i=0; i < (unsigned int)elf64->e_phnum ;i++,elf64ph++) { + if (elf64ph->p_type == PT_LOAD && elf64ph->p_offset != 0) + break; } + printf("... skipping 0x%lx bytes of ELF header\n\r", + (unsigned long)elf64ph->p_offset); + vmlinux.addr += (unsigned long)elf64ph->p_offset; + vmlinux.size -= (unsigned long)elf64ph->p_offset; - flush_cache(dst, len); + flush_cache((void *)vmlinux.addr, vmlinux.memsize); - bi_recs = make_bi_recs((unsigned long)dst + vmlinux_end); + bi_recs = make_bi_recs(vmlinux.addr + vmlinux.memsize); - kernel_entry = (kernel_entry_t)dst; -#ifdef DEBUG + kernel_entry = (kernel_entry_t)vmlinux.addr; printf( "kernel:\n\r" " entry addr = 0x%lx\n\r" " a1 = 0x%lx,\n\r" @@ -131,13 +198,12 @@ chrpboot(unsigned long a1, unsigned long a2, void *prom) " bi_recs = 0x%lx,\n\r", (unsigned long)kernel_entry, a1, a2, (unsigned long)prom, (unsigned long)bi_recs); -#endif kernel_entry( a1, a2, prom, bi_recs ); - printf("returned?\n\r"); + printf("Error: Linux kernel returned to zImage bootloader!\n\r"); - pause(); + exit(); } static struct bi_record * @@ -162,21 +228,19 @@ make_bi_recs(unsigned long addr) rec->data[0] = PLATFORM_PSERIES; rec->data[1] = 1; - if ( initrd_size > 0 ) { + if ( initrd.size > 0 ) { rec = bi_rec_alloc(rec, 2); rec->tag = BI_INITRD; - rec->data[0] = initrd_start; - rec->data[1] = initrd_size; + rec->data[0] = initrd.addr; + rec->data[1] = initrd.size; } -#if 0 - if ( sysmap_len > 0 ) { + if ( sysmap.size > 0 ) { rec = bi_rec_alloc(rec, 2); rec->tag = BI_SYSMAP; - rec->data[0] = (unsigned long)sysmap_data; - rec->data[1] = sysmap_len; + rec->data[0] = (unsigned long)sysmap.addr; + rec->data[1] = (unsigned long)sysmap.size; } -#endif rec = bi_rec_alloc(rec, 1); rec->tag = BI_LAST; diff --git a/arch/ppc64/boot/ppc32-types.h b/arch/ppc64/boot/ppc32-types.h new file mode 100644 index 0000000000000000000000000000000000000000..16d5be49b2841b77002371c495dbf165db7103b3 --- /dev/null +++ b/arch/ppc64/boot/ppc32-types.h @@ -0,0 +1,30 @@ +#ifndef _PPC64_TYPES_H +#define _PPC64_TYPES_H + +typedef __signed__ char __s8; +typedef unsigned char __u8; + +typedef __signed__ short __s16; +typedef unsigned short __u16; + +typedef __signed__ int __s32; +typedef unsigned int __u32; + +typedef __signed__ long long __s64; +typedef unsigned long long __u64; + +typedef signed char s8; +typedef unsigned char u8; + +typedef signed short s16; +typedef unsigned short u16; + +typedef signed int s32; +typedef unsigned int u32; + +typedef signed long long s64; +typedef unsigned long long u64; + +#define BITS_PER_LONG 32 + +#endif /* _PPC64_TYPES_H */ diff --git a/arch/ppc64/boot/prom.c b/arch/ppc64/boot/prom.c new file mode 100644 index 0000000000000000000000000000000000000000..2c620f105896426980bc472a49d6e8c27e384df4 --- /dev/null +++ b/arch/ppc64/boot/prom.c @@ -0,0 +1,636 @@ +/* + * 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 <linux/types.h> +#include <linux/string.h> +#include <linux/ctype.h> + +#include <asm/div64.h> + +int (*prom)(void *); + +void *chosen_handle; +void *stdin; +void *stdout; +void *stderr; + +void exit(void); +void *finddevice(const char *name); +int getprop(void *phandle, const char *name, void *buf, int buflen); +void chrpboot(int a1, int a2, void *prom); /* in main.c */ + +void printk(char *fmt, ...); + +int +write(void *handle, void *ptr, int nb) +{ + struct prom_args { + char *service; + int nargs; + int nret; + void *ihandle; + void *addr; + int len; + int actual; + } args; + + args.service = "write"; + args.nargs = 3; + args.nret = 1; + args.ihandle = handle; + args.addr = ptr; + args.len = nb; + args.actual = -1; + (*prom)(&args); + return args.actual; +} + +int +read(void *handle, void *ptr, int nb) +{ + struct prom_args { + char *service; + int nargs; + int nret; + void *ihandle; + void *addr; + int len; + int actual; + } args; + + args.service = "read"; + args.nargs = 3; + args.nret = 1; + args.ihandle = handle; + args.addr = ptr; + args.len = nb; + args.actual = -1; + (*prom)(&args); + return args.actual; +} + +void +exit() +{ + struct prom_args { + char *service; + } args; + + for (;;) { + args.service = "exit"; + (*prom)(&args); + } +} + +void +pause(void) +{ + struct prom_args { + char *service; + } args; + + args.service = "enter"; + (*prom)(&args); +} + +void * +finddevice(const char *name) +{ + struct prom_args { + char *service; + int nargs; + int nret; + const char *devspec; + void *phandle; + } args; + + args.service = "finddevice"; + args.nargs = 1; + args.nret = 1; + args.devspec = name; + args.phandle = (void *) -1; + (*prom)(&args); + return args.phandle; +} + +void * +claim(unsigned long virt, unsigned long size, unsigned long align) +{ + struct prom_args { + char *service; + int nargs; + int nret; + unsigned int virt; + unsigned int size; + unsigned int align; + void *ret; + } args; + + args.service = "claim"; + args.nargs = 3; + args.nret = 1; + args.virt = virt; + args.size = size; + args.align = align; + (*prom)(&args); + return args.ret; +} + +int +getprop(void *phandle, const char *name, void *buf, int buflen) +{ + struct prom_args { + char *service; + int nargs; + int nret; + void *phandle; + const char *name; + void *buf; + int buflen; + int size; + } args; + + args.service = "getprop"; + args.nargs = 4; + args.nret = 1; + args.phandle = phandle; + args.name = name; + args.buf = buf; + args.buflen = buflen; + args.size = -1; + (*prom)(&args); + return args.size; +} + +int +putc(int c, void *f) +{ + char ch = c; + + if (c == '\n') + putc('\r', f); + return write(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 write(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\r\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++; +} + + + +/* String functions lifted from lib/vsprintf.c and lib/ctype.c */ +unsigned char _ctype[] = { +_C,_C,_C,_C,_C,_C,_C,_C, /* 0-7 */ +_C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C, /* 8-15 */ +_C,_C,_C,_C,_C,_C,_C,_C, /* 16-23 */ +_C,_C,_C,_C,_C,_C,_C,_C, /* 24-31 */ +_S|_SP,_P,_P,_P,_P,_P,_P,_P, /* 32-39 */ +_P,_P,_P,_P,_P,_P,_P,_P, /* 40-47 */ +_D,_D,_D,_D,_D,_D,_D,_D, /* 48-55 */ +_D,_D,_P,_P,_P,_P,_P,_P, /* 56-63 */ +_P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U, /* 64-71 */ +_U,_U,_U,_U,_U,_U,_U,_U, /* 72-79 */ +_U,_U,_U,_U,_U,_U,_U,_U, /* 80-87 */ +_U,_U,_U,_P,_P,_P,_P,_P, /* 88-95 */ +_P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L, /* 96-103 */ +_L,_L,_L,_L,_L,_L,_L,_L, /* 104-111 */ +_L,_L,_L,_L,_L,_L,_L,_L, /* 112-119 */ +_L,_L,_L,_P,_P,_P,_P,_C, /* 120-127 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 128-143 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 144-159 */ +_S|_SP,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 160-175 */ +_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 176-191 */ +_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U, /* 192-207 */ +_U,_U,_U,_U,_U,_U,_U,_P,_U,_U,_U,_U,_U,_U,_U,_L, /* 208-223 */ +_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L, /* 224-239 */ +_L,_L,_L,_L,_L,_L,_L,_P,_L,_L,_L,_L,_L,_L,_L,_L}; /* 240-255 */ + +size_t strnlen(const char * s, size_t count) +{ + const char *sc; + + for (sc = s; count-- && *sc != '\0'; ++sc) + /* nothing */; + return sc - s; +} + +unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base) +{ + unsigned long result = 0,value; + + if (!base) { + base = 10; + if (*cp == '0') { + base = 8; + cp++; + if ((*cp == 'x') && isxdigit(cp[1])) { + cp++; + base = 16; + } + } + } + while (isxdigit(*cp) && + (value = isdigit(*cp) ? *cp-'0' : toupper(*cp)-'A'+10) < base) { + result = result*base + value; + cp++; + } + if (endp) + *endp = (char *)cp; + return result; +} + +long simple_strtol(const char *cp,char **endp,unsigned int base) +{ + if(*cp=='-') + return -simple_strtoul(cp+1,endp,base); + return simple_strtoul(cp,endp,base); +} + +static int skip_atoi(const char **s) +{ + int i=0; + + while (isdigit(**s)) + i = i*10 + *((*s)++) - '0'; + return i; +} + +#define ZEROPAD 1 /* pad with zero */ +#define SIGN 2 /* unsigned/signed long */ +#define PLUS 4 /* show plus */ +#define SPACE 8 /* space if plus */ +#define LEFT 16 /* left justified */ +#define SPECIAL 32 /* 0x */ +#define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */ + +static char * number(char * str, long long num, int base, int size, int precision, int type) +{ + char c,sign,tmp[66]; + const char *digits="0123456789abcdefghijklmnopqrstuvwxyz"; + int i; + + if (type & LARGE) + digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + if (type & LEFT) + type &= ~ZEROPAD; + if (base < 2 || base > 36) + return 0; + c = (type & ZEROPAD) ? '0' : ' '; + sign = 0; + if (type & SIGN) { + if (num < 0) { + sign = '-'; + num = -num; + size--; + } else if (type & PLUS) { + sign = '+'; + size--; + } else if (type & SPACE) { + sign = ' '; + size--; + } + } + if (type & SPECIAL) { + if (base == 16) + size -= 2; + else if (base == 8) + size--; + } + i = 0; + if (num == 0) + tmp[i++]='0'; + else while (num != 0) + tmp[i++] = digits[do_div(num,base)]; + if (i > precision) + precision = i; + size -= precision; + if (!(type&(ZEROPAD+LEFT))) + while(size-->0) + *str++ = ' '; + if (sign) + *str++ = sign; + if (type & SPECIAL) { + if (base==8) + *str++ = '0'; + else if (base==16) { + *str++ = '0'; + *str++ = digits[33]; + } + } + if (!(type & LEFT)) + while (size-- > 0) + *str++ = c; + while (i < precision--) + *str++ = '0'; + while (i-- > 0) + *str++ = tmp[i]; + while (size-- > 0) + *str++ = ' '; + return str; +} + +/* Forward decl. needed for IP address printing stuff... */ +int sprintf(char * buf, const char *fmt, ...); + +int vsprintf(char *buf, const char *fmt, va_list args) +{ + int len; + unsigned long long num; + int i, base; + char * str; + const char *s; + + int flags; /* flags to number() */ + + int field_width; /* width of output field */ + int precision; /* min. # of digits for integers; max + number of chars for from string */ + int qualifier; /* 'h', 'l', or 'L' for integer fields */ + /* 'z' support added 23/7/1999 S.H. */ + /* 'z' changed to 'Z' --davidm 1/25/99 */ + + + for (str=buf ; *fmt ; ++fmt) { + if (*fmt != '%') { + *str++ = *fmt; + continue; + } + + /* process flags */ + flags = 0; + repeat: + ++fmt; /* this also skips first '%' */ + switch (*fmt) { + case '-': flags |= LEFT; goto repeat; + case '+': flags |= PLUS; goto repeat; + case ' ': flags |= SPACE; goto repeat; + case '#': flags |= SPECIAL; goto repeat; + case '0': flags |= ZEROPAD; goto repeat; + } + + /* get field width */ + field_width = -1; + if (isdigit(*fmt)) + field_width = skip_atoi(&fmt); + else if (*fmt == '*') { + ++fmt; + /* it's the next argument */ + field_width = va_arg(args, int); + if (field_width < 0) { + field_width = -field_width; + flags |= LEFT; + } + } + + /* get the precision */ + precision = -1; + if (*fmt == '.') { + ++fmt; + if (isdigit(*fmt)) + precision = skip_atoi(&fmt); + else if (*fmt == '*') { + ++fmt; + /* it's the next argument */ + precision = va_arg(args, int); + } + if (precision < 0) + precision = 0; + } + + /* get the conversion qualifier */ + qualifier = -1; + if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || *fmt =='Z') { + qualifier = *fmt; + ++fmt; + } + + /* default base */ + base = 10; + + switch (*fmt) { + case 'c': + if (!(flags & LEFT)) + while (--field_width > 0) + *str++ = ' '; + *str++ = (unsigned char) va_arg(args, int); + while (--field_width > 0) + *str++ = ' '; + continue; + + case 's': + s = va_arg(args, char *); + if (!s) + s = "<NULL>"; + + len = strnlen(s, precision); + + if (!(flags & LEFT)) + while (len < field_width--) + *str++ = ' '; + for (i = 0; i < len; ++i) + *str++ = *s++; + while (len < field_width--) + *str++ = ' '; + continue; + + case 'p': + if (field_width == -1) { + field_width = 2*sizeof(void *); + flags |= ZEROPAD; + } + str = number(str, + (unsigned long) va_arg(args, void *), 16, + field_width, precision, flags); + continue; + + + case 'n': + if (qualifier == 'l') { + long * ip = va_arg(args, long *); + *ip = (str - buf); + } else if (qualifier == 'Z') { + size_t * ip = va_arg(args, size_t *); + *ip = (str - buf); + } else { + int * ip = va_arg(args, int *); + *ip = (str - buf); + } + continue; + + case '%': + *str++ = '%'; + continue; + + /* integer number formats - set up the flags and "break" */ + case 'o': + base = 8; + break; + + case 'X': + flags |= LARGE; + case 'x': + base = 16; + break; + + case 'd': + case 'i': + flags |= SIGN; + case 'u': + break; + + default: + *str++ = '%'; + if (*fmt) + *str++ = *fmt; + else + --fmt; + continue; + } + if (qualifier == 'L') + num = va_arg(args, long long); + else if (qualifier == 'l') { + num = va_arg(args, unsigned long); + if (flags & SIGN) + num = (signed long) num; + } else if (qualifier == 'Z') { + num = va_arg(args, size_t); + } else if (qualifier == 'h') { + num = (unsigned short) va_arg(args, int); + if (flags & SIGN) + num = (signed short) num; + } else { + num = va_arg(args, unsigned int); + if (flags & SIGN) + num = (signed int) num; + } + str = number(str, num, base, field_width, precision, flags); + } + *str = '\0'; + return str-buf; +} + +int sprintf(char * buf, const char *fmt, ...) +{ + va_list args; + int i; + + va_start(args, fmt); + i=vsprintf(buf,fmt,args); + va_end(args); + return i; +} + +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); + write(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); + write(stdout, sprint_buf, n); + return n; +} diff --git a/arch/ppc64/boot/string.S b/arch/ppc64/boot/string.S new file mode 100644 index 0000000000000000000000000000000000000000..105368607e85e43b0cfdc3365b9c17bd0150c070 --- /dev/null +++ b/arch/ppc64/boot/string.S @@ -0,0 +1,223 @@ +/* + * 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. + * + * NOTE: this code runs in 32 bit mode and is packaged as ELF32. + */ + +#include <asm/ppc_asm.h> + + .text + .globl strcpy +strcpy: + addi r5,r3,-1 + addi r4,r4,-1 +1: lbzu r0,1(r4) + cmpwi 0,r0,0 + stbu r0,1(r5) + bne 1b + blr + + .globl strncpy +strncpy: + cmpwi 0,r5,0 + beqlr + mtctr r5 + addi r6,r3,-1 + addi r4,r4,-1 +1: lbzu r0,1(r4) + cmpwi 0,r0,0 + stbu r0,1(r6) + bdnzf 2,1b /* dec ctr, branch if ctr != 0 && !cr0.eq */ + blr + + .globl strcat +strcat: + addi r5,r3,-1 + addi r4,r4,-1 +1: lbzu r0,1(r5) + cmpwi 0,r0,0 + bne 1b + addi r5,r5,-1 +1: lbzu r0,1(r4) + cmpwi 0,r0,0 + stbu r0,1(r5) + bne 1b + blr + + .globl strcmp +strcmp: + addi r5,r3,-1 + addi r4,r4,-1 +1: lbzu r3,1(r5) + cmpwi 1,r3,0 + lbzu r0,1(r4) + subf. r3,r0,r3 + beqlr 1 + beq 1b + blr + + .globl strlen +strlen: + addi r4,r3,-1 +1: lbzu r0,1(r4) + cmpwi 0,r0,0 + bne 1b + subf r3,r3,r4 + blr + + .globl memset +memset: + rlwimi r4,r4,8,16,23 + rlwimi r4,r4,16,0,15 + addi r6,r3,-4 + cmplwi 0,r5,4 + blt 7f + stwu r4,4(r6) + beqlr + andi. r0,r6,3 + add r5,r0,r5 + subf r6,r0,r6 + rlwinm r0,r5,32-2,2,31 + mtctr r0 + bdz 6f +1: stwu r4,4(r6) + bdnz 1b +6: andi. r5,r5,3 +7: cmpwi 0,r5,0 + beqlr + mtctr r5 + addi r6,r6,3 +8: stbu r4,1(r6) + bdnz 8b + blr + + .globl bcopy +bcopy: + mr r6,r3 + mr r3,r4 + mr r4,r6 + b memcpy + + .globl memmove +memmove: + cmplw 0,r3,r4 + bgt backwards_memcpy + /* fall through */ + + .globl memcpy +memcpy: + rlwinm. r7,r5,32-3,3,31 /* r0 = r5 >> 3 */ + addi r6,r3,-4 + addi r4,r4,-4 + beq 2f /* if less than 8 bytes to do */ + andi. r0,r6,3 /* get dest word aligned */ + mtctr r7 + bne 5f +1: lwz r7,4(r4) + lwzu r8,8(r4) + stw r7,4(r6) + stwu r8,8(r6) + bdnz 1b + andi. r5,r5,7 +2: cmplwi 0,r5,4 + blt 3f + lwzu r0,4(r4) + addi r5,r5,-4 + stwu r0,4(r6) +3: cmpwi 0,r5,0 + beqlr + mtctr r5 + addi r4,r4,3 + addi r6,r6,3 +4: lbzu r0,1(r4) + stbu r0,1(r6) + bdnz 4b + blr +5: subfic r0,r0,4 + mtctr r0 +6: lbz r7,4(r4) + addi r4,r4,1 + stb r7,4(r6) + addi r6,r6,1 + bdnz 6b + subf r5,r0,r5 + rlwinm. r7,r5,32-3,3,31 + beq 2b + mtctr r7 + b 1b + + .globl backwards_memcpy +backwards_memcpy: + rlwinm. r7,r5,32-3,3,31 /* r0 = r5 >> 3 */ + add r6,r3,r5 + add r4,r4,r5 + beq 2f + andi. r0,r6,3 + mtctr r7 + bne 5f +1: lwz r7,-4(r4) + lwzu r8,-8(r4) + stw r7,-4(r6) + stwu r8,-8(r6) + bdnz 1b + andi. r5,r5,7 +2: cmplwi 0,r5,4 + blt 3f + lwzu r0,-4(r4) + subi r5,r5,4 + stwu r0,-4(r6) +3: cmpwi 0,r5,0 + beqlr + mtctr r5 +4: lbzu r0,-1(r4) + stbu r0,-1(r6) + bdnz 4b + blr +5: mtctr r0 +6: lbzu r7,-1(r4) + stbu r7,-1(r6) + bdnz 6b + subf r5,r0,r5 + rlwinm. r7,r5,32-3,3,31 + beq 2b + mtctr r7 + b 1b + + .globl memcmp +memcmp: + cmpwi 0,r5,0 + blelr + mtctr r5 + addi r6,r3,-1 + addi r4,r4,-1 +1: lbzu r3,1(r6) + lbzu r0,1(r4) + subf. r3,r0,r3 + bdnzt 2,1b + 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/ppc64/boot/zImage.lds b/arch/ppc64/boot/zImage.lds index f0a4179ab7a4e9b7c5d7b4b1e015b91544a23794..7070cd2f77de7d8b6a7b27a311f286c2d298f084 100644 --- a/arch/ppc64/boot/zImage.lds +++ b/arch/ppc64/boot/zImage.lds @@ -58,6 +58,27 @@ SECTIONS *(.dynamic) CONSTRUCTORS } + + . = ALIGN(4096); + _vmlinux_start = .; + .kernel:vmlinux : { *(.kernel:vmlinux) } + _vmlinux_end = .; + + . = ALIGN(4096); + _dotconfig_start = .; + .kernel:.config : { *(.kernel:.config) } + _dotconfig_end = .; + + . = ALIGN(4096); + _sysmap_start = .; + .kernel:System.map : { *(.kernel:System.map) } + _sysmap_end = .; + + . = ALIGN(4096); + _initrd_start = .; + .kernel:initrd : { *(.kernel:initrd) } + _initrd_end = .; + . = ALIGN(4096); _edata = .; PROVIDE (edata = .);