aboutsummaryrefslogtreecommitdiff
path: root/arch/powerpc
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@samba.org>2005-11-16 13:38:21 +1100
committerPaul Mackerras <paulus@samba.org>2005-11-16 13:52:21 +1100
commit94b212c29f685ca54b5689a8e89ac7671c43d651 (patch)
tree356266520a5ba530b2a5b77b68e90e87a2402ecb /arch/powerpc
parent7486a38f683d49e6f8b2b9050ff06778b151a40c (diff)
powerpc: Move ppc64 boot wrapper code over to arch/powerpc
This also extends the code to handle 32-bit ELF vmlinux files as well as 64-bit ones. This is sufficient for booting on new-world 32-bit powermacs (i.e. all recent machines). Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc')
-rw-r--r--arch/powerpc/Makefile25
-rw-r--r--arch/powerpc/boot/Makefile149
-rw-r--r--arch/powerpc/boot/README11
-rw-r--r--arch/powerpc/boot/addRamDisk.c311
-rw-r--r--arch/powerpc/boot/addnote.c205
-rw-r--r--arch/powerpc/boot/crt0.S59
-rw-r--r--arch/powerpc/boot/div64.S58
-rw-r--r--arch/powerpc/boot/elf.h149
-rw-r--r--arch/powerpc/boot/install.sh42
-rw-r--r--arch/powerpc/boot/main.c321
-rw-r--r--arch/powerpc/boot/page.h34
-rw-r--r--arch/powerpc/boot/ppc_asm.h62
-rw-r--r--arch/powerpc/boot/prom.c499
-rw-r--r--arch/powerpc/boot/prom.h18
-rw-r--r--arch/powerpc/boot/stdio.h16
-rw-r--r--arch/powerpc/boot/string.S216
-rw-r--r--arch/powerpc/boot/string.h17
-rw-r--r--arch/powerpc/boot/zImage.lds46
18 files changed, 2220 insertions, 18 deletions
diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile
index d41ad2e675d..99dbea8c5c5 100644
--- a/arch/powerpc/Makefile
+++ b/arch/powerpc/Makefile
@@ -14,10 +14,6 @@
HAS_BIARCH := $(call cc-option-yn, -m32)
-ifeq ($(CONFIG_PPC64),y)
-OLDARCH := ppc64
-SZ := 64
-
# Set default 32 bits cross compilers for vdso and boot wrapper
CROSS32_COMPILE ?=
@@ -37,6 +33,10 @@ endif
export CROSS32CC CROSS32AS CROSS32LD CROSS32OBJCOPY
+ifeq ($(CONFIG_PPC64),y)
+OLDARCH := ppc64
+SZ := 64
+
new_nm := $(shell if $(NM) --help 2>&1 | grep -- '--synthetic' > /dev/null; then echo y; else echo n; fi)
ifeq ($(new_nm),y)
@@ -139,7 +139,7 @@ drivers-$(CONFIG_CPM2) += arch/ppc/8260_io/
drivers-$(CONFIG_OPROFILE) += arch/powerpc/oprofile/
-defaultimage-$(CONFIG_PPC32) := uImage zImage
+defaultimage-$(CONFIG_PPC32) := zImage
defaultimage-$(CONFIG_PPC_ISERIES) := vmlinux
defaultimage-$(CONFIG_PPC_PSERIES) := zImage
KBUILD_IMAGE := $(defaultimage-y)
@@ -154,23 +154,13 @@ BOOT_TARGETS = zImage zImage.initrd znetboot znetboot.initrd vmlinux.sm
.PHONY: $(BOOT_TARGETS)
-boot := arch/$(OLDARCH)/boot
+boot := arch/$(ARCH)/boot
-# urk
-ifeq ($(CONFIG_PPC64),y)
$(BOOT_TARGETS): vmlinux
$(Q)$(MAKE) ARCH=ppc64 $(build)=$(boot) $(patsubst %,$(boot)/%,$@)
-else
-$(BOOT_TARGETS): vmlinux
- $(Q)$(MAKE) ARCH=ppc $(build)=$(boot) $@
-endif
-
-uImage: vmlinux
- $(Q)$(MAKE) ARCH=$(OLDARCH) $(build)=$(boot)/images $(boot)/images/$@
define archhelp
- @echo '* zImage - Compressed kernel image (arch/$(ARCH)/boot/images/zImage.*)'
- @echo ' uImage - Create a bootable image for U-Boot / PPCBoot'
+ @echo '* zImage - Compressed kernel image (arch/$(ARCH)/boot/zImage.*)'
@echo ' install - Install kernel using'
@echo ' (your) ~/bin/installkernel or'
@echo ' (distribution) /sbin/installkernel or'
@@ -180,7 +170,6 @@ endef
archclean:
$(Q)$(MAKE) $(clean)=$(boot)
- # Temporary hack until we have migrated to asm-powerpc
$(Q)rm -rf arch/$(ARCH)/include
archprepare: checkbin
diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile
new file mode 100644
index 00000000000..9770f587af7
--- /dev/null
+++ b/arch/powerpc/boot/Makefile
@@ -0,0 +1,149 @@
+# Makefile for making ELF bootable images for booting on CHRP
+# using Open Firmware.
+#
+# Geert Uytterhoeven September 1997
+#
+# Based on coffboot by Paul Mackerras
+# Simplified for ppc64 by Todd Inglett
+#
+# NOTE: this code is built for 32 bit in ELF32 format even though
+# it packages a 64 bit kernel. We do this to simplify the
+# bootloader and increase compatibility with OpenFirmware.
+#
+# To this end we need to define BOOTCC, etc, as the tools
+# needed to build the 32 bit image. These are normally HOSTCC,
+# but may be a third compiler if, for example, you are cross
+# compiling from an intel box. Once the 64bit ppc gcc is
+# stable it will probably simply be a compiler switch to
+# compile for 32bit mode.
+# To make it easier to setup a cross compiler,
+# CROSS32_COMPILE is setup as a prefix just like CROSS_COMPILE
+# in the toplevel makefile.
+
+
+HOSTCC := gcc
+BOOTCFLAGS := $(HOSTCFLAGS) -fno-builtin -nostdinc -isystem \
+ $(shell $(CROSS32CC) -print-file-name=include) -fPIC
+BOOTAFLAGS := -D__ASSEMBLY__ $(BOOTCFLAGS) -traditional -nostdinc
+BOOTLFLAGS := -T $(srctree)/$(src)/zImage.lds
+OBJCOPYFLAGS := contents,alloc,load,readonly,data
+
+zlib := infblock.c infcodes.c inffast.c inflate.c inftrees.c infutil.c
+zlibheader := infblock.h infcodes.h inffast.h inftrees.h infutil.h
+zliblinuxheader := zlib.h zconf.h zutil.h
+
+$(addprefix $(obj)/,$(zlib) main.o): $(addprefix $(obj)/,$(zliblinuxheader)) $(addprefix $(obj)/,$(zlibheader))
+#$(addprefix $(obj)/,main.o): $(addprefix $(obj)/,zlib.h)
+
+src-boot := string.S prom.c main.c div64.S crt0.S
+src-boot += $(zlib)
+src-boot := $(addprefix $(obj)/, $(src-boot))
+obj-boot := $(addsuffix .o, $(basename $(src-boot)))
+
+BOOTCFLAGS += -I$(obj) -I$(srctree)/$(obj)
+
+quiet_cmd_copy_zlib = COPY $@
+ cmd_copy_zlib = sed "s@__attribute_used__@@;s@<linux/\([^>]\+\).*@\"\1\"@" $< > $@
+
+quiet_cmd_copy_zlibheader = COPY $@
+ cmd_copy_zlibheader = sed "s@<linux/\([^>]\+\).*@\"\1\"@" $< > $@
+# stddef.h for NULL
+quiet_cmd_copy_zliblinuxheader = COPY $@
+ cmd_copy_zliblinuxheader = sed "s@<linux/string.h>@\"string.h\"@;s@<linux/kernel.h>@<stddef.h>@;s@<linux/\([^>]\+\).*@\"\1\"@" $< > $@
+
+$(addprefix $(obj)/,$(zlib)): $(obj)/%: $(srctree)/lib/zlib_inflate/%
+ $(call cmd,copy_zlib)
+
+$(addprefix $(obj)/,$(zlibheader)): $(obj)/%: $(srctree)/lib/zlib_inflate/%
+ $(call cmd,copy_zlibheader)
+
+$(addprefix $(obj)/,$(zliblinuxheader)): $(obj)/%: $(srctree)/include/linux/%
+ $(call cmd,copy_zliblinuxheader)
+
+clean-files := $(zlib) $(zlibheader) $(zliblinuxheader)
+
+
+quiet_cmd_bootcc = BOOTCC $@
+ cmd_bootcc = $(CROSS32CC) -Wp,-MD,$(depfile) $(BOOTCFLAGS) -c -o $@ $<
+
+quiet_cmd_bootas = BOOTAS $@
+ cmd_bootas = $(CROSS32CC) -Wp,-MD,$(depfile) $(BOOTAFLAGS) -c -o $@ $<
+
+quiet_cmd_bootld = BOOTLD $@
+ cmd_bootld = $(CROSS32LD) $(BOOTLFLAGS) -o $@ $(2)
+
+$(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)
+
+#-----------------------------------------------------------
+# ELF sections within the zImage bootloader/wrapper
+#-----------------------------------------------------------
+required := vmlinux.strip
+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)))
+
+hostprogs-y := addnote addRamDisk
+targets += zImage.vmode zImage.initrd.vmode zImage zImage.initrd \
+ $(patsubst $(obj)/%,%, $(call obj-sec, $(required) $(initrd))) \
+ $(patsubst $(obj)/%,%, $(call src-sec, $(required) $(initrd))) \
+ $(patsubst $(obj)/%,%, $(call gz-sec, $(required) $(initrd))) \
+ vmlinux.initrd
+extra-y := initrd.o
+
+quiet_cmd_ramdisk = RAMDISK $@
+ cmd_ramdisk = $(obj)/addRamDisk $(obj)/ramdisk.image.gz $< $@
+
+quiet_cmd_stripvm = STRIP $@
+ cmd_stripvm = $(STRIP) -s -R .comment $< -o $@
+
+vmlinux.strip: vmlinux
+ $(call if_changed,stripvm)
+$(obj)/vmlinux.initrd: vmlinux.strip $(obj)/addRamDisk $(obj)/ramdisk.image.gz
+ $(call if_changed,ramdisk)
+
+quiet_cmd_addsection = ADDSEC $@
+ cmd_addsection = $(CROSS32OBJCOPY) $@ \
+ --add-section=.kernel:$(strip $(patsubst $(obj)/kernel-%.o,%, $@))=$(patsubst %.o,%.gz, $@) \
+ --set-section-flags=.kernel:$(strip $(patsubst $(obj)/kernel-%.o,%, $@))=$(OBJCOPYFLAGS)
+
+quiet_cmd_addnote = ADDNOTE $@
+ cmd_addnote = $(obj)/addnote $@
+
+$(call gz-sec, $(required)): $(obj)/kernel-%.gz: %
+ $(call if_changed,gzip)
+
+$(obj)/kernel-initrd.gz: $(obj)/ramdisk.image.gz
+ cp -f $(obj)/ramdisk.image.gz $@
+
+$(call src-sec, $(required) $(initrd)): $(obj)/kernel-%.c: $(obj)/kernel-%.gz
+ @touch $@
+
+$(call obj-sec, $(required) $(initrd)): $(obj)/kernel-%.o: $(obj)/kernel-%.c
+ $(call if_changed_dep,bootcc)
+ $(call cmd,addsection)
+
+$(obj)/zImage.vmode: obj-boot += $(call obj-sec, $(required))
+$(obj)/zImage.vmode: $(call obj-sec, $(required)) $(obj-boot) $(srctree)/$(src)/zImage.lds
+ $(call cmd,bootld,$(obj-boot))
+
+$(obj)/zImage.initrd.vmode: obj-boot += $(call obj-sec, $(required) $(initrd))
+$(obj)/zImage.initrd.vmode: $(call obj-sec, $(required) $(initrd)) $(obj-boot) $(srctree)/$(src)/zImage.lds
+ $(call cmd,bootld,$(obj-boot))
+
+$(obj)/zImage: $(obj)/zImage.vmode $(obj)/addnote
+ @cp -f $< $@
+ $(call if_changed,addnote)
+
+$(obj)/zImage.initrd: $(obj)/zImage.initrd.vmode $(obj)/addnote
+ @cp -f $< $@
+ $(call if_changed,addnote)
+
+install: $(CONFIGURE) $(BOOTIMAGE)
+ sh -x $(srctree)/$(src)/install.sh "$(KERNELRELEASE)" vmlinux System.map "$(INSTALL_PATH)" "$(BOOTIMAGE)"
+
+clean-files := $(addprefix $(objtree)/, $(obj-boot) vmlinux.strip)
diff --git a/arch/powerpc/boot/README b/arch/powerpc/boot/README
new file mode 100644
index 00000000000..3e11058760e
--- /dev/null
+++ b/arch/powerpc/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/powerpc/boot/addRamDisk.c b/arch/powerpc/boot/addRamDisk.c
new file mode 100644
index 00000000000..c02a99952be
--- /dev/null
+++ b/arch/powerpc/boot/addRamDisk.c
@@ -0,0 +1,311 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <netinet/in.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <elf.h>
+
+#define ElfHeaderSize (64 * 1024)
+#define ElfPages (ElfHeaderSize / 4096)
+#define KERNELBASE (0xc000000000000000)
+#define _ALIGN_UP(addr,size) (((addr)+((size)-1))&(~((size)-1)))
+
+struct addr_range {
+ unsigned long long addr;
+ unsigned long memsize;
+ unsigned long offset;
+};
+
+static int check_elf64(void *p, int size, struct addr_range *r)
+{
+ Elf64_Ehdr *elf64 = p;
+ Elf64_Phdr *elf64ph;
+
+ 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)
+ return 0;
+
+ if ((elf64->e_phoff + sizeof(Elf64_Phdr)) > size)
+ return 0;
+
+ elf64ph = (Elf64_Phdr *) ((unsigned long)elf64 +
+ (unsigned long)elf64->e_phoff);
+
+ r->memsize = (unsigned long)elf64ph->p_memsz;
+ r->offset = (unsigned long)elf64ph->p_offset;
+ r->addr = (unsigned long long)elf64ph->p_vaddr;
+
+#ifdef DEBUG
+ printf("PPC64 ELF file, ph:\n");
+ printf("p_type 0x%08x\n", elf64ph->p_type);
+ printf("p_flags 0x%08x\n", elf64ph->p_flags);
+ printf("p_offset 0x%016llx\n", elf64ph->p_offset);
+ printf("p_vaddr 0x%016llx\n", elf64ph->p_vaddr);
+ printf("p_paddr 0x%016llx\n", elf64ph->p_paddr);
+ printf("p_filesz 0x%016llx\n", elf64ph->p_filesz);
+ printf("p_memsz 0x%016llx\n", elf64ph->p_memsz);
+ printf("p_align 0x%016llx\n", elf64ph->p_align);
+ printf("... skipping 0x%08lx bytes of ELF header\n",
+ (unsigned long)elf64ph->p_offset);
+#endif
+
+ return 64;
+}
+void get4k(FILE *file, char *buf )
+{
+ unsigned j;
+ unsigned num = fread(buf, 1, 4096, file);
+ for ( j=num; j<4096; ++j )
+ buf[j] = 0;
+}
+
+void put4k(FILE *file, char *buf )
+{
+ fwrite(buf, 1, 4096, file);
+}
+
+void death(const char *msg, FILE *fdesc, const char *fname)
+{
+ fprintf(stderr, msg);
+ fclose(fdesc);
+ unlink(fname);
+ exit(1);
+}
+
+int main(int argc, char **argv)
+{
+ char inbuf[4096];
+ struct addr_range vmlinux;
+ FILE *ramDisk;
+ FILE *inputVmlinux;
+ FILE *outputVmlinux;
+
+ char *rd_name, *lx_name, *out_name;
+
+ size_t i;
+ unsigned long ramFileLen;
+ unsigned long ramLen;
+ unsigned long roundR;
+ unsigned long offset_end;
+
+ unsigned long kernelLen;
+ unsigned long actualKernelLen;
+ unsigned long round;
+ unsigned long roundedKernelLen;
+ unsigned long ramStartOffs;
+ unsigned long ramPages;
+ unsigned long roundedKernelPages;
+ unsigned long hvReleaseData;
+ u_int32_t eyeCatcher = 0xc8a5d9c4;
+ unsigned long naca;
+ unsigned long xRamDisk;
+ unsigned long xRamDiskSize;
+ long padPages;
+
+
+ if (argc < 2) {
+ fprintf(stderr, "Name of RAM disk file missing.\n");
+ exit(1);
+ }
+ rd_name = argv[1];
+
+ if (argc < 3) {
+ fprintf(stderr, "Name of vmlinux file missing.\n");
+ exit(1);
+ }
+ lx_name = argv[2];
+
+ if (argc < 4) {
+ fprintf(stderr, "Name of vmlinux output file missing.\n");
+ exit(1);
+ }
+ out_name = argv[3];
+
+
+ ramDisk = fopen(rd_name, "r");
+ if ( ! ramDisk ) {
+ fprintf(stderr, "RAM disk file \"%s\" failed to open.\n", rd_name);
+ exit(1);
+ }
+
+ inputVmlinux = fopen(lx_name, "r");
+ if ( ! inputVmlinux ) {
+ fprintf(stderr, "vmlinux file \"%s\" failed to open.\n", lx_name);
+ exit(1);
+ }
+
+ outputVmlinux = fopen(out_name, "w+");
+ if ( ! outputVmlinux ) {
+ fprintf(stderr, "output vmlinux file \"%s\" failed to open.\n", out_name);
+ exit(1);
+ }
+
+ i = fread(inbuf, 1, sizeof(inbuf), inputVmlinux);
+ if (i != sizeof(inbuf)) {
+ fprintf(stderr, "can not read vmlinux file %s: %u\n", lx_name, i);
+ exit(1);
+ }
+
+ i = check_elf64(inbuf, sizeof(inbuf), &vmlinux);
+ if (i == 0) {
+ fprintf(stderr, "You must have a linux kernel specified as argv[2]\n");
+ exit(1);
+ }
+
+ /* Input Vmlinux file */
+ fseek(inputVmlinux, 0, SEEK_END);
+ kernelLen = ftell(inputVmlinux);
+ fseek(inputVmlinux, 0, SEEK_SET);
+ printf("kernel file size = %lu\n", kernelLen);
+
+ actualKernelLen = kernelLen - ElfHeaderSize;
+
+ printf("actual kernel length (minus ELF header) = %lu\n", actualKernelLen);
+
+ round = actualKernelLen % 4096;
+ roundedKernelLen = actualKernelLen;
+ if ( round )
+ roundedKernelLen += (4096 - round);
+ printf("Vmlinux length rounded up to a 4k multiple = %ld/0x%lx \n", roundedKernelLen, roundedKernelLen);
+ roundedKernelPages = roundedKernelLen / 4096;
+ printf("Vmlinux pages to copy = %ld/0x%lx \n", roundedKernelPages, roundedKernelPages);
+
+ offset_end = _ALIGN_UP(vmlinux.memsize, 4096);
+ /* calc how many pages we need to insert between the vmlinux and the start of the ram disk */
+ padPages = offset_end/4096 - roundedKernelPages;
+
+ /* Check and see if the vmlinux is already larger than _end in System.map */
+ if (padPages < 0) {
+ /* vmlinux is larger than _end - adjust the offset to the start of the embedded ram disk */
+ offset_end = roundedKernelLen;
+ printf("vmlinux is larger than _end indicates it needs to be - offset_end = %lx \n", offset_end);
+ padPages = 0;
+ printf("will insert %lx pages between the vmlinux and the start of the ram disk \n", padPages);
+ }
+ else {
+ /* _end is larger than vmlinux - use the offset to _end that we calculated from the system map */
+ printf("vmlinux is smaller than _end indicates is needed - offset_end = %lx \n", offset_end);
+ printf("will insert %lx pages between the vmlinux and the start of the ram disk \n", padPages);
+ }
+
+
+
+ /* Input Ram Disk file */
+ // Set the offset that the ram disk will be started at.
+ ramStartOffs = offset_end; /* determined from the input vmlinux file and the system map */
+ printf("Ram Disk will start at offset = 0x%lx \n", ramStartOffs);
+
+ fseek(ramDisk, 0, SEEK_END);
+ ramFileLen = ftell(ramDisk);
+ fseek(ramDisk, 0, SEEK_SET);
+ printf("%s file size = %ld/0x%lx \n", rd_name, ramFileLen, ramFileLen);
+
+ ramLen = ramFileLen;
+
+ roundR = 4096 - (ramLen % 4096);
+ if ( roundR ) {
+ printf("Rounding RAM disk file up to a multiple of 4096, adding %ld/0x%lx \n", roundR, roundR);
+ ramLen += roundR;
+ }
+
+ printf("Rounded RAM disk size is %ld/0x%lx \n", ramLen, ramLen);
+ ramPages = ramLen / 4096;
+ printf("RAM disk pages to copy = %ld/0x%lx\n", ramPages, ramPages);
+
+
+
+ // Copy 64K ELF header
+ for (i=0; i<(ElfPages); ++i) {
+ get4k( inputVmlinux, inbuf );
+ put4k( outputVmlinux, inbuf );
+ }
+
+ /* Copy the vmlinux (as full pages). */
+ fseek(inputVmlinux, ElfHeaderSize, SEEK_SET);
+ for ( i=0; i<roundedKernelPages; ++i ) {
+ get4k( inputVmlinux, inbuf );
+ put4k( outputVmlinux, inbuf );
+ }
+
+ /* Insert pad pages (if appropriate) that are needed between */
+ /* | the end of the vmlinux and the ram disk. */
+ for (i=0; i<padPages; ++i) {
+ memset(inbuf, 0, 4096);
+ put4k(outputVmlinux, inbuf);
+ }
+
+ /* Copy the ram disk (as full pages). */
+ for ( i=0; i<ramPages; ++i ) {
+ get4k( ramDisk, inbuf );
+ put4k( outputVmlinux, inbuf );
+ }
+
+ /* Close the input files */
+ fclose(ramDisk);
+ fclose(inputVmlinux);
+ /* And flush the written output file */
+ fflush(outputVmlinux);
+
+
+
+ /* Fixup the new vmlinux to contain the ram disk starting offset (xRamDisk) and the ram disk size (xRamDiskSize) */
+ /* fseek to the hvReleaseData pointer */
+ fseek(outputVmlinux, ElfHeaderSize + 0x24, SEEK_SET);
+ if (fread(&hvReleaseData, 4, 1, outputVmlinux) != 1) {
+ death("Could not read hvReleaseData pointer\n", outputVmlinux, out_name);
+ }
+ hvReleaseData = ntohl(hvReleaseData); /* Convert to native int */
+ printf("hvReleaseData is at %08lx\n", hvReleaseData);
+
+ /* fseek to the hvReleaseData */
+ fseek(outputVmlinux, ElfHeaderSize + hvReleaseData, SEEK_SET);
+ if (fread(inbuf, 0x40, 1, outputVmlinux) != 1) {
+ death("Could not read hvReleaseData\n", outputVmlinux, out_name);
+ }
+ /* Check hvReleaseData sanity */
+ if (memcmp(inbuf, &eyeCatcher, 4) != 0) {
+ death("hvReleaseData is invalid\n", outputVmlinux, out_name);
+ }
+ /* Get the naca pointer */
+ naca = ntohl(*((u_int32_t*) &inbuf[0x0C])) - KERNELBASE;
+ printf("Naca is at offset 0x%lx \n", naca);
+
+ /* fseek to the naca */
+ fseek(outputVmlinux, ElfHeaderSize + naca, SEEK_SET);
+ if (fread(inbuf, 0x18, 1, outputVmlinux) != 1) {
+ death("Could not read naca\n", outputVmlinux, out_name);
+ }
+ xRamDisk = ntohl(*((u_int32_t *) &inbuf[0x0c]));
+ xRamDiskSize = ntohl(*((u_int32_t *) &inbuf[0x14]));
+ /* Make sure a RAM disk isn't already present */
+ if ((xRamDisk != 0) || (xRamDiskSize != 0)) {
+ death("RAM disk is already attached to this kernel\n", outputVmlinux, out_name);
+ }
+ /* Fill in the values */
+ *((u_int32_t *) &inbuf[0x0c]) = htonl(ramStartOffs);
+ *((u_int32_t *) &inbuf[0x14]) = htonl(ramPages);
+
+ /* Write out the new naca */
+ fflush(outputVmlinux);
+ fseek(outputVmlinux, ElfHeaderSize + naca, SEEK_SET);
+ if (fwrite(inbuf, 0x18, 1, outputVmlinux) != 1) {
+ death("Could not write naca\n", outputVmlinux, out_name);
+ }
+ printf("Ram Disk of 0x%lx pages is attached to the kernel at offset 0x%08lx\n",
+ ramPages, ramStartOffs);
+
+ /* Done */
+ fclose(outputVmlinux);
+ /* Set permission to executable */
+ chmod(out_name, S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH);
+
+ return 0;
+}
+
diff --git a/arch/powerpc/boot/addnote.c b/arch/powerpc/boot/addnote.c
new file mode 100644
index 00000000000..8041a9845ab
--- /dev/null
+++ b/arch/powerpc/boot/addnote.c
@@ -0,0 +1,205 @@
+/*
+ * Program to hack in a PT_NOTE program header entry in an ELF file.
+ * This is needed for OF on RS/6000s to load an image correctly.
+ * Note that OF needs a program header entry for the note, not an
+ * ELF section.
+ *
+ * Copyright 2000 Paul Mackerras.
+ *
+ * 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.
+ *
+ * Usage: addnote zImage
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+
+/* CHRP note section */
+char arch[] = "PowerPC";
+
+#define N_DESCR 6
+unsigned int descr[N_DESCR] = {
+ 0xffffffff, /* real-mode = true */
+ 0x00c00000, /* real-base, i.e. where we expect OF to be */
+ 0xffffffff, /* real-size */
+ 0xffffffff, /* virt-base */
+ 0xffffffff, /* virt-size */
+ 0x4000, /* load-base */
+};
+
+/* RPA note section */
+char rpaname[] = "IBM,RPA-Client-Config";
+
+/*
+ * Note: setting ignore_my_client_config *should* mean that OF ignores
+ * all the other fields, but there is a firmware bug which means that
+ * it looks at the splpar field at least. So these values need to be
+ * reasonable.
+ */
+#define N_RPA_DESCR 8
+unsigned int rpanote[N_RPA_DESCR] = {
+ 0, /* lparaffinity */
+ 64, /* min_rmo_size */
+ 0, /* min_rmo_percent */
+ 40, /* max_pft_size */
+ 1, /* splpar */
+ -1, /* min_load */
+ 0, /* new_mem_def */
+ 1, /* ignore_my_client_config */
+};
+
+#define ROUNDUP(len) (((len) + 3) & ~3)
+
+unsigned char buf[512];
+
+#define GET_16BE(off) ((buf[off] << 8) + (buf[(off)+1]))
+#define GET_32BE(off) ((GET_16BE(off) << 16) + GET_16BE((off)+2))
+
+#define PUT_16BE(off, v) (buf[off] = ((v) >> 8) & 0xff, \
+ buf[(off) + 1] = (v) & 0xff)
+#define PUT_32BE(off, v) (PUT_16BE((off), (v) >> 16), \
+ PUT_16BE((off) + 2, (v)))
+
+/* Structure of an ELF file */
+#define E_IDENT 0 /* ELF header */
+#define E_PHOFF 28
+#define E_PHENTSIZE 42
+#define E_PHNUM 44
+#define E_HSIZE 52 /* size of ELF header */
+
+#define EI_MAGIC 0 /* offsets in E_IDENT area */
+#define EI_CLASS 4
+#define EI_DATA 5
+
+#define PH_TYPE 0 /* ELF program header */
+#define PH_OFFSET 4
+#define PH_FILESZ 16
+#define PH_HSIZE 32 /* size of program header */
+
+#define PT_NOTE 4 /* Program header type = note */
+
+#define ELFCLASS32 1
+#define ELFDATA2MSB 2
+
+unsigned char elf_magic[4] = { 0x7f, 'E', 'L', 'F' };
+
+int
+main(int ac, char **av)
+{
+ int fd, n, i;
+ int ph, ps, np;
+ int nnote, nnote2, ns;
+
+ if (ac != 2) {
+ fprintf(stderr, "Usage: %s elf-file\n", av[0]);
+ exit(1);
+ }
+ fd = open(av[1], O_RDWR);
+ if (fd < 0) {
+ perror(av[1]);
+ exit(1);
+ }
+
+ nnote = 12 + ROUNDUP(strlen(arch) + 1) + sizeof(descr);
+ nnote2 = 12 + ROUNDUP(strlen(rpaname) + 1) + sizeof(rpanote);
+
+ n = read(fd, buf, sizeof(buf));
+ if (n < 0) {
+ perror("read");
+ exit(1);
+ }
+
+ if (n < E_HSIZE || memcmp(&buf[E_IDENT+EI_MAGIC], elf_magic, 4) != 0)
+ goto notelf;
+
+ if (buf[E_IDENT+EI_CLASS] != ELFCLASS32
+ || buf[E_IDENT+EI_DATA] != ELFDATA2MSB) {
+ fprintf(stderr, "%s is not a big-endian 32-bit ELF image\n",
+ av[1]);
+ exit(1);
+ }
+
+ ph = GET_32BE(E_PHOFF);
+ ps = GET_16BE(E_PHENTSIZE);
+ np = GET_16BE(E_PHNUM);
+ if (ph < E_HSIZE || ps < PH_HSIZE || np < 1)
+ goto notelf;
+ if (ph + (np + 2) * ps + nnote + nnote2 > n)
+ goto nospace;
+
+ for (i = 0; i < np; ++i) {
+ if (GET_32BE(ph + PH_TYPE) == PT_NOTE) {
+ fprintf(stderr, "%s already has a note entry\n",
+ av[1]);
+ exit(0);
+ }
+ ph += ps;
+ }
+
+ /* XXX check that the area we want to use is all zeroes */
+ for (i = 0; i < 2 * ps + nnote + nnote2; ++i)
+ if (buf[ph + i] != 0)
+ goto nospace;
+
+ /* fill in the program header entry */
+ ns = ph + 2 * ps;
+ PUT_32BE(ph + PH_TYPE, PT_NOTE);
+ PUT_32BE(ph + PH_OFFSET, ns);
+ PUT_32BE(ph + PH_FILESZ, nnote);
+
+ /* fill in the note area we point to */
+ /* XXX we should probably make this a proper section */
+ PUT_32BE(ns, strlen(arch) + 1);
+ PUT_32BE(ns + 4, N_DESCR * 4);
+ PUT_32BE(ns + 8, 0x1275);
+ strcpy((char *) &buf[ns + 12], arch);
+ ns += 12 + strlen(arch) + 1;
+ for (i = 0; i < N_DESCR; ++i, ns += 4)
+ PUT_32BE(ns, descr[i]);
+
+ /* fill in the second program header entry and the RPA note area */
+ ph += ps;
+ PUT_32BE(ph + PH_TYPE, PT_NOTE);
+ PUT_32BE(ph + PH_OFFSET, ns);
+ PUT_32BE(ph + PH_FILESZ, nnote2);
+
+ /* fill in the note area we point to */
+ PUT_32BE(ns, strlen(rpaname) + 1);
+ PUT_32BE(ns + 4, sizeof(rpanote));
+ PUT_32BE(ns + 8, 0x12759999);
+ strcpy((char *) &buf[ns + 12], rpaname);
+ ns += 12 + ROUNDUP(strlen(rpaname) + 1);
+ for (i = 0; i < N_RPA_DESCR; ++i, ns += 4)
+ PUT_32BE(ns, rpanote[i]);
+
+ /* Update the number of program headers */
+ PUT_16BE(E_PHNUM, np + 2);
+
+ /* write back */
+ lseek(fd, (long) 0, SEEK_SET);
+ i = write(fd, buf, n);
+ if (i < 0) {
+ perror("write");
+ exit(1);
+ }
+ if (i < n) {
+ fprintf(stderr, "%s: write truncated\n", av[1]);
+ exit(1);
+ }
+
+ exit(0);
+
+ notelf:
+ fprintf(stderr, "%s does not appear to be an ELF file\n", av[1]);
+ exit(1);
+
+ nospace:
+ fprintf(stderr, "sorry, I can't find space in %s to put the note\n",
+ av[1]);
+ exit(1);
+}
diff --git a/arch/powerpc/boot/crt0.S b/arch/powerpc/boot/crt0.S
new file mode 100644
index 00000000000..9cc44226393
--- /dev/null
+++ b/arch/powerpc/boot/crt0.S
@@ -0,0 +1,59 @@
+/*
+ * 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 "ppc_asm.h"
+
+ .text
+ .globl _zimage_start
+_zimage_start:
+ bl reloc_offset
+
+reloc_offset:
+ mflr r0
+ lis r9,reloc_offset@ha
+ addi r9,r9,reloc_offset@l
+ subf. r0,r9,r0
+ beq clear_caches
+
+reloc_got2:
+ lis r9,__got2_start@ha
+ addi r9,r9,__got2_start@l
+ lis r8,__got2_end@ha
+ addi r8,r8,__got2_end@l
+ subf. r8,r9,r8
+ beq clear_caches
+ srwi. r8,r8,2
+ mtctr r8
+ add r9,r0,r9
+reloc_got2_loop:
+ lwz r8,0(r9)
+ add r8,r8,r0
+ stw r8,0(r9)
+ addi r9,r9,4
+ bdnz reloc_got2_loop
+
+clear_caches:
+ lis r9,_start@h
+ add r9,r0,r9
+ lis r8,_etext@ha
+ addi r8,r8,_etext@l
+ add r8,r0,r8
+1: dcbf r0,r9
+ icbi r0,r9
+ addi r9,r9,0x20
+ cmplwi 0,r9,8
+ blt 1b
+ sync
+ isync
+
+ mr r6,r1
+ b start
+
diff --git a/arch/powerpc/boot/div64.S b/arch/powerpc/boot/div64.S
new file mode 100644
index 00000000000..722f360a32a
--- /dev/null
+++ b/arch/powerpc/boot/div64.S
@@ -0,0 +1,58 @@
+/*
+ * Divide a 64-bit unsigned number by a 32-bit unsigned number.
+ * This routine assumes that the top 32 bits of the dividend are
+ * non-zero to start with.
+ * On entry, r3 points to the dividend, which get overwritten with
+ * the 64-bit quotient, and r4 contains the divisor.
+ * On exit, r3 contains the remainder.
+ *
+ * Copyright (C) 2002 Paul Mackerras, IBM Corp.
+ *
+ * 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 "ppc_asm.h"
+
+ .globl __div64_32
+__div64_32:
+ lwz r5,0(r3) # get the dividend into r5/r6
+ lwz r6,4(r3)
+ cmplw r5,r4
+ li r7,0
+ li r8,0
+ blt 1f
+ divwu r7,r5,r4 # if dividend.hi >= divisor,
+ mullw r0,r7,r4 # quotient.hi = dividend.hi / divisor
+ subf. r5,r0,r5 # dividend.hi %= divisor
+ beq 3f
+1: mr r11,r5 # here dividend.hi != 0
+ andis. r0,r5,0xc000
+ bne 2f
+ cntlzw r0,r5 # we are shifting the dividend right
+ li r10,-1 # to make it < 2^32, and shifting
+ srw r10,r10,r0 # the divisor right the same amount,
+ add r9,r4,r10 # rounding up (so the estimate cannot
+ andc r11,r6,r10 # ever be too large, only too small)
+ andc r9,r9,r10
+ or r11,r5,r11
+ rotlw r9,r9,r0
+ rotlw r11,r11,r0
+ divwu r11,r11,r9 # then we divide the shifted quantities
+2: mullw r10,r11,r4 # to get an estimate of the quotient,
+ mulhwu r9,r11,r4 # multiply the estimate by the divisor,
+ subfc r6,r10,r6 # take the product from the divisor,
+ add r8,r8,r11 # and add the estimate to the accumulated
+ subfe. r5,r9,r5 # quotient
+ bne 1b
+3: cmplw r6,r4
+ blt 4f
+ divwu r0,r6,r4 # perform the remaining 32-bit division
+ mullw r10,r0,r4 # and get the remainder
+ add r8,r8,r0
+ subf r6,r10,r6
+4: stw r7,0(r3) # return the quotient in *r3
+ stw r8,4(r3)
+ mr r3,r6 # return the remainder in r3
+ blr
diff --git a/arch/powerpc/boot/elf.h b/arch/powerpc/boot/elf.h
new file mode 100644
index 00000000000..d4828fcf1cb
--- /dev/null
+++ b/arch/powerpc/boot/elf.h
@@ -0,0 +1,149 @@
+#ifndef _PPC_BOOT_ELF_H_
+#define _PPC_BOOT_ELF_H_
+
+/* 32-bit ELF base types. */
+typedef unsigned int Elf32_Addr;
+typedef unsigned short Elf32_Half;
+typedef unsigned int Elf32_Off;
+typedef signed int Elf32_Sword;
+typedef unsigned int Elf32_Word;
+
+/* 64-bit ELF base types. */
+typedef unsigned long long Elf64_Addr;
+typedef unsigned short Elf64_Half;
+typedef signed short Elf64_SHalf;
+typedef unsigned long long Elf64_Off;
+typedef signed int Elf64_Sword;
+typedef unsigned int Elf64_Word;
+typedef unsigned long long Elf64_Xword;
+typedef signed long long Elf64_Sxword;
+
+/* These constants are for the segment types stored in the image headers */
+#define PT_NULL 0
+#define PT_LOAD 1
+#define PT_DYNAMIC 2
+#define PT_INTERP 3
+#define PT_NOTE 4
+#define PT_SHLIB 5
+#define PT_PHDR 6
+#define PT_TLS 7 /* Thread local storage segment */
+#define PT_LOOS 0x60000000 /* OS-specific */
+#define PT_HIOS 0x6fffffff /* OS-specific */
+#define PT_LOPROC 0x70000000
+#define PT_HIPROC 0x7fffffff
+#define PT_GNU_EH_FRAME 0x6474e550
+
+#define PT_GNU_STACK (PT_LOOS + 0x474e551)
+
+/* These constants define the different elf file types */
+#define ET_NONE 0
+#define ET_REL 1
+#define ET_EXEC 2
+#define ET_DYN 3
+#define ET_CORE 4
+#define ET_LOPROC 0xff00
+#define ET_HIPROC 0xffff
+
+/* These constants define the various ELF target machines */
+#define EM_NONE 0
+#define EM_PPC 20 /* PowerPC */
+#define EM_PPC64 21 /* PowerPC64 */
+
+#define EI_NIDENT 16
+
+typedef struct elf32_hdr {
+ unsigned char e_ident[EI_NIDENT];
+ Elf32_Half e_type;
+ Elf32_Half e_machine;
+ Elf32_Word e_version;
+ Elf32_Addr e_entry; /* Entry point */
+ Elf32_Off e_phoff;
+ Elf32_Off e_shoff;
+ Elf32_Word e_flags;
+ Elf32_Half e_ehsize;
+ Elf32_Half e_phentsize;
+ Elf32_Half e_phnum;
+ Elf32_Half e_shentsize;
+ Elf32_Half e_shnum;
+ Elf32_Half e_shstrndx;
+} Elf32_Ehdr;
+
+typedef struct elf64_hdr {
+ unsigned char e_ident[16]; /* ELF "magic number" */
+ Elf64_Half e