powerpc: Make COFF zImages for old 32-bit powermacs
authorPaul Mackerras <paulus@samba.org>
Sat, 14 Jan 2006 04:04:06 +0000 (15:04 +1100)
committerPaul Mackerras <paulus@samba.org>
Sat, 14 Jan 2006 04:04:06 +0000 (15:04 +1100)
This adds code to build zImage.coff and/or zImage.initrd.coff when
CONFIG_PPC32 and CONFIG_PPC_PMAC are defined.  It also restructures
the OF client code and adds some workarounds for OF quirks on the
older machines.

Signed-off-by: Paul Mackerras <paulus@samba.org>
arch/powerpc/boot/Makefile
arch/powerpc/boot/crt0.S
arch/powerpc/boot/hack-coff.c [new file with mode: 0644]
arch/powerpc/boot/main.c
arch/powerpc/boot/prom.c
arch/powerpc/boot/prom.h
arch/powerpc/boot/rs6000.h [new file with mode: 0644]
arch/powerpc/boot/stdio.c [new file with mode: 0644]
arch/powerpc/boot/stdio.h
arch/powerpc/boot/zImage.coff.lds [new file with mode: 0644]

index b53d677..788dec4 100644 (file)
@@ -25,8 +25,8 @@ 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
+OBJCOPY_COFF_ARGS := -O aixcoff-rs6000 --set-start 0x500000
 
 zlib       := infblock.c infcodes.c inffast.c inflate.c inftrees.c infutil.c
 zlibheader := infblock.h infcodes.h inffast.h inftrees.h infutil.h
@@ -35,7 +35,7 @@ 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 := crt0.S string.S prom.c stdio.c main.c div64.S
 src-boot += $(zlib)
 src-boot := $(addprefix $(obj)/, $(src-boot))
 obj-boot := $(addsuffix .o, $(basename $(src-boot)))
@@ -70,7 +70,7 @@ quiet_cmd_bootas = BOOTAS  $@
       cmd_bootas = $(CROSS32CC) -Wp,-MD,$(depfile) $(BOOTAFLAGS) -c -o $@ $<
 
 quiet_cmd_bootld = BOOTLD  $@
-      cmd_bootld = $(CROSS32LD) $(BOOTLFLAGS) -o $@ $(2)
+      cmd_bootld = $(CROSS32LD) -T $(srctree)/$(src)/$(3) -o $@ $(2)
 
 $(patsubst %.c,%.o, $(filter %.c, $(src-boot))): %.o: %.c
        $(call if_changed_dep,bootcc)
@@ -87,12 +87,14 @@ 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
+hostprogs-y            := addnote addRamDisk hack-coff
+
+targets += zImage.vmode zImage.initrd.vmode zImage zImage.initrd \
+          zImage.coff zImage.initrd.coff \
+          $(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 $@
@@ -114,6 +116,10 @@ quiet_cmd_addsection = ADDSEC  $@
 quiet_cmd_addnote = ADDNOTE $@
       cmd_addnote = $(obj)/addnote $@
 
+quiet_cmd_gencoff = COFF    $@
+      cmd_gencoff = $(OBJCOPY) $(OBJCOPY_COFF_ARGS) $@ && \
+                   $(obj)/hack-coff $@
+
 $(call gz-sec, $(required)): $(obj)/kernel-%.gz: %
        $(call if_changed,gzip)
 
@@ -127,22 +133,35 @@ $(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 $(obj)/zImage.coff: obj-boot += $(call obj-sec, $(required))
 $(obj)/zImage.vmode: $(call obj-sec, $(required)) $(obj-boot) $(srctree)/$(src)/zImage.lds
-       $(call cmd,bootld,$(obj-boot))
+       $(call cmd,bootld,$(obj-boot),zImage.lds)
 
-$(obj)/zImage.initrd.vmode: obj-boot += $(call obj-sec, $(required) $(initrd))
+$(obj)/zImage.initrd.vmode $(obj)/zImage.initrd.coff: 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))
+       $(call cmd,bootld,$(obj-boot),zImage.lds)
+
+# For 32-bit powermacs, build the COFF images as well as the ELF images.
+coffimage-$(CONFIG_PPC_PMAC)-$(CONFIG_PPC32) := $(obj)/zImage.coff
+coffrdimg-$(CONFIG_PPC_PMAC)-$(CONFIG_PPC32) := $(obj)/zImage.initrd.coff
 
-$(obj)/zImage: $(obj)/zImage.vmode $(obj)/addnote
+$(obj)/zImage: $(obj)/zImage.vmode $(obj)/addnote $(coffimage-y-y)
        @cp -f $< $@
        $(call if_changed,addnote)
 
-$(obj)/zImage.initrd: $(obj)/zImage.initrd.vmode $(obj)/addnote
+$(obj)/zImage.initrd: $(obj)/zImage.initrd.vmode $(obj)/addnote $(coffrdimg-y-y)
        @cp -f $< $@
        $(call if_changed,addnote)
 
+$(obj)/zImage.coff: $(call obj-sec, $(required)) $(obj-boot) $(srctree)/$(src)/zImage.coff.lds $(obj)/hack-coff
+       $(call cmd,bootld,$(obj-boot),zImage.coff.lds)
+       $(call cmd,gencoff)
+
+$(obj)/zImage.initrd.coff: $(call obj-sec, $(required) $(initrd)) $(obj-boot) \
+                          $(srctree)/$(src)/zImage.coff.lds $(obj)/hack-coff
+       $(call cmd,bootld,$(obj-boot),zImage.coff.lds)
+       $(call cmd,gencoff)
+
 #-----------------------------------------------------------
 # build u-boot images
 #-----------------------------------------------------------
index d2f2ace..e0192c2 100644 (file)
 #include "ppc_asm.h"
 
        .text
+       /* a procedure descriptor used when booting this as a COFF file */
+_zimage_start_opd:
+       .long   _zimage_start, 0, 0, 0
+
        .globl  _zimage_start
 _zimage_start:
+       /* Work out the offset between the address we were linked at
+          and the address where we're running. */
        bl      1f
-
-1:
-       mflr    r0
+1:     mflr    r0
        lis     r9,1b@ha
        addi    r9,r9,1b@l
        subf.   r0,r9,r0
-       beq     3f
+       beq     3f              /* if running at same address as linked */
 
+       /* The .got2 section contains a list of addresses, so add
+          the address offset onto each entry. */
        lis     r9,__got2_start@ha
        addi    r9,r9,__got2_start@l
        lis     r8,__got2_end@ha
@@ -32,15 +38,14 @@ _zimage_start:
        srwi.   r8,r8,2
        mtctr   r8
        add     r9,r0,r9
-2:
-       lwz     r8,0(r9)
+2:     lwz     r8,0(r9)
        add     r8,r8,r0
        stw     r8,0(r9)
        addi    r9,r9,4
        bdnz    2b
 
-3:
-       lis     r9,_start@h
+       /* Do a cache flush for our text, in case OF didn't */
+3:     lis     r9,_start@h
        add     r9,r0,r9
        lis     r8,_etext@ha
        addi    r8,r8,_etext@l
diff --git a/arch/powerpc/boot/hack-coff.c b/arch/powerpc/boot/hack-coff.c
new file mode 100644 (file)
index 0000000..5e5a657
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * hack-coff.c - hack the header of an xcoff file to fill in
+ * a few fields needed by the Open Firmware xcoff loader on
+ * Power Macs but not initialized by objcopy.
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include "rs6000.h"
+
+#define AOUT_MAGIC     0x010b
+
+#define get_16be(x)    ((((unsigned char *)(x))[0] << 8) \
+                        + ((unsigned char *)(x))[1])
+#define put_16be(x, v) (((unsigned char *)(x))[0] = (v) >> 8, \
+                        ((unsigned char *)(x))[1] = (v) & 0xff)
+#define get_32be(x)    ((((unsigned char *)(x))[0] << 24) \
+                        + (((unsigned char *)(x))[1] << 16) \
+                        + (((unsigned char *)(x))[2] << 8) \
+                        + ((unsigned char *)(x))[3])
+
+int
+main(int ac, char **av)
+{
+    int fd;
+    int i, nsect;
+    int aoutsz;
+    struct external_filehdr fhdr;
+    AOUTHDR aout;
+    struct external_scnhdr shdr;
+
+    if (ac != 2) {
+       fprintf(stderr, "Usage: hack-coff coff-file\n");
+       exit(1);
+    }
+    if ((fd = open(av[1], 2)) == -1) {
+       perror(av[2]);
+       exit(1);
+    }
+    if (read(fd, &fhdr, sizeof(fhdr)) != sizeof(fhdr))
+       goto readerr;
+    i = get_16be(fhdr.f_magic);
+    if (i != U802TOCMAGIC && i != U802WRMAGIC && i != U802ROMAGIC) {
+       fprintf(stderr, "%s: not an xcoff file\n", av[1]);
+       exit(1);
+    }
+    aoutsz = get_16be(fhdr.f_opthdr);
+    if (read(fd, &aout, aoutsz) != aoutsz)
+       goto readerr;
+    nsect = get_16be(fhdr.f_nscns);
+    for (i = 0; i < nsect; ++i) {
+       if (read(fd, &shdr, sizeof(shdr)) != sizeof(shdr))
+           goto readerr;
+       if (strcmp(shdr.s_name, ".text") == 0) {
+           put_16be(aout.o_snentry, i+1);
+           put_16be(aout.o_sntext, i+1);
+       } else if (strcmp(shdr.s_name, ".data") == 0) {
+           put_16be(aout.o_sndata, i+1);
+       } else if (strcmp(shdr.s_name, ".bss") == 0) {
+           put_16be(aout.o_snbss, i+1);
+       }
+    }
+    put_16be(aout.magic, AOUT_MAGIC);
+    if (lseek(fd, (long) sizeof(struct external_filehdr), 0) == -1
+       || write(fd, &aout, aoutsz) != aoutsz) {
+       fprintf(stderr, "%s: write error\n", av[1]);
+       exit(1);
+    }
+    close(fd);
+    exit(0);
+
+readerr:
+    fprintf(stderr, "%s: read error or file too short\n", av[1]);
+    exit(1);
+}
index 64ec931..55ec598 100644 (file)
@@ -21,8 +21,8 @@ extern void flush_cache(void *, unsigned long);
 
 
 /* Value picked to match that used by yaboot */
-#define PROG_START     0x01400000
-#define RAM_END                (512<<20) // Fixme: use OF */
+#define PROG_START     0x01400000      /* only used on 64-bit systems */
+#define RAM_END                (512<<20)       /* Fixme: use OF */
 #define        ONE_MB          0x100000
 
 extern char _start[];
@@ -160,6 +160,17 @@ static int is_elf64(void *hdr)
        elfoffset = (unsigned long)elf64ph->p_offset;
        vmlinux.size = (unsigned long)elf64ph->p_filesz + elfoffset;
        vmlinux.memsize = (unsigned long)elf64ph->p_memsz + elfoffset;
+
+#if defined(PROG_START)
+       /*
+        * Maintain a "magic" minimum address. This keeps some older
+        * firmware platforms running.
+        */
+
+       if (claim_base < PROG_START)
+               claim_base = PROG_START;
+#endif
+
        return 1;
 }
 
@@ -206,12 +217,18 @@ void start(unsigned long a1, unsigned long a2, void *promptr, void *sp)
                exit();
        if (getprop(chosen_handle, "stdout", &stdout, sizeof(stdout)) != 4)
                exit();
-       stderr = stdout;
-       if (getprop(chosen_handle, "stdin", &stdin, sizeof(stdin)) != 4)
-               exit();
 
        printf("\n\rzImage starting: loaded at 0x%p (sp: 0x%p)\n\r", _start, sp);
 
+       /*
+        * The first available claim_base must be above the end of the
+        * the loaded kernel wrapper file (_start to _end includes the
+        * initrd image if it is present) and rounded up to a nice
+        * 1 MB boundary for good measure.
+        */
+
+       claim_base = _ALIGN_UP((unsigned long)_end, ONE_MB);
+
        vmlinuz.addr = (unsigned long)_vmlinux_start;
        vmlinuz.size = (unsigned long)(_vmlinux_end - _vmlinux_start);
 
@@ -228,25 +245,6 @@ void start(unsigned long a1, unsigned long a2, void *promptr, void *sp)
                exit();
        }
 
-       /*
-        * The first available claim_base must be above the end of the
-        * the loaded kernel wrapper file (_start to _end includes the
-        * initrd image if it is present) and rounded up to a nice
-        * 1 MB boundary for good measure.
-        */
-
-       claim_base = _ALIGN_UP((unsigned long)_end, ONE_MB);
-
-#if defined(PROG_START)
-       /*
-        * Maintain a "magic" minimum address. This keeps some older
-        * firmware platforms running.
-        */
-
-       if (claim_base < PROG_START)
-               claim_base = PROG_START;
-#endif
-
        /* We need to claim the memsize plus the file offset since gzip
         * will expand the header (file offset), then the kernel, then
         * possible rubbish we don't care about. But the kernel bss must
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge